diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index 36c4d17ff..714b84bd2 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -1,221 +1,221 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // Unit tests for denial-of-service detection/prevention code #include "chainparams.h" #include "config.h" #include "keystore.h" #include "net.h" #include "net_processing.h" #include "pow.h" #include "script/sign.h" #include "serialize.h" #include "util.h" #include "validation.h" #include "test/test_bitcoin.h" #include #include #include // Tests these internal-to-net_processing.cpp methods: extern bool AddOrphanTx(const CTransactionRef &tx, NodeId peer); extern void EraseOrphansFor(NodeId peer); extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); struct COrphanTx { CTransactionRef tx; NodeId fromPeer; int64_t nTimeExpire; }; extern std::map mapOrphanTransactions; CService ip(uint32_t i) { struct in_addr s; s.s_addr = i; return CService(CNetAddr(s), Params().GetDefaultPort()); } static NodeId id = 0; BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup) BOOST_AUTO_TEST_CASE(DoS_banning) { const Config &config = GetConfig(); std::atomic interruptDummy(false); connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); GetNodeSignals().InitializeNode(config, &dummyNode1, *connman); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; // Should get banned. Misbehaving(dummyNode1.GetId(), 100, ""); SendMessages(config, &dummyNode1, *connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); // Different IP, not banned. BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001 | 0x0000ff00))); CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true); dummyNode2.SetSendVersion(PROTOCOL_VERSION); GetNodeSignals().InitializeNode(config, &dummyNode2, *connman); dummyNode2.nVersion = 1; dummyNode2.fSuccessfullyConnected = true; Misbehaving(dummyNode2.GetId(), 50, ""); SendMessages(config, &dummyNode2, *connman, interruptDummy); // 2 not banned yet... BOOST_CHECK(!connman->IsBanned(addr2)); // ... but 1 still should be. BOOST_CHECK(connman->IsBanned(addr1)); Misbehaving(dummyNode2.GetId(), 50, ""); SendMessages(config, &dummyNode2, *connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr2)); } BOOST_AUTO_TEST_CASE(DoS_banscore) { const Config &config = GetConfig(); std::atomic interruptDummy(false); connman->ClearBanned(); // because 11 is my favorite number. ForceSetArg("-banscore", "111"); CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true); dummyNode1.SetSendVersion(PROTOCOL_VERSION); GetNodeSignals().InitializeNode(config, &dummyNode1, *connman); dummyNode1.nVersion = 1; dummyNode1.fSuccessfullyConnected = true; Misbehaving(dummyNode1.GetId(), 100, ""); SendMessages(config, &dummyNode1, *connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 10, ""); SendMessages(config, &dummyNode1, *connman, interruptDummy); BOOST_CHECK(!connman->IsBanned(addr1)); Misbehaving(dummyNode1.GetId(), 1, ""); SendMessages(config, &dummyNode1, *connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr1)); ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD)); } BOOST_AUTO_TEST_CASE(DoS_bantime) { const Config &config = GetConfig(); std::atomic interruptDummy(false); connman->ClearBanned(); int64_t nStartTime = GetTime(); // Overrides future calls to GetTime() SetMockTime(nStartTime); CAddress addr(ip(0xa0b0c001), NODE_NONE); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true); dummyNode.SetSendVersion(PROTOCOL_VERSION); GetNodeSignals().InitializeNode(config, &dummyNode, *connman); dummyNode.nVersion = 1; dummyNode.fSuccessfullyConnected = true; Misbehaving(dummyNode.GetId(), 100, ""); SendMessages(config, &dummyNode, *connman, interruptDummy); BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime + 60 * 60); BOOST_CHECK(connman->IsBanned(addr)); SetMockTime(nStartTime + 60 * 60 * 24 + 1); BOOST_CHECK(!connman->IsBanned(addr)); } CTransactionRef RandomOrphan() { std::map::iterator it; - it = mapOrphanTransactions.lower_bound(GetRandHash()); + it = mapOrphanTransactions.lower_bound(insecure_rand256()); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); return it->second.tx; } BOOST_AUTO_TEST_CASE(DoS_mapOrphans) { CKey key; key.MakeNewKey(true); CBasicKeyStore keystore; keystore.AddKey(key); // 50 orphan transactions: for (int i = 0; i < 50; i++) { CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1 * CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); AddOrphanTx(MakeTransactionRef(tx), i); } // ... and 50 that depend on other orphans: for (int i = 0; i < 50; i++) { CTransactionRef txPrev = RandomOrphan(); CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; tx.vin[0].prevout.hash = txPrev->GetId(); tx.vout.resize(1); tx.vout[0].nValue = 1 * CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL); AddOrphanTx(MakeTransactionRef(tx), i); } // This really-big orphan should be ignored: for (int i = 0; i < 10; i++) { CTransactionRef txPrev = RandomOrphan(); CMutableTransaction tx; tx.vout.resize(1); tx.vout[0].nValue = 1 * CENT; tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID()); tx.vin.resize(2777); for (unsigned int j = 0; j < tx.vin.size(); j++) { tx.vin[j].prevout.n = j; tx.vin[j].prevout.hash = txPrev->GetId(); } SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL); // Re-use same signature for other inputs // (they don't have to be valid for this test) for (unsigned int j = 1; j < tx.vin.size(); j++) tx.vin[j].scriptSig = tx.vin[0].scriptSig; BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i)); } // Test EraseOrphansFor: for (NodeId i = 0; i < 3; i++) { size_t sizeBefore = mapOrphanTransactions.size(); EraseOrphansFor(i); BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore); } // Test LimitOrphanTxSize() function: LimitOrphanTxSize(40); BOOST_CHECK(mapOrphanTransactions.size() <= 40); LimitOrphanTxSize(10); BOOST_CHECK(mapOrphanTransactions.size() <= 10); LimitOrphanTxSize(0); BOOST_CHECK(mapOrphanTransactions.empty()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blockcheck_tests.cpp b/src/test/blockcheck_tests.cpp index 98e978b99..e8c9a599d 100644 --- a/src/test/blockcheck_tests.cpp +++ b/src/test/blockcheck_tests.cpp @@ -1,99 +1,99 @@ // Copyright (c) 2013-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 "chainparams.h" #include "config.h" #include "consensus/consensus.h" #include "consensus/validation.h" #include "validation.h" #include "test/test_bitcoin.h" #include BOOST_FIXTURE_TEST_SUITE(blockcheck_tests, BasicTestingSetup) static void RunCheckOnBlockImpl(const GlobalConfig &config, const CBlock &block, CValidationState &state, bool expected) { block.fChecked = false; bool fValid = CheckBlock(config, block, state, false, false); BOOST_CHECK_EQUAL(fValid, expected); BOOST_CHECK_EQUAL(fValid, state.IsValid()); } static void RunCheckOnBlock(const GlobalConfig &config, const CBlock &block) { CValidationState state; RunCheckOnBlockImpl(config, block, state, true); } static void RunCheckOnBlock(const GlobalConfig &config, const CBlock &block, const std::string &reason) { CValidationState state; RunCheckOnBlockImpl(config, block, state, false); BOOST_CHECK_EQUAL(state.GetRejectCode(), REJECT_INVALID); BOOST_CHECK_EQUAL(state.GetRejectReason(), reason); } BOOST_AUTO_TEST_CASE(blockfail) { SelectParams(CBaseChainParams::MAIN); // Set max blocksize to default in case other tests left it dirty GlobalConfig config; config.SetMaxBlockSize(DEFAULT_MAX_BLOCK_SIZE); CBlock block; RunCheckOnBlock(config, block, "bad-cb-missing"); CMutableTransaction tx; // Coinbase only. tx.vin.resize(1); tx.vin[0].scriptSig.resize(10); tx.vout.resize(1); tx.vout[0].nValue = Amount(42); auto coinbaseTx = CTransaction(tx); block.vtx.resize(1); block.vtx[0] = MakeTransactionRef(tx); RunCheckOnBlock(config, block); // No coinbase - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); tx.vin[0].prevout.n = 0; block.vtx[0] = MakeTransactionRef(tx); RunCheckOnBlock(config, block, "bad-cb-missing"); // Invalid coinbase tx = CMutableTransaction(coinbaseTx); tx.vin[0].scriptSig.resize(0); block.vtx[0] = MakeTransactionRef(tx); RunCheckOnBlock(config, block, "bad-cb-length"); // Oversize block. tx = CMutableTransaction(coinbaseTx); block.vtx[0] = MakeTransactionRef(tx); tx.vin[0].prevout.n = 0; auto txSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); auto maxTxCount = ((DEFAULT_MAX_BLOCK_SIZE - 1) / txSize) - 1; for (size_t i = 1; i < maxTxCount; i++) { - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); block.vtx.push_back(MakeTransactionRef(tx)); } // Check that at this point, we still accept the block. RunCheckOnBlock(config, block); // But reject it with one more transaction as it goes over the maximum // allowed block size. - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); block.vtx.push_back(MakeTransactionRef(tx)); RunCheckOnBlock(config, block, "bad-blk-length"); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 712738405..c47c069df 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -1,390 +1,390 @@ // Copyright (c) 2011-2016 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 "blockencodings.h" #include "chainparams.h" #include "config.h" #include "consensus/merkle.h" #include "random.h" #include "test/test_bitcoin.h" #include std::vector> extra_txn; struct RegtestingSetup : public TestingSetup { RegtestingSetup() : TestingSetup(CBaseChainParams::REGTEST) {} }; BOOST_FIXTURE_TEST_SUITE(blockencodings_tests, RegtestingSetup) static CBlock BuildBlockTestCase() { CBlock block; CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].scriptSig.resize(10); tx.vout.resize(1); tx.vout[0].nValue = Amount(42); block.vtx.resize(3); block.vtx[0] = MakeTransactionRef(tx); block.nVersion = 42; - block.hashPrevBlock = GetRandHash(); + block.hashPrevBlock = insecure_rand256(); block.nBits = 0x207fffff; - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); tx.vin[0].prevout.n = 0; block.vtx[1] = MakeTransactionRef(tx); tx.vin.resize(10); for (size_t i = 0; i < tx.vin.size(); i++) { - tx.vin[i].prevout.hash = GetRandHash(); + tx.vin[i].prevout.hash = insecure_rand256(); tx.vin[i].prevout.n = 0; } block.vtx[2] = MakeTransactionRef(tx); bool mutated; block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); assert(!mutated); GlobalConfig config; while (!CheckProofOfWork(block.GetHash(), block.nBits, config)) { ++block.nNonce; } return block; } // Number of shared use_counts we expect for a tx we havent touched // == 2 (mempool + our copy from the GetSharedTx call) #define SHARED_TX_OFFSET 2 BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) { CTxMemPool pool(CFeeRate(Amount(0))); TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); pool.addUnchecked(block.vtx[2]->GetId(), entry.FromTx(*block.vtx[2])); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); // Do a simple ShortTxIDs RT { CBlockHeaderAndShortTxIDs shortIDs(block); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(partialBlock.IsTxAvailable(0)); BOOST_CHECK(!partialBlock.IsTxAvailable(1)); BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); size_t poolSize = pool.size(); pool.removeRecursive(*block.vtx[2]); BOOST_CHECK_EQUAL(pool.size(), poolSize - 1); CBlock block2; { // No transactions. PartiallyDownloadedBlock tmp = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); partialBlock = tmp; } // Wrong transaction { // Current implementation doesn't check txn here, but don't require // that. PartiallyDownloadedBlock tmp = partialBlock; partialBlock.FillBlock(block2, {block.vtx[2]}); partialBlock = tmp; } bool mutated; BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated)); CBlock block3; BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[1]}) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString()); BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString()); BOOST_CHECK(!mutated); } } class TestHeaderAndShortIDs { // Utility to encode custom CBlockHeaderAndShortTxIDs public: CBlockHeader header; uint64_t nonce; std::vector shorttxids; std::vector prefilledtxn; TestHeaderAndShortIDs(const CBlockHeaderAndShortTxIDs &orig) { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << orig; stream >> *this; } TestHeaderAndShortIDs(const CBlock &block) : TestHeaderAndShortIDs(CBlockHeaderAndShortTxIDs(block)) {} uint64_t GetShortID(const uint256 &txhash) const { CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << *this; CBlockHeaderAndShortTxIDs base; stream >> base; return base.GetShortID(txhash); } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { READWRITE(header); READWRITE(nonce); size_t shorttxids_size = shorttxids.size(); READWRITE(VARINT(shorttxids_size)); shorttxids.resize(shorttxids_size); for (size_t i = 0; i < shorttxids.size(); i++) { uint32_t lsb = shorttxids[i] & 0xffffffff; uint16_t msb = (shorttxids[i] >> 32) & 0xffff; READWRITE(lsb); READWRITE(msb); shorttxids[i] = (uint64_t(msb) << 32) | uint64_t(lsb); } READWRITE(prefilledtxn); } }; BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) { CTxMemPool pool(CFeeRate(Amount(0))); TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); pool.addUnchecked(block.vtx[2]->GetId(), entry.FromTx(*block.vtx[2])); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); uint256 txhash; // Test with pre-forwarding tx 1, but not coinbase { TestHeaderAndShortIDs shortIDs(block); shortIDs.prefilledtxn.resize(1); shortIDs.prefilledtxn[0] = {1, block.vtx[1]}; shortIDs.shorttxids.resize(2); shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetId()); shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetId()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(!partialBlock.IsTxAvailable(0)); BOOST_CHECK(partialBlock.IsTxAvailable(1)); BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[2]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; { // No transactions. PartiallyDownloadedBlock tmp = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_INVALID); partialBlock = tmp; } // Wrong transaction { // Current implementation doesn't check txn here, but don't require // that. PartiallyDownloadedBlock tmp = partialBlock; partialBlock.FillBlock(block2, {block.vtx[1]}); partialBlock = tmp; } bool mutated; BOOST_CHECK(block.hashMerkleRoot != BlockMerkleRoot(block2, &mutated)); CBlock block3; PartiallyDownloadedBlock partialBlockCopy = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block3, {block.vtx[0]}) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block3.GetHash().ToString()); BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString()); BOOST_CHECK(!mutated); txhash = block.vtx[2]->GetId(); block.vtx.clear(); block2.vtx.clear(); block3.vtx.clear(); // + 1 because of partialBlockCopy. BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); } BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); } BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) { CTxMemPool pool(CFeeRate(Amount(0))); TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); pool.addUnchecked(block.vtx[1]->GetId(), entry.FromTx(*block.vtx[1])); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); uint256 txhash; // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool { TestHeaderAndShortIDs shortIDs(block); shortIDs.prefilledtxn.resize(2); shortIDs.prefilledtxn[0] = {0, block.vtx[0]}; // id == 1 as it is 1 after index 1 shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; shortIDs.shorttxids.resize(1); shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetId()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(partialBlock.IsTxAvailable(0)); BOOST_CHECK(partialBlock.IsTxAvailable(1)); BOOST_CHECK(partialBlock.IsTxAvailable(2)); BOOST_CHECK_EQUAL( pool.mapTx.find(block.vtx[1]->GetId())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; PartiallyDownloadedBlock partialBlockCopy = partialBlock; BOOST_CHECK(partialBlock.FillBlock(block2, {}) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString()); bool mutated; BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString()); BOOST_CHECK(!mutated); txhash = block.vtx[1]->GetId(); block.vtx.clear(); block2.vtx.clear(); // + 1 because of partialBlockCopy. BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); } BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); } BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) { CTxMemPool pool(CFeeRate(Amount(0))); CMutableTransaction coinbase; coinbase.vin.resize(1); coinbase.vin[0].scriptSig.resize(10); coinbase.vout.resize(1); coinbase.vout[0].nValue = Amount(42); CBlock block; block.vtx.resize(1); block.vtx[0] = MakeTransactionRef(std::move(coinbase)); block.nVersion = 42; - block.hashPrevBlock = GetRandHash(); + block.hashPrevBlock = insecure_rand256(); block.nBits = 0x207fffff; bool mutated; block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); assert(!mutated); GlobalConfig config; while (!CheckProofOfWork(block.GetHash(), block.nBits, config)) { ++block.nNonce; } // Test simple header round-trip with only coinbase { CBlockHeaderAndShortTxIDs shortIDs(block); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; CBlockHeaderAndShortTxIDs shortIDs2; stream >> shortIDs2; PartiallyDownloadedBlock partialBlock(GetConfig(), &pool); BOOST_CHECK(partialBlock.InitData(shortIDs2, extra_txn) == READ_STATUS_OK); BOOST_CHECK(partialBlock.IsTxAvailable(0)); CBlock block2; std::vector vtx_missing; BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString()); BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString()); BOOST_CHECK(!mutated); } } BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BlockTransactionsRequest req1; - req1.blockhash = GetRandHash(); + req1.blockhash = insecure_rand256(); req1.indexes.resize(4); req1.indexes[0] = 0; req1.indexes[1] = 1; req1.indexes[2] = 3; req1.indexes[3] = 4; CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << req1; BlockTransactionsRequest req2; stream >> req2; BOOST_CHECK_EQUAL(req1.blockhash.ToString(), req2.blockhash.ToString()); BOOST_CHECK_EQUAL(req1.indexes.size(), req2.indexes.size()); BOOST_CHECK_EQUAL(req1.indexes[0], req2.indexes[0]); BOOST_CHECK_EQUAL(req1.indexes[1], req2.indexes[1]); BOOST_CHECK_EQUAL(req1.indexes[2], req2.indexes[2]); BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 547153b62..9094aed82 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -1,1129 +1,1129 @@ // Copyright (c) 2012-2016 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 "bloom.h" #include "base58.h" #include "clientversion.h" #include "key.h" #include "merkleblock.h" #include "random.h" #include "serialize.h" #include "streams.h" #include "test/test_bitcoin.h" #include "uint256.h" #include "util.h" #include "utilstrencodings.h" #include #include #include BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) { CBloomFilter filter(3, 0.01, 0, BLOOM_UPDATE_ALL); filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!"); // One bit different in first byte BOOST_CHECK_MESSAGE( !filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter contains something it shouldn't!"); filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "Bloom filter doesn't contain just-inserted object (2)!"); filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!"); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << filter; std::vector vch = ParseHex("03614e9b050000000000000001"); std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!"); filter.clear(); BOOST_CHECK_MESSAGE( !filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter should be empty!"); } BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize_with_tweak) { // Same test as bloom_create_insert_serialize, but we add a nTweak of 100 CBloomFilter filter(3, 0.01, 2147483649UL, BLOOM_UPDATE_ALL); filter.insert(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("99108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter doesn't contain just-inserted object!"); // One bit different in first byte BOOST_CHECK_MESSAGE( !filter.contains(ParseHex("19108ad8ed9bb6274d3980bab5a85c048f0950c8")), "Bloom filter contains something it shouldn't!"); filter.insert(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("b5a2c786d9ef4658287ced5914b37a1b4aa32eee")), "Bloom filter doesn't contain just-inserted object (2)!"); filter.insert(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")); BOOST_CHECK_MESSAGE( filter.contains(ParseHex("b9300670b4c5366e95b2699e8b18bc75e5f729c5")), "Bloom filter doesn't contain just-inserted object (3)!"); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << filter; std::vector vch = ParseHex("03ce4299050000000100008001"); std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); } BOOST_AUTO_TEST_CASE(bloom_create_insert_key) { std::string strSecret = std::string("5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"); CBitcoinSecret vchSecret; BOOST_CHECK(vchSecret.SetString(strSecret)); CKey key = vchSecret.GetKey(); CPubKey pubkey = key.GetPubKey(); std::vector vchPubKey(pubkey.begin(), pubkey.end()); CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); filter.insert(vchPubKey); uint160 hash = pubkey.GetID(); filter.insert(std::vector(hash.begin(), hash.end())); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << filter; std::vector vch = ParseHex("038fc16b080000000000000001"); std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; BOOST_CHECK_EQUAL_COLLECTIONS(stream.begin(), stream.end(), expected.begin(), expected.end()); } BOOST_AUTO_TEST_CASE(bloom_match) { // Random real transaction // (b4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b) CDataStream stream( ParseHex("01000000010b26e9b7735eb6aabdf358bab62f9816a21ba9ebdb719d5299e" "88607d722c190000000008b4830450220070aca44506c5cef3a16ed519d7c" "3c39f8aab192c4e1c90d065f37b8a4af6141022100a8e160b856c2d43d27d" "8fba71e5aef6405b8643ac4cb7cb3c462aced7f14711a0141046d11fee51b" "0e60666d5049a9101a72741df480b96ee26488a4d3466b95c9a40ac5eeef8" "7e10a5cd336c19a84565f80fa6c547957b7700ff4dfbdefe76036c339ffff" "ffff021bff3d11000000001976a91404943fdd508053c75000106d3bc6e27" "54dbcff1988ac2f15de00000000001976a914a266436d2965547608b9e15d" "9032a7b9d64fa43188ac00000000"), SER_DISK, CLIENT_VERSION); CTransaction tx(deserialize, stream); // and one which spends it // (e2769b09e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436) uint8_t ch[] = { 0x01, 0x00, 0x00, 0x00, 0x01, 0x6b, 0xff, 0x7f, 0xcd, 0x4f, 0x85, 0x65, 0xef, 0x40, 0x6d, 0xd5, 0xd6, 0x3d, 0x4f, 0xf9, 0x4f, 0x31, 0x8f, 0xe8, 0x20, 0x27, 0xfd, 0x4d, 0xc4, 0x51, 0xb0, 0x44, 0x74, 0x01, 0x9f, 0x74, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x49, 0x30, 0x46, 0x02, 0x21, 0x00, 0xda, 0x0d, 0xc6, 0xae, 0xce, 0xfe, 0x1e, 0x06, 0xef, 0xdf, 0x05, 0x77, 0x37, 0x57, 0xde, 0xb1, 0x68, 0x82, 0x09, 0x30, 0xe3, 0xb0, 0xd0, 0x3f, 0x46, 0xf5, 0xfc, 0xf1, 0x50, 0xbf, 0x99, 0x0c, 0x02, 0x21, 0x00, 0xd2, 0x5b, 0x5c, 0x87, 0x04, 0x00, 0x76, 0xe4, 0xf2, 0x53, 0xf8, 0x26, 0x2e, 0x76, 0x3e, 0x2d, 0xd5, 0x1e, 0x7f, 0xf0, 0xbe, 0x15, 0x77, 0x27, 0xc4, 0xbc, 0x42, 0x80, 0x7f, 0x17, 0xbd, 0x39, 0x01, 0x41, 0x04, 0xe6, 0xc2, 0x6e, 0xf6, 0x7d, 0xc6, 0x10, 0xd2, 0xcd, 0x19, 0x24, 0x84, 0x78, 0x9a, 0x6c, 0xf9, 0xae, 0xa9, 0x93, 0x0b, 0x94, 0x4b, 0x7e, 0x2d, 0xb5, 0x34, 0x2b, 0x9d, 0x9e, 0x5b, 0x9f, 0xf7, 0x9a, 0xff, 0x9a, 0x2e, 0xe1, 0x97, 0x8d, 0xd7, 0xfd, 0x01, 0xdf, 0xc5, 0x22, 0xee, 0x02, 0x28, 0x3d, 0x3b, 0x06, 0xa9, 0xd0, 0x3a, 0xcf, 0x80, 0x96, 0x96, 0x8d, 0x7d, 0xbb, 0x0f, 0x91, 0x78, 0xff, 0xff, 0xff, 0xff, 0x02, 0x8b, 0xa7, 0x94, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xba, 0xde, 0xec, 0xfd, 0xef, 0x05, 0x07, 0x24, 0x7f, 0xc8, 0xf7, 0x42, 0x41, 0xd7, 0x3b, 0xc0, 0x39, 0x97, 0x2d, 0x7b, 0x88, 0xac, 0x40, 0x94, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x19, 0x76, 0xa9, 0x14, 0xc1, 0x09, 0x32, 0x48, 0x3f, 0xec, 0x93, 0xed, 0x51, 0xf5, 0xfe, 0x95, 0xe7, 0x25, 0x59, 0xf2, 0xcc, 0x70, 0x43, 0xf9, 0x88, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00}; std::vector vch(ch, ch + sizeof(ch) - 1); CDataStream spendStream(vch, SER_DISK, CLIENT_VERSION); CTransaction spendingTx(deserialize, spendStream); CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(uint256S( "0xb4749f017444b051c44dfd2720e88f314ff94f3dd6d56d40ef65854fcd7fff6b")); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match tx hash"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // byte-reversed tx hash filter.insert(ParseHex( "6bff7fcd4f8565ef406dd5d63d4ff94f318fe82027fd4dc451b04474019f74b4")); BOOST_CHECK_MESSAGE( filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized tx hash"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(ParseHex("30450220070aca44506c5cef3a16ed519d7c3c39f8aab192c4e" "1c90d065f37b8a4af6141022100a8e160b856c2d43d27d8fba7" "1e5aef6405b8643ac4cb7cb3c462aced7f14711a01")); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input signature"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(ParseHex("046d11fee51b0e60666d5049a9101a72741df480b96ee26488a" "4d3466b95c9a40ac5eeef87e10a5cd336c19a84565f80fa6c54" "7957b7700ff4dfbdefe76036c339")); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match input pub key"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(ParseHex("04943fdd508053c75000106d3bc6e2754dbcff19")); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address"); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(spendingTx), "Simple Bloom filter didn't add output"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(ParseHex("a266436d2965547608b9e15d9032a7b9d64fa431")); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match output address"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb" "6ba58f3bdaab65e73b7e9260b"), 0)); BOOST_CHECK_MESSAGE(filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match COutPoint"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); COutPoint prevOutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb6" "ba58f3bdaab65e73b7e9260b"), 0); { std::vector data(32 + sizeof(unsigned int)); memcpy(&data[0], prevOutPoint.hash.begin(), 32); memcpy(&data[32], &prevOutPoint.n, sizeof(unsigned int)); filter.insert(data); } BOOST_CHECK_MESSAGE( filter.IsRelevantAndUpdate(tx), "Simple Bloom filter didn't match manually serialized COutPoint"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(uint256S( "00000009e784f32f62ef849763d4f45b98e07ba658647343b915ff832b110436")); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random tx hash"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(ParseHex("0000006d2965547608b9e15d9032a7b9d64fa431")); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched random address"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(COutPoint(uint256S("0x90c122d70786e899529d71dbeba91ba216982fb" "6ba58f3bdaab65e73b7e9260b"), 1)); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output " "we didn't care about"); filter = CBloomFilter(10, 0.000001, 0, BLOOM_UPDATE_ALL); filter.insert(COutPoint(uint256S("0x000000d70786e899529d71dbeba91ba216982fb" "6ba58f3bdaab65e73b7e9260b"), 0)); BOOST_CHECK_MESSAGE(!filter.IsRelevantAndUpdate(tx), "Simple Bloom filter matched COutPoint for an output " "we didn't care about"); } BOOST_AUTO_TEST_CASE(merkle_block_1) { // Random real block // (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) // With 9 txes CBlock block; CDataStream stream( ParseHex( "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb680000000" "0000005275289558f51c9966699404ae2294730c3c9f9bda53523ce50e9b95e558" "da2fdb261b4d4c86041b1ab1bf9309010000000100000000000000000000000000" "00000000000000000000000000000000000000ffffffff07044c86041b0146ffff" "ffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf2" "54bb5c7b949450c3e997c2dc1242487a8169507b631eb3771f2b425483fb13102c" "4eb5d858eef260fe70fbfae0ac00000000010000000196608ccbafa16abada9027" "80da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a493046022100da" "b24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd0221" "00fe37900e0644bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb4" "01ffffffff0100f2052a010000001976a914f15d1921f52e4007b146dfa60f369e" "d2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81e48b24d98e" "c706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad" "2e6d93f089cfcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21ad" "c6c401887f2bfd1922f11d76159cbc597fbd756a23dcbb00f4d7290141042b4e86" "25a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c40f1f8b8d8982" "35e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff02" "80969800000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388" "ac80d6e34c000000001976a914f0688ba1c0d1ce182c7af6741e02658c7d4dfcd3" "88ac000000000100000002c40297f730dd7b5a99567eb8d27b78758f607507c522" "92d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3" "889e0c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2f" "afd60a129ed94504c4ac7bdc67b56fe67512658b3e014104732012cb962afa90d3" "1b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5d0e676841733cb83aba" "f975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cb" "cba45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044" "022068010362a13c7f9919fa832b2dee4e788f61f6f5d344a7c2a0da6ae7406056" "58022006d1af525b9a14a35c003b78b72bd59738cd676f845d1ff3fc25049e0100" "3614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c342" "3e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc" "2d68ecffffffff01001ec4110200000043410469ab4181eceb28985b9b4e895c13" "fa5e68d85761b7eee311db5addef76fa8621865134a221bd01f28ec9999ee3e021" "e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f758e91" "c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b4830" "4502207ab51be6f12a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9" "236102210086ae728b370e5329eead9accd880d0cb070aea0c96255fae6c4f1ddc" "ce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990" "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8" "ebbb12dcd4ffffffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942" "fc9288edd37c32f5c388ac002d3101000000001976a9141befba0cdc1ad5652937" "1864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61bc3326efd9" "0111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37" "f9a505c3f1a1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b" "25a2ee80eb59292e52b987dad92acb0c64eced92ed9ee105ad153cdb12d0014104" "43bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6cb46cc1a4d3cf" "7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffff" "ffff0280651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a1232" "2d3788ac00aa0271000000001976a914ea4720a7a52fc166c55ff2298e07baf70a" "e67e1b88ac00000000010000000586c62cd602d219bb60edb14a3e204de0705176" "f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf" "062eb993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b956" "00db8535bbf331b19eed8d961f7a8e54159c53675d5f69df8c014104462e76fd40" "67b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c6" "9b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e" "58ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b217901000000" "8b483045022100be12b2937179da88599e27bb31c3525097a07cdb52422d165b3c" "a2f2020ffcf702200971b51f853a53d644ebae9ec8f3512e442b1bcb6c315a5b49" "1d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33" "d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312e" "f1c0e8ebbb12dcd4ffffffff2acfcab629bbc8685792603762c921580030ba144a" "f553d271716a95089e107b010000008b483045022100fa579a840ac258871365dd" "48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cfbb1b" "659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0" "aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc3" "1895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffffdcdc6023bbc9" "944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd2000000008b4830" "450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1a" "f03c75022010e55c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d9" "8a9ed34c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d78990" "4f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8" "ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a03" "8fd69f06b83ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261" "b866f86bf6867d4558165f7c8c8aca2d86022100dc6e1f53a91de3efe8f6351285" "0811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4067b3a0aa4207" "0082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0" "c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c0000000000" "1976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac00000000010000" "000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023df5595602aae96ed" "8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc" "87edd1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded" "4026e896b213d73ca4b63f014104979b82d02226b3a4597523845754d44f13639e" "3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90d661a3d0a33161dab29" "934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695" "a02af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93" "376d6b37b5c2940655a6fcaf1c8e74237988ac0000000001000000014e3f8ef2e9" "1349a9059cb4f01e54ab2597c1387161d3da89919f7ea6acdbb371010000008c49" "304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb580654" "d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66" "ddb9c694e240014104976c79848e18251612f8940875b2b08d06e6dc73b9840e88" "60c066b7e87432c477e9a59a453e71e6d76d5fe34058b800a098fc1740ce3012e8" "fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb604203" "4aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75e" "ef7942fc9288edd37c32f5c388ac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the last transaction filter.insert(uint256S( "0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20")); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b" "586ec87451f20")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 8); std::vector vMatched; std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); // Also match the 8th transaction filter.insert(uint256S( "0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f168809cdfae1053")); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2); BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xdd1fd2a6fc16404faf339881a90adbde7f4f728691ac62e8f16" "8809cdfae1053")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 7); BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); } BOOST_AUTO_TEST_CASE(merkle_block_2) { // Random real block // (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) // With 4 txes CBlock block; CDataStream stream( ParseHex( "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800" "000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f" "0ae1d4d26e49ffff001d00f0a44104010000000100000000000000000000000000" "00000000000000000000000000000000000000ffffffff0804ffff001d029105ff" "ffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a62" "94078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc571" "9aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6d" "a58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100" "aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702" "205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df15" "01ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c" "268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e" "3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8b" "be9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a07" "65b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a" "68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d" "8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad7" "69f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cf" "c617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d" "182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b" "06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27" "ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06" "d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c202801000000" "4a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca" "42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391f" "a3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce" "08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d484" "8b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f0000000043" "41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef1" "70e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0c" "ac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f1" "19b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376a" "aa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e" "27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d96" "3914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a4930460221" "00b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9" "022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb900" "5c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8" "dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8d" "d2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5" "865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68ae" "e3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the first transaction filter.insert(uint256S( "0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df" "5b47aecb93b70")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); std::vector vMatched; std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); // Match an output from the second transaction (the pubkey for address // 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) // This should match the third transaction because it spends the output // matched // It also matches the fourth transaction, which spends to the pubkey again filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad" "769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875" "a390f67c1f6c94cfc617c0ea45af")); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 4); BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56e" "bdcacd3069a5f")); BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x6b0f8a73a56c04b519f1883e8aafda643ba61a30bd1439969df" "21bea5f4e27e2")); BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 2); BOOST_CHECK(merkleBlock.vMatchedTxn[3].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d70076" "63ace63cddb23")); BOOST_CHECK(merkleBlock.vMatchedTxn[3].first == 3); BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); } BOOST_AUTO_TEST_CASE(merkle_block_2_with_update_none) { // Random real block // (000000005a4ded781e667e06ceefafb71410b511fe0d5adc3e5a27ecbec34ae6) // With 4 txes CBlock block; CDataStream stream( ParseHex( "0100000075616236cc2126035fadb38deb65b9102cc2c41c09cdf29fc051906800" "000000fe7d5e12ef0ff901f6050211249919b1c0653771832b3a80c66cea42847f" "0ae1d4d26e49ffff001d00f0a44104010000000100000000000000000000000000" "00000000000000000000000000000000000000ffffffff0804ffff001d029105ff" "ffffff0100f2052a010000004341046d8709a041d34357697dfcb30a9d05900a62" "94078012bf3bb09c6f9b525f1d16d5503d7905db1ada9501446ea00728668fc571" "9aa80be2fdfc8a858a4dbdd4fbac00000000010000000255605dc6f5c3dc148b6d" "a58442b0b2cd422be385eab2ebea4119ee9c268d28350000000049483045022100" "aa46504baa86df8a33b1192b1b9367b4d729dc41e389f2c04f3e5c7f0559aae702" "205e82253a54bf5c4f65b7428551554b2045167d6d206dfe6a2e198127d3f7df15" "01ffffffff55605dc6f5c3dc148b6da58442b0b2cd422be385eab2ebea4119ee9c" "268d2835010000004847304402202329484c35fa9d6bb32a55a70c0982f606ce0e" "3634b69006138683bcd12cbb6602200c28feb1e2555c3210f1dddb299738b4ff8b" "be9667b68cb8764b5ac17b7adf0001ffffffff0200e1f505000000004341046a07" "65b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a" "68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d" "8f000000004341044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad7" "69f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cf" "c617c0ea45afac0000000001000000025f9a06d3acdceb56be1bfeaa3e8a25e62d" "182fa24fefe899d1c17f1dad4c2028000000004847304402205d6058484157235b" "06028c30736c15613a28bdb768ee628094ca8b0030d4d6eb0220328789c9a2ec27" "ddaec0ad5ef58efded42e6ea17c2e1ce838f3d6913f5e95db601ffffffff5f9a06" "d3acdceb56be1bfeaa3e8a25e62d182fa24fefe899d1c17f1dad4c202801000000" "4a493046022100c45af050d3cea806cedd0ab22520c53ebe63b987b8954146cdca" "42487b84bdd6022100b9b027716a6b59e640da50a864d6dd8a0ef24c76ce62391f" "a3eabaf4d2886d2d01ffffffff0200e1f505000000004341046a0765b5865641ce" "08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d484" "8b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00180d8f0000000043" "41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef1" "70e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0c" "ac000000000100000002e2274e5fea1bf29d963914bd301aa63b64daaf8a3e88f1" "19b5046ca5738a0f6b0000000048473044022016e7a727a061ea2254a6c358376a" "aa617ac537eb836c77d646ebda4c748aac8b0220192ce28bf9f2c06a6467e6531e" "27648d2b3e2e2bae85159c9242939840295ba501ffffffffe2274e5fea1bf29d96" "3914bd301aa63b64daaf8a3e88f119b5046ca5738a0f6b010000004a4930460221" "00b7a1a755588d4190118936e15cd217d133b0e4a53c3c15924010d5648d8925c9" "022100aaef031874db2114f2d869ac2de4ae53908fbfea5b2b1862e181626bb900" "5c9f01ffffffff0200e1f505000000004341044a656f065871a353f216ca26cef8" "dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8d" "d2c875a390f67c1f6c94cfc617c0ea45afac00180d8f000000004341046a0765b5" "865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68ae" "e3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); // Match the first transaction filter.insert(uint256S( "0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df5b47aecb93b70")); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0xe980fe9f792d014e73b95203dc1335c5f9ce19ac537a419e6df" "5b47aecb93b70")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); std::vector vMatched; std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); // Match an output from the second transaction (the pubkey for address // 1DZTzaBHUDM7T3QvUKBz4qXMRpkg8jsfB5) // This should not match the third transaction though it spends the output // matched // It will match the fourth transaction, which has another pay-to-pubkey // output to the same address filter.insert(ParseHex("044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad" "769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875" "a390f67c1f6c94cfc617c0ea45af")); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 3); BOOST_CHECK(pair == merkleBlock.vMatchedTxn[0]); BOOST_CHECK(merkleBlock.vMatchedTxn[1].second == uint256S("0x28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56e" "bdcacd3069a5f")); BOOST_CHECK(merkleBlock.vMatchedTxn[1].first == 1); BOOST_CHECK(merkleBlock.vMatchedTxn[2].second == uint256S("0x3c1d7e82342158e4109df2e0b6348b6e84e403d8b4046d70076" "63ace63cddb23")); BOOST_CHECK(merkleBlock.vMatchedTxn[2].first == 3); BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); } BOOST_AUTO_TEST_CASE(merkle_block_3_and_serialize) { // Random real block // (000000000000dab0130bbcc991d3d7ae6b81aa6f50a798888dfe62337458dc45) // With one tx CBlock block; CDataStream stream( ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b00" "00000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3f" "f60abe184f196367291b4d4c86041b8fa45d6301010000000100000000000" "00000000000000000000000000000000000000000000000000000ffffffff" "08044c86041b020a02ffffffff0100f2052a01000000434104ecd3229b057" "1c3be876feaac0442a9f13c5a572742927af1dc623353ecf8c202225f6486" "8137a18cdd85cbbb4c74fbccfd4f49639cf1bdc94a5672bb15ad5d4cac000" "00000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the only transaction filter.insert(uint256S( "0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee3a3d669c00cb5")); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x63194f18be0af63f2c6bc9dc0f777cbefed3d9415c4af83f3ee" "3a3d669c00cb5")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 0); std::vector vMatched; std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); CDataStream merkleStream(SER_NETWORK, PROTOCOL_VERSION); merkleStream << merkleBlock; std::vector vch = ParseHex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b00" "00000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3f" "f60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e" "33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101"); std::vector expected(vch.size()); for (unsigned int i = 0; i < vch.size(); i++) expected[i] = (char)vch[i]; BOOST_CHECK_EQUAL_COLLECTIONS(expected.begin(), expected.end(), merkleStream.begin(), merkleStream.end()); } BOOST_AUTO_TEST_CASE(merkle_block_4) { // Random real block // (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) // With 7 txes CBlock block; CDataStream stream( ParseHex( "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc88067010000" "0000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9" "728776381b4d4c86041b554b852907010000000100000000000000000000000000" "00000000000000000000000000000000000000ffffffff07044c86041b0136ffff" "ffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1" "f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad" "1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08" "989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e" "834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea1022100" "9253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901" "ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643" "207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58cc" "b3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9d" "ee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca" "0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8" "acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf4" "9e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fc" "ad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff30" "9e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af830000" "00004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b" "51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb542" "8f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6" "d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c8" "10ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d" "31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff01007144" "60030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000" "000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72" "a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6" "f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423" "746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6" "fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd62" "38f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d225" "3d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a47304402207812" "4c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e93022069" "1d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a360141" "0462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab8" "44c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ff" "fffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4daf" "daa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab0" "23abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7" "fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561" "f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d8" "7270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9" "e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e0084714" "7cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b" "2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd7014104" "62bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844" "c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffff" "ffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c38" "5d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758d" "f616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11e" "eb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a" "0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f" "464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e" "88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636" "030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c" "00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac0000" "0000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d" "850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1a" "c1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90" "f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1" "e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c" "4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f000000000019" "76a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f0000000000" "1976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000" "000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3" "f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e2" "80007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a" "690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2" "b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a3" "3ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf041" "76b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b" "903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb" "87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf8" "0125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06" "820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff01" "00093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888" "ac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_ALL); // Match the last transaction filter.insert(uint256S( "0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f19b15df0ac154")); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 1); std::pair pair = merkleBlock.vMatchedTxn[0]; BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x0a2a92f0bda4727d0a13eaddf4dd9ac6b5c61a1429e6b2b818f" "19b15df0ac154")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 6); std::vector vMatched; std::vector vIndex; BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); // Also match the 4th transaction filter.insert(uint256S( "0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041")); merkleBlock = CMerkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); BOOST_CHECK(merkleBlock.vMatchedTxn.size() == 2); BOOST_CHECK(merkleBlock.vMatchedTxn[0].second == uint256S("0x02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de673" "26471df5bc041")); BOOST_CHECK(merkleBlock.vMatchedTxn[0].first == 3); BOOST_CHECK(merkleBlock.vMatchedTxn[1] == pair); BOOST_CHECK(merkleBlock.txn.ExtractMatches(vMatched, vIndex) == block.hashMerkleRoot); BOOST_CHECK(vMatched.size() == merkleBlock.vMatchedTxn.size()); for (unsigned int i = 0; i < vMatched.size(); i++) BOOST_CHECK(vMatched[i] == merkleBlock.vMatchedTxn[i].second); } BOOST_AUTO_TEST_CASE(merkle_block_4_test_p2pubkey_only) { // Random real block // (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) // With 7 txes CBlock block; CDataStream stream( ParseHex( "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc88067010000" "0000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9" "728776381b4d4c86041b554b852907010000000100000000000000000000000000" "00000000000000000000000000000000000000ffffffff07044c86041b0136ffff" "ffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1" "f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad" "1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08" "989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e" "834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea1022100" "9253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901" "ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643" "207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58cc" "b3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9d" "ee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca" "0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8" "acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf4" "9e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fc" "ad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff30" "9e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af830000" "00004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b" "51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb542" "8f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6" "d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c8" "10ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d" "31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff01007144" "60030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000" "000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72" "a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6" "f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423" "746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6" "fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd62" "38f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d225" "3d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a47304402207812" "4c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e93022069" "1d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a360141" "0462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab8" "44c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ff" "fffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4daf" "daa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab0" "23abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7" "fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561" "f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d8" "7270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9" "e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e0084714" "7cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b" "2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd7014104" "62bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844" "c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffff" "ffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c38" "5d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758d" "f616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11e" "eb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a" "0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f" "464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e" "88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636" "030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c" "00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac0000" "0000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d" "850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1a" "c1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90" "f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1" "e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c" "4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f000000000019" "76a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f0000000000" "1976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000" "000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3" "f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e2" "80007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a" "690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2" "b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a3" "3ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf041" "76b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b" "903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb" "87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf8" "0125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06" "820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff01" "00093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888" "ac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_P2PUBKEY_ONLY); // Match the generation pubkey filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f" "134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce" "13ad1357231a2252247d97a46a91")); // ...and the output address of the 4th transaction filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); // We should match the generation outpoint BOOST_CHECK( filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b8" "6c7765e489f7a6ff3360fe5c674360b"), 0))); // ... but not the 4th transaction's output (its not pay-2-pubkey) BOOST_CHECK( !filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc216603" "5a10f27a03cfd2de67326471df5bc041"), 0))); } BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) { // Random real block // (000000000000b731f2eef9e8c63173adfb07e41bd53eb0ef0a6b720d6cb6dea4) // With 7 txes CBlock block; CDataStream stream( ParseHex( "0100000082bb869cf3a793432a66e826e05a6fc37469f8efb7421dc88067010000" "0000007f16c5962e8bd963659c793ce370d95f093bc7e367117b3c30c1f8fdd0d9" "728776381b4d4c86041b554b852907010000000100000000000000000000000000" "00000000000000000000000000000000000000ffffffff07044c86041b0136ffff" "ffff0100f2052a01000000434104eaafc2314def4ca98ac970241bcab022b9c1e1" "f4ea423a20f134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce13ad" "1357231a2252247d97a46a91ac000000000100000001bcad20a6a29827d1424f08" "989255120bf7f3e9e3cdaaa6bb31b0737fe048724300000000494830450220356e" "834b046cadc0f8ebb5a8a017b02de59c86305403dad52cd77b55af062ea1022100" "9253cd6c119d4729b77c978e1e2aa19f5ea6e0e52b3f16e32fa608cd5bab753901" "ffffffff02008d380c010000001976a9142b4b8072ecbba129b6453c63e129e643" "207249ca88ac0065cd1d000000001976a9141b8dd13b994bcfc787b32aeadf58cc" "b3615cbd5488ac000000000100000003fdacf9b3eb077412e7a968d2e4f11b9a9d" "ee312d666187ed77ee7d26af16cb0b000000008c493046022100ea1608e70911ca" "0de5af51ba57ad23b9a51db8d28f82c53563c56a05c20f5a87022100a8bdc8b4a8" "acc8634c6b420410150775eb7f2474f5615f7fccd65af30f310fbf01410465fdf4" "9e29b06b9a1582287b6279014f834edc317695d125ef623c1cc3aaece245bd69fc" "ad7508666e9c74a49dc9056d5fc14338ef38118dc4afae5fe2c585caffffffff30" "9e1913634ecb50f3c4f83e96e70b2df071b497b8973a3e75429df397b5af830000" "00004948304502202bdb79c596a9ffc24e96f4386199aba386e9bc7b6071516e2b" "51dda942b3a1ed022100c53a857e76b724fc14d45311eac5019650d415c3abb542" "8f3aae16d8e69bec2301ffffffff2089e33491695080c9edc18a428f7d834db5b6" "d372df13ce2b1b0e0cbcb1e6c10000000049483045022100d4ce67c5896ee251c8" "10ac1ff9ceccd328b497c8f553ab6e08431e7d40bad6b5022033119c0c2b7d792d" "31f1187779c7bd95aefd93d90a715586d73801d9b47471c601ffffffff01007144" "60030000001976a914c7b55141d097ea5df7a0ed330cf794376e53ec8d88ac0000" "000001000000045bf0e214aa4069a3e792ecee1e1bf0c1d397cde8dd08138f4b72" "a00681743447000000008b48304502200c45de8c4f3e2c1821f2fc878cba97b1e6" "f8807d94930713aa1c86a67b9bf1e40221008581abfef2e30f957815fc89978423" "746b2086375ca8ecf359c85c2a5b7c88ad01410462bb73f76ca0994fcb8b4271e6" "fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd62" "38f4d87270efb1d3ae37079b794a92d7ec95ffffffffd669f7d7958d40fc59d225" "3d88e0f248e29b599c80bbcec344a83dda5f9aa72c000000008a47304402207812" "4c8beeaa825f9e0b30bff96e564dd859432f2d0cb3b72d3d5d93d38d7e93022069" "1d233b6c0f995be5acb03d70a7f7a65b6bc9bdd426260f38a1346669507a360141" "0462bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab8" "44c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ff" "fffffff878af0d93f5229a68166cf051fd372bb7a537232946e0a46f53636b4daf" "daa4000000008c493046022100c717d1714551663f69c3c5759bdbb3a0fcd3fab0" "23abc0e522fe6440de35d8290221008d9cbe25bffc44af2b18e81c58eb37293fd7" "fe1c2e7b46fc37ee8c96c50ab1e201410462bb73f76ca0994fcb8b4271e6fb7561" "f5c0f9ca0cf6485261c4a0dc894f4ab844c6cdfb97cd0b60ffb5018ffd6238f4d8" "7270efb1d3ae37079b794a92d7ec95ffffffff27f2b668859cd7f2f894aa0fd2d9" "e60963bcd07c88973f425f999b8cbfd7a1e2000000008c493046022100e0084714" "7cbf517bcc2f502f3ddc6d284358d102ed20d47a8aa788a62f0db780022100d17b" "2d6fa84dcaf1c95d88d7e7c30385aecf415588d749afd3ec81f6022cecd7014104" "62bb73f76ca0994fcb8b4271e6fb7561f5c0f9ca0cf6485261c4a0dc894f4ab844" "c6cdfb97cd0b60ffb5018ffd6238f4d87270efb1d3ae37079b794a92d7ec95ffff" "ffff0100c817a8040000001976a914b6efd80d99179f4f4ff6f4dd0a007d018c38" "5d2188ac000000000100000001834537b2f1ce8ef9373a258e10545ce5a50b758d" "f616cd4356e0032554ebd3c4000000008b483045022100e68f422dd7c34fdce11e" "eb4509ddae38201773dd62f284e8aa9d96f85099d0b002202243bd399ff96b649a" "0fad05fa759d6a882f0af8c90cf7632c2840c29070aec20141045e58067e815c2f" "464c6a2a15f987758374203895710c2d452442e28496ff38ba8f5fd901dc20e29e" "88477167fe4fc299bf818fd0d9e1632d467b2a3d9503b1aaffffffff0280d7e636" "030000001976a914f34c3e10eb387efe872acb614c89e78bfca7815d88ac404b4c" "00000000001976a914a84e272933aaf87e1715d7786c51dfaeb5b65a6f88ac0000" "0000010000000143ac81c8e6f6ef307dfe17f3d906d999e23e0189fda838c5510d" "850927e03ae7000000008c4930460221009c87c344760a64cb8ae6685a3eec2c1a" "c1bed5b88c87de51acd0e124f266c16602210082d07c037359c3a257b5c63ebd90" "f5a5edf97b2ac1c434b08ca998839f346dd40141040ba7e521fa7946d12edbb1d1" "e95a15c34bd4398195e86433c92b431cd315f455fe30032ede69cad9d1e1ed6c3c" "4ec0dbfced53438c625462afb792dcb098544bffffffff0240420f000000000019" "76a9144676d1b820d63ec272f1900d59d43bc6463d96f888ac40420f0000000000" "1976a914648d04341d00d7968b3405c034adc38d4d8fb9bd88ac00000000010000" "000248cc917501ea5c55f4a8d2009c0567c40cfe037c2e71af017d0a452ff705e3" "f1000000008b483045022100bf5fdc86dc5f08a5d5c8e43a8c9d5b1ed8c65562e2" "80007b52b133021acd9acc02205e325d613e555f772802bf413d36ba807892ed1a" "690a77811d3033b3de226e0a01410429fa713b124484cb2bd7b5557b2c0b9df7b2" "b1fee61825eadc5ae6c37a9920d38bfccdc7dc3cb0c47d7b173dbc9db8d37db0a3" "3ae487982c59c6f8606e9d1791ffffffff41ed70551dd7e841883ab8f0b16bf041" "76b7d1480e4f0af9f3d4c3595768d068000000008b4830450221008513ad65187b" "903aed1102d1d0c47688127658c51106753fed0151ce9c16b80902201432b9ebcb" "87bd04ceb2de66035fbbaf4bf8b00d1cfe41f1a1f7338f9ad79d210141049d4cf8" "0125bf50be1709f718c07ad15d0fc612b7da1f5570dddc35f2a352f0f27c978b06" "820edca9ef982c35fda2d255afba340068c5035552368bc7200c1488ffffffff01" "00093d00000000001976a9148edb68822f1ad580b043c7b3df2e400f8699eb4888" "ac00000000"), SER_NETWORK, PROTOCOL_VERSION); stream >> block; CBloomFilter filter(10, 0.000001, 0, BLOOM_UPDATE_NONE); // Match the generation pubkey filter.insert(ParseHex("04eaafc2314def4ca98ac970241bcab022b9c1e1f4ea423a20f" "134c876f2c01ec0f0dd5b2e86e7168cefe0d81113c3807420ce" "13ad1357231a2252247d97a46a91")); // ...and the output address of the 4th transaction filter.insert(ParseHex("b6efd80d99179f4f4ff6f4dd0a007d018c385d21")); CMerkleBlock merkleBlock(block, filter); BOOST_CHECK(merkleBlock.header.GetHash() == block.GetHash()); // We shouldn't match any outpoints (UPDATE_NONE) BOOST_CHECK( !filter.contains(COutPoint(uint256S("0x147caa76786596590baa4e98f5d9f48b" "86c7765e489f7a6ff3360fe5c674360b"), 0))); BOOST_CHECK( !filter.contains(COutPoint(uint256S("0x02981fa052f0481dbc5868f4fc216603" "5a10f27a03cfd2de67326471df5bc041"), 0))); } static std::vector RandomData() { - uint256 r = GetRandHash(); + uint256 r = insecure_rand256(); return std::vector(r.begin(), r.end()); } BOOST_AUTO_TEST_CASE(rolling_bloom) { // last-100-entry, 1% false positive: CRollingBloomFilter rb1(100, 0.01); // Overfill: static const int DATASIZE = 399; std::vector data[DATASIZE]; for (int i = 0; i < DATASIZE; i++) { data[i] = RandomData(); rb1.insert(data[i]); } // Last 100 guaranteed to be remembered: for (int i = 299; i < DATASIZE; i++) { BOOST_CHECK(rb1.contains(data[i])); } // false positive rate is 1%, so we should get about 100 hits if // testing 10,000 random keys. We get worst-case false positive // behavior when the filter is as full as possible, which is // when we've inserted one minus an integer multiple of nElement*2. unsigned int nHits = 0; for (int i = 0; i < 10000; i++) { if (rb1.contains(RandomData())) ++nHits; } // Run test_bitcoin with --log_level=message to see BOOST_TEST_MESSAGEs: BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~100 expected)"); // Insanely unlikely to get a fp count outside this range: BOOST_CHECK(nHits > 25); BOOST_CHECK(nHits < 175); BOOST_CHECK(rb1.contains(data[DATASIZE - 1])); rb1.reset(); BOOST_CHECK(!rb1.contains(data[DATASIZE - 1])); // Now roll through data, make sure last 100 entries // are always remembered: for (int i = 0; i < DATASIZE; i++) { if (i >= 100) BOOST_CHECK(rb1.contains(data[i - 100])); rb1.insert(data[i]); BOOST_CHECK(rb1.contains(data[i])); } // Insert 999 more random entries: for (int i = 0; i < 999; i++) { std::vector d = RandomData(); rb1.insert(d); BOOST_CHECK(rb1.contains(d)); } // Sanity check to make sure the filter isn't just filling up: nHits = 0; for (int i = 0; i < DATASIZE; i++) { if (rb1.contains(data[i])) ++nHits; } // Expect about 5 false positives, more than 100 means // something is definitely broken. BOOST_TEST_MESSAGE("RollingBloomFilter got " << nHits << " false positives (~5 expected)"); BOOST_CHECK(nHits < 100); // last-1000-entry, 0.01% false positive: CRollingBloomFilter rb2(1000, 0.001); for (int i = 0; i < DATASIZE; i++) { rb2.insert(data[i]); } // ... room for all of them: for (int i = 0; i < DATASIZE; i++) { BOOST_CHECK(rb2.contains(data[i])); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index c628cd228..44e8faca9 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -1,897 +1,899 @@ // Copyright (c) 2014-2016 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 "coins.h" #include "consensus/validation.h" #include "script/standard.h" #include "test/test_bitcoin.h" #include "uint256.h" #include "undo.h" #include "utilstrencodings.h" #include "validation.h" #include #include #include namespace { //! equality test bool operator==(const Coin &a, const Coin &b) { // Empty Coin objects are always equal. if (a.IsSpent() && b.IsSpent()) { return true; } return a.IsCoinBase() == b.IsCoinBase() && a.GetHeight() == b.GetHeight() && a.GetTxOut() == b.GetTxOut(); } class CCoinsViewTest : public CCoinsView { uint256 hashBestBlock_; std::map map_; public: bool GetCoin(const COutPoint &outpoint, Coin &coin) const override { std::map::const_iterator it = map_.find(outpoint); if (it == map_.end()) { return false; } coin = it->second; - if (coin.IsSpent() && insecure_rand() % 2 == 0) { + if (coin.IsSpent() && insecure_randrange(2) == 0) { // Randomly return false in case of an empty entry. return false; } return true; } bool HaveCoin(const COutPoint &outpoint) const override { Coin coin; return GetCoin(outpoint, coin); } uint256 GetBestBlock() const override { return hashBestBlock_; } bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override { for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Same optimization used in CCoinsViewDB is to only write dirty // entries. map_[it->first] = it->second.coin; - if (it->second.coin.IsSpent() && insecure_rand() % 3 == 0) { + if (it->second.coin.IsSpent() && insecure_randrange(3) == 0) { // Randomly delete empty entries on write. map_.erase(it->first); } } mapCoins.erase(it++); } if (!hashBlock.IsNull()) { hashBestBlock_ = hashBlock; } return true; } }; class CCoinsViewCacheTest : public CCoinsViewCache { public: CCoinsViewCacheTest(CCoinsView *base) : CCoinsViewCache(base) {} void SelfTest() const { // Manually recompute the dynamic usage of the whole data, and compare // it. size_t ret = memusage::DynamicUsage(cacheCoins); size_t count = 0; for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) { ret += it->second.coin.DynamicMemoryUsage(); count++; } BOOST_CHECK_EQUAL(GetCacheSize(), count); BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret); } CCoinsMap &map() { return cacheCoins; } size_t &usage() { return cachedCoinsUsage; } }; } // namespace BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; // This is a large randomized insert/remove simulation test on a variable-size // stack of caches on top of CCoinsViewTest. // // It will randomly create/update/delete Coin entries to a tip of caches, with // txids picked from a limited list of random 256-bit hashes. Occasionally, a // new tip is added to the stack of caches, or the tip is flushed and removed. // // During the process, booleans are kept to make sure that the randomized // operation hits all branches. BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) { // Various coverage trackers. bool removed_all_caches = false; bool reached_4_caches = false; bool added_an_entry = false; bool added_an_unspendable_entry = false; bool removed_an_entry = false; bool updated_an_entry = false; bool found_an_entry = false; bool missed_an_entry = false; bool uncached_an_entry = false; // A simple map to track what we expect the cache stack to represent. std::map result; // The cache stack. // A CCoinsViewTest at the bottom. CCoinsViewTest base; // A stack of CCoinsViewCaches on top. std::vector stack; // Start with one cache. stack.push_back(new CCoinsViewCacheTest(&base)); // Use a limited set of random transaction ids, so we do test overwriting // entries. std::vector txids; txids.resize(NUM_SIMULATION_ITERATIONS / 8); for (size_t i = 0; i < txids.size(); i++) { - txids[i] = GetRandHash(); + txids[i] = insecure_rand256(); } for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { // Do a random modification. { // txid we're going to modify in this iteration. uint256 txid = txids[insecure_rand() % txids.size()]; Coin &coin = result[COutPoint(txid, 0)]; const Coin &entry = - (insecure_rand() % 500 == 0) + (insecure_randrange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0)); BOOST_CHECK(coin == entry); - if (insecure_rand() % 5 == 0 || coin.IsSpent()) { + if (insecure_randrange(5) == 0 || coin.IsSpent()) { CTxOut txout; txout.nValue = Amount(int64_t(insecure_rand())); - if (insecure_rand() % 16 == 0 && coin.IsSpent()) { + if (insecure_randrange(16) == 0 && coin.IsSpent()) { txout.scriptPubKey.assign(1 + (insecure_rand() & 0x3F), OP_RETURN); BOOST_CHECK(txout.scriptPubKey.IsUnspendable()); added_an_unspendable_entry = true; } else { // Random sizes so we can test memory usage accounting txout.scriptPubKey.assign(insecure_rand() & 0x3F, 0); (coin.IsSpent() ? added_an_entry : updated_an_entry) = true; coin = Coin(txout, 1, false); } Coin newcoin(txout, 1, false); stack.back()->AddCoin(COutPoint(txid, 0), newcoin, !coin.IsSpent() || insecure_rand() & 1); } else { removed_an_entry = true; coin.Clear(); stack.back()->SpendCoin(COutPoint(txid, 0)); } } // One every 10 iterations, remove a random entry from the cache - if (insecure_rand() % 10) { + if (insecure_randrange(10)) { COutPoint out(txids[insecure_rand() % txids.size()], 0); int cacheid = insecure_rand() % stack.size(); stack[cacheid]->Uncache(out); uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); } // Once every 1000 iterations and at the end, verify the full cache. - if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + if (insecure_randrange(1000) == 1 || + i == NUM_SIMULATION_ITERATIONS - 1) { for (auto it = result.begin(); it != result.end(); it++) { bool have = stack.back()->HaveCoin(it->first); const Coin &coin = stack.back()->AccessCoin(it->first); BOOST_CHECK(have == !coin.IsSpent()); BOOST_CHECK(coin == it->second); if (coin.IsSpent()) { missed_an_entry = true; } else { BOOST_CHECK(stack.back()->HaveCoinInCache(it->first)); found_an_entry = true; } } for (const CCoinsViewCacheTest *test : stack) { test->SelfTest(); } } // Every 100 iterations, flush an intermediate cache - if (insecure_rand() % 100 == 0) { - if (stack.size() > 1 && insecure_rand() % 2 == 0) { + if (insecure_randrange(100) == 0) { + if (stack.size() > 1 && insecure_randrange(2) == 0) { unsigned int flushIndex = insecure_rand() % (stack.size() - 1); stack[flushIndex]->Flush(); } } - if (insecure_rand() % 100 == 0) { + if (insecure_randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && insecure_rand() % 2 == 0) { + if (stack.size() > 0 && insecure_randrange(2) == 0) { // Remove the top cache stack.back()->Flush(); delete stack.back(); stack.pop_back(); } if (stack.size() == 0 || - (stack.size() < 4 && insecure_rand() % 2)) { + (stack.size() < 4 && insecure_randrange(2))) { // Add a new cache CCoinsView *tip = &base; if (stack.size() > 0) { tip = stack.back(); } else { removed_all_caches = true; } stack.push_back(new CCoinsViewCacheTest(tip)); if (stack.size() == 4) { reached_4_caches = true; } } } } // Clean up the stack. while (stack.size() > 0) { delete stack.back(); stack.pop_back(); } // Verify coverage. BOOST_CHECK(removed_all_caches); BOOST_CHECK(reached_4_caches); BOOST_CHECK(added_an_entry); BOOST_CHECK(added_an_unspendable_entry); BOOST_CHECK(removed_an_entry); BOOST_CHECK(updated_an_entry); BOOST_CHECK(found_an_entry); BOOST_CHECK(missed_an_entry); BOOST_CHECK(uncached_an_entry); } // Store of all necessary tx and undo data for next test typedef std::map> UtxoData; UtxoData utxoData; UtxoData::iterator FindRandomFrom(const std::set &utxoSet) { assert(utxoSet.size()); - auto utxoSetIt = utxoSet.lower_bound(COutPoint(GetRandHash(), 0)); + auto utxoSetIt = utxoSet.lower_bound(COutPoint(insecure_rand256(), 0)); if (utxoSetIt == utxoSet.end()) { utxoSetIt = utxoSet.begin(); } auto utxoDataIt = utxoData.find(*utxoSetIt); assert(utxoDataIt != utxoData.end()); return utxoDataIt; } // This test is similar to the previous test except the emphasis is on testing // the functionality of UpdateCoins random txs are created and UpdateCoins is // used to update the cache stack. In particular it is tested that spending a // duplicate coinbase tx has the expected effect (the other duplicate is // overwitten at all cache levels) BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) { bool spent_a_duplicate_coinbase = false; // A simple map to track what we expect the cache stack to represent. std::map result; // The cache stack. // A CCoinsViewTest at the bottom. CCoinsViewTest base; // A stack of CCoinsViewCaches on top. std::vector stack; // Start with one cache. stack.push_back(new CCoinsViewCacheTest(&base)); // Track the txids we've used in various sets std::set coinbase_coins; std::set disconnected_coins; std::set duplicate_coins; std::set utxoset; for (int64_t i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { uint32_t randiter = insecure_rand(); // 19/20 txs add a new transaction if (randiter % 20 < 19) { CMutableTransaction tx; tx.vin.resize(1); tx.vout.resize(1); // Keep txs unique unless intended to duplicate. tx.vout[0].nValue = Amount(i); // Random sizes so we can test memory usage accounting tx.vout[0].scriptPubKey.assign(insecure_rand() & 0x3F, 0); unsigned int height = insecure_rand(); Coin old_coin; // 2/20 times create a new coinbase if (randiter % 20 < 2 || coinbase_coins.size() < 10) { // 1/10 of those times create a duplicate coinbase - if (insecure_rand() % 10 == 0 && coinbase_coins.size()) { + if (insecure_randrange(10) == 0 && coinbase_coins.size()) { auto utxod = FindRandomFrom(coinbase_coins); // Reuse the exact same coinbase tx = std::get<0>(utxod->second); // shouldn't be available for reconnection if its been // duplicated disconnected_coins.erase(utxod->first); duplicate_coins.insert(utxod->first); } else { coinbase_coins.insert(COutPoint(tx.GetId(), 0)); } assert(CTransaction(tx).IsCoinBase()); } // 17/20 times reconnect previous or add a regular tx else { COutPoint prevout; // 1/20 times reconnect a previously disconnected tx if (randiter % 20 == 2 && disconnected_coins.size()) { auto utxod = FindRandomFrom(disconnected_coins); tx = std::get<0>(utxod->second); prevout = tx.vin[0].prevout; if (!CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) { disconnected_coins.erase(utxod->first); continue; } // If this tx is already IN the UTXO, then it must be a // coinbase, and it must be a duplicate if (utxoset.count(utxod->first)) { assert(CTransaction(tx).IsCoinBase()); assert(duplicate_coins.count(utxod->first)); } disconnected_coins.erase(utxod->first); } // 16/20 times create a regular tx else { auto utxod = FindRandomFrom(utxoset); prevout = utxod->first; // Construct the tx to spend the coins of prevouthash tx.vin[0].prevout = prevout; tx.vin[0].prevout.n = 0; assert(!CTransaction(tx).IsCoinBase()); } // In this simple test coins only have two states, spent or // unspent, save the unspent state to restore old_coin = result[prevout]; // Update the expected result of prevouthash to know these coins // are spent result[prevout].Clear(); utxoset.erase(prevout); // The test is designed to ensure spending a duplicate coinbase // will work properly if that ever happens and not resurrect the // previously overwritten coinbase if (duplicate_coins.count(prevout)) { spent_a_duplicate_coinbase = true; } } // Update the expected result to know about the new output coins assert(tx.vout.size() == 1); const COutPoint outpoint(tx.GetId(), 0); result[outpoint] = Coin(tx.vout[0], height, CTransaction(tx).IsCoinBase()); // Call UpdateCoins on the top cache CTxUndo undo; UpdateCoins(tx, *(stack.back()), undo, height); // Update the utxo set for future spends utxoset.insert(outpoint); // Track this tx and undo info to use later utxoData.emplace(outpoint, std::make_tuple(tx, undo, old_coin)); } // 1/20 times undo a previous transaction else if (utxoset.size()) { auto utxod = FindRandomFrom(utxoset); CTransaction &tx = std::get<0>(utxod->second); CTxUndo &undo = std::get<1>(utxod->second); Coin &orig_coin = std::get<2>(utxod->second); // Update the expected result // Remove new outputs result[utxod->first].Clear(); // If not coinbase restore prevout if (!tx.IsCoinBase()) { result[tx.vin[0].prevout] = orig_coin; } // Disconnect the tx from the current UTXO // See code in DisconnectBlock // remove outputs stack.back()->SpendCoin(utxod->first); // restore inputs if (!tx.IsCoinBase()) { const COutPoint &out = tx.vin[0].prevout; UndoCoinSpend(undo.vprevout[0], *(stack.back()), out); } // Store as a candidate for reconnection disconnected_coins.insert(utxod->first); // Update the utxoset utxoset.erase(utxod->first); if (!tx.IsCoinBase()) { utxoset.insert(tx.vin[0].prevout); } } // Once every 1000 iterations and at the end, verify the full cache. - if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + if (insecure_randrange(1000) == 1 || + i == NUM_SIMULATION_ITERATIONS - 1) { for (auto it = result.begin(); it != result.end(); it++) { bool have = stack.back()->HaveCoin(it->first); const Coin &coin = stack.back()->AccessCoin(it->first); BOOST_CHECK(have == !coin.IsSpent()); BOOST_CHECK(coin == it->second); } } // One every 10 iterations, remove a random entry from the cache - if (utxoset.size() > 1 && insecure_rand() % 30) { + if (utxoset.size() > 1 && insecure_randrange(30)) { stack[insecure_rand() % stack.size()]->Uncache( FindRandomFrom(utxoset)->first); } - if (disconnected_coins.size() > 1 && insecure_rand() % 30) { + if (disconnected_coins.size() > 1 && insecure_randrange(30)) { stack[insecure_rand() % stack.size()]->Uncache( FindRandomFrom(disconnected_coins)->first); } - if (duplicate_coins.size() > 1 && insecure_rand() % 30) { + if (duplicate_coins.size() > 1 && insecure_randrange(30)) { stack[insecure_rand() % stack.size()]->Uncache( FindRandomFrom(duplicate_coins)->first); } - if (insecure_rand() % 100 == 0) { + if (insecure_randrange(100) == 0) { // Every 100 iterations, flush an intermediate cache - if (stack.size() > 1 && insecure_rand() % 2 == 0) { + if (stack.size() > 1 && insecure_randrange(2) == 0) { unsigned int flushIndex = insecure_rand() % (stack.size() - 1); stack[flushIndex]->Flush(); } } - if (insecure_rand() % 100 == 0) { + if (insecure_randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && insecure_rand() % 2 == 0) { + if (stack.size() > 0 && insecure_randrange(2) == 0) { stack.back()->Flush(); delete stack.back(); stack.pop_back(); } if (stack.size() == 0 || - (stack.size() < 4 && insecure_rand() % 2)) { + (stack.size() < 4 && insecure_randrange(2))) { CCoinsView *tip = &base; if (stack.size() > 0) { tip = stack.back(); } stack.push_back(new CCoinsViewCacheTest(tip)); } } } // Clean up the stack. while (stack.size() > 0) { delete stack.back(); stack.pop_back(); } // Verify coverage. BOOST_CHECK(spent_a_duplicate_coinbase); } BOOST_AUTO_TEST_CASE(coin_serialization) { // Good example CDataStream ss1( ParseHex("97f23c835800816115944e077fe7c803cfa57f29b36bf87c1d35"), SER_DISK, CLIENT_VERSION); Coin c1; ss1 >> c1; BOOST_CHECK_EQUAL(c1.IsCoinBase(), false); BOOST_CHECK_EQUAL(c1.GetHeight(), 203998U); BOOST_CHECK_EQUAL(c1.GetTxOut().nValue, Amount(60000000000LL)); BOOST_CHECK_EQUAL(HexStr(c1.GetTxOut().scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex( "816115944e077fe7c803cfa57f29b36bf87c1d35")))))); // Good example CDataStream ss2( ParseHex("8ddf77bbd123008c988f1a4a4de2161e0f50aac7f17e7f9555caa4"), SER_DISK, CLIENT_VERSION); Coin c2; ss2 >> c2; BOOST_CHECK_EQUAL(c2.IsCoinBase(), true); BOOST_CHECK_EQUAL(c2.GetHeight(), 120891); BOOST_CHECK_EQUAL(c2.GetTxOut().nValue, Amount(110397LL)); BOOST_CHECK_EQUAL(HexStr(c2.GetTxOut().scriptPubKey), HexStr(GetScriptForDestination(CKeyID(uint160(ParseHex( "8c988f1a4a4de2161e0f50aac7f17e7f9555caa4")))))); // Smallest possible example CDataStream ss3(ParseHex("000006"), SER_DISK, CLIENT_VERSION); Coin c3; ss3 >> c3; BOOST_CHECK_EQUAL(c3.IsCoinBase(), false); BOOST_CHECK_EQUAL(c3.GetHeight(), 0); BOOST_CHECK_EQUAL(c3.GetTxOut().nValue, Amount(0)); BOOST_CHECK_EQUAL(c3.GetTxOut().scriptPubKey.size(), 0); // scriptPubKey that ends beyond the end of the stream CDataStream ss4(ParseHex("000007"), SER_DISK, CLIENT_VERSION); try { Coin c4; ss4 >> c4; BOOST_CHECK_MESSAGE(false, "We should have thrown"); } catch (const std::ios_base::failure &e) { } // Very large scriptPubKey (3*10^9 bytes) past the end of the stream CDataStream tmp(SER_DISK, CLIENT_VERSION); uint64_t x = 3000000000ULL; tmp << VARINT(x); BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00"); CDataStream ss5(ParseHex("00008a95c0bb00"), SER_DISK, CLIENT_VERSION); try { Coin c5; ss5 >> c5; BOOST_CHECK_MESSAGE(false, "We should have thrown"); } catch (const std::ios_base::failure &e) { } } static const COutPoint OUTPOINT; static const Amount PRUNED(-1); static const Amount ABSENT(-2); static const Amount FAIL(-3); static const Amount VALUE1(100); static const Amount VALUE2(200); static const Amount VALUE3(300); static const char DIRTY = CCoinsCacheEntry::DIRTY; static const char FRESH = CCoinsCacheEntry::FRESH; static const char NO_ENTRY = -1; static const auto FLAGS = {char(0), FRESH, DIRTY, char(DIRTY | FRESH)}; static const auto CLEAN_FLAGS = {char(0), FRESH}; static const auto ABSENT_FLAGS = {NO_ENTRY}; static void SetCoinValue(const Amount value, Coin &coin) { assert(value != ABSENT); coin.Clear(); assert(coin.IsSpent()); if (value != PRUNED) { CTxOut out; out.nValue = value; coin = Coin(std::move(out), 1, false); assert(!coin.IsSpent()); } } size_t InsertCoinMapEntry(CCoinsMap &map, const Amount value, char flags) { if (value == ABSENT) { assert(flags == NO_ENTRY); return 0; } assert(flags != NO_ENTRY); CCoinsCacheEntry entry; entry.flags = flags; SetCoinValue(value, entry.coin); auto inserted = map.emplace(OUTPOINT, std::move(entry)); assert(inserted.second); return inserted.first->second.coin.DynamicMemoryUsage(); } void GetCoinMapEntry(const CCoinsMap &map, Amount &value, char &flags) { auto it = map.find(OUTPOINT); if (it == map.end()) { value = ABSENT; flags = NO_ENTRY; } else { if (it->second.coin.IsSpent()) { value = PRUNED; } else { value = it->second.coin.GetTxOut().nValue; } flags = it->second.flags; assert(flags != NO_ENTRY); } } void WriteCoinViewEntry(CCoinsView &view, const Amount value, char flags) { CCoinsMap map; InsertCoinMapEntry(map, value, flags); view.BatchWrite(map, {}); } class SingleEntryCacheTest { public: SingleEntryCacheTest(const Amount base_value, const Amount cache_value, char cache_flags) { WriteCoinViewEntry(base, base_value, base_value == ABSENT ? NO_ENTRY : DIRTY); cache.usage() += InsertCoinMapEntry(cache.map(), cache_value, cache_flags); } CCoinsView root; CCoinsViewCacheTest base{&root}; CCoinsViewCacheTest cache{&base}; }; void CheckAccessCoin(const Amount base_value, const Amount cache_value, const Amount expected_value, char cache_flags, char expected_flags) { SingleEntryCacheTest test(base_value, cache_value, cache_flags); test.cache.AccessCoin(OUTPOINT); test.cache.SelfTest(); Amount result_value; char result_flags; GetCoinMapEntry(test.cache.map(), result_value, result_flags); BOOST_CHECK_EQUAL(result_value, expected_value); BOOST_CHECK_EQUAL(result_flags, expected_flags); } BOOST_AUTO_TEST_CASE(coin_access) { /* Check AccessCoin behavior, requesting a coin from a cache view layered on * top of a base view, and checking the resulting entry in the cache after * the access. * * Base Cache Result Cache Result * Value Value Value Flags Flags */ CheckAccessCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY); CheckAccessCoin(ABSENT, PRUNED, PRUNED, 0, 0); CheckAccessCoin(ABSENT, PRUNED, PRUNED, FRESH, FRESH); CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY, DIRTY); CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY | FRESH, DIRTY | FRESH); CheckAccessCoin(ABSENT, VALUE2, VALUE2, 0, 0); CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH, FRESH); CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY, DIRTY); CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH); CheckAccessCoin(PRUNED, ABSENT, PRUNED, NO_ENTRY, FRESH); CheckAccessCoin(PRUNED, PRUNED, PRUNED, 0, 0); CheckAccessCoin(PRUNED, PRUNED, PRUNED, FRESH, FRESH); CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY); CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY | FRESH, DIRTY | FRESH); CheckAccessCoin(PRUNED, VALUE2, VALUE2, 0, 0); CheckAccessCoin(PRUNED, VALUE2, VALUE2, FRESH, FRESH); CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY); CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH); CheckAccessCoin(VALUE1, ABSENT, VALUE1, NO_ENTRY, 0); CheckAccessCoin(VALUE1, PRUNED, PRUNED, 0, 0); CheckAccessCoin(VALUE1, PRUNED, PRUNED, FRESH, FRESH); CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY); CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY | FRESH, DIRTY | FRESH); CheckAccessCoin(VALUE1, VALUE2, VALUE2, 0, 0); CheckAccessCoin(VALUE1, VALUE2, VALUE2, FRESH, FRESH); CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY); CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH); } void CheckSpendCoin(Amount base_value, Amount cache_value, Amount expected_value, char cache_flags, char expected_flags) { SingleEntryCacheTest test(base_value, cache_value, cache_flags); test.cache.SpendCoin(OUTPOINT); test.cache.SelfTest(); Amount result_value; char result_flags; GetCoinMapEntry(test.cache.map(), result_value, result_flags); BOOST_CHECK_EQUAL(result_value, expected_value); BOOST_CHECK_EQUAL(result_flags, expected_flags); }; BOOST_AUTO_TEST_CASE(coin_spend) { /** * Check SpendCoin behavior, requesting a coin from a cache view layered on * top of a base view, spending, and then checking the resulting entry in * the cache after the modification. * * Base Cache Result Cache Result * Value Value Value Flags Flags */ CheckSpendCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY); CheckSpendCoin(ABSENT, PRUNED, PRUNED, 0, DIRTY); CheckSpendCoin(ABSENT, PRUNED, ABSENT, FRESH, NO_ENTRY); CheckSpendCoin(ABSENT, PRUNED, PRUNED, DIRTY, DIRTY); CheckSpendCoin(ABSENT, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY); CheckSpendCoin(ABSENT, VALUE2, PRUNED, 0, DIRTY); CheckSpendCoin(ABSENT, VALUE2, ABSENT, FRESH, NO_ENTRY); CheckSpendCoin(ABSENT, VALUE2, PRUNED, DIRTY, DIRTY); CheckSpendCoin(ABSENT, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY); CheckSpendCoin(PRUNED, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY); CheckSpendCoin(PRUNED, PRUNED, PRUNED, 0, DIRTY); CheckSpendCoin(PRUNED, PRUNED, ABSENT, FRESH, NO_ENTRY); CheckSpendCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY); CheckSpendCoin(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY); CheckSpendCoin(PRUNED, VALUE2, PRUNED, 0, DIRTY); CheckSpendCoin(PRUNED, VALUE2, ABSENT, FRESH, NO_ENTRY); CheckSpendCoin(PRUNED, VALUE2, PRUNED, DIRTY, DIRTY); CheckSpendCoin(PRUNED, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY); CheckSpendCoin(VALUE1, ABSENT, PRUNED, NO_ENTRY, DIRTY); CheckSpendCoin(VALUE1, PRUNED, PRUNED, 0, DIRTY); CheckSpendCoin(VALUE1, PRUNED, ABSENT, FRESH, NO_ENTRY); CheckSpendCoin(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY); CheckSpendCoin(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, NO_ENTRY); CheckSpendCoin(VALUE1, VALUE2, PRUNED, 0, DIRTY); CheckSpendCoin(VALUE1, VALUE2, ABSENT, FRESH, NO_ENTRY); CheckSpendCoin(VALUE1, VALUE2, PRUNED, DIRTY, DIRTY); CheckSpendCoin(VALUE1, VALUE2, ABSENT, DIRTY | FRESH, NO_ENTRY); } void CheckAddCoinBase(Amount base_value, Amount cache_value, Amount modify_value, Amount expected_value, char cache_flags, char expected_flags, bool coinbase) { SingleEntryCacheTest test(base_value, cache_value, cache_flags); Amount result_value; char result_flags; try { CTxOut output; output.nValue = modify_value; test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase); test.cache.SelfTest(); GetCoinMapEntry(test.cache.map(), result_value, result_flags); } catch (std::logic_error &e) { result_value = FAIL; result_flags = NO_ENTRY; } BOOST_CHECK_EQUAL(result_value, expected_value); BOOST_CHECK_EQUAL(result_flags, expected_flags); } // Simple wrapper for CheckAddCoinBase function above that loops through // different possible base_values, making sure each one gives the same results. // This wrapper lets the coin_add test below be shorter and less repetitive, // while still verifying that the CoinsViewCache::AddCoin implementation ignores // base values. template void CheckAddCoin(Args &&... args) { for (Amount base_value : {ABSENT, PRUNED, VALUE1}) { CheckAddCoinBase(base_value, std::forward(args)...); } } BOOST_AUTO_TEST_CASE(coin_add) { /** * Check AddCoin behavior, requesting a new coin from a cache view, writing * a modification to the coin, and then checking the resulting entry in the * cache after the modification. Verify behavior with the with the AddCoin * potential_overwrite argument set to false, and to true. * * Cache Write Result Cache Result potential_overwrite * Value Value Value Flags Flags */ CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY, DIRTY | FRESH, false); CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY, DIRTY, true); CheckAddCoin(PRUNED, VALUE3, VALUE3, 0, DIRTY | FRESH, false); CheckAddCoin(PRUNED, VALUE3, VALUE3, 0, DIRTY, true); CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH, DIRTY | FRESH, false); CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH, DIRTY | FRESH, true); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY, DIRTY, false); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY, DIRTY, true); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, false); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, true); CheckAddCoin(VALUE2, VALUE3, FAIL, 0, NO_ENTRY, false); CheckAddCoin(VALUE2, VALUE3, VALUE3, 0, DIRTY, true); CheckAddCoin(VALUE2, VALUE3, FAIL, FRESH, NO_ENTRY, false); CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH, DIRTY | FRESH, true); CheckAddCoin(VALUE2, VALUE3, FAIL, DIRTY, NO_ENTRY, false); CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY, DIRTY, true); CheckAddCoin(VALUE2, VALUE3, FAIL, DIRTY | FRESH, NO_ENTRY, false); CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY | FRESH, DIRTY | FRESH, true); } void CheckWriteCoin(Amount parent_value, Amount child_value, Amount expected_value, char parent_flags, char child_flags, char expected_flags) { SingleEntryCacheTest test(ABSENT, parent_value, parent_flags); Amount result_value; char result_flags; try { WriteCoinViewEntry(test.cache, child_value, child_flags); test.cache.SelfTest(); GetCoinMapEntry(test.cache.map(), result_value, result_flags); } catch (std::logic_error &e) { result_value = FAIL; result_flags = NO_ENTRY; } BOOST_CHECK_EQUAL(result_value, expected_value); BOOST_CHECK_EQUAL(result_flags, expected_flags); } BOOST_AUTO_TEST_CASE(coin_write) { /* Check BatchWrite behavior, flushing one entry from a child cache to a * parent cache, and checking the resulting entry in the parent cache * after the write. * * Parent Child Result Parent Child Result * Value Value Value Flags Flags Flags */ CheckWriteCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY, NO_ENTRY, NO_ENTRY); CheckWriteCoin(ABSENT, PRUNED, PRUNED, NO_ENTRY, DIRTY, DIRTY); CheckWriteCoin(ABSENT, PRUNED, ABSENT, NO_ENTRY, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY, DIRTY); CheckWriteCoin(ABSENT, VALUE2, VALUE2, NO_ENTRY, DIRTY | FRESH, DIRTY | FRESH); CheckWriteCoin(PRUNED, ABSENT, PRUNED, 0, NO_ENTRY, 0); CheckWriteCoin(PRUNED, ABSENT, PRUNED, FRESH, NO_ENTRY, FRESH); CheckWriteCoin(PRUNED, ABSENT, PRUNED, DIRTY, NO_ENTRY, DIRTY); CheckWriteCoin(PRUNED, ABSENT, PRUNED, DIRTY | FRESH, NO_ENTRY, DIRTY | FRESH); CheckWriteCoin(PRUNED, PRUNED, PRUNED, 0, DIRTY, DIRTY); CheckWriteCoin(PRUNED, PRUNED, PRUNED, 0, DIRTY | FRESH, DIRTY); CheckWriteCoin(PRUNED, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY); CheckWriteCoin(PRUNED, PRUNED, ABSENT, FRESH, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY); CheckWriteCoin(PRUNED, PRUNED, PRUNED, DIRTY, DIRTY | FRESH, DIRTY); CheckWriteCoin(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY); CheckWriteCoin(PRUNED, PRUNED, ABSENT, DIRTY | FRESH, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(PRUNED, VALUE2, VALUE2, 0, DIRTY, DIRTY); CheckWriteCoin(PRUNED, VALUE2, VALUE2, 0, DIRTY | FRESH, DIRTY); CheckWriteCoin(PRUNED, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH); CheckWriteCoin(PRUNED, VALUE2, VALUE2, FRESH, DIRTY | FRESH, DIRTY | FRESH); CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY); CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY, DIRTY | FRESH, DIRTY); CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH); CheckWriteCoin(PRUNED, VALUE2, VALUE2, DIRTY | FRESH, DIRTY | FRESH, DIRTY | FRESH); CheckWriteCoin(VALUE1, ABSENT, VALUE1, 0, NO_ENTRY, 0); CheckWriteCoin(VALUE1, ABSENT, VALUE1, FRESH, NO_ENTRY, FRESH); CheckWriteCoin(VALUE1, ABSENT, VALUE1, DIRTY, NO_ENTRY, DIRTY); CheckWriteCoin(VALUE1, ABSENT, VALUE1, DIRTY | FRESH, NO_ENTRY, DIRTY | FRESH); CheckWriteCoin(VALUE1, PRUNED, PRUNED, 0, DIRTY, DIRTY); CheckWriteCoin(VALUE1, PRUNED, FAIL, 0, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(VALUE1, PRUNED, ABSENT, FRESH, DIRTY, NO_ENTRY); CheckWriteCoin(VALUE1, PRUNED, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(VALUE1, PRUNED, PRUNED, DIRTY, DIRTY, DIRTY); CheckWriteCoin(VALUE1, PRUNED, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(VALUE1, PRUNED, ABSENT, DIRTY | FRESH, DIRTY, NO_ENTRY); CheckWriteCoin(VALUE1, PRUNED, FAIL, DIRTY | FRESH, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(VALUE1, VALUE2, VALUE2, 0, DIRTY, DIRTY); CheckWriteCoin(VALUE1, VALUE2, FAIL, 0, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(VALUE1, VALUE2, VALUE2, FRESH, DIRTY, DIRTY | FRESH); CheckWriteCoin(VALUE1, VALUE2, FAIL, FRESH, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(VALUE1, VALUE2, VALUE2, DIRTY, DIRTY, DIRTY); CheckWriteCoin(VALUE1, VALUE2, FAIL, DIRTY, DIRTY | FRESH, NO_ENTRY); CheckWriteCoin(VALUE1, VALUE2, VALUE2, DIRTY | FRESH, DIRTY, DIRTY | FRESH); CheckWriteCoin(VALUE1, VALUE2, FAIL, DIRTY | FRESH, DIRTY | FRESH, NO_ENTRY); // The checks above omit cases where the child flags are not DIRTY, since // they would be too repetitive (the parent cache is never updated in these // cases). The loop below covers these cases and makes sure the parent cache // is always left unchanged. for (Amount parent_value : {ABSENT, PRUNED, VALUE1}) { for (Amount child_value : {ABSENT, PRUNED, VALUE2}) { for (char parent_flags : parent_value == ABSENT ? ABSENT_FLAGS : FLAGS) { for (char child_flags : child_value == ABSENT ? ABSENT_FLAGS : CLEAN_FLAGS) { CheckWriteCoin(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags); } } } } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 9f0eef853..2509c7ecd 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -1,331 +1,331 @@ // Copyright (c) 2012-2016 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 "dbwrapper.h" #include "random.h" #include "test/test_bitcoin.h" #include "uint256.h" #include #include // for 'operator+=()' #include // Test if a string consists entirely of null characters bool is_null_key(const std::vector &key) { bool isnull = true; for (unsigned int i = 0; i < key.size(); i++) isnull &= (key[i] == '\x00'); return isnull; } BOOST_FIXTURE_TEST_SUITE(dbwrapper_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(dbwrapper) { // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'k'; - uint256 in = GetRandHash(); + uint256 in = insecure_rand256(); uint256 res; // Ensure that we're doing real obfuscation when obfuscate=true BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw))); BOOST_CHECK(dbw.Write(key, in)); BOOST_CHECK(dbw.Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); } } // Test batch operations BOOST_AUTO_TEST_CASE(dbwrapper_batch) { // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); char key = 'i'; - uint256 in = GetRandHash(); + uint256 in = insecure_rand256(); char key2 = 'j'; - uint256 in2 = GetRandHash(); + uint256 in2 = insecure_rand256(); char key3 = 'k'; - uint256 in3 = GetRandHash(); + uint256 in3 = insecure_rand256(); uint256 res; CDBBatch batch(dbw); batch.Write(key, in); batch.Write(key2, in2); batch.Write(key3, in3); // Remove key3 before it's even been written batch.Erase(key3); dbw.WriteBatch(batch); BOOST_CHECK(dbw.Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); BOOST_CHECK(dbw.Read(key2, res)); BOOST_CHECK_EQUAL(res.ToString(), in2.ToString()); // key3 should've never been written BOOST_CHECK(dbw.Read(key3, res) == false); } } BOOST_AUTO_TEST_CASE(dbwrapper_iterator) { // Perform tests both obfuscated and non-obfuscated. for (int i = 0; i < 2; i++) { bool obfuscate = (bool)i; boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, obfuscate); // The two keys are intentionally chosen for ordering char key = 'j'; - uint256 in = GetRandHash(); + uint256 in = insecure_rand256(); BOOST_CHECK(dbw.Write(key, in)); char key2 = 'k'; - uint256 in2 = GetRandHash(); + uint256 in2 = insecure_rand256(); BOOST_CHECK(dbw.Write(key2, in2)); std::unique_ptr it( const_cast(&dbw)->NewIterator()); // Be sure to seek past the obfuscation key (if it exists) it->Seek(key); char key_res; uint256 val_res; it->GetKey(key_res); it->GetValue(val_res); BOOST_CHECK_EQUAL(key_res, key); BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString()); it->Next(); it->GetKey(key_res); it->GetValue(val_res); BOOST_CHECK_EQUAL(key_res, key2); BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString()); it->Next(); BOOST_CHECK_EQUAL(it->Valid(), false); } } // Test that we do not obfuscation if there is existing data. BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) { // We're going to share this boost::filesystem::path between two wrappers boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. CDBWrapper *dbw = new CDBWrapper(ph, (1 << 10), false, false, false); char key = 'k'; - uint256 in = GetRandHash(); + uint256 in = insecure_rand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); BOOST_CHECK(dbw->Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); // Call the destructor to free leveldb LOCK delete dbw; // Now, set up another wrapper that wants to obfuscate the same directory CDBWrapper odbw(ph, (1 << 10), false, false, true); // Check that the key/val we wrote with unobfuscated wrapper exists and // is readable. uint256 res2; BOOST_CHECK(odbw.Read(key, res2)); BOOST_CHECK_EQUAL(res2.ToString(), in.ToString()); // There should be existing data BOOST_CHECK(!odbw.IsEmpty()); // The key should be an empty string BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); - uint256 in2 = GetRandHash(); + uint256 in2 = insecure_rand256(); uint256 res3; // Check that we can write successfully BOOST_CHECK(odbw.Write(key, in2)); BOOST_CHECK(odbw.Read(key, res3)); BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString()); } // Ensure that we start obfuscating during a reindex. BOOST_AUTO_TEST_CASE(existing_data_reindex) { // We're going to share this boost::filesystem::path between two wrappers boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); create_directories(ph); // Set up a non-obfuscated wrapper to write some initial data. CDBWrapper *dbw = new CDBWrapper(ph, (1 << 10), false, false, false); char key = 'k'; - uint256 in = GetRandHash(); + uint256 in = insecure_rand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); BOOST_CHECK(dbw->Read(key, res)); BOOST_CHECK_EQUAL(res.ToString(), in.ToString()); // Call the destructor to free leveldb LOCK delete dbw; // Simulate a -reindex by wiping the existing data store CDBWrapper odbw(ph, (1 << 10), false, true, true); // Check that the key/val we wrote with unobfuscated wrapper doesn't exist uint256 res2; BOOST_CHECK(!odbw.Read(key, res2)); BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); - uint256 in2 = GetRandHash(); + uint256 in2 = insecure_rand256(); uint256 res3; // Check that we can write successfully BOOST_CHECK(odbw.Write(key, in2)); BOOST_CHECK(odbw.Read(key, res3)); BOOST_CHECK_EQUAL(res3.ToString(), in2.ToString()); } BOOST_AUTO_TEST_CASE(iterator_ordering) { boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x = 0x00; x < 256; ++x) { uint8_t key = x; uint32_t value = x * x; BOOST_CHECK(dbw.Write(key, value)); } std::unique_ptr it( const_cast(&dbw)->NewIterator()); for (int c = 0; c < 2; ++c) { int seek_start; if (c == 0) seek_start = 0x00; else seek_start = 0x80; it->Seek((uint8_t)seek_start); for (int x = seek_start; x < 256; ++x) { uint8_t key; uint32_t value; BOOST_CHECK(it->Valid()); // Avoid spurious errors about invalid iterator's key and value in // case of failure if (!it->Valid()) break; BOOST_CHECK(it->GetKey(key)); BOOST_CHECK(it->GetValue(value)); BOOST_CHECK_EQUAL(key, x); BOOST_CHECK_EQUAL(value, x * x); it->Next(); } BOOST_CHECK(!it->Valid()); } } struct StringContentsSerializer { // Used to make two serialized objects the same while letting them have a // different lengths. This is a terrible idea. std::string str; StringContentsSerializer() {} StringContentsSerializer(const std::string &inp) : str(inp) {} StringContentsSerializer &operator+=(const std::string &s) { str += s; return *this; } StringContentsSerializer &operator+=(const StringContentsSerializer &s) { return *this += s.str; } ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream &s, Operation ser_action) { if (ser_action.ForRead()) { str.clear(); char c = 0; while (true) { try { READWRITE(c); str.push_back(c); } catch (const std::ios_base::failure &e) { break; } } } else { for (size_t i = 0; i < str.size(); i++) READWRITE(str[i]); } } }; BOOST_AUTO_TEST_CASE(iterator_string_ordering) { char buf[10]; boost::filesystem::path ph = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); CDBWrapper dbw(ph, (1 << 20), true, false, false); for (int x = 0x00; x < 10; ++x) { for (int y = 0; y < 10; y++) { sprintf(buf, "%d", x); StringContentsSerializer key(buf); for (int z = 0; z < y; z++) key += key; uint32_t value = x * x; BOOST_CHECK(dbw.Write(key, value)); } } std::unique_ptr it( const_cast(&dbw)->NewIterator()); for (int c = 0; c < 2; ++c) { int seek_start; if (c == 0) seek_start = 0; else seek_start = 5; sprintf(buf, "%d", seek_start); StringContentsSerializer seek_key(buf); it->Seek(seek_key); for (int x = seek_start; x < 10; ++x) { for (int y = 0; y < 10; y++) { sprintf(buf, "%d", x); std::string exp_key(buf); for (int z = 0; z < y; z++) exp_key += exp_key; StringContentsSerializer key; uint32_t value; BOOST_CHECK(it->Valid()); // Avoid spurious errors about invalid iterator's key and value // in case of failure if (!it->Valid()) break; BOOST_CHECK(it->GetKey(key)); BOOST_CHECK(it->GetValue(value)); BOOST_CHECK_EQUAL(key.str, exp_key); BOOST_CHECK_EQUAL(value, x * x); it->Next(); } } BOOST_CHECK(!it->Valid()); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 327bf1062..84e556b70 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -1,202 +1,202 @@ // Copyright (c) 2013-2016 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 "hash.h" #include "test/test_bitcoin.h" #include "utilstrencodings.h" #include #include BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(murmurhash3) { #define T(expected, seed, data) \ BOOST_CHECK_EQUAL(MurmurHash3(seed, ParseHex(data)), expected) // Test MurmurHash3 with various inputs. Of course this is retested in the // bloom filter tests - they would fail if MurmurHash3() had any problems - // but is useful for those trying to implement Bitcoin libraries as a // source of test data for their MurmurHash3() primitive during // development. // // The magic number 0xFBA4C795 comes from CBloomFilter::Hash() T(0x00000000, 0x00000000, ""); T(0x6a396f08, 0xFBA4C795, ""); T(0x81f16f39, 0xffffffff, ""); T(0x514e28b7, 0x00000000, "00"); T(0xea3f0b17, 0xFBA4C795, "00"); T(0xfd6cf10d, 0x00000000, "ff"); T(0x16c6b7ab, 0x00000000, "0011"); T(0x8eb51c3d, 0x00000000, "001122"); T(0xb4471bf8, 0x00000000, "00112233"); T(0xe2301fa8, 0x00000000, "0011223344"); T(0xfc2e4a15, 0x00000000, "001122334455"); T(0xb074502c, 0x00000000, "00112233445566"); T(0x8034d2a0, 0x00000000, "0011223344556677"); T(0xb4698def, 0x00000000, "001122334455667788"); #undef T } /** * SipHash-2-4 output with * k = 00 01 02 ... * and * in = (empty string) * in = 00 (1 byte) * in = 00 01 (2 bytes) * in = 00 01 02 (3 bytes) * ... * in = 00 01 02 ... 3e (63 bytes) * * from: https://131002.net/siphash/siphash24.c */ uint64_t siphash_4_2_testvec[] = { 0x726fdb47dd0e0e31, 0x74f839c593dc67fd, 0x0d6c8009d9a94f5a, 0x85676696d7fb7e2d, 0xcf2794e0277187b7, 0x18765564cd99a68d, 0xcbc9466e58fee3ce, 0xab0200f58b01d137, 0x93f5f5799a932462, 0x9e0082df0ba9e4b0, 0x7a5dbbc594ddb9f3, 0xf4b32f46226bada7, 0x751e8fbc860ee5fb, 0x14ea5627c0843d90, 0xf723ca908e7af2ee, 0xa129ca6149be45e5, 0x3f2acc7f57c29bdb, 0x699ae9f52cbe4794, 0x4bc1b3f0968dd39c, 0xbb6dc91da77961bd, 0xbed65cf21aa2ee98, 0xd0f2cbb02e3b67c7, 0x93536795e3a33e88, 0xa80c038ccd5ccec8, 0xb8ad50c6f649af94, 0xbce192de8a85b8ea, 0x17d835b85bbb15f3, 0x2f2e6163076bcfad, 0xde4daaaca71dc9a5, 0xa6a2506687956571, 0xad87a3535c49ef28, 0x32d892fad841c342, 0x7127512f72f27cce, 0xa7f32346f95978e3, 0x12e0b01abb051238, 0x15e034d40fa197ae, 0x314dffbe0815a3b4, 0x027990f029623981, 0xcadcd4e59ef40c4d, 0x9abfd8766a33735c, 0x0e3ea96b5304a7d0, 0xad0c42d6fc585992, 0x187306c89bc215a9, 0xd4a60abcf3792b95, 0xf935451de4f21df2, 0xa9538f0419755787, 0xdb9acddff56ca510, 0xd06c98cd5c0975eb, 0xe612a3cb9ecba951, 0xc766e62cfcadaf96, 0xee64435a9752fe72, 0xa192d576b245165a, 0x0a8787bf8ecb74b2, 0x81b3e73d20b49b6f, 0x7fa8220ba3b2ecea, 0x245731c13ca42499, 0xb78dbfaf3a8d83bd, 0xea1ad565322a1a0b, 0x60e61c23a3795013, 0x6606d7e446282b93, 0x6ca4ecb15c5f91e1, 0x9f626da15c9625f3, 0xe51b38608ef25f57, 0x958a324ceb064572}; BOOST_AUTO_TEST_CASE(siphash) { CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull); static const uint8_t t0[1] = {0}; hasher.Write(t0, 1); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x74f839c593dc67fdull); static const uint8_t t1[7] = {1, 2, 3, 4, 5, 6, 7}; hasher.Write(t1, 7); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull); hasher.Write(0x0F0E0D0C0B0A0908ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull); static const uint8_t t2[2] = {16, 17}; hasher.Write(t2, 2); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x4bc1b3f0968dd39cull); static const uint8_t t3[9] = {18, 19, 20, 21, 22, 23, 24, 25, 26}; hasher.Write(t3, 9); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x2f2e6163076bcfadull); static const uint8_t t4[5] = {27, 28, 29, 30, 31}; hasher.Write(t4, 5); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull); hasher.Write(0x2726252423222120ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull); hasher.Write(0x2F2E2D2C2B2A2928ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull); BOOST_CHECK_EQUAL( SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256S("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09" "080706050403020100")), 0x7127512f72f27cceull); // Check test vectors from spec, one byte at a time CSipHasher hasher2(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); for (uint8_t x = 0; x < ARRAYLEN(siphash_4_2_testvec); ++x) { BOOST_CHECK_EQUAL(hasher2.Finalize(), siphash_4_2_testvec[x]); hasher2.Write(&x, 1); } // Check test vectors from spec, eight bytes at a time CSipHasher hasher3(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); for (uint8_t x = 0; x < ARRAYLEN(siphash_4_2_testvec); x += 8) { BOOST_CHECK_EQUAL(hasher3.Finalize(), siphash_4_2_testvec[x]); hasher3.Write(uint64_t(x) | (uint64_t(x + 1) << 8) | (uint64_t(x + 2) << 16) | (uint64_t(x + 3) << 24) | (uint64_t(x + 4) << 32) | (uint64_t(x + 5) << 40) | (uint64_t(x + 6) << 48) | (uint64_t(x + 7) << 56)); } CHashWriter ss(SER_DISK, CLIENT_VERSION); CMutableTransaction tx; // Note these tests were originally written with tx.nVersion=1 // and the test would be affected by default tx version bumps if not fixed. tx.nVersion = 1; ss << tx; BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL); // Check consistency between CSipHasher and SipHashUint256[Extra]. FastRandomContext ctx; for (int i = 0; i < 16; ++i) { uint64_t k1 = ctx.rand64(); uint64_t k2 = ctx.rand64(); - uint256 x = GetRandHash(); + uint256 x = insecure_rand256(); uint32_t n = ctx.rand32(); uint8_t nb[4]; WriteLE32(nb, n); CSipHasher sip256(k1, k2); sip256.Write(x.begin(), 32); CSipHasher sip288 = sip256; sip288.Write(nb, 4); BOOST_CHECK_EQUAL(SipHashUint256(k1, k2, x), sip256.Finalize()); BOOST_CHECK_EQUAL(SipHashUint256Extra(k1, k2, x, n), sip288.Finalize()); } } namespace { class CDummyObject { uint32_t value; public: CDummyObject() : value(0) {} uint32_t GetValue() { return value; } template void Serialize(Stream &s) const { int nVersionDummy = 0; ::Serialize(s, VARINT(nVersionDummy)); ::Serialize(s, VARINT(value)); } template void Unserialize(Stream &s) { int nVersionDummy; ::Unserialize(s, VARINT(nVersionDummy)); ::Unserialize(s, VARINT(value)); } }; } BOOST_AUTO_TEST_CASE(hashverifier_tests) { std::vector data = ParseHex("4223"); CDataStream ss(data, SER_DISK, CLIENT_VERSION); CHashVerifier verifier(&ss); CDummyObject dummy; verifier >> dummy; uint256 checksum = verifier.GetHash(); BOOST_CHECK_EQUAL(dummy.GetValue(), 0x23); CHashWriter h0(SER_DISK, CLIENT_VERSION); h0 << CDataStream(data, SER_DISK, CLIENT_VERSION); BOOST_CHECK(h0.GetHash() == checksum); CHashWriter h1(SER_DISK, CLIENT_VERSION); h1 << dummy; BOOST_CHECK(h1.GetHash() != checksum); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index b96147e1a..130d294c6 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -1,155 +1,155 @@ // Copyright (c) 2015-2016 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 "consensus/merkle.h" #include "test/test_bitcoin.h" #include BOOST_FIXTURE_TEST_SUITE(merkle_tests, TestingSetup) // Older version of the merkle root computation code, for comparison. static uint256 BlockBuildMerkleTree(const CBlock &block, bool *fMutated, std::vector &vMerkleTree) { vMerkleTree.clear(); // Safe upper bound for the number of total nodes. vMerkleTree.reserve(block.vtx.size() * 2 + 16); for (std::vector::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it) vMerkleTree.push_back((*it)->GetId()); int j = 0; bool mutated = false; for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { for (int i = 0; i < nSize; i += 2) { int i2 = std::min(i + 1, nSize - 1); if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j + i] == vMerkleTree[j + i2]) { // Two identical hashes at the end of the list at a particular // level. mutated = true; } vMerkleTree.push_back( Hash(vMerkleTree[j + i].begin(), vMerkleTree[j + i].end(), vMerkleTree[j + i2].begin(), vMerkleTree[j + i2].end())); } j += nSize; } if (fMutated) { *fMutated = mutated; } return (vMerkleTree.empty() ? uint256() : vMerkleTree.back()); } // Older version of the merkle branch computation code, for comparison. static std::vector BlockGetMerkleBranch(const CBlock &block, const std::vector &vMerkleTree, int nIndex) { std::vector vMerkleBranch; int j = 0; for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { int i = std::min(nIndex ^ 1, nSize - 1); vMerkleBranch.push_back(vMerkleTree[j + i]); nIndex >>= 1; j += nSize; } return vMerkleBranch; } static inline int ctz(uint32_t i) { if (i == 0) return 0; int j = 0; while (!(i & 1)) { j++; i >>= 1; } return j; } BOOST_AUTO_TEST_CASE(merkle_test) { for (int i = 0; i < 32; i++) { // Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 // random sizes. - int ntx = (i <= 16) ? i : 17 + (insecure_rand() % 4000); + int ntx = (i <= 16) ? i : 17 + (insecure_randrange(4000)); // Try up to 3 mutations. for (int mutate = 0; mutate <= 3; mutate++) { // The last how many transactions to duplicate first. int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; if (duplicate1 >= ntx) { // Duplication of the entire tree results in a different root // (it adds a level). break; } // The resulting number of transactions after the first duplication. int ntx1 = ntx + duplicate1; // Likewise for the second mutation. int duplicate2 = mutate >= 2 ? 1 << ctz(ntx1) : 0; if (duplicate2 >= ntx1) break; int ntx2 = ntx1 + duplicate2; // And for the third mutation. int duplicate3 = mutate >= 3 ? 1 << ctz(ntx2) : 0; if (duplicate3 >= ntx2) break; int ntx3 = ntx2 + duplicate3; // Build a block with ntx different transactions. CBlock block; block.vtx.resize(ntx); for (int j = 0; j < ntx; j++) { CMutableTransaction mtx; mtx.nLockTime = j; block.vtx[j] = MakeTransactionRef(std::move(mtx)); } // Compute the root of the block before mutating it. bool unmutatedMutated = false; uint256 unmutatedRoot = BlockMerkleRoot(block, &unmutatedMutated); BOOST_CHECK(unmutatedMutated == false); // Optionally mutate by duplicating the last transactions, resulting // in the same merkle root. block.vtx.resize(ntx3); for (int j = 0; j < duplicate1; j++) { block.vtx[ntx + j] = block.vtx[ntx + j - duplicate1]; } for (int j = 0; j < duplicate2; j++) { block.vtx[ntx1 + j] = block.vtx[ntx1 + j - duplicate2]; } for (int j = 0; j < duplicate3; j++) { block.vtx[ntx2 + j] = block.vtx[ntx2 + j - duplicate3]; } // Compute the merkle root and merkle tree using the old mechanism. bool oldMutated = false; std::vector merkleTree; uint256 oldRoot = BlockBuildMerkleTree(block, &oldMutated, merkleTree); // Compute the merkle root using the new mechanism. bool newMutated = false; uint256 newRoot = BlockMerkleRoot(block, &newMutated); BOOST_CHECK(oldRoot == newRoot); BOOST_CHECK(newRoot == unmutatedRoot); BOOST_CHECK((newRoot == uint256()) == (ntx == 0)); BOOST_CHECK(oldMutated == newMutated); BOOST_CHECK(newMutated == !!mutate); // If no mutation was done (once for every ntx value), try up to 16 // branches. if (mutate == 0) { for (int loop = 0; loop < std::min(ntx, 16); loop++) { // If ntx <= 16, try all branches. Otherise, try 16 random // ones. int mtx = loop; if (ntx > 16) { mtx = insecure_rand() % ntx; } std::vector newBranch = BlockMerkleBranch(block, mtx); std::vector oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); BOOST_CHECK(oldBranch == newBranch); BOOST_CHECK( ComputeMerkleRootFromBranch(block.vtx[mtx]->GetId(), newBranch, mtx) == oldRoot); } } } } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c55ef187d..f64a2d2a5 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -1,783 +1,783 @@ // Copyright (c) 2011-2016 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 "miner.h" #include "chainparams.h" #include "coins.h" #include "config.h" #include "consensus/consensus.h" #include "consensus/merkle.h" #include "consensus/validation.h" #include "policy/policy.h" #include "pubkey.h" #include "script/standard.h" #include "txmempool.h" #include "uint256.h" #include "util.h" #include "utilstrencodings.h" #include "validation.h" #include "test/test_bitcoin.h" #include #include BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); static struct { uint8_t extranonce; unsigned int nonce; } blockinfo[] = { {4, 0xa4a3e223}, {2, 0x15c32f9e}, {1, 0x0375b547}, {1, 0x7004a8a5}, {2, 0xce440296}, {2, 0x52cfe198}, {1, 0x77a72cd0}, {2, 0xbb5d6f84}, {2, 0x83f30c2c}, {1, 0x48a73d5b}, {1, 0xef7dcd01}, {2, 0x6809c6c4}, {2, 0x0883ab3c}, {1, 0x087bbbe2}, {2, 0x2104a814}, {2, 0xdffb6daa}, {1, 0xee8a0a08}, {2, 0xba4237c1}, {1, 0xa70349dc}, {1, 0x344722bb}, {3, 0xd6294733}, {2, 0xec9f5c94}, {2, 0xca2fbc28}, {1, 0x6ba4f406}, {2, 0x015d4532}, {1, 0x6e119b7c}, {2, 0x43e8f314}, {2, 0x27962f38}, {2, 0xb571b51b}, {2, 0xb36bee23}, {2, 0xd17924a8}, {2, 0x6bc212d9}, {1, 0x630d4948}, {2, 0x9a4c4ebb}, {2, 0x554be537}, {1, 0xd63ddfc7}, {2, 0xa10acc11}, {1, 0x759a8363}, {2, 0xfb73090d}, {1, 0xe82c6a34}, {1, 0xe33e92d7}, {3, 0x658ef5cb}, {2, 0xba32ff22}, {5, 0x0227a10c}, {1, 0xa9a70155}, {5, 0xd096d809}, {1, 0x37176174}, {1, 0x830b8d0f}, {1, 0xc6e3910e}, {2, 0x823f3ca8}, {1, 0x99850849}, {1, 0x7521fb81}, {1, 0xaacaabab}, {1, 0xd645a2eb}, {5, 0x7aea1781}, {5, 0x9d6e4b78}, {1, 0x4ce90fd8}, {1, 0xabdc832d}, {6, 0x4a34f32a}, {2, 0xf2524c1c}, {2, 0x1bbeb08a}, {1, 0xad47f480}, {1, 0x9f026aeb}, {1, 0x15a95049}, {2, 0xd1cb95b2}, {2, 0xf84bbda5}, {1, 0x0fa62cd1}, {1, 0xe05f9169}, {1, 0x78d194a9}, {5, 0x3e38147b}, {5, 0x737ba0d4}, {1, 0x63378e10}, {1, 0x6d5f91cf}, {2, 0x88612eb8}, {2, 0xe9639484}, {1, 0xb7fabc9d}, {2, 0x19b01592}, {1, 0x5a90dd31}, {2, 0x5bd7e028}, {2, 0x94d00323}, {1, 0xa9b9c01a}, {1, 0x3a40de61}, {1, 0x56e7eec7}, {5, 0x859f7ef6}, {1, 0xfd8e5630}, {1, 0x2b0c9f7f}, {1, 0xba700e26}, {1, 0x7170a408}, {1, 0x70de86a8}, {1, 0x74d64cd5}, {1, 0x49e738a1}, {2, 0x6910b602}, {0, 0x643c565f}, {1, 0x54264b3f}, {2, 0x97ea6396}, {2, 0x55174459}, {2, 0x03e8779a}, {1, 0x98f34d8f}, {1, 0xc07b2b07}, {1, 0xdfe29668}, {1, 0x3141c7c1}, {1, 0xb3b595f4}, {1, 0x735abf08}, {5, 0x623bfbce}, {2, 0xd351e722}, {1, 0xf4ca48c9}, {1, 0x5b19c670}, {1, 0xa164bf0e}, {2, 0xbbbeb305}, {2, 0xfe1c810a}, }; CBlockIndex CreateBlockIndex(int nHeight) { CBlockIndex index; index.nHeight = nHeight; index.pprev = chainActive.Tip(); return index; } bool TestSequenceLocks(const CTransaction &tx, int flags) { LOCK(mempool.cs); return CheckSequenceLocks(tx, flags); } // Test suite for ancestor feerate transaction selection. // Implemented as an additional function, rather than a separate test case, to // allow reusing the blockchain created in CreateNewBlock_validity. // Note that this test assumes blockprioritypercentage is 0. void TestPackageSelection(const CChainParams &chainparams, CScript scriptPubKey, std::vector &txFirst) { // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; GlobalConfig config; // these 3 tests assume blockprioritypercentage is 0. config.SetBlockPriorityPercentage(0); // Test that a medium fee transaction will be selected after a higher fee // rate package with a low fee rate parent. CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].scriptSig = CScript() << OP_1; tx.vin[0].prevout.hash = txFirst[0]->GetId(); tx.vin[0].prevout.n = 0; tx.vout.resize(1); tx.vout[0].nValue = Amount(5000000000LL - 1000); // This tx has a low fee: 1000 satoshis. // Save this txid for later use. uint256 hashParentTx = tx.GetId(); mempool.addUnchecked(hashParentTx, entry.Fee(Amount(1000)) .Time(GetTime()) .SpendsCoinbase(true) .FromTx(tx)); // This tx has a medium fee: 10000 satoshis. tx.vin[0].prevout.hash = txFirst[1]->GetId(); tx.vout[0].nValue = Amount(5000000000LL - 10000); uint256 hashMediumFeeTx = tx.GetId(); mempool.addUnchecked(hashMediumFeeTx, entry.Fee(Amount(10000)) .Time(GetTime()) .SpendsCoinbase(true) .FromTx(tx)); // This tx has a high fee, but depends on the first transaction. tx.vin[0].prevout.hash = hashParentTx; // 50k satoshi fee. tx.vout[0].nValue = Amount(5000000000LL - 1000 - 50000); uint256 hashHighFeeTx = tx.GetId(); mempool.addUnchecked(hashHighFeeTx, entry.Fee(Amount(50000)) .Time(GetTime()) .SpendsCoinbase(false) .FromTx(tx)); std::unique_ptr pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == hashParentTx); BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == hashHighFeeTx); BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == hashMediumFeeTx); // Test that a package below the block min tx fee doesn't get included tx.vin[0].prevout.hash = hashHighFeeTx; // 0 fee. tx.vout[0].nValue = Amount(5000000000LL - 1000 - 50000); uint256 hashFreeTx = tx.GetId(); mempool.addUnchecked(hashFreeTx, entry.Fee(Amount(0)).FromTx(tx)); size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); // Calculate a fee on child transaction that will put the package just // below the block min tx fee (assuming 1 child tx of the same size). Amount feeToUse = blockMinFeeRate.GetFee(2 * freeTxSize) - Amount(1); tx.vin[0].prevout.hash = hashFreeTx; tx.vout[0].nValue = Amount(5000000000LL - 1000 - 50000) - feeToUse; uint256 hashLowFeeTx = tx.GetId(); mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse).FromTx(tx)); pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected. for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashLowFeeTx); } // Test that packages above the min relay fee do get included, even if one // of the transactions is below the min relay fee. Remove the low fee // transaction and replace with a higher fee transaction mempool.removeRecursive(tx); // Now we should be just over the min relay fee. tx.vout[0].nValue -= Amount(2); hashLowFeeTx = tx.GetId(); mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse + Amount(2)).FromTx(tx)); pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == hashFreeTx); BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == hashLowFeeTx); // Test that transaction selection properly updates ancestor fee // calculations as ancestor transactions get included in a block. Add a // 0-fee transaction that has 2 outputs. tx.vin[0].prevout.hash = txFirst[2]->GetId(); tx.vout.resize(2); tx.vout[0].nValue = Amount(5000000000LL - 100000000); // 1BCC output. tx.vout[1].nValue = Amount(100000000); uint256 hashFreeTx2 = tx.GetId(); mempool.addUnchecked(hashFreeTx2, entry.Fee(Amount(0)).SpendsCoinbase(true).FromTx(tx)); // This tx can't be mined by itself. tx.vin[0].prevout.hash = hashFreeTx2; tx.vout.resize(1); feeToUse = blockMinFeeRate.GetFee(freeTxSize); tx.vout[0].nValue = Amount(5000000000LL) - Amount(100000000) - feeToUse; uint256 hashLowFeeTx2 = tx.GetId(); mempool.addUnchecked(hashLowFeeTx2, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx)); pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); // Verify that this tx isn't selected. for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) { BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashFreeTx2); BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashLowFeeTx2); } // This tx will be mineable, and should cause hashLowFeeTx2 to be selected // as well. tx.vin[0].prevout.n = 1; // 10k satoshi fee. tx.vout[0].nValue = Amount(100000000 - 10000); mempool.addUnchecked(tx.GetId(), entry.Fee(Amount(10000)).FromTx(tx)); pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); BOOST_CHECK(pblocktemplate->block.vtx[8]->GetId() == hashLowFeeTx2); } void TestCoinbaseMessageEB(uint64_t eb, std::string cbmsg) { GlobalConfig config; config.SetMaxBlockSize(eb); const CChainParams &chainparams = config.GetChainParams(); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" "a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112" "de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; std::unique_ptr pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); CBlock *pblock = &pblocktemplate->block; // IncrementExtraNonce creates a valid coinbase and merkleRoot unsigned int extraNonce = 0; IncrementExtraNonce(config, pblock, chainActive.Tip(), extraNonce); unsigned int nHeight = chainActive.Tip()->nHeight + 1; std::vector vec(cbmsg.begin(), cbmsg.end()); BOOST_CHECK(pblock->vtx[0]->vin[0].scriptSig == ((CScript() << nHeight << CScriptNum(extraNonce) << vec) + COINBASE_FLAGS)); } // Coinbase scriptSig has to contains the correct EB value // converted to MB, rounded down to the first decimal BOOST_AUTO_TEST_CASE(CheckCoinbase_EB) { TestCoinbaseMessageEB(1000001, "/EB1.0/"); TestCoinbaseMessageEB(2000000, "/EB2.0/"); TestCoinbaseMessageEB(8000000, "/EB8.0/"); TestCoinbaseMessageEB(8320000, "/EB8.3/"); } // NOTE: These tests rely on CreateNewBlock doing its own self-validation! BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) { // Note that by default, these tests run with size accounting enabled. const CChainParams &chainparams = Params(CBaseChainParams::MAIN); CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909" "a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112" "de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; std::unique_ptr pblocktemplate; CMutableTransaction tx, tx2; CScript script; uint256 hash; TestMemPoolEntryHelper entry; entry.nFee = Amount(11); entry.dPriority = 111.0; entry.nHeight = 11; GlobalConfig config; LOCK(cs_main); fCheckpointsEnabled = false; // Simple block creation, nothing special yet: BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); // We can't make transactions until we have inputs. Therefore, load 100 // blocks :) int baseheight = 0; std::vector txFirst; for (unsigned int i = 0; i < sizeof(blockinfo) / sizeof(*blockinfo); ++i) { // pointer for convenience. CBlock *pblock = &pblocktemplate->block; pblock->nVersion = 1; pblock->nTime = chainActive.Tip()->GetMedianTimePast() + 1; CMutableTransaction txCoinbase(*pblock->vtx[0]); txCoinbase.nVersion = 1; txCoinbase.vin[0].scriptSig = CScript(); txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce); txCoinbase.vin[0].scriptSig.push_back(chainActive.Height()); // Ignore the (optional) segwit commitment added by CreateNewBlock (as // the hardcoded nonces don't account for this) txCoinbase.vout.resize(1); txCoinbase.vout[0].scriptPubKey = CScript(); pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); if (txFirst.size() == 0) baseheight = chainActive.Height(); if (txFirst.size() < 4) txFirst.push_back(pblock->vtx[0]); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; std::shared_ptr shared_pblock = std::make_shared(*pblock); BOOST_CHECK(ProcessNewBlock(GetConfig(), shared_pblock, true, nullptr)); pblock->hashPrevBlock = pblock->GetHash(); } // Just to make sure we can still make simple blocks. BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); const Amount BLOCKSUBSIDY = 50 * COIN; const Amount LOWFEE = CENT; const Amount HIGHFEE = COIN; const Amount HIGHERFEE = 4 * COIN; // block sigops > limit: 1000 CHECKMULTISIG + 1 tx.vin.resize(1); // NOTE: OP_NOP is used to force 20 SigOps for the CHECKMULTISIG tx.vin[0].scriptSig = CScript() << OP_0 << OP_0 << OP_0 << OP_NOP << OP_CHECKMULTISIG << OP_1; tx.vin[0].prevout.hash = txFirst[0]->GetId(); tx.vin[0].prevout.n = 0; tx.vout.resize(1); tx.vout[0].nValue = BLOCKSUBSIDY; for (unsigned int i = 0; i < 1001; ++i) { tx.vout[0].nValue -= LOWFEE; hash = tx.GetId(); // Only first tx spends coinbase. bool spendsCoinbase = (i == 0) ? true : false; // If we don't set the # of sig ops in the CTxMemPoolEntry, template // creation fails. mempool.addUnchecked(hash, entry.Fee(LOWFEE) .Time(GetTime()) .SpendsCoinbase(spendsCoinbase) .FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK_THROW( BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); tx.vin[0].prevout.hash = txFirst[0]->GetId(); tx.vout[0].nValue = BLOCKSUBSIDY; for (unsigned int i = 0; i < 1001; ++i) { tx.vout[0].nValue -= LOWFEE; hash = tx.GetId(); // Only first tx spends coinbase. bool spendsCoinbase = (i == 0) ? true : false; // If we do set the # of sig ops in the CTxMemPoolEntry, template // creation passes. mempool.addUnchecked(hash, entry.Fee(LOWFEE) .Time(GetTime()) .SpendsCoinbase(spendsCoinbase) .SigOpsCost(80) .FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); mempool.clear(); // block size > limit tx.vin[0].scriptSig = CScript(); // 18 * (520char + DROP) + OP_1 = 9433 bytes std::vector vchData(520); for (unsigned int i = 0; i < 18; ++i) tx.vin[0].scriptSig << vchData << OP_DROP; tx.vin[0].scriptSig << OP_1; tx.vin[0].prevout.hash = txFirst[0]->GetId(); tx.vout[0].nValue = BLOCKSUBSIDY; for (unsigned int i = 0; i < 128; ++i) { tx.vout[0].nValue -= LOWFEE; hash = tx.GetId(); // Only first tx spends coinbase. bool spendsCoinbase = (i == 0) ? true : false; mempool.addUnchecked(hash, entry.Fee(LOWFEE) .Time(GetTime()) .SpendsCoinbase(spendsCoinbase) .FromTx(tx)); tx.vin[0].prevout.hash = hash; } BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); mempool.clear(); // Orphan in mempool, template creation fails. hash = tx.GetId(); mempool.addUnchecked(hash, entry.Fee(LOWFEE).Time(GetTime()).FromTx(tx)); BOOST_CHECK_THROW( BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); // Child with higher priority than parent. tx.vin[0].scriptSig = CScript() << OP_1; tx.vin[0].prevout.hash = txFirst[1]->GetId(); tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; hash = tx.GetId(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin.resize(2); tx.vin[1].scriptSig = CScript() << OP_1; tx.vin[1].prevout.hash = txFirst[0]->GetId(); tx.vin[1].prevout.n = 0; // First txn output + fresh coinbase - new txn fee. tx.vout[0].nValue = tx.vout[0].nValue + BLOCKSUBSIDY - HIGHERFEE; hash = tx.GetId(); mempool.addUnchecked( hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); mempool.clear(); // Coinbase in mempool, template creation fails. tx.vin.resize(1); tx.vin[0].prevout.SetNull(); tx.vin[0].scriptSig = CScript() << OP_0 << OP_1; tx.vout[0].nValue = Amount(0); hash = tx.GetId(); // Give it a fee so it'll get mined. mempool.addUnchecked( hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); BOOST_CHECK_THROW( BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); // Invalid (pre-p2sh) txn in mempool, template creation fails. tx.vin[0].prevout.hash = txFirst[0]->GetId(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE; script = CScript() << OP_0; tx.vout[0].scriptPubKey = GetScriptForDestination(CScriptID(script)); hash = tx.GetId(); mempool.addUnchecked( hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vin[0].prevout.hash = hash; tx.vin[0].scriptSig = CScript() << std::vector(script.begin(), script.end()); tx.vout[0].nValue -= LOWFEE; hash = tx.GetId(); mempool.addUnchecked( hash, entry.Fee(LOWFEE).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); BOOST_CHECK_THROW( BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); // Double spend txn pair in mempool, template creation fails. tx.vin[0].prevout.hash = txFirst[0]->GetId(); tx.vin[0].scriptSig = CScript() << OP_1; tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; hash = tx.GetId(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); tx.vout[0].scriptPubKey = CScript() << OP_2; hash = tx.GetId(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); BOOST_CHECK_THROW( BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); mempool.clear(); // Subsidy changing. int nHeight = chainActive.Height(); // Create an actual 209999-long block chain (without valid blocks). while (chainActive.Tip()->nHeight < 209999) { CBlockIndex *prev = chainActive.Tip(); CBlockIndex *next = new CBlockIndex(); - next->phashBlock = new uint256(GetRandHash()); + next->phashBlock = new uint256(insecure_rand256()); pcoinsTip->SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; next->BuildSkip(); chainActive.SetTip(next); } BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); // Extend to a 210000-long block chain. while (chainActive.Tip()->nHeight < 210000) { CBlockIndex *prev = chainActive.Tip(); CBlockIndex *next = new CBlockIndex(); - next->phashBlock = new uint256(GetRandHash()); + next->phashBlock = new uint256(insecure_rand256()); pcoinsTip->SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; next->BuildSkip(); chainActive.SetTip(next); } BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); // Delete the dummy blocks again. while (chainActive.Tip()->nHeight > nHeight) { CBlockIndex *del = chainActive.Tip(); chainActive.SetTip(del->pprev); pcoinsTip->SetBestBlock(del->pprev->GetBlockHash()); delete del->phashBlock; delete del; } // non-final txs in mempool SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); int flags = LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST; // height map std::vector prevheights; // Relative height locked. tx.nVersion = 2; tx.vin.resize(1); prevheights.resize(1); // Only 1 transaction. tx.vin[0].prevout.hash = txFirst[0]->GetId(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript() << OP_1; // txFirst[0] is the 2nd block tx.vin[0].nSequence = chainActive.Tip()->nHeight + 1; prevheights[0] = baseheight + 1; tx.vout.resize(1); tx.vout[0].nValue = BLOCKSUBSIDY - HIGHFEE; tx.vout[0].scriptPubKey = CScript() << OP_1; tx.nLockTime = 0; hash = tx.GetId(); mempool.addUnchecked( hash, entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); { // Locktime passes. GlobalConfig config; CValidationState state; BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(config, tx, state, flags)); } // Sequence locks fail. BOOST_CHECK(!TestSequenceLocks(tx, flags)); // Sequence locks pass on 2nd block. BOOST_CHECK( SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 2))); // Relative time locked. tx.vin[0].prevout.hash = txFirst[1]->GetId(); // txFirst[1] is the 3rd block. tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | (((chainActive.Tip()->GetMedianTimePast() + 1 - chainActive[1]->GetMedianTimePast()) >> CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) + 1); prevheights[0] = baseheight + 2; hash = tx.GetId(); mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); { // Locktime passes. GlobalConfig config; CValidationState state; BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(config, tx, state, flags)); } // Sequence locks fail. BOOST_CHECK(!TestSequenceLocks(tx, flags)); for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { // Trick the MedianTimePast. chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; } // Sequence locks pass 512 seconds later. BOOST_CHECK( SequenceLocks(tx, flags, &prevheights, CreateBlockIndex(chainActive.Tip()->nHeight + 1))); for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { // Undo tricked MTP. chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime -= 512; } // Absolute height locked. tx.vin[0].prevout.hash = txFirst[2]->GetId(); tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; prevheights[0] = baseheight + 3; tx.nLockTime = chainActive.Tip()->nHeight + 1; hash = tx.GetId(); mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); { // Locktime fails. GlobalConfig config; CValidationState state; BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(config, tx, state, flags)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal"); } // Sequence locks pass. BOOST_CHECK(TestSequenceLocks(tx, flags)); { // Locktime passes on 2nd block. GlobalConfig config; CValidationState state; BOOST_CHECK(ContextualCheckTransaction( config, tx, state, chainActive.Tip()->nHeight + 2, chainActive.Tip()->GetMedianTimePast())); } // Absolute time locked. tx.vin[0].prevout.hash = txFirst[3]->GetId(); tx.nLockTime = chainActive.Tip()->GetMedianTimePast(); prevheights.resize(1); prevheights[0] = baseheight + 4; hash = tx.GetId(); mempool.addUnchecked(hash, entry.Time(GetTime()).FromTx(tx)); { // Locktime fails. GlobalConfig config; CValidationState state; BOOST_CHECK(!ContextualCheckTransactionForCurrentBlock(config, tx, state, flags)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-nonfinal"); } // Sequence locks pass. BOOST_CHECK(TestSequenceLocks(tx, flags)); { // Locktime passes 1 second later. GlobalConfig config; CValidationState state; BOOST_CHECK(ContextualCheckTransaction( config, tx, state, chainActive.Tip()->nHeight + 1, chainActive.Tip()->GetMedianTimePast() + 1)); } // mempool-dependent transactions (not added) tx.vin[0].prevout.hash = hash; prevheights[0] = chainActive.Tip()->nHeight + 1; tx.nLockTime = 0; tx.vin[0].nSequence = 0; { // Locktime passes. GlobalConfig config; CValidationState state; BOOST_CHECK(ContextualCheckTransactionForCurrentBlock(config, tx, state, flags)); } // Sequence locks pass. BOOST_CHECK(TestSequenceLocks(tx, flags)); tx.vin[0].nSequence = 1; // Sequence locks fail. BOOST_CHECK(!TestSequenceLocks(tx, flags)); tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; // Sequence locks pass. BOOST_CHECK(TestSequenceLocks(tx, flags)); tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; // Sequence locks fail. BOOST_CHECK(!TestSequenceLocks(tx, flags)); BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); // None of the of the absolute height/time locked tx should have made it // into the template because we still check IsFinalTx in CreateNewBlock, but // relative locked txs will if inconsistently added to mempool. For now // these will still generate a valid template until BIP68 soft fork. BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3UL); // However if we advance height by 1 and time by 512, all of them should be // mined. for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) { // Trick the MedianTimePast. chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; } chainActive.Tip()->nHeight++; SetMockTime(chainActive.Tip()->GetMedianTimePast() + 1); BOOST_CHECK( pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey)); BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL); chainActive.Tip()->nHeight--; SetMockTime(0); mempool.clear(); TestPackageSelection(chainparams, scriptPubKey, txFirst); fCheckpointsEnabled = true; } void CheckBlockMaxSize(const CChainParams &chainparams, uint64_t size, uint64_t expected) { GlobalConfig config; ForceSetArg("-blockmaxsize", std::to_string(size)); BlockAssembler ba(config, chainparams); BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), expected); } BOOST_AUTO_TEST_CASE(BlockAssembler_construction) { GlobalConfig config; const CChainParams &chainparams = Params(); // We are working on a fake chain and need to protect ourselves. LOCK(cs_main); // Activate UAHF the dirty way const int64_t uahfHeight = config.GetChainParams().GetConsensus().uahfHeight; auto pindex = chainActive.Tip(); for (size_t i = 0; pindex && i < 5; i++) { pindex->nHeight = uahfHeight + 5 - i; pindex = pindex->pprev; } // Test around historical 1MB (plus one byte because that's mandatory) config.SetMaxBlockSize(ONE_MEGABYTE + 1); CheckBlockMaxSize(chainparams, 0, 1000); CheckBlockMaxSize(chainparams, 1000, 1000); CheckBlockMaxSize(chainparams, 1001, 1001); CheckBlockMaxSize(chainparams, 12345, 12345); CheckBlockMaxSize(chainparams, ONE_MEGABYTE - 1001, ONE_MEGABYTE - 1001); CheckBlockMaxSize(chainparams, ONE_MEGABYTE - 1000, ONE_MEGABYTE - 1000); CheckBlockMaxSize(chainparams, ONE_MEGABYTE - 999, ONE_MEGABYTE - 999); CheckBlockMaxSize(chainparams, ONE_MEGABYTE, ONE_MEGABYTE - 999); // Test around higher limit such as 8MB static const auto EIGHT_MEGABYTES = 8 * ONE_MEGABYTE; config.SetMaxBlockSize(EIGHT_MEGABYTES); CheckBlockMaxSize(chainparams, EIGHT_MEGABYTES - 1001, EIGHT_MEGABYTES - 1001); CheckBlockMaxSize(chainparams, EIGHT_MEGABYTES - 1000, EIGHT_MEGABYTES - 1000); CheckBlockMaxSize(chainparams, EIGHT_MEGABYTES - 999, EIGHT_MEGABYTES - 1000); CheckBlockMaxSize(chainparams, EIGHT_MEGABYTES, EIGHT_MEGABYTES - 1000); // Test around default cap config.SetMaxBlockSize(DEFAULT_MAX_BLOCK_SIZE); CheckBlockMaxSize(chainparams, DEFAULT_MAX_BLOCK_SIZE - 1001, DEFAULT_MAX_BLOCK_SIZE - 1001); CheckBlockMaxSize(chainparams, DEFAULT_MAX_BLOCK_SIZE - 1000, DEFAULT_MAX_BLOCK_SIZE - 1000); CheckBlockMaxSize(chainparams, DEFAULT_MAX_BLOCK_SIZE - 999, DEFAULT_MAX_BLOCK_SIZE - 1000); CheckBlockMaxSize(chainparams, DEFAULT_MAX_BLOCK_SIZE, DEFAULT_MAX_BLOCK_SIZE - 1000); // If the parameter is not specified, we use // DEFAULT_MAX_GENERATED_BLOCK_SIZE { ClearArg("-blockmaxsize"); BlockAssembler ba(config, chainparams); BOOST_CHECK_EQUAL(ba.GetMaxGeneratedBlockSize(), DEFAULT_MAX_GENERATED_BLOCK_SIZE); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 9e88b0102..57cceb05b 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -1,127 +1,127 @@ // Copyright (c) 2012-2016 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 "arith_uint256.h" #include "consensus/merkle.h" #include "merkleblock.h" #include "serialize.h" #include "streams.h" #include "test/test_bitcoin.h" #include "uint256.h" #include "version.h" #include #include class CPartialMerkleTreeTester : public CPartialMerkleTree { public: // flip one bit in one of the hashes - this should break the authentication void Damage() { unsigned int n = insecure_rand() % vHash.size(); - int bit = insecure_rand() % 256; + int bit = insecure_randrange(256); *(vHash[n].begin() + (bit >> 3)) ^= 1 << (bit & 7); } }; BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(pmt_test1) { seed_insecure_rand(false); static const unsigned int nTxCounts[] = {1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095}; for (int i = 0; i < 12; i++) { unsigned int nTx = nTxCounts[i]; // build a block with some dummy transactions CBlock block; for (unsigned int j = 0; j < nTx; j++) { CMutableTransaction tx; // actual transaction data doesn't matter; just make the nLockTime's // unique tx.nLockTime = j; block.vtx.push_back(MakeTransactionRef(std::move(tx))); } // calculate actual merkle root and height uint256 merkleRoot1 = BlockMerkleRoot(block); std::vector vTxid(nTx, uint256()); for (unsigned int j = 0; j < nTx; j++) vTxid[j] = block.vtx[j]->GetId(); int nHeight = 1, nTx_ = nTx; while (nTx_ > 1) { nTx_ = (nTx_ + 1) / 2; nHeight++; } // check with random subsets with inclusion chances 1, 1/2, 1/4, ..., // 1/128 for (int att = 1; att < 15; att++) { // build random subset of txid's std::vector vMatch(nTx, false); std::vector vMatchTxid1; for (unsigned int j = 0; j < nTx; j++) { bool fInclude = (insecure_rand() & ((1 << (att / 2)) - 1)) == 0; vMatch[j] = fInclude; if (fInclude) vMatchTxid1.push_back(vTxid[j]); } // build the partial merkle tree CPartialMerkleTree pmt1(vTxid, vMatch); // serialize CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << pmt1; // verify CPartialMerkleTree's size guarantees unsigned int n = std::min(nTx, 1 + vMatchTxid1.size() * nHeight); BOOST_CHECK(ss.size() <= 10 + (258 * n + 7) / 8); // deserialize into a tester copy CPartialMerkleTreeTester pmt2; ss >> pmt2; // extract merkle root and matched txids from copy std::vector vMatchTxid2; std::vector vIndex; uint256 merkleRoot2 = pmt2.ExtractMatches(vMatchTxid2, vIndex); // check that it has the same merkle root as the original, and a // valid one BOOST_CHECK(merkleRoot1 == merkleRoot2); BOOST_CHECK(!merkleRoot2.IsNull()); // check that it contains the matched transactions (in the same // order!) BOOST_CHECK(vMatchTxid1 == vMatchTxid2); // check that random bit flips break the authentication for (int j = 0; j < 4; j++) { CPartialMerkleTreeTester pmt3(pmt2); pmt3.Damage(); std::vector vMatchTxid3; uint256 merkleRoot3 = pmt3.ExtractMatches(vMatchTxid3, vIndex); BOOST_CHECK(merkleRoot3 != merkleRoot1); } } } } BOOST_AUTO_TEST_CASE(pmt_malleability) { std::vector vTxid = { ArithToUint256(1), ArithToUint256(2), ArithToUint256(3), ArithToUint256(4), ArithToUint256(5), ArithToUint256(6), ArithToUint256(7), ArithToUint256(8), ArithToUint256(9), ArithToUint256(10), ArithToUint256(9), ArithToUint256(10)}; std::vector vMatch = {false, false, false, false, false, false, false, false, false, true, true, false}; CPartialMerkleTree tree(vTxid, vMatch); std::vector vIndex; BOOST_CHECK(tree.ExtractMatches(vTxid, vIndex).IsNull()); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index b950a70e7..7f1acb3cf 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -1,373 +1,373 @@ // Copyright (c) 2015 The Bitcoin Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "pow.h" #include "chain.h" #include "chainparams.h" #include "config.h" #include "random.h" #include "test/test_bitcoin.h" #include "util.h" #include BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) /* Test calculation of next difficulty target with no constraints applying */ BOOST_AUTO_TEST_CASE(get_next_work) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; int64_t nLastRetargetTime = 1261130161; // Block #30240 CBlockIndex pindexLast; pindexLast.nHeight = 32255; pindexLast.nTime = 1262152739; // Block #32255 pindexLast.nBits = 0x1d00ffff; BOOST_CHECK_EQUAL( CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, config), 0x1d00d86a); } /* Test the constraint on the upper bound for next work */ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; int64_t nLastRetargetTime = 1231006505; // Block #0 CBlockIndex pindexLast; pindexLast.nHeight = 2015; pindexLast.nTime = 1233061996; // Block #2015 pindexLast.nBits = 0x1d00ffff; BOOST_CHECK_EQUAL( CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, config), 0x1d00ffff); } /* Test the constraint on the lower bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; int64_t nLastRetargetTime = 1279008237; // Block #66528 CBlockIndex pindexLast; pindexLast.nHeight = 68543; pindexLast.nTime = 1279297671; // Block #68543 pindexLast.nBits = 0x1c05a3f4; BOOST_CHECK_EQUAL( CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, config), 0x1c0168fd); } /* Test the constraint on the upper bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time CBlockIndex pindexLast; pindexLast.nHeight = 46367; pindexLast.nTime = 1269211443; // Block #46367 pindexLast.nBits = 0x1c387f6f; BOOST_CHECK_EQUAL( CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, config), 0x1d00e1fd); } BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) { SelectParams(CBaseChainParams::MAIN); const Consensus::Params ¶ms = Params().GetConsensus(); std::vector blocks(10000); for (int i = 0; i < 10000; i++) { blocks[i].pprev = i ? &blocks[i - 1] : nullptr; blocks[i].nHeight = i; blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing; blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */ blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i]) : arith_uint256(0); } for (int j = 0; j < 1000; j++) { - CBlockIndex *p1 = &blocks[GetRand(10000)]; - CBlockIndex *p2 = &blocks[GetRand(10000)]; - CBlockIndex *p3 = &blocks[GetRand(10000)]; + CBlockIndex *p1 = &blocks[insecure_randrange(10000)]; + CBlockIndex *p2 = &blocks[insecure_randrange(10000)]; + CBlockIndex *p3 = &blocks[insecure_randrange(10000)]; int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, params); BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime()); } } static CBlockIndex GetBlockIndex(CBlockIndex *pindexPrev, int64_t nTimeInterval, uint32_t nBits) { CBlockIndex block; block.pprev = pindexPrev; block.nHeight = pindexPrev->nHeight + 1; block.nTime = pindexPrev->nTime + nTimeInterval; block.nBits = nBits; block.nChainWork = pindexPrev->nChainWork + GetBlockProof(block); return block; } BOOST_AUTO_TEST_CASE(retargeting_test) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; std::vector blocks(115); const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); const arith_uint256 powLimit = UintToArith256(params.powLimit); arith_uint256 currentPow = powLimit >> 1; uint32_t initialBits = currentPow.GetCompact(); // Genesis block. blocks[0] = CBlockIndex(); blocks[0].nHeight = 0; blocks[0].nTime = 1269211443; blocks[0].nBits = initialBits; blocks[0].nChainWork = GetBlockProof(blocks[0]); // Pile up some blocks. for (size_t i = 1; i < 100; i++) { blocks[i] = GetBlockIndex(&blocks[i - 1], params.nPowTargetSpacing, initialBits); } CBlockHeader blkHeaderDummy; // We start getting 2h blocks time. For the first 5 blocks, it doesn't // matter as the MTP is not affected. For the next 5 block, MTP difference // increases but stays below 12h. for (size_t i = 100; i < 110; i++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 2 * 3600, initialBits); BOOST_CHECK_EQUAL( GetNextWorkRequired(&blocks[i], &blkHeaderDummy, config), initialBits); } // Now we expect the difficulty to decrease. blocks[110] = GetBlockIndex(&blocks[109], 2 * 3600, initialBits); currentPow.SetCompact(currentPow.GetCompact()); currentPow += (currentPow >> 2); BOOST_CHECK_EQUAL( GetNextWorkRequired(&blocks[110], &blkHeaderDummy, config), currentPow.GetCompact()); // As we continue with 2h blocks, difficulty continue to decrease. blocks[111] = GetBlockIndex(&blocks[110], 2 * 3600, currentPow.GetCompact()); currentPow.SetCompact(currentPow.GetCompact()); currentPow += (currentPow >> 2); BOOST_CHECK_EQUAL( GetNextWorkRequired(&blocks[111], &blkHeaderDummy, config), currentPow.GetCompact()); // We decrease again. blocks[112] = GetBlockIndex(&blocks[111], 2 * 3600, currentPow.GetCompact()); currentPow.SetCompact(currentPow.GetCompact()); currentPow += (currentPow >> 2); BOOST_CHECK_EQUAL( GetNextWorkRequired(&blocks[112], &blkHeaderDummy, config), currentPow.GetCompact()); // We check that we do not go below the minimal difficulty. blocks[113] = GetBlockIndex(&blocks[112], 2 * 3600, currentPow.GetCompact()); currentPow.SetCompact(currentPow.GetCompact()); currentPow += (currentPow >> 2); BOOST_CHECK(powLimit.GetCompact() != currentPow.GetCompact()); BOOST_CHECK_EQUAL( GetNextWorkRequired(&blocks[113], &blkHeaderDummy, config), powLimit.GetCompact()); // Once we reached the minimal difficulty, we stick with it. blocks[114] = GetBlockIndex(&blocks[113], 2 * 3600, powLimit.GetCompact()); BOOST_CHECK(powLimit.GetCompact() != currentPow.GetCompact()); BOOST_CHECK_EQUAL( GetNextWorkRequired(&blocks[114], &blkHeaderDummy, config), powLimit.GetCompact()); } BOOST_AUTO_TEST_CASE(cash_difficulty_test) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; std::vector blocks(3000); const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); const arith_uint256 powLimit = UintToArith256(params.powLimit); uint32_t powLimitBits = powLimit.GetCompact(); arith_uint256 currentPow = powLimit >> 4; uint32_t initialBits = currentPow.GetCompact(); // Genesis block. blocks[0] = CBlockIndex(); blocks[0].nHeight = 0; blocks[0].nTime = 1269211443; blocks[0].nBits = initialBits; blocks[0].nChainWork = GetBlockProof(blocks[0]); // Block counter. size_t i; // Pile up some blocks every 10 mins to establish some history. for (i = 1; i < 2050; i++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 600, initialBits); } CBlockHeader blkHeaderDummy; uint32_t nBits = GetNextCashWorkRequired(&blocks[2049], &blkHeaderDummy, config); // Difficulty stays the same as long as we produce a block every 10 mins. for (size_t j = 0; j < 10; i++, j++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits); BOOST_CHECK_EQUAL( GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, config), nBits); } // Make sure we skip over blocks that are out of wack. To do so, we produce // a block that is far in the future, and then produce a block with the // expected timestamp. blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); BOOST_CHECK_EQUAL( GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, config), nBits); blocks[i] = GetBlockIndex(&blocks[i - 1], 2 * 600 - 6000, nBits); BOOST_CHECK_EQUAL( GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, config), nBits); // The system should continue unaffected by the block with a bogous // timestamps. for (size_t j = 0; j < 20; i++, j++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 600, nBits); BOOST_CHECK_EQUAL( GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, config), nBits); } // We start emitting blocks slightly faster. The first block has no impact. blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits); BOOST_CHECK_EQUAL( GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, config), nBits); // Now we should see difficulty increase slowly. for (size_t j = 0; j < 10; i++, j++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 550, nBits); const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, config); arith_uint256 currentTarget; currentTarget.SetCompact(nBits); arith_uint256 nextTarget; nextTarget.SetCompact(nextBits); // Make sure that difficulty increases very slowly. BOOST_CHECK(nextTarget < currentTarget); BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 10)); nBits = nextBits; } // Check the actual value. BOOST_CHECK_EQUAL(nBits, 0x1c0fe7b1); // If we dramatically shorten block production, difficulty increases faster. for (size_t j = 0; j < 20; i++, j++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 10, nBits); const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, config); arith_uint256 currentTarget; currentTarget.SetCompact(nBits); arith_uint256 nextTarget; nextTarget.SetCompact(nextBits); // Make sure that difficulty increases faster. BOOST_CHECK(nextTarget < currentTarget); BOOST_CHECK((currentTarget - nextTarget) < (currentTarget >> 4)); nBits = nextBits; } // Check the actual value. BOOST_CHECK_EQUAL(nBits, 0x1c0db19f); // We start to emit blocks significantly slower. The first block has no // impact. blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); nBits = GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, config); // Check the actual value. BOOST_CHECK_EQUAL(nBits, 0x1c0d9222); // If we dramatically slow down block production, difficulty decreases. for (size_t j = 0; j < 93; i++, j++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, config); arith_uint256 currentTarget; currentTarget.SetCompact(nBits); arith_uint256 nextTarget; nextTarget.SetCompact(nextBits); // Check the difficulty decreases. BOOST_CHECK(nextTarget <= powLimit); BOOST_CHECK(nextTarget > currentTarget); BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3)); nBits = nextBits; } // Check the actual value. BOOST_CHECK_EQUAL(nBits, 0x1c2f13b9); // Due to the window of time being bounded, next block's difficulty actually // gets harder. blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); nBits = GetNextCashWorkRequired(&blocks[i++], &blkHeaderDummy, config); BOOST_CHECK_EQUAL(nBits, 0x1c2ee9bf); // And goes down again. It takes a while due to the window being bounded and // the skewed block causes 2 blocks to get out of the window. for (size_t j = 0; j < 192; i++, j++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, config); arith_uint256 currentTarget; currentTarget.SetCompact(nBits); arith_uint256 nextTarget; nextTarget.SetCompact(nextBits); // Check the difficulty decreases. BOOST_CHECK(nextTarget <= powLimit); BOOST_CHECK(nextTarget > currentTarget); BOOST_CHECK((nextTarget - currentTarget) < (currentTarget >> 3)); nBits = nextBits; } // Check the actual value. BOOST_CHECK_EQUAL(nBits, 0x1d00ffff); // Once the difficulty reached the minimum allowed level, it doesn't get any // easier. for (size_t j = 0; j < 5; i++, j++) { blocks[i] = GetBlockIndex(&blocks[i - 1], 6000, nBits); const uint32_t nextBits = GetNextCashWorkRequired(&blocks[i], &blkHeaderDummy, config); // Check the difficulty stays constant. BOOST_CHECK_EQUAL(nextBits, powLimitBits); nBits = nextBits; } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index 4b80976ea..aac46d84c 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -1,267 +1,269 @@ // Copyright (c) 2015-2016 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 "prevector.h" #include #include "serialize.h" #include "streams.h" #include "test/test_bitcoin.h" #include #include BOOST_FIXTURE_TEST_SUITE(prevector_tests, TestingSetup) template class prevector_tester { typedef std::vector realtype; realtype real_vector; realtype real_vector_alt; typedef prevector pretype; pretype pre_vector; pretype pre_vector_alt; typedef typename pretype::size_type Size; bool passed = true; FastRandomContext rand_cache; uint256 rand_seed; template void local_check_equal(A a, B b) { local_check(a == b); } void local_check(bool b) { passed &= b; } void test() { const pretype &const_pre_vector = pre_vector; local_check_equal(real_vector.size(), pre_vector.size()); local_check_equal(real_vector.empty(), pre_vector.empty()); for (Size s = 0; s < real_vector.size(); s++) { local_check(real_vector[s] == pre_vector[s]); local_check(&(pre_vector[s]) == &(pre_vector.begin()[s])); local_check(&(pre_vector[s]) == &*(pre_vector.begin() + s)); local_check(&(pre_vector[s]) == &*((pre_vector.end() + s) - real_vector.size())); } // local_check(realtype(pre_vector) == real_vector); local_check(pretype(real_vector.begin(), real_vector.end()) == pre_vector); local_check(pretype(pre_vector.begin(), pre_vector.end()) == pre_vector); size_t pos = 0; for (const T &v : pre_vector) { local_check(v == real_vector[pos++]); } // FIXME: For some reason, the prevector iterrator doesn't conform to // what boost::adaptors::reverse expect. for (const T &v : boost::adaptors::reverse(pre_vector)) { local_check(v == real_vector[--pos]); } for (const T &v : const_pre_vector) { local_check(v == real_vector[pos++]); } for (const T &v : boost::adaptors::reverse(const_pre_vector)) { local_check(v == real_vector[--pos]); } CDataStream ss1(SER_DISK, 0); CDataStream ss2(SER_DISK, 0); ss1 << real_vector; ss2 << pre_vector; local_check_equal(ss1.size(), ss2.size()); for (Size s = 0; s < ss1.size(); s++) { local_check_equal(ss1[s], ss2[s]); } } public: void resize(Size s) { real_vector.resize(s); local_check_equal(real_vector.size(), s); pre_vector.resize(s); local_check_equal(pre_vector.size(), s); test(); } void reserve(Size s) { real_vector.reserve(s); local_check(real_vector.capacity() >= s); pre_vector.reserve(s); local_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(); } void swap() { real_vector.swap(real_vector_alt); pre_vector.swap(pre_vector_alt); test(); } void move() { real_vector = std::move(real_vector_alt); real_vector_alt.clear(); pre_vector = std::move(pre_vector_alt); pre_vector_alt.clear(); } void copy() { real_vector = real_vector_alt; pre_vector = pre_vector_alt; } ~prevector_tester() { BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString()); } prevector_tester() { seed_insecure_rand(); rand_seed = insecure_rand_seed; rand_cache = insecure_rand_ctx; } }; 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)); + 0, std::min( + 30, test.size() + (insecure_randrange(5)) - 2)); test.resize(new_size); } if (((r >> 7) % 8) == 3) { test.insert(insecure_rand() % (test.size() + 1), - 1 + (insecure_rand() % 2), insecure_rand()); + 1 + (insecure_randrange(2)), insecure_rand()); } if (((r >> 10) % 8) == 4) { - int del = std::min(test.size(), 1 + (insecure_rand() % 2)); + int del = + std::min(test.size(), 1 + (insecure_randrange(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); + int num = 1 + (insecure_randrange(4)); for (int k = 0; k < num; k++) { values[k] = 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 del = + std::min(test.size(), 1 + (insecure_randrange(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); + test.reserve(insecure_randrange(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()); + test.assign(insecure_randrange(32), insecure_rand()); } if (((r >> 15) % 8) == 3) { test.swap(); } if (((r >> 15) % 16) == 8) { test.copy(); } if (((r >> 15) % 32) == 18) { test.move(); } } } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_antireplay_tests.cpp b/src/test/script_antireplay_tests.cpp index c66ffeb13..4fcfef9ce 100644 --- a/src/test/script_antireplay_tests.cpp +++ b/src/test/script_antireplay_tests.cpp @@ -1,155 +1,155 @@ // Copyright (c) 2017 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "script/script.h" #include "test/test_bitcoin.h" #include "chainparams.h" #include "config.h" #include "consensus/validation.h" #include "validation.h" #include #include #include BOOST_FIXTURE_TEST_SUITE(script_antireplay_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(test_is_commitment) { std::vector data{}; // Empty commitment. auto s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // Commitment to a value of the wrong size. data.push_back(42); BOOST_CHECK(!s.IsCommitment(data)); // Not a commitment. s = CScript() << data; BOOST_CHECK(!s.IsCommitment(data)); // Non empty commitment. s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // Commitment to the wrong value. data[0] = 0x42; BOOST_CHECK(!s.IsCommitment(data)); // Commitment to a larger value. std::string str = "Bitcoin: A peer-to-peer Electronic Cash System"; data = std::vector(str.begin(), str.end()); BOOST_CHECK(!s.IsCommitment(data)); s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // 64 bytes commitment, still valid. data.resize(64); s = CScript() << OP_RETURN << data; BOOST_CHECK(s.IsCommitment(data)); // Commitment is too large. data.push_back(23); s = CScript() << OP_RETURN << data; BOOST_CHECK(!s.IsCommitment(data)); // Check with the actual replay commitment we are going to use. SelectParams(CBaseChainParams::MAIN); const Consensus::Params ¶ms = Params().GetConsensus(); s = CScript() << OP_RETURN << params.antiReplayOpReturnCommitment; BOOST_CHECK(s.IsCommitment(params.antiReplayOpReturnCommitment)); } BOOST_AUTO_TEST_CASE(test_antireplay) { SelectParams(CBaseChainParams::MAIN); GlobalConfig config; const Consensus::Params ¶ms = config.GetChainParams().GetConsensus(); // The anti replay rule start at uahfHeight and stops at // antiReplayOpReturnSunsetHeight. const int nUAHFHeight = params.uahfHeight; const int nSunsetHeight = params.antiReplayOpReturnSunsetHeight; const int64_t nUAHFStartTime = 123456; CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(1); - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript(); tx.vout.resize(1); tx.vout[0].nValue = Amount(1); tx.vout[0].scriptPubKey = CScript(); { // Base transaction is valid. CValidationState state; BOOST_CHECK(ContextualCheckTransaction(config, tx, state, nSunsetHeight, nUAHFStartTime)); } { // Base transaction is still valid after sunset. CValidationState state; BOOST_CHECK(ContextualCheckTransaction( config, tx, state, nSunsetHeight + 1, nUAHFStartTime)); } { // Base transaction is valid before the fork. CValidationState state; BOOST_CHECK(ContextualCheckTransaction( config, tx, state, nUAHFHeight - 1, nUAHFStartTime - 1)); } tx.vout[0].scriptPubKey = CScript() << OP_RETURN << OP_0; { // Wrong commitment, still valid. CValidationState state; BOOST_CHECK(ContextualCheckTransaction(config, tx, state, nSunsetHeight, nUAHFStartTime)); } tx.vout[0].scriptPubKey = CScript() << OP_RETURN << params.antiReplayOpReturnCommitment; { // Anti replay commitment, not valid anymore. CValidationState state; BOOST_CHECK(!ContextualCheckTransaction(config, tx, state, nUAHFHeight, nUAHFStartTime)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txn-replay"); } { // Anti replay commitment, not valid anymore. CValidationState state; BOOST_CHECK(!ContextualCheckTransaction(config, tx, state, nSunsetHeight, nUAHFStartTime)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txn-replay"); } { // Anti replay commitment, disabled before start time. CValidationState state; BOOST_CHECK(ContextualCheckTransaction( config, tx, state, nUAHFHeight - 1, nUAHFStartTime)); } { // Anti replay commitment, disabled after sunset. CValidationState state; BOOST_CHECK(ContextualCheckTransaction( config, tx, state, nSunsetHeight + 1, nUAHFStartTime)); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index f99f55908..f764cf4db 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -1,219 +1,219 @@ // Copyright (c) 2013-2016 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 "consensus/validation.h" #include "data/sighash.json.h" #include "hash.h" #include "script/interpreter.h" #include "script/script.h" #include "serialize.h" #include "streams.h" #include "test/test_bitcoin.h" #include "util.h" #include "utilstrencodings.h" #include "validation.h" // For CheckRegularTransaction #include "version.h" #include #include #include extern UniValue read_json(const std::string &jsondata); // Old script.cpp SignatureHash function static uint256 SignatureHashOld(CScript scriptCode, const CTransaction &txTo, unsigned int nIn, int nHashType) { static const uint256 one(uint256S( "0000000000000000000000000000000000000000000000000000000000000001")); if (nIn >= txTo.vin.size()) { printf("ERROR: SignatureHash(): nIn=%d out of range\n", nIn); return one; } CMutableTransaction txTmp(txTo); // In case concatenating two scripts ends up with two codeseparators, or an // extra one at the end, this prevents all those possible incompatibilities. scriptCode.FindAndDelete(CScript(OP_CODESEPARATOR)); // Blank out other inputs' signatures for (unsigned int i = 0; i < txTmp.vin.size(); i++) txTmp.vin[i].scriptSig = CScript(); txTmp.vin[nIn].scriptSig = scriptCode; // Blank out some of the outputs if ((nHashType & 0x1f) == SIGHASH_NONE) { // Wildcard payee txTmp.vout.clear(); // Let the others update at will for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } else if ((nHashType & 0x1f) == SIGHASH_SINGLE) { // Only lock-in the txout payee at same index as txin unsigned int nOut = nIn; if (nOut >= txTmp.vout.size()) { printf("ERROR: SignatureHash(): nOut=%d out of range\n", nOut); return one; } txTmp.vout.resize(nOut + 1); for (unsigned int i = 0; i < nOut; i++) txTmp.vout[i].SetNull(); // Let the others update at will for (unsigned int i = 0; i < txTmp.vin.size(); i++) if (i != nIn) txTmp.vin[i].nSequence = 0; } // Blank out other inputs completely, not recommended for open transactions if (nHashType & SIGHASH_ANYONECANPAY) { txTmp.vin[0] = txTmp.vin[nIn]; txTmp.vin.resize(1); } // Serialize and hash CHashWriter ss(SER_GETHASH, 0); ss << txTmp << nHashType; return ss.GetHash(); } static void RandomScript(CScript &script) { static const opcodetype oplist[] = { OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; script = CScript(); - int ops = (insecure_rand() % 10); + int ops = (insecure_randrange(10)); for (int i = 0; i < ops; i++) script << oplist[insecure_rand() % (sizeof(oplist) / sizeof(oplist[0]))]; } static void RandomTransaction(CMutableTransaction &tx, bool fSingle) { tx.nVersion = insecure_rand(); tx.vin.clear(); tx.vout.clear(); - tx.nLockTime = (insecure_rand() % 2) ? insecure_rand() : 0; - int ins = (insecure_rand() % 4) + 1; - int outs = fSingle ? ins : (insecure_rand() % 4) + 1; + tx.nLockTime = (insecure_randrange(2)) ? insecure_rand() : 0; + int ins = (insecure_randrange(4)) + 1; + int outs = fSingle ? ins : (insecure_randrange(4)) + 1; for (int in = 0; in < ins; in++) { tx.vin.push_back(CTxIn()); CTxIn &txin = tx.vin.back(); - txin.prevout.hash = GetRandHash(); - txin.prevout.n = insecure_rand() % 4; + txin.prevout.hash = insecure_rand256(); + txin.prevout.n = insecure_randrange(4); RandomScript(txin.scriptSig); txin.nSequence = - (insecure_rand() % 2) ? insecure_rand() : (unsigned int)-1; + (insecure_randrange(2)) ? insecure_rand() : (unsigned int)-1; } for (int out = 0; out < outs; out++) { tx.vout.push_back(CTxOut()); CTxOut &txout = tx.vout.back(); txout.nValue = Amount(int64_t(insecure_rand()) % 100000000); RandomScript(txout.scriptPubKey); } } BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sighash_test) { seed_insecure_rand(false); #if defined(PRINT_SIGHASH_JSON) std::cout << "[\n"; std::cout << "\t[\"raw_transaction, script, input_index, hashType, " "signature_hash (result)\"],\n"; #endif int nRandomTests = 50000; #if defined(PRINT_SIGHASH_JSON) nRandomTests = 500; #endif for (int i = 0; i < nRandomTests; i++) { int nHashType = insecure_rand(); // Clear forkid nHashType &= ~SIGHASH_FORKID; CMutableTransaction txTo; RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); CScript scriptCode; RandomScript(scriptCode); int nIn = insecure_rand() % txTo.vin.size(); uint256 sh, sho; sho = SignatureHashOld(scriptCode, txTo, nIn, nHashType); sh = SignatureHash(scriptCode, txTo, nIn, nHashType, Amount(0)); #if defined(PRINT_SIGHASH_JSON) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << txTo; std::cout << "\t[\""; std::cout << HexStr(ss.begin(), ss.end()) << "\", \""; std::cout << HexStr(scriptCode) << "\", "; std::cout << nIn << ", "; std::cout << nHashType << ", \""; std::cout << sh.GetHex() << "\"]"; if (i + 1 != nRandomTests) { std::cout << ","; } std::cout << "\n"; #endif BOOST_CHECK(sh == sho); } #if defined(PRINT_SIGHASH_JSON) std::cout << "]\n"; #endif } // Goal: check that SignatureHash generates correct hash BOOST_AUTO_TEST_CASE(sighash_from_data) { UniValue tests = read_json( std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash))); for (unsigned int idx = 0; idx < tests.size(); idx++) { UniValue test = tests[idx]; std::string strTest = test.write(); // Allow for extra stuff (useful for comments) if (test.size() < 1) { BOOST_ERROR("Bad test: " << strTest); continue; } if (test.size() == 1) continue; // comment std::string raw_tx, raw_script, sigHashHex; int nIn, nHashType; uint256 sh; CTransactionRef tx; CScript scriptCode = CScript(); try { // deserialize test data raw_tx = test[0].get_str(); raw_script = test[1].get_str(); nIn = test[2].get_int(); nHashType = test[3].get_int(); sigHashHex = test[4].get_str(); CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION); stream >> tx; CValidationState state; BOOST_CHECK_MESSAGE(CheckRegularTransaction(*tx, state), strTest); BOOST_CHECK(state.IsValid()); std::vector raw = ParseHex(raw_script); scriptCode.insert(scriptCode.end(), raw.begin(), raw.end()); } catch (...) { BOOST_ERROR("Bad test, couldn't deserialize data: " << strTest); continue; } sh = SignatureHash(scriptCode, *tx, nIn, nHashType, Amount(0)); BOOST_CHECK_MESSAGE(sh.GetHex() == sigHashHex, strTest); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp index 5e11aca0a..e310e283b 100644 --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -1,224 +1,224 @@ // Copyright (c) 2012-2016 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 "consensus/consensus.h" #include "consensus/validation.h" #include "key.h" #include "pubkey.h" #include "script/script.h" #include "script/standard.h" #include "test/test_bitcoin.h" #include "uint256.h" #include "validation.h" #include #include #include // Helpers: static std::vector Serialize(const CScript &s) { std::vector sSerialized(s.begin(), s.end()); return sSerialized; } BOOST_FIXTURE_TEST_SUITE(sigopcount_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(GetSigOpCount) { // Test CScript::GetSigOpCount() CScript s1; BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 0U); BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 0U); uint160 dummy; s1 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << OP_2 << OP_CHECKMULTISIG; BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 2U); s1 << OP_IF << OP_CHECKSIG << OP_ENDIF; BOOST_CHECK_EQUAL(s1.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s1.GetSigOpCount(false), 21U); CScript p2sh = GetScriptForDestination(CScriptID(s1)); CScript scriptSig; scriptSig << OP_0 << Serialize(s1); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig), 3U); std::vector keys; for (int i = 0; i < 3; i++) { CKey k; k.MakeNewKey(true); keys.push_back(k.GetPubKey()); } CScript s2 = GetScriptForMultisig(1, keys); BOOST_CHECK_EQUAL(s2.GetSigOpCount(true), 3U); BOOST_CHECK_EQUAL(s2.GetSigOpCount(false), 20U); p2sh = GetScriptForDestination(CScriptID(s2)); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(true), 0U); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(false), 0U); CScript scriptSig2; scriptSig2 << OP_1 << ToByteVector(dummy) << ToByteVector(dummy) << Serialize(s2); BOOST_CHECK_EQUAL(p2sh.GetSigOpCount(scriptSig2), 3U); } /** * Verifies script execution of the zeroth scriptPubKey of tx output and zeroth * scriptSig and witness of tx input. */ ScriptError VerifyWithFlag(const CTransaction &output, const CMutableTransaction &input, int flags) { ScriptError error; CTransaction inputi(input); bool ret = VerifyScript( inputi.vin[0].scriptSig, output.vout[0].scriptPubKey, flags, TransactionSignatureChecker(&inputi, 0, output.vout[0].nValue), &error); BOOST_CHECK((ret == true) == (error == SCRIPT_ERR_OK)); return error; } /** * Builds a creationTx from scriptPubKey and a spendingTx from scriptSig and * witness such that spendingTx spends output zero of creationTx. Also inserts * creationTx's output into the coins view. */ void BuildTxs(CMutableTransaction &spendingTx, CCoinsViewCache &coins, CMutableTransaction &creationTx, const CScript &scriptPubKey, const CScript &scriptSig) { creationTx.nVersion = 1; creationTx.vin.resize(1); creationTx.vin[0].prevout.SetNull(); creationTx.vin[0].scriptSig = CScript(); creationTx.vout.resize(1); creationTx.vout[0].nValue = Amount(1); creationTx.vout[0].scriptPubKey = scriptPubKey; spendingTx.nVersion = 1; spendingTx.vin.resize(1); spendingTx.vin[0].prevout.hash = creationTx.GetId(); spendingTx.vin[0].prevout.n = 0; spendingTx.vin[0].scriptSig = scriptSig; spendingTx.vout.resize(1); spendingTx.vout[0].nValue = Amount(1); spendingTx.vout[0].scriptPubKey = CScript(); AddCoins(coins, creationTx, 0); } BOOST_AUTO_TEST_CASE(GetTxSigOpCost) { // Transaction creates outputs CMutableTransaction creationTx; // Transaction that spends outputs and whose sig op cost is going to be // tested CMutableTransaction spendingTx; // Create utxo set CCoinsView coinsDummy; CCoinsViewCache coins(&coinsDummy); // Create key CKey key; key.MakeNewKey(true); CPubKey pubkey = key.GetPubKey(); // Default flags int flags = SCRIPT_VERIFY_P2SH; // Multisig script (legacy counting) { CScript scriptPubKey = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; // Do not use a valid signature to avoid using wallet operations. CScript scriptSig = CScript() << OP_0 << OP_0; BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig); // Legacy counting only includes signature operations in scriptSigs and // scriptPubKeys of a transaction and does not take the actual executed // sig operations into account. spendingTx in itself does not contain a // signature operation. assert(GetTransactionSigOpCount(CTransaction(spendingTx), coins, flags) == 0); // creationTx contains two signature operations in its scriptPubKey, but // legacy counting is not accurate. assert(GetTransactionSigOpCount(CTransaction(creationTx), coins, flags) == MAX_PUBKEYS_PER_MULTISIG); // Sanity check: script verification fails because of an invalid // signature. assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY); } // Multisig nested in P2SH { CScript redeemScript = CScript() << 1 << ToByteVector(pubkey) << ToByteVector(pubkey) << 2 << OP_CHECKMULTISIGVERIFY; CScript scriptPubKey = GetScriptForDestination(CScriptID(redeemScript)); CScript scriptSig = CScript() << OP_0 << OP_0 << ToByteVector(redeemScript); BuildTxs(spendingTx, coins, creationTx, scriptPubKey, scriptSig); assert(GetTransactionSigOpCount(CTransaction(spendingTx), coins, flags) == 2); assert(VerifyWithFlag(creationTx, spendingTx, flags) == SCRIPT_ERR_CHECKMULTISIGVERIFY); } } BOOST_AUTO_TEST_CASE(test_consensus_sigops_limit) { BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(1), MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(123456), MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(1000000), MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(1000001), 2 * MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(1348592), 2 * MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(2000000), 2 * MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(2000001), 3 * MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL(GetMaxBlockSigOpsCount(2654321), 3 * MAX_BLOCK_SIGOPS_PER_MB); BOOST_CHECK_EQUAL( GetMaxBlockSigOpsCount(std::numeric_limits::max()), 4295 * MAX_BLOCK_SIGOPS_PER_MB); } BOOST_AUTO_TEST_CASE(test_max_sigops_per_tx) { CMutableTransaction tx; tx.nVersion = 1; tx.vin.resize(1); - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); tx.vin[0].prevout.n = 0; tx.vin[0].scriptSig = CScript(); tx.vout.resize(1); tx.vout[0].nValue = Amount(1); tx.vout[0].scriptPubKey = CScript(); { CValidationState state; BOOST_CHECK(CheckRegularTransaction(tx, state, false)); } // Get just before the limit. for (size_t i = 0; i < MAX_TX_SIGOPS_COUNT; i++) { tx.vout[0].scriptPubKey << OP_CHECKSIG; } { CValidationState state; BOOST_CHECK(CheckRegularTransaction(tx, state, false)); } // And go over. tx.vout[0].scriptPubKey << OP_CHECKSIG; { CValidationState state; BOOST_CHECK(!CheckRegularTransaction(tx, state, false)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txn-sigops"); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index f92631b58..a9804b33c 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -1,163 +1,163 @@ // Copyright (c) 2014-2016 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 "chain.h" #include "test/test_bitcoin.h" #include "util.h" #include #include #define SKIPLIST_LENGTH 300000 BOOST_FIXTURE_TEST_SUITE(skiplist_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(skiplist_test) { std::vector vIndex(SKIPLIST_LENGTH); for (int i = 0; i < SKIPLIST_LENGTH; i++) { vIndex[i].nHeight = i; vIndex[i].pprev = (i == 0) ? nullptr : &vIndex[i - 1]; vIndex[i].BuildSkip(); } for (int i = 0; i < SKIPLIST_LENGTH; i++) { if (i > 0) { BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]); BOOST_CHECK(vIndex[i].pskip->nHeight < i); } else { BOOST_CHECK(vIndex[i].pskip == nullptr); } } for (int i = 0; i < 1000; i++) { int from = insecure_rand() % (SKIPLIST_LENGTH - 1); int to = insecure_rand() % (from + 1); BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]); BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]); BOOST_CHECK(vIndex[from].GetAncestor(0) == &vIndex[0]); } } BOOST_AUTO_TEST_CASE(getlocator_test) { // Build a main chain 100000 blocks long. std::vector vHashMain(100000); std::vector vBlocksMain(100000); for (unsigned int i = 0; i < vBlocksMain.size(); i++) { // Set the hash equal to the height, so we can quickly check the // distances. vHashMain[i] = ArithToUint256(i); vBlocksMain[i].nHeight = i; vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr; vBlocksMain[i].phashBlock = &vHashMain[i]; vBlocksMain[i].BuildSkip(); BOOST_CHECK_EQUAL( (int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64(), vBlocksMain[i].nHeight); BOOST_CHECK(vBlocksMain[i].pprev == nullptr || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1); } // Build a branch that splits off at block 49999, 50000 blocks long. std::vector vHashSide(50000); std::vector vBlocksSide(50000); for (unsigned int i = 0; i < vBlocksSide.size(); i++) { // Add 1<<128 to the hashes, so GetLow64() still returns the height. vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); vBlocksSide[i].nHeight = i + 50000; vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : &vBlocksMain[49999]; vBlocksSide[i].phashBlock = &vHashSide[i]; vBlocksSide[i].BuildSkip(); BOOST_CHECK_EQUAL( (int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight); BOOST_CHECK(vBlocksSide[i].pprev == nullptr || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1); } // Build a CChain for the main branch. CChain chain; chain.SetTip(&vBlocksMain.back()); // Test 100 random starting points for locators. for (int n = 0; n < 100; n++) { - int r = insecure_rand() % 150000; + int r = insecure_randrange(150000); CBlockIndex *tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000]; CBlockLocator locator = chain.GetLocator(tip); // The first result must be the block itself, the last one must be // genesis. BOOST_CHECK(locator.vHave.front() == tip->GetBlockHash()); BOOST_CHECK(locator.vHave.back() == vBlocksMain[0].GetBlockHash()); // Entries 1 through 11 (inclusive) go back one step each. for (unsigned int i = 1; i < 12 && i < locator.vHave.size() - 1; i++) { BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i]).GetLow64(), tip->nHeight - i); } // The further ones (excluding the last one) go back with exponential // steps. unsigned int dist = 2; for (unsigned int i = 12; i < locator.vHave.size() - 1; i++) { BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i - 1]).GetLow64() - UintToArith256(locator.vHave[i]).GetLow64(), dist); dist *= 2; } } } BOOST_AUTO_TEST_CASE(findearliestatleast_test) { std::vector vHashMain(100000); std::vector vBlocksMain(100000); for (unsigned int i = 0; i < vBlocksMain.size(); i++) { // Set the hash equal to the height vHashMain[i] = ArithToUint256(i); vBlocksMain[i].nHeight = i; vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr; vBlocksMain[i].phashBlock = &vHashMain[i]; vBlocksMain[i].BuildSkip(); if (i < 10) { vBlocksMain[i].nTime = i; vBlocksMain[i].nTimeMax = i; } else { // randomly choose something in the range [MTP, MTP*2] int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast(); int r = insecure_rand() % medianTimePast; vBlocksMain[i].nTime = r + medianTimePast; vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i - 1].nTimeMax); } } // Check that we set nTimeMax up correctly. unsigned int curTimeMax = 0; for (unsigned int i = 0; i < vBlocksMain.size(); ++i) { curTimeMax = std::max(curTimeMax, vBlocksMain[i].nTime); BOOST_CHECK(curTimeMax == vBlocksMain[i].nTimeMax); } // Build a CChain for the main branch. CChain chain; chain.SetTip(&vBlocksMain.back()); // Verify that FindEarliestAtLeast is correct. for (unsigned int i = 0; i < 10000; ++i) { // Pick a random element in vBlocksMain. int r = insecure_rand() % vBlocksMain.size(); int64_t test_time = vBlocksMain[r].nTime; CBlockIndex *ret = chain.FindEarliestAtLeast(test_time); BOOST_CHECK(ret->nTimeMax >= test_time); BOOST_CHECK((ret->pprev == nullptr) || ret->pprev->nTimeMax < test_time); BOOST_CHECK(vBlocksMain[r].GetAncestor(ret->nHeight) == ret); } } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 88cf00cd9..c01add2a1 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -1,262 +1,262 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #define BOOST_TEST_MODULE Bitcoin Test Suite #include "test_bitcoin.h" #include "chainparams.h" #include "config.h" #include "consensus/consensus.h" #include "consensus/validation.h" #include "key.h" #include "miner.h" #include "net_processing.h" #include "pubkey.h" #include "random.h" #include "rpc/register.h" #include "rpc/server.h" #include "script/scriptcache.h" #include "script/sigcache.h" #include "txdb.h" #include "txmempool.h" #include "ui_interface.h" #include "validation.h" #include "test/testutil.h" #include #include #include #include #include #include #include #include #include #include #include std::unique_ptr g_connman; uint256 insecure_rand_seed = GetRandHash(); FastRandomContext insecure_rand_ctx(insecure_rand_seed); extern bool fPrintToConsole; extern void noui_connect(); BasicTestingSetup::BasicTestingSetup(const std::string &chainName) { RandomInit(); ECC_Start(); SetupEnvironment(); SetupNetworking(); InitSignatureCache(); InitScriptExecutionCache(); // Don't want to write to debug.log file. fPrintToDebugLog = false; fCheckBlockIndex = true; SelectParams(chainName); noui_connect(); // Set config parameters to default. GlobalConfig config; config.SetMaxBlockSize(DEFAULT_MAX_BLOCK_SIZE); } BasicTestingSetup::~BasicTestingSetup() { ECC_Stop(); g_connman.reset(); } TestingSetup::TestingSetup(const std::string &chainName) : BasicTestingSetup(chainName) { // Ideally we'd move all the RPC tests to the functional testing framework // instead of unit tests, but for now we need these here. const Config &config = GetConfig(); RegisterAllRPCCommands(tableRPC); ClearDatadirCache(); pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), - (int)(GetRand(100000))); + (int)(insecure_randrange(100000))); boost::filesystem::create_directories(pathTemp); ForceSetArg("-datadir", pathTemp.string()); mempool.setSanityCheck(1.0); pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); pcoinsTip = new CCoinsViewCache(pcoinsdbview); InitBlockIndex(config); { CValidationState state; bool ok = ActivateBestChain(config, state); BOOST_CHECK(ok); } nScriptCheckThreads = 3; for (int i = 0; i < nScriptCheckThreads - 1; i++) { threadGroup.create_thread(&ThreadScriptCheck); } // Deterministic randomness for tests. g_connman = std::unique_ptr(new CConnman(config, 0x1337, 0x1337)); connman = g_connman.get(); RegisterNodeSignals(GetNodeSignals()); } TestingSetup::~TestingSetup() { UnregisterNodeSignals(GetNodeSignals()); threadGroup.interrupt_all(); threadGroup.join_all(); UnloadBlockIndex(); delete pcoinsTip; delete pcoinsdbview; delete pblocktree; boost::filesystem::remove_all(pathTemp); } TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) { // Generate a 100-block chain: coinbaseKey.MakeNewKey(true); CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; for (int i = 0; i < COINBASE_MATURITY; i++) { std::vector noTxns; CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); coinbaseTxns.push_back(*b.vtx[0]); } } // // Create a new block with just given transactions, coinbase paying to // scriptPubKey, and try to add it to the current chain. // CBlock TestChain100Setup::CreateAndProcessBlock( const std::vector &txns, const CScript &scriptPubKey) { const CChainParams &chainparams = Params(); const Config &config = GetConfig(); std::unique_ptr pblocktemplate = BlockAssembler(config, chainparams).CreateNewBlock(scriptPubKey); CBlock &block = pblocktemplate->block; // Replace mempool-selected txns with just coinbase plus passed-in txns: block.vtx.resize(1); for (const CMutableTransaction &tx : txns) { block.vtx.push_back(MakeTransactionRef(tx)); } // IncrementExtraNonce creates a valid coinbase and merkleRoot unsigned int extraNonce = 0; IncrementExtraNonce(config, &block, chainActive.Tip(), extraNonce); while (!CheckProofOfWork(block.GetHash(), block.nBits, config)) { ++block.nNonce; } std::shared_ptr shared_pblock = std::make_shared(block); ProcessNewBlock(GetConfig(), shared_pblock, true, nullptr); CBlock result = block; return result; } TestChain100Setup::~TestChain100Setup() {} CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool) { CTransaction txn(tx); return FromTx(txn, pool); } CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool) { // Hack to assume either it's completely dependent on other mempool txs or // not at all. Amount inChainValue = pool && pool->HasNoInputsOf(txn) ? txn.GetValueOut() : Amount(0); return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight, inChainValue, spendsCoinbase, sigOpCost, lp); } void Shutdown(void *parg) { exit(0); } void StartShutdown() { exit(0); } bool ShutdownRequested() { return false; } namespace { // A place to put misc. setup code eg "the travis workaround" that needs to run // at program startup and exit struct Init { Init(); ~Init(); std::list> cleanup; }; Init init; Init::Init() { if (getenv("TRAVIS_NOHANG_WORKAROUND")) { // This is a workaround for MinGW/Win32 builds on Travis sometimes // hanging due to no output received by Travis after a 10-minute // timeout. // The strategy here is to let the jobs finish however long they take // on Travis, by feeding Travis output. We start a parallel thread // that just prints out '.' once per second. struct Private { Private() : stop(false) {} std::atomic_bool stop; std::thread thr; std::condition_variable cond; std::mutex mut; } *p = new Private; p->thr = std::thread([p] { // thread func.. print dots std::unique_lock lock(p->mut); unsigned ctr = 0; while (!p->stop) { if (ctr) { // skip first period to allow app to print first std::cerr << "." << std::flush; } if (!(++ctr % 79)) { // newline once in a while to keep travis happy std::cerr << std::endl; } p->cond.wait_for(lock, std::chrono::milliseconds(1000)); } }); cleanup.emplace_back([p]() { // cleanup function to kill the thread and delete the struct p->mut.lock(); p->stop = true; p->cond.notify_all(); p->mut.unlock(); if (p->thr.joinable()) { p->thr.join(); } delete p; }); } } Init::~Init() { for (auto &f : cleanup) { if (f) { f(); } } } } // end anonymous namespace diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 9a47a610c..bd0d00e1d 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -1,144 +1,145 @@ // Copyright (c) 2015-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_TEST_TEST_BITCOIN_H #define BITCOIN_TEST_TEST_BITCOIN_H #include "chainparamsbase.h" #include "key.h" #include "pubkey.h" #include "random.h" #include "txdb.h" #include "txmempool.h" #include #include extern uint256 insecure_rand_seed; extern FastRandomContext insecure_rand_ctx; static inline void seed_insecure_rand(bool fDeterministic = false) { if (fDeterministic) { insecure_rand_seed = uint256(); } else { insecure_rand_seed = GetRandHash(); } insecure_rand_ctx = FastRandomContext(insecure_rand_seed); } static inline uint32_t insecure_rand() { return insecure_rand_ctx.rand32(); } static inline uint256 insecure_rand256() { return insecure_rand_ctx.rand256(); } static inline uint64_t insecure_randbits(int bits) { return insecure_rand_ctx.randbits(bits); } static inline uint64_t insecure_randrange(uint64_t range) { return insecure_rand_ctx.randrange(range); } static inline bool insecure_randbool() { return insecure_rand_ctx.randbool(); } static inline std::vector insecure_randbytes(size_t len) { return insecure_rand_ctx.randbytes(len); } -/** Basic testing setup. +/** + * Basic testing setup. * This just configures logging and chain parameters. */ struct BasicTestingSetup { ECCVerifyHandle globalVerifyHandle; BasicTestingSetup(const std::string &chainName = CBaseChainParams::MAIN); ~BasicTestingSetup(); }; /** Testing setup that configures a complete environment. * Included are data directory, coins database, script check threads setup. */ class CConnman; struct TestingSetup : public BasicTestingSetup { CCoinsViewDB *pcoinsdbview; boost::filesystem::path pathTemp; boost::thread_group threadGroup; CConnman *connman; TestingSetup(const std::string &chainName = CBaseChainParams::MAIN); ~TestingSetup(); }; class CBlock; class CMutableTransaction; class CScript; // // Testing fixture that pre-creates a // 100-block REGTEST-mode block chain // struct TestChain100Setup : public TestingSetup { TestChain100Setup(); // Create a new block with just given transactions, coinbase paying to // scriptPubKey, and try to add it to the current chain. CBlock CreateAndProcessBlock(const std::vector &txns, const CScript &scriptPubKey); ~TestChain100Setup(); // For convenience, coinbase transactions. std::vector coinbaseTxns; // private/public key needed to spend coinbase transactions. CKey coinbaseKey; }; class CTxMemPoolEntry; class CTxMemPool; struct TestMemPoolEntryHelper { // Default values Amount nFee; int64_t nTime; double dPriority; unsigned int nHeight; bool spendsCoinbase; unsigned int sigOpCost; LockPoints lp; TestMemPoolEntryHelper() : nFee(0), nTime(0), dPriority(0.0), nHeight(1), spendsCoinbase(false), sigOpCost(4) {} CTxMemPoolEntry FromTx(const CMutableTransaction &tx, CTxMemPool *pool = nullptr); CTxMemPoolEntry FromTx(const CTransaction &tx, CTxMemPool *pool = nullptr); // Change the default value TestMemPoolEntryHelper &Fee(Amount _fee) { nFee = _fee; return *this; } TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; } TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; } TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; } TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; } TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; } }; #endif diff --git a/src/test/undo_tests.cpp b/src/test/undo_tests.cpp index 79f8bdd9a..1f66db59e 100644 --- a/src/test/undo_tests.cpp +++ b/src/test/undo_tests.cpp @@ -1,100 +1,100 @@ // Copyright (c) 2017 Amaury SÉCHET // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "undo.h" #include "chainparams.h" #include "consensus/validation.h" #include "validation.h" #include "test/test_bitcoin.h" #include BOOST_FIXTURE_TEST_SUITE(undo_tests, BasicTestingSetup) static void UpdateUTXOSet(const CBlock &block, CCoinsViewCache &view, CBlockUndo &blockundo, const CChainParams &chainparams, uint32_t nHeight) { CValidationState state; auto &coinbaseTx = *block.vtx[0]; UpdateCoins(coinbaseTx, view, nHeight); for (size_t i = 1; i < block.vtx.size(); i++) { auto &tx = *block.vtx[1]; blockundo.vtxundo.push_back(CTxUndo()); UpdateCoins(tx, view, blockundo.vtxundo.back(), nHeight); } view.SetBestBlock(block.GetHash()); } static void UndoBlock(const CBlock &block, CCoinsViewCache &view, const CBlockUndo &blockUndo, const CChainParams &chainparams, uint32_t nHeight) { CBlockIndex pindex; pindex.nHeight = nHeight; ApplyBlockUndo(blockUndo, block, &pindex, view); } static bool HasSpendableCoin(const CCoinsViewCache &view, const uint256 &txid) { return !view.AccessCoin(COutPoint(txid, 0)).IsSpent(); } BOOST_AUTO_TEST_CASE(connect_utxo_extblock) { SelectParams(CBaseChainParams::MAIN); const CChainParams &chainparams = Params(); CBlock block; CMutableTransaction tx; CCoinsView coinsDummy; CCoinsViewCache view(&coinsDummy); - block.hashPrevBlock = GetRandHash(); + block.hashPrevBlock = insecure_rand256(); view.SetBestBlock(block.hashPrevBlock); // Create a block with coinbase and resolution transaction. tx.vin.resize(1); tx.vin[0].scriptSig.resize(10); tx.vout.resize(1); tx.vout[0].nValue = Amount(42); auto coinbaseTx = CTransaction(tx); block.vtx.resize(2); block.vtx[0] = MakeTransactionRef(tx); tx.vout[0].scriptPubKey = CScript() << OP_TRUE; - tx.vin[0].prevout.hash = GetRandHash(); + tx.vin[0].prevout.hash = insecure_rand256(); tx.vin[0].prevout.n = 0; tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL; tx.vin[0].scriptSig.resize(0); tx.nVersion = 2; auto prevTx0 = CTransaction(tx); AddCoins(view, prevTx0, 100); tx.vin[0].prevout.hash = prevTx0.GetId(); auto tx0 = CTransaction(tx); block.vtx[1] = MakeTransactionRef(tx0); // Now update the UTXO set. CBlockUndo blockundo; UpdateUTXOSet(block, view, blockundo, chainparams, 123456); BOOST_CHECK(view.GetBestBlock() == block.GetHash()); BOOST_CHECK(HasSpendableCoin(view, coinbaseTx.GetId())); BOOST_CHECK(HasSpendableCoin(view, tx0.GetId())); BOOST_CHECK(!HasSpendableCoin(view, prevTx0.GetId())); UndoBlock(block, view, blockundo, chainparams, 123456); BOOST_CHECK(view.GetBestBlock() == block.hashPrevBlock); BOOST_CHECK(!HasSpendableCoin(view, coinbaseTx.GetId())); BOOST_CHECK(!HasSpendableCoin(view, tx0.GetId())); BOOST_CHECK(HasSpendableCoin(view, prevTx0.GetId())); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/validation_tests.cpp b/src/test/validation_tests.cpp index 4d0af9384..e181e4de5 100644 --- a/src/test/validation_tests.cpp +++ b/src/test/validation_tests.cpp @@ -1,79 +1,79 @@ // Copyright (c) 2011-2016 The Bitcoin Core developers // Copyright (c) 2017 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "validation.h" #include "chainparams.h" #include "config.h" #include "consensus/consensus.h" #include "primitives/transaction.h" #include "test/test_bitcoin.h" #include "util.h" #include #include #include #include static CBlock makeLargeDummyBlock(const size_t num_tx) { CBlock block; block.vtx.reserve(num_tx); CTransaction tx; for (size_t i = 0; i < num_tx; i++) { block.vtx.push_back(MakeTransactionRef(tx)); } return block; } BOOST_FIXTURE_TEST_SUITE(validation_tests, TestingSetup) /** Test that LoadExternalBlockFile works with the buffer size set below the size of a large block. Currently, LoadExternalBlockFile has the buffer size for CBufferedFile set to 2 * MAX_TX_SIZE. Test with a value of 10 * MAX_TX_SIZE. */ BOOST_AUTO_TEST_CASE(validation_load_external_block_file) { boost::filesystem::path tmpfile_name = pathTemp / strprintf("vlebf_test_%lu_%i", (unsigned long)GetTime(), - (int)(GetRand(100000))); + (int)(insecure_randrange(100000))); FILE *fp = fopen(tmpfile_name.string().c_str(), "wb+"); BOOST_CHECK(fp != nullptr); const Config &config = GetConfig(); const CChainParams &chainparams = config.GetChainParams(); // serialization format is: // message start magic, size of block, block size_t nwritten = fwrite(std::begin(chainparams.DiskMagic()), CMessageHeader::MESSAGE_START_SIZE, 1, fp); BOOST_CHECK_EQUAL(nwritten, 1UL); CTransaction empty_tx; size_t empty_tx_size = GetSerializeSize(empty_tx, SER_DISK, CLIENT_VERSION); size_t num_tx = (10 * MAX_TX_SIZE) / empty_tx_size; CBlock block = makeLargeDummyBlock(num_tx); BOOST_CHECK(GetSerializeSize(block, SER_DISK, CLIENT_VERSION) > 2 * MAX_TX_SIZE); unsigned int size = GetSerializeSize(block, SER_DISK, CLIENT_VERSION); { CAutoFile outs(fp, SER_DISK, CLIENT_VERSION); outs << size; outs << block; outs.release(); } fseek(fp, 0, SEEK_SET); BOOST_CHECK_NO_THROW({ LoadExternalBlockFile(config, fp, 0); }); } BOOST_AUTO_TEST_SUITE_END()