From a3c4ee3fda66710f64d593ff9026ff4ad8b5c096 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Mon, 12 Feb 2018 14:44:32 +0100 Subject: [PATCH] DIP2 changes to CTransaction and CMutableTransaction --- src/consensus/consensus.h | 2 ++ src/primitives/transaction.cpp | 22 +++++++++++++--------- src/primitives/transaction.h | 30 +++++++++++++++++++++++++----- src/rpc/rawtransaction.cpp | 7 +++++++ src/script/interpreter.cpp | 5 ++++- 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index ee199b875c..0efe580c1e 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -18,6 +18,8 @@ inline unsigned int MaxBlockSigOps(bool fDIP0001Active /*= false */) { return MaxBlockSize(fDIP0001Active) / 50; } +/** The maximum allowed size of version 3 extra payload */ +static const unsigned int MAX_TX_EXTRA_PAYLOAD = 10000; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index f2afae047c..892cec4f69 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -60,8 +60,8 @@ 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) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime) {} +CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nType(TRANSACTION_NORMAL), nLockTime(0) {} +CMutableTransaction::CMutableTransaction(const CTransaction& tx) : nVersion(tx.nVersion), nType(tx.nType), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vExtraPayload(tx.vExtraPayload) {} uint256 CMutableTransaction::GetHash() const { @@ -71,12 +71,14 @@ uint256 CMutableTransaction::GetHash() const std::string CMutableTransaction::ToString() const { std::string str; - str += strprintf("CMutableTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n", + str += strprintf("CMutableTransaction(hash=%s, ver=%d, type=%d, vin.size=%u, vout.size=%u, nLockTime=%u, vExtraPayload.size=%d)\n", GetHash().ToString().substr(0,10), nVersion, + nType, vin.size(), vout.size(), - nLockTime); + nLockTime, + vExtraPayload.size()); for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) @@ -90,9 +92,9 @@ uint256 CTransaction::ComputeHash() const } /* For backward compatibility, the hash is initialized to 0. TODO: remove the need for this default constructor entirely. */ -CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), vin(), vout(), nLockTime(0), hash() {} -CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), hash(ComputeHash()) {} -CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), hash(ComputeHash()) {} +CTransaction::CTransaction() : nVersion(CTransaction::CURRENT_VERSION), nType(TRANSACTION_NORMAL), vin(), vout(), nLockTime(0), hash() {} +CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion), nType(tx.nType), vin(tx.vin), vout(tx.vout), nLockTime(tx.nLockTime), vExtraPayload(tx.vExtraPayload), hash(ComputeHash()) {} +CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), nType(tx.nType), vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), vExtraPayload(tx.vExtraPayload), hash(ComputeHash()) {} CAmount CTransaction::GetValueOut() const { @@ -140,12 +142,14 @@ unsigned int CTransaction::GetTotalSize() const std::string CTransaction::ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n", + str += strprintf("CTransaction(hash=%s, ver=%d, type=%d, vin.size=%u, vout.size=%u, nLockTime=%u, vExtraPayload.size=%d)\n", GetHash().ToString().substr(0,10), nVersion, + nType, vin.size(), vout.size(), - nLockTime); + nLockTime, + vExtraPayload.size()); for (unsigned int i = 0; i < vin.size(); i++) str += " " + vin[i].ToString() + "\n"; for (unsigned int i = 0; i < vout.size(); i++) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index e29af2bcef..23ec4f698b 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -11,6 +11,11 @@ #include "serialize.h" #include "uint256.h" +/** Transaction types */ +enum { + TRANSACTION_NORMAL = 0, +}; + /** An outpoint - a combination of a transaction hash and an index n into its vout */ class COutPoint { @@ -215,17 +220,19 @@ public: // adapting relay policy by bumping MAX_STANDARD_VERSION, and then later date // bumping the default CURRENT_VERSION at which point both CURRENT_VERSION and // MAX_STANDARD_VERSION will be equal. - static const int32_t MAX_STANDARD_VERSION=2; + static const int32_t MAX_STANDARD_VERSION=3; // The local variables are made const to prevent unintended modification // without updating the cached hash value. However, CTransaction is not // actually immutable; deserialization and assignment are implemented, // and bypass the constness. This is safe, as they update the entire // structure, including the hash. - const int32_t nVersion; + const int16_t nVersion; + const int16_t nType; const std::vector vin; const std::vector vout; const uint32_t nLockTime; + const std::vector vExtraPayload; // only available for special transaction types private: /** Memory only. */ @@ -243,10 +250,13 @@ public: template inline void Serialize(Stream& s) const { - s << this->nVersion; + int32_t n32bitVersion = this->nVersion | (this->nType << 16); + s << n32bitVersion; s << vin; s << vout; s << nLockTime; + if (this->nVersion >= 3 && this->nType != TRANSACTION_NORMAL) + s << vExtraPayload; } /** This deserializing constructor is provided instead of an Unserialize method. @@ -301,10 +311,12 @@ public: /** A mutable version of CTransaction. */ struct CMutableTransaction { - int32_t nVersion; + int16_t nVersion; + int16_t nType; std::vector vin; std::vector vout; uint32_t nLockTime; + std::vector vExtraPayload; // only available for special transaction types CMutableTransaction(); CMutableTransaction(const CTransaction& tx); @@ -313,10 +325,18 @@ struct CMutableTransaction template inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(this->nVersion); + int32_t n32bitVersion = this->nVersion | (this->nType << 16); + READWRITE(n32bitVersion); + if (ser_action.ForRead()) { + this->nVersion = (int16_t) (n32bitVersion & 0xffff); + this->nType = (int16_t) ((n32bitVersion >> 16) & 0xffff); + } READWRITE(vin); READWRITE(vout); READWRITE(nLockTime); + if (this->nVersion >= 3 && this->nType != TRANSACTION_NORMAL) { + READWRITE(vExtraPayload); + } } template diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index e773e6518c..0c02ce00ff 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -65,6 +65,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) entry.push_back(Pair("txid", txid.GetHex())); entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION))); entry.push_back(Pair("version", tx.nVersion)); + entry.push_back(Pair("type", tx.nType)); entry.push_back(Pair("locktime", (int64_t)tx.nLockTime)); UniValue vin(UniValue::VARR); BOOST_FOREACH(const CTxIn& txin, tx.vin) { @@ -121,6 +122,11 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) } entry.push_back(Pair("vout", vout)); + if (!tx.vExtraPayload.empty()) { + entry.push_back(Pair("extraPayloadSize", (int)tx.vExtraPayload.size())); + entry.push_back(Pair("extraPayload", HexStr(tx.vExtraPayload))); + } + if (!hashBlock.IsNull()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); BlockMap::iterator mi = mapBlockIndex.find(hashBlock); @@ -500,6 +506,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) " \"txid\" : \"id\", (string) The transaction id\n" " \"size\" : n, (numeric) The transaction size\n" " \"version\" : n, (numeric) The version\n" + " \"type\" : n, (numeric) The type\n" " \"locktime\" : ttt, (numeric) The lock time\n" " \"vin\" : [ (array of json objects)\n" " {\n" diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 80c804b929..d86696cb8b 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1098,7 +1098,8 @@ public: template void Serialize(S &s) const { // Serialize nVersion - ::Serialize(s, txTo.nVersion); + int32_t n32bitVersion = txTo.nVersion | (txTo.nType << 16); + ::Serialize(s, n32bitVersion); // Serialize vin unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); ::WriteCompactSize(s, nInputs); @@ -1111,6 +1112,8 @@ public: SerializeOutput(s, nOutput); // Serialize nLockTime ::Serialize(s, txTo.nLockTime); + if (txTo.nVersion >= 3 && txTo.nType != TRANSACTION_NORMAL) + ::Serialize(s, txTo.vExtraPayload); } };