From 690d38f0f8583e8eecc7b73b562cb9dff8bdb93a Mon Sep 17 00:00:00 2001 From: mruddy Date: Thu, 30 Jul 2015 19:56:00 -0400 Subject: [PATCH 01/20] Resolve issue bitcoin/bitcoin#3166. These changes decode valid SIGHASH types on signatures in assembly (asm) representations of scriptSig scripts. This squashed commit incorporates substantial helpful feedback from jtimon, laanwj, and sipa. --- doc/release-notes.md | 27 +++++++++++++ qa/rpc-tests/decodescript.py | 72 +++++++++++++++++++++++++++++++++- src/bitcoin-tx.cpp | 4 +- src/core_io.h | 4 +- src/core_write.cpp | 66 ++++++++++++++++++++++++++++++- src/primitives/transaction.cpp | 4 +- src/rpcrawtransaction.cpp | 8 ++-- src/script/interpreter.cpp | 2 +- src/script/interpreter.h | 2 + src/script/script.cpp | 33 ---------------- src/script/script.h | 1 - src/test/script_tests.cpp | 32 ++++++++++++++- 12 files changed, 206 insertions(+), 49 deletions(-) diff --git a/doc/release-notes.md b/doc/release-notes.md index c684ffc77..f51ae12da 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -19,3 +19,30 @@ For example: It is recommended to use this for sensitive information such as private keys, as command-line arguments can usually be read from the process table by any user on the system. + +Asm representations of scriptSig signatures now contain SIGHASH type decodes +---------------------------------------------------------------------------- + +The `asm` property of each scriptSig now contains the decoded signature hash +type for each signature that provides a valid defined hash type. + +The following items contain assembly representations of scriptSig signatures +and are affected by this change: + +- RPC `getrawtransaction` +- RPC `decoderawtransaction` +- REST `/rest/tx/` (JSON format) +- REST `/rest/block/` (JSON format when including extended tx details) +- `zcash-tx -json` + +For example, the `scriptSig.asm` property of a transaction input that +previously showed an assembly representation of: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001 + +now shows as: + + 304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090[ALL] + +Note that the output of the RPC `decodescript` did not change because it is +configured specifically to process scriptPubKey and not scriptSig scripts. diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py index 89364a840..293fd0ebb 100755 --- a/qa/rpc-tests/decodescript.py +++ b/qa/rpc-tests/decodescript.py @@ -6,6 +6,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, initialize_chain_clean, \ start_nodes +from test_framework.mininode import CTransaction +from binascii import hexlify, unhexlify +from cStringIO import StringIO class DecodeScriptTest(BitcoinTestFramework): @@ -109,10 +112,77 @@ class DecodeScriptTest(BitcoinTestFramework): rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac') assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) + def decoderawtransaction_asm_sighashtype(self): + """Tests decoding scripts via RPC command "decoderawtransaction". + + This test is in with the "decodescript" tests because they are testing the same "asm" script decodes. + """ + + # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output + tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm']) + + # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs. + # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc + # verify that we have not altered scriptPubKey decoding. + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid']) + assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm']) + assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) + assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) + txSave = CTransaction() + txSave.deserialize(StringIO(unhexlify(tx))) + + # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type + tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm']) + + # verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000' + rpc_result = self.nodes[0].decoderawtransaction(tx) + assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) + assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) + + # some more full transaction tests of varying specific scriptSigs. used instead of + # tests in decodescript_script_sig because the decodescript RPC is specifically + # for working on scriptPubKeys (argh!). + push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)] + signature = push_signature[2:] + der_signature = signature[:-2] + signature_sighash_decoded = der_signature + '[ALL]' + signature_2 = der_signature + '82' + push_signature_2 = '48' + signature_2 + signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]' + + # 1) P2PK scriptSig + txSave.vin[0].scriptSig = unhexlify(push_signature) + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # make sure that the sighash decodes come out correctly for a more complex / lesser used case. + txSave.vin[0].scriptSig = unhexlify(push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # 2) multisig scriptSig + txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2) + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) + + # 3) test a scriptSig that contains more than push operations. + # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it. + txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101') + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) + print(hexlify('636174')) + assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm']) + def run_test(self): self.decodescript_script_sig() self.decodescript_script_pub_key() + self.decoderawtransaction_asm_sighashtype() if __name__ == '__main__': DecodeScriptTest().main() - diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index b0fa5d476..82e72d0bd 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -437,8 +437,8 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& strInput) CCoinsModifier coins = view.ModifyCoins(txid); if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { std::string err("Previous output scriptPubKey mismatch:\n"); - err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ - scriptPubKey.ToString(); + err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+ + ScriptToAsmStr(scriptPubKey); throw std::runtime_error(err); } if ((unsigned int)nOut >= coins->vout.size()) diff --git a/src/core_io.h b/src/core_io.h index 115e3199d..ba5b4e648 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -16,6 +16,7 @@ class UniValue; // core_read.cpp extern CScript ParseScript(const std::string& s); +extern std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false); extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); extern uint256 ParseHashUV(const UniValue& v, const std::string& strName); @@ -25,8 +26,7 @@ extern std::vector ParseHexUV(const UniValue& v, const std::strin // core_write.cpp extern std::string FormatScript(const CScript& script); extern std::string EncodeHexTx(const CTransaction& tx); -extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, - UniValue& out, bool fIncludeHex); +extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); extern void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry); #endif // BITCOIN_CORE_IO_H diff --git a/src/core_write.cpp b/src/core_write.cpp index 26eeba655..533fedfe7 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -15,6 +15,7 @@ #include "utilmoneystr.h" #include "utilstrencodings.h" +#include #include using namespace std; @@ -54,6 +55,67 @@ string FormatScript(const CScript& script) return ret.substr(0, ret.size() - 1); } +const map mapSigHashTypes = + boost::assign::map_list_of + (static_cast(SIGHASH_ALL), string("ALL")) + (static_cast(SIGHASH_ALL|SIGHASH_ANYONECANPAY), string("ALL|ANYONECANPAY")) + (static_cast(SIGHASH_NONE), string("NONE")) + (static_cast(SIGHASH_NONE|SIGHASH_ANYONECANPAY), string("NONE|ANYONECANPAY")) + (static_cast(SIGHASH_SINGLE), string("SINGLE")) + (static_cast(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY), string("SINGLE|ANYONECANPAY")) + ; + +/** + * Create the assembly string representation of a CScript object. + * @param[in] script CScript object to convert into the asm string representation. + * @param[in] fAttemptSighashDecode Whether to attempt to decode sighash types on data within the script that matches the format + * of a signature. Only pass true for scripts you believe could contain signatures. For example, + * pass false, or omit the this argument (defaults to false), for scriptPubKeys. + */ +string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode) +{ + string str; + opcodetype opcode; + vector vch; + CScript::const_iterator pc = script.begin(); + while (pc < script.end()) { + if (!str.empty()) { + str += " "; + } + if (!script.GetOp(pc, opcode, vch)) { + str += "[error]"; + return str; + } + if (0 <= opcode && opcode <= OP_PUSHDATA4) { + if (vch.size() <= static_cast::size_type>(4)) { + str += strprintf("%d", CScriptNum(vch, false).getint()); + } else { + // the IsUnspendable check makes sure not to try to decode OP_RETURN data that may match the format of a signature + if (fAttemptSighashDecode && !script.IsUnspendable()) { + string strSigHashDecode; + // goal: only attempt to decode a defined sighash type from data that looks like a signature within a scriptSig. + // this won't decode correctly formatted public keys in Pubkey or Multisig scripts due to + // the restrictions on the pubkey formats (see IsCompressedOrUncompressedPubKey) being incongruous with the + // checks in CheckSignatureEncoding. + if (CheckSignatureEncoding(vch, SCRIPT_VERIFY_STRICTENC, NULL)) { + const unsigned char chSigHashType = vch.back(); + if (mapSigHashTypes.count(chSigHashType)) { + strSigHashDecode = "[" + mapSigHashTypes.find(chSigHashType)->second + "]"; + vch.pop_back(); // remove the sighash type byte. it will be replaced by the decode. + } + } + str += HexStr(vch) + strSigHashDecode; + } else { + str += HexStr(vch); + } + } + } else { + str += GetOpName(opcode); + } + } + return str; +} + string EncodeHexTx(const CTransaction& tx) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -68,7 +130,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey, vector addresses; int nRequired; - out.pushKV("asm", scriptPubKey.ToString()); + out.pushKV("asm", ScriptToAsmStr(scriptPubKey)); if (fIncludeHex) out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())); @@ -101,7 +163,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry) in.pushKV("txid", txin.prevout.hash.GetHex()); in.pushKV("vout", (int64_t)txin.prevout.n); UniValue o(UniValue::VOBJ); - o.pushKV("asm", txin.scriptSig.ToString()); + o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true)); o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())); in.pushKV("scriptSig", o); } diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index b362d3d6e..b433f810f 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -123,7 +123,7 @@ std::string CTxIn::ToString() const if (prevout.IsNull()) str += strprintf(", coinbase %s", HexStr(scriptSig)); else - str += strprintf(", scriptSig=%s", scriptSig.ToString().substr(0,24)); + str += strprintf(", scriptSig=%s", HexStr(scriptSig).substr(0, 24)); if (nSequence != std::numeric_limits::max()) str += strprintf(", nSequence=%u", nSequence); str += ")"; @@ -143,7 +143,7 @@ uint256 CTxOut::GetHash() const std::string CTxOut::ToString() const { - return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30)); + return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30)); } CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::SPROUT_MIN_CURRENT_VERSION), fOverwintered(false), nVersionGroupId(0), nExpiryHeight(0), nLockTime(0) {} diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index d928c36f8..d4307b2c5 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -37,7 +37,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud vector addresses; int nRequired; - out.push_back(Pair("asm", scriptPubKey.ToString())); + out.push_back(Pair("asm", ScriptToAsmStr(scriptPubKey))); if (fIncludeHex) out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); @@ -132,7 +132,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) in.push_back(Pair("txid", txin.prevout.hash.GetHex())); in.push_back(Pair("vout", (int64_t)txin.prevout.n)); UniValue o(UniValue::VOBJ); - o.push_back(Pair("asm", txin.scriptSig.ToString())); + o.push_back(Pair("asm", ScriptToAsmStr(txin.scriptSig, true))); o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); in.push_back(Pair("scriptSig", o)); } @@ -814,8 +814,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp) CCoinsModifier coins = view.ModifyCoins(txid); if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { string err("Previous output scriptPubKey mismatch:\n"); - err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ - scriptPubKey.ToString(); + err = err + ScriptToAsmStr(coins->vout[nOut].scriptPubKey) + "\nvs:\n"+ + ScriptToAsmStr(scriptPubKey); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); } if ((unsigned int)nOut >= coins->vout.size()) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index a8a026aef..9c1ae72cb 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -186,7 +186,7 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) { return true; } -bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { +bool CheckSignatureEncoding(const vector &vchSig, unsigned int flags, ScriptError* serror) { // Empty signature. Not strictly DER encoded, but allowed to provide a // compact way to provide an invalid signature for use with CHECK(MULTI)SIG if (vchSig.size() == 0) { diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 7f2956eec..bbfe672e0 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -88,6 +88,8 @@ enum SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), }; +bool CheckSignatureEncoding(const std::vector &vchSig, unsigned int flags, ScriptError* serror); + struct PrecomputedTransactionData { uint256 hashPrevouts, hashSequence, hashOutputs, hashJoinSplits; diff --git a/src/script/script.cpp b/src/script/script.cpp index 24a73d637..73c27c89b 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -8,16 +8,6 @@ #include "tinyformat.h" #include "utilstrencodings.h" -namespace { -inline std::string ValueString(const std::vector& vch) -{ - if (vch.size() <= 4) - return strprintf("%d", CScriptNum(vch, false).getint()); - else - return HexStr(vch); -} -} // anon namespace - using namespace std; const char* GetOpName(opcodetype opcode) @@ -237,26 +227,3 @@ bool CScript::IsPushOnly() const } return true; } - -std::string CScript::ToString() const -{ - std::string str; - opcodetype opcode; - std::vector vch; - const_iterator pc = begin(); - while (pc < end()) - { - if (!str.empty()) - str += " "; - if (!GetOp(pc, opcode, vch)) - { - str += "[error]"; - return str; - } - if (0 <= opcode && opcode <= OP_PUSHDATA4) - str += ValueString(vch); - else - str += GetOpName(opcode); - } - return str; -} diff --git a/src/script/script.h b/src/script/script.h index e0e89185f..112b93418 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -576,7 +576,6 @@ public: return (size() > 0 && *begin() == OP_RETURN) || (size() > MAX_SCRIPT_SIZE); } - std::string ToString() const; void clear() { // The default std::vector::clear() does not release memory. diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index c43a0ea0c..772457c99 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -808,7 +808,7 @@ BOOST_DATA_TEST_CASE(script_CHECKMULTISIG23, boost::unit_test::data::xrange(stat CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23, consensusBranchId); BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0, txFrom23.vout[0].nValue), consensusBranchId, &err)); BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err)); -} +} // Parameterized testing over consensus branch ids BOOST_DATA_TEST_CASE(script_combineSigs, boost::unit_test::data::xrange(static_cast(Consensus::MAX_NETWORK_UPGRADES))) @@ -958,4 +958,34 @@ BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts) BOOST_CHECK(!CScript(direct, direct+sizeof(direct)).IsPushOnly()); } +BOOST_AUTO_TEST_CASE(script_GetScriptAsm) +{ + BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_NOP2, true)); + BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY, true)); + BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_NOP2)); + BOOST_CHECK_EQUAL("OP_NOP2", ScriptToAsmStr(CScript() << OP_CHECKLOCKTIMEVERIFY)); + + string derSig("304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c5090"); + string pubKey("03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2"); + vector vchPubKey = ToByteVector(ParseHex(pubKey)); + + BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[ALL] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[NONE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[SINGLE] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[ALL|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[NONE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey, true)); + BOOST_CHECK_EQUAL(derSig + "[SINGLE|ANYONECANPAY] " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey, true)); + + BOOST_CHECK_EQUAL(derSig + "00 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "00")) << vchPubKey)); + BOOST_CHECK_EQUAL(derSig + "80 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "80")) << vchPubKey)); + BOOST_CHECK_EQUAL(derSig + "01 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "01")) << vchPubKey)); + BOOST_CHECK_EQUAL(derSig + "02 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "02")) << vchPubKey)); + BOOST_CHECK_EQUAL(derSig + "03 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "03")) << vchPubKey)); + BOOST_CHECK_EQUAL(derSig + "81 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "81")) << vchPubKey)); + BOOST_CHECK_EQUAL(derSig + "82 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "82")) << vchPubKey)); + BOOST_CHECK_EQUAL(derSig + "83 " + pubKey, ScriptToAsmStr(CScript() << ToByteVector(ParseHex(derSig + "83")) << vchPubKey)); +} + BOOST_AUTO_TEST_SUITE_END() From 29a8ade78222ee6d61b766c9db1238957a8ca7ba Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 29 Oct 2015 07:11:24 +0100 Subject: [PATCH 02/20] Prevector type --- src/Makefile.am | 1 + src/Makefile.test.include | 1 + src/core_memusage.h | 2 +- src/hash.h | 8 + src/memusage.h | 10 +- src/prevector.h | 486 +++++++++++++++++++++++++++++++++ src/primitives/transaction.h | 4 +- src/script/interpreter.cpp | 2 +- src/script/script.cpp | 6 +- src/script/script.h | 14 +- src/script/sign.cpp | 2 +- src/serialize.h | 157 ++++++++--- src/test/miner_tests.cpp | 2 +- src/test/prevector_tests.cpp | 217 +++++++++++++++ src/test/script_P2SH_tests.cpp | 10 +- src/test/script_tests.cpp | 4 +- src/test/sigopcount_tests.cpp | 2 +- src/wallet/walletdb.cpp | 10 +- 18 files changed, 872 insertions(+), 66 deletions(-) create mode 100644 src/prevector.h create mode 100644 src/test/prevector_tests.cpp diff --git a/src/Makefile.am b/src/Makefile.am index f323e56e5..516d2d272 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -167,6 +167,7 @@ BITCOIN_CORE_H = \ paymentdisclosuredb.h \ policy/fees.h \ pow.h \ + prevector.h \ primitives/block.h \ primitives/transaction.h \ protocol.h \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 0d33c3434..0b80921a9 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -70,6 +70,7 @@ BITCOIN_TESTS =\ test/pmt_tests.cpp \ test/policyestimator_tests.cpp \ test/pow_tests.cpp \ + test/prevector_tests.cpp \ test/raii_event_tests.cpp \ test/reverselock_tests.cpp \ test/rpc_tests.cpp \ diff --git a/src/core_memusage.h b/src/core_memusage.h index 711135bb4..b2f4a28ae 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -10,7 +10,7 @@ #include "memusage.h" static inline size_t RecursiveDynamicUsage(const CScript& script) { - return memusage::DynamicUsage(*static_cast*>(&script)); + return memusage::DynamicUsage(*static_cast(&script)); } static inline size_t RecursiveDynamicUsage(const COutPoint& out) { diff --git a/src/hash.h b/src/hash.h index 06fcced0a..fa1ba4d1e 100644 --- a/src/hash.h +++ b/src/hash.h @@ -8,6 +8,7 @@ #include "crypto/ripemd160.h" #include "crypto/sha256.h" +#include "prevector.h" #include "serialize.h" #include "uint256.h" #include "version.h" @@ -120,6 +121,13 @@ inline uint160 Hash160(const std::vector& vch) return Hash160(vch.begin(), vch.end()); } +/** Compute the 160-bit hash of a vector. */ +template +inline uint160 Hash160(const prevector& vch) +{ + return Hash160(vch.begin(), vch.end()); +} + /** A writer stream (for serialization) that computes a 256-bit hash. */ class CHashWriter { diff --git a/src/memusage.h b/src/memusage.h index be3964df1..0b232d88b 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -46,7 +46,9 @@ template static inline size_t DynamicUsage(const X * const &v) { ret static inline size_t MallocUsage(size_t alloc) { // Measured on libc6 2.19 on Linux. - if (sizeof(void*) == 8) { + if (alloc == 0) { + return 0; + } else if (sizeof(void*) == 8) { return ((alloc + 31) >> 4) << 4; } else if (sizeof(void*) == 4) { return ((alloc + 15) >> 3) << 3; @@ -74,6 +76,12 @@ static inline size_t DynamicUsage(const std::vector& v) return MallocUsage(v.capacity() * sizeof(X)); } +template +static inline size_t DynamicUsage(const prevector& v) +{ + return MallocUsage(v.allocated_memory()); +} + template static inline size_t DynamicUsage(const std::set& s) { diff --git a/src/prevector.h b/src/prevector.h new file mode 100644 index 000000000..3e80ef5d3 --- /dev/null +++ b/src/prevector.h @@ -0,0 +1,486 @@ +#ifndef _BITCOIN_PREVECTOR_H_ +#define _BITCOIN_PREVECTOR_H_ + +#include +#include +#include + +#include + +#pragma pack(push, 1) +/** Implements a drop-in replacement for std::vector which stores up to N + * elements directly (without heap allocation). The types Size and Diff are + * used to store element counts, and can be any unsigned + signed type. + * + * Storage layout is either: + * - Direct allocation: + * - Size _size: the number of used elements (between 0 and N) + * - T direct[N]: an array of N elements of type T + * (only the first _size are initialized). + * - Indirect allocation: + * - Size _size: the number of used elements plus N + 1 + * - Size capacity: the number of allocated elements + * - T* indirect: a pointer to an array of capacity elements of type T + * (only the first _size are initialized). + * + * The data type T must be movable by memmove/realloc(). Once we switch to C++, + * move constructors can be used instead. + */ +template +class prevector { +public: + typedef Size size_type; + typedef Diff difference_type; + typedef T value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + + class iterator { + T* ptr; + public: + typedef Diff difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef std::random_access_iterator_tag iterator_category; + iterator(T* ptr_) : ptr(ptr_) {} + T& operator*() const { return *ptr; } + T* operator->() const { return ptr; } + T& operator[](size_type pos) { return ptr[pos]; } + const T& operator[](size_type pos) const { return ptr[pos]; } + iterator& operator++() { ptr++; return *this; } + iterator& operator--() { ptr--; return *this; } + iterator operator++(int) { iterator copy(*this); ++(*this); return copy; } + iterator operator--(int) { iterator copy(*this); --(*this); return copy; } + difference_type friend operator-(iterator a, iterator b) { return (&(*a) - &(*b)); } + iterator operator+(size_type n) { return iterator(ptr + n); } + iterator& operator+=(size_type n) { ptr += n; return *this; } + iterator operator-(size_type n) { return iterator(ptr - n); } + iterator& operator-=(size_type n) { ptr -= n; return *this; } + bool operator==(iterator x) const { return ptr == x.ptr; } + bool operator!=(iterator x) const { return ptr != x.ptr; } + bool operator>=(iterator x) const { return ptr >= x.ptr; } + bool operator<=(iterator x) const { return ptr <= x.ptr; } + bool operator>(iterator x) const { return ptr > x.ptr; } + bool operator<(iterator x) const { return ptr < x.ptr; } + }; + + class reverse_iterator { + T* ptr; + public: + typedef Diff difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef std::bidirectional_iterator_tag iterator_category; + reverse_iterator(T* ptr_) : ptr(ptr_) {} + T& operator*() { return *ptr; } + const T& operator*() const { return *ptr; } + T* operator->() { return ptr; } + const T* operator->() const { return ptr; } + reverse_iterator& operator--() { ptr++; return *this; } + reverse_iterator& operator++() { ptr--; return *this; } + reverse_iterator operator++(int) { reverse_iterator copy(*this); ++(*this); return copy; } + reverse_iterator operator--(int) { reverse_iterator copy(*this); --(*this); return copy; } + bool operator==(reverse_iterator x) const { return ptr == x.ptr; } + bool operator!=(reverse_iterator x) const { return ptr != x.ptr; } + }; + + class const_iterator { + const T* ptr; + public: + typedef Diff difference_type; + typedef const T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef std::random_access_iterator_tag iterator_category; + const_iterator(const T* ptr_) : ptr(ptr_) {} + const_iterator(iterator x) : ptr(&(*x)) {} + const T& operator*() const { return *ptr; } + const T* operator->() const { return ptr; } + const T& operator[](size_type pos) const { return ptr[pos]; } + const_iterator& operator++() { ptr++; return *this; } + const_iterator& operator--() { ptr--; return *this; } + const_iterator operator++(int) { const_iterator copy(*this); ++(*this); return copy; } + const_iterator operator--(int) { const_iterator copy(*this); --(*this); return copy; } + difference_type friend operator-(const_iterator a, const_iterator b) { return (&(*a) - &(*b)); } + const_iterator operator+(size_type n) { return const_iterator(ptr + n); } + const_iterator& operator+=(size_type n) { ptr += n; return *this; } + const_iterator operator-(size_type n) { return const_iterator(ptr - n); } + const_iterator& operator-=(size_type n) { ptr -= n; return *this; } + bool operator==(const_iterator x) const { return ptr == x.ptr; } + bool operator!=(const_iterator x) const { return ptr != x.ptr; } + bool operator>=(const_iterator x) const { return ptr >= x.ptr; } + bool operator<=(const_iterator x) const { return ptr <= x.ptr; } + bool operator>(const_iterator x) const { return ptr > x.ptr; } + bool operator<(const_iterator x) const { return ptr < x.ptr; } + }; + + class const_reverse_iterator { + const T* ptr; + public: + typedef Diff difference_type; + typedef const T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef std::bidirectional_iterator_tag iterator_category; + const_reverse_iterator(T* ptr_) : ptr(ptr_) {} + const_reverse_iterator(reverse_iterator x) : ptr(&(*x)) {} + const T& operator*() const { return *ptr; } + const T* operator->() const { return ptr; } + const_reverse_iterator& operator--() { ptr++; return *this; } + const_reverse_iterator& operator++() { ptr--; return *this; } + const_reverse_iterator operator++(int) { const_reverse_iterator copy(*this); ++(*this); return copy; } + const_reverse_iterator operator--(int) { const_reverse_iterator copy(*this); --(*this); return copy; } + bool operator==(const_reverse_iterator x) const { return ptr == x.ptr; } + bool operator!=(const_reverse_iterator x) const { return ptr != x.ptr; } + }; + +private: + size_type _size; + union { + char direct[sizeof(T) * N]; + struct { + size_type capacity; + char* indirect; + }; + } _union; + + T* direct_ptr(difference_type pos) { return reinterpret_cast(_union.direct) + pos; } + const T* direct_ptr(difference_type pos) const { return reinterpret_cast(_union.direct) + pos; } + T* indirect_ptr(difference_type pos) { return reinterpret_cast(_union.indirect) + pos; } + const T* indirect_ptr(difference_type pos) const { return reinterpret_cast(_union.indirect) + pos; } + bool is_direct() const { return _size <= N; } + + void change_capacity(size_type new_capacity) { + if (new_capacity <= N) { + if (!is_direct()) { + T* indirect = indirect_ptr(0); + T* src = indirect; + T* dst = direct_ptr(0); + memcpy(dst, src, size() * sizeof(T)); + free(indirect); + _size -= N + 1; + } + } else { + if (!is_direct()) { + _union.indirect = static_cast(realloc(_union.indirect, ((size_t)sizeof(T)) * new_capacity)); + _union.capacity = new_capacity; + } else { + char* new_indirect = static_cast(malloc(((size_t)sizeof(T)) * new_capacity)); + T* src = direct_ptr(0); + T* dst = reinterpret_cast(new_indirect); + memcpy(dst, src, size() * sizeof(T)); + _union.indirect = new_indirect; + _union.capacity = new_capacity; + _size += N + 1; + } + } + } + + T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } + const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } + +public: + void assign(size_type n, const T& val) { + clear(); + if (capacity() < n) { + change_capacity(n); + } + while (size() < n) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(val); + } + } + + template + void assign(InputIterator first, InputIterator last) { + size_type n = last - first; + clear(); + if (capacity() < n) { + change_capacity(n); + } + while (first != last) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*first); + ++first; + } + } + + prevector() : _size(0) {} + + explicit prevector(size_type n) : _size(0) { + resize(n); + } + + explicit prevector(size_type n, const T& val = T()) : _size(0) { + change_capacity(n); + while (size() < n) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(val); + } + } + + template + prevector(InputIterator first, InputIterator last) : _size(0) { + size_type n = last - first; + change_capacity(n); + while (first != last) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*first); + ++first; + } + } + + prevector(const prevector& other) : _size(0) { + change_capacity(other.size()); + const_iterator it = other.begin(); + while (it != other.end()) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*it); + ++it; + } + } + + prevector& operator=(const prevector& other) { + if (&other == this) { + return *this; + } + resize(0); + change_capacity(other.size()); + const_iterator it = other.begin(); + while (it != other.end()) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(*it); + ++it; + } + return *this; + } + + size_type size() const { + return is_direct() ? _size : _size - N - 1; + } + + bool empty() const { + return size() == 0; + } + + iterator begin() { return iterator(item_ptr(0)); } + const_iterator begin() const { return const_iterator(item_ptr(0)); } + iterator end() { return iterator(item_ptr(size())); } + const_iterator end() const { return const_iterator(item_ptr(size())); } + + reverse_iterator rbegin() { return reverse_iterator(item_ptr(size() - 1)); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(item_ptr(size() - 1)); } + reverse_iterator rend() { return reverse_iterator(item_ptr(-1)); } + const_reverse_iterator rend() const { return const_reverse_iterator(item_ptr(-1)); } + + size_t capacity() const { + if (is_direct()) { + return N; + } else { + return _union.capacity; + } + } + + T& operator[](size_type pos) { + return *item_ptr(pos); + } + + const T& operator[](size_type pos) const { + return *item_ptr(pos); + } + + void resize(size_type new_size) { + while (size() > new_size) { + item_ptr(size() - 1)->~T(); + _size--; + } + if (new_size > capacity()) { + change_capacity(new_size); + } + while (size() < new_size) { + _size++; + new(static_cast(item_ptr(size() - 1))) T(); + } + } + + void reserve(size_type new_capacity) { + if (new_capacity > capacity()) { + change_capacity(new_capacity); + } + } + + void shrink_to_fit() { + change_capacity(size()); + } + + void clear() { + resize(0); + } + + iterator insert(iterator pos, const T& value) { + size_type p = pos - begin(); + size_type new_size = size() + 1; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + memmove(item_ptr(p + 1), item_ptr(p), (size() - p) * sizeof(T)); + _size++; + new(static_cast(item_ptr(p))) T(value); + return iterator(item_ptr(p)); + } + + void insert(iterator pos, size_type count, const T& value) { + size_type p = pos - begin(); + size_type new_size = size() + count; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); + _size += count; + for (size_type i = 0; i < count; i++) { + new(static_cast(item_ptr(p + i))) T(value); + } + } + + template + void insert(iterator pos, InputIterator first, InputIterator last) { + size_type p = pos - begin(); + difference_type count = last - first; + size_type new_size = size() + count; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + memmove(item_ptr(p + count), item_ptr(p), (size() - p) * sizeof(T)); + _size += count; + while (first != last) { + new(static_cast(item_ptr(p))) T(*first); + ++p; + ++first; + } + } + + iterator erase(iterator pos) { + (*pos).~T(); + memmove(&(*pos), &(*pos) + 1, ((char*)&(*end())) - ((char*)(1 + &(*pos)))); + _size--; + return pos; + } + + iterator erase(iterator first, iterator last) { + iterator p = first; + char* endp = (char*)&(*end()); + while (p != last) { + (*p).~T(); + _size--; + ++p; + } + memmove(&(*first), &(*last), endp - ((char*)(&(*last)))); + return first; + } + + void push_back(const T& value) { + size_type new_size = size() + 1; + if (capacity() < new_size) { + change_capacity(new_size + (new_size >> 1)); + } + new(item_ptr(size())) T(value); + _size++; + } + + void pop_back() { + _size--; + } + + T& front() { + return *item_ptr(0); + } + + const T& front() const { + return *item_ptr(0); + } + + T& back() { + return *item_ptr(size() - 1); + } + + const T& back() const { + return *item_ptr(size() - 1); + } + + void swap(prevector& other) { + if (_size & other._size & 1) { + std::swap(_union.capacity, other._union.capacity); + std::swap(_union.indirect, other._union.indirect); + } else { + std::swap(_union, other._union); + } + std::swap(_size, other._size); + } + + ~prevector() { + clear(); + if (!is_direct()) { + free(_union.indirect); + _union.indirect = NULL; + } + } + + bool operator==(const prevector& other) const { + if (other.size() != size()) { + return false; + } + const_iterator b1 = begin(); + const_iterator b2 = other.begin(); + const_iterator e1 = end(); + while (b1 != e1) { + if ((*b1) != (*b2)) { + return false; + } + ++b1; + ++b2; + } + return true; + } + + bool operator!=(const prevector& other) const { + return !(*this == other); + } + + bool operator<(const prevector& other) const { + if (size() < other.size()) { + return true; + } + if (size() > other.size()) { + return false; + } + const_iterator b1 = begin(); + const_iterator b2 = other.begin(); + const_iterator e1 = end(); + while (b1 != e1) { + if ((*b1) < (*b2)) { + return true; + } + if ((*b2) < (*b1)) { + return false; + } + ++b1; + ++b2; + } + return false; + } + + size_t allocated_memory() const { + if (is_direct()) { + return 0; + } else { + return ((size_t)(sizeof(T))) * _union.capacity; + } + } +}; +#pragma pack(pop) + +#endif diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index bcd7eaa8a..adc957433 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -207,7 +207,7 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(prevout); - READWRITE(scriptSig); + READWRITE(*(CScriptBase*)(&scriptSig)); READWRITE(nSequence); } @@ -252,7 +252,7 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(nValue); - READWRITE(scriptPubKey); + READWRITE(*(CScriptBase*)(&scriptPubKey)); } void SetNull() diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 9c1ae72cb..9237a9af9 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -999,7 +999,7 @@ public: assert(nInput != NOT_AN_INPUT); if (nInput != nIn) // Blank out other inputs' signatures - ::Serialize(s, CScript(), nType, nVersion); + ::Serialize(s, CScriptBase(), nType, nVersion); else SerializeScriptCode(s, nType, nVersion); // Serialize the nSequence diff --git a/src/script/script.cpp b/src/script/script.cpp index 73c27c89b..d5234cae8 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -205,9 +205,9 @@ bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: return (this->size() == 23 && - this->at(0) == OP_HASH160 && - this->at(1) == 0x14 && - this->at(22) == OP_EQUAL); + (*this)[0] == OP_HASH160 && + (*this)[1] == 0x14 && + (*this)[22] == OP_EQUAL); } bool CScript::IsPushOnly() const diff --git a/src/script/script.h b/src/script/script.h index 112b93418..781a09773 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -7,6 +7,7 @@ #define BITCOIN_SCRIPT_SCRIPT_H #include "crypto/common.h" +#include "prevector.h" #include #include @@ -351,8 +352,10 @@ private: int64_t m_value; }; +typedef prevector<28, unsigned char> CScriptBase; + /** Serialized script, used inside transaction inputs and outputs */ -class CScript : public std::vector +class CScript : public CScriptBase { protected: CScript& push_int64(int64_t n) @@ -373,9 +376,10 @@ protected: } public: CScript() { } - CScript(const CScript& b) : std::vector(b.begin(), b.end()) { } - CScript(const_iterator pbegin, const_iterator pend) : std::vector(pbegin, pend) { } - CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector(pbegin, pend) { } + CScript(const CScript& b) : CScriptBase(b.begin(), b.end()) { } + CScript(const_iterator pbegin, const_iterator pend) : CScriptBase(pbegin, pend) { } + CScript(std::vector::const_iterator pbegin, std::vector::const_iterator pend) : CScriptBase(pbegin, pend) { } + CScript(const unsigned char* pbegin, const unsigned char* pend) : CScriptBase(pbegin, pend) { } CScript& operator+=(const CScript& b) { @@ -579,7 +583,7 @@ public: void clear() { // The default std::vector::clear() does not release memory. - std::vector().swap(*this); + CScriptBase().swap(*this); } }; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 1aade8477..a4f642f97 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -15,7 +15,7 @@ using namespace std; -typedef vector valtype; +typedef std::vector valtype; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} diff --git a/src/serialize.h b/src/serialize.h index f776d6d99..a63b7a64e 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -24,7 +24,7 @@ #include #include -class CScript; +#include "prevector.h" static const unsigned int MAX_SIZE = 0x02000000; @@ -53,26 +53,26 @@ inline T* NCONST_PTR(const T* val) * @note These functions avoid the undefined case of indexing into an empty * vector, as well as that of indexing after the end of the vector. */ -template -inline T* begin_ptr(std::vector& v) +template +inline typename V::value_type* begin_ptr(V& v) { return v.empty() ? NULL : &v[0]; } /** Get begin pointer of vector (const version) */ -template -inline const T* begin_ptr(const std::vector& v) +template +inline const typename V::value_type* begin_ptr(const V& v) { return v.empty() ? NULL : &v[0]; } /** Get end pointer of vector (non-const version) */ -template -inline T* end_ptr(std::vector& v) +template +inline typename V::value_type* end_ptr(V& v) { return v.empty() ? NULL : (&v[0] + v.size()); } /** Get end pointer of vector (const version) */ -template -inline const T* end_ptr(const std::vector& v) +template +inline const typename V::value_type* end_ptr(const V& v) { return v.empty() ? NULL : (&v[0] + v.size()); } @@ -394,6 +394,12 @@ public: pbegin = (char*)begin_ptr(v); pend = (char*)end_ptr(v); } + template + explicit CFlatData(prevector &v) + { + pbegin = (char*)begin_ptr(v); + pend = (char*)end_ptr(v); + } char* begin() { return pbegin; } const char* begin() const { return pbegin; } char* end() { return pend; } @@ -488,6 +494,20 @@ template unsigned int GetSerializeSize(const std::basic_string& s template void Serialize(Stream& os, const std::basic_string& str, int, int=0); template void Unserialize(Stream& is, std::basic_string& str, int, int=0); +/** + * prevector + * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. + */ +template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&); +template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&); +template inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion); +template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&); +template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&); +template inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion); +template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&); +template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&); +template inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion); + /** * vector * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. @@ -502,13 +522,6 @@ template void Unserialize_impl(Stream& template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&); template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion); -/** - * others derived from vector - */ -extern inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion); -template void Serialize(Stream& os, const CScript& v, int nType, int nVersion); -template void Unserialize(Stream& is, CScript& v, int nType, int nVersion); - /** * optional */ @@ -611,6 +624,96 @@ void Unserialize(Stream& is, std::basic_string& str, int, int) +/** + * prevector + */ +template +unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&) +{ + return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); +} + +template +unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&) +{ + unsigned int nSize = GetSizeOfCompactSize(v.size()); + for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + nSize += GetSerializeSize((*vi), nType, nVersion); + return nSize; +} + +template +inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion) +{ + return GetSerializeSize_impl(v, nType, nVersion, T()); +} + + +template +void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&) +{ + WriteCompactSize(os, v.size()); + if (!v.empty()) + os.write((char*)&v[0], v.size() * sizeof(T)); +} + +template +void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&) +{ + WriteCompactSize(os, v.size()); + for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + ::Serialize(os, (*vi), nType, nVersion); +} + +template +inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion) +{ + Serialize_impl(os, v, nType, nVersion, T()); +} + + +template +void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&) +{ + // Limit size per read so bogus size value won't cause out of memory + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + while (i < nSize) + { + unsigned int blk = std::min(nSize - i, (unsigned int)(1 + 4999999 / sizeof(T))); + v.resize(i + blk); + is.read((char*)&v[i], blk * sizeof(T)); + i += blk; + } +} + +template +void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&) +{ + v.clear(); + unsigned int nSize = ReadCompactSize(is); + unsigned int i = 0; + unsigned int nMid = 0; + while (nMid < nSize) + { + nMid += 5000000 / sizeof(T); + if (nMid > nSize) + nMid = nSize; + v.resize(nMid); + for (; i < nMid; i++) + Unserialize(is, v[i], nType, nVersion); + } +} + +template +inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion) +{ + Unserialize_impl(is, v, nType, nVersion, T()); +} + + + /** * vector */ @@ -701,28 +804,6 @@ inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersio -/** - * others derived from vector - */ -inline unsigned int GetSerializeSize(const CScript& v, int nType, int nVersion) -{ - return GetSerializeSize((const std::vector&)v, nType, nVersion); -} - -template -void Serialize(Stream& os, const CScript& v, int nType, int nVersion) -{ - Serialize(os, (const std::vector&)v, nType, nVersion); -} - -template -void Unserialize(Stream& is, CScript& v, int nType, int nVersion) -{ - Unserialize(is, (std::vector&)v, nType, nVersion); -} - - - /** * optional */ diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 9b8674f04..152919510 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -360,7 +360,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; - tx.vin[0].scriptSig = CScript() << (std::vector)script; + tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end()); tx.vout[0].nValue -= 10000; hash = tx.GetHash(); mempool.addUnchecked(hash, entry.Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp new file mode 100644 index 000000000..01a45b540 --- /dev/null +++ b/src/test/prevector_tests.cpp @@ -0,0 +1,217 @@ +// Copyright (c) 2015 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include "prevector.h" +#include "random.h" + +#include "serialize.h" +#include "streams.h" + +#include "test/test_bitcoin.h" + +#include + +BOOST_FIXTURE_TEST_SUITE(PrevectorTests, TestingSetup) + +template +class prevector_tester { + typedef std::vector realtype; + realtype real_vector; + + typedef prevector pretype; + pretype pre_vector; + + typedef typename pretype::size_type Size; + + void test() { + const pretype& const_pre_vector = pre_vector; + BOOST_CHECK_EQUAL(real_vector.size(), pre_vector.size()); + BOOST_CHECK_EQUAL(real_vector.empty(), pre_vector.empty()); + for (Size s = 0; s < real_vector.size(); s++) { + BOOST_CHECK(real_vector[s] == pre_vector[s]); + BOOST_CHECK(&(pre_vector[s]) == &(pre_vector.begin()[s])); + BOOST_CHECK(&(pre_vector[s]) == &*(pre_vector.begin() + s)); + BOOST_CHECK(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size())); + } + // BOOST_CHECK(realtype(pre_vector) == real_vector); + BOOST_CHECK(pretype(real_vector.begin(), real_vector.end()) == pre_vector); + BOOST_CHECK(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector); + size_t pos = 0; + BOOST_FOREACH(const T& v, pre_vector) { + BOOST_CHECK(v == real_vector[pos++]); + } + BOOST_REVERSE_FOREACH(const T& v, pre_vector) { + BOOST_CHECK(v == real_vector[--pos]); + } + BOOST_FOREACH(const T& v, const_pre_vector) { + BOOST_CHECK(v == real_vector[pos++]); + } + BOOST_REVERSE_FOREACH(const T& v, const_pre_vector) { + BOOST_CHECK(v == real_vector[--pos]); + } + CDataStream ss1(SER_DISK, 0); + CDataStream ss2(SER_DISK, 0); + ss1 << real_vector; + ss2 << pre_vector; + BOOST_CHECK_EQUAL(ss1.size(), ss2.size()); + for (Size s = 0; s < ss1.size(); s++) { + BOOST_CHECK_EQUAL(ss1[s], ss2[s]); + } + } + +public: + void resize(Size s) { + real_vector.resize(s); + BOOST_CHECK_EQUAL(real_vector.size(), s); + pre_vector.resize(s); + BOOST_CHECK_EQUAL(pre_vector.size(), s); + test(); + } + + void reserve(Size s) { + real_vector.reserve(s); + BOOST_CHECK(real_vector.capacity() >= s); + pre_vector.reserve(s); + BOOST_CHECK(pre_vector.capacity() >= s); + test(); + } + + void insert(Size position, const T& value) { + real_vector.insert(real_vector.begin() + position, value); + pre_vector.insert(pre_vector.begin() + position, value); + test(); + } + + void insert(Size position, Size count, const T& value) { + real_vector.insert(real_vector.begin() + position, count, value); + pre_vector.insert(pre_vector.begin() + position, count, value); + test(); + } + + template + void insert_range(Size position, I first, I last) { + real_vector.insert(real_vector.begin() + position, first, last); + pre_vector.insert(pre_vector.begin() + position, first, last); + test(); + } + + void erase(Size position) { + real_vector.erase(real_vector.begin() + position); + pre_vector.erase(pre_vector.begin() + position); + test(); + } + + void erase(Size first, Size last) { + real_vector.erase(real_vector.begin() + first, real_vector.begin() + last); + pre_vector.erase(pre_vector.begin() + first, pre_vector.begin() + last); + test(); + } + + void update(Size pos, const T& value) { + real_vector[pos] = value; + pre_vector[pos] = value; + test(); + } + + void push_back(const T& value) { + real_vector.push_back(value); + pre_vector.push_back(value); + test(); + } + + void pop_back() { + real_vector.pop_back(); + pre_vector.pop_back(); + test(); + } + + void clear() { + real_vector.clear(); + pre_vector.clear(); + } + + void assign(Size n, const T& value) { + real_vector.assign(n, value); + pre_vector.assign(n, value); + } + + Size size() { + return real_vector.size(); + } + + Size capacity() { + return pre_vector.capacity(); + } + + void shrink_to_fit() { + pre_vector.shrink_to_fit(); + test(); + } +}; + +BOOST_AUTO_TEST_CASE(PrevectorTestInt) +{ + for (int j = 0; j < 64; j++) { + prevector_tester<8, int> test; + for (int i = 0; i < 2048; i++) { + int r = insecure_rand(); + if ((r % 4) == 0) { + test.insert(insecure_rand() % (test.size() + 1), insecure_rand()); + } + if (test.size() > 0 && ((r >> 2) % 4) == 1) { + test.erase(insecure_rand() % test.size()); + } + if (((r >> 4) % 8) == 2) { + int new_size = std::max(0, std::min(30, test.size() + (insecure_rand() % 5) - 2)); + test.resize(new_size); + } + if (((r >> 7) % 8) == 3) { + test.insert(insecure_rand() % (test.size() + 1), 1 + (insecure_rand() % 2), insecure_rand()); + } + if (((r >> 10) % 8) == 4) { + int del = std::min(test.size(), 1 + (insecure_rand() % 2)); + int beg = insecure_rand() % (test.size() + 1 - del); + test.erase(beg, beg + del); + } + if (((r >> 13) % 16) == 5) { + test.push_back(insecure_rand()); + } + if (test.size() > 0 && ((r >> 17) % 16) == 6) { + test.pop_back(); + } + if (((r >> 21) % 32) == 7) { + int values[4]; + int num = 1 + (insecure_rand() % 4); + for (int i = 0; i < num; i++) { + values[i] = insecure_rand(); + } + test.insert_range(insecure_rand() % (test.size() + 1), values, values + num); + } + if (((r >> 26) % 32) == 8) { + int del = std::min(test.size(), 1 + (insecure_rand() % 4)); + int beg = insecure_rand() % (test.size() + 1 - del); + test.erase(beg, beg + del); + } + r = insecure_rand(); + if (r % 32 == 9) { + test.reserve(insecure_rand() % 32); + } + if ((r >> 5) % 64 == 10) { + test.shrink_to_fit(); + } + if (test.size() > 0) { + test.update(insecure_rand() % test.size(), insecure_rand()); + } + if (((r >> 11) & 1024) == 11) { + test.clear(); + } + if (((r >> 21) & 512) == 12) { + test.assign(insecure_rand() % 32, insecure_rand()); + } + } + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index ea60fe452..fac63dbf5 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -27,7 +27,7 @@ using namespace std; static std::vector Serialize(const CScript& s) { - std::vector sSerialized(s); + std::vector sSerialized(s.begin(), s.end()); return sSerialized; } @@ -355,8 +355,8 @@ BOOST_DATA_TEST_CASE(AreInputsStandard, boost::unit_test::data::xrange(static_ca // SignSignature doesn't know how to sign these. We're // not testing validating signatures, so just create // dummy signatures that DO include the correct P2SH scripts: - txTo.vin[3].scriptSig << OP_11 << OP_11 << static_cast >(oneAndTwo); - txTo.vin[4].scriptSig << static_cast >(fifteenSigops); + txTo.vin[3].scriptSig << OP_11 << OP_11 << vector(oneAndTwo.begin(), oneAndTwo.end()); + txTo.vin[4].scriptSig << vector(fifteenSigops.begin(), fifteenSigops.end()); BOOST_CHECK(::AreInputsStandard(txTo, coins, consensusBranchId)); // 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4] @@ -378,7 +378,7 @@ BOOST_DATA_TEST_CASE(AreInputsStandard, boost::unit_test::data::xrange(static_ca txToNonStd1.vin.resize(1); txToNonStd1.vin[0].prevout.n = 5; txToNonStd1.vin[0].prevout.hash = txFrom.GetHash(); - txToNonStd1.vin[0].scriptSig << static_cast >(sixteenSigops); + txToNonStd1.vin[0].scriptSig << vector(sixteenSigops.begin(), sixteenSigops.end()); BOOST_CHECK(!::AreInputsStandard(txToNonStd1, coins, consensusBranchId)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd1, coins), 16U); @@ -390,7 +390,7 @@ BOOST_DATA_TEST_CASE(AreInputsStandard, boost::unit_test::data::xrange(static_ca txToNonStd2.vin.resize(1); txToNonStd2.vin[0].prevout.n = 6; txToNonStd2.vin[0].prevout.hash = txFrom.GetHash(); - txToNonStd2.vin[0].scriptSig << static_cast >(twentySigops); + txToNonStd2.vin[0].scriptSig << vector(twentySigops.begin(), twentySigops.end()); BOOST_CHECK(!::AreInputsStandard(txToNonStd2, coins, consensusBranchId)); BOOST_CHECK_EQUAL(GetP2SHSigOpCount(txToNonStd2, coins), 20U); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 772457c99..4e8388358 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -264,7 +264,7 @@ public: TestBuilder& PushRedeem() { - DoPush(static_cast >(scriptPubKey)); + DoPush(std::vector(scriptPubKey.begin(), scriptPubKey.end())); return *this; } @@ -864,7 +864,7 @@ BOOST_DATA_TEST_CASE(script_combineSigs, boost::unit_test::data::xrange(static_c combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSigCopy || combined.scriptSig == scriptSig); // dummy scriptSigCopy with placeholder, should always choose non-placeholder: - scriptSigCopy = CScript() << OP_0 << static_cast >(pkSingle); + scriptSigCopy = CScript() << OP_0 << vector(pkSingle.begin(), pkSingle.end()); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSigCopy), SignatureData(scriptSig), consensusBranchId); BOOST_CHECK(combined.scriptSig == scriptSig); combined = CombineSignatures(scriptPubKey, MutableTransactionSignatureChecker(&txTo, 0, amount), SignatureData(scriptSig), SignatureData(scriptSigCopy), consensusBranchId); diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index b26fed99f..ea2b9b795 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -20,7 +20,7 @@ using namespace std; static std::vector Serialize(const CScript& s) { - std::vector sSerialized(s); + std::vector sSerialized(s.begin(), s.end()); return sSerialized; } diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 4bf191380..dc1b40d95 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -157,19 +157,19 @@ bool CWalletDB::EraseViewingKey(const libzcash::ViewingKey &vk) bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("cscript"), hash), redeemScript, false); + return Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false); } bool CWalletDB::WriteWatchOnly(const CScript &dest) { nWalletDBUpdated++; - return Write(std::make_pair(std::string("watchs"), dest), '1'); + return Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1'); } bool CWalletDB::EraseWatchOnly(const CScript &dest) { nWalletDBUpdated++; - return Erase(std::make_pair(std::string("watchs"), dest)); + return Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest))); } bool CWalletDB::WriteBestBlock(const CBlockLocator& locator) @@ -473,7 +473,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, else if (strType == "watchs") { CScript script; - ssKey >> script; + ssKey >> *(CScriptBase*)(&script); char fYes; ssValue >> fYes; if (fYes == '1') @@ -681,7 +681,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, uint160 hash; ssKey >> hash; CScript script; - ssValue >> script; + ssValue >> *(CScriptBase*)(&script); if (!pwallet->LoadCScript(script)) { strErr = "Error reading wallet database: LoadCScript failed"; From d2fb34fb7ca56e612bfc619224aa27cd914aeb55 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 9 Mar 2018 12:05:21 +0000 Subject: [PATCH 03/20] Handle usage of prevector for CScript in Zcash-specific code --- src/gtest/test_foundersreward.cpp | 6 +++--- src/script/interpreter.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp index b5e8acc18..8ffe51280 100644 --- a/src/gtest/test_foundersreward.cpp +++ b/src/gtest/test_foundersreward.cpp @@ -106,11 +106,11 @@ TEST(founders_reward_test, general) { // address = t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy // script.ToString() = OP_HASH160 55d64928e69829d9376c776550b6cc710d427153 OP_EQUAL // HexStr(script) = a91455d64928e69829d9376c776550b6cc710d42715387 - EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(1), ParseHex("a914ef775f1f997f122a062fff1a2d7443abd1f9c64287")); + EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(1)), "a914ef775f1f997f122a062fff1a2d7443abd1f9c64287"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(1), "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi"); - EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53126), ParseHex("a914ac67f4c072668138d88a86ff21b27207b283212f87")); + EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53126)), "a914ac67f4c072668138d88a86ff21b27207b283212f87"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53126), "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2"); - EXPECT_EQ(params.GetFoundersRewardScriptAtHeight(53127), ParseHex("a91455d64928e69829d9376c776550b6cc710d42715387")); + EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53127)), "a91455d64928e69829d9376c776550b6cc710d42715387"); EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53127), "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy"); int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 9237a9af9..8e46d96b8 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1191,7 +1191,7 @@ uint256 SignatureHash( // The prevout may already be contained in hashPrevout, and the nSequence // may already be contained in hashSequence. ss << txTo.vin[nIn].prevout; - ss << scriptCode; + ss << static_cast(scriptCode); ss << amount; ss << txTo.vin[nIn].nSequence; } From 6cbe2c482c1fc62dfc7d2ad9f32fc1037dbced7f Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Mon, 1 Jun 2015 16:35:19 +0200 Subject: [PATCH 04/20] add bip32 pubkey serialization CExtPubKey should be serializable like CPubKey --- src/base58.h | 4 ++-- src/key.cpp | 6 +++--- src/key.h | 21 +++++++++++++++++++-- src/pubkey.cpp | 6 +++--- src/pubkey.h | 30 ++++++++++++++++++++++++++++-- src/test/bip32_tests.cpp | 16 ++++++++++++++++ 6 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/base58.h b/src/base58.h index 24e7abfc8..8b82c6393 100644 --- a/src/base58.h +++ b/src/base58.h @@ -211,7 +211,7 @@ public: CBitcoinExtKeyBase() {} }; -typedef CBitcoinExtKeyBase CBitcoinExtKey; -typedef CBitcoinExtKeyBase CBitcoinExtPubKey; +typedef CBitcoinExtKeyBase CBitcoinExtKey; +typedef CBitcoinExtKeyBase CBitcoinExtPubKey; #endif // BITCOIN_BASE58_H diff --git a/src/key.cpp b/src/key.cpp index c93f8d15d..5688b1302 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -307,7 +307,7 @@ CExtPubKey CExtKey::Neuter() const { return ret; } -void CExtKey::Encode(unsigned char code[74]) const { +void CExtKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; memcpy(code+1, vchFingerprint, 4); code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; @@ -318,12 +318,12 @@ void CExtKey::Encode(unsigned char code[74]) const { memcpy(code+42, key.begin(), 32); } -void CExtKey::Decode(const unsigned char code[74]) { +void CExtKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; memcpy(vchFingerprint, code+1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; memcpy(chaincode.begin(), code+9, 32); - key.Set(code+42, code+74, true); + key.Set(code+42, code+BIP32_EXTKEY_SIZE, true); } bool ECC_InitSanityCheck() { diff --git a/src/key.h b/src/key.h index c2b75935c..d07bac91b 100644 --- a/src/key.h +++ b/src/key.h @@ -170,11 +170,28 @@ struct CExtKey { a.chaincode == b.chaincode && a.key == b.key; } - void Encode(unsigned char code[74]) const; - void Decode(const unsigned char code[74]); + void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; + void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; void SetMaster(const unsigned char* seed, unsigned int nSeedLen); + template + void Serialize(Stream& s, int nType, int nVersion) const + { + unsigned int len = BIP32_EXTKEY_SIZE; + ::WriteCompactSize(s, len); + unsigned char code[BIP32_EXTKEY_SIZE]; + Encode(code); + s.write((const char *)&code[0], len); + } + template + void Unserialize(Stream& s, int nType, int nVersion) + { + unsigned int len = ::ReadCompactSize(s); + unsigned char code[BIP32_EXTKEY_SIZE]; + s.read((char *)&code[0], len); + Decode(code); + } }; /** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 0b87bb526..53e94fbdb 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -98,7 +98,7 @@ bool CPubKey::Derive(CPubKey& pubkeyChild, ChainCode &ccChild, unsigned int nChi return true; } -void CExtPubKey::Encode(unsigned char code[74]) const { +void CExtPubKey::Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const { code[0] = nDepth; memcpy(code+1, vchFingerprint, 4); code[5] = (nChild >> 24) & 0xFF; code[6] = (nChild >> 16) & 0xFF; @@ -108,12 +108,12 @@ void CExtPubKey::Encode(unsigned char code[74]) const { memcpy(code+41, pubkey.begin(), CPubKey::COMPRESSED_PUBLIC_KEY_SIZE); } -void CExtPubKey::Decode(const unsigned char code[74]) { +void CExtPubKey::Decode(const unsigned char code[BIP32_EXTKEY_SIZE]) { nDepth = code[0]; memcpy(vchFingerprint, code+1, 4); nChild = (code[5] << 24) | (code[6] << 16) | (code[7] << 8) | code[8]; memcpy(chaincode.begin(), code+9, 32); - pubkey.Set(code+41, code+74); + pubkey.Set(code+41, code+BIP32_EXTKEY_SIZE); } bool CExtPubKey::Derive(CExtPubKey &out, unsigned int nChild) const { diff --git a/src/pubkey.h b/src/pubkey.h index 237237e05..a7aeac4c7 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -14,6 +14,8 @@ #include #include +const unsigned int BIP32_EXTKEY_SIZE = 74; + /** A reference to a CKey: the Hash160 of its serialized public key */ class CKeyID : public uint160 { @@ -212,9 +214,33 @@ struct CExtPubKey { a.chaincode == b.chaincode && a.pubkey == b.pubkey; } - void Encode(unsigned char code[74]) const; - void Decode(const unsigned char code[74]); + void Encode(unsigned char code[BIP32_EXTKEY_SIZE]) const; + void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtPubKey& out, unsigned int nChild) const; + + unsigned int GetSerializeSize(int nType, int nVersion) const + { + return BIP32_EXTKEY_SIZE+1; //add one byte for the size (compact int) + } + template + void Serialize(Stream& s, int nType, int nVersion) const + { + unsigned int len = BIP32_EXTKEY_SIZE; + ::WriteCompactSize(s, len); + unsigned char code[BIP32_EXTKEY_SIZE]; + Encode(code); + s.write((const char *)&code[0], len); + } + template + void Unserialize(Stream& s, int nType, int nVersion) + { + unsigned int len = ::ReadCompactSize(s); + unsigned char code[BIP32_EXTKEY_SIZE]; + if (len != BIP32_EXTKEY_SIZE) + throw std::runtime_error("Invalid extended key size\n"); + s.read((char *)&code[0], len); + Decode(code); + } }; /** Users of this module must hold an ECCVerifyHandle. The constructor and diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 69084213a..41b541747 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -117,6 +117,22 @@ void RunTest(const TestVector &test) { } key = keyNew; pubkey = pubkeyNew; + + CDataStream ssPub(SER_DISK, CLIENT_VERSION); + ssPub << pubkeyNew; + BOOST_CHECK(ssPub.size() == 75); + + CDataStream ssPriv(SER_DISK, CLIENT_VERSION); + ssPriv << keyNew; + BOOST_CHECK(ssPriv.size() == 75); + + CExtPubKey pubCheck; + CExtKey privCheck; + ssPub >> pubCheck; + ssPriv >> privCheck; + + BOOST_CHECK(pubCheck == pubkeyNew); + BOOST_CHECK(privCheck == keyNew); } } From c803fa10947f1fa051e4d6b3b461470620f22a62 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 18 May 2016 13:11:42 -0700 Subject: [PATCH 05/20] Add COMPACTSIZE wrapper similar to VARINT for serialization --- src/serialize.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/serialize.h b/src/serialize.h index a63b7a64e..bf5ce49d5 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -376,6 +376,7 @@ I ReadVarInt(Stream& is) #define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj))) #define VARINT(obj) REF(WrapVarInt(REF(obj))) +#define COMPACTSIZE(obj) REF(CCompactSize(REF(obj))) #define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj))) /** @@ -446,6 +447,28 @@ public: } }; +class CCompactSize +{ +protected: + uint64_t &n; +public: + CCompactSize(uint64_t& nIn) : n(nIn) { } + + unsigned int GetSerializeSize(int, int) const { + return GetSizeOfCompactSize(n); + } + + template + void Serialize(Stream &s, int, int) const { + WriteCompactSize(s, n); + } + + template + void Unserialize(Stream& s, int, int) { + n = ReadCompactSize(s); + } +}; + template class LimitedString { From ead36d85c7fbc5349047da7c0ce5d47374980da4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20Jan=C3=ADk?= Date: Fri, 2 Sep 2016 22:05:47 +0200 Subject: [PATCH 06/20] [WIP] Remove unused statement in serialization Zcash: Excludes changes to CBanEntry and CHDChain, which we don't have yet. --- src/wallet/wallet.h | 1 - src/wallet/walletdb.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 407c81ffc..3530d7632 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -316,7 +316,6 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(*(CTransaction*)this); - nVersion = this->nVersion; READWRITE(hashBlock); READWRITE(vMerkleBranch); READWRITE(nIndex); diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index e455ad953..a977e17ee 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -62,7 +62,6 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(this->nVersion); - nVersion = this->nVersion; READWRITE(nCreateTime); } From d1c9ef86067a858bb3ab942a5a9a7bb26de91607 Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Mon, 12 Sep 2016 14:38:01 -0400 Subject: [PATCH 07/20] serialization: teach serializers variadics Also add a variadic CDataStream ctor for ease-of-use. --- src/serialize.h | 49 +++++++++++++++++++++++++ src/streams.h | 11 ++++++ src/test/serialize_tests.cpp | 70 ++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/src/serialize.h b/src/serialize.h index bf5ce49d5..185d5e109 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -165,6 +165,7 @@ enum }; #define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) +#define READWRITEMANY(...) (::SerReadWriteMany(s, nType, nVersion, ser_action, __VA_ARGS__)) /** * Implement three methods for serializable objects. These are actually wrappers over @@ -1098,4 +1099,52 @@ public: } }; +template +void SerializeMany(Stream& s, int nType, int nVersion) +{ +} + +template +void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg) +{ + ::Serialize(s, std::forward(arg), nType, nVersion); +} + +template +void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg, Args&&... args) +{ + ::Serialize(s, std::forward(arg), nType, nVersion); + ::SerializeMany(s, nType, nVersion, std::forward(args)...); +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion) +{ +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg) +{ + ::Unserialize(s, arg, nType, nVersion); +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg, Args&... args) +{ + ::Unserialize(s, arg, nType, nVersion); + ::UnserializeMany(s, nType, nVersion, args...); +} + +template +inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionSerialize ser_action, Args&&... args) +{ + ::SerializeMany(s, nType, nVersion, std::forward(args)...); +} + +template +inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionUnserialize ser_action, Args&... args) +{ + ::UnserializeMany(s, nType, nVersion, args...); +} + #endif // BITCOIN_SERIALIZE_H diff --git a/src/streams.h b/src/streams.h index 81b58fd05..37945bfc9 100644 --- a/src/streams.h +++ b/src/streams.h @@ -80,6 +80,13 @@ public: Init(nTypeIn, nVersionIn); } + template + CBaseDataStream(int nTypeIn, int nVersionIn, Args&&... args) + { + Init(nTypeIn, nVersionIn); + ::SerializeMany(*this, nType, nVersion, std::forward(args)...); + } + void Init(int nTypeIn, int nVersionIn) { nReadPos = 0; @@ -323,6 +330,10 @@ public: CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : CBaseDataStream(vchIn, nTypeIn, nVersionIn) { } + template + CDataStream(int nTypeIn, int nVersionIn, Args&&... args) : + CBaseDataStream(nTypeIn, nVersionIn, args...) { } + }; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index d3e51c7d1..59a42d0a9 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -36,6 +36,50 @@ void check_ser_rep(T thing, std::vector expected) BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) +class CSerializeMethodsTestSingle +{ +protected: + int intval; + bool boolval; + std::string stringval; + const char* charstrval; + CTransaction txval; +public: + CSerializeMethodsTestSingle() = default; + CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), charstrval(charstrvalin), txval(txvalin){} + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(intval); + READWRITE(boolval); + READWRITE(stringval); + READWRITE(FLATDATA(charstrval)); + READWRITE(txval); + } + + bool operator==(const CSerializeMethodsTestSingle& rhs) + { + return intval == rhs.intval && \ + boolval == rhs.boolval && \ + stringval == rhs.stringval && \ + strcmp(charstrval, rhs.charstrval) == 0 && \ + txval == rhs.txval; + } +}; + +class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle +{ +public: + using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle; + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval); + } +}; + BOOST_AUTO_TEST_CASE(boost_optional) { check_ser_rep>(0xff, {0x01, 0xff}); @@ -346,4 +390,30 @@ BOOST_AUTO_TEST_CASE(insert_delete) BOOST_CHECK_EQUAL(ss.size(), 0); } +BOOST_AUTO_TEST_CASE(class_methods) +{ + int intval(100); + bool boolval(true); + std::string stringval("testing"); + const char* charstrval("testing charstr"); + CMutableTransaction txval; + CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval); + CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval); + CSerializeMethodsTestSingle methodtest3; + CSerializeMethodsTestMany methodtest4; + CDataStream ss(SER_DISK, PROTOCOL_VERSION); + BOOST_CHECK(methodtest1 == methodtest2); + ss << methodtest1; + ss >> methodtest4; + ss << methodtest2; + ss >> methodtest3; + BOOST_CHECK(methodtest1 == methodtest2); + BOOST_CHECK(methodtest2 == methodtest3); + BOOST_CHECK(methodtest3 == methodtest4); + + CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, FLATDATA(charstrval), txval); + ss2 >> methodtest3; + BOOST_CHECK(methodtest3 == methodtest4); +} + BOOST_AUTO_TEST_SUITE_END() From 670a7686a6d0898b4ff257a6cc8ce53a6e8d9057 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 16:53:00 -0700 Subject: [PATCH 08/20] Remove unused ReadVersion and WriteVersion CDataStream and CAutoFile had a ReadVersion and WriteVersion method that was never used. Remove them. --- src/streams.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/streams.h b/src/streams.h index 37945bfc9..48c9f1880 100644 --- a/src/streams.h +++ b/src/streams.h @@ -222,8 +222,6 @@ public: int GetType() { return nType; } void SetVersion(int n) { nVersion = n; } int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } CBaseDataStream& read(char* pch, size_t nSize) { @@ -407,8 +405,6 @@ public: int GetType() { return nType; } void SetVersion(int n) { nVersion = n; } int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } CAutoFile& read(char* pch, size_t nSize) { From 1315591c852aa4e470824eea5ccfa60009c50065 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 21:55:12 -0700 Subject: [PATCH 09/20] Make streams' read and write return void The stream implementations had two cascading layers (the upper one with operator<< and operator>>, and a lower one with read and write). The lower layer's functions are never cascaded (nor should they, as they should only be used from the higher layer), so make them return void instead. --- src/hash.h | 3 +-- src/script/zcashconsensus.cpp | 3 +-- src/serialize.h | 3 +-- src/streams.h | 25 +++++++++---------------- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/hash.h b/src/hash.h index fa1ba4d1e..29f828e87 100644 --- a/src/hash.h +++ b/src/hash.h @@ -140,9 +140,8 @@ public: CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {} - CHashWriter& write(const char *pch, size_t size) { + void write(const char *pch, size_t size) { ctx.Write((const unsigned char*)pch, size); - return (*this); } // invalidates the object diff --git a/src/script/zcashconsensus.cpp b/src/script/zcashconsensus.cpp index dbec305fc..edfb84359 100644 --- a/src/script/zcashconsensus.cpp +++ b/src/script/zcashconsensus.cpp @@ -24,7 +24,7 @@ public: m_remaining(txToLen) {} - TxInputStream& read(char* pch, size_t nSize) + void read(char* pch, size_t nSize) { if (nSize > m_remaining) throw std::ios_base::failure(std::string(__func__) + ": end of data"); @@ -38,7 +38,6 @@ public: memcpy(pch, m_data, nSize); m_remaining -= nSize; m_data += nSize; - return *this; } template diff --git a/src/serialize.h b/src/serialize.h index 185d5e109..42b6721c5 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1081,10 +1081,9 @@ public: CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} - CSizeComputer& write(const char *psz, size_t nSize) + void write(const char *psz, size_t nSize) { this->nSize += nSize; - return *this; } template diff --git a/src/streams.h b/src/streams.h index 48c9f1880..77a9f1821 100644 --- a/src/streams.h +++ b/src/streams.h @@ -223,7 +223,7 @@ public: void SetVersion(int n) { nVersion = n; } int GetVersion() { return nVersion; } - CBaseDataStream& read(char* pch, size_t nSize) + void read(char* pch, size_t nSize) { // Read from the beginning of the buffer unsigned int nReadPosNext = nReadPos + nSize; @@ -236,14 +236,13 @@ public: memcpy(pch, &vch[nReadPos], nSize); nReadPos = 0; vch.clear(); - return (*this); + return; } memcpy(pch, &vch[nReadPos], nSize); nReadPos = nReadPosNext; - return (*this); } - CBaseDataStream& ignore(int nSize) + void ignore(int nSize) { // Ignore from the beginning of the buffer if (nSize < 0) { @@ -256,17 +255,15 @@ public: throw std::ios_base::failure("CBaseDataStream::ignore(): end of data"); nReadPos = 0; vch.clear(); - return (*this); + return; } nReadPos = nReadPosNext; - return (*this); } - CBaseDataStream& write(const char* pch, size_t nSize) + void write(const char* pch, size_t nSize) { // Write to the end of the buffer vch.insert(vch.end(), pch, pch + nSize); - return (*this); } template @@ -406,16 +403,15 @@ public: void SetVersion(int n) { nVersion = n; } int GetVersion() { return nVersion; } - CAutoFile& read(char* pch, size_t nSize) + void read(char* pch, size_t nSize) { if (!file) throw std::ios_base::failure("CAutoFile::read: file handle is NULL"); if (fread(pch, 1, nSize, file) != nSize) throw std::ios_base::failure(feof(file) ? "CAutoFile::read: end of file" : "CAutoFile::read: fread failed"); - return (*this); } - CAutoFile& ignore(size_t nSize) + void ignore(size_t nSize) { if (!file) throw std::ios_base::failure("CAutoFile::ignore: file handle is NULL"); @@ -426,16 +422,14 @@ public: throw std::ios_base::failure(feof(file) ? "CAutoFile::ignore: end of file" : "CAutoFile::read: fread failed"); nSize -= nNow; } - return (*this); } - CAutoFile& write(const char* pch, size_t nSize) + void write(const char* pch, size_t nSize) { if (!file) throw std::ios_base::failure("CAutoFile::write: file handle is NULL"); if (fwrite(pch, 1, nSize, file) != nSize) throw std::ios_base::failure("CAutoFile::write: write failed"); - return (*this); } template @@ -536,7 +530,7 @@ public: } // read a number of bytes - CBufferedFile& read(char *pch, size_t nSize) { + void read(char *pch, size_t nSize) { if (nSize + nReadPos > nReadLimit) throw std::ios_base::failure("Read attempted past buffer limit"); if (nSize + nRewind > vchBuf.size()) @@ -555,7 +549,6 @@ public: pch += nNow; nSize -= nNow; } - return (*this); } // return the current reading position From 7f4acac433e8052ed7f10f93b20042a811f2e7be Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 16:57:24 -0700 Subject: [PATCH 10/20] Make nType and nVersion private and sometimes const Make the various stream implementations' nType and nVersion private and const (except in CDataStream where we really need a setter). --- src/hash.h | 4 ++-- src/serialize.h | 4 ++-- src/streams.h | 31 +++++++++++++------------------ 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/hash.h b/src/hash.h index 29f828e87..1d28d6bdf 100644 --- a/src/hash.h +++ b/src/hash.h @@ -134,9 +134,9 @@ class CHashWriter private: CHash256 ctx; + const int nType; + const int nVersion; public: - int nType; - int nVersion; CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {} diff --git a/src/serialize.h b/src/serialize.h index 42b6721c5..ea4cc903a 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1075,9 +1075,9 @@ class CSizeComputer protected: size_t nSize; + const int nType; + const int nVersion; public: - int nType; - int nVersion; CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} diff --git a/src/streams.h b/src/streams.h index 77a9f1821..7aef8a0aa 100644 --- a/src/streams.h +++ b/src/streams.h @@ -34,9 +34,10 @@ protected: typedef SerializeType vector_type; vector_type vch; unsigned int nReadPos; -public: + int nType; int nVersion; +public: typedef typename vector_type::allocator_type allocator_type; typedef typename vector_type::size_type size_type; @@ -219,9 +220,9 @@ public: int in_avail() { return size(); } void SetType(int n) { nType = n; } - int GetType() { return nType; } + int GetType() const { return nType; } void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } + int GetVersion() const { return nVersion; } void read(char* pch, size_t nSize) { @@ -353,17 +354,15 @@ private: CAutoFile(const CAutoFile&); CAutoFile& operator=(const CAutoFile&); - int nType; - int nVersion; - + const int nType; + const int nVersion; + FILE* file; public: - CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) + CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) { file = filenew; - nType = nTypeIn; - nVersion = nVersionIn; } ~CAutoFile() @@ -398,10 +397,8 @@ public: // // Stream subset // - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } + int GetType() const { return nType; } + int GetVersion() const { return nVersion; } void read(char* pch, size_t nSize) { @@ -473,8 +470,8 @@ private: CBufferedFile(const CBufferedFile&); CBufferedFile& operator=(const CBufferedFile&); - int nType; - int nVersion; + const int nType; + const int nVersion; FILE *src; // source file uint64_t nSrcPos; // how many bytes have been read from source @@ -504,11 +501,9 @@ protected: public: CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) : - nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0) + nType(nTypeIn), nVersion(nVersionIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0) { src = fileIn; - nType = nTypeIn; - nVersion = nVersionIn; } ~CBufferedFile() From b8a6579366711127364b807ab62db391eee7d07a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 16:51:33 -0700 Subject: [PATCH 11/20] Make GetSerializeSize a wrapper on top of CSizeComputer Given that in default GetSerializeSize implementations created by ADD_SERIALIZE_METHODS we're already using CSizeComputer(), get rid of the specialized GetSerializeSize methods everywhere, and just use CSizeComputer. This removes a lot of code which isn't actually used anywhere. For CCompactSize and CVarInt this actually removes a more efficient size computing algorithm, which is brought back in a later commit. --- src/addrman.h | 5 -- src/coins.h | 23 ------ src/compressor.h | 8 -- src/dbwrapper.h | 10 +-- src/main.cpp | 4 +- src/primitives/transaction.h | 2 +- src/pubkey.h | 8 -- src/script/zcashconsensus.cpp | 2 +- src/serialize.h | 138 +++------------------------------- src/streams.h | 14 ---- src/test/uint256_tests.cpp | 8 +- src/uint256.h | 5 -- src/undo.h | 6 -- 13 files changed, 25 insertions(+), 208 deletions(-) diff --git a/src/addrman.h b/src/addrman.h index 0483e8bdb..7753f1822 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -434,11 +434,6 @@ public: Check(); } - unsigned int GetSerializeSize(int nType, int nVersion) const - { - return (CSizeComputer(nType, nVersion) << *this).size(); - } - void Clear() { std::vector().swap(vRandom); diff --git a/src/coins.h b/src/coins.h index a2bd78893..52b724193 100644 --- a/src/coins.h +++ b/src/coins.h @@ -153,29 +153,6 @@ public: return fCoinBase; } - unsigned int GetSerializeSize(int nType, int nVersion) const { - unsigned int nSize = 0; - unsigned int nMaskSize = 0, nMaskCode = 0; - CalcMaskSize(nMaskSize, nMaskCode); - bool fFirst = vout.size() > 0 && !vout[0].IsNull(); - bool fSecond = vout.size() > 1 && !vout[1].IsNull(); - assert(fFirst || fSecond || nMaskCode); - unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); - // version - nSize += ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion); - // size of header code - nSize += ::GetSerializeSize(VARINT(nCode), nType, nVersion); - // spentness bitmask - nSize += nMaskSize; - // txouts - for (unsigned int i = 0; i < vout.size(); i++) - if (!vout[i].IsNull()) - nSize += ::GetSerializeSize(CTxOutCompressor(REF(vout[i])), nType, nVersion); - // height - nSize += ::GetSerializeSize(VARINT(nHeight), nType, nVersion); - return nSize; - } - template void Serialize(Stream &s, int nType, int nVersion) const { unsigned int nMaskSize = 0, nMaskCode = 0; diff --git a/src/compressor.h b/src/compressor.h index fa702f0df..90749499d 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -55,14 +55,6 @@ protected: public: CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } - unsigned int GetSerializeSize(int nType, int nVersion) const { - std::vector compr; - if (Compress(compr)) - return compr.size(); - unsigned int nSize = script.size() + nSpecialScripts; - return script.size() + VARINT(nSize).GetSerializeSize(nType, nVersion); - } - template void Serialize(Stream &s, int nType, int nVersion) const { std::vector compr; diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 1f3b4fc16..40ed9e583 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -53,12 +53,12 @@ public: void Write(const K& key, const V& value) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(GetSerializeSize(ssKey, key)); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue.reserve(ssValue.GetSerializeSize(value)); + ssValue.reserve(GetSerializeSize(ssValue, value)); ssValue << value; leveldb::Slice slValue(&ssValue[0], ssValue.size()); @@ -69,7 +69,7 @@ public: void Erase(const K& key) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(GetSerializeSize(ssKey, key)); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); @@ -177,7 +177,7 @@ public: bool Read(const K& key, V& value) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(GetSerializeSize(ssKey, key)); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); @@ -210,7 +210,7 @@ public: bool Exists(const K& key) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(GetSerializeSize(ssKey, key)); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); diff --git a/src/main.cpp b/src/main.cpp index 587032547..7a401e673 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1480,7 +1480,7 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::M return error("WriteBlockToDisk: OpenBlockFile failed"); // Write index header - unsigned int nSize = fileout.GetSerializeSize(block); + unsigned int nSize = GetSerializeSize(fileout, block); fileout << FLATDATA(messageStart) << nSize; // Write block @@ -1913,7 +1913,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint return error("%s: OpenUndoFile failed", __func__); // Write index header - unsigned int nSize = fileout.GetSerializeSize(blockundo); + unsigned int nSize = GetSerializeSize(fileout, blockundo); fileout << FLATDATA(messageStart) << nSize; // Write undo data diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index adc957433..5e4f4a526 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -281,7 +281,7 @@ public: if (scriptPubKey.IsUnspendable()) return 0; - size_t nSize = GetSerializeSize(SER_DISK,0)+148u; + size_t nSize = GetSerializeSize(*this, SER_DISK, 0) + 148u; return 3*minRelayTxFee.GetFee(nSize); } diff --git a/src/pubkey.h b/src/pubkey.h index a7aeac4c7..3589cbd16 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -123,10 +123,6 @@ public: } //! Implement serialization, as if this was a byte vector. - unsigned int GetSerializeSize(int nType, int nVersion) const - { - return size() + 1; - } template void Serialize(Stream& s, int nType, int nVersion) const { @@ -218,10 +214,6 @@ struct CExtPubKey { void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtPubKey& out, unsigned int nChild) const; - unsigned int GetSerializeSize(int nType, int nVersion) const - { - return BIP32_EXTKEY_SIZE+1; //add one byte for the size (compact int) - } template void Serialize(Stream& s, int nType, int nVersion) const { diff --git a/src/script/zcashconsensus.cpp b/src/script/zcashconsensus.cpp index edfb84359..daf445d34 100644 --- a/src/script/zcashconsensus.cpp +++ b/src/script/zcashconsensus.cpp @@ -79,7 +79,7 @@ int zcashconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int stream >> tx; if (nIn >= tx.vin.size()) return set_error(err, zcashconsensus_ERR_TX_INDEX); - if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen) + if (GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) != txToLen) return set_error(err, zcashconsensus_ERR_TX_SIZE_MISMATCH); // Regardless of the verification result, the tx did not error. diff --git a/src/serialize.h b/src/serialize.h index ea4cc903a..da80b7630 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -174,11 +174,6 @@ enum * added as members. */ #define ADD_SERIALIZE_METHODS \ - size_t GetSerializeSize(int nType, int nVersion) const { \ - CSizeComputer s(nType, nVersion); \ - NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ - return s.size(); \ - } \ template \ void Serialize(Stream& s, int nType, int nVersion) const { \ NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ @@ -191,18 +186,6 @@ enum /* * Basic Types */ -inline unsigned int GetSerializeSize(char a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(int8_t a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(uint8_t a, int, int=0) { return 1; } -inline unsigned int GetSerializeSize(int16_t a, int, int=0) { return 2; } -inline unsigned int GetSerializeSize(uint16_t a, int, int=0) { return 2; } -inline unsigned int GetSerializeSize(int32_t a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(uint32_t a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(int64_t a, int, int=0) { return 8; } -inline unsigned int GetSerializeSize(uint64_t a, int, int=0) { return 8; } -inline unsigned int GetSerializeSize(float a, int, int=0) { return 4; } -inline unsigned int GetSerializeSize(double a, int, int=0) { return 8; } - template inline void Serialize(Stream& s, char a, int, int=0) { ser_writedata8(s, a); } // TODO Get rid of bare char template inline void Serialize(Stream& s, int8_t a, int, int=0) { ser_writedata8(s, a); } template inline void Serialize(Stream& s, uint8_t a, int, int=0) { ser_writedata8(s, a); } @@ -227,7 +210,6 @@ template inline void Unserialize(Stream& s, uint64_t& a, int, template inline void Unserialize(Stream& s, float& a, int, int=0) { a = ser_uint32_to_float(ser_readdata32(s)); } template inline void Unserialize(Stream& s, double& a, int, int=0) { a = ser_uint64_to_double(ser_readdata64(s)); } -inline unsigned int GetSerializeSize(bool a, int, int=0) { return sizeof(char); } template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; ser_writedata8(s, f); } template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f=ser_readdata8(s); a=f; } @@ -407,11 +389,6 @@ public: char* end() { return pend; } const char* end() const { return pend; } - unsigned int GetSerializeSize(int, int=0) const - { - return pend - pbegin; - } - template void Serialize(Stream& s, int, int=0) const { @@ -433,10 +410,6 @@ protected: public: CVarInt(I& nIn) : n(nIn) { } - unsigned int GetSerializeSize(int, int) const { - return GetSizeOfVarInt(n); - } - template void Serialize(Stream &s, int, int) const { WriteVarInt(s, n); @@ -455,10 +428,6 @@ protected: public: CCompactSize(uint64_t& nIn) : n(nIn) { } - unsigned int GetSerializeSize(int, int) const { - return GetSizeOfCompactSize(n); - } - template void Serialize(Stream &s, int, int) const { WriteCompactSize(s, n); @@ -497,11 +466,6 @@ public: if (!string.empty()) s.write((char*)&string[0], string.size()); } - - unsigned int GetSerializeSize(int, int=0) const - { - return GetSizeOfCompactSize(string.size()) + string.size(); - } }; template @@ -514,7 +478,6 @@ CVarInt WrapVarInt(I& n) { return CVarInt(n); } /** * string */ -template unsigned int GetSerializeSize(const std::basic_string& str, int, int=0); template void Serialize(Stream& os, const std::basic_string& str, int, int=0); template void Unserialize(Stream& is, std::basic_string& str, int, int=0); @@ -522,9 +485,6 @@ template void Unserialize(Stream& is, std::basic_st * prevector * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. */ -template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&); -template unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&); -template inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion); template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&); template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&); template inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion); @@ -536,9 +496,6 @@ template inline void Unserialize(St * vector * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. */ -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const unsigned char&); -template unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const V&); -template inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion); template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&); template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const V&); template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion); @@ -563,21 +520,18 @@ template void Unserialize(Stream& is /** * pair */ -template unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion); template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion); template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion); /** * map */ -template unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion); template void Serialize(Stream& os, const std::map& m, int nType, int nVersion); template void Unserialize(Stream& is, std::map& m, int nType, int nVersion); /** * set */ -template unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion); template void Serialize(Stream& os, const std::set& m, int nType, int nVersion); template void Unserialize(Stream& is, std::set& m, int nType, int nVersion); @@ -598,12 +552,6 @@ template void Unserialize(Stream& is, s * The compiler will only cast int to long if none of the other templates matched. * Thanks to Boost serialization for this idea. */ -template -inline unsigned int GetSerializeSize(const T& a, long nType, int nVersion) -{ - return a.GetSerializeSize((int)nType, nVersion); -} - template inline void Serialize(Stream& os, const T& a, long nType, int nVersion) { @@ -623,12 +571,6 @@ inline void Unserialize(Stream& is, T& a, long nType, int nVersion) /** * string */ -template -unsigned int GetSerializeSize(const std::basic_string& str, int, int) -{ - return GetSizeOfCompactSize(str.size()) + str.size() * sizeof(str[0]); -} - template void Serialize(Stream& os, const std::basic_string& str, int, int) { @@ -651,28 +593,6 @@ void Unserialize(Stream& is, std::basic_string& str, int, int) /** * prevector */ -template -unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const unsigned char&) -{ - return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); -} - -template -unsigned int GetSerializeSize_impl(const prevector& v, int nType, int nVersion, const V&) -{ - unsigned int nSize = GetSizeOfCompactSize(v.size()); - for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - nSize += GetSerializeSize((*vi), nType, nVersion); - return nSize; -} - -template -inline unsigned int GetSerializeSize(const prevector& v, int nType, int nVersion) -{ - return GetSerializeSize_impl(v, nType, nVersion, T()); -} - - template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&) { @@ -741,28 +661,6 @@ inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion) /** * vector */ -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const unsigned char&) -{ - return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); -} - -template -unsigned int GetSerializeSize_impl(const std::vector& v, int nType, int nVersion, const V&) -{ - unsigned int nSize = GetSizeOfCompactSize(v.size()); - for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - nSize += GetSerializeSize((*vi), nType, nVersion); - return nSize; -} - -template -inline unsigned int GetSerializeSize(const std::vector& v, int nType, int nVersion) -{ - return GetSerializeSize_impl(v, nType, nVersion, T()); -} - - template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&) { @@ -908,12 +806,6 @@ void Unserialize(Stream& is, boost::array& item, int nType, int nVersion) /** * pair */ -template -unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) -{ - return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); -} - template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) { @@ -933,15 +825,6 @@ void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) /** * map */ -template -unsigned int GetSerializeSize(const std::map& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - nSize += GetSerializeSize((*mi), nType, nVersion); - return nSize; -} - template void Serialize(Stream& os, const std::map& m, int nType, int nVersion) { @@ -969,15 +852,6 @@ void Unserialize(Stream& is, std::map& m, int nType, int nVersion /** * set */ -template -unsigned int GetSerializeSize(const std::set& m, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(m.size()); - for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - nSize += GetSerializeSize((*it), nType, nVersion); - return nSize; -} - template void Serialize(Stream& os, const std::set& m, int nType, int nVersion) { @@ -1146,4 +1020,16 @@ inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionUnser ::UnserializeMany(s, nType, nVersion, args...); } +template +size_t GetSerializeSize(const T& t, int nType, int nVersion = 0) +{ + return (CSizeComputer(nType, nVersion) << t).size(); +} + +template +size_t GetSerializeSize(const S& s, const T& t) +{ + return (CSizeComputer(s.GetType(), s.GetVersion()) << t).size(); +} + #endif // BITCOIN_SERIALIZE_H diff --git a/src/streams.h b/src/streams.h index 7aef8a0aa..6fc8a93da 100644 --- a/src/streams.h +++ b/src/streams.h @@ -275,13 +275,6 @@ public: s.write((char*)&vch[0], vch.size() * sizeof(vch[0])); } - template - unsigned int GetSerializeSize(const T& obj) - { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); - } - template CBaseDataStream& operator<<(const T& obj) { @@ -429,13 +422,6 @@ public: throw std::ios_base::failure("CAutoFile::write: write failed"); } - template - unsigned int GetSerializeSize(const T& obj) - { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); - } - template CAutoFile& operator<<(const T& obj) { diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index 426d296a9..f8b9c70e0 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -184,8 +184,8 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(OneL.begin() + 32 == OneL.end()); BOOST_CHECK(MaxL.begin() + 32 == MaxL.end()); BOOST_CHECK(TmpL.begin() + 32 == TmpL.end()); - BOOST_CHECK(R1L.GetSerializeSize(0,PROTOCOL_VERSION) == 32); - BOOST_CHECK(ZeroL.GetSerializeSize(0,PROTOCOL_VERSION) == 32); + BOOST_CHECK(GetSerializeSize(R1L, 0, PROTOCOL_VERSION) == 32); + BOOST_CHECK(GetSerializeSize(ZeroL, 0, PROTOCOL_VERSION) == 32); std::stringstream ss; R1L.Serialize(ss,0,PROTOCOL_VERSION); @@ -230,8 +230,8 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(OneS.begin() + 20 == OneS.end()); BOOST_CHECK(MaxS.begin() + 20 == MaxS.end()); BOOST_CHECK(TmpS.begin() + 20 == TmpS.end()); - BOOST_CHECK(R1S.GetSerializeSize(0,PROTOCOL_VERSION) == 20); - BOOST_CHECK(ZeroS.GetSerializeSize(0,PROTOCOL_VERSION) == 20); + BOOST_CHECK(GetSerializeSize(R1S, 0, PROTOCOL_VERSION) == 20); + BOOST_CHECK(GetSerializeSize(ZeroS, 0, PROTOCOL_VERSION) == 20); R1S.Serialize(ss,0,PROTOCOL_VERSION); BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+20)); diff --git a/src/uint256.h b/src/uint256.h index 3729c981a..6e79d31cd 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -75,11 +75,6 @@ public: return sizeof(data); } - unsigned int GetSerializeSize(int nType, int nVersion) const - { - return sizeof(data); - } - template void Serialize(Stream& s, int nType, int nVersion) const { diff --git a/src/undo.h b/src/undo.h index 2c7b74183..274c01ed9 100644 --- a/src/undo.h +++ b/src/undo.h @@ -27,12 +27,6 @@ public: CTxInUndo() : txout(), fCoinBase(false), nHeight(0), nVersion(0) {} CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { } - unsigned int GetSerializeSize(int nType, int nVersion) const { - return ::GetSerializeSize(VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion) + - (nHeight > 0 ? ::GetSerializeSize(VARINT(this->nVersion), nType, nVersion) : 0) + - ::GetSerializeSize(CTxOutCompressor(REF(txout)), nType, nVersion); - } - template void Serialize(Stream &s, int nType, int nVersion) const { ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion); From a8e5ae92bae9760df78b4c405e2a0ab2300f3fa1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 9 Mar 2018 12:32:02 +0000 Subject: [PATCH 12/20] GetSerializeSize changes in Zcash-specific code --- src/dbwrapper.h | 2 +- src/main.cpp | 2 +- src/paymentdisclosuredb.cpp | 2 +- src/serialize.h | 32 -------------------------------- src/wallet/rpcwallet.cpp | 10 +++++----- 5 files changed, 8 insertions(+), 40 deletions(-) diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 40ed9e583..1d62d2b72 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -99,7 +99,7 @@ public: template void Seek(const K& key) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(key)); + ssKey.reserve(GetSerializeSize(ssKey, key)); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); piter->Seek(slKey); diff --git a/src/main.cpp b/src/main.cpp index 7a401e673..f6d3f3992 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -575,7 +575,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c // have been mined or received. // 10,000 orphans, each of which is at most 5,000 bytes big is // at most 500 megabytes of orphans: - unsigned int sz = tx.GetSerializeSize(SER_NETWORK, tx.nVersion); + unsigned int sz = GetSerializeSize(tx, SER_NETWORK, tx.nVersion); if (sz > 5000) { LogPrint("mempool", "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); diff --git a/src/paymentdisclosuredb.cpp b/src/paymentdisclosuredb.cpp index 1851e77ec..8840dcda0 100644 --- a/src/paymentdisclosuredb.cpp +++ b/src/paymentdisclosuredb.cpp @@ -57,7 +57,7 @@ bool PaymentDisclosureDB::Put(const PaymentDisclosureKey& key, const PaymentDisc std::lock_guard guard(lock_); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue.reserve(ssValue.GetSerializeSize(info)); + ssValue.reserve(GetSerializeSize(ssValue, info)); ssValue << info; leveldb::Slice slice(&ssValue[0], ssValue.size()); diff --git a/src/serialize.h b/src/serialize.h index da80b7630..124169c67 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -506,14 +506,12 @@ template inline void Unserialize(Stream /** * optional */ -template unsigned int GetSerializeSize(const boost::optional &item, int nType, int nVersion); template void Serialize(Stream& os, const boost::optional& item, int nType, int nVersion); template void Unserialize(Stream& is, boost::optional& item, int nType, int nVersion); /** * array */ -template unsigned int GetSerializeSize(const boost::array &item, int nType, int nVersion); template void Serialize(Stream& os, const boost::array& item, int nType, int nVersion); template void Unserialize(Stream& is, boost::array& item, int nType, int nVersion); @@ -538,7 +536,6 @@ template void Unserializ /** * list */ -template unsigned int GetSerializeSize(const std::list& m, int nType, int nVersion); template void Serialize(Stream& os, const std::list& m, int nType, int nVersion); template void Unserialize(Stream& is, std::list& m, int nType, int nVersion); @@ -729,16 +726,6 @@ inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersio /** * optional */ -template -unsigned int GetSerializeSize(const boost::optional &item, int nType, int nVersion) -{ - if (item) { - return 1 + GetSerializeSize(*item, nType, nVersion); - } else { - return 1; - } -} - template void Serialize(Stream& os, const boost::optional& item, int nType, int nVersion) { @@ -776,16 +763,6 @@ void Unserialize(Stream& is, boost::optional& item, int nType, int nVersion) /** * array */ -template -unsigned int GetSerializeSize(const boost::array &item, int nType, int nVersion) -{ - unsigned int size = 0; - for (size_t i = 0; i < N; i++) { - size += GetSerializeSize(item[0], nType, nVersion); - } - return size; -} - template void Serialize(Stream& os, const boost::array& item, int nType, int nVersion) { @@ -879,15 +856,6 @@ void Unserialize(Stream& is, std::set& m, int nType, int nVersion) /** * list */ -template -unsigned int GetSerializeSize(const std::list& l, int nType, int nVersion) -{ - unsigned int nSize = GetSizeOfCompactSize(l.size()); - for (typename std::list::const_iterator it = l.begin(); it != l.end(); ++it) - nSize += GetSerializeSize((*it), nType, nVersion); - return nSize; -} - template void Serialize(Stream& os, const std::list& l, int nType, int nVersion) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c03194e54..e86f0e2de 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -1341,7 +1341,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe entry.push_back(Pair("fee", ValueFromAmount(-nFee))); if (fLong) WalletTxToJSON(wtx, entry); - entry.push_back(Pair("size", static_cast(static_cast(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)))); + entry.push_back(Pair("size", static_cast(GetSerializeSize(static_cast(wtx), SER_NETWORK, PROTOCOL_VERSION)))); ret.push_back(entry); } } @@ -1378,7 +1378,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe entry.push_back(Pair("vout", r.vout)); if (fLong) WalletTxToJSON(wtx, entry); - entry.push_back(Pair("size", static_cast(static_cast(wtx).GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)))); + entry.push_back(Pair("size", static_cast(GetSerializeSize(static_cast(wtx), SER_NETWORK, PROTOCOL_VERSION)))); ret.push_back(entry); } } @@ -3482,7 +3482,7 @@ UniValue z_getoperationstatus_IMPL(const UniValue& params, bool fRemoveFinishedO // If input notes are small, we might actually require more than one joinsplit per zaddr output. // For now though, we assume we use one joinsplit per zaddr output (and the second output note is change). // We reduce the result by 1 to ensure there is room for non-joinsplit CTransaction data. -#define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION)) - 1) +#define Z_SENDMANY_MAX_ZADDR_OUTPUTS ((MAX_TX_SIZE / GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION)) - 1) // transaction.h comment: spending taddr output requires CTxIn >= 148 bytes and typical taddr txout is 34 bytes #define CTXIN_SPEND_DUST_SIZE 148 @@ -3627,7 +3627,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) mtx.vjoinsplit.push_back(JSDescription()); } CTransaction tx(mtx); - txsize += tx.GetSerializeSize(SER_NETWORK, tx.nVersion); + txsize += GetSerializeSize(tx, SER_NETWORK, tx.nVersion); if (fromTaddr) { txsize += CTXIN_SPEND_DUST_SIZE; txsize += CTXOUT_REGULAR_SIZE; // There will probably be taddr change @@ -3898,7 +3898,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp) #define MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT 50 #define MERGE_TO_ADDRESS_DEFAULT_SHIELDED_LIMIT 10 -#define JOINSPLIT_SIZE JSDescription().GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) +#define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION) UniValue z_mergetoaddress(const UniValue& params, bool fHelp) { From 242f1421dbc93c30bb6b1d3b62b640d2b3b1e9ca Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 16:29:17 -0700 Subject: [PATCH 13/20] Get rid of nType and nVersion Remove the nType and nVersion as parameters to all serialization methods and functions. There is only one place where it's read and has an impact (in CAddress), and even there it does not impact any of the recursively invoked serializers. Instead, the few places that need nType or nVersion are changed to read it directly from the stream object, through GetType() and GetVersion() methods which are added to all stream classes. --- src/addrman.h | 6 +- src/amount.h | 2 +- src/bloom.h | 2 +- src/chain.h | 7 +- src/coins.h | 24 ++-- src/compressor.h | 6 +- src/hash.h | 5 +- src/key.h | 4 +- src/main.h | 4 +- src/merkleblock.h | 4 +- src/netbase.h | 4 +- src/primitives/block.h | 9 +- src/primitives/transaction.h | 10 +- src/protocol.h | 13 +- src/pubkey.h | 8 +- src/rest.cpp | 2 +- src/script/interpreter.cpp | 30 ++-- src/script/zcashconsensus.cpp | 4 +- src/serialize.h | 256 +++++++++++++++++----------------- src/streams.h | 17 ++- src/test/bloom_tests.cpp | 6 +- src/test/dbwrapper_tests.cpp | 2 +- src/test/serialize_tests.cpp | 4 +- src/test/uint256_tests.cpp | 38 ++--- src/uint256.h | 4 +- src/undo.h | 20 +-- src/wallet/crypter.h | 2 +- src/wallet/wallet.h | 28 ++-- src/wallet/walletdb.h | 2 +- 29 files changed, 267 insertions(+), 256 deletions(-) diff --git a/src/addrman.h b/src/addrman.h index 7753f1822..5c77a4fdb 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -54,7 +54,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CAddress*)this); READWRITE(source); READWRITE(nLastSuccess); @@ -279,7 +279,7 @@ public: * very little in common. */ template - void Serialize(Stream &s, int nType, int nVersionDummy) const + void Serialize(Stream &s) const { LOCK(cs); @@ -329,7 +329,7 @@ public: } template - void Unserialize(Stream& s, int nType, int nVersionDummy) + void Unserialize(Stream& s) { LOCK(cs); diff --git a/src/amount.h b/src/amount.h index 90e6b5aa8..3d7eefc58 100644 --- a/src/amount.h +++ b/src/amount.h @@ -56,7 +56,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nSatoshisPerK); } }; diff --git a/src/bloom.h b/src/bloom.h index a4dba8cb4..df5c30b1e 100644 --- a/src/bloom.h +++ b/src/bloom.h @@ -73,7 +73,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vData); READWRITE(nHashFuncs); READWRITE(nTweak); diff --git a/src/chain.h b/src/chain.h index 937e20bda..793ef4f03 100644 --- a/src/chain.h +++ b/src/chain.h @@ -26,7 +26,7 @@ struct CDiskBlockPos ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(VARINT(nFile)); READWRITE(VARINT(nPos)); } @@ -340,8 +340,9 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(VARINT(nVersion)); READWRITE(VARINT(nHeight)); diff --git a/src/coins.h b/src/coins.h index 52b724193..4e1cac438 100644 --- a/src/coins.h +++ b/src/coins.h @@ -154,7 +154,7 @@ public: } template - void Serialize(Stream &s, int nType, int nVersion) const { + void Serialize(Stream &s) const { unsigned int nMaskSize = 0, nMaskCode = 0; CalcMaskSize(nMaskSize, nMaskCode); bool fFirst = vout.size() > 0 && !vout[0].IsNull(); @@ -162,33 +162,33 @@ public: assert(fFirst || fSecond || nMaskCode); unsigned int nCode = 8*(nMaskCode - (fFirst || fSecond ? 0 : 1)) + (fCoinBase ? 1 : 0) + (fFirst ? 2 : 0) + (fSecond ? 4 : 0); // version - ::Serialize(s, VARINT(this->nVersion), nType, nVersion); + ::Serialize(s, VARINT(this->nVersion)); // header code - ::Serialize(s, VARINT(nCode), nType, nVersion); + ::Serialize(s, VARINT(nCode)); // spentness bitmask for (unsigned int b = 0; b - void Unserialize(Stream &s, int nType, int nVersion) { + void Unserialize(Stream &s) { unsigned int nCode = 0; // version - ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); + ::Unserialize(s, VARINT(this->nVersion)); // header code - ::Unserialize(s, VARINT(nCode), nType, nVersion); + ::Unserialize(s, VARINT(nCode)); fCoinBase = nCode & 1; std::vector vAvail(2, false); vAvail[0] = (nCode & 2) != 0; @@ -197,7 +197,7 @@ public: // spentness bitmask while (nMaskCode > 0) { unsigned char chAvail = 0; - ::Unserialize(s, chAvail, nType, nVersion); + ::Unserialize(s, chAvail); for (unsigned int p = 0; p < 8; p++) { bool f = (chAvail & (1 << p)) != 0; vAvail.push_back(f); @@ -209,10 +209,10 @@ public: vout.assign(vAvail.size(), CTxOut()); for (unsigned int i = 0; i < vAvail.size(); i++) { if (vAvail[i]) - ::Unserialize(s, REF(CTxOutCompressor(vout[i])), nType, nVersion); + ::Unserialize(s, REF(CTxOutCompressor(vout[i]))); } // coinbase height - ::Unserialize(s, VARINT(nHeight), nType, nVersion); + ::Unserialize(s, VARINT(nHeight)); Cleanup(); } diff --git a/src/compressor.h b/src/compressor.h index 90749499d..961365d26 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -56,7 +56,7 @@ public: CScriptCompressor(CScript &scriptIn) : script(scriptIn) { } template - void Serialize(Stream &s, int nType, int nVersion) const { + void Serialize(Stream &s) const { std::vector compr; if (Compress(compr)) { s << CFlatData(compr); @@ -68,7 +68,7 @@ public: } template - void Unserialize(Stream &s, int nType, int nVersion) { + void Unserialize(Stream &s) { unsigned int nSize = 0; s >> VARINT(nSize); if (nSize < nSpecialScripts) { @@ -104,7 +104,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { if (!ser_action.ForRead()) { uint64_t nVal = CompressAmount(txout.nValue); READWRITE(VARINT(nVal)); diff --git a/src/hash.h b/src/hash.h index 1d28d6bdf..8276c9184 100644 --- a/src/hash.h +++ b/src/hash.h @@ -140,6 +140,9 @@ public: CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {} + int GetType() const { return nType; } + int GetVersion() const { return nVersion; } + void write(const char *pch, size_t size) { ctx.Write((const unsigned char*)pch, size); } @@ -154,7 +157,7 @@ public: template CHashWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; diff --git a/src/key.h b/src/key.h index d07bac91b..8d64151e3 100644 --- a/src/key.h +++ b/src/key.h @@ -176,7 +176,7 @@ struct CExtKey { CExtPubKey Neuter() const; void SetMaster(const unsigned char* seed, unsigned int nSeedLen); template - void Serialize(Stream& s, int nType, int nVersion) const + void Serialize(Stream& s) const { unsigned int len = BIP32_EXTKEY_SIZE; ::WriteCompactSize(s, len); @@ -185,7 +185,7 @@ struct CExtKey { s.write((const char *)&code[0], len); } template - void Unserialize(Stream& s, int nType, int nVersion) + void Unserialize(Stream& s) { unsigned int len = ::ReadCompactSize(s); unsigned char code[BIP32_EXTKEY_SIZE]; diff --git a/src/main.h b/src/main.h index 2a3b4175a..580de352a 100644 --- a/src/main.h +++ b/src/main.h @@ -273,7 +273,7 @@ struct CDiskTxPos : public CDiskBlockPos ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CDiskBlockPos*)this); READWRITE(VARINT(nTxOffset)); } @@ -493,7 +493,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(VARINT(nBlocks)); READWRITE(VARINT(nSize)); READWRITE(VARINT(nUndoSize)); diff --git a/src/merkleblock.h b/src/merkleblock.h index 0181723af..97223ed92 100644 --- a/src/merkleblock.h +++ b/src/merkleblock.h @@ -85,7 +85,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nTransactions); READWRITE(vHash); std::vector vBytes; @@ -147,7 +147,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(header); READWRITE(txn); } diff --git a/src/netbase.h b/src/netbase.h index 8f02fa025..a50efc428 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -97,7 +97,7 @@ class CNetAddr ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(FLATDATA(ip)); } @@ -162,7 +162,7 @@ class CService : public CNetAddr ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(FLATDATA(ip)); unsigned short portN = htons(port); READWRITE(FLATDATA(portN)); diff --git a/src/primitives/block.h b/src/primitives/block.h index 6b3f13a86..7fe1a3588 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -40,7 +40,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(hashPrevBlock); @@ -101,7 +101,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CBlockHeader*)this); READWRITE(vtx); } @@ -185,8 +185,9 @@ struct CBlockLocator ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(vHave); } diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 5e4f4a526..60ea11239 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -157,7 +157,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(hash); READWRITE(n); } @@ -205,7 +205,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(prevout); READWRITE(*(CScriptBase*)(&scriptSig)); READWRITE(nSequence); @@ -250,7 +250,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nValue); READWRITE(*(CScriptBase*)(&scriptPubKey)); } @@ -372,7 +372,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { if (ser_action.ForRead()) { // When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion. uint32_t header; @@ -482,7 +482,7 @@ struct CMutableTransaction ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { if (ser_action.ForRead()) { // When deserializing, unpack the 4 byte header to extract fOverwintered and nVersion. uint32_t header; diff --git a/src/protocol.h b/src/protocol.h index 5eafb7df6..d908191cc 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -40,7 +40,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(FLATDATA(pchMessageStart)); READWRITE(FLATDATA(pchCommand)); @@ -97,14 +97,15 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + inline void SerializationOp(Stream& s, Operation ser_action) { if (ser_action.ForRead()) Init(); - if (nType & SER_DISK) + int nVersion = s.GetVersion(); + if (s.GetType() & SER_DISK) READWRITE(nVersion); - if ((nType & SER_DISK) || - (nVersion >= CADDR_TIME_VERSION && !(nType & SER_GETHASH))) + if ((s.GetType() & SER_DISK) || + (nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH))) READWRITE(nTime); READWRITE(nServices); READWRITE(*(CService*)this); @@ -129,7 +130,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(type); READWRITE(hash); diff --git a/src/pubkey.h b/src/pubkey.h index 3589cbd16..9521bd2c0 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -124,14 +124,14 @@ public: //! Implement serialization, as if this was a byte vector. template - void Serialize(Stream& s, int nType, int nVersion) const + void Serialize(Stream& s) const { unsigned int len = size(); ::WriteCompactSize(s, len); s.write((char*)vch, len); } template - void Unserialize(Stream& s, int nType, int nVersion) + void Unserialize(Stream& s) { unsigned int len = ::ReadCompactSize(s); if (len <= PUBLIC_KEY_SIZE) { @@ -215,7 +215,7 @@ struct CExtPubKey { bool Derive(CExtPubKey& out, unsigned int nChild) const; template - void Serialize(Stream& s, int nType, int nVersion) const + void Serialize(Stream& s) const { unsigned int len = BIP32_EXTKEY_SIZE; ::WriteCompactSize(s, len); @@ -224,7 +224,7 @@ struct CExtPubKey { s.write((const char *)&code[0], len); } template - void Unserialize(Stream& s, int nType, int nVersion) + void Unserialize(Stream& s) { unsigned int len = ::ReadCompactSize(s); unsigned char code[BIP32_EXTKEY_SIZE]; diff --git a/src/rest.cpp b/src/rest.cpp index 813850b4a..c0d8f5320 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -48,7 +48,7 @@ struct CCoin { ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(nTxVer); READWRITE(nHeight); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 8e46d96b8..f262faef9 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -981,7 +981,7 @@ public: /** Serialize the passed scriptCode */ template - void SerializeScriptCode(S &s, int nType, int nVersion) const { + void SerializeScriptCode(S &s) const { auto size = scriptCode.size(); ::WriteCompactSize(s, size); s.write((char*)&scriptCode.begin()[0], size); @@ -989,54 +989,54 @@ public: /** Serialize an input of txTo */ template - void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const { + void SerializeInput(S &s, unsigned int nInput) const { // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized if (fAnyoneCanPay) nInput = nIn; // Serialize the prevout - ::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion); + ::Serialize(s, txTo.vin[nInput].prevout); // Serialize the script assert(nInput != NOT_AN_INPUT); if (nInput != nIn) // Blank out other inputs' signatures - ::Serialize(s, CScriptBase(), nType, nVersion); + ::Serialize(s, CScriptBase()); else - SerializeScriptCode(s, nType, nVersion); + SerializeScriptCode(s); // Serialize the nSequence if (nInput != nIn && (fHashSingle || fHashNone)) // let the others update at will - ::Serialize(s, (int)0, nType, nVersion); + ::Serialize(s, (int)0); else - ::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion); + ::Serialize(s, txTo.vin[nInput].nSequence); } /** Serialize an output of txTo */ template - void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const { + void SerializeOutput(S &s, unsigned int nOutput) const { if (fHashSingle && nOutput != nIn) // Do not lock-in the txout payee at other indices as txin - ::Serialize(s, CTxOut(), nType, nVersion); + ::Serialize(s, CTxOut()); else - ::Serialize(s, txTo.vout[nOutput], nType, nVersion); + ::Serialize(s, txTo.vout[nOutput]); } /** Serialize txTo */ template - void Serialize(S &s, int nType, int nVersion) const { + void Serialize(S &s) const { // Serialize nVersion - ::Serialize(s, txTo.nVersion, nType, nVersion); + ::Serialize(s, txTo.nVersion); // Serialize vin unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size(); ::WriteCompactSize(s, nInputs); for (unsigned int nInput = 0; nInput < nInputs; nInput++) - SerializeInput(s, nInput, nType, nVersion); + SerializeInput(s, nInput); // Serialize vout unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size()); ::WriteCompactSize(s, nOutputs); for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) - SerializeOutput(s, nOutput, nType, nVersion); + SerializeOutput(s, nOutput); // Serialize nLockTime - ::Serialize(s, txTo.nLockTime, nType, nVersion); + ::Serialize(s, txTo.nLockTime); // Serialize vjoinsplit if (txTo.nVersion >= 2) { diff --git a/src/script/zcashconsensus.cpp b/src/script/zcashconsensus.cpp index daf445d34..50d732fff 100644 --- a/src/script/zcashconsensus.cpp +++ b/src/script/zcashconsensus.cpp @@ -43,10 +43,12 @@ public: template TxInputStream& operator>>(T& obj) { - ::Unserialize(*this, obj, m_type, m_version); + ::Unserialize(*this, obj); return *this; } + int GetVersion() const { return m_version; } + int GetType() const { return m_type; } private: const int m_type; const int m_version; diff --git a/src/serialize.h b/src/serialize.h index 124169c67..0cc5216fd 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -164,8 +164,8 @@ enum SER_GETHASH = (1 << 2), }; -#define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) -#define READWRITEMANY(...) (::SerReadWriteMany(s, nType, nVersion, ser_action, __VA_ARGS__)) +#define READWRITE(obj) (::SerReadWrite(s, (obj), ser_action)) +#define READWRITEMANY(...) (::SerReadWriteMany(s, ser_action, __VA_ARGS__)) /** * Implement three methods for serializable objects. These are actually wrappers over @@ -173,45 +173,42 @@ enum * code. Adding "ADD_SERIALIZE_METHODS" in the body of the class causes these wrappers to be * added as members. */ -#define ADD_SERIALIZE_METHODS \ - template \ - void Serialize(Stream& s, int nType, int nVersion) const { \ - NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize(), nType, nVersion);\ - } \ - template \ - void Unserialize(Stream& s, int nType, int nVersion) { \ - SerializationOp(s, CSerActionUnserialize(), nType, nVersion); \ +#define ADD_SERIALIZE_METHODS \ + template \ + void Serialize(Stream& s) const { \ + NCONST_PTR(this)->SerializationOp(s, CSerActionSerialize()); \ + } \ + template \ + void Unserialize(Stream& s) { \ + SerializationOp(s, CSerActionUnserialize()); \ } -/* - * Basic Types - */ -template inline void Serialize(Stream& s, char a, int, int=0) { ser_writedata8(s, a); } // TODO Get rid of bare char -template inline void Serialize(Stream& s, int8_t a, int, int=0) { ser_writedata8(s, a); } -template inline void Serialize(Stream& s, uint8_t a, int, int=0) { ser_writedata8(s, a); } -template inline void Serialize(Stream& s, int16_t a, int, int=0) { ser_writedata16(s, a); } -template inline void Serialize(Stream& s, uint16_t a, int, int=0) { ser_writedata16(s, a); } -template inline void Serialize(Stream& s, int32_t a, int, int=0) { ser_writedata32(s, a); } -template inline void Serialize(Stream& s, uint32_t a, int, int=0) { ser_writedata32(s, a); } -template inline void Serialize(Stream& s, int64_t a, int, int=0) { ser_writedata64(s, a); } -template inline void Serialize(Stream& s, uint64_t a, int, int=0) { ser_writedata64(s, a); } -template inline void Serialize(Stream& s, float a, int, int=0) { ser_writedata32(s, ser_float_to_uint32(a)); } -template inline void Serialize(Stream& s, double a, int, int=0) { ser_writedata64(s, ser_double_to_uint64(a)); } +template inline void Serialize(Stream& s, char a ) { ser_writedata8(s, a); } // TODO Get rid of bare char +template inline void Serialize(Stream& s, int8_t a ) { ser_writedata8(s, a); } +template inline void Serialize(Stream& s, uint8_t a ) { ser_writedata8(s, a); } +template inline void Serialize(Stream& s, int16_t a ) { ser_writedata16(s, a); } +template inline void Serialize(Stream& s, uint16_t a) { ser_writedata16(s, a); } +template inline void Serialize(Stream& s, int32_t a ) { ser_writedata32(s, a); } +template inline void Serialize(Stream& s, uint32_t a) { ser_writedata32(s, a); } +template inline void Serialize(Stream& s, int64_t a ) { ser_writedata64(s, a); } +template inline void Serialize(Stream& s, uint64_t a) { ser_writedata64(s, a); } +template inline void Serialize(Stream& s, float a ) { ser_writedata32(s, ser_float_to_uint32(a)); } +template inline void Serialize(Stream& s, double a ) { ser_writedata64(s, ser_double_to_uint64(a)); } -template inline void Unserialize(Stream& s, char& a, int, int=0) { a = ser_readdata8(s); } // TODO Get rid of bare char -template inline void Unserialize(Stream& s, int8_t& a, int, int=0) { a = ser_readdata8(s); } -template inline void Unserialize(Stream& s, uint8_t& a, int, int=0) { a = ser_readdata8(s); } -template inline void Unserialize(Stream& s, int16_t& a, int, int=0) { a = ser_readdata16(s); } -template inline void Unserialize(Stream& s, uint16_t& a, int, int=0) { a = ser_readdata16(s); } -template inline void Unserialize(Stream& s, int32_t& a, int, int=0) { a = ser_readdata32(s); } -template inline void Unserialize(Stream& s, uint32_t& a, int, int=0) { a = ser_readdata32(s); } -template inline void Unserialize(Stream& s, int64_t& a, int, int=0) { a = ser_readdata64(s); } -template inline void Unserialize(Stream& s, uint64_t& a, int, int=0) { a = ser_readdata64(s); } -template inline void Unserialize(Stream& s, float& a, int, int=0) { a = ser_uint32_to_float(ser_readdata32(s)); } -template inline void Unserialize(Stream& s, double& a, int, int=0) { a = ser_uint64_to_double(ser_readdata64(s)); } +template inline void Unserialize(Stream& s, char& a ) { a = ser_readdata8(s); } // TODO Get rid of bare char +template inline void Unserialize(Stream& s, int8_t& a ) { a = ser_readdata8(s); } +template inline void Unserialize(Stream& s, uint8_t& a ) { a = ser_readdata8(s); } +template inline void Unserialize(Stream& s, int16_t& a ) { a = ser_readdata16(s); } +template inline void Unserialize(Stream& s, uint16_t& a) { a = ser_readdata16(s); } +template inline void Unserialize(Stream& s, int32_t& a ) { a = ser_readdata32(s); } +template inline void Unserialize(Stream& s, uint32_t& a) { a = ser_readdata32(s); } +template inline void Unserialize(Stream& s, int64_t& a ) { a = ser_readdata64(s); } +template inline void Unserialize(Stream& s, uint64_t& a) { a = ser_readdata64(s); } +template inline void Unserialize(Stream& s, float& a ) { a = ser_uint32_to_float(ser_readdata32(s)); } +template inline void Unserialize(Stream& s, double& a ) { a = ser_uint64_to_double(ser_readdata64(s)); } -template inline void Serialize(Stream& s, bool a, int, int=0) { char f=a; ser_writedata8(s, f); } -template inline void Unserialize(Stream& s, bool& a, int, int=0) { char f=ser_readdata8(s); a=f; } +template inline void Serialize(Stream& s, bool a) { char f=a; ser_writedata8(s, f); } +template inline void Unserialize(Stream& s, bool& a) { char f=ser_readdata8(s); a=f; } @@ -390,13 +387,13 @@ public: const char* end() const { return pend; } template - void Serialize(Stream& s, int, int=0) const + void Serialize(Stream& s) const { s.write(pbegin, pend - pbegin); } template - void Unserialize(Stream& s, int, int=0) + void Unserialize(Stream& s) { s.read(pbegin, pend - pbegin); } @@ -411,12 +408,12 @@ public: CVarInt(I& nIn) : n(nIn) { } template - void Serialize(Stream &s, int, int) const { + void Serialize(Stream &s) const { WriteVarInt(s, n); } template - void Unserialize(Stream& s, int, int) { + void Unserialize(Stream& s) { n = ReadVarInt(s); } }; @@ -429,12 +426,12 @@ public: CCompactSize(uint64_t& nIn) : n(nIn) { } template - void Serialize(Stream &s, int, int) const { + void Serialize(Stream &s) const { WriteCompactSize(s, n); } template - void Unserialize(Stream& s, int, int) { + void Unserialize(Stream& s) { n = ReadCompactSize(s); } }; @@ -448,7 +445,7 @@ public: LimitedString(std::string& string) : string(string) {} template - void Unserialize(Stream& s, int, int=0) + void Unserialize(Stream& s) { size_t size = ReadCompactSize(s); if (size > Limit) { @@ -460,7 +457,7 @@ public: } template - void Serialize(Stream& s, int, int=0) const + void Serialize(Stream& s) const { WriteCompactSize(s, string.size()); if (!string.empty()) @@ -478,30 +475,30 @@ CVarInt WrapVarInt(I& n) { return CVarInt(n); } /** * string */ -template void Serialize(Stream& os, const std::basic_string& str, int, int=0); -template void Unserialize(Stream& is, std::basic_string& str, int, int=0); +template void Serialize(Stream& os, const std::basic_string& str); +template void Unserialize(Stream& is, std::basic_string& str); /** * prevector * prevectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. */ -template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&); -template void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&); -template inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion); -template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&); -template void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&); -template inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion); +template void Serialize_impl(Stream& os, const prevector& v, const unsigned char&); +template void Serialize_impl(Stream& os, const prevector& v, const V&); +template inline void Serialize(Stream& os, const prevector& v); +template void Unserialize_impl(Stream& is, prevector& v, const unsigned char&); +template void Unserialize_impl(Stream& is, prevector& v, const V&); +template inline void Unserialize(Stream& is, prevector& v); /** * vector * vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. */ -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&); -template void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const V&); -template inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const unsigned char&); -template void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&); -template inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion); +template void Serialize_impl(Stream& os, const std::vector& v, const unsigned char&); +template void Serialize_impl(Stream& os, const std::vector& v, const V&); +template inline void Serialize(Stream& os, const std::vector& v); +template void Unserialize_impl(Stream& is, std::vector& v, const unsigned char&); +template void Unserialize_impl(Stream& is, std::vector& v, const V&); +template inline void Unserialize(Stream& is, std::vector& v); /** * optional @@ -518,20 +515,20 @@ template void Unserialize(Stream& is /** * pair */ -template void Serialize(Stream& os, const std::pair& item, int nType, int nVersion); -template void Unserialize(Stream& is, std::pair& item, int nType, int nVersion); +template void Serialize(Stream& os, const std::pair& item); +template void Unserialize(Stream& is, std::pair& item); /** * map */ -template void Serialize(Stream& os, const std::map& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::map& m, int nType, int nVersion); +template void Serialize(Stream& os, const std::map& m); +template void Unserialize(Stream& is, std::map& m); /** * set */ -template void Serialize(Stream& os, const std::set& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::set& m, int nType, int nVersion); +template void Serialize(Stream& os, const std::set& m); +template void Unserialize(Stream& is, std::set& m); /** * list @@ -545,20 +542,17 @@ template void Unserialize(Stream& is, s /** * If none of the specialized versions above matched, default to calling member function. - * "int nType" is changed to "long nType" to keep from getting an ambiguous overload error. - * The compiler will only cast int to long if none of the other templates matched. - * Thanks to Boost serialization for this idea. */ template -inline void Serialize(Stream& os, const T& a, long nType, int nVersion) +inline void Serialize(Stream& os, const T& a) { - a.Serialize(os, (int)nType, nVersion); + a.Serialize(os); } template -inline void Unserialize(Stream& is, T& a, long nType, int nVersion) +inline void Unserialize(Stream& is, T& a) { - a.Unserialize(is, (int)nType, nVersion); + a.Unserialize(is); } @@ -569,7 +563,7 @@ inline void Unserialize(Stream& is, T& a, long nType, int nVersion) * string */ template -void Serialize(Stream& os, const std::basic_string& str, int, int) +void Serialize(Stream& os, const std::basic_string& str) { WriteCompactSize(os, str.size()); if (!str.empty()) @@ -577,7 +571,7 @@ void Serialize(Stream& os, const std::basic_string& str, int, int) } template -void Unserialize(Stream& is, std::basic_string& str, int, int) +void Unserialize(Stream& is, std::basic_string& str) { unsigned int nSize = ReadCompactSize(is); str.resize(nSize); @@ -591,7 +585,7 @@ void Unserialize(Stream& is, std::basic_string& str, int, int) * prevector */ template -void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const unsigned char&) +void Serialize_impl(Stream& os, const prevector& v, const unsigned char&) { WriteCompactSize(os, v.size()); if (!v.empty()) @@ -599,22 +593,22 @@ void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersio } template -void Serialize_impl(Stream& os, const prevector& v, int nType, int nVersion, const V&) +void Serialize_impl(Stream& os, const prevector& v, const V&) { WriteCompactSize(os, v.size()); for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - ::Serialize(os, (*vi), nType, nVersion); + ::Serialize(os, (*vi)); } template -inline void Serialize(Stream& os, const prevector& v, int nType, int nVersion) +inline void Serialize(Stream& os, const prevector& v) { - Serialize_impl(os, v, nType, nVersion, T()); + Serialize_impl(os, v, T()); } template -void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const unsigned char&) +void Unserialize_impl(Stream& is, prevector& v, const unsigned char&) { // Limit size per read so bogus size value won't cause out of memory v.clear(); @@ -630,7 +624,7 @@ void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, c } template -void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, const V&) +void Unserialize_impl(Stream& is, prevector& v, const V&) { v.clear(); unsigned int nSize = ReadCompactSize(is); @@ -643,14 +637,14 @@ void Unserialize_impl(Stream& is, prevector& v, int nType, int nVersion, c nMid = nSize; v.resize(nMid); for (; i < nMid; i++) - Unserialize(is, v[i], nType, nVersion); + Unserialize(is, v[i]); } } template -inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion) +inline void Unserialize(Stream& is, prevector& v) { - Unserialize_impl(is, v, nType, nVersion, T()); + Unserialize_impl(is, v, T()); } @@ -659,7 +653,7 @@ inline void Unserialize(Stream& is, prevector& v, int nType, int nVersion) * vector */ template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const unsigned char&) +void Serialize_impl(Stream& os, const std::vector& v, const unsigned char&) { WriteCompactSize(os, v.size()); if (!v.empty()) @@ -667,22 +661,22 @@ void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVers } template -void Serialize_impl(Stream& os, const std::vector& v, int nType, int nVersion, const V&) +void Serialize_impl(Stream& os, const std::vector& v, const V&) { WriteCompactSize(os, v.size()); for (typename std::vector::const_iterator vi = v.begin(); vi != v.end(); ++vi) - ::Serialize(os, (*vi), nType, nVersion); + ::Serialize(os, (*vi)); } template -inline void Serialize(Stream& os, const std::vector& v, int nType, int nVersion) +inline void Serialize(Stream& os, const std::vector& v) { - Serialize_impl(os, v, nType, nVersion, T()); + Serialize_impl(os, v, T()); } template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const unsigned char&) +void Unserialize_impl(Stream& is, std::vector& v, const unsigned char&) { // Limit size per read so bogus size value won't cause out of memory v.clear(); @@ -698,7 +692,7 @@ void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, } template -void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, const V&) +void Unserialize_impl(Stream& is, std::vector& v, const V&) { v.clear(); unsigned int nSize = ReadCompactSize(is); @@ -711,14 +705,14 @@ void Unserialize_impl(Stream& is, std::vector& v, int nType, int nVersion, nMid = nSize; v.resize(nMid); for (; i < nMid; i++) - Unserialize(is, v[i], nType, nVersion); + Unserialize(is, v[i]); } } template -inline void Unserialize(Stream& is, std::vector& v, int nType, int nVersion) +inline void Unserialize(Stream& is, std::vector& v) { - Unserialize_impl(is, v, nType, nVersion, T()); + Unserialize_impl(is, v, T()); } @@ -784,17 +778,17 @@ void Unserialize(Stream& is, boost::array& item, int nType, int nVersion) * pair */ template -void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) +void Serialize(Stream& os, const std::pair& item) { - Serialize(os, item.first, nType, nVersion); - Serialize(os, item.second, nType, nVersion); + Serialize(os, item.first); + Serialize(os, item.second); } template -void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) +void Unserialize(Stream& is, std::pair& item) { - Unserialize(is, item.first, nType, nVersion); - Unserialize(is, item.second, nType, nVersion); + Unserialize(is, item.first); + Unserialize(is, item.second); } @@ -803,15 +797,15 @@ void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) * map */ template -void Serialize(Stream& os, const std::map& m, int nType, int nVersion) +void Serialize(Stream& os, const std::map& m) { WriteCompactSize(os, m.size()); for (typename std::map::const_iterator mi = m.begin(); mi != m.end(); ++mi) - Serialize(os, (*mi), nType, nVersion); + Serialize(os, (*mi)); } template -void Unserialize(Stream& is, std::map& m, int nType, int nVersion) +void Unserialize(Stream& is, std::map& m) { m.clear(); unsigned int nSize = ReadCompactSize(is); @@ -819,7 +813,7 @@ void Unserialize(Stream& is, std::map& m, int nType, int nVersion for (unsigned int i = 0; i < nSize; i++) { std::pair item; - Unserialize(is, item, nType, nVersion); + Unserialize(is, item); mi = m.insert(mi, item); } } @@ -830,15 +824,15 @@ void Unserialize(Stream& is, std::map& m, int nType, int nVersion * set */ template -void Serialize(Stream& os, const std::set& m, int nType, int nVersion) +void Serialize(Stream& os, const std::set& m) { WriteCompactSize(os, m.size()); for (typename std::set::const_iterator it = m.begin(); it != m.end(); ++it) - Serialize(os, (*it), nType, nVersion); + Serialize(os, (*it)); } template -void Unserialize(Stream& is, std::set& m, int nType, int nVersion) +void Unserialize(Stream& is, std::set& m) { m.clear(); unsigned int nSize = ReadCompactSize(is); @@ -846,7 +840,7 @@ void Unserialize(Stream& is, std::set& m, int nType, int nVersion) for (unsigned int i = 0; i < nSize; i++) { K key; - Unserialize(is, key, nType, nVersion); + Unserialize(is, key); it = m.insert(it, key); } } @@ -893,15 +887,15 @@ struct CSerActionUnserialize }; template -inline void SerReadWrite(Stream& s, const T& obj, int nType, int nVersion, CSerActionSerialize ser_action) +inline void SerReadWrite(Stream& s, const T& obj, CSerActionSerialize ser_action) { - ::Serialize(s, obj, nType, nVersion); + ::Serialize(s, obj); } template -inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionUnserialize ser_action) +inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action) { - ::Unserialize(s, obj, nType, nVersion); + ::Unserialize(s, obj); } @@ -920,7 +914,6 @@ protected: const int nType; const int nVersion; public: - CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} void write(const char *psz, size_t nSize) @@ -931,61 +924,64 @@ public: template CSizeComputer& operator<<(const T& obj) { - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } size_t size() const { return nSize; } + + int GetVersion() const { return nVersion; } + int GetType() const { return nType; } }; template -void SerializeMany(Stream& s, int nType, int nVersion) +void SerializeMany(Stream& s) { } template -void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg) +void SerializeMany(Stream& s, Arg&& arg) { - ::Serialize(s, std::forward(arg), nType, nVersion); + ::Serialize(s, std::forward(arg)); } template -void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg, Args&&... args) +void SerializeMany(Stream& s, Arg&& arg, Args&&... args) { - ::Serialize(s, std::forward(arg), nType, nVersion); - ::SerializeMany(s, nType, nVersion, std::forward(args)...); + ::Serialize(s, std::forward(arg)); + ::SerializeMany(s, std::forward(args)...); } template -inline void UnserializeMany(Stream& s, int nType, int nVersion) +inline void UnserializeMany(Stream& s) { } template -inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg) +inline void UnserializeMany(Stream& s, Arg& arg) { - ::Unserialize(s, arg, nType, nVersion); + ::Unserialize(s, arg); } template -inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg, Args&... args) +inline void UnserializeMany(Stream& s, Arg& arg, Args&... args) { - ::Unserialize(s, arg, nType, nVersion); - ::UnserializeMany(s, nType, nVersion, args...); + ::Unserialize(s, arg); + ::UnserializeMany(s, args...); } template -inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionSerialize ser_action, Args&&... args) +inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, Args&&... args) { - ::SerializeMany(s, nType, nVersion, std::forward(args)...); + ::SerializeMany(s, std::forward(args)...); } template -inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionUnserialize ser_action, Args&... args) +inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&... args) { - ::UnserializeMany(s, nType, nVersion, args...); + ::UnserializeMany(s, args...); } template diff --git a/src/streams.h b/src/streams.h index 6fc8a93da..2fb6c7e01 100644 --- a/src/streams.h +++ b/src/streams.h @@ -85,7 +85,7 @@ public: CBaseDataStream(int nTypeIn, int nVersionIn, Args&&... args) { Init(nTypeIn, nVersionIn); - ::SerializeMany(*this, nType, nVersion, std::forward(args)...); + ::SerializeMany(*this, std::forward(args)...); } void Init(int nTypeIn, int nVersionIn) @@ -268,7 +268,7 @@ public: } template - void Serialize(Stream& s, int nType, int nVersion) const + void Serialize(Stream& s) const { // Special case: stream << stream concatenates like stream += stream if (!vch.empty()) @@ -279,7 +279,7 @@ public: CBaseDataStream& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } @@ -287,7 +287,7 @@ public: CBaseDataStream& operator>>(T& obj) { // Unserialize from this stream - ::Unserialize(*this, obj, nType, nVersion); + ::Unserialize(*this, obj); return (*this); } @@ -428,7 +428,7 @@ public: // Serialize to this stream if (!file) throw std::ios_base::failure("CAutoFile::operator<<: file handle is NULL"); - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } @@ -438,7 +438,7 @@ public: // Unserialize from this stream if (!file) throw std::ios_base::failure("CAutoFile::operator>>: file handle is NULL"); - ::Unserialize(*this, obj, nType, nVersion); + ::Unserialize(*this, obj); return (*this); } }; @@ -497,6 +497,9 @@ public: fclose(); } + int GetVersion() const { return nVersion; } + int GetType() const { return nType; } + void fclose() { if (src) { @@ -575,7 +578,7 @@ public: template CBufferedFile& operator>>(T& obj) { // Unserialize from this stream - ::Unserialize(*this, obj, nType, nVersion); + ::Unserialize(*this, obj); return (*this); } diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index e99f99226..a8f3c0454 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "BloomFilter doesn't contain just-inserted object (3)!"); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); + stream << filter; vector vch = ParseHex("03614e9b050000000000000001"); vector expected(vch.size()); @@ -73,7 +73,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) BOOST_CHECK_MESSAGE(filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "BloomFilter doesn't contain just-inserted object (3)!"); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); + stream << filter; vector vch = ParseHex("03ce4299050000000100008001"); vector expected(vch.size()); @@ -100,7 +100,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key) filter.insert(vector(hash.begin(), hash.end())); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); - filter.Serialize(stream, SER_NETWORK, PROTOCOL_VERSION); + stream << filter; vector vch = ParseHex("038fc16b080000000000000001"); vector expected(vch.size()); diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index c9b119ab2..a047938db 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -163,7 +163,7 @@ struct StringContentsSerializer { ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { if (ser_action.ForRead()) { str.clear(); char c = 0; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 59a42d0a9..6c0144271 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -50,7 +50,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(intval); READWRITE(boolval); READWRITE(stringval); @@ -75,7 +75,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval); } }; diff --git a/src/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index f8b9c70e0..a6501faa1 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -187,22 +187,22 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(GetSerializeSize(R1L, 0, PROTOCOL_VERSION) == 32); BOOST_CHECK(GetSerializeSize(ZeroL, 0, PROTOCOL_VERSION) == 32); - std::stringstream ss; - R1L.Serialize(ss,0,PROTOCOL_VERSION); + CDataStream ss(0, PROTOCOL_VERSION); + ss << R1L; BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+32)); - TmpL.Unserialize(ss,0,PROTOCOL_VERSION); + ss >> TmpL; BOOST_CHECK(R1L == TmpL); - ss.str(""); - ZeroL.Serialize(ss,0,PROTOCOL_VERSION); + ss.clear(); + ss << ZeroL; BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+32)); - TmpL.Unserialize(ss,0,PROTOCOL_VERSION); + ss >> TmpL; BOOST_CHECK(ZeroL == TmpL); - ss.str(""); - MaxL.Serialize(ss,0,PROTOCOL_VERSION); + ss.clear(); + ss << MaxL; BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+32)); - TmpL.Unserialize(ss,0,PROTOCOL_VERSION); + ss >> TmpL; BOOST_CHECK(MaxL == TmpL); - ss.str(""); + ss.clear(); BOOST_CHECK(R1S.GetHex() == R1S.ToString()); BOOST_CHECK(R2S.GetHex() == R2S.ToString()); @@ -233,21 +233,21 @@ BOOST_AUTO_TEST_CASE( methods ) // GetHex SetHex begin() end() size() GetLow64 G BOOST_CHECK(GetSerializeSize(R1S, 0, PROTOCOL_VERSION) == 20); BOOST_CHECK(GetSerializeSize(ZeroS, 0, PROTOCOL_VERSION) == 20); - R1S.Serialize(ss,0,PROTOCOL_VERSION); + ss << R1S; BOOST_CHECK(ss.str() == std::string(R1Array,R1Array+20)); - TmpS.Unserialize(ss,0,PROTOCOL_VERSION); + ss >> TmpS; BOOST_CHECK(R1S == TmpS); - ss.str(""); - ZeroS.Serialize(ss,0,PROTOCOL_VERSION); + ss.clear(); + ss << ZeroS; BOOST_CHECK(ss.str() == std::string(ZeroArray,ZeroArray+20)); - TmpS.Unserialize(ss,0,PROTOCOL_VERSION); + ss >> TmpS; BOOST_CHECK(ZeroS == TmpS); - ss.str(""); - MaxS.Serialize(ss,0,PROTOCOL_VERSION); + ss.clear(); + ss << MaxS; BOOST_CHECK(ss.str() == std::string(MaxArray,MaxArray+20)); - TmpS.Unserialize(ss,0,PROTOCOL_VERSION); + ss >> TmpS; BOOST_CHECK(MaxS == TmpS); - ss.str(""); + ss.clear(); } BOOST_AUTO_TEST_CASE( conversion ) diff --git a/src/uint256.h b/src/uint256.h index 6e79d31cd..b3a6cb242 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -76,13 +76,13 @@ public: } template - void Serialize(Stream& s, int nType, int nVersion) const + void Serialize(Stream& s) const { s.write((char*)data, sizeof(data)); } template - void Unserialize(Stream& s, int nType, int nVersion) + void Unserialize(Stream& s) { s.read((char*)data, sizeof(data)); } diff --git a/src/undo.h b/src/undo.h index 274c01ed9..e01814e72 100644 --- a/src/undo.h +++ b/src/undo.h @@ -28,22 +28,22 @@ public: CTxInUndo(const CTxOut &txoutIn, bool fCoinBaseIn = false, unsigned int nHeightIn = 0, int nVersionIn = 0) : txout(txoutIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), nVersion(nVersionIn) { } template - void Serialize(Stream &s, int nType, int nVersion) const { - ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0)), nType, nVersion); + void Serialize(Stream &s) const { + ::Serialize(s, VARINT(nHeight*2+(fCoinBase ? 1 : 0))); if (nHeight > 0) - ::Serialize(s, VARINT(this->nVersion), nType, nVersion); - ::Serialize(s, CTxOutCompressor(REF(txout)), nType, nVersion); + ::Serialize(s, VARINT(this->nVersion)); + ::Serialize(s, CTxOutCompressor(REF(txout))); } template - void Unserialize(Stream &s, int nType, int nVersion) { + void Unserialize(Stream &s) { unsigned int nCode = 0; - ::Unserialize(s, VARINT(nCode), nType, nVersion); + ::Unserialize(s, VARINT(nCode)); nHeight = nCode / 2; fCoinBase = nCode & 1; if (nHeight > 0) - ::Unserialize(s, VARINT(this->nVersion), nType, nVersion); - ::Unserialize(s, REF(CTxOutCompressor(REF(txout))), nType, nVersion); + ::Unserialize(s, VARINT(this->nVersion)); + ::Unserialize(s, REF(CTxOutCompressor(REF(txout)))); } }; @@ -57,7 +57,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vprevout); } }; @@ -72,7 +72,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vtxundo); READWRITE(old_tree_root); } diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index bcee188cf..e0d91ee5a 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -48,7 +48,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vchCryptedKey); READWRITE(vchSalt); READWRITE(nDerivationMethod); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3530d7632..5a16cb290 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -93,8 +93,9 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(nTime); READWRITE(vchPubKey); @@ -314,7 +315,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(*(CTransaction*)this); READWRITE(hashBlock); READWRITE(vMerkleBranch); @@ -432,7 +433,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { if (ser_action.ForRead()) Init(NULL); char fSpent = false; @@ -565,8 +566,9 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(vchPrivKey); READWRITE(nTimeCreated); @@ -610,8 +612,9 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); //! Note: strAccount is serialized as part of the key, not here. READWRITE(nCreditDebit); @@ -624,7 +627,7 @@ public: if (!(mapValue.empty() && _ssExtra.empty())) { - CDataStream ss(nType, nVersion); + CDataStream ss(s.GetType(), s.GetVersion()); ss.insert(ss.begin(), '\0'); ss << mapValue; ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end()); @@ -640,7 +643,7 @@ public: mapValue.clear(); if (std::string::npos != nSepPos) { - CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion); + CDataStream ss(std::vector(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion()); ss >> mapValue; _ssExtra = std::vector(ss.begin(), ss.end()); } @@ -1204,8 +1207,9 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) + inline void SerializationOp(Stream& s, Operation ser_action) { + int nVersion = s.GetVersion(); + if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); READWRITE(vchPubKey); } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index a977e17ee..c388921f0 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -60,7 +60,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); READWRITE(nCreateTime); } From 68a1a592ca479146e6c228ef76471e7d4a8ad94e Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sun, 15 Apr 2018 21:09:19 -0600 Subject: [PATCH 14/20] Remove nType and nVersion from Zcash-specific code --- src/alert.h | 4 +-- src/chain.h | 2 +- src/hash.h | 2 +- src/paymentdisclosure.h | 6 ++--- src/primitives/block.h | 3 +-- src/primitives/transaction.h | 4 +-- src/script/interpreter.cpp | 6 ++--- src/serialize.h | 42 ++++++++++++++--------------- src/uint252.h | 2 +- src/wallet/wallet.h | 4 +-- src/zcash/Address.hpp | 4 +-- src/zcash/IncrementalMerkleTree.hpp | 6 ++--- src/zcash/Note.hpp | 2 +- src/zcash/Proof.hpp | 10 +++---- 14 files changed, 47 insertions(+), 50 deletions(-) diff --git a/src/alert.h b/src/alert.h index 76d8d916e..bf29e854c 100644 --- a/src/alert.h +++ b/src/alert.h @@ -49,7 +49,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); nVersion = this->nVersion; READWRITE(nRelayUntil); @@ -87,7 +87,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vchMsg); READWRITE(vchSig); } diff --git a/src/chain.h b/src/chain.h index 793ef4f03..906267326 100644 --- a/src/chain.h +++ b/src/chain.h @@ -380,7 +380,7 @@ public: // Only read/write nSproutValue if the client version used to create // this index was storing them. - if ((nType & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) { + if ((s.GetType() & SER_DISK) && (nVersion >= SPROUT_VALUE_VERSION)) { READWRITE(nSproutValue); } } diff --git a/src/hash.h b/src/hash.h index 8276c9184..76634bd37 100644 --- a/src/hash.h +++ b/src/hash.h @@ -197,7 +197,7 @@ public: template CBLAKE2bWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; diff --git a/src/paymentdisclosure.h b/src/paymentdisclosure.h index c5d29d5c6..b3681affc 100644 --- a/src/paymentdisclosure.h +++ b/src/paymentdisclosure.h @@ -48,7 +48,7 @@ struct PaymentDisclosureInfo { ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(version); READWRITE(esk); READWRITE(joinSplitPrivKey); @@ -81,7 +81,7 @@ struct PaymentDisclosurePayload { ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(marker); READWRITE(version); READWRITE(esk); @@ -123,7 +123,7 @@ struct PaymentDisclosure { ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(payload); READWRITE(payloadSig); } diff --git a/src/primitives/block.h b/src/primitives/block.h index 7fe1a3588..1d8750588 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -155,9 +155,8 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(this->nVersion); - nVersion = this->nVersion; READWRITE(hashPrevBlock); READWRITE(hashMerkleRoot); READWRITE(hashReserved); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 60ea11239..7a4a315e2 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -109,7 +109,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(vpub_old); READWRITE(vpub_new); READWRITE(anchor); @@ -383,7 +383,6 @@ public: uint32_t header = GetHeader(); READWRITE(header); } - nVersion = this->nVersion; if (fOverwintered) { READWRITE(*const_cast(&this->nVersionGroupId)); } @@ -498,7 +497,6 @@ struct CMutableTransaction } READWRITE(header); } - nVersion = this->nVersion; if (fOverwintered) { READWRITE(nVersionGroupId); } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f262faef9..e405b42f3 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1046,12 +1046,12 @@ public: // keeps the JoinSplit cryptographically bound // to the transaction. // - ::Serialize(s, txTo.vjoinsplit, nType, nVersion); + ::Serialize(s, txTo.vjoinsplit); if (txTo.vjoinsplit.size() > 0) { - ::Serialize(s, txTo.joinSplitPubKey, nType, nVersion); + ::Serialize(s, txTo.joinSplitPubKey); CTransaction::joinsplit_sig_t nullSig = {}; - ::Serialize(s, nullSig, nType, nVersion); + ::Serialize(s, nullSig); } } } diff --git a/src/serialize.h b/src/serialize.h index 0cc5216fd..2bb80f822 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -503,14 +503,14 @@ template inline void Unserialize(Stream /** * optional */ -template void Serialize(Stream& os, const boost::optional& item, int nType, int nVersion); -template void Unserialize(Stream& is, boost::optional& item, int nType, int nVersion); +template void Serialize(Stream& os, const boost::optional& item); +template void Unserialize(Stream& is, boost::optional& item); /** * array */ -template void Serialize(Stream& os, const boost::array& item, int nType, int nVersion); -template void Unserialize(Stream& is, boost::array& item, int nType, int nVersion); +template void Serialize(Stream& os, const boost::array& item); +template void Unserialize(Stream& is, boost::array& item); /** * pair @@ -533,8 +533,8 @@ template void Unserializ /** * list */ -template void Serialize(Stream& os, const std::list& m, int nType, int nVersion); -template void Unserialize(Stream& is, std::list& m, int nType, int nVersion); +template void Serialize(Stream& os, const std::list& m); +template void Unserialize(Stream& is, std::list& m); @@ -721,31 +721,31 @@ inline void Unserialize(Stream& is, std::vector& v) * optional */ template -void Serialize(Stream& os, const boost::optional& item, int nType, int nVersion) +void Serialize(Stream& os, const boost::optional& item) { // If the value is there, put 0x01 and then serialize the value. // If it's not, put 0x00. if (item) { unsigned char discriminant = 0x01; - Serialize(os, discriminant, nType, nVersion); - Serialize(os, *item, nType, nVersion); + Serialize(os, discriminant); + Serialize(os, *item); } else { unsigned char discriminant = 0x00; - Serialize(os, discriminant, nType, nVersion); + Serialize(os, discriminant); } } template -void Unserialize(Stream& is, boost::optional& item, int nType, int nVersion) +void Unserialize(Stream& is, boost::optional& item) { unsigned char discriminant = 0x00; - Unserialize(is, discriminant, nType, nVersion); + Unserialize(is, discriminant); if (discriminant == 0x00) { item = boost::none; } else if (discriminant == 0x01) { T object; - Unserialize(is, object, nType, nVersion); + Unserialize(is, object); item = object; } else { throw std::ios_base::failure("non-canonical optional discriminant"); @@ -758,18 +758,18 @@ void Unserialize(Stream& is, boost::optional& item, int nType, int nVersion) * array */ template -void Serialize(Stream& os, const boost::array& item, int nType, int nVersion) +void Serialize(Stream& os, const boost::array& item) { for (size_t i = 0; i < N; i++) { - Serialize(os, item[i], nType, nVersion); + Serialize(os, item[i]); } } template -void Unserialize(Stream& is, boost::array& item, int nType, int nVersion) +void Unserialize(Stream& is, boost::array& item) { for (size_t i = 0; i < N; i++) { - Unserialize(is, item[i], nType, nVersion); + Unserialize(is, item[i]); } } @@ -851,15 +851,15 @@ void Unserialize(Stream& is, std::set& m) * list */ template -void Serialize(Stream& os, const std::list& l, int nType, int nVersion) +void Serialize(Stream& os, const std::list& l) { WriteCompactSize(os, l.size()); for (typename std::list::const_iterator it = l.begin(); it != l.end(); ++it) - Serialize(os, (*it), nType, nVersion); + Serialize(os, (*it)); } template -void Unserialize(Stream& is, std::list& l, int nType, int nVersion) +void Unserialize(Stream& is, std::list& l) { l.clear(); unsigned int nSize = ReadCompactSize(is); @@ -867,7 +867,7 @@ void Unserialize(Stream& is, std::list& l, int nType, int nVersion) for (unsigned int i = 0; i < nSize; i++) { T item; - Unserialize(is, item, nType, nVersion); + Unserialize(is, item); l.push_back(item); } } diff --git a/src/uint252.h b/src/uint252.h index 6281e8533..e7b98ddf0 100644 --- a/src/uint252.h +++ b/src/uint252.h @@ -15,7 +15,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(contents); if ((*contents.begin()) & 0xF0) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 5a16cb290..6c968fca9 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -170,7 +170,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(hash); READWRITE(js); READWRITE(n); @@ -241,7 +241,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(address); READWRITE(nullifier); READWRITE(witnesses); diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index 2dbe10a60..c165c20dd 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -22,7 +22,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(a_pk); READWRITE(pk_enc); } @@ -58,7 +58,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(a_pk); READWRITE(sk_enc); } diff --git a/src/zcash/IncrementalMerkleTree.hpp b/src/zcash/IncrementalMerkleTree.hpp index fd7c61518..c4cf9d675 100644 --- a/src/zcash/IncrementalMerkleTree.hpp +++ b/src/zcash/IncrementalMerkleTree.hpp @@ -21,7 +21,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { std::vector> pathBytes; uint64_t indexInt; if (ser_action.ForRead()) { @@ -112,7 +112,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(left); READWRITE(right); READWRITE(parents); @@ -178,7 +178,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(tree); READWRITE(filled); READWRITE(cursor); diff --git a/src/zcash/Note.hpp b/src/zcash/Note.hpp index faacd2720..9b2676931 100644 --- a/src/zcash/Note.hpp +++ b/src/zcash/Note.hpp @@ -40,7 +40,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { unsigned char leadingByte = 0x00; READWRITE(leadingByte); diff --git a/src/zcash/Proof.hpp b/src/zcash/Proof.hpp index 5f05aa2c5..573a65cd3 100644 --- a/src/zcash/Proof.hpp +++ b/src/zcash/Proof.hpp @@ -25,7 +25,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(data); } @@ -58,7 +58,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(data); } @@ -93,7 +93,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { unsigned char leadingByte = G1_PREFIX_MASK; if (y_lsb) { @@ -143,7 +143,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { unsigned char leadingByte = G2_PREFIX_MASK; if (y_gt) { @@ -204,7 +204,7 @@ public: ADD_SERIALIZE_METHODS; template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(g_A); READWRITE(g_A_prime); READWRITE(g_B); From 9b228f0391792b5399b3cebdb1cf2aef853a909a Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 30 Oct 2016 13:09:20 -0700 Subject: [PATCH 15/20] Avoid -Wshadow errors Suggested by Pavel Janik. --- src/serialize.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serialize.h b/src/serialize.h index 2bb80f822..3b100481d 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -442,7 +442,7 @@ class LimitedString protected: std::string& string; public: - LimitedString(std::string& string) : string(string) {} + LimitedString(std::string& _string) : string(_string) {} template void Unserialize(Stream& s) @@ -916,9 +916,9 @@ protected: public: CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {} - void write(const char *psz, size_t nSize) + void write(const char *psz, size_t _nSize) { - this->nSize += nSize; + this->nSize += _nSize; } template From 93aaf4fc94c7669391bd101755a1aba1573e5310 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 17:07:29 -0700 Subject: [PATCH 16/20] Make CSerAction's ForRead() constexpr The CSerAction's ForRead() method does not depend on any runtime data, so guarantee that requests to it can be optimized out by making it constexpr. Suggested by Cory Fields. --- src/serialize.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serialize.h b/src/serialize.h index 3b100481d..3b73c5cdf 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -879,11 +879,11 @@ void Unserialize(Stream& is, std::list& l) */ struct CSerActionSerialize { - bool ForRead() const { return false; } + constexpr bool ForRead() const { return false; } }; struct CSerActionUnserialize { - bool ForRead() const { return true; } + constexpr bool ForRead() const { return true; } }; template From 098917052d7ef656d1866dc4f8f730bc56b09fe0 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 17:50:04 -0700 Subject: [PATCH 17/20] Add optimized CSizeComputer serializers To get the advantages of faster GetSerializeSize() implementations back that were removed in "Make GetSerializeSize a wrapper on top of CSizeComputer", reintroduce them in the few places in the form of a specialized Serialize() implementation. This actually gets us in a better state than before, as these even get used when they're invoked indirectly in the serialization of another object. --- src/pubkey.h | 5 +++++ src/serialize.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/pubkey.h b/src/pubkey.h index 9521bd2c0..12f11c249 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -214,6 +214,11 @@ struct CExtPubKey { void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtPubKey& out, unsigned int nChild) const; + void Serialize(CSizeComputer& s) const + { + // Optimized implementation for ::GetSerializeSize that avoids copying. + s.seek(BIP32_EXTKEY_SIZE + 1); // add one byte for the size (compact int) + } template void Serialize(Stream& s) const { diff --git a/src/serialize.h b/src/serialize.h index 3b73c5cdf..c713c3fe1 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -156,6 +156,8 @@ inline float ser_uint32_to_float(uint32_t y) // i.e. anything that supports .read(char*, size_t) and .write(char*, size_t) // +class CSizeComputer; + enum { // primary actions @@ -230,6 +232,8 @@ inline unsigned int GetSizeOfCompactSize(uint64_t nSize) else return 9; } +inline void WriteCompactSize(CSizeComputer& os, uint64_t nSize); + template void WriteCompactSize(Stream& os, uint64_t nSize) { @@ -323,6 +327,9 @@ inline unsigned int GetSizeOfVarInt(I n) return nRet; } +template +inline void WriteVarInt(CSizeComputer& os, I n); + template void WriteVarInt(Stream& os, I n) { @@ -906,6 +913,17 @@ inline void SerReadWrite(Stream& s, T& obj, CSerActionUnserialize ser_action) +/* ::GetSerializeSize implementations + * + * Computing the serialized size of objects is done through a special stream + * object of type CSizeComputer, which only records the number of bytes written + * to it. + * + * If your Serialize or SerializationOp method has non-trivial overhead for + * serialization, it may be worthwhile to implement a specialized version for + * CSizeComputer, which uses the s.seek() method to record bytes that would + * be written instead. + */ class CSizeComputer { protected: @@ -921,6 +939,12 @@ public: this->nSize += _nSize; } + /** Pretend _nSize bytes are written, without specifying them. */ + void seek(size_t _nSize) + { + this->nSize += _nSize; + } + template CSizeComputer& operator<<(const T& obj) { @@ -984,6 +1008,17 @@ inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&. ::UnserializeMany(s, args...); } +template +inline void WriteVarInt(CSizeComputer &s, I n) +{ + s.seek(GetSizeOfVarInt(n)); +} + +inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize) +{ + s.seek(GetSizeOfCompactSize(nSize)); +} + template size_t GetSerializeSize(const T& t, int nType, int nVersion = 0) { From 87a5975ca0a6e37c0a8df049a88140a895978fe1 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 28 Oct 2016 19:12:39 -0700 Subject: [PATCH 18/20] Use fixed preallocation instead of costly GetSerializeSize Dbwrapper used GetSerializeSize() to compute the size of the buffer to preallocate. For some cases (specifically: CCoins) this requires a costly compression call. Avoid this by just using fixed size preallocations instead. --- src/dbwrapper.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/dbwrapper.h b/src/dbwrapper.h index 1d62d2b72..e3f9a2652 100644 --- a/src/dbwrapper.h +++ b/src/dbwrapper.h @@ -16,6 +16,9 @@ #include #include +static const size_t DBWRAPPER_PREALLOC_KEY_SIZE = 64; +static const size_t DBWRAPPER_PREALLOC_VALUE_SIZE = 1024; + class dbwrapper_error : public std::runtime_error { public: @@ -53,12 +56,12 @@ public: void Write(const K& key, const V& value) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(GetSerializeSize(ssKey, key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue.reserve(GetSerializeSize(ssValue, value)); + ssValue.reserve(DBWRAPPER_PREALLOC_VALUE_SIZE); ssValue << value; leveldb::Slice slValue(&ssValue[0], ssValue.size()); @@ -69,7 +72,7 @@ public: void Erase(const K& key) { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(GetSerializeSize(ssKey, key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); @@ -177,7 +180,7 @@ public: bool Read(const K& key, V& value) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(GetSerializeSize(ssKey, key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); @@ -210,7 +213,7 @@ public: bool Exists(const K& key) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(GetSerializeSize(ssKey, key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); From 40cc9aa7dd9155256cd6f3d46027f95333b298fe Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 10 Nov 2016 10:54:14 -0800 Subject: [PATCH 19/20] Add serialization for unique_ptr and shared_ptr --- src/serialize.h | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/serialize.h b/src/serialize.h index c713c3fe1..829d565a2 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,20 @@ static const unsigned int MAX_SIZE = 0x02000000; +/** + * Dummy data type to identify deserializing constructors. + * + * By convention, a constructor of a type T with signature + * + * template T::T(deserialize_type, Stream& s) + * + * is a deserializing constructor, which builds the type by + * deserializing it from s. If T contains const fields, this + * is likely the only way to do so. + */ +struct deserialize_type {}; +constexpr deserialize_type deserialize {}; + /** * Used to bypass the rule against non-const reference to temporary * where it makes sense with wrappers such as CFlatData or CTxDB @@ -543,7 +558,17 @@ template void Unserializ template void Serialize(Stream& os, const std::list& m); template void Unserialize(Stream& is, std::list& m); +/** + * shared_ptr + */ +template void Serialize(Stream& os, const std::shared_ptr& p); +template void Unserialize(Stream& os, std::shared_ptr& p); +/** + * unique_ptr + */ +template void Serialize(Stream& os, const std::unique_ptr& p); +template void Unserialize(Stream& os, std::unique_ptr& p); @@ -881,6 +906,40 @@ void Unserialize(Stream& is, std::list& l) +/** + * unique_ptr + */ +template void +Serialize(Stream& os, const std::unique_ptr& p) +{ + Serialize(os, *p); +} + +template +void Unserialize(Stream& is, std::unique_ptr& p) +{ + p.reset(new T(deserialize, is)); +} + + + +/** + * shared_ptr + */ +template void +Serialize(Stream& os, const std::shared_ptr& p) +{ + Serialize(os, *p); +} + +template +void Unserialize(Stream& is, std::shared_ptr& p) +{ + p = std::make_shared(deserialize, is); +} + + + /** * Support for ADD_SERIALIZE_METHODS and READWRITE macro */ From c7d71985c9a76e94764cd28d5d46b986ad3f83db Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 10 Nov 2016 15:53:43 -0800 Subject: [PATCH 20/20] Add deserializing constructors to CTransaction and CMutableTransaction --- src/primitives/transaction.cpp | 8 ++++++++ src/primitives/transaction.h | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index b433f810f..36d46377b 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -184,6 +184,14 @@ CTransaction::CTransaction( assert(evilDeveloperFlag); } +CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), fOverwintered(tx.fOverwintered), nVersionGroupId(tx.nVersionGroupId), + vin(std::move(tx.vin)), vout(std::move(tx.vout)), nLockTime(tx.nLockTime), nExpiryHeight(tx.nExpiryHeight), + vjoinsplit(std::move(tx.vjoinsplit)), + joinSplitPubKey(std::move(tx.joinSplitPubKey)), joinSplitSig(std::move(tx.joinSplitSig)) +{ + UpdateHash(); +} + CTransaction& CTransaction::operator=(const CTransaction &tx) { *const_cast(&fOverwintered) = tx.fOverwintered; *const_cast(&nVersion) = tx.nVersion; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 7a4a315e2..683b13543 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -366,6 +366,7 @@ public: /** Convert a CMutableTransaction into a CTransaction. */ CTransaction(const CMutableTransaction &tx); + CTransaction(CMutableTransaction &&tx); CTransaction& operator=(const CTransaction& tx); @@ -411,6 +412,9 @@ public: UpdateHash(); } + template + CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {} + bool IsNull() const { return vin.empty() && vout.empty(); } @@ -523,6 +527,11 @@ struct CMutableTransaction } } + template + CMutableTransaction(deserialize_type, Stream& s) { + Unserialize(s); + } + /** Compute the hash of this CMutableTransaction. This is computed on the * fly, as opposed to GetHash() in CTransaction, which uses a cached result. */