diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/bloom_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/data/README.md | 2 | ||||
-rw-r--r-- | src/test/fuzz/addrman.cpp | 36 | ||||
-rw-r--r-- | src/test/fuzz/data_stream.cpp | 30 | ||||
-rw-r--r-- | src/test/fuzz/muhash.cpp | 73 | ||||
-rw-r--r-- | src/test/fuzz/script.cpp | 62 | ||||
-rw-r--r-- | src/test/fuzz/system.cpp | 12 | ||||
-rw-r--r-- | src/test/fuzz/transaction.cpp | 4 | ||||
-rw-r--r-- | src/test/fuzz/utxo_snapshot.cpp | 1 | ||||
-rw-r--r-- | src/test/getarg_tests.cpp | 18 | ||||
-rw-r--r-- | src/test/script_standard_tests.cpp | 61 | ||||
-rw-r--r-- | src/test/txvalidationcache_tests.cpp | 9 | ||||
-rw-r--r-- | src/test/util/chainstate.h | 54 | ||||
-rw-r--r-- | src/test/util/setup_common.cpp | 29 | ||||
-rw-r--r-- | src/test/util/setup_common.h | 19 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 14 | ||||
-rw-r--r-- | src/test/validation_chainstate_tests.cpp | 76 | ||||
-rw-r--r-- | src/test/validation_chainstatemanager_tests.cpp | 66 | ||||
-rw-r--r-- | src/test/validation_flush_tests.cpp | 4 |
19 files changed, 280 insertions, 292 deletions
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 5a98558240..23ef2062ef 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(bloom_create_insert_key) CBloomFilter filter(2, 0.001, 0, BLOOM_UPDATE_ALL); filter.insert(vchPubKey); uint160 hash = pubkey.GetID(); - filter.insert(std::vector<unsigned char>(hash.begin(), hash.end())); + filter.insert(hash); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << filter; diff --git a/src/test/data/README.md b/src/test/data/README.md index 2463daa42a..a05d9c668b 100644 --- a/src/test/data/README.md +++ b/src/test/data/README.md @@ -8,5 +8,5 @@ License The data files in this directory are distributed under the MIT software license, see the accompanying file COPYING or -http://www.opensource.org/licenses/mit-license.php. +https://www.opensource.org/licenses/mit-license.php. diff --git a/src/test/fuzz/addrman.cpp b/src/test/fuzz/addrman.cpp index fdbfb3b93b..45ee778b87 100644 --- a/src/test/fuzz/addrman.cpp +++ b/src/test/fuzz/addrman.cpp @@ -23,6 +23,17 @@ void initialize_addrman() SelectParams(CBaseChainParams::REGTEST); } +FUZZ_TARGET_INIT(data_stream_addr_man, initialize_addrman) +{ + FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; + CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); + CAddrMan addr_man(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); + try { + ReadFromStream(addr_man, data_stream); + } catch (const std::exception&) { + } +} + class CAddrManDeterministic : public CAddrMan { public: @@ -85,7 +96,7 @@ public: // 0, 1, 2, 3 corresponding to 0%, 100%, 50%, 33% const size_t n = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 3); - const size_t num_sources = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(10, 50); + const size_t num_sources = m_fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 50); CNetAddr prev_source; // Use insecure_rand inside the loops instead of m_fuzzed_data_provider because when // the latter is exhausted it just returns 0. @@ -96,31 +107,12 @@ public: for (size_t j = 0; j < num_addresses; ++j) { const auto addr = CAddress{CService{RandAddr(), 8333}, NODE_NETWORK}; const auto time_penalty = insecure_rand.randrange(100000001); -#if 1 - // 2.83 sec to fill. - if (n > 0 && mapInfo.size() % n == 0 && mapAddr.find(addr) == mapAddr.end()) { - // Add to the "tried" table (if the bucket slot is free). - const CAddrInfo dummy{addr, source}; - const int bucket = dummy.GetTriedBucket(nKey, m_asmap); - const int bucket_pos = dummy.GetBucketPosition(nKey, false, bucket); - if (vvTried[bucket][bucket_pos] == -1) { - int id; - CAddrInfo* addr_info = Create(addr, source, &id); - vvTried[bucket][bucket_pos] = id; - addr_info->fInTried = true; - ++nTried; - } - } else { - // Add to the "new" table. - Add_(addr, source, time_penalty); - } -#else - // 261.91 sec to fill. Add_(addr, source, time_penalty); + if (n > 0 && mapInfo.size() % n == 0) { Good_(addr, false, GetTime()); } -#endif + // Add 10% of the addresses from more than one source. if (insecure_rand.randrange(10) == 0 && prev_source.IsValid()) { Add_(addr, prev_source, time_penalty); diff --git a/src/test/fuzz/data_stream.cpp b/src/test/fuzz/data_stream.cpp deleted file mode 100644 index 323090e041..0000000000 --- a/src/test/fuzz/data_stream.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2020-2021 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 <addrdb.h> -#include <addrman.h> -#include <net.h> -#include <test/fuzz/FuzzedDataProvider.h> -#include <test/fuzz/fuzz.h> -#include <test/fuzz/util.h> -#include <test/util/setup_common.h> - -#include <cstdint> -#include <vector> - -void initialize_data_stream_addr_man() -{ - static const auto testing_setup = MakeNoLogFileContext<>(); -} - -FUZZ_TARGET_INIT(data_stream_addr_man, initialize_data_stream_addr_man) -{ - FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - CDataStream data_stream = ConsumeDataStream(fuzzed_data_provider); - CAddrMan addr_man(/* asmap */ std::vector<bool>(), /* deterministic */ false, /* consistency_check_ratio */ 0); - try { - ReadFromStream(addr_man, data_stream); - } catch (const std::exception&) { - } -} diff --git a/src/test/fuzz/muhash.cpp b/src/test/fuzz/muhash.cpp index 4ea9511870..8304e6fdb8 100644 --- a/src/test/fuzz/muhash.cpp +++ b/src/test/fuzz/muhash.cpp @@ -12,52 +12,47 @@ FUZZ_TARGET(muhash) { FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; - std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider); - std::vector<uint8_t> data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider); - if (data.empty()) { - data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); - } - if (data2.empty()) { - data2.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>()); - } - - data = ConsumeRandomLengthByteVector(fuzzed_data_provider); - data2 = ConsumeRandomLengthByteVector(fuzzed_data_provider); + std::vector<uint8_t> data{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; + std::vector<uint8_t> data2{ConsumeRandomLengthByteVector(fuzzed_data_provider)}; MuHash3072 muhash; - // Test that MuHash result is consistent independent of order of operations muhash.Insert(data); muhash.Insert(data2); + const std::string initial_state_hash{"dd5ad2a105c2d29495f577245c357409002329b9f4d6182c0af3dc2f462555c8"}; uint256 out; - muhash.Finalize(out); - - muhash = MuHash3072(); - muhash.Insert(data2); - muhash.Insert(data); - uint256 out2; - muhash.Finalize(out2); - + CallOneOf( + fuzzed_data_provider, + [&] { + // Test that MuHash result is consistent independent of order of operations + muhash.Finalize(out); + + muhash = MuHash3072(); + muhash.Insert(data2); + muhash.Insert(data); + muhash.Finalize(out2); + }, + [&] { + // Test that multiplication with the initial state never changes the finalized result + muhash.Finalize(out); + MuHash3072 muhash3; + muhash3 *= muhash; + muhash3.Finalize(out2); + }, + [&] { + // Test that dividing a MuHash by itself brings it back to it's initial state + muhash /= muhash; + muhash.Finalize(out); + out2 = uint256S(initial_state_hash); + }, + [&] { + // Test that removing all added elements brings the object back to it's initial state + muhash.Remove(data); + muhash.Remove(data2); + muhash.Finalize(out); + out2 = uint256S(initial_state_hash); + }); assert(out == out2); - MuHash3072 muhash3; - muhash3 *= muhash; - uint256 out3; - muhash3.Finalize(out3); - assert(out == out3); - - // Test that removing all added elements brings the object back to it's initial state - muhash /= muhash; - muhash.Finalize(out); - - MuHash3072 muhash2; - muhash2.Finalize(out2); - - assert(out == out2); - - muhash3.Remove(data); - muhash3.Remove(data2); - muhash3.Finalize(out3); - assert(out == out3); } diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index 950ee45d1d..74c576322a 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -56,46 +56,8 @@ FUZZ_TARGET_INIT(script, initialize_script) assert(script == decompressed_script); } - CTxDestination address; - TxoutType type_ret; - std::vector<CTxDestination> addresses; - int required_ret; - bool extract_destinations_ret = ExtractDestinations(script, type_ret, addresses, required_ret); - bool extract_destination_ret = ExtractDestination(script, address); - if (!extract_destinations_ret) { - assert(!extract_destination_ret); - if (type_ret == TxoutType::MULTISIG) { - assert(addresses.empty() && required_ret == 0); - } else { - assert(type_ret == TxoutType::PUBKEY || - type_ret == TxoutType::NONSTANDARD || - type_ret == TxoutType::NULL_DATA); - } - } else { - assert(required_ret >= 1 && required_ret <= 16); - assert((unsigned long)required_ret == addresses.size()); - assert(type_ret == TxoutType::MULTISIG || required_ret == 1); - } - if (type_ret == TxoutType::NONSTANDARD || type_ret == TxoutType::NULL_DATA) { - assert(!extract_destinations_ret); - } - if (!extract_destination_ret) { - assert(type_ret == TxoutType::PUBKEY || - type_ret == TxoutType::NONSTANDARD || - type_ret == TxoutType::NULL_DATA || - type_ret == TxoutType::MULTISIG); - } else { - assert(address == addresses[0]); - } - if (type_ret == TxoutType::NONSTANDARD || - type_ret == TxoutType::NULL_DATA || - type_ret == TxoutType::MULTISIG) { - assert(!extract_destination_ret); - } - TxoutType which_type; bool is_standard_ret = IsStandard(script, which_type); - assert(type_ret == which_type); if (!is_standard_ret) { assert(which_type == TxoutType::NONSTANDARD || which_type == TxoutType::NULL_DATA || @@ -112,6 +74,20 @@ FUZZ_TARGET_INIT(script, initialize_script) which_type == TxoutType::NONSTANDARD); } + CTxDestination address; + bool extract_destination_ret = ExtractDestination(script, address); + if (!extract_destination_ret) { + assert(which_type == TxoutType::PUBKEY || + which_type == TxoutType::NONSTANDARD || + which_type == TxoutType::NULL_DATA || + which_type == TxoutType::MULTISIG); + } + if (which_type == TxoutType::NONSTANDARD || + which_type == TxoutType::NULL_DATA || + which_type == TxoutType::MULTISIG) { + assert(!extract_destination_ret); + } + const FlatSigningProvider signing_provider; (void)InferDescriptor(script, signing_provider); (void)IsSegWitOutput(signing_provider, script); @@ -133,15 +109,11 @@ FUZZ_TARGET_INIT(script, initialize_script) (void)ScriptToAsmStr(script, true); UniValue o1(UniValue::VOBJ); - ScriptPubKeyToUniv(script, o1, true, true); - ScriptPubKeyToUniv(script, o1, true, false); + ScriptPubKeyToUniv(script, o1, true); UniValue o2(UniValue::VOBJ); - ScriptPubKeyToUniv(script, o2, false, true); - ScriptPubKeyToUniv(script, o2, false, false); + ScriptPubKeyToUniv(script, o2, false); UniValue o3(UniValue::VOBJ); - ScriptToUniv(script, o3, true); - UniValue o4(UniValue::VOBJ); - ScriptToUniv(script, o4, false); + ScriptToUniv(script, o3); { const std::vector<uint8_t> bytes = ConsumeRandomLengthByteVector(fuzzed_data_provider); diff --git a/src/test/fuzz/system.cpp b/src/test/fuzz/system.cpp index 0f53939eac..dc3f9c8b8f 100644 --- a/src/test/fuzz/system.cpp +++ b/src/test/fuzz/system.cpp @@ -5,6 +5,7 @@ #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> +#include <test/util/setup_common.h> #include <util/system.h> #include <cstdint> @@ -12,6 +13,11 @@ #include <vector> namespace { +void initialize_system() +{ + static const auto testing_setup = MakeNoLogFileContext<>(); +} + std::string GetArgumentName(const std::string& name) { size_t idx = name.find('='); @@ -20,9 +26,8 @@ std::string GetArgumentName(const std::string& name) } return name.substr(0, idx); } -} // namespace -FUZZ_TARGET(system) +FUZZ_TARGET_INIT(system, initialize_system) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); ArgsManager args_manager{}; @@ -97,7 +102,7 @@ FUZZ_TARGET(system) const int64_t i64 = fuzzed_data_provider.ConsumeIntegral<int64_t>(); const bool b = fuzzed_data_provider.ConsumeBool(); - (void)args_manager.GetArg(s1, i64); + (void)args_manager.GetIntArg(s1, i64); (void)args_manager.GetArg(s1, s2); (void)args_manager.GetArgFlags(s1); (void)args_manager.GetArgs(s1); @@ -114,3 +119,4 @@ FUZZ_TARGET(system) (void)HelpRequested(args_manager); } +} // namespace diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp index ff34cc87b2..a21e5cea0c 100644 --- a/src/test/fuzz/transaction.cpp +++ b/src/test/fuzz/transaction.cpp @@ -103,6 +103,6 @@ FUZZ_TARGET_INIT(transaction, initialize_transaction) (void)IsWitnessStandard(tx, coins_view_cache); UniValue u(UniValue::VOBJ); - TxToUniv(tx, /* hashBlock */ uint256::ZERO, /* include_addresses */ true, u); - TxToUniv(tx, /* hashBlock */ uint256::ONE, /* include_addresses */ false, u); + TxToUniv(tx, /* hashBlock */ uint256::ZERO, u); + TxToUniv(tx, /* hashBlock */ uint256::ONE, u); } diff --git a/src/test/fuzz/utxo_snapshot.cpp b/src/test/fuzz/utxo_snapshot.cpp index 6f2bc081c6..8d2a06f11a 100644 --- a/src/test/fuzz/utxo_snapshot.cpp +++ b/src/test/fuzz/utxo_snapshot.cpp @@ -4,6 +4,7 @@ #include <chainparams.h> #include <consensus/validation.h> +#include <node/utxo_snapshot.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> #include <test/fuzz/util.h> diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 2a217f3455..17e904fcff 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -137,20 +137,20 @@ BOOST_AUTO_TEST_CASE(intarg) const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); SetupArgs({foo, bar}); ResetArgs(""); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 11); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 0); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 11), 11); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), 0); ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 11), 0); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); ResetArgs("-foo=11 -bar=12"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 0), 11); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 12); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), 11); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 12); ResetArgs("-foo=NaN -bar=NotANumber"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", 1), 0); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 1), 0); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); } BOOST_AUTO_TEST_CASE(doubledash) @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(doubledash) ResetArgs("--foo=verbose --bar=1"); BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "verbose"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 0), 1); + BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 0), 1); } BOOST_AUTO_TEST_CASE(boolargno) diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index a01d3fa03a..bf8ff5f5e2 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -252,67 +252,6 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) BOOST_CHECK(std::get<WitnessUnknown>(address) == unk); } -BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) -{ - CKey keys[3]; - CPubKey pubkeys[3]; - for (int i = 0; i < 3; i++) { - keys[i].MakeNewKey(true); - pubkeys[i] = keys[i].GetPubKey(); - } - - CScript s; - TxoutType whichType; - std::vector<CTxDestination> addresses; - int nRequired; - - // TxoutType::PUBKEY - s.clear(); - s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; - BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); - BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEY); - BOOST_CHECK_EQUAL(addresses.size(), 1U); - BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(std::get<PKHash>(addresses[0]) == PKHash(pubkeys[0])); - - // TxoutType::PUBKEYHASH - s.clear(); - s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; - BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); - BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEYHASH); - BOOST_CHECK_EQUAL(addresses.size(), 1U); - BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(std::get<PKHash>(addresses[0]) == PKHash(pubkeys[0])); - - // TxoutType::SCRIPTHASH - CScript redeemScript(s); // initialize with leftover P2PKH script - s.clear(); - s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; - BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); - BOOST_CHECK_EQUAL(whichType, TxoutType::SCRIPTHASH); - BOOST_CHECK_EQUAL(addresses.size(), 1U); - BOOST_CHECK_EQUAL(nRequired, 1); - BOOST_CHECK(std::get<ScriptHash>(addresses[0]) == ScriptHash(redeemScript)); - - // TxoutType::MULTISIG - s.clear(); - s << OP_2 << - ToByteVector(pubkeys[0]) << - ToByteVector(pubkeys[1]) << - OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); - BOOST_CHECK_EQUAL(whichType, TxoutType::MULTISIG); - BOOST_CHECK_EQUAL(addresses.size(), 2U); - BOOST_CHECK_EQUAL(nRequired, 2); - BOOST_CHECK(std::get<PKHash>(addresses[0]) == PKHash(pubkeys[0])); - BOOST_CHECK(std::get<PKHash>(addresses[1]) == PKHash(pubkeys[1])); - - // TxoutType::NULL_DATA - s.clear(); - s << OP_RETURN << std::vector<unsigned char>({75}); - BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired)); -} - BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) { CKey keys[3]; diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp index 1924ea55b1..afb3ad0cfd 100644 --- a/src/test/txvalidationcache_tests.cpp +++ b/src/test/txvalidationcache_tests.cpp @@ -13,6 +13,11 @@ #include <boost/test/unit_test.hpp> +struct Dersig100Setup : public TestChain100Setup { + Dersig100Setup() + : TestChain100Setup{{"-testactivationheight=dersig@102"}} {} +}; + bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, @@ -20,7 +25,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state, BOOST_AUTO_TEST_SUITE(txvalidationcache_tests) -BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) +BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, Dersig100Setup) { // Make sure skipping validation of transactions that were // validated going into the memory pool does not allow @@ -153,7 +158,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail } } -BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup) +BOOST_FIXTURE_TEST_CASE(checkinputs_test, Dersig100Setup) { // Test that passing CheckInputScripts with one set of script flags doesn't imply // that we would pass again with a different set of flags. diff --git a/src/test/util/chainstate.h b/src/test/util/chainstate.h new file mode 100644 index 0000000000..81ea4c38f5 --- /dev/null +++ b/src/test/util/chainstate.h @@ -0,0 +1,54 @@ +// Copyright (c) 2021 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_UTIL_CHAINSTATE_H +#define BITCOIN_TEST_UTIL_CHAINSTATE_H + +#include <clientversion.h> +#include <fs.h> +#include <node/context.h> +#include <node/utxo_snapshot.h> +#include <rpc/blockchain.h> +#include <validation.h> + +#include <univalue.h> + +#include <boost/test/unit_test.hpp> + +const auto NoMalleation = [](CAutoFile& file, SnapshotMetadata& meta){}; + +/** + * Create and activate a UTXO snapshot, optionally providing a function to + * malleate the snapshot. + */ +template<typename F = decltype(NoMalleation)> +static bool +CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleation = NoMalleation) +{ + // Write out a snapshot to the test's tempdir. + // + int height; + WITH_LOCK(::cs_main, height = node.chainman->ActiveHeight()); + fs::path snapshot_path = root / tfm::format("test_snapshot.%d.dat", height); + FILE* outfile{fsbridge::fopen(snapshot_path, "wb")}; + CAutoFile auto_outfile{outfile, SER_DISK, CLIENT_VERSION}; + + UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), auto_outfile); + BOOST_TEST_MESSAGE( + "Wrote UTXO snapshot to " << snapshot_path.make_preferred().string() << ": " << result.write()); + + // Read the written snapshot in and then activate it. + // + FILE* infile{fsbridge::fopen(snapshot_path, "rb")}; + CAutoFile auto_infile{infile, SER_DISK, CLIENT_VERSION}; + SnapshotMetadata metadata; + auto_infile >> metadata; + + malleation(auto_infile, metadata); + + return node.chainman->ActivateSnapshot(auto_infile, metadata, /*in_memory*/ true); +} + + +#endif // BITCOIN_TEST_UTIL_CHAINSTATE_H diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index cabc4b3b49..97e614379c 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -205,7 +205,8 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const } } -TestChain100Setup::TestChain100Setup() +TestChain100Setup::TestChain100Setup(const std::vector<const char*>& extra_args) + : TestingSetup{CBaseChainParams::REGTEST, extra_args} { SetMockTime(1598887952); constexpr std::array<unsigned char, 32> vchKey = { @@ -234,11 +235,14 @@ void TestChain100Setup::mineBlocks(int num_blocks) } } -CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey) +CBlock TestChain100Setup::CreateBlock( + const std::vector<CMutableTransaction>& txns, + const CScript& scriptPubKey, + CChainState& chainstate) { const CChainParams& chainparams = Params(); CTxMemPool empty_pool; - CBlock block = BlockAssembler(m_node.chainman->ActiveChainstate(), empty_pool, chainparams).CreateNewBlock(scriptPubKey)->block; + CBlock block = BlockAssembler(chainstate, empty_pool, chainparams).CreateNewBlock(scriptPubKey)->block; Assert(block.vtx.size() == 1); for (const CMutableTransaction& tx : txns) { @@ -248,6 +252,20 @@ CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransa while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; + return block; +} + +CBlock TestChain100Setup::CreateAndProcessBlock( + const std::vector<CMutableTransaction>& txns, + const CScript& scriptPubKey, + CChainState* chainstate) +{ + if (!chainstate) { + chainstate = &Assert(m_node.chainman)->ActiveChainstate(); + } + + const CChainParams& chainparams = Params(); + const CBlock block = this->CreateBlock(txns, scriptPubKey, *chainstate); std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block); Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr); @@ -304,11 +322,6 @@ CMutableTransaction TestChain100Setup::CreateValidMempoolTransaction(CTransactio return mempool_txn; } -TestChain100Setup::~TestChain100Setup() -{ - gArgs.ForceSetArg("-segwitheight", "0"); -} - CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) const { return FromTx(MakeTransactionRef(tx)); diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index 5d12dc2323..7518cdb042 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -113,15 +113,26 @@ class CScript; /** * Testing fixture that pre-creates a 100-block REGTEST-mode block chain */ -struct TestChain100Setup : public RegTestingSetup { - TestChain100Setup(); +struct TestChain100Setup : public TestingSetup { + TestChain100Setup(const std::vector<const char*>& extra_args = {}); /** * Create a new block with just given transactions, coinbase paying to * scriptPubKey, and try to add it to the current chain. + * If no chainstate is specified, default to the active. */ CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, - const CScript& scriptPubKey); + const CScript& scriptPubKey, + CChainState* chainstate = nullptr); + + /** + * Create a new block with just given transactions, coinbase paying to + * scriptPubKey. + */ + CBlock CreateBlock( + const std::vector<CMutableTransaction>& txns, + const CScript& scriptPubKey, + CChainState& chainstate); //! Mine a series of new blocks on the active chain. void mineBlocks(int num_blocks); @@ -145,8 +156,6 @@ struct TestChain100Setup : public RegTestingSetup { CAmount output_amount = CAmount(1 * COIN), bool submit = true); - ~TestChain100Setup(); - std::vector<CTransactionRef> m_coinbase_txns; // For convenience, coinbase transactions CKey coinbaseKey; // private/public key needed to spend coinbase transactions }; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 5ee522ea0a..a13700d733 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -300,9 +300,9 @@ public: } if (expect.default_int) { - BOOST_CHECK_EQUAL(test.GetArg("-value", 99999), 99999); + BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), 99999); } else if (expect.int_value) { - BOOST_CHECK_EQUAL(test.GetArg("-value", 99999), *expect.int_value); + BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), *expect.int_value); } else { BOOST_CHECK(!success); } @@ -432,8 +432,8 @@ static void TestParse(const std::string& str, bool expected_bool, int64_t expect BOOST_CHECK(test.ParseParameters(2, (char**)argv, error)); BOOST_CHECK_EQUAL(test.GetBoolArg("-value", false), expected_bool); BOOST_CHECK_EQUAL(test.GetBoolArg("-value", true), expected_bool); - BOOST_CHECK_EQUAL(test.GetArg("-value", 99998), expected_int); - BOOST_CHECK_EQUAL(test.GetArg("-value", 99999), expected_int); + BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99998), expected_int); + BOOST_CHECK_EQUAL(test.GetIntArg("-value", 99999), expected_int); } // Test bool and int parsing. @@ -784,9 +784,9 @@ BOOST_AUTO_TEST_CASE(util_GetArg) BOOST_CHECK_EQUAL(testArgs.GetArg("strtest1", "default"), "string..."); BOOST_CHECK_EQUAL(testArgs.GetArg("strtest2", "default"), "default"); - BOOST_CHECK_EQUAL(testArgs.GetArg("inttest1", -1), 12345); - BOOST_CHECK_EQUAL(testArgs.GetArg("inttest2", -1), 81985529216486895LL); - BOOST_CHECK_EQUAL(testArgs.GetArg("inttest3", -1), -1); + BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest1", -1), 12345); + BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest2", -1), 81985529216486895LL); + BOOST_CHECK_EQUAL(testArgs.GetIntArg("inttest3", -1), -1); BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest1", false), true); BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest2", false), false); BOOST_CHECK_EQUAL(testArgs.GetBoolArg("booltest3", false), false); diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index 315ef22599..726c9ebbb8 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -2,10 +2,13 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // +#include <chainparams.h> #include <random.h> #include <uint256.h> #include <consensus/validation.h> #include <sync.h> +#include <rpc/blockchain.h> +#include <test/util/chainstate.h> #include <test/util/setup_common.h> #include <validation.h> @@ -73,4 +76,77 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) WITH_LOCK(::cs_main, manager.Unload()); } +//! Test UpdateTip behavior for both active and background chainstates. +//! +//! When run on the background chainstate, UpdateTip should do a subset +//! of what it does for the active chainstate. +BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup) +{ + ChainstateManager& chainman = *Assert(m_node.chainman); + uint256 curr_tip = ::g_best_block; + + // Mine 10 more blocks, putting at us height 110 where a valid assumeutxo value can + // be found. + mineBlocks(10); + + // After adding some blocks to the tip, best block should have changed. + BOOST_CHECK(::g_best_block != curr_tip); + + BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root)); + + // Ensure our active chain is the snapshot chainstate. + BOOST_CHECK(chainman.IsSnapshotActive()); + + curr_tip = ::g_best_block; + + // Mine a new block on top of the activated snapshot chainstate. + mineBlocks(1); // Defined in TestChain100Setup. + + // After adding some blocks to the snapshot tip, best block should have changed. + BOOST_CHECK(::g_best_block != curr_tip); + + curr_tip = ::g_best_block; + + CChainState* background_cs; + + BOOST_CHECK_EQUAL(chainman.GetAll().size(), 2); + for (CChainState* cs : chainman.GetAll()) { + if (cs != &chainman.ActiveChainstate()) { + background_cs = cs; + } + } + BOOST_CHECK(background_cs); + + // Create a block to append to the validation chain. + std::vector<CMutableTransaction> noTxns; + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + CBlock validation_block = this->CreateBlock(noTxns, scriptPubKey, *background_cs); + auto pblock = std::make_shared<const CBlock>(validation_block); + BlockValidationState state; + CBlockIndex* pindex = nullptr; + const CChainParams& chainparams = Params(); + bool newblock = false; + + // TODO: much of this is inlined from ProcessNewBlock(); just reuse PNB() + // once it is changed to support multiple chainstates. + { + LOCK(::cs_main); + bool checked = CheckBlock(*pblock, state, chainparams.GetConsensus()); + BOOST_CHECK(checked); + bool accepted = background_cs->AcceptBlock( + pblock, state, &pindex, true, nullptr, &newblock); + BOOST_CHECK(accepted); + } + // UpdateTip is called here + bool block_added = background_cs->ActivateBestChain(state, pblock); + + // Ensure tip is as expected + BOOST_CHECK_EQUAL(background_cs->m_chain.Tip()->GetBlockHash(), validation_block.GetHash()); + + // g_best_block should be unchanged after adding a block to the background + // validation chain. + BOOST_CHECK(block_added); + BOOST_CHECK_EQUAL(curr_tip, ::g_best_block); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 0bd378631b..be9e05a65e 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -8,13 +8,13 @@ #include <random.h> #include <rpc/blockchain.h> #include <sync.h> +#include <test/util/chainstate.h> #include <test/util/setup_common.h> #include <uint256.h> #include <validation.h> #include <validationinterface.h> #include <tinyformat.h> -#include <univalue.h> #include <vector> @@ -44,7 +44,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) BOOST_CHECK(!manager.IsSnapshotActive()); BOOST_CHECK(!manager.IsSnapshotValidated()); - BOOST_CHECK(!manager.IsBackgroundIBD(&c1)); auto all = manager.GetAll(); BOOST_CHECK_EQUAL_COLLECTIONS(all.begin(), all.end(), chainstates.begin(), chainstates.end()); @@ -57,9 +56,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) auto exp_tip = c1.m_chain.Tip(); BOOST_CHECK_EQUAL(active_tip, exp_tip); - auto& validated_cs = manager.ValidatedChainstate(); - BOOST_CHECK_EQUAL(&validated_cs, &c1); - BOOST_CHECK(!manager.SnapshotBlockhash().has_value()); // Create a snapshot-based chainstate. @@ -81,8 +77,8 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) BOOST_CHECK(manager.IsSnapshotActive()); BOOST_CHECK(!manager.IsSnapshotValidated()); - BOOST_CHECK(manager.IsBackgroundIBD(&c1)); - BOOST_CHECK(!manager.IsBackgroundIBD(&c2)); + BOOST_CHECK_EQUAL(&c2, &manager.ActiveChainstate()); + BOOST_CHECK(&c1 != &manager.ActiveChainstate()); auto all2 = manager.GetAll(); BOOST_CHECK_EQUAL_COLLECTIONS(all2.begin(), all2.end(), chainstates.begin(), chainstates.end()); @@ -99,16 +95,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) // CCoinsViewCache instances. BOOST_CHECK(exp_tip != exp_tip2); - auto& validated_cs2 = manager.ValidatedChainstate(); - BOOST_CHECK_EQUAL(&validated_cs2, &c1); - - auto& validated_chain = manager.ValidatedChain(); - BOOST_CHECK_EQUAL(&validated_chain, &c1.m_chain); - - auto validated_tip = manager.ValidatedTip(); - exp_tip = c1.m_chain.Tip(); - BOOST_CHECK_EQUAL(validated_tip, exp_tip); - // Let scheduler events finish running to avoid accessing memory that is going to be unloaded SyncWithValidationInterfaceQueue(); @@ -168,36 +154,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches) BOOST_CHECK_CLOSE(c2.m_coinsdb_cache_size_bytes, max_cache * 0.95, 1); } -auto NoMalleation = [](CAutoFile& file, SnapshotMetadata& meta){}; - -template<typename F = decltype(NoMalleation)> -static bool -CreateAndActivateUTXOSnapshot(NodeContext& node, const fs::path root, F malleation = NoMalleation) -{ - // Write out a snapshot to the test's tempdir. - // - int height; - WITH_LOCK(::cs_main, height = node.chainman->ActiveHeight()); - fs::path snapshot_path = root / tfm::format("test_snapshot.%d.dat", height); - FILE* outfile{fsbridge::fopen(snapshot_path, "wb")}; - CAutoFile auto_outfile{outfile, SER_DISK, CLIENT_VERSION}; - - UniValue result = CreateUTXOSnapshot(node, node.chainman->ActiveChainstate(), auto_outfile); - BOOST_TEST_MESSAGE( - "Wrote UTXO snapshot to " << snapshot_path.make_preferred().string() << ": " << result.write()); - - // Read the written snapshot in and then activate it. - // - FILE* infile{fsbridge::fopen(snapshot_path, "rb")}; - CAutoFile auto_infile{infile, SER_DISK, CLIENT_VERSION}; - SnapshotMetadata metadata; - auto_infile >> metadata; - - malleation(auto_infile, metadata); - - return node.chainman->ActivateSnapshot(auto_infile, metadata, /*in_memory*/ true); -} - //! Test basic snapshot activation. BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) { @@ -321,27 +277,27 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_activate_snapshot, TestChain100Setup) { LOCK(::cs_main); size_t coins_in_active{0}; - size_t coins_in_ibd{0}; - size_t coins_missing_ibd{0}; + size_t coins_in_background{0}; + size_t coins_missing_from_background{0}; for (CChainState* chainstate : chainman.GetAll()) { BOOST_TEST_MESSAGE("Checking coins in " << chainstate->ToString()); CCoinsViewCache& coinscache = chainstate->CoinsTip(); - bool is_ibd = chainman.IsBackgroundIBD(chainstate); + bool is_background = chainstate != &chainman.ActiveChainstate(); for (CTransactionRef& txn : m_coinbase_txns) { COutPoint op{txn->GetHash(), 0}; if (coinscache.HaveCoin(op)) { - (is_ibd ? coins_in_ibd : coins_in_active)++; - } else if (is_ibd) { - coins_missing_ibd++; + (is_background ? coins_in_background : coins_in_active)++; + } else if (is_background) { + coins_missing_from_background++; } } } BOOST_CHECK_EQUAL(coins_in_active, initial_total_coins + new_coins); - BOOST_CHECK_EQUAL(coins_in_ibd, initial_total_coins); - BOOST_CHECK_EQUAL(coins_missing_ibd, new_coins); + BOOST_CHECK_EQUAL(coins_in_background, initial_total_coins); + BOOST_CHECK_EQUAL(coins_missing_from_background, new_coins); } // Snapshot should refuse to load after one has already loaded. diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp index 22aafcaa6c..9136c497ea 100644 --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -9,7 +9,7 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(validation_flush_tests, ChainTestingSetup) //! Test utilities for detecting when we need to flush the coins cache based //! on estimated memory usage. @@ -20,7 +20,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) { CTxMemPool mempool; BlockManager blockman{}; - CChainState chainstate{&mempool, blockman}; + CChainState chainstate{&mempool, blockman, *Assert(m_node.chainman)}; chainstate.InitCoinsDB(/*cache_size_bytes*/ 1 << 10, /*in_memory*/ true, /*should_wipe*/ false); WITH_LOCK(::cs_main, chainstate.InitCoinsCache(1 << 10)); |