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/Makefile.am b/src/Makefile.am index 51079f6cf..825e061eb 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/addrman.h b/src/addrman.h index 0483e8bdb..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); @@ -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/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/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/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/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/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..906267326 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)); @@ -379,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/coins.h b/src/coins.h index a2bd78893..4e1cac438 100644 --- a/src/coins.h +++ b/src/coins.h @@ -153,31 +153,8 @@ 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 { + void Serialize(Stream &s) const { unsigned int nMaskSize = 0, nMaskCode = 0; CalcMaskSize(nMaskSize, nMaskCode); bool fFirst = vout.size() > 0 && !vout[0].IsNull(); @@ -185,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; @@ -220,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); @@ -232,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 fa702f0df..961365d26 100644 --- a/src/compressor.h +++ b/src/compressor.h @@ -55,16 +55,8 @@ 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 { + void Serialize(Stream &s) const { std::vector compr; if (Compress(compr)) { s << CFlatData(compr); @@ -76,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) { @@ -112,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/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_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/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/dbwrapper.h b/src/dbwrapper.h index 1f3b4fc16..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(ssKey.GetSerializeSize(key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue.reserve(ssValue.GetSerializeSize(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(ssKey.GetSerializeSize(key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); @@ -99,7 +102,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); @@ -177,7 +180,7 @@ public: bool Read(const K& key, V& value) const { CDataStream ssKey(SER_DISK, CLIENT_VERSION); - ssKey.reserve(ssKey.GetSerializeSize(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(ssKey.GetSerializeSize(key)); + ssKey.reserve(DBWRAPPER_PREALLOC_KEY_SIZE); ssKey << key; leveldb::Slice slKey(&ssKey[0], ssKey.size()); 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/hash.h b/src/hash.h index 06fcced0a..76634bd37 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,21 +121,30 @@ 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 { private: CHash256 ctx; + const int nType; + const int nVersion; public: - int nType; - int nVersion; CHashWriter(int nTypeIn, int nVersionIn) : nType(nTypeIn), nVersion(nVersionIn) {} - CHashWriter& write(const char *pch, size_t size) { + 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); - return (*this); } // invalidates the object @@ -147,7 +157,7 @@ public: template CHashWriter& operator<<(const T& obj) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } }; @@ -187,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/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..8d64151e3 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) 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) + { + 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/main.cpp b/src/main.cpp index 587032547..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()); @@ -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/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/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/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/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/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/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/block.h b/src/primitives/block.h index 6b3f13a86..1d8750588 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); } @@ -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); @@ -185,8 +184,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.cpp b/src/primitives/transaction.cpp index b362d3d6e..36d46377b 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) {} @@ -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 bcd7eaa8a..683b13543 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); @@ -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,9 +205,9 @@ 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(scriptSig); + READWRITE(*(CScriptBase*)(&scriptSig)); READWRITE(nSequence); } @@ -250,9 +250,9 @@ 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(scriptPubKey); + READWRITE(*(CScriptBase*)(&scriptPubKey)); } void SetNull() @@ -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); } @@ -366,13 +366,14 @@ public: /** Convert a CMutableTransaction into a CTransaction. */ CTransaction(const CMutableTransaction &tx); + CTransaction(CMutableTransaction &&tx); CTransaction& operator=(const CTransaction& tx); 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; @@ -383,7 +384,6 @@ public: uint32_t header = GetHeader(); READWRITE(header); } - nVersion = this->nVersion; if (fOverwintered) { READWRITE(*const_cast(&this->nVersionGroupId)); } @@ -412,6 +412,9 @@ public: UpdateHash(); } + template + CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {} + bool IsNull() const { return vin.empty() && vout.empty(); } @@ -482,7 +485,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; @@ -498,7 +501,6 @@ struct CMutableTransaction } READWRITE(header); } - nVersion = this->nVersion; if (fOverwintered) { READWRITE(nVersionGroupId); } @@ -525,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. */ 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.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..12f11c249 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 { @@ -121,19 +123,15 @@ 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 + 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) { @@ -212,9 +210,34 @@ 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; + + 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 + { + 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) + { + 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/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/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..e405b42f3 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) { @@ -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, CScript(), 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) { @@ -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); } } } @@ -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; } 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..d5234cae8 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) @@ -215,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 @@ -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..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) { @@ -576,11 +580,10 @@ 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. - 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/script/zcashconsensus.cpp b/src/script/zcashconsensus.cpp index dbec305fc..50d732fff 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,16 +38,17 @@ public: memcpy(pch, m_data, nSize); m_remaining -= nSize; m_data += nSize; - return *this; } 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; @@ -80,7 +81,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 f776d6d99..829d565a2 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -24,10 +25,24 @@ #include #include -class CScript; +#include "prevector.h" 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 @@ -53,26 +68,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()); } @@ -156,6 +171,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 @@ -164,7 +181,8 @@ enum SER_GETHASH = (1 << 2), }; -#define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) +#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 @@ -172,63 +190,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 \ - 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);\ - } \ - 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 - */ -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 ) { 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 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 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 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)); } - -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; } +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; } @@ -250,6 +247,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) { @@ -343,6 +342,9 @@ inline unsigned int GetSizeOfVarInt(I n) return nRet; } +template +inline void WriteVarInt(CSizeComputer& os, I n); + template void WriteVarInt(Stream& os, I n) { @@ -376,6 +378,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))) /** @@ -394,24 +397,25 @@ 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; } 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 + 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); } @@ -425,31 +429,45 @@ protected: public: CVarInt(I& nIn) : n(nIn) { } - unsigned int GetSerializeSize(int, int) const { - return GetSizeOfVarInt(n); - } - 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); } }; +class CCompactSize +{ +protected: + uint64_t &n; +public: + CCompactSize(uint64_t& nIn) : n(nIn) { } + + template + void Serialize(Stream &s) const { + WriteCompactSize(s, n); + } + + template + void Unserialize(Stream& s) { + n = ReadCompactSize(s); + } +}; + template class LimitedString { protected: std::string& string; public: - LimitedString(std::string& string) : string(string) {} + 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) { @@ -461,17 +479,12 @@ public: } template - void Serialize(Stream& s, int, int=0) const + void Serialize(Stream& s) const { WriteCompactSize(s, string.size()); if (!string.empty()) s.write((char*)&string[0], string.size()); } - - unsigned int GetSerializeSize(int, int=0) const - { - return GetSizeOfCompactSize(string.size()) + string.size(); - } }; template @@ -484,99 +497,94 @@ 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); +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, 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 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); -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); - -/** - * 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); +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 */ -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); +template void Serialize(Stream& os, const boost::optional& item); +template void Unserialize(Stream& is, boost::optional& item); /** * 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); +template void Serialize(Stream& os, const boost::array& item); +template void Unserialize(Stream& is, boost::array& item); /** * 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); +template void Serialize(Stream& os, const std::pair& item); +template void Unserialize(Stream& is, std::pair& item); /** * 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); +template void Serialize(Stream& os, const std::map& m); +template void Unserialize(Stream& is, std::map& m); /** * 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); +template void Serialize(Stream& os, const std::set& m); +template void Unserialize(Stream& is, std::set& m); /** * 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); +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); /** * 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 unsigned int GetSerializeSize(const T& a, long nType, int nVersion) +template +inline void Serialize(Stream& os, const T& a) { - return a.GetSerializeSize((int)nType, nVersion); + a.Serialize(os); } template -inline void Serialize(Stream& os, const T& a, long nType, int nVersion) +inline void Unserialize(Stream& is, T& a) { - a.Serialize(os, (int)nType, nVersion); -} - -template -inline void Unserialize(Stream& is, T& a, long nType, int nVersion) -{ - a.Unserialize(is, (int)nType, nVersion); + a.Unserialize(is); } @@ -586,14 +594,8 @@ 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) +void Serialize(Stream& os, const std::basic_string& str) { WriteCompactSize(os, str.size()); if (!str.empty()) @@ -601,7 +603,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); @@ -611,33 +613,79 @@ void Unserialize(Stream& is, std::basic_string& str, int, int) +/** + * prevector + */ +template +void Serialize_impl(Stream& os, const prevector& v, 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, const V&) +{ + WriteCompactSize(os, v.size()); + for (typename prevector::const_iterator vi = v.begin(); vi != v.end(); ++vi) + ::Serialize(os, (*vi)); +} + +template +inline void Serialize(Stream& os, const prevector& v) +{ + Serialize_impl(os, v, T()); +} + + +template +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(); + 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, 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]); + } +} + +template +inline void Unserialize(Stream& is, prevector& v) +{ + Unserialize_impl(is, v, T()); +} + + + /** * 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&) +void Serialize_impl(Stream& os, const std::vector& v, const unsigned char&) { WriteCompactSize(os, v.size()); if (!v.empty()) @@ -645,22 +693,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(); @@ -676,7 +724,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); @@ -689,36 +737,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()); -} - - - -/** - * 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); + Unserialize_impl(is, v, T()); } @@ -726,42 +752,32 @@ void Unserialize(Stream& is, CScript& v, int nType, int nVersion) /** * 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) +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"); @@ -773,29 +789,19 @@ 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) +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]); } } @@ -803,24 +809,18 @@ void Unserialize(Stream& is, boost::array& item, int nType, int nVersion) /** * pair */ -template -unsigned int GetSerializeSize(const std::pair& item, int nType, int nVersion) +template +void Serialize(Stream& os, const std::pair& item) { - return GetSerializeSize(item.first, nType, nVersion) + GetSerializeSize(item.second, nType, nVersion); + Serialize(os, item.first); + Serialize(os, item.second); } template -void Serialize(Stream& os, const std::pair& item, int nType, int nVersion) +void Unserialize(Stream& is, std::pair& item) { - Serialize(os, item.first, nType, nVersion); - Serialize(os, item.second, nType, nVersion); -} - -template -void Unserialize(Stream& is, std::pair& item, int nType, int nVersion) -{ - Unserialize(is, item.first, nType, nVersion); - Unserialize(is, item.second, nType, nVersion); + Unserialize(is, item.first); + Unserialize(is, item.second); } @@ -828,25 +828,16 @@ 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) +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); @@ -854,7 +845,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); } } @@ -864,25 +855,16 @@ 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) +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); @@ -890,7 +872,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); } } @@ -900,25 +882,16 @@ 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) +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); @@ -926,35 +899,69 @@ 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); } } +/** + * 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 */ 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 -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); } @@ -965,33 +972,122 @@ inline void SerReadWrite(Stream& s, T& obj, int nType, int nVersion, CSerActionU +/* ::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: 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) {} - CSizeComputer& write(const char *psz, size_t nSize) + void write(const char *psz, size_t _nSize) { - this->nSize += nSize; - return *this; + 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) { - ::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) +{ +} + +template +void SerializeMany(Stream& s, Arg&& arg) +{ + ::Serialize(s, std::forward(arg)); +} + +template +void SerializeMany(Stream& s, Arg&& arg, Args&&... args) +{ + ::Serialize(s, std::forward(arg)); + ::SerializeMany(s, std::forward(args)...); +} + +template +inline void UnserializeMany(Stream& s) +{ +} + +template +inline void UnserializeMany(Stream& s, Arg& arg) +{ + ::Unserialize(s, arg); +} + +template +inline void UnserializeMany(Stream& s, Arg& arg, Args&... args) +{ + ::Unserialize(s, arg); + ::UnserializeMany(s, args...); +} + +template +inline void SerReadWriteMany(Stream& s, CSerActionSerialize ser_action, Args&&... args) +{ + ::SerializeMany(s, std::forward(args)...); +} + +template +inline void SerReadWriteMany(Stream& s, CSerActionUnserialize ser_action, Args&... 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) +{ + 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 81b58fd05..2fb6c7e01 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; @@ -80,6 +81,13 @@ public: Init(nTypeIn, nVersionIn); } + template + CBaseDataStream(int nTypeIn, int nVersionIn, Args&&... args) + { + Init(nTypeIn, nVersionIn); + ::SerializeMany(*this, std::forward(args)...); + } + void Init(int nTypeIn, int nVersionIn) { nReadPos = 0; @@ -212,13 +220,11 @@ 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; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } + int GetVersion() const { 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; @@ -231,14 +237,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) { @@ -251,39 +256,30 @@ 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 - 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()) 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) { // Serialize to this stream - ::Serialize(*this, obj, nType, nVersion); + ::Serialize(*this, obj); return (*this); } @@ -291,7 +287,7 @@ public: CBaseDataStream& operator>>(T& obj) { // Unserialize from this stream - ::Unserialize(*this, obj, nType, nVersion); + ::Unserialize(*this, obj); return (*this); } @@ -323,6 +319,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...) { } + }; @@ -347,17 +347,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() @@ -392,23 +390,18 @@ public: // // Stream subset // - void SetType(int n) { nType = n; } - int GetType() { return nType; } - void SetVersion(int n) { nVersion = n; } - int GetVersion() { return nVersion; } - void ReadVersion() { *this >> nVersion; } - void WriteVersion() { *this << nVersion; } + int GetType() const { return nType; } + int GetVersion() const { 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"); @@ -419,23 +412,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 - unsigned int GetSerializeSize(const T& obj) - { - // Tells the size of the object if serialized to this stream - return ::GetSerializeSize(obj, nType, nVersion); } template @@ -444,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); } @@ -454,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); } }; @@ -472,8 +456,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 @@ -503,11 +487,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() @@ -515,6 +497,9 @@ public: fclose(); } + int GetVersion() const { return nVersion; } + int GetType() const { return nType; } + void fclose() { if (src) { @@ -529,7 +514,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()) @@ -548,7 +533,6 @@ public: pch += nNow; nSize -= nNow; } - return (*this); } // return the current reading position @@ -594,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/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); } } 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/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 c43a0ea0c..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; } @@ -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))) @@ -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); @@ -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() diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index d3e51c7d1..6c0144271 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) { + 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) { + 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() 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/test/uint256_tests.cpp b/src/test/uint256_tests.cpp index 426d296a9..a6501faa1 100644 --- a/src/test/uint256_tests.cpp +++ b/src/test/uint256_tests.cpp @@ -184,25 +184,25 @@ 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); + 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()); @@ -230,24 +230,24 @@ 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); + 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/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/uint256.h b/src/uint256.h index 3729c981a..b3a6cb242 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -75,19 +75,14 @@ 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 + 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 2c7b74183..e01814e72 100644 --- a/src/undo.h +++ b/src/undo.h @@ -27,29 +27,23 @@ 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); + 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)))); } }; @@ -63,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); } }; @@ -78,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/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) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 407c81ffc..6c968fca9 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); @@ -169,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); @@ -240,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); @@ -314,9 +315,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(*(CTransaction*)this); - nVersion = this->nVersion; READWRITE(hashBlock); READWRITE(vMerkleBranch); READWRITE(nIndex); @@ -433,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; @@ -566,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); @@ -611,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); @@ -625,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()); @@ -641,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()); } @@ -1205,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.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"; diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index e455ad953..c388921f0 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -60,9 +60,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(nCreateTime); } 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);