MWEB: Primitives (CTransaction, CBlock, serialization)
This commit is contained in:
parent
9417feaab4
commit
9d1f530a5f
@ -203,6 +203,7 @@ BITCOIN_CORE_H = \
|
||||
merkleblock.h \
|
||||
miner.h \
|
||||
mweb/mweb_db.h \
|
||||
mweb/mweb_models.h \
|
||||
net.h \
|
||||
net_permissions.h \
|
||||
net_processing.h \
|
||||
|
||||
214
src/mweb/mweb_models.h
Normal file
214
src/mweb/mweb_models.h
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright(C) 2011 - 2020 The Litecoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef LITECOIN_MWEB_MODELS_H
|
||||
#define LITECOIN_MWEB_MODELS_H
|
||||
|
||||
#include <amount.h>
|
||||
#include <mw/models/block/Block.h>
|
||||
#include <mw/models/tx/Transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <tinyformat.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace MWEB {
|
||||
|
||||
/// <summary>
|
||||
/// A convenience wrapper around a possibly-null extension block.
|
||||
/// </summary>
|
||||
struct Block {
|
||||
mw::Block::CPtr m_block;
|
||||
|
||||
Block() = default;
|
||||
Block(const mw::Block::CPtr& block)
|
||||
: m_block(block) {}
|
||||
|
||||
CAmount GetTotalFee() const noexcept
|
||||
{
|
||||
return IsNull() ? 0 : m_block->GetTotalFee();
|
||||
}
|
||||
|
||||
CAmount GetSupplyChange() const noexcept
|
||||
{
|
||||
return IsNull() ? 0 : m_block->GetSupplyChange();
|
||||
}
|
||||
|
||||
mw::Header::CPtr GetMWEBHeader() const noexcept
|
||||
{
|
||||
return IsNull() ? mw::Header::CPtr{nullptr} : m_block->GetHeader();
|
||||
}
|
||||
|
||||
int32_t GetHeight() const noexcept
|
||||
{
|
||||
return IsNull() ? -1 : m_block->GetHeight();
|
||||
}
|
||||
|
||||
std::vector<mw::Hash> GetSpentIDs() const
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::vector<mw::Hash>{};
|
||||
}
|
||||
|
||||
std::vector<mw::Hash> spent_ids;
|
||||
for (const Input& input : m_block->GetInputs()) {
|
||||
spent_ids.push_back(input.GetOutputID());
|
||||
}
|
||||
|
||||
return spent_ids;
|
||||
}
|
||||
|
||||
std::vector<mw::Hash> GetOutputIDs() const
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::vector<mw::Hash>{};
|
||||
}
|
||||
|
||||
std::vector<mw::Hash> output_ids;
|
||||
for (const Output& output : m_block->GetOutputs()) {
|
||||
output_ids.push_back(output.GetOutputID());
|
||||
}
|
||||
|
||||
return output_ids;
|
||||
}
|
||||
|
||||
std::set<mw::Hash> GetKernelIDs() const
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::set<mw::Hash>{};
|
||||
}
|
||||
|
||||
std::set<mw::Hash> kernel_ids;
|
||||
for (const Kernel& kernel : m_block->GetKernels()) {
|
||||
kernel_ids.insert(kernel.GetKernelID());
|
||||
}
|
||||
|
||||
return kernel_ids;
|
||||
}
|
||||
|
||||
SERIALIZE_METHODS(Block, obj)
|
||||
{
|
||||
READWRITE(WrapOptionalPtr(obj.m_block));
|
||||
}
|
||||
|
||||
bool IsNull() const noexcept { return m_block == nullptr; }
|
||||
void SetNull() noexcept { m_block.reset(); }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// A convenience wrapper around a possibly-null MWEB transcation.
|
||||
/// </summary>
|
||||
struct Tx {
|
||||
mw::Transaction::CPtr m_transaction;
|
||||
|
||||
Tx() = default;
|
||||
Tx(const mw::Transaction::CPtr& tx)
|
||||
: m_transaction(tx) {}
|
||||
|
||||
std::set<mw::Hash> GetSpentIDs() const noexcept
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::set<mw::Hash>{};
|
||||
}
|
||||
|
||||
std::set<mw::Hash> spent_ids;
|
||||
for (const Input& input : m_transaction->GetInputs()) {
|
||||
spent_ids.insert(input.GetOutputID());
|
||||
}
|
||||
|
||||
return spent_ids;
|
||||
}
|
||||
|
||||
std::set<mw::Hash> GetKernelIDs() const noexcept
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::set<mw::Hash>{};
|
||||
}
|
||||
|
||||
std::set<mw::Hash> kernel_ids;
|
||||
for (const Kernel& kernel : m_transaction->GetKernels()) {
|
||||
kernel_ids.insert(kernel.GetKernelID());
|
||||
}
|
||||
|
||||
return kernel_ids;
|
||||
}
|
||||
|
||||
std::set<mw::Hash> GetOutputIDs() const noexcept
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::set<mw::Hash>{};
|
||||
}
|
||||
|
||||
std::set<mw::Hash> output_ids;
|
||||
for (const Output& output : m_transaction->GetOutputs()) {
|
||||
output_ids.insert(output.GetOutputID());
|
||||
}
|
||||
|
||||
return output_ids;
|
||||
}
|
||||
|
||||
std::vector<PegInCoin> GetPegIns() const noexcept
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::vector<PegInCoin>{};
|
||||
}
|
||||
|
||||
return m_transaction->GetPegIns();
|
||||
}
|
||||
|
||||
bool HasPegOut() const noexcept
|
||||
{
|
||||
if (IsNull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<Kernel>& kernels = m_transaction->GetKernels();
|
||||
return std::any_of(
|
||||
kernels.cbegin(), kernels.cend(),
|
||||
[](const Kernel& kernel) { return kernel.HasPegOut(); }
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<PegOutCoin> GetPegOuts() const noexcept
|
||||
{
|
||||
if (IsNull()) {
|
||||
return std::vector<PegOutCoin>{};
|
||||
}
|
||||
|
||||
return m_transaction->GetPegOuts();
|
||||
}
|
||||
|
||||
uint64_t GetMWEBWeight() const noexcept
|
||||
{
|
||||
return IsNull() ? 0 : m_transaction->CalcWeight();
|
||||
}
|
||||
|
||||
CAmount GetFee() const noexcept
|
||||
{
|
||||
return IsNull() ? 0 : CAmount(m_transaction->GetTotalFee());
|
||||
}
|
||||
|
||||
int32_t GetLockHeight() const noexcept
|
||||
{
|
||||
return IsNull() ? 0 : m_transaction->GetLockHeight();
|
||||
}
|
||||
|
||||
SERIALIZE_METHODS(Tx, obj)
|
||||
{
|
||||
READWRITE(WrapOptionalPtr(obj.m_transaction));
|
||||
}
|
||||
|
||||
bool IsNull() const noexcept { return m_transaction == nullptr; }
|
||||
void SetNull() noexcept { m_transaction.reset(); }
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return IsNull() ? "" : m_transaction->Print();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace MWEB
|
||||
|
||||
#endif // LITECOIN_MWEB_MODELS_H
|
||||
@ -38,3 +38,13 @@ std::string CBlock::ToString() const
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
CTransactionRef CBlock::GetHogEx() const noexcept
|
||||
{
|
||||
if (vtx.size() >= 2 && vtx.back()->IsHogEx()) {
|
||||
assert(!vtx.back()->vout.empty());
|
||||
return vtx.back();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@ -9,6 +9,7 @@
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
#include <mweb/mweb_models.h>
|
||||
|
||||
/** Nodes collect new transactions into a block, hash them into a hash tree,
|
||||
* and scan through nonce values to make the block's hash satisfy proof-of-work
|
||||
@ -70,6 +71,8 @@ public:
|
||||
// memory only
|
||||
mutable bool fChecked;
|
||||
|
||||
MWEB::Block mweb_block;
|
||||
|
||||
CBlock()
|
||||
{
|
||||
SetNull();
|
||||
@ -85,6 +88,11 @@ public:
|
||||
{
|
||||
READWRITEAS(CBlockHeader, obj);
|
||||
READWRITE(obj.vtx);
|
||||
if (!(s.GetVersion() & SERIALIZE_NO_MWEB)) {
|
||||
if (obj.vtx.size() >= 2 && obj.vtx.back()->IsHogEx()) {
|
||||
READWRITE(obj.mweb_block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetNull()
|
||||
@ -92,6 +100,7 @@ public:
|
||||
CBlockHeader::SetNull();
|
||||
vtx.clear();
|
||||
fChecked = false;
|
||||
mweb_block.SetNull();
|
||||
}
|
||||
|
||||
CBlockHeader GetBlockHeader() const
|
||||
@ -107,6 +116,9 @@ public:
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
// Returns the hogex (integrating) transaction, if it exists.
|
||||
CTransactionRef GetHogEx() const noexcept;
|
||||
};
|
||||
|
||||
/** Describes a place in the block chain to another node such that if the
|
||||
|
||||
@ -56,17 +56,31 @@ std::string CTxOut::ToString() const
|
||||
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
|
||||
}
|
||||
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
|
||||
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), m_hogEx(false) {}
|
||||
CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), mweb_tx(tx.mweb_tx), m_hogEx(tx.m_hogEx) {}
|
||||
|
||||
uint256 CMutableTransaction::GetHash() const
|
||||
{
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
if (IsMWEBOnly()) {
|
||||
const auto& kernels = mweb_tx.m_transaction->GetKernels();
|
||||
if (!kernels.empty()) {
|
||||
return uint256(kernels.front().GetHash().vec());
|
||||
}
|
||||
}
|
||||
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS | SERIALIZE_NO_MWEB);
|
||||
}
|
||||
|
||||
uint256 CTransaction::ComputeHash() const
|
||||
{
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
if (IsMWEBOnly()) {
|
||||
const auto& kernels = mweb_tx.m_transaction->GetKernels();
|
||||
if (!kernels.empty()) {
|
||||
return uint256(kernels.front().GetHash().vec());
|
||||
}
|
||||
}
|
||||
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_TRANSACTION_NO_WITNESS | SERIALIZE_NO_MWEB);
|
||||
}
|
||||
|
||||
uint256 CTransaction::ComputeWitnessHash() const
|
||||
@ -74,13 +88,14 @@ uint256 CTransaction::ComputeWitnessHash() const
|
||||
if (!HasWitness()) {
|
||||
return hash;
|
||||
}
|
||||
return SerializeHash(*this, SER_GETHASH, 0);
|
||||
|
||||
return SerializeHash(*this, SER_GETHASH, SERIALIZE_NO_MWEB);
|
||||
}
|
||||
|
||||
/* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */
|
||||
CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), hash{}, m_witness_hash{} {}
|
||||
CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||
CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||
CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION), nLockTime(0), m_hogEx(false), hash{}, m_witness_hash{} {}
|
||||
CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), mweb_tx(tx.mweb_tx), m_hogEx(tx.m_hogEx), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||
CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), mweb_tx(tx.mweb_tx), m_hogEx(tx.m_hogEx), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
|
||||
|
||||
CAmount CTransaction::GetValueOut() const
|
||||
{
|
||||
@ -114,5 +129,57 @@ std::string CTransaction::ToString() const
|
||||
str += " " + tx_in.scriptWitness.ToString() + "\n";
|
||||
for (const auto& tx_out : vout)
|
||||
str += " " + tx_out.ToString() + "\n";
|
||||
|
||||
if (!mweb_tx.IsNull()) {
|
||||
str += " " + mweb_tx.ToString() + "\n";
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector<CTxInput> CTransaction::GetInputs() const noexcept
|
||||
{
|
||||
std::vector<CTxInput> inputs;
|
||||
|
||||
for (const CTxIn& txin : vin) {
|
||||
inputs.push_back(txin);
|
||||
}
|
||||
|
||||
for (const mw::Hash& spent_id : mweb_tx.GetSpentIDs()) {
|
||||
inputs.push_back(spent_id);
|
||||
}
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
CTxOutput CTransaction::GetOutput(const size_t index) const noexcept
|
||||
{
|
||||
assert(vout.size() > index);
|
||||
return CTxOutput{COutPoint(GetHash(), index), vout[index]};
|
||||
}
|
||||
|
||||
CTxOutput CTransaction::GetOutput(const OutputIndex& idx) const noexcept
|
||||
{
|
||||
if (idx.type() == typeid(mw::Hash)) {
|
||||
return CTxOutput{boost::get<mw::Hash>(idx)};
|
||||
} else {
|
||||
const COutPoint& outpoint = boost::get<COutPoint>(idx);
|
||||
assert(vout.size() > outpoint.n);
|
||||
return CTxOutput{outpoint, vout[outpoint.n]};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CTxOutput> CTransaction::GetOutputs() const noexcept
|
||||
{
|
||||
std::vector<CTxOutput> outputs;
|
||||
|
||||
for (size_t n = 0; n < vout.size(); n++) {
|
||||
outputs.push_back(CTxOutput{COutPoint(GetHash(), n), vout[n]});
|
||||
}
|
||||
|
||||
for (const mw::Hash& output_id : mweb_tx.GetOutputIDs()) {
|
||||
outputs.push_back(CTxOutput{output_id});
|
||||
}
|
||||
|
||||
return outputs;
|
||||
}
|
||||
@ -11,6 +11,9 @@
|
||||
#include <script/script.h>
|
||||
#include <serialize.h>
|
||||
#include <uint256.h>
|
||||
#include <mweb/mweb_models.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
@ -21,6 +24,7 @@
|
||||
* or with `ADDRV2_FORMAT`.
|
||||
*/
|
||||
static const int SERIALIZE_TRANSACTION_NO_WITNESS = 0x40000000;
|
||||
static const int SERIALIZE_NO_MWEB = 0x20000000;
|
||||
|
||||
/** An outpoint - a combination of a transaction hash and an index n into its vout */
|
||||
class COutPoint
|
||||
@ -122,6 +126,46 @@ public:
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
typedef boost::variant<COutPoint, mw::Hash> OutputIndex;
|
||||
|
||||
/// <summary>
|
||||
/// A generic transaction input that could either be an MWEB input hash or a canonical CTxIn.
|
||||
/// </summary>
|
||||
class CTxInput
|
||||
{
|
||||
public:
|
||||
CTxInput(mw::Hash output_id)
|
||||
: m_input(std::move(output_id)) {}
|
||||
CTxInput(CTxIn txin)
|
||||
: m_input(std::move(txin)) {}
|
||||
|
||||
bool IsMWEB() const noexcept { return m_input.type() == typeid(mw::Hash); }
|
||||
OutputIndex GetIndex() const noexcept
|
||||
{
|
||||
return IsMWEB() ? OutputIndex{ToMWEB()} : OutputIndex{GetTxIn().prevout};
|
||||
}
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return IsMWEB() ? ToMWEB().ToHex() : GetTxIn().ToString();
|
||||
}
|
||||
|
||||
const mw::Hash& ToMWEB() const noexcept
|
||||
{
|
||||
assert(IsMWEB());
|
||||
return boost::get<mw::Hash>(m_input);
|
||||
}
|
||||
|
||||
const CTxIn& GetTxIn() const noexcept
|
||||
{
|
||||
assert(!IsMWEB());
|
||||
return boost::get<CTxIn>(m_input);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::variant<CTxIn, mw::Hash> m_input;
|
||||
};
|
||||
|
||||
/** An output of a transaction. It contains the public key that the next input
|
||||
* must be able to sign with to claim it.
|
||||
*/
|
||||
@ -165,6 +209,52 @@ public:
|
||||
std::string ToString() const;
|
||||
};
|
||||
|
||||
class CTransaction;
|
||||
|
||||
/// <summary>
|
||||
/// A generic transaction output that could either be an MWEB output ID or a canonical CTxOut.
|
||||
/// </summary>
|
||||
class CTxOutput
|
||||
{
|
||||
public:
|
||||
CTxOutput() = default;
|
||||
CTxOutput(mw::Hash output_id)
|
||||
: m_idx(std::move(output_id)), m_txout(boost::none) {}
|
||||
CTxOutput(OutputIndex idx, CTxOut txout)
|
||||
: m_idx(std::move(idx)), m_txout(std::move(txout)) {}
|
||||
|
||||
bool IsMWEB() const noexcept { return m_idx.type() == typeid(mw::Hash); }
|
||||
|
||||
const OutputIndex& GetIndex() const noexcept { return m_idx; }
|
||||
|
||||
std::string ToString() const
|
||||
{
|
||||
return IsMWEB() ? ToMWEB().ToHex() : GetTxOut().ToString();
|
||||
}
|
||||
|
||||
const mw::Hash& ToMWEB() const noexcept
|
||||
{
|
||||
assert(IsMWEB());
|
||||
return boost::get<mw::Hash>(m_idx);
|
||||
}
|
||||
|
||||
const CTxOut& GetTxOut() const noexcept
|
||||
{
|
||||
assert(!IsMWEB() && !!m_txout);
|
||||
return *m_txout;
|
||||
}
|
||||
|
||||
const CScript& GetScriptPubKey() const noexcept
|
||||
{
|
||||
assert(!IsMWEB());
|
||||
return GetTxOut().scriptPubKey;
|
||||
}
|
||||
|
||||
private:
|
||||
OutputIndex m_idx;
|
||||
boost::optional<CTxOut> m_txout;
|
||||
};
|
||||
|
||||
struct CMutableTransaction;
|
||||
|
||||
/**
|
||||
@ -187,6 +277,7 @@ struct CMutableTransaction;
|
||||
template<typename Stream, typename TxType>
|
||||
inline void UnserializeTransaction(TxType& tx, Stream& s) {
|
||||
const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
const bool fAllowMWEB = !(s.GetVersion() & SERIALIZE_NO_MWEB);
|
||||
|
||||
s >> tx.nVersion;
|
||||
unsigned char flags = 0;
|
||||
@ -216,6 +307,21 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
|
||||
throw std::ios_base::failure("Superfluous witness record");
|
||||
}
|
||||
}
|
||||
if ((flags & 8) && fAllowMWEB) {
|
||||
/* The MWEB flag is present, and we support MWEB. */
|
||||
flags ^= 8;
|
||||
|
||||
s >> tx.mweb_tx;
|
||||
if (tx.mweb_tx.IsNull()) {
|
||||
if (tx.vout.empty()) {
|
||||
/* It's illegal to include a HogEx with no outputs. */
|
||||
throw std::ios_base::failure("Missing HogEx output");
|
||||
}
|
||||
|
||||
/* If the MWEB flag is set, but there are no MWEB txs, assume HogEx txn. */
|
||||
tx.m_hogEx = true;
|
||||
}
|
||||
}
|
||||
if (flags) {
|
||||
/* Unknown flag in the serialization */
|
||||
throw std::ios_base::failure("Unknown transaction optional data");
|
||||
@ -226,6 +332,7 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
|
||||
template<typename Stream, typename TxType>
|
||||
inline void SerializeTransaction(const TxType& tx, Stream& s) {
|
||||
const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
|
||||
const bool fAllowMWEB = !(s.GetVersion() & SERIALIZE_NO_MWEB);
|
||||
|
||||
s << tx.nVersion;
|
||||
unsigned char flags = 0;
|
||||
@ -236,6 +343,12 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
|
||||
flags |= 1;
|
||||
}
|
||||
}
|
||||
if (fAllowMWEB) {
|
||||
if (tx.m_hogEx || !tx.mweb_tx.IsNull()) {
|
||||
flags |= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags) {
|
||||
/* Use extended format in case witnesses are to be serialized. */
|
||||
std::vector<CTxIn> vinDummy;
|
||||
@ -249,6 +362,9 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
|
||||
s << tx.vin[i].scriptWitness.stack;
|
||||
}
|
||||
}
|
||||
if (flags & 8) {
|
||||
s << tx.mweb_tx;
|
||||
}
|
||||
s << tx.nLockTime;
|
||||
}
|
||||
|
||||
@ -277,6 +393,10 @@ public:
|
||||
const std::vector<CTxOut> vout;
|
||||
const int32_t nVersion;
|
||||
const uint32_t nLockTime;
|
||||
const MWEB::Tx mweb_tx;
|
||||
|
||||
/** Memory only. */
|
||||
const bool m_hogEx;
|
||||
|
||||
private:
|
||||
/** Memory only. */
|
||||
@ -347,6 +467,41 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasMWEBTx() const noexcept { return !mweb_tx.IsNull(); }
|
||||
bool IsHogEx() const noexcept { return m_hogEx; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the transaction is strictly MWEB-to-MWEB, with no canonical transaction data.
|
||||
/// </summary>
|
||||
/// <returns>True if the tx is MWEB-to-MWEB only.</returns>
|
||||
bool IsMWEBOnly() const noexcept { return HasMWEBTx() && vin.empty() && vout.empty(); }
|
||||
|
||||
/// <summary>
|
||||
/// Builds a vector of CTxInputs, starting with the canoncial inputs (CTxIn), followed by the MWEB input hashes.
|
||||
/// </summary>
|
||||
/// <returns>A vector of all of the transaction's inputs.</returns>
|
||||
std::vector<CTxInput> GetInputs() const noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a CTxOutput for the specified canonical output.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the CTxOut. This must be a valid index.</param>
|
||||
/// <returns>The CTxOutput object.</returns>
|
||||
CTxOutput GetOutput(const size_t index) const noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a CTxOutput for the specified output.
|
||||
/// </summary>
|
||||
/// <param name="idx">The index of the output. This could either be an output ID or a valid canonical output index.</param>
|
||||
/// <returns>The CTxOutput object.</returns>
|
||||
CTxOutput GetOutput(const OutputIndex& idx) const noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a vector of CTxOutputs, starting with the canoncial outputs (CTxOut), followed by the MWEB output IDs.
|
||||
/// </summary>
|
||||
/// <returns>A vector of all of the transaction's outputs.</returns>
|
||||
std::vector<CTxOutput> GetOutputs() const noexcept;
|
||||
};
|
||||
|
||||
/** A mutable version of CTransaction. */
|
||||
@ -356,6 +511,10 @@ struct CMutableTransaction
|
||||
std::vector<CTxOut> vout;
|
||||
int32_t nVersion;
|
||||
uint32_t nLockTime;
|
||||
MWEB::Tx mweb_tx;
|
||||
|
||||
/** Memory only. */
|
||||
bool m_hogEx = false;
|
||||
|
||||
CMutableTransaction();
|
||||
explicit CMutableTransaction(const CTransaction& tx);
|
||||
@ -390,12 +549,21 @@ struct CMutableTransaction
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasMWEBTx() const noexcept { return !mweb_tx.IsNull(); }
|
||||
bool IsMWEBOnly() const noexcept { return HasMWEBTx() && vin.empty() && vout.empty(); }
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<const CTransaction> CTransactionRef;
|
||||
static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); }
|
||||
template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); }
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& is, std::shared_ptr<const CTransaction>& p)
|
||||
{
|
||||
p = std::make_shared<const CTransaction>(deserialize, is);
|
||||
}
|
||||
|
||||
/** A generic txid reference (txid or wtxid). */
|
||||
class GenTxid
|
||||
{
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
#include <prevector.h>
|
||||
#include <span.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
/**
|
||||
* The maximum size of a serialized object in bytes or number of elements
|
||||
@ -689,12 +690,59 @@ template<typename Stream, typename K, typename Pred, typename A> void Unserializ
|
||||
template<typename Stream, typename T> void Serialize(Stream& os, const std::shared_ptr<const T>& p);
|
||||
template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_ptr<const T>& p);
|
||||
|
||||
class CTransaction;
|
||||
template<typename Stream> void Unserialize(Stream& is, std::shared_ptr<const CTransaction>& item);
|
||||
|
||||
/**
|
||||
* unique_ptr
|
||||
*/
|
||||
template<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p);
|
||||
template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p);
|
||||
|
||||
/**
|
||||
* optional
|
||||
*/
|
||||
template<typename Stream, typename T> void Serialize(Stream& os, const boost::optional<T>& item);
|
||||
template<typename Stream, typename T> void Unserialize(Stream& is, boost::optional<T>& item);
|
||||
|
||||
|
||||
template <class T>
|
||||
class OptionalPtr
|
||||
{
|
||||
protected:
|
||||
T& obj;
|
||||
|
||||
public:
|
||||
explicit OptionalPtr(T& _obj) : obj(_obj) {}
|
||||
|
||||
template <typename Stream>
|
||||
void Serialize(Stream& os) const
|
||||
{
|
||||
uint8_t is_set = obj != nullptr ? 1 : 0;
|
||||
os << is_set;
|
||||
|
||||
if (is_set == 1) {
|
||||
::Serialize(os, obj);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
void Unserialize(Stream& is)
|
||||
{
|
||||
uint8_t is_set = 0;
|
||||
is >> is_set;
|
||||
|
||||
if (is_set == 1) {
|
||||
::Unserialize(is, obj);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename I>
|
||||
OptionalPtr<I> WrapOptionalPtr(I& n)
|
||||
{
|
||||
return OptionalPtr<I>(n);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -974,10 +1022,40 @@ Serialize(Stream& os, const std::shared_ptr<const T>& p)
|
||||
template<typename Stream, typename T>
|
||||
void Unserialize(Stream& is, std::shared_ptr<const T>& p)
|
||||
{
|
||||
p = std::make_shared<const T>(deserialize, is);
|
||||
T obj;
|
||||
is >> obj;
|
||||
p = std::make_shared<const T>(std::move(obj));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* optional
|
||||
*/
|
||||
template <typename Stream, typename T>
|
||||
void Serialize(Stream& os, const boost::optional<T>& p)
|
||||
{
|
||||
uint8_t is_set = !!p ? 1 : 0;
|
||||
Serialize(os, is_set);
|
||||
|
||||
if (is_set == 1) {
|
||||
Serialize(os, (*p));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stream, typename T>
|
||||
void Unserialize(Stream& is, boost::optional<T>& p)
|
||||
{
|
||||
uint8_t is_set = 0;
|
||||
Unserialize(is, is_set);
|
||||
|
||||
if (is_set == 1) {
|
||||
T val;
|
||||
Unserialize(is, val);
|
||||
|
||||
p = boost::make_optional(std::move(val));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Support for SERIALIZE_METHODS and READWRITE macro.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user