diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/addrman_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/blockencodings_tests.cpp | 45 | ||||
-rw-r--r-- | src/test/coins_tests.cpp | 9 | ||||
-rw-r--r-- | src/test/dbwrapper_tests.cpp | 8 | ||||
-rw-r--r-- | src/test/descriptor_tests.cpp | 50 | ||||
-rw-r--r-- | src/test/getarg_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/net_tests.cpp | 38 | ||||
-rw-r--r-- | src/test/rpc_tests.cpp | 3 | ||||
-rw-r--r-- | src/test/serialize_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/sighash_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 46 |
11 files changed, 162 insertions, 45 deletions
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index 8c2873d916..55fe19cebe 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -34,7 +34,7 @@ public: int RandomInt(int nMax) override { - state = (CHashWriter(SER_GETHASH, 0) << state).GetHash().GetCheapHash(); + state = (CHashWriter(SER_GETHASH, 0) << state).GetCheapHash(); return (unsigned int)(state % nMax); } diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 5131fe8235..309b8d2d06 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -344,4 +344,49 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]); } +BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) { + // Check that the highest legal index is decoded correctly + BlockTransactionsRequest req0; + req0.blockhash = InsecureRand256(); + req0.indexes.resize(1); + req0.indexes[0] = 0xffff; + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << req0; + + BlockTransactionsRequest req1; + stream >> req1; + BOOST_CHECK_EQUAL(req0.indexes.size(), req1.indexes.size()); + BOOST_CHECK_EQUAL(req0.indexes[0], req1.indexes[0]); +} + +BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) { + // Any set of index deltas that starts with N values that sum to (0x10000 - N) + // causes the edge-case overflow that was originally not checked for. Such + // a request cannot be created by serializing a real BlockTransactionsRequest + // due to the overflow, so here we'll serialize from raw deltas. + BlockTransactionsRequest req0; + req0.blockhash = InsecureRand256(); + req0.indexes.resize(3); + req0.indexes[0] = 0x7000; + req0.indexes[1] = 0x10000 - 0x7000 - 2; + req0.indexes[2] = 0; + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << req0.blockhash; + WriteCompactSize(stream, req0.indexes.size()); + WriteCompactSize(stream, req0.indexes[0]); + WriteCompactSize(stream, req0.indexes[1]); + WriteCompactSize(stream, req0.indexes[2]); + + BlockTransactionsRequest req1; + try { + stream >> req1; + // before patch: deserialize above succeeds and this check fails, demonstrating the overflow + BOOST_CHECK(req1.indexes[1] < req1.indexes[2]); + // this shouldn't be reachable before or after patch + BOOST_CHECK(0); + } catch(std::ios_base::failure &) { + // deserialize should fail + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 521312f1b7..d3cbaedf00 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -2,17 +2,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <attributes.h> #include <coins.h> +#include <consensus/validation.h> #include <script/standard.h> +#include <test/test_bitcoin.h> #include <uint256.h> #include <undo.h> #include <util/strencodings.h> -#include <test/test_bitcoin.h> #include <validation.h> -#include <consensus/validation.h> -#include <vector> #include <map> +#include <vector> #include <boost/test/unit_test.hpp> @@ -36,7 +37,7 @@ class CCoinsViewTest : public CCoinsView std::map<COutPoint, Coin> map_; public: - bool GetCoin(const COutPoint& outpoint, Coin& coin) const override + NODISCARD bool GetCoin(const COutPoint& outpoint, Coin& coin) const override { std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); if (it == map_.end()) { diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 9957ac074b..1034d4ade2 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -102,15 +102,15 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) char key_res; uint256 val_res; - it->GetKey(key_res); - it->GetValue(val_res); + BOOST_REQUIRE(it->GetKey(key_res)); + BOOST_REQUIRE(it->GetValue(val_res)); BOOST_CHECK_EQUAL(key_res, key); BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString()); it->Next(); - it->GetKey(key_res); - it->GetValue(val_res); + BOOST_REQUIRE(it->GetKey(key_res)); + BOOST_REQUIRE(it->GetValue(val_res)); BOOST_CHECK_EQUAL(key_res, key2); BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString()); diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 57e4b067c0..8da8cfc00c 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -62,7 +62,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std: // Check that both versions serialize back to the public version. std::string pub1 = parse_priv->ToString(); - std::string pub2 = parse_priv->ToString(); + std::string pub2 = parse_pub->ToString(); BOOST_CHECK_EQUAL(pub, pub1); BOOST_CHECK_EQUAL(pub, pub2); @@ -79,19 +79,42 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std: BOOST_CHECK_EQUAL(parse_pub->IsRange(), (flags & RANGE) != 0); BOOST_CHECK_EQUAL(parse_priv->IsRange(), (flags & RANGE) != 0); - - // Is not ranged descriptor, only a single result is expected. + // * For ranged descriptors, the `scripts` parameter is a list of expected result outputs, for subsequent + // positions to evaluate the descriptors on (so the first element of `scripts` is for evaluating the + // descriptor at 0; the second at 1; and so on). To verify this, we evaluate the descriptors once for + // each element in `scripts`. + // * For non-ranged descriptors, we evaluate the descriptors at positions 0, 1, and 2, but expect the + // same result in each case, namely the first element of `scripts`. Because of that, the size of + // `scripts` must be one in that case. if (!(flags & RANGE)) assert(scripts.size() == 1); - size_t max = (flags & RANGE) ? scripts.size() : 3; + + // Iterate over the position we'll evaluate the descriptors in. for (size_t i = 0; i < max; ++i) { + // Call the expected result scripts `ref`. const auto& ref = scripts[(flags & RANGE) ? i : 0]; + // When t=0, evaluate the `prv` descriptor; when t=1, evaluate the `pub` descriptor. for (int t = 0; t < 2; ++t) { + // When the descriptor is hardened, evaluate with access to the private keys inside. const FlatSigningProvider& key_provider = (flags & HARDENED) ? keys_priv : keys_pub; - FlatSigningProvider script_provider; - std::vector<CScript> spks; - BOOST_CHECK((t ? parse_priv : parse_pub)->Expand(i, key_provider, spks, script_provider)); + + // Evaluate the descriptor selected by `t` in poisition `i`. + FlatSigningProvider script_provider, script_provider_cached; + std::vector<CScript> spks, spks_cached; + std::vector<unsigned char> cache; + BOOST_CHECK((t ? parse_priv : parse_pub)->Expand(i, key_provider, spks, script_provider, &cache)); + + // Compare the output with the expected result. BOOST_CHECK_EQUAL(spks.size(), ref.size()); + + // Try to expand again using cached data, and compare. + BOOST_CHECK(parse_pub->ExpandFromCache(i, cache, spks_cached, script_provider_cached)); + BOOST_CHECK(spks == spks_cached); + BOOST_CHECK(script_provider.pubkeys == script_provider_cached.pubkeys); + BOOST_CHECK(script_provider.scripts == script_provider_cached.scripts); + BOOST_CHECK(script_provider.origins == script_provider_cached.origins); + + // For each of the produced scripts, verify solvability, and when possible, try to sign a transaction spending it. for (size_t n = 0; n < spks.size(); ++n) { BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n].begin(), spks[n].end())); BOOST_CHECK_EQUAL(IsSolvable(Merge(key_provider, script_provider), spks[n]), (flags & UNSOLVABLE) == 0); @@ -102,7 +125,19 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std: spend.vout.resize(1); BOOST_CHECK_MESSAGE(SignSignature(Merge(keys_priv, script_provider), spks[n], spend, 0, 1, SIGHASH_ALL), prv); } + + /* Infer a descriptor from the generated script, and verify its solvability and that it roundtrips. */ + auto inferred = InferDescriptor(spks[n], script_provider); + BOOST_CHECK_EQUAL(inferred->IsSolvable(), !(flags & UNSOLVABLE)); + std::vector<CScript> spks_inferred; + FlatSigningProvider provider_inferred; + BOOST_CHECK(inferred->Expand(0, provider_inferred, spks_inferred, provider_inferred)); + BOOST_CHECK_EQUAL(spks_inferred.size(), 1); + BOOST_CHECK(spks_inferred[0] == spks[n]); + BOOST_CHECK_EQUAL(IsSolvable(provider_inferred, spks_inferred[0]), !(flags & UNSOLVABLE)); + BOOST_CHECK(provider_inferred.origins == script_provider.origins); } + // Test whether the observed key path is present in the 'paths' variable (which contains expected, unobserved paths), // and then remove it from that set. for (const auto& origin : script_provider.origins) { @@ -111,6 +146,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std: } } } + // Verify no expected paths remain that were not observed. BOOST_CHECK_MESSAGE(left_paths.empty(), "Not all expected key paths found: " + prv); } diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 0432ede3e0..14ddf4d10e 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -28,7 +28,7 @@ static void ResetArgs(const std::string& strArg) vecChar.push_back(s.c_str()); std::string error; - gArgs.ParseParameters(vecChar.size(), vecChar.data(), error); + BOOST_CHECK(gArgs.ParseParameters(vecChar.size(), vecChar.data(), error)); } static void SetupArgs(const std::vector<std::string>& args) diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 213afed730..c1ee231d8a 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -189,4 +189,42 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test) BOOST_CHECK(pnode2->fFeeler == false); } +// prior to PR #14728, this test triggers an undefined behavior +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 + { + LOCK(cs_mapLocalHost); + in_addr ipv4AddrLocal; + ipv4AddrLocal.s_addr = 0x0100007f; + CNetAddr addr = CNetAddr(ipv4AddrLocal); + LocalServiceInfo lsi; + lsi.nScore = 23; + lsi.nPort = 42; + mapLocalHost[addr] = lsi; + } + + // create a peer with an IPv4 address + in_addr ipv4AddrPeer; + ipv4AddrPeer.s_addr = 0xa0b0c001; + CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK); + std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, false); + pnode->fSuccessfullyConnected.store(true); + + // the peer claims to be reaching us via IPv6 + in6_addr ipv6AddrLocal; + memset(ipv6AddrLocal.s6_addr, 0, 16); + ipv6AddrLocal.s6_addr[0] = 0xcc; + CAddress addrLocal = CAddress(CService(ipv6AddrLocal, 7777), NODE_NETWORK); + pnode->SetAddrLocal(addrLocal); + + // before patch, this causes undefined behavior detectable with clang's -fsanitize=memory + AdvertiseLocal(&*pnode); + + // suppress no-checks-run warning; if this test fails, it's by triggering a sanitizer + BOOST_CHECK(1); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 121b72a5f7..ff48398925 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -129,9 +129,6 @@ BOOST_AUTO_TEST_CASE(rpc_createraw_op_return) { BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\"}")); - // Allow more than one data transaction output - BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}")); - // Key not "data" (bad address) BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), std::runtime_error); diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index e754996d2f..002f61f6a2 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(varints) } for (uint64_t i = 0; i < 100000000000ULL; i += 999999937) { - uint64_t j = -1; + uint64_t j = std::numeric_limits<uint64_t>::max(); ss >> VARINT(j); BOOST_CHECK_MESSAGE(i == j, "decoded:" << j << " expected:" << i); } diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index c329844341..773204a00c 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -105,7 +105,7 @@ void static RandomTransaction(CMutableTransaction &tx, bool fSingle) { txin.prevout.hash = InsecureRand256(); txin.prevout.n = InsecureRandBits(2); RandomScript(txin.scriptSig); - txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : (unsigned int)-1; + txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : std::numeric_limits<uint32_t>::max(); } for (int out = 0; out < outs; out++) { tx.vout.push_back(CTxOut()); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index ff19b12a9c..9acebdd820 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -187,7 +187,7 @@ struct TestArgsManager : public ArgsManager m_config_args.clear(); } std::string error; - ReadConfigStream(streamConfig, error); + BOOST_REQUIRE(ReadConfigStream(streamConfig, error)); } void SetNetworkOnlyArg(const std::string arg) { @@ -210,13 +210,13 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters) std::string error; testArgs.SetupArgs(4, avail_args); - testArgs.ParseParameters(0, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(0, (char**)argv_test, error)); BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty()); - testArgs.ParseParameters(1, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error)); BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty()); - testArgs.ParseParameters(7, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error)); // expectation: -ignored is ignored (program name argument), // -a, -b and -ccc end up in map, -d ignored because it is after // a non-option argument (non-GNU option parsing) @@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArg) "ignored", "-a", "-nob", "-c=0", "-d=1", "-e=false", "-f=true"}; std::string error; testArgs.SetupArgs(6, avail_args); - testArgs.ParseParameters(7, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error)); // Each letter should be set. for (const char opt : "abcdef") @@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases) const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"}; testArgs.SetupArgs(2, avail_args); std::string error; - testArgs.ParseParameters(4, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(4, (char**)argv_test, error)); // This was passed twice, second one overrides the negative setting. BOOST_CHECK(!testArgs.IsArgNegated("-foo")); @@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases) // Config test const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n"; - testArgs.ParseParameters(1, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error)); testArgs.ReadConfigString(conf_test); // This was passed twice, second one overrides the negative setting, @@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases) // Combined test const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"}; const char *combo_test_conf = "foo=1\nnobar=1\n"; - testArgs.ParseParameters(3, (char**)combo_test_args, error); + BOOST_CHECK(testArgs.ParseParameters(3, (char**)combo_test_args, error)); testArgs.ReadConfigString(combo_test_conf); // Command line overrides, but doesn't erase old setting @@ -557,38 +557,38 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1"; std::string error; - test_args.ParseParameters(0, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "main"); - test_args.ParseParameters(2, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_regtest, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest"); - test_args.ParseParameters(3, (char**)argv_test_no_reg, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(3, (char**)argv_both, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error)); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); - test_args.ParseParameters(0, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_regtest, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); - test_args.ParseParameters(3, (char**)argv_test_no_reg, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(3, (char**)argv_both, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); @@ -596,23 +596,23 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) // [test] regtest=1 potentially relevant) doesn't break things test_args.SelectConfigNetwork("test"); - test_args.ParseParameters(0, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_regtest, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); - test_args.ParseParameters(2, (char**)argv_test_no_reg, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_test_no_reg, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(3, (char**)argv_both, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); } |