diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/coinstatsindex_tests.cpp | 61 | ||||
-rw-r--r-- | src/test/fs_tests.cpp | 6 | ||||
-rw-r--r-- | src/test/fuzz/netaddress.cpp | 3 | ||||
-rw-r--r-- | src/test/fuzz/script_format.cpp | 5 | ||||
-rw-r--r-- | src/test/getarg_tests.cpp | 492 | ||||
-rw-r--r-- | src/test/miner_tests.cpp | 32 | ||||
-rw-r--r-- | src/test/net_peer_eviction_tests.cpp | 163 | ||||
-rw-r--r-- | src/test/net_tests.cpp | 191 | ||||
-rw-r--r-- | src/test/netbase_tests.cpp | 20 | ||||
-rw-r--r-- | src/test/script_segwit_tests.cpp | 164 | ||||
-rw-r--r-- | src/test/timedata_tests.cpp | 3 | ||||
-rw-r--r-- | src/test/util/setup_common.cpp | 3 | ||||
-rw-r--r-- | src/test/util/validation.cpp | 6 | ||||
-rw-r--r-- | src/test/util/validation.h | 8 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 49 | ||||
-rw-r--r-- | src/test/validation_chainstate_tests.cpp | 3 | ||||
-rw-r--r-- | src/test/validation_chainstatemanager_tests.cpp | 2 |
17 files changed, 975 insertions, 236 deletions
diff --git a/src/test/coinstatsindex_tests.cpp b/src/test/coinstatsindex_tests.cpp index 92de4ec7ba..5b73481bc1 100644 --- a/src/test/coinstatsindex_tests.cpp +++ b/src/test/coinstatsindex_tests.cpp @@ -2,8 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <chainparams.h> #include <index/coinstatsindex.h> #include <test/util/setup_common.h> +#include <test/util/validation.h> #include <util/time.h> #include <validation.h> @@ -16,6 +18,17 @@ using node::CoinStatsHashType; BOOST_AUTO_TEST_SUITE(coinstatsindex_tests) +static void IndexWaitSynced(BaseIndex& index) +{ + // Allow the CoinStatsIndex to catch up with the block index that is syncing + // in a background thread. + const auto timeout = GetTime<std::chrono::seconds>() + 120s; + while (!index.BlockUntilSyncedToCurrentChain()) { + BOOST_REQUIRE(timeout > GetTime<std::chrono::milliseconds>()); + UninterruptibleSleep(100ms); + } +} + BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) { CoinStatsIndex coin_stats_index{1 << 20, true}; @@ -36,13 +49,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) BOOST_REQUIRE(coin_stats_index.Start(m_node.chainman->ActiveChainstate())); - // Allow the CoinStatsIndex to catch up with the block index that is syncing - // in a background thread. - const auto timeout = GetTime<std::chrono::seconds>() + 120s; - while (!coin_stats_index.BlockUntilSyncedToCurrentChain()) { - BOOST_REQUIRE(timeout > GetTime<std::chrono::milliseconds>()); - UninterruptibleSleep(100ms); - } + IndexWaitSynced(coin_stats_index); // Check that CoinStatsIndex works for genesis block. const CBlockIndex* genesis_block_index; @@ -78,4 +85,44 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) // Rest of shutdown sequence and destructors happen in ~TestingSetup() } +// Test shutdown between BlockConnected and ChainStateFlushed notifications, +// make sure index is not corrupted and is able to reload. +BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup) +{ + CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate(); + const CChainParams& params = Params(); + { + CoinStatsIndex index{1 << 20}; + BOOST_REQUIRE(index.Start(chainstate)); + IndexWaitSynced(index); + std::shared_ptr<const CBlock> new_block; + CBlockIndex* new_block_index = nullptr; + { + const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG}; + const CBlock block = this->CreateBlock({}, script_pub_key, chainstate); + + new_block = std::make_shared<CBlock>(block); + + LOCK(cs_main); + BlockValidationState state; + BOOST_CHECK(CheckBlock(block, state, params.GetConsensus())); + BOOST_CHECK(chainstate.AcceptBlock(new_block, state, &new_block_index, true, nullptr, nullptr)); + CCoinsViewCache view(&chainstate.CoinsTip()); + BOOST_CHECK(chainstate.ConnectBlock(block, state, new_block_index, view)); + } + // Send block connected notification, then stop the index without + // sending a chainstate flushed notification. Prior to #24138, this + // would cause the index to be corrupted and fail to reload. + ValidationInterfaceTest::BlockConnected(index, new_block, new_block_index); + index.Stop(); + } + + { + CoinStatsIndex index{1 << 20}; + // Make sure the index can be loaded. + BOOST_REQUIRE(index.Start(chainstate)); + index.Stop(); + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/fs_tests.cpp b/src/test/fs_tests.cpp index 5875f0218f..d2554483d4 100644 --- a/src/test/fs_tests.cpp +++ b/src/test/fs_tests.cpp @@ -46,8 +46,8 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) { fs::path tmpfolder = m_args.GetDataDirBase(); // tmpfile1 should be the same as tmpfile2 - fs::path tmpfile1 = tmpfolder / "fs_tests_₿_🏃"; - fs::path tmpfile2 = tmpfolder / "fs_tests_₿_🏃"; + fs::path tmpfile1 = tmpfolder / fs::u8path("fs_tests_₿_🏃"); + fs::path tmpfile2 = tmpfolder / fs::u8path("fs_tests_₿_🏃"); { std::ofstream file{tmpfile1}; file << "bitcoin"; @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(fsbridge_fstream) } { // Join an absolute path and a relative path. - fs::path p = fsbridge::AbsPathJoin(tmpfolder, "fs_tests_₿_🏃"); + fs::path p = fsbridge::AbsPathJoin(tmpfolder, fs::u8path("fs_tests_₿_🏃")); BOOST_CHECK(p.is_absolute()); BOOST_CHECK_EQUAL(tmpfile1, p); } diff --git a/src/test/fuzz/netaddress.cpp b/src/test/fuzz/netaddress.cpp index 6cb81901cb..35e6688c61 100644 --- a/src/test/fuzz/netaddress.cpp +++ b/src/test/fuzz/netaddress.cpp @@ -16,7 +16,6 @@ FUZZ_TARGET(netaddress) FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const CNetAddr net_addr = ConsumeNetAddr(fuzzed_data_provider); - (void)net_addr.GetHash(); (void)net_addr.GetNetClass(); if (net_addr.GetNetwork() == Network::NET_IPV4) { assert(net_addr.IsIPv4()); @@ -84,6 +83,8 @@ FUZZ_TARGET(netaddress) (void)service.ToString(); (void)service.ToStringIPPort(); (void)service.ToStringPort(); + (void)CServiceHash()(service); + (void)CServiceHash(0, 0)(service); const CNetAddr other_net_addr = ConsumeNetAddr(fuzzed_data_provider); (void)net_addr.GetReachabilityFrom(&other_net_addr); diff --git a/src/test/fuzz/script_format.cpp b/src/test/fuzz/script_format.cpp index 2fa893f812..241bdfe666 100644 --- a/src/test/fuzz/script_format.cpp +++ b/src/test/fuzz/script_format.cpp @@ -3,7 +3,9 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <chainparams.h> +#include <consensus/consensus.h> #include <core_io.h> +#include <policy/policy.h> #include <script/script.h> #include <test/fuzz/FuzzedDataProvider.h> #include <test/fuzz/fuzz.h> @@ -19,6 +21,9 @@ FUZZ_TARGET_INIT(script_format, initialize_script_format) { FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); const CScript script{ConsumeScript(fuzzed_data_provider)}; + if (script.size() > MAX_STANDARD_TX_WEIGHT / WITNESS_SCALE_FACTOR) { + return; + } (void)FormatScript(script); (void)ScriptToAsmStr(script, /*fAttemptSighashDecode=*/fuzzed_data_provider.ConsumeBool()); diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 597d774673..c877105fe7 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -3,6 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <test/util/setup_common.h> +#include <univalue.h> +#include <util/settings.h> #include <util/strencodings.h> #include <util/system.h> @@ -14,22 +16,13 @@ #include <boost/algorithm/string.hpp> #include <boost/test/unit_test.hpp> -namespace getarg_tests{ - class LocalTestingSetup : BasicTestingSetup { - protected: - void SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args); - void ResetArgs(const std::string& strArg); - ArgsManager m_local_args; - }; -} +BOOST_FIXTURE_TEST_SUITE(getarg_tests, BasicTestingSetup) -BOOST_FIXTURE_TEST_SUITE(getarg_tests, LocalTestingSetup) - -void LocalTestingSetup :: ResetArgs(const std::string& strArg) +void ResetArgs(ArgsManager& local_args, const std::string& strArg) { std::vector<std::string> vecArg; if (strArg.size()) - boost::split(vecArg, strArg, IsSpace, boost::token_compress_on); + boost::split(vecArg, strArg, IsSpace, boost::token_compress_on); // Insert dummy executable name: vecArg.insert(vecArg.begin(), "testbitcoin"); @@ -40,264 +33,403 @@ void LocalTestingSetup :: ResetArgs(const std::string& strArg) vecChar.push_back(s.c_str()); std::string error; - BOOST_CHECK(m_local_args.ParseParameters(vecChar.size(), vecChar.data(), error)); + BOOST_CHECK(local_args.ParseParameters(vecChar.size(), vecChar.data(), error)); } -void LocalTestingSetup :: SetupArgs(const std::vector<std::pair<std::string, unsigned int>>& args) +void SetupArgs(ArgsManager& local_args, const std::vector<std::pair<std::string, unsigned int>>& args) { - m_local_args.ClearArgs(); for (const auto& arg : args) { - m_local_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS); + local_args.AddArg(arg.first, "", arg.second, OptionsCategory::OPTIONS); } } +// Test behavior of GetArg functions when string, integer, and boolean types +// are specified in the settings.json file. GetArg functions are convenience +// functions. The GetSetting method can always be used instead of GetArg +// methods to retrieve original values, and there's not always an objective +// answer to what GetArg behavior is best in every case. This test makes sure +// there's test coverage for whatever the current behavior is, so it's not +// broken or changed unintentionally. +BOOST_AUTO_TEST_CASE(setting_args) +{ + ArgsManager args; + SetupArgs(args, {{"-foo", ArgsManager::ALLOW_ANY}}); + + auto set_foo = [&](const util::SettingsValue& value) { + args.LockSettings([&](util::Settings& settings) { + settings.rw_settings["foo"] = value; + }); + }; + + set_foo("str"); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "\"str\""); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "str"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 0); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), false); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), false); + + set_foo("99"); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "\"99\""); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "99"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 99); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), true); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), true); + + set_foo("3.25"); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "\"3.25\""); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "3.25"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 3); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), true); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), true); + + set_foo("0"); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "\"0\""); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "0"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 0); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), false); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), false); + + set_foo(""); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "\"\""); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), ""); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 0); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), true); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), true); + + set_foo(99); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "99"); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "99"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 99); + BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error); + + set_foo(3.25); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "3.25"); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "3.25"); + BOOST_CHECK_THROW(args.GetIntArg("foo", 100), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error); + + set_foo(0); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "0"); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "0"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 0); + BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error); + + set_foo(true); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "true"); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "1"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 1); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), true); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), true); + + set_foo(false); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "false"); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "0"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 0); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), false); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), false); + + set_foo(UniValue::VOBJ); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "{}"); + BOOST_CHECK_THROW(args.GetArg("foo", "default"), std::runtime_error); + BOOST_CHECK_THROW(args.GetIntArg("foo", 100), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error); + + set_foo(UniValue::VARR); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "[]"); + BOOST_CHECK_THROW(args.GetArg("foo", "default"), std::runtime_error); + BOOST_CHECK_THROW(args.GetIntArg("foo", 100), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error); + BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error); + + set_foo(UniValue::VNULL); + BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "null"); + BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "default"); + BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 100); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), true); + BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), false); +} + BOOST_AUTO_TEST_CASE(boolarg) { + ArgsManager local_args; + const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); - SetupArgs({foo}); - ResetArgs("-foo"); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); + SetupArgs(local_args, {foo}); + ResetArgs(local_args, "-foo"); + BOOST_CHECK(local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_local_args.GetBoolArg("-fo", false)); - BOOST_CHECK(m_local_args.GetBoolArg("-fo", true)); + BOOST_CHECK(!local_args.GetBoolArg("-fo", false)); + BOOST_CHECK(local_args.GetBoolArg("-fo", true)); - BOOST_CHECK(!m_local_args.GetBoolArg("-fooo", false)); - BOOST_CHECK(m_local_args.GetBoolArg("-fooo", true)); + BOOST_CHECK(!local_args.GetBoolArg("-fooo", false)); + BOOST_CHECK(local_args.GetBoolArg("-fooo", true)); - ResetArgs("-foo=0"); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "-foo=0"); + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); - ResetArgs("-foo=1"); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "-foo=1"); + BOOST_CHECK(local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(local_args.GetBoolArg("-foo", true)); // New 0.6 feature: auto-map -nosomething to !-something: - ResetArgs("-nofoo"); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "-nofoo"); + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); - ResetArgs("-nofoo=1"); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "-nofoo=1"); + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); - ResetArgs("-foo -nofoo"); // -nofoo should win - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "-foo -nofoo"); // -nofoo should win + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); - ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "-foo=1 -nofoo=1"); // -nofoo should win + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); - ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win - BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "-foo=0 -nofoo=0"); // -nofoo=0 should win + BOOST_CHECK(local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(local_args.GetBoolArg("-foo", true)); // New 0.6 feature: treat -- same as -: - ResetArgs("--foo=1"); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); - - ResetArgs("--nofoo=1"); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "--foo=1"); + BOOST_CHECK(local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(local_args.GetBoolArg("-foo", true)); + ResetArgs(local_args, "--nofoo=1"); + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); } BOOST_AUTO_TEST_CASE(stringarg) { + ArgsManager local_args; + const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); - SetupArgs({foo, bar}); - ResetArgs(""); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven"); - - ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), ""); - - ResetArgs("-foo="); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), ""); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), ""); - - ResetArgs("-foo=11"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "11"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "11"); - - ResetArgs("-foo=eleven"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "eleven"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", "eleven"), "eleven"); - + SetupArgs(local_args, {foo, bar}); + ResetArgs(local_args, ""); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", "eleven"), "eleven"); + + ResetArgs(local_args, "-foo -bar"); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", "eleven"), ""); + + ResetArgs(local_args, "-foo="); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", ""), ""); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", "eleven"), ""); + + ResetArgs(local_args, "-foo=11"); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", ""), "11"); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", "eleven"), "11"); + + ResetArgs(local_args, "-foo=eleven"); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", ""), "eleven"); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", "eleven"), "eleven"); } BOOST_AUTO_TEST_CASE(intarg) { + ArgsManager local_args; + const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); - SetupArgs({foo, bar}); - ResetArgs(""); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 11), 11); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), 0); + SetupArgs(local_args, {foo, bar}); + ResetArgs(local_args, ""); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-foo", 11), 11); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-foo", 0), 0); - ResetArgs("-foo -bar"); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 11), 0); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); + ResetArgs(local_args, "-foo -bar"); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-foo", 11), 0); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-bar", 11), 0); // Check under-/overflow behavior. - ResetArgs("-foo=-9223372036854775809 -bar=9223372036854775808"); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), std::numeric_limits<int64_t>::min()); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 0), std::numeric_limits<int64_t>::max()); + ResetArgs(local_args, "-foo=-9223372036854775809 -bar=9223372036854775808"); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-foo", 0), std::numeric_limits<int64_t>::min()); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-bar", 0), std::numeric_limits<int64_t>::max()); - ResetArgs("-foo=11 -bar=12"); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 0), 11); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 12); + ResetArgs(local_args, "-foo=11 -bar=12"); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-foo", 0), 11); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-bar", 11), 12); - ResetArgs("-foo=NaN -bar=NotANumber"); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-foo", 1), 0); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 11), 0); + ResetArgs(local_args, "-foo=NaN -bar=NotANumber"); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-foo", 1), 0); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-bar", 11), 0); } BOOST_AUTO_TEST_CASE(patharg) { + ArgsManager local_args; + const auto dir = std::make_pair("-dir", ArgsManager::ALLOW_ANY); - SetupArgs({dir}); - ResetArgs(""); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), fs::path{}); + SetupArgs(local_args, {dir}); + ResetArgs(local_args, ""); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), fs::path{}); const fs::path root_path{"/"}; - ResetArgs("-dir=/"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + ResetArgs(local_args, "-dir=/"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), root_path); - ResetArgs("-dir=/."); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + ResetArgs(local_args, "-dir=/."); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), root_path); - ResetArgs("-dir=/./"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + ResetArgs(local_args, "-dir=/./"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), root_path); - ResetArgs("-dir=/.//"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + ResetArgs(local_args, "-dir=/.//"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), root_path); #ifdef WIN32 const fs::path win_root_path{"C:\\"}; - ResetArgs("-dir=C:\\"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + ResetArgs(local_args, "-dir=C:\\"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), win_root_path); - ResetArgs("-dir=C:/"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + ResetArgs(local_args, "-dir=C:/"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), win_root_path); - ResetArgs("-dir=C:\\\\"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + ResetArgs(local_args, "-dir=C:\\\\"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), win_root_path); - ResetArgs("-dir=C:\\."); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + ResetArgs(local_args, "-dir=C:\\."); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), win_root_path); - ResetArgs("-dir=C:\\.\\"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + ResetArgs(local_args, "-dir=C:\\.\\"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), win_root_path); - ResetArgs("-dir=C:\\.\\\\"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + ResetArgs(local_args, "-dir=C:\\.\\\\"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), win_root_path); #endif const fs::path absolute_path{"/home/user/.bitcoin"}; - ResetArgs("-dir=/home/user/.bitcoin"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/home/user/.bitcoin"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); - ResetArgs("-dir=/root/../home/user/.bitcoin"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/root/../home/user/.bitcoin"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); - ResetArgs("-dir=/home/./user/.bitcoin"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/home/./user/.bitcoin"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); - ResetArgs("-dir=/home/user/.bitcoin/"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/home/user/.bitcoin/"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); - ResetArgs("-dir=/home/user/.bitcoin//"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/home/user/.bitcoin//"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); - ResetArgs("-dir=/home/user/.bitcoin/."); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/home/user/.bitcoin/."); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); - ResetArgs("-dir=/home/user/.bitcoin/./"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/home/user/.bitcoin/./"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); - ResetArgs("-dir=/home/user/.bitcoin/.//"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + ResetArgs(local_args, "-dir=/home/user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), absolute_path); const fs::path relative_path{"user/.bitcoin"}; - ResetArgs("-dir=user/.bitcoin"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); - - ResetArgs("-dir=somewhere/../user/.bitcoin"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); - - ResetArgs("-dir=user/./.bitcoin"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); - - ResetArgs("-dir=user/.bitcoin/"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); - - ResetArgs("-dir=user/.bitcoin//"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); - - ResetArgs("-dir=user/.bitcoin/."); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); - - ResetArgs("-dir=user/.bitcoin/./"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); - - ResetArgs("-dir=user/.bitcoin/.//"); - BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + ResetArgs(local_args, "-dir=user/.bitcoin"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + ResetArgs(local_args, "-dir=somewhere/../user/.bitcoin"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + ResetArgs(local_args, "-dir=user/./.bitcoin"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + ResetArgs(local_args, "-dir=user/.bitcoin/"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + ResetArgs(local_args, "-dir=user/.bitcoin//"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + ResetArgs(local_args, "-dir=user/.bitcoin/."); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + ResetArgs(local_args, "-dir=user/.bitcoin/./"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + ResetArgs(local_args, "-dir=user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir"), relative_path); + + // Check negated and default argument handling. Specifying an empty argument + // is the same as not specifying the argument. This is convenient for + // scripting so later command line arguments can override earlier command + // line arguments or bitcoin.conf values. Currently the -dir= case cannot be + // distinguished from -dir case with no assignment, but #16545 would add the + // ability to distinguish these in the future (and treat the no-assign case + // like an imperative command or an error). + ResetArgs(local_args, ""); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir", "default"), fs::path{"default"}); + ResetArgs(local_args, "-dir=override"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir", "default"), fs::path{"override"}); + ResetArgs(local_args, "-dir="); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir", "default"), fs::path{"default"}); + ResetArgs(local_args, "-dir"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir", "default"), fs::path{"default"}); + ResetArgs(local_args, "-nodir"); + BOOST_CHECK_EQUAL(local_args.GetPathArg("-dir", "default"), fs::path{""}); } BOOST_AUTO_TEST_CASE(doubledash) { + ArgsManager local_args; + const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); - SetupArgs({foo, bar}); - ResetArgs("--foo"); - BOOST_CHECK_EQUAL(m_local_args.GetBoolArg("-foo", false), true); + SetupArgs(local_args, {foo, bar}); + ResetArgs(local_args, "--foo"); + BOOST_CHECK_EQUAL(local_args.GetBoolArg("-foo", false), true); - ResetArgs("--foo=verbose --bar=1"); - BOOST_CHECK_EQUAL(m_local_args.GetArg("-foo", ""), "verbose"); - BOOST_CHECK_EQUAL(m_local_args.GetIntArg("-bar", 0), 1); + ResetArgs(local_args, "--foo=verbose --bar=1"); + BOOST_CHECK_EQUAL(local_args.GetArg("-foo", ""), "verbose"); + BOOST_CHECK_EQUAL(local_args.GetIntArg("-bar", 0), 1); } BOOST_AUTO_TEST_CASE(boolargno) { + ArgsManager local_args; + const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); const auto bar = std::make_pair("-bar", ArgsManager::ALLOW_ANY); - SetupArgs({foo, bar}); - ResetArgs("-nofoo"); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - - ResetArgs("-nofoo=1"); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - - ResetArgs("-nofoo=0"); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); - - ResetArgs("-foo --nofoo"); // --nofoo should win - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(!m_local_args.GetBoolArg("-foo", false)); - - ResetArgs("-nofoo -foo"); // foo always wins: - BOOST_CHECK(m_local_args.GetBoolArg("-foo", true)); - BOOST_CHECK(m_local_args.GetBoolArg("-foo", false)); + SetupArgs(local_args, {foo, bar}); + ResetArgs(local_args, "-nofoo"); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + + ResetArgs(local_args, "-nofoo=1"); + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + + ResetArgs(local_args, "-nofoo=0"); + BOOST_CHECK(local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(local_args.GetBoolArg("-foo", false)); + + ResetArgs(local_args, "-foo --nofoo"); // --nofoo should win + BOOST_CHECK(!local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(!local_args.GetBoolArg("-foo", false)); + + ResetArgs(local_args, "-nofoo -foo"); // foo always wins: + BOOST_CHECK(local_args.GetBoolArg("-foo", true)); + BOOST_CHECK(local_args.GetBoolArg("-foo", false)); } BOOST_AUTO_TEST_CASE(logargs) { + ArgsManager local_args; + const auto okaylog_bool = std::make_pair("-okaylog-bool", ArgsManager::ALLOW_ANY); const auto okaylog_negbool = std::make_pair("-okaylog-negbool", ArgsManager::ALLOW_ANY); const auto okaylog = std::make_pair("-okaylog", ArgsManager::ALLOW_ANY); const auto dontlog = std::make_pair("-dontlog", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE); - SetupArgs({okaylog_bool, okaylog_negbool, okaylog, dontlog}); - ResetArgs("-okaylog-bool -nookaylog-negbool -okaylog=public -dontlog=private"); + SetupArgs(local_args, {okaylog_bool, okaylog_negbool, okaylog, dontlog}); + ResetArgs(local_args, "-okaylog-bool -nookaylog-negbool -okaylog=public -dontlog=private"); // Everything logged to debug.log will also append to str std::string str; @@ -307,7 +439,7 @@ BOOST_AUTO_TEST_CASE(logargs) }); // Log the arguments - m_local_args.LogArgs(); + local_args.LogArgs(); LogInstance().DeleteCallback(print_connection); // Check that what should appear does, and what shouldn't doesn't. diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c453dae701..f6c1d1efad 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -30,10 +30,10 @@ using node::CBlockTemplate; namespace miner_tests { struct MinerTestingSetup : public TestingSetup { void TestPackageSelection(const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs); - bool TestSequenceLocks(const CTransaction& tx, int flags) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs) + bool TestSequenceLocks(const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs) { CCoinsViewMemPool view_mempool(&m_node.chainman->ActiveChainstate().CoinsTip(), *m_node.mempool); - return CheckSequenceLocks(m_node.chainman->ActiveChain().Tip(), view_mempool, tx, flags); + return CheckSequenceLocksAtTip(m_node.chainman->ActiveChain().Tip(), view_mempool, tx); } BlockAssembler AssemblerForTest(const CChainParams& params); }; @@ -410,7 +410,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // non-final txs in mempool SetMockTime(m_node.chainman->ActiveChain().Tip()->GetMedianTimePast()+1); - int flags = LOCKTIME_VERIFY_SEQUENCE|LOCKTIME_MEDIAN_TIME_PAST; + const int flags{LOCKTIME_VERIFY_SEQUENCE | LOCKTIME_MEDIAN_TIME_PAST}; // height map std::vector<int> prevheights; @@ -429,8 +429,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.nLockTime = 0; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Fee(HIGHFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx)); - BOOST_CHECK(CheckFinalTx(m_node.chainman->ActiveChain().Tip(), CTransaction(tx), flags)); // Locktime passes - BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail + BOOST_CHECK(CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail { CBlockIndex* active_chain_tip = m_node.chainman->ActiveChain().Tip(); @@ -443,8 +443,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = baseheight + 2; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); - BOOST_CHECK(CheckFinalTx(m_node.chainman->ActiveChain().Tip(), CTransaction(tx), flags)); // Locktime passes - BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail + BOOST_CHECK(CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime passes + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++) m_node.chainman->ActiveChain().Tip()->GetAncestor(m_node.chainman->ActiveChain().Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast @@ -464,8 +464,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); - BOOST_CHECK(!CheckFinalTx(m_node.chainman->ActiveChain().Tip(), CTransaction(tx), flags)); // Locktime fails - BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass + BOOST_CHECK(!CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime fails + BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast())); // Locktime passes on 2nd block // absolute time locked @@ -475,8 +475,8 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = baseheight + 4; hash = tx.GetHash(); m_node.mempool->addUnchecked(entry.Time(GetTime()).FromTx(tx)); - BOOST_CHECK(!CheckFinalTx(m_node.chainman->ActiveChain().Tip(), CTransaction(tx), flags)); // Locktime fails - BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass + BOOST_CHECK(!CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime fails + BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass BOOST_CHECK(IsFinalTx(CTransaction(tx), m_node.chainman->ActiveChain().Tip()->nHeight + 2, m_node.chainman->ActiveChain().Tip()->GetMedianTimePast() + 1)); // Locktime passes 1 second later // mempool-dependent transactions (not added) @@ -484,14 +484,14 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) prevheights[0] = m_node.chainman->ActiveChain().Tip()->nHeight + 1; tx.nLockTime = 0; tx.vin[0].nSequence = 0; - BOOST_CHECK(CheckFinalTx(m_node.chainman->ActiveChain().Tip(), CTransaction(tx), flags)); // Locktime passes - BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass + BOOST_CHECK(CheckFinalTxAtTip(m_node.chainman->ActiveChain().Tip(), CTransaction{tx})); // Locktime passes + BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass tx.vin[0].nSequence = 1; - BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG; - BOOST_CHECK(TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks pass + BOOST_CHECK(TestSequenceLocks(CTransaction{tx})); // Sequence locks pass tx.vin[0].nSequence = CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | 1; - BOOST_CHECK(!TestSequenceLocks(CTransaction(tx), flags)); // Sequence locks fail + BOOST_CHECK(!TestSequenceLocks(CTransaction{tx})); // Sequence locks fail BOOST_CHECK(pblocktemplate = AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey)); diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp index 78ad24a408..6ec3fb0c6b 100644 --- a/src/test/net_peer_eviction_tests.cpp +++ b/src/test/net_peer_eviction_tests.cpp @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) // Test protection of onion, localhost, and I2P peers... // Expect 1/4 onion peers to be protected from eviction, - // if no localhost or I2P peers. + // if no localhost, I2P, or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { c.m_is_local = false; @@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) random_context)); // Expect 1/4 onion peers and 1/4 of the other peers to be protected, - // sorted by longest uptime (lowest m_connected), if no localhost or I2P peers. + // sorted by longest uptime (lowest m_connected), if no localhost, I2P or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; @@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) random_context)); // Expect 1/4 localhost peers to be protected from eviction, - // if no onion or I2P peers. + // if no onion, I2P, or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { c.m_is_local = (c.id == 1 || c.id == 9 || c.id == 11); @@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) random_context)); // Expect 1/4 localhost peers and 1/4 of the other peers to be protected, - // sorted by longest uptime (lowest m_connected), if no onion or I2P peers. + // sorted by longest uptime (lowest m_connected), if no onion, I2P, or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) random_context)); // Expect 1/4 I2P peers to be protected from eviction, - // if no onion or localhost peers. + // if no onion, localhost, or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { c.m_is_local = false; @@ -146,8 +146,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) /*unprotected_peer_ids=*/{}, random_context)); - // Expect 1/4 I2P peers and 1/4 of the other peers to be protected, - // sorted by longest uptime (lowest m_connected), if no onion or localhost peers. + // Expect 1/4 I2P peers and 1/4 of the other peers to be protected, sorted + // by longest uptime (lowest m_connected), if no onion, localhost, or CJDNS peers. BOOST_CHECK(IsProtected( num_peers, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; @@ -158,6 +158,29 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) /*unprotected_peer_ids=*/{3, 5, 6, 7, 8, 11}, random_context)); + // Expect 1/4 CJDNS peers to be protected from eviction, + // if no onion, localhost, or I2P peers. + BOOST_CHECK(IsProtected( + num_peers, [](NodeEvictionCandidate& c) { + c.m_is_local = false; + c.m_network = (c.id == 2 || c.id == 7 || c.id == 10) ? NET_CJDNS : NET_IPV4; + }, + /*protected_peer_ids=*/{2, 7, 10}, + /*unprotected_peer_ids=*/{}, + random_context)); + + // Expect 1/4 CJDNS peers and 1/4 of the other peers to be protected, sorted + // by longest uptime (lowest m_connected), if no onion, localhost, or I2P peers. + BOOST_CHECK(IsProtected( + num_peers, [](NodeEvictionCandidate& c) { + c.m_connected = std::chrono::seconds{c.id}; + c.m_is_local = false; + c.m_network = (c.id == 4 || c.id > 8) ? NET_CJDNS : NET_IPV6; + }, + /*protected_peer_ids=*/{0, 1, 2, 4, 9, 10}, + /*unprotected_peer_ids=*/{3, 5, 6, 7, 8, 11}, + random_context)); + // Tests with 2 networks... // Combined test: expect having 1 localhost and 1 onion peer out of 4 to @@ -289,16 +312,16 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) BOOST_CHECK(IsProtected( 4, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; - c.m_is_local = (c.id == 3); - if (c.id == 4) { + c.m_is_local = (c.id == 2); + if (c.id == 3) { c.m_network = NET_I2P; - } else if (c.id == 2) { + } else if (c.id == 1) { c.m_network = NET_ONION; } else { c.m_network = NET_IPV6; } }, - /*protected_peer_ids=*/{0, 4}, + /*protected_peer_ids=*/{0, 3}, /*unprotected_peer_ids=*/{1, 2}, random_context)); @@ -416,15 +439,15 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) /*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 16, 19, 20, 21, 22, 23}, random_context)); - // Combined test: expect having 8 localhost, 4 I2P, and 3 onion peers out of - // 24 to protect 2 of each (6 total), plus 6 others for 12/24 total, sorted - // by longest uptime. + // Combined test: expect having 8 localhost, 4 CJDNS, and 3 onion peers out + // of 24 to protect 2 of each (6 total), plus 6 others for 12/24 total, + // sorted by longest uptime. BOOST_CHECK(IsProtected( 24, [](NodeEvictionCandidate& c) { c.m_connected = std::chrono::seconds{c.id}; c.m_is_local = (c.id > 15); if (c.id > 10 && c.id < 15) { - c.m_network = NET_I2P; + c.m_network = NET_CJDNS; } else if (c.id > 6 && c.id < 10) { c.m_network = NET_ONION; } else { @@ -434,6 +457,116 @@ BOOST_AUTO_TEST_CASE(peer_protection_test) /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 16, 17}, /*unprotected_peer_ids=*/{6, 9, 10, 13, 14, 15, 18, 19, 20, 21, 22, 23}, random_context)); + + // Tests with 4 networks... + + // Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer + // out of 5 to protect 1 CJDNS, 0 I2P, 0 localhost, 0 onion and 1 other peer + // (2 total), sorted by longest uptime; stable sort breaks tie with array + // order of CJDNS first. + BOOST_CHECK(IsProtected( + 5, [](NodeEvictionCandidate& c) { + c.m_connected = std::chrono::seconds{c.id}; + c.m_is_local = (c.id == 3); + if (c.id == 4) { + c.m_network = NET_CJDNS; + } else if (c.id == 1) { + c.m_network = NET_I2P; + } else if (c.id == 2) { + c.m_network = NET_ONION; + } else { + c.m_network = NET_IPV6; + } + }, + /* protected_peer_ids */ {0, 4}, + /* unprotected_peer_ids */ {1, 2, 3}, + random_context)); + + // Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer + // out of 7 to protect 1 CJDNS, 0, I2P, 0 localhost, 0 onion and 2 other + // peers (3 total) sorted by longest uptime; stable sort breaks tie with + // array order of CJDNS first. + BOOST_CHECK(IsProtected( + 7, [](NodeEvictionCandidate& c) { + c.m_connected = std::chrono::seconds{c.id}; + c.m_is_local = (c.id == 4); + if (c.id == 6) { + c.m_network = NET_CJDNS; + } else if (c.id == 5) { + c.m_network = NET_I2P; + } else if (c.id == 3) { + c.m_network = NET_ONION; + } else { + c.m_network = NET_IPV4; + } + }, + /*protected_peer_ids=*/{0, 1, 6}, + /*unprotected_peer_ids=*/{2, 3, 4, 5}, + random_context)); + + // Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer + // out of 8 to protect 1 CJDNS, 1 I2P, 0 localhost, 0 onion and 2 other + // peers (4 total) sorted by longest uptime; stable sort breaks tie with + // array order of CJDNS first. + BOOST_CHECK(IsProtected( + 8, [](NodeEvictionCandidate& c) { + c.m_connected = std::chrono::seconds{c.id}; + c.m_is_local = (c.id == 3); + if (c.id == 5) { + c.m_network = NET_CJDNS; + } else if (c.id == 6) { + c.m_network = NET_I2P; + } else if (c.id == 3) { + c.m_network = NET_ONION; + } else { + c.m_network = NET_IPV6; + } + }, + /*protected_peer_ids=*/{0, 1, 5, 6}, + /*unprotected_peer_ids=*/{2, 3, 4, 7}, + random_context)); + + // Combined test: expect having 2 CJDNS, 2 I2P, 4 localhost, and 2 onion + // peers out of 16 to protect 1 CJDNS, 1 I2P, 1 localhost, 1 onion (4/16 + // total), plus 4 others for 8 total, sorted by longest uptime. + BOOST_CHECK(IsProtected( + 16, [](NodeEvictionCandidate& c) { + c.m_connected = std::chrono::seconds{c.id}; + c.m_is_local = (c.id > 5); + if (c.id == 11 || c.id == 15) { + c.m_network = NET_CJDNS; + } else if (c.id == 10 || c.id == 14) { + c.m_network = NET_I2P; + } else if (c.id == 8 || c.id == 9) { + c.m_network = NET_ONION; + } else { + c.m_network = NET_IPV4; + } + }, + /*protected_peer_ids=*/{0, 1, 2, 3, 6, 8, 10, 11}, + /*unprotected_peer_ids=*/{4, 5, 7, 9, 12, 13, 14, 15}, + random_context)); + + // Combined test: expect having 6 CJDNS, 1 I2P, 1 localhost, and 4 onion + // peers out of 24 to protect 2 CJDNS, 1 I2P, 1 localhost, and 2 onions (6 + // total), plus 6 others for 12/24 total, sorted by longest uptime. + BOOST_CHECK(IsProtected( + 24, [](NodeEvictionCandidate& c) { + c.m_connected = std::chrono::seconds{c.id}; + c.m_is_local = (c.id == 13); + if (c.id > 17) { + c.m_network = NET_CJDNS; + } else if (c.id == 17) { + c.m_network = NET_I2P; + } else if (c.id == 12 || c.id == 14 || c.id == 15 || c.id == 16) { + c.m_network = NET_ONION; + } else { + c.m_network = NET_IPV6; + } + }, + /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 13, 14, 17, 18, 19}, + /*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 15, 16, 20, 21, 22, 23}, + random_context)); } // Returns true if any of the node ids in node_ids are selected for eviction. diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 908b030eea..fcb1a80765 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -4,17 +4,23 @@ #include <chainparams.h> #include <clientversion.h> +#include <compat.h> #include <cstdint> #include <net.h> +#include <net_processing.h> #include <netaddress.h> #include <netbase.h> +#include <netmessagemaker.h> #include <serialize.h> #include <span.h> #include <streams.h> #include <test/util/setup_common.h> +#include <test/util/validation.h> +#include <timedata.h> #include <util/strencodings.h> #include <util/string.h> #include <util/system.h> +#include <validation.h> #include <version.h> #include <boost/test/unit_test.hpp> @@ -27,7 +33,7 @@ using namespace std::literals; -BOOST_FIXTURE_TEST_SUITE(net_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(net_tests, RegTestingSetup) BOOST_AUTO_TEST_CASE(cnode_listen_port) { @@ -607,15 +613,15 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) // set up local addresses; all that's necessary to reproduce the bug is // that a normal IPv4 address is among the entries, but if this address is // !IsRoutable the undefined behavior is easier to trigger deterministically + in_addr raw_addr; + raw_addr.s_addr = htonl(0x7f000001); + const CNetAddr mapLocalHost_entry = CNetAddr(raw_addr); { LOCK(g_maplocalhost_mutex); - in_addr ipv4AddrLocal; - ipv4AddrLocal.s_addr = 0x0100007f; - CNetAddr addr = CNetAddr(ipv4AddrLocal); LocalServiceInfo lsi; lsi.nScore = 23; lsi.nPort = 42; - mapLocalHost[addr] = lsi; + mapLocalHost[mapLocalHost_entry] = lsi; } // create a peer with an IPv4 address @@ -646,8 +652,79 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test) // suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer BOOST_CHECK(1); + + // Cleanup, so that we don't confuse other tests. + { + LOCK(g_maplocalhost_mutex); + mapLocalHost.erase(mapLocalHost_entry); + } } +BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port) +{ + // Test that GetLocalAddrForPeer() properly selects the address to self-advertise: + // + // 1. GetLocalAddrForPeer() calls GetLocalAddress() which returns an address that is + // not routable. + // 2. GetLocalAddrForPeer() overrides the address with whatever the peer has told us + // he sees us as. + // 2.1. For inbound connections we must override both the address and the port. + // 2.2. For outbound connections we must override only the address. + + // Pretend that we bound to this port. + const uint16_t bind_port = 20001; + m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port)); + + // Our address:port as seen from the peer, completely different from the above. + in_addr peer_us_addr; + peer_us_addr.s_addr = htonl(0x02030405); + const CAddress peer_us{CService{peer_us_addr, 20002}, NODE_NETWORK}; + + // Create a peer with a routable IPv4 address (outbound). + in_addr peer_out_in_addr; + peer_out_in_addr.s_addr = htonl(0x01020304); + CNode peer_out{/*id=*/0, + /*nLocalServicesIn=*/NODE_NETWORK, + /*sock=*/nullptr, + /*addrIn=*/CAddress{CService{peer_out_in_addr, 8333}, NODE_NETWORK}, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + /*addrBindIn=*/CAddress{}, + /*addrNameIn=*/std::string{}, + /*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY, + /*inbound_onion=*/false}; + peer_out.fSuccessfullyConnected = true; + peer_out.SetAddrLocal(peer_us); + + // Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port. + auto chosen_local_addr = GetLocalAddrForPeer(&peer_out); + BOOST_REQUIRE(chosen_local_addr); + const CService expected{peer_us_addr, bind_port}; + BOOST_CHECK(*chosen_local_addr == expected); + + // Create a peer with a routable IPv4 address (inbound). + in_addr peer_in_in_addr; + peer_in_in_addr.s_addr = htonl(0x05060708); + CNode peer_in{/*id=*/0, + /*nLocalServicesIn=*/NODE_NETWORK, + /*sock=*/nullptr, + /*addrIn=*/CAddress{CService{peer_in_in_addr, 8333}, NODE_NETWORK}, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + /*addrBindIn=*/CAddress{}, + /*addrNameIn=*/std::string{}, + /*conn_type_in=*/ConnectionType::INBOUND, + /*inbound_onion=*/false}; + peer_in.fSuccessfullyConnected = true; + peer_in.SetAddrLocal(peer_us); + + // Without the fix peer_us:8333 is chosen instead of the proper peer_us:peer_us.GetPort(). + chosen_local_addr = GetLocalAddrForPeer(&peer_in); + BOOST_REQUIRE(chosen_local_addr); + BOOST_CHECK(*chosen_local_addr == peer_us); + + m_node.args->ForceSetArg("-bind", ""); +} BOOST_AUTO_TEST_CASE(LimitedAndReachable_Network) { @@ -728,4 +805,108 @@ BOOST_AUTO_TEST_CASE(LocalAddress_BasicLifecycle) BOOST_CHECK(!IsLocal(addr)); } +BOOST_AUTO_TEST_CASE(initial_advertise_from_version_message) +{ + // Tests the following scenario: + // * -bind=3.4.5.6:20001 is specified + // * we make an outbound connection to a peer + // * the peer reports he sees us as 2.3.4.5:20002 in the version message + // (20002 is a random port assigned by our OS for the outgoing TCP connection, + // we cannot accept connections to it) + // * we should self-advertise to that peer as 2.3.4.5:20001 + + // Pretend that we bound to this port. + const uint16_t bind_port = 20001; + m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port)); + m_node.args->ForceSetArg("-capturemessages", "1"); + + // Our address:port as seen from the peer - 2.3.4.5:20002 (different from the above). + in_addr peer_us_addr; + peer_us_addr.s_addr = htonl(0x02030405); + const CService peer_us{peer_us_addr, 20002}; + + // Create a peer with a routable IPv4 address. + in_addr peer_in_addr; + peer_in_addr.s_addr = htonl(0x01020304); + CNode peer{/*id=*/0, + /*nLocalServicesIn=*/NODE_NETWORK, + /*sock=*/nullptr, + /*addrIn=*/CAddress{CService{peer_in_addr, 8333}, NODE_NETWORK}, + /*nKeyedNetGroupIn=*/0, + /*nLocalHostNonceIn=*/0, + /*addrBindIn=*/CAddress{}, + /*addrNameIn=*/std::string{}, + /*conn_type_in=*/ConnectionType::OUTBOUND_FULL_RELAY, + /*inbound_onion=*/false}; + + const uint64_t services{NODE_NETWORK | NODE_WITNESS}; + const int64_t time{0}; + const CNetMsgMaker msg_maker{PROTOCOL_VERSION}; + + // Force CChainState::IsInitialBlockDownload() to return false. + // Otherwise PushAddress() isn't called by PeerManager::ProcessMessage(). + TestChainState& chainstate = + *static_cast<TestChainState*>(&m_node.chainman->ActiveChainstate()); + chainstate.JumpOutOfIbd(); + + m_node.peerman->InitializeNode(&peer); + + std::atomic<bool> interrupt_dummy{false}; + std::chrono::microseconds time_received_dummy{0}; + + const auto msg_version = + msg_maker.Make(NetMsgType::VERSION, PROTOCOL_VERSION, services, time, services, peer_us); + CDataStream msg_version_stream{msg_version.data, SER_NETWORK, PROTOCOL_VERSION}; + + m_node.peerman->ProcessMessage( + peer, NetMsgType::VERSION, msg_version_stream, time_received_dummy, interrupt_dummy); + + const auto msg_verack = msg_maker.Make(NetMsgType::VERACK); + CDataStream msg_verack_stream{msg_verack.data, SER_NETWORK, PROTOCOL_VERSION}; + + // Will set peer.fSuccessfullyConnected to true (necessary in SendMessages()). + m_node.peerman->ProcessMessage( + peer, NetMsgType::VERACK, msg_verack_stream, time_received_dummy, interrupt_dummy); + + // Ensure that peer_us_addr:bind_port is sent to the peer. + const CService expected{peer_us_addr, bind_port}; + bool sent{false}; + + const auto CaptureMessageOrig = CaptureMessage; + CaptureMessage = [&sent, &expected](const CAddress& addr, + const std::string& msg_type, + Span<const unsigned char> data, + bool is_incoming) -> void { + if (!is_incoming && msg_type == "addr") { + CDataStream s(data, SER_NETWORK, PROTOCOL_VERSION); + std::vector<CAddress> addresses; + + s >> addresses; + + for (const auto& addr : addresses) { + if (addr == expected) { + sent = true; + return; + } + } + } + }; + + { + LOCK(peer.cs_sendProcessing); + m_node.peerman->SendMessages(&peer); + } + + BOOST_CHECK(sent); + + CaptureMessage = CaptureMessageOrig; + chainstate.ResetIbd(); + m_node.args->ForceSetArg("-capturemessages", "0"); + m_node.args->ForceSetArg("-bind", ""); + // PeerManager::ProcessMessage() calls AddTimeData() which changes the internal state + // in timedata.cpp and later confuses the test "timedata_tests/addtimedata". Thus reset + // that state as it was before our test was run. + TestOnlyResetTimeData(); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index 6410ac565a..8e6e911ec2 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -576,4 +576,24 @@ BOOST_AUTO_TEST_CASE(caddress_unserialize_v2) BOOST_CHECK(fixture_addresses == addresses_unserialized); } +BOOST_AUTO_TEST_CASE(isbadport) +{ + BOOST_CHECK(IsBadPort(1)); + BOOST_CHECK(IsBadPort(22)); + BOOST_CHECK(IsBadPort(6000)); + + BOOST_CHECK(!IsBadPort(80)); + BOOST_CHECK(!IsBadPort(443)); + BOOST_CHECK(!IsBadPort(8333)); + + // Check all ports, there must be 80 bad ports in total. + size_t total_bad_ports{0}; + for (uint16_t port = std::numeric_limits<uint16_t>::max(); port > 0; --port) { + if (IsBadPort(port)) { + ++total_bad_ports; + } + } + BOOST_CHECK_EQUAL(total_bad_ports, 80); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/script_segwit_tests.cpp b/src/test/script_segwit_tests.cpp new file mode 100644 index 0000000000..2bad59805f --- /dev/null +++ b/src/test/script_segwit_tests.cpp @@ -0,0 +1,164 @@ +// Copyright (c) 2012-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 <script/script.h> +#include <test/util/setup_common.h> + +#include <boost/test/unit_test.hpp> + +BOOST_FIXTURE_TEST_SUITE(script_segwit_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(IsPayToWitnessScriptHash_Valid) +{ + uint256 dummy; + CScript p2wsh; + p2wsh << OP_0 << ToByteVector(dummy); + BOOST_CHECK(p2wsh.IsPayToWitnessScriptHash()); + + std::vector<unsigned char> bytes = {OP_0, 32}; + bytes.insert(bytes.end(), 32, 0); + BOOST_CHECK(CScript(bytes.begin(), bytes.end()).IsPayToWitnessScriptHash()); +} + +BOOST_AUTO_TEST_CASE(IsPayToWitnessScriptHash_Invalid_NotOp0) +{ + uint256 dummy; + CScript notp2wsh; + notp2wsh << OP_1 << ToByteVector(dummy); + BOOST_CHECK(!notp2wsh.IsPayToWitnessScriptHash()); +} + +BOOST_AUTO_TEST_CASE(IsPayToWitnessScriptHash_Invalid_Size) +{ + uint160 dummy; + CScript notp2wsh; + notp2wsh << OP_0 << ToByteVector(dummy); + BOOST_CHECK(!notp2wsh.IsPayToWitnessScriptHash()); +} + +BOOST_AUTO_TEST_CASE(IsPayToWitnessScriptHash_Invalid_Nop) +{ + uint256 dummy; + CScript notp2wsh; + notp2wsh << OP_0 << OP_NOP << ToByteVector(dummy); + BOOST_CHECK(!notp2wsh.IsPayToWitnessScriptHash()); +} + +BOOST_AUTO_TEST_CASE(IsPayToWitnessScriptHash_Invalid_EmptyScript) +{ + CScript notp2wsh; + BOOST_CHECK(!notp2wsh.IsPayToWitnessScriptHash()); +} + +BOOST_AUTO_TEST_CASE(IsPayToWitnessScriptHash_Invalid_Pushdata) +{ + // A script is not P2WSH if OP_PUSHDATA is used to push the hash. + std::vector<unsigned char> bytes = {OP_0, OP_PUSHDATA1, 32}; + bytes.insert(bytes.end(), 32, 0); + BOOST_CHECK(!CScript(bytes.begin(), bytes.end()).IsPayToWitnessScriptHash()); + + bytes = {OP_0, OP_PUSHDATA2, 32, 0}; + bytes.insert(bytes.end(), 32, 0); + BOOST_CHECK(!CScript(bytes.begin(), bytes.end()).IsPayToWitnessScriptHash()); + + bytes = {OP_0, OP_PUSHDATA4, 32, 0, 0, 0}; + bytes.insert(bytes.end(), 32, 0); + BOOST_CHECK(!CScript(bytes.begin(), bytes.end()).IsPayToWitnessScriptHash()); +} + +namespace { + +bool IsExpectedWitnessProgram(const CScript& script, const int expectedVersion, const std::vector<unsigned char>& expectedProgram) +{ + int actualVersion; + std::vector<unsigned char> actualProgram; + if (!script.IsWitnessProgram(actualVersion, actualProgram)) { + return false; + } + BOOST_CHECK_EQUAL(actualVersion, expectedVersion); + BOOST_CHECK(actualProgram == expectedProgram); + return true; +} + +bool IsNoWitnessProgram(const CScript& script) +{ + int dummyVersion; + std::vector<unsigned char> dummyProgram; + return !script.IsWitnessProgram(dummyVersion, dummyProgram); +} + +} // anonymous namespace + +BOOST_AUTO_TEST_CASE(IsWitnessProgram_Valid) +{ + // Witness programs have a minimum data push of 2 bytes. + std::vector<unsigned char> program = {42, 18}; + CScript wit; + wit << OP_0 << program; + BOOST_CHECK(IsExpectedWitnessProgram(wit, 0, program)); + + wit.clear(); + // Witness programs have a maximum data push of 40 bytes. + program.resize(40); + wit << OP_16 << program; + BOOST_CHECK(IsExpectedWitnessProgram(wit, 16, program)); + + program.resize(32); + std::vector<unsigned char> bytes = {OP_5, static_cast<unsigned char>(program.size())}; + bytes.insert(bytes.end(), program.begin(), program.end()); + BOOST_CHECK(IsExpectedWitnessProgram(CScript(bytes.begin(), bytes.end()), 5, program)); +} + +BOOST_AUTO_TEST_CASE(IsWitnessProgram_Invalid_Version) +{ + std::vector<unsigned char> program(10); + CScript nowit; + nowit << OP_1NEGATE << program; + BOOST_CHECK(IsNoWitnessProgram(nowit)); +} + +BOOST_AUTO_TEST_CASE(IsWitnessProgram_Invalid_Size) +{ + std::vector<unsigned char> program(1); + CScript nowit; + nowit << OP_0 << program; + BOOST_CHECK(IsNoWitnessProgram(nowit)); + + nowit.clear(); + program.resize(41); + nowit << OP_0 << program; + BOOST_CHECK(IsNoWitnessProgram(nowit)); +} + +BOOST_AUTO_TEST_CASE(IsWitnessProgram_Invalid_Nop) +{ + std::vector<unsigned char> program(10); + CScript nowit; + nowit << OP_0 << OP_NOP << program; + BOOST_CHECK(IsNoWitnessProgram(nowit)); +} + +BOOST_AUTO_TEST_CASE(IsWitnessProgram_Invalid_EmptyScript) +{ + CScript nowit; + BOOST_CHECK(IsNoWitnessProgram(nowit)); +} + +BOOST_AUTO_TEST_CASE(IsWitnessProgram_Invalid_Pushdata) +{ + // A script is no witness program if OP_PUSHDATA is used to push the hash. + std::vector<unsigned char> bytes = {OP_0, OP_PUSHDATA1, 32}; + bytes.insert(bytes.end(), 32, 0); + BOOST_CHECK(IsNoWitnessProgram(CScript(bytes.begin(), bytes.end()))); + + bytes = {OP_0, OP_PUSHDATA2, 32, 0}; + bytes.insert(bytes.end(), 32, 0); + BOOST_CHECK(IsNoWitnessProgram(CScript(bytes.begin(), bytes.end()))); + + bytes = {OP_0, OP_PUSHDATA4, 32, 0, 0, 0}; + bytes.insert(bytes.end(), 32, 0); + BOOST_CHECK(IsNoWitnessProgram(CScript(bytes.begin(), bytes.end()))); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp index 1dcee23bbb..478d61d5e2 100644 --- a/src/test/timedata_tests.cpp +++ b/src/test/timedata_tests.cpp @@ -96,9 +96,10 @@ BOOST_AUTO_TEST_CASE(addtimedata) // not to fix this because it prevents possible attacks. See the comment in AddTimeData() or issue #4521 // for a more detailed explanation. MultiAddTimeData(2, 100); // filter median is 100 now, but nTimeOffset will not change + // We want this test to end with nTimeOffset==0, otherwise subsequent tests of the suite will fail. BOOST_CHECK_EQUAL(GetTimeOffset(), 0); - // We want this test to end with nTimeOffset==0, otherwise subsequent tests of the suite will fail. + TestOnlyResetTimeData(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index c968e4d124..211153f06c 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -180,10 +180,9 @@ ChainTestingSetup::~ChainTestingSetup() m_node.banman.reset(); m_node.addrman.reset(); m_node.args = nullptr; - UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman); + WITH_LOCK(::cs_main, UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman)); m_node.mempool.reset(); m_node.scheduler.reset(); - m_node.chainman->Reset(); m_node.chainman.reset(); } diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp index 1aed492c3c..49535855f9 100644 --- a/src/test/util/validation.cpp +++ b/src/test/util/validation.cpp @@ -7,6 +7,7 @@ #include <util/check.h> #include <util/time.h> #include <validation.h> +#include <validationinterface.h> void TestChainState::ResetIbd() { @@ -20,3 +21,8 @@ void TestChainState::JumpOutOfIbd() m_cached_finished_ibd = true; Assert(!IsInitialBlockDownload()); } + +void ValidationInterfaceTest::BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) +{ + obj.BlockConnected(block, pindex); +} diff --git a/src/test/util/validation.h b/src/test/util/validation.h index b13aa0be60..b0bc717b6c 100644 --- a/src/test/util/validation.h +++ b/src/test/util/validation.h @@ -7,6 +7,8 @@ #include <validation.h> +class CValidationInterface; + struct TestChainState : public CChainState { /** Reset the ibd cache to its initial state */ void ResetIbd(); @@ -14,4 +16,10 @@ struct TestChainState : public CChainState { void JumpOutOfIbd(); }; +class ValidationInterfaceTest +{ +public: + static void BlockConnected(CValidationInterface& obj, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex); +}; + #endif // BITCOIN_TEST_UTIL_VALIDATION_H diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 9f78215de2..1881573e7a 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -17,6 +17,7 @@ #include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC #include <util/moneystr.h> #include <util/overflow.h> +#include <util/readwritefile.h> #include <util/spanparsing.h> #include <util/strencodings.h> #include <util/string.h> @@ -24,9 +25,10 @@ #include <util/vector.h> #include <array> -#include <optional> +#include <fstream> #include <limits> #include <map> +#include <optional> #include <stdint.h> #include <string.h> #include <thread> @@ -2592,4 +2594,49 @@ BOOST_AUTO_TEST_CASE(util_ParseByteUnits) BOOST_CHECK(!ParseByteUnits("1x", noop)); } +BOOST_AUTO_TEST_CASE(util_ReadBinaryFile) +{ + fs::path tmpfolder = m_args.GetDataDirBase(); + fs::path tmpfile = tmpfolder / "read_binary.dat"; + std::string expected_text; + for (int i = 0; i < 30; i++) { + expected_text += "0123456789"; + } + { + std::ofstream file{tmpfile}; + file << expected_text; + } + { + // read all contents in file + auto [valid, text] = ReadBinaryFile(tmpfile); + BOOST_CHECK(valid); + BOOST_CHECK_EQUAL(text, expected_text); + } + { + // read half contents in file + auto [valid, text] = ReadBinaryFile(tmpfile, expected_text.size() / 2); + BOOST_CHECK(valid); + BOOST_CHECK_EQUAL(text, expected_text.substr(0, expected_text.size() / 2)); + } + { + // read from non-existent file + fs::path invalid_file = tmpfolder / "invalid_binary.dat"; + auto [valid, text] = ReadBinaryFile(invalid_file); + BOOST_CHECK(!valid); + BOOST_CHECK(text.empty()); + } +} + +BOOST_AUTO_TEST_CASE(util_WriteBinaryFile) +{ + fs::path tmpfolder = m_args.GetDataDirBase(); + fs::path tmpfile = tmpfolder / "write_binary.dat"; + std::string expected_text = "bitcoin"; + auto valid = WriteBinaryFile(tmpfile, expected_text); + std::string actual_text; + std::ifstream file{tmpfile}; + file >> actual_text; + BOOST_CHECK(valid); + BOOST_CHECK_EQUAL(actual_text, expected_text); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index 1beef5cf04..b0d7389d39 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -72,9 +72,6 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) // The view cache should be empty since we had to destruct to downsize. BOOST_CHECK(!c1.CoinsTip().HaveCoinInCache(outpoint)); } - - // Avoid triggering the address sanitizer. - WITH_LOCK(::cs_main, manager.Unload()); } //! Test UpdateTip behavior for both active and background chainstates. diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 26392e690d..5d0ec593e3 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -99,8 +99,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) // Let scheduler events finish running to avoid accessing memory that is going to be unloaded SyncWithValidationInterfaceQueue(); - - WITH_LOCK(::cs_main, manager.Unload()); } //! Test rebalancing the caches associated with each chainstate. |