diff options
48 files changed, 514 insertions, 459 deletions
diff --git a/src/bench/sign_transaction.cpp b/src/bench/sign_transaction.cpp index 7b2a75942c..3f0635711d 100644 --- a/src/bench/sign_transaction.cpp +++ b/src/bench/sign_transaction.cpp @@ -75,12 +75,13 @@ static void SignTransactionSchnorr(benchmark::Bench& bench) { SignTransactionSin static void SignSchnorrTapTweakBenchmark(benchmark::Bench& bench, bool use_null_merkle_root) { + FastRandomContext rng; ECC_Context ecc_context{}; auto key = GenerateRandomKey(); - auto msg = InsecureRand256(); - auto merkle_root = use_null_merkle_root ? uint256() : InsecureRand256(); - auto aux = InsecureRand256(); + auto msg = rng.rand256(); + auto merkle_root = use_null_merkle_root ? uint256() : rng.rand256(); + auto aux = rng.rand256(); std::vector<unsigned char> sig(64); bench.minEpochIterations(100).run([&] { diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index bb3defb93e..0491c8283f 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -84,14 +84,14 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58) BOOST_AUTO_TEST_CASE(base58_random_encode_decode) { for (int n = 0; n < 1000; ++n) { - unsigned int len = 1 + InsecureRandBits(8); - unsigned int zeroes = InsecureRandBool() ? InsecureRandRange(len + 1) : 0; - auto data = Cat(std::vector<unsigned char>(zeroes, '\000'), g_insecure_rand_ctx.randbytes(len - zeroes)); + unsigned int len = 1 + m_rng.randbits(8); + unsigned int zeroes = m_rng.randbool() ? m_rng.randrange(len + 1) : 0; + auto data = Cat(std::vector<unsigned char>(zeroes, '\000'), m_rng.randbytes(len - zeroes)); auto encoded = EncodeBase58Check(data); std::vector<unsigned char> decoded; - auto ok_too_small = DecodeBase58Check(encoded, decoded, InsecureRandRange(len)); + auto ok_too_small = DecodeBase58Check(encoded, decoded, m_rng.randrange(len)); BOOST_CHECK(!ok_too_small); - auto ok = DecodeBase58Check(encoded, decoded, len + InsecureRandRange(257 - len)); + auto ok = DecodeBase58Check(encoded, decoded, len + m_rng.randrange(257 - len)); BOOST_CHECK(ok); BOOST_CHECK(data == decoded); } diff --git a/src/test/bip324_tests.cpp b/src/test/bip324_tests.cpp index 1caea4000c..adabb7ef57 100644 --- a/src/test/bip324_tests.cpp +++ b/src/test/bip324_tests.cpp @@ -21,6 +21,7 @@ namespace { +struct BIP324Test : BasicTestingSetup { void TestBIP324PacketVector( uint32_t in_idx, const std::string& in_priv_ours_hex, @@ -116,7 +117,7 @@ void TestBIP324PacketVector( // Seek to the numbered packet. if (in_idx == 0 && error == 12) continue; - uint32_t dec_idx = in_idx ^ (error == 12 ? (1U << InsecureRandRange(16)) : 0); + uint32_t dec_idx = in_idx ^ (error == 12 ? (1U << m_rng.randrange(16)) : 0); for (uint32_t i = 0; i < dec_idx; ++i) { unsigned use_idx = i < in_idx ? i : 0; bool dec_ignore{false}; @@ -128,7 +129,7 @@ void TestBIP324PacketVector( // Decrypt length auto to_decrypt = ciphertext; if (error >= 2 && error <= 9) { - to_decrypt[InsecureRandRange(to_decrypt.size())] ^= std::byte(1U << (error - 2)); + to_decrypt[m_rng.randrange(to_decrypt.size())] ^= std::byte(1U << (error - 2)); } // Decrypt length and resize ciphertext to accommodate. @@ -139,7 +140,7 @@ void TestBIP324PacketVector( auto dec_aad = in_aad; if (error == 10) { if (in_aad.size() == 0) continue; - dec_aad[InsecureRandRange(dec_aad.size())] ^= std::byte(1U << InsecureRandRange(8)); + dec_aad[m_rng.randrange(dec_aad.size())] ^= std::byte(1U << m_rng.randrange(8)); } if (error == 11) dec_aad.push_back({}); @@ -156,10 +157,11 @@ void TestBIP324PacketVector( } } } +}; // struct BIP324Test } // namespace -BOOST_FIXTURE_TEST_SUITE(bip324_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(bip324_tests, BIP324Test) BOOST_AUTO_TEST_CASE(packet_test_vectors) { // BIP324 key derivation uses network magic in the HKDF process. We use mainnet params here diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index b0749c851c..3a33bdb7ec 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -356,7 +356,7 @@ BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) { BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BlockTransactionsRequest req1; - req1.blockhash = InsecureRand256(); + req1.blockhash = m_rng.rand256(); req1.indexes.resize(4); req1.indexes[0] = 0; req1.indexes[1] = 1; @@ -380,7 +380,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) { // Check that the highest legal index is decoded correctly BlockTransactionsRequest req0; - req0.blockhash = InsecureRand256(); + req0.blockhash = m_rng.rand256(); req0.indexes.resize(1); req0.indexes[0] = 0xffff; DataStream stream{}; @@ -398,7 +398,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) { // 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.blockhash = m_rng.rand256(); req0.indexes.resize(3); req0.indexes[0] = 0x7000; req0.indexes[1] = 0x10000 - 0x7000 - 2; diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp index 0c6e2e752d..706049e531 100644 --- a/src/test/bloom_tests.cpp +++ b/src/test/bloom_tests.cpp @@ -22,7 +22,13 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(bloom_tests, BasicTestingSetup) +namespace bloom_tests { +struct BloomTest : public BasicTestingSetup { + std::vector<unsigned char> RandomData(); +}; +} // namespace bloom_tests + +BOOST_FIXTURE_TEST_SUITE(bloom_tests, BloomTest) BOOST_AUTO_TEST_CASE(bloom_create_insert_serialize) { @@ -455,9 +461,9 @@ BOOST_AUTO_TEST_CASE(merkle_block_4_test_update_none) BOOST_CHECK(!filter.contains(COutPoint(Txid::FromHex("02981fa052f0481dbc5868f4fc2166035a10f27a03cfd2de67326471df5bc041").value(), 0))); } -static std::vector<unsigned char> RandomData() +std::vector<unsigned char> BloomTest::RandomData() { - uint256 r = InsecureRand256(); + uint256 r = m_rng.rand256(); return std::vector<unsigned char>(r.begin(), r.end()); } diff --git a/src/test/checkqueue_tests.cpp b/src/test/checkqueue_tests.cpp index 7810d91a77..a9a1e47070 100644 --- a/src/test/checkqueue_tests.cpp +++ b/src/test/checkqueue_tests.cpp @@ -34,7 +34,9 @@ struct NoLockLoggingTestingSetup : public TestingSetup { #endif }; -BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, NoLockLoggingTestingSetup) +struct CheckQueueTest : NoLockLoggingTestingSetup { + void Correct_Queue_range(std::vector<size_t> range); +}; static const unsigned int QUEUE_BATCH_SIZE = 128; static const int SCRIPT_CHECK_THREADS = 3; @@ -156,7 +158,7 @@ typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue; /** This test case checks that the CCheckQueue works properly * with each specified size_t Checks pushed. */ -static void Correct_Queue_range(std::vector<size_t> range) +void CheckQueueTest::Correct_Queue_range(std::vector<size_t> range) { auto small_queue = std::make_unique<Correct_Queue>(QUEUE_BATCH_SIZE, SCRIPT_CHECK_THREADS); // Make vChecks here to save on malloc (this test can be slow...) @@ -168,7 +170,7 @@ static void Correct_Queue_range(std::vector<size_t> range) CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get()); while (total) { vChecks.clear(); - vChecks.resize(std::min<size_t>(total, InsecureRandRange(10))); + vChecks.resize(std::min<size_t>(total, m_rng.randrange(10))); total -= vChecks.size(); control.Add(std::move(vChecks)); } @@ -177,6 +179,8 @@ static void Correct_Queue_range(std::vector<size_t> range) } } +BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, CheckQueueTest) + /** Test that 0 checks is correct */ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) @@ -207,7 +211,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random) { std::vector<size_t> range; range.reserve(100000/1000); - for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)InsecureRandRange(std::min((size_t)1000, ((size_t)100000) - i)))) + for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)m_rng.randrange(std::min((size_t)1000, ((size_t)100000) - i)))) range.push_back(i); Correct_Queue_range(range); } @@ -221,7 +225,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure) CCheckQueueControl<FailingCheck> control(fail_queue.get()); size_t remaining = i; while (remaining) { - size_t r = InsecureRandRange(10); + size_t r = m_rng.randrange(10); std::vector<FailingCheck> vChecks; vChecks.reserve(r); @@ -268,7 +272,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck) { CCheckQueueControl<UniqueCheck> control(queue.get()); while (total) { - size_t r = InsecureRandRange(10); + size_t r = m_rng.randrange(10); std::vector<UniqueCheck> vChecks; for (size_t k = 0; k < r && total; k++) vChecks.emplace_back(--total); @@ -300,7 +304,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory) { CCheckQueueControl<MemoryCheck> control(queue.get()); while (total) { - size_t r = InsecureRandRange(10); + size_t r = m_rng.randrange(10); std::vector<MemoryCheck> vChecks; for (size_t k = 0; k < r && total; k++) { total--; diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index fb929a2b0e..4873f76dd9 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -35,10 +35,13 @@ bool operator==(const Coin &a, const Coin &b) { class CCoinsViewTest : public CCoinsView { + FastRandomContext& m_rng; uint256 hashBestBlock_; std::map<COutPoint, Coin> map_; public: + CCoinsViewTest(FastRandomContext& rng) : m_rng{rng} {} + [[nodiscard]] bool GetCoin(const COutPoint& outpoint, Coin& coin) const override { std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); @@ -46,7 +49,7 @@ public: return false; } coin = it->second; - if (coin.IsSpent() && InsecureRandBool() == 0) { + if (coin.IsSpent() && m_rng.randbool() == 0) { // Randomly return false in case of an empty entry. return false; } @@ -61,7 +64,7 @@ public: if (it->second.IsDirty()) { // Same optimization used in CCoinsViewDB is to only write dirty entries. map_[it->first] = it->second.coin; - if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) { + if (it->second.coin.IsSpent() && m_rng.randrange(3) == 0) { // Randomly delete empty entries on write. map_.erase(it->first); } @@ -105,6 +108,7 @@ BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup) static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; +struct CacheTest : BasicTestingSetup { // This is a large randomized insert/remove simulation test on a variable-size // stack of caches on top of CCoinsViewTest. // @@ -144,26 +148,26 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) std::vector<Txid> txids; txids.resize(NUM_SIMULATION_ITERATIONS / 8); for (unsigned int i = 0; i < txids.size(); i++) { - txids[i] = Txid::FromUint256(InsecureRand256()); + txids[i] = Txid::FromUint256(m_rng.rand256()); } for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { // Do a random modification. { - auto txid = txids[InsecureRandRange(txids.size())]; // txid we're going to modify in this iteration. + auto txid = txids[m_rng.randrange(txids.size())]; // txid we're going to modify in this iteration. Coin& coin = result[COutPoint(txid, 0)]; // Determine whether to test HaveCoin before or after Access* (or both). As these functions // can influence each other's behaviour by pulling things into the cache, all combinations // are tested. - bool test_havecoin_before = InsecureRandBits(2) == 0; - bool test_havecoin_after = InsecureRandBits(2) == 0; + bool test_havecoin_before = m_rng.randbits(2) == 0; + bool test_havecoin_after = m_rng.randbits(2) == 0; bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false; // Infrequently, test usage of AccessByTxid instead of AccessCoin - the // former just delegates to the latter and returns the first unspent in a txn. - const Coin& entry = (InsecureRandRange(500) == 0) ? + const Coin& entry = (m_rng.randrange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0)); BOOST_CHECK(coin == entry); @@ -176,23 +180,23 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) BOOST_CHECK(ret == !entry.IsSpent()); } - if (InsecureRandRange(5) == 0 || coin.IsSpent()) { + if (m_rng.randrange(5) == 0 || coin.IsSpent()) { Coin newcoin; - newcoin.out.nValue = InsecureRandMoneyAmount(); + newcoin.out.nValue = RandMoney(m_rng); newcoin.nHeight = 1; // Infrequently test adding unspendable coins. - if (InsecureRandRange(16) == 0 && coin.IsSpent()) { - newcoin.out.scriptPubKey.assign(1 + InsecureRandBits(6), OP_RETURN); + if (m_rng.randrange(16) == 0 && coin.IsSpent()) { + newcoin.out.scriptPubKey.assign(1 + m_rng.randbits(6), OP_RETURN); BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable()); added_an_unspendable_entry = true; } else { // Random sizes so we can test memory usage accounting - newcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); + newcoin.out.scriptPubKey.assign(m_rng.randbits(6), 0); (coin.IsSpent() ? added_an_entry : updated_an_entry) = true; coin = newcoin; } - bool is_overwrite = !coin.IsSpent() || InsecureRand32() & 1; + bool is_overwrite = !coin.IsSpent() || m_rng.rand32() & 1; stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), is_overwrite); } else { // Spend the coin. @@ -203,15 +207,15 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) } // Once every 10 iterations, remove a random entry from the cache - if (InsecureRandRange(10) == 0) { - COutPoint out(txids[InsecureRand32() % txids.size()], 0); - int cacheid = InsecureRand32() % stack.size(); + if (m_rng.randrange(10) == 0) { + COutPoint out(txids[m_rng.rand32() % txids.size()], 0); + int cacheid = m_rng.rand32() % stack.size(); stack[cacheid]->Uncache(out); uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); } // Once every 1000 iterations and at the end, verify the full cache. - if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + if (m_rng.randrange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { for (const auto& entry : result) { bool have = stack.back()->HaveCoin(entry.first); const Coin& coin = stack.back()->AccessCoin(entry.first); @@ -229,27 +233,27 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) } } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, flush an intermediate cache - if (stack.size() > 1 && InsecureRandBool() == 0) { - unsigned int flushIndex = InsecureRandRange(stack.size() - 1); - if (fake_best_block) stack[flushIndex]->SetBestBlock(InsecureRand256()); - bool should_erase = InsecureRandRange(4) < 3; + if (stack.size() > 1 && m_rng.randbool() == 0) { + unsigned int flushIndex = m_rng.randrange(stack.size() - 1); + if (fake_best_block) stack[flushIndex]->SetBestBlock(m_rng.rand256()); + bool should_erase = m_rng.randrange(4) < 3; BOOST_CHECK(should_erase ? stack[flushIndex]->Flush() : stack[flushIndex]->Sync()); flushed_without_erase |= !should_erase; } } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && InsecureRandBool() == 0) { + if (stack.size() > 0 && m_rng.randbool() == 0) { //Remove the top cache - if (fake_best_block) stack.back()->SetBestBlock(InsecureRand256()); - bool should_erase = InsecureRandRange(4) < 3; + if (fake_best_block) stack.back()->SetBestBlock(m_rng.rand256()); + bool should_erase = m_rng.randrange(4) < 3; BOOST_CHECK(should_erase ? stack.back()->Flush() : stack.back()->Sync()); flushed_without_erase |= !should_erase; stack.pop_back(); } - if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) { + if (stack.size() == 0 || (stack.size() < 4 && m_rng.randbool())) { //Add a new cache CCoinsView* tip = base; if (stack.size() > 0) { @@ -277,24 +281,26 @@ void SimulationTest(CCoinsView* base, bool fake_best_block) BOOST_CHECK(uncached_an_entry); BOOST_CHECK(flushed_without_erase); } +}; // struct CacheTest // Run the above simulation for multiple base types. -BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) +BOOST_FIXTURE_TEST_CASE(coins_cache_simulation_test, CacheTest) { - CCoinsViewTest base; + CCoinsViewTest base{m_rng}; SimulationTest(&base, false); CCoinsViewDB db_base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}}; SimulationTest(&db_base, true); } +struct UpdateTest : BasicTestingSetup { // Store of all necessary tx and undo data for next test typedef std::map<COutPoint, std::tuple<CTransaction,CTxUndo,Coin>> UtxoData; UtxoData utxoData; UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { assert(utxoSet.size()); - auto utxoSetIt = utxoSet.lower_bound(COutPoint(Txid::FromUint256(InsecureRand256()), 0)); + auto utxoSetIt = utxoSet.lower_bound(COutPoint(Txid::FromUint256(m_rng.rand256()), 0)); if (utxoSetIt == utxoSet.end()) { utxoSetIt = utxoSet.begin(); } @@ -302,6 +308,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { assert(utxoDataIt != utxoData.end()); return utxoDataIt; } +}; // struct UpdateTest // This test is similar to the previous test @@ -309,7 +316,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { // random txs are created and UpdateCoins is used to update the cache stack // In particular it is tested that spending a duplicate coinbase tx // has the expected effect (the other duplicate is overwritten at all cache levels) -BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) +BOOST_FIXTURE_TEST_CASE(updatecoins_simulation_test, UpdateTest) { SeedRandomForTest(SeedRand::ZEROS); @@ -318,7 +325,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) std::map<COutPoint, Coin> result; // The cache stack. - CCoinsViewTest base; // A CCoinsViewTest at the bottom. + CCoinsViewTest base{m_rng}; // A CCoinsViewTest at the bottom. std::vector<std::unique_ptr<CCoinsViewCacheTest>> stack; // A stack of CCoinsViewCaches on top. stack.push_back(std::make_unique<CCoinsViewCacheTest>(&base)); // Start with one cache. @@ -329,7 +336,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) std::set<COutPoint> utxoset; for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { - uint32_t randiter = InsecureRand32(); + uint32_t randiter = m_rng.rand32(); // 19/20 txs add a new transaction if (randiter % 20 < 19) { @@ -337,14 +344,14 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) tx.vin.resize(1); tx.vout.resize(1); tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate - tx.vout[0].scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting - const int height{int(InsecureRand32() >> 1)}; + tx.vout[0].scriptPubKey.assign(m_rng.rand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting + const int height{int(m_rng.rand32() >> 1)}; Coin old_coin; // 2/20 times create a new coinbase if (randiter % 20 < 2 || coinbase_coins.size() < 10) { // 1/10 of those times create a duplicate coinbase - if (InsecureRandRange(10) == 0 && coinbase_coins.size()) { + if (m_rng.randrange(10) == 0 && coinbase_coins.size()) { auto utxod = FindRandomFrom(coinbase_coins); // Reuse the exact same coinbase tx = CMutableTransaction{std::get<0>(utxod->second)}; @@ -454,7 +461,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) } // Once every 1000 iterations and at the end, verify the full cache. - if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + if (m_rng.randrange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { for (const auto& entry : result) { bool have = stack.back()->HaveCoin(entry.first); const Coin& coin = stack.back()->AccessCoin(entry.first); @@ -464,30 +471,30 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) } // One every 10 iterations, remove a random entry from the cache - if (utxoset.size() > 1 && InsecureRandRange(30) == 0) { - stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); + if (utxoset.size() > 1 && m_rng.randrange(30) == 0) { + stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); } - if (disconnected_coins.size() > 1 && InsecureRandRange(30) == 0) { - stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first); + if (disconnected_coins.size() > 1 && m_rng.randrange(30) == 0) { + stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first); } - if (duplicate_coins.size() > 1 && InsecureRandRange(30) == 0) { - stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first); + if (duplicate_coins.size() > 1 && m_rng.randrange(30) == 0) { + stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first); } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, flush an intermediate cache - if (stack.size() > 1 && InsecureRandBool() == 0) { - unsigned int flushIndex = InsecureRandRange(stack.size() - 1); + if (stack.size() > 1 && m_rng.randbool() == 0) { + unsigned int flushIndex = m_rng.randrange(stack.size() - 1); BOOST_CHECK(stack[flushIndex]->Flush()); } } - if (InsecureRandRange(100) == 0) { + if (m_rng.randrange(100) == 0) { // Every 100 iterations, change the cache stack. - if (stack.size() > 0 && InsecureRandBool() == 0) { + if (stack.size() > 0 && m_rng.randbool() == 0) { BOOST_CHECK(stack.back()->Flush()); stack.pop_back(); } - if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) { + if (stack.size() == 0 || (stack.size() < 4 && m_rng.randbool())) { CCoinsView* tip = &base; if (stack.size() > 0) { tip = stack.back().get(); @@ -888,11 +895,12 @@ BOOST_AUTO_TEST_CASE(ccoins_write) } +struct FlushTest : BasicTestingSetup { Coin MakeCoin() { Coin coin; - coin.out.nValue = InsecureRand32(); - coin.nHeight = InsecureRandRange(4096); + coin.out.nValue = m_rng.rand32(); + coin.nHeight = m_rng.randrange(4096); coin.fCoinBase = 0; return coin; } @@ -919,19 +927,19 @@ void TestFlushBehavior( size_t cache_usage; size_t cache_size; - auto flush_all = [&all_caches](bool erase) { + auto flush_all = [this, &all_caches](bool erase) { // Flush in reverse order to ensure that flushes happen from children up. for (auto i = all_caches.rbegin(); i != all_caches.rend(); ++i) { auto& cache = *i; cache->SanityCheck(); // hashBlock must be filled before flushing to disk; value is // unimportant here. This is normally done during connect/disconnect block. - cache->SetBestBlock(InsecureRand256()); + cache->SetBestBlock(m_rng.rand256()); erase ? cache->Flush() : cache->Sync(); } }; - Txid txid = Txid::FromUint256(InsecureRand256()); + Txid txid = Txid::FromUint256(m_rng.rand256()); COutPoint outp = COutPoint(txid, 0); Coin coin = MakeCoin(); // Ensure the coins views haven't seen this coin before. @@ -1022,7 +1030,7 @@ void TestFlushBehavior( // --- Bonus check: ensure that a coin added to the base view via one cache // can be spent by another cache which has never seen it. // - txid = Txid::FromUint256(InsecureRand256()); + txid = Txid::FromUint256(m_rng.rand256()); outp = COutPoint(txid, 0); coin = MakeCoin(); BOOST_CHECK(!base.HaveCoin(outp)); @@ -1045,7 +1053,7 @@ void TestFlushBehavior( // --- Bonus check 2: ensure that a FRESH, spent coin is deleted by Sync() // - txid = Txid::FromUint256(InsecureRand256()); + txid = Txid::FromUint256(m_rng.rand256()); outp = COutPoint(txid, 0); coin = MakeCoin(); CAmount coin_val = coin.out.nValue; @@ -1074,8 +1082,9 @@ void TestFlushBehavior( BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp)); BOOST_CHECK(!base.HaveCoin(outp)); } +}; // struct FlushTest -BOOST_AUTO_TEST_CASE(ccoins_flush_behavior) +BOOST_FIXTURE_TEST_CASE(ccoins_flush_behavior, FlushTest) { // Create two in-memory caches atop a leveldb view. CCoinsViewDB base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}}; diff --git a/src/test/compress_tests.cpp b/src/test/compress_tests.cpp index 13c2740553..7e17e6ef93 100644 --- a/src/test/compress_tests.cpp +++ b/src/test/compress_tests.cpp @@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(compress_p2pk_scripts_not_on_curve) { XOnlyPubKey x_not_on_curve; do { - x_not_on_curve = XOnlyPubKey(g_insecure_rand_ctx.randbytes(32)); + x_not_on_curve = XOnlyPubKey(m_rng.randbytes(32)); } while (x_not_on_curve.IsFullyValid()); // Check that P2PK script with uncompressed pubkey [=> OP_PUSH65 <0x04 .....> OP_CHECKSIG] diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index 9b485a24e2..9913999e10 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -26,10 +26,11 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(crypto_tests, BasicTestingSetup) +namespace crypto_tests { +struct CryptoTest : BasicTestingSetup { template<typename Hasher, typename In, typename Out> -static void TestVector(const Hasher &h, const In &in, const Out &out) { +void TestVector(const Hasher &h, const In &in, const Out &out) { Out hash; BOOST_CHECK(out.size() == h.OUTPUT_SIZE); hash.resize(out.size()); @@ -43,7 +44,7 @@ static void TestVector(const Hasher &h, const In &in, const Out &out) { Hasher hasher(h); size_t pos = 0; while (pos < in.size()) { - size_t len = InsecureRandRange((in.size() - pos + 1) / 2 + 1); + size_t len = m_rng.randrange((in.size() - pos + 1) / 2 + 1); hasher.Write((const uint8_t*)in.data() + pos, len); pos += len; if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) { @@ -57,22 +58,22 @@ static void TestVector(const Hasher &h, const In &in, const Out &out) { } } -static void TestSHA1(const std::string &in, const std::string &hexout) { TestVector(CSHA1(), in, ParseHex(hexout));} -static void TestSHA256(const std::string &in, const std::string &hexout) { TestVector(CSHA256(), in, ParseHex(hexout));} -static void TestSHA512(const std::string &in, const std::string &hexout) { TestVector(CSHA512(), in, ParseHex(hexout));} -static void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVector(CRIPEMD160(), in, ParseHex(hexout));} +void TestSHA1(const std::string &in, const std::string &hexout) { TestVector(CSHA1(), in, ParseHex(hexout));} +void TestSHA256(const std::string &in, const std::string &hexout) { TestVector(CSHA256(), in, ParseHex(hexout));} +void TestSHA512(const std::string &in, const std::string &hexout) { TestVector(CSHA512(), in, ParseHex(hexout));} +void TestRIPEMD160(const std::string &in, const std::string &hexout) { TestVector(CRIPEMD160(), in, ParseHex(hexout));} -static void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { +void TestHMACSHA256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); TestVector(CHMAC_SHA256(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); } -static void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { +void TestHMACSHA512(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); } -static void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) +void TestAES256(const std::string &hexkey, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); std::vector<unsigned char> in = ParseHex(hexin); @@ -91,7 +92,7 @@ static void TestAES256(const std::string &hexkey, const std::string &hexin, cons BOOST_CHECK(buf == in); } -static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout) +void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, bool pad, const std::string &hexin, const std::string &hexout) { std::vector<unsigned char> key = ParseHex(hexkey); std::vector<unsigned char> iv = ParseHex(hexiv); @@ -132,7 +133,7 @@ static void TestAES256CBC(const std::string &hexkey, const std::string &hexiv, b } } -static void TestChaCha20(const std::string &hex_message, const std::string &hexkey, ChaCha20::Nonce96 nonce, uint32_t seek, const std::string& hexout) +void TestChaCha20(const std::string &hex_message, const std::string &hexkey, ChaCha20::Nonce96 nonce, uint32_t seek, const std::string& hexout) { auto key = ParseHex<std::byte>(hexkey); assert(key.size() == 32); @@ -164,8 +165,8 @@ static void TestChaCha20(const std::string &hex_message, const std::string &hexk // Repeat 10x, but fragmented into 3 chunks, to exercise the ChaCha20 class's caching. for (int i = 0; i < 10; ++i) { size_t lens[3]; - lens[0] = InsecureRandRange(hexout.size() / 2U + 1U); - lens[1] = InsecureRandRange(hexout.size() / 2U + 1U - lens[0]); + lens[0] = m_rng.randrange(hexout.size() / 2U + 1U); + lens[1] = m_rng.randrange(hexout.size() / 2U + 1U - lens[0]); lens[2] = hexout.size() / 2U - lens[0] - lens[1]; rng.Seek(nonce, seek); @@ -183,7 +184,7 @@ static void TestChaCha20(const std::string &hex_message, const std::string &hexk } } -static void TestFSChaCha20(const std::string& hex_plaintext, const std::string& hexkey, uint32_t rekey_interval, const std::string& ciphertext_after_rotation) +void TestFSChaCha20(const std::string& hex_plaintext, const std::string& hexkey, uint32_t rekey_interval, const std::string& ciphertext_after_rotation) { auto key = ParseHex<std::byte>(hexkey); BOOST_CHECK_EQUAL(FSChaCha20::KEYLEN, key.size()); @@ -223,7 +224,7 @@ static void TestFSChaCha20(const std::string& hex_plaintext, const std::string& BOOST_CHECK_EQUAL(HexStr(fsc20_output), ciphertext_after_rotation); } -static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag) +void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag) { auto key = ParseHex<std::byte>(hexkey); auto m = ParseHex<std::byte>(hexmessage); @@ -237,7 +238,7 @@ static void TestPoly1305(const std::string &hexmessage, const std::string &hexke auto data = Span{m}; Poly1305 poly1305{key}; for (int chunk = 0; chunk < splits; ++chunk) { - size_t now = InsecureRandRange(data.size() + 1); + size_t now = m_rng.randrange(data.size() + 1); poly1305.Update(data.first(now)); data = data.subspan(now); } @@ -248,7 +249,7 @@ static void TestPoly1305(const std::string &hexmessage, const std::string &hexke } } -static void TestChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, ChaCha20::Nonce96 nonce, const std::string& cipher_hex) +void TestChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, ChaCha20::Nonce96 nonce, const std::string& cipher_hex) { auto plain = ParseHex<std::byte>(plain_hex); auto aad = ParseHex<std::byte>(aad_hex); @@ -257,7 +258,7 @@ static void TestChaCha20Poly1305(const std::string& plain_hex, const std::string for (int i = 0; i < 10; ++i) { // During i=0, use single-plain Encrypt/Decrypt; others use a split at prefix. - size_t prefix = i ? InsecureRandRange(plain.size() + 1) : plain.size(); + size_t prefix = i ? m_rng.randrange(plain.size() + 1) : plain.size(); // Encrypt. std::vector<std::byte> cipher(plain.size() + AEADChaCha20Poly1305::EXPANSION); AEADChaCha20Poly1305 aead{key}; @@ -289,7 +290,7 @@ static void TestChaCha20Poly1305(const std::string& plain_hex, const std::string } } -static void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, uint64_t msg_idx, const std::string& cipher_hex) +void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::string& aad_hex, const std::string& key_hex, uint64_t msg_idx, const std::string& cipher_hex) { auto plain = ParseHex<std::byte>(plain_hex); auto aad = ParseHex<std::byte>(aad_hex); @@ -299,7 +300,7 @@ static void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::stri for (int it = 0; it < 10; ++it) { // During it==0 we use the single-plain Encrypt/Decrypt; others use a split at prefix. - size_t prefix = it ? InsecureRandRange(plain.size() + 1) : plain.size(); + size_t prefix = it ? m_rng.randrange(plain.size() + 1) : plain.size(); std::byte dummy_tag[FSChaCha20Poly1305::EXPANSION] = {{}}; // Do msg_idx dummy encryptions to seek to the correct packet. @@ -335,7 +336,7 @@ static void TestFSChaCha20Poly1305(const std::string& plain_hex, const std::stri } } -static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, const std::string &okm_check_hex) { +void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, const std::string &okm_check_hex) { std::vector<unsigned char> initial_key_material = ParseHex(ikm_hex); std::vector<unsigned char> salt = ParseHex(salt_hex); std::vector<unsigned char> info = ParseHex(info_hex); @@ -351,6 +352,10 @@ static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &sa BOOST_CHECK(HexStr(out) == okm_check_hex); } +void TestSHA3_256(const std::string& input, const std::string& output); +}; // struct CryptoTests +} // namespace crypto_tests + static std::string LongTestString() { std::string ret; @@ -366,6 +371,8 @@ static std::string LongTestString() const std::string test1 = LongTestString(); +BOOST_FIXTURE_TEST_SUITE(crypto_tests, CryptoTest) + BOOST_AUTO_TEST_CASE(ripemd160_testvectors) { TestRIPEMD160("", "9c1185a5c5e9fc54612808977ee8f548b2258d31"); TestRIPEMD160("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); @@ -1067,7 +1074,7 @@ BOOST_AUTO_TEST_CASE(sha256d64) unsigned char in[64 * 32]; unsigned char out1[32 * 32], out2[32 * 32]; for (int j = 0; j < 64 * i; ++j) { - in[j] = InsecureRandBits(8); + in[j] = m_rng.randbits(8); } for (int j = 0; j < i; ++j) { CHash256().Write({in + 64 * j, 64}).Finalize({out1 + 32 * j, 32}); @@ -1077,7 +1084,7 @@ BOOST_AUTO_TEST_CASE(sha256d64) } } -static void TestSHA3_256(const std::string& input, const std::string& output) +void CryptoTest::TestSHA3_256(const std::string& input, const std::string& output) { const auto in_bytes = ParseHex(input); const auto out_bytes = ParseHex(output); @@ -1091,8 +1098,8 @@ static void TestSHA3_256(const std::string& input, const std::string& output) // Reset and split randomly in 3 sha.Reset(); - int s1 = InsecureRandRange(in_bytes.size() + 1); - int s2 = InsecureRandRange(in_bytes.size() + 1 - s1); + int s1 = m_rng.randrange(in_bytes.size() + 1); + int s2 = m_rng.randrange(in_bytes.size() + 1 - s1); int s3 = in_bytes.size() - s1 - s2; sha.Write(Span{in_bytes}.first(s1)).Write(Span{in_bytes}.subspan(s1, s2)); sha.Write(Span{in_bytes}.last(s3)).Finalize(out); @@ -1196,7 +1203,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests) uint256 res; int table[4]; for (int i = 0; i < 4; ++i) { - table[i] = g_insecure_rand_ctx.randbits<3>(); + table[i] = m_rng.randbits<3>(); } for (int order = 0; order < 4; ++order) { MuHash3072 acc; @@ -1216,8 +1223,8 @@ BOOST_AUTO_TEST_CASE(muhash_tests) } } - MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X - MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X, y=Y + MuHash3072 x = FromInt(m_rng.randbits<4>()); // x=X + MuHash3072 y = FromInt(m_rng.randbits<4>()); // x=X, y=Y MuHash3072 z; // x=X, y=Y, z=1 z *= x; // x=X, y=Y, z=X z *= y; // x=X, y=Y, z=X*Y diff --git a/src/test/cuckoocache_tests.cpp b/src/test/cuckoocache_tests.cpp index fc22daeb57..bb4c8c7093 100644 --- a/src/test/cuckoocache_tests.cpp +++ b/src/test/cuckoocache_tests.cpp @@ -29,11 +29,11 @@ * using BOOST_CHECK_CLOSE to fail. * */ -BOOST_AUTO_TEST_SUITE(cuckoocache_tests); +BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup); /* Test that no values not inserted into the cache are read out of it. * - * There are no repeats in the first 200000 InsecureRand256() calls + * There are no repeats in the first 200000 m_rng.rand256() calls */ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes) { @@ -42,18 +42,19 @@ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes) size_t megabytes = 4; cc.setup_bytes(megabytes << 20); for (int x = 0; x < 100000; ++x) { - cc.insert(InsecureRand256()); + cc.insert(m_rng.rand256()); } for (int x = 0; x < 100000; ++x) { - BOOST_CHECK(!cc.contains(InsecureRand256(), false)); + BOOST_CHECK(!cc.contains(m_rng.rand256(), false)); } }; +struct HitRateTest : BasicTestingSetup { /** This helper returns the hit rate when megabytes*load worth of entries are * inserted into a megabytes sized cache */ template <typename Cache> -static double test_cache(size_t megabytes, double load) +double test_cache(size_t megabytes, double load) { SeedRandomForTest(SeedRand::ZEROS); std::vector<uint256> hashes; @@ -65,7 +66,7 @@ static double test_cache(size_t megabytes, double load) for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = m_rng.rand32(); } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is @@ -104,9 +105,10 @@ static double normalize_hit_rate(double hits, double load) { return hits * std::max(load, 1.0); } +}; // struct HitRateTest /** Check the hit rate on loads ranging from 0.1 to 1.6 */ -BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok) +BOOST_FIXTURE_TEST_CASE(cuckoocache_hit_rate_ok, HitRateTest) { /** Arbitrarily selected Hit Rate threshold that happens to work for this test * as a lower bound on performance. @@ -120,10 +122,11 @@ BOOST_AUTO_TEST_CASE(cuckoocache_hit_rate_ok) } +struct EraseTest : BasicTestingSetup { /** This helper checks that erased elements are preferentially inserted onto and * that the hit rate of "fresher" keys is reasonable*/ template <typename Cache> -static void test_cache_erase(size_t megabytes) +void test_cache_erase(size_t megabytes) { double load = 1; SeedRandomForTest(SeedRand::ZEROS); @@ -136,7 +139,7 @@ static void test_cache_erase(size_t megabytes) for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = m_rng.rand32(); } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is @@ -178,15 +181,17 @@ static void test_cache_erase(size_t megabytes) // erased elements. BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); } +}; // struct EraseTest -BOOST_AUTO_TEST_CASE(cuckoocache_erase_ok) +BOOST_FIXTURE_TEST_CASE(cuckoocache_erase_ok, EraseTest) { size_t megabytes = 4; test_cache_erase<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes); } +struct EraseParallelTest : BasicTestingSetup { template <typename Cache> -static void test_cache_erase_parallel(size_t megabytes) +void test_cache_erase_parallel(size_t megabytes) { double load = 1; SeedRandomForTest(SeedRand::ZEROS); @@ -199,7 +204,7 @@ static void test_cache_erase_parallel(size_t megabytes) for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)hashes[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = m_rng.rand32(); } /** We make a copy of the hashes because future optimizations of the * cuckoocache may overwrite the inserted element, so the test is @@ -268,15 +273,17 @@ static void test_cache_erase_parallel(size_t megabytes) // erased elements. BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); } -BOOST_AUTO_TEST_CASE(cuckoocache_erase_parallel_ok) +}; // struct EraseParallelTest +BOOST_FIXTURE_TEST_CASE(cuckoocache_erase_parallel_ok, EraseParallelTest) { size_t megabytes = 4; test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes); } +struct GenerationsTest : BasicTestingSetup { template <typename Cache> -static void test_cache_generations() +void test_cache_generations() { // This test checks that for a simulation of network activity, the fresh hit // rate is never below 99%, and the number of times that it is worse than @@ -302,7 +309,7 @@ static void test_cache_generations() // immediately and never uses the other half. struct block_activity { std::vector<uint256> reads; - block_activity(uint32_t n_insert, Cache& c) : reads() + block_activity(uint32_t n_insert, FastRandomContext& rng, Cache& c) { std::vector<uint256> inserts; inserts.resize(n_insert); @@ -310,7 +317,7 @@ static void test_cache_generations() for (uint32_t i = 0; i < n_insert; ++i) { uint32_t* ptr = (uint32_t*)inserts[i].begin(); for (uint8_t j = 0; j < 8; ++j) - *(ptr++) = InsecureRand32(); + *(ptr++) = rng.rand32(); } for (uint32_t i = 0; i < n_insert / 4; ++i) reads.push_back(inserts[i]); @@ -344,7 +351,7 @@ static void test_cache_generations() for (uint32_t i = 0; i < total; ++i) { if (last_few.size() == WINDOW_SIZE) last_few.pop_front(); - last_few.emplace_back(BLOCK_SIZE, set); + last_few.emplace_back(BLOCK_SIZE, m_rng, set); uint32_t count = 0; for (auto& act : last_few) for (uint32_t k = 0; k < POP_AMOUNT; ++k) { @@ -365,7 +372,8 @@ static void test_cache_generations() // max_rate_less_than_tight_hit_rate of the time BOOST_CHECK(double(out_of_tight_tolerance) / double(total) < max_rate_less_than_tight_hit_rate); } -BOOST_AUTO_TEST_CASE(cuckoocache_generations) +}; // struct GenerationsTest +BOOST_FIXTURE_TEST_CASE(cuckoocache_generations, GenerationsTest) { test_cache_generations<CuckooCache::cache<uint256, SignatureCacheHasher>>(); } diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 167e4be288..3a86036327 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -33,7 +33,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper) fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate}); uint8_t key{'k'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint256 res; // Ensure that we're doing real obfuscation when obfuscate=true @@ -60,65 +60,65 @@ BOOST_AUTO_TEST_CASE(dbwrapper_basic_data) BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw))); //Simulate block raw data - "b + block hash" - std::string key_block = "b" + InsecureRand256().ToString(); + std::string key_block = "b" + m_rng.rand256().ToString(); - uint256 in_block = InsecureRand256(); + uint256 in_block = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_block, in_block)); BOOST_CHECK(dbw.Read(key_block, res)); BOOST_CHECK_EQUAL(res.ToString(), in_block.ToString()); //Simulate file raw data - "f + file_number" - std::string key_file = strprintf("f%04x", InsecureRand32()); + std::string key_file = strprintf("f%04x", m_rng.rand32()); - uint256 in_file_info = InsecureRand256(); + uint256 in_file_info = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_file, in_file_info)); BOOST_CHECK(dbw.Read(key_file, res)); BOOST_CHECK_EQUAL(res.ToString(), in_file_info.ToString()); //Simulate transaction raw data - "t + transaction hash" - std::string key_transaction = "t" + InsecureRand256().ToString(); + std::string key_transaction = "t" + m_rng.rand256().ToString(); - uint256 in_transaction = InsecureRand256(); + uint256 in_transaction = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_transaction, in_transaction)); BOOST_CHECK(dbw.Read(key_transaction, res)); BOOST_CHECK_EQUAL(res.ToString(), in_transaction.ToString()); //Simulate UTXO raw data - "c + transaction hash" - std::string key_utxo = "c" + InsecureRand256().ToString(); + std::string key_utxo = "c" + m_rng.rand256().ToString(); - uint256 in_utxo = InsecureRand256(); + uint256 in_utxo = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_utxo, in_utxo)); BOOST_CHECK(dbw.Read(key_utxo, res)); BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString()); //Simulate last block file number - "l" uint8_t key_last_blockfile_number{'l'}; - uint32_t lastblockfilenumber = InsecureRand32(); + uint32_t lastblockfilenumber = m_rng.rand32(); BOOST_CHECK(dbw.Write(key_last_blockfile_number, lastblockfilenumber)); BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32)); BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32); //Simulate Is Reindexing - "R" uint8_t key_IsReindexing{'R'}; - bool isInReindexing = InsecureRandBool(); + bool isInReindexing = m_rng.randbool(); BOOST_CHECK(dbw.Write(key_IsReindexing, isInReindexing)); BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool)); BOOST_CHECK_EQUAL(isInReindexing, res_bool); //Simulate last block hash up to which UXTO covers - 'B' uint8_t key_lastblockhash_uxto{'B'}; - uint256 lastblock_hash = InsecureRand256(); + uint256 lastblock_hash = m_rng.rand256(); BOOST_CHECK(dbw.Write(key_lastblockhash_uxto, lastblock_hash)); BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res)); BOOST_CHECK_EQUAL(lastblock_hash, res); //Simulate file raw data - "F + filename_number + filename" std::string file_option_tag = "F"; - uint8_t filename_length = InsecureRandBits(8); + uint8_t filename_length = m_rng.randbits(8); std::string filename = "randomfilename"; std::string key_file_option = strprintf("%s%01x%s", file_option_tag,filename_length,filename); - bool in_file_bool = InsecureRandBool(); + bool in_file_bool = m_rng.randbool(); BOOST_CHECK(dbw.Write(key_file_option, in_file_bool)); BOOST_CHECK(dbw.Read(key_file_option, res_bool)); BOOST_CHECK_EQUAL(res_bool, in_file_bool); @@ -134,11 +134,11 @@ BOOST_AUTO_TEST_CASE(dbwrapper_batch) CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate}); uint8_t key{'i'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint8_t key2{'j'}; - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); uint8_t key3{'k'}; - uint256 in3 = InsecureRand256(); + uint256 in3 = m_rng.rand256(); uint256 res; CDBBatch batch(dbw); @@ -171,10 +171,10 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) // The two keys are intentionally chosen for ordering uint8_t key{'j'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); BOOST_CHECK(dbw.Write(key, in)); uint8_t key2{'k'}; - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); BOOST_CHECK(dbw.Write(key2, in2)); std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator()); @@ -212,7 +212,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false}); uint8_t key{'k'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); @@ -234,7 +234,7 @@ BOOST_AUTO_TEST_CASE(existing_data_no_obfuscate) BOOST_CHECK(!odbw.IsEmpty()); // There should be existing data BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); uint256 res3; // Check that we can write successfully @@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) // Set up a non-obfuscated wrapper to write some initial data. std::unique_ptr<CDBWrapper> dbw = std::make_unique<CDBWrapper>(DBParams{.path = ph, .cache_bytes = 1 << 10, .memory_only = false, .wipe_data = false, .obfuscate = false}); uint8_t key{'k'}; - uint256 in = InsecureRand256(); + uint256 in = m_rng.rand256(); uint256 res; BOOST_CHECK(dbw->Write(key, in)); @@ -271,7 +271,7 @@ BOOST_AUTO_TEST_CASE(existing_data_reindex) BOOST_CHECK(!odbw.Read(key, res2)); BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); - uint256 in2 = InsecureRand256(); + uint256 in2 = m_rng.rand256(); uint256 res3; // Check that we can write successfully diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index 42db28daf5..9ee7e9c9fe 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -106,17 +106,18 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) peerman.FinalizeNode(dummyNode1); } -static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false) +struct OutboundTest : TestingSetup { +void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false) { CAddress addr; if (onion_peer) { - auto tor_addr{g_insecure_rand_ctx.randbytes(ADDR_TORV3_SIZE)}; + auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)}; BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr))); } while (!addr.IsRoutable()) { - addr = CAddress(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE); + addr = CAddress(ip(m_rng.randbits(32)), NODE_NONE); } vNodes.emplace_back(new CNode{id++, @@ -136,8 +137,9 @@ static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerM connman.AddTestNode(node); } +}; // struct OutboundTest -BOOST_AUTO_TEST_CASE(stale_tip_peer_management) +BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest) { NodeId id{0}; auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); @@ -235,7 +237,7 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management) connman->ClearTestNodes(); } -BOOST_AUTO_TEST_CASE(block_relay_only_eviction) +BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest) { NodeId id{0}; auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); diff --git a/src/test/fuzz/fuzz.cpp b/src/test/fuzz/fuzz.cpp index 96283a3e15..fdad0a287a 100644 --- a/src/test/fuzz/fuzz.cpp +++ b/src/test/fuzz/fuzz.cpp @@ -106,7 +106,7 @@ void initialize() // randomness during the fuzz test, except: // - GetStrongRandBytes(), which is used for the creation of private key material. // - Creating a BasicTestingSetup or derived class will switch to a random seed. - SeedRandomForTest(SeedRand::ZEROS); + SeedRandomStateForTest(SeedRand::ZEROS); // Terminate immediately if a fuzzing harness ever tries to create a socket. // Individual tests can override this by pointing CreateSock to a mocked alternative. diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 150e386c2d..f56f7232c3 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -11,7 +11,7 @@ #include <boost/test/unit_test.hpp> -BOOST_AUTO_TEST_SUITE(hash_tests) +BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(murmurhash3) { @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(siphash) for (int i = 0; i < 16; ++i) { uint64_t k1 = ctx.rand64(); uint64_t k2 = ctx.rand64(); - uint256 x = InsecureRand256(); + uint256 x = m_rng.rand256(); uint32_t n = ctx.rand32(); uint8_t nb[4]; WriteLE32(nb, n); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index d0f9ef8161..698cedbb16 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -312,11 +312,11 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors) // In iteration i=0 we tweak with empty Merkle tree. for (int i = 0; i < 10; ++i) { uint256 merkle_root; - if (i) merkle_root = InsecureRand256(); + if (i) merkle_root = m_rng.rand256(); auto tweaked = pubkey.CreateTapTweak(i ? &merkle_root : nullptr); BOOST_CHECK(tweaked); XOnlyPubKey tweaked_key = tweaked->first; - aux256 = InsecureRand256(); + aux256 = m_rng.rand256(); bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, aux256); BOOST_CHECK(ok); BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64)); @@ -336,7 +336,7 @@ BOOST_AUTO_TEST_CASE(key_ellswift) CKey key = DecodeSecret(secret); BOOST_CHECK(key.IsValid()); - uint256 ent32 = InsecureRand256(); + uint256 ent32 = m_rng.rand256(); auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32})); CPubKey decoded_pubkey = ellswift.Decode(); @@ -366,7 +366,7 @@ BOOST_AUTO_TEST_CASE(key_schnorr_tweak_smoke_test) CKey key; key.MakeNewKey(true); - uint256 merkle_root = InsecureRand256(); + uint256 merkle_root = m_rng.rand256(); // secp256k1 functions secp256k1_keypair keypair; diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 66f7be3c4e..70308cb29a 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -184,7 +184,7 @@ BOOST_AUTO_TEST_CASE(merkle_test) { for (int i = 0; i < 32; i++) { // Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes. - int ntx = (i <= 16) ? i : 17 + (InsecureRandRange(4000)); + int ntx = (i <= 16) ? i : 17 + (m_rng.randrange(4000)); // Try up to 3 mutations. for (int mutate = 0; mutate <= 3; mutate++) { int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first. @@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE(merkle_test) // If ntx <= 16, try all branches. Otherwise, try 16 random ones. int mtx = loop; if (ntx > 16) { - mtx = InsecureRandRange(ntx); + mtx = m_rng.randrange(ntx); } std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx); std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index c4cf6f8a40..ac18cdbd73 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -367,7 +367,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) { CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); + next->phashBlock = new uint256(m_rng.rand256()); m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; @@ -379,7 +379,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std:: while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) { CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); CBlockIndex* next = new CBlockIndex(); - next->phashBlock = new uint256(InsecureRand256()); + next->phashBlock = new uint256(m_rng.rand256()); m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); next->pprev = prev; next->nHeight = prev->nHeight + 1; diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 55aa90e29e..c7fb3c2ce4 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -341,13 +341,14 @@ void SatisfactionToWitness(miniscript::MiniscriptContext ctx, CScriptWitness& wi witness.stack.push_back(*builder.GetSpendData().scripts.begin()->second.begin()); } +struct MiniScriptTest : BasicTestingSetup { /** Run random satisfaction tests. */ void TestSatisfy(const KeyConverter& converter, const std::string& testcase, const NodeRef& node) { auto script = node->ToScript(converter); auto challenges = FindChallenges(node); // Find all challenges in the generated miniscript. std::vector<Challenge> challist(challenges.begin(), challenges.end()); for (int iter = 0; iter < 3; ++iter) { - std::shuffle(challist.begin(), challist.end(), g_insecure_rand_ctx); + std::shuffle(challist.begin(), challist.end(), m_rng); Satisfier satisfier(converter.MsContext()); TestSignatureChecker checker(satisfier); bool prev_mal_success = false, prev_nonmal_success = false; @@ -489,10 +490,11 @@ void Test(const std::string& ms, const std::string& hexscript, const std::string /*opslimit=*/-1, /*stacklimit=*/-1, /*max_wit_size=*/std::nullopt, /*max_tap_wit_size=*/std::nullopt, /*stack_exec=*/std::nullopt); } +}; // struct MiniScriptTest } // namespace -BOOST_FIXTURE_TEST_SUITE(miniscript_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(miniscript_tests, MiniScriptTest) BOOST_AUTO_TEST_CASE(fixed_tests) { diff --git a/src/test/minisketch_tests.cpp b/src/test/minisketch_tests.cpp index 10506da783..3d2a835113 100644 --- a/src/test/minisketch_tests.cpp +++ b/src/test/minisketch_tests.cpp @@ -14,16 +14,16 @@ using node::MakeMinisketch32; -BOOST_AUTO_TEST_SUITE(minisketch_tests) +BOOST_FIXTURE_TEST_SUITE(minisketch_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(minisketch_test) { for (int i = 0; i < 100; ++i) { - uint32_t errors = 0 + InsecureRandRange(11); - uint32_t start_a = 1 + InsecureRandRange(1000000000); - uint32_t a_not_b = InsecureRandRange(errors + 1); + uint32_t errors = 0 + m_rng.randrange(11); + uint32_t start_a = 1 + m_rng.randrange(1000000000); + uint32_t a_not_b = m_rng.randrange(errors + 1); uint32_t b_not_a = errors - a_not_b; - uint32_t both = InsecureRandRange(10000); + uint32_t both = m_rng.randrange(10000); uint32_t end_a = start_a + a_not_b + both; uint32_t start_b = start_a + a_not_b; uint32_t end_b = start_b + both + b_not_a; diff --git a/src/test/net_peer_connection_tests.cpp b/src/test/net_peer_connection_tests.cpp index 2dde6daee5..e60ce8b99d 100644 --- a/src/test/net_peer_connection_tests.cpp +++ b/src/test/net_peer_connection_tests.cpp @@ -43,20 +43,21 @@ static CService ip(uint32_t i) return CService{CNetAddr{s}, Params().GetDefaultPort()}; } +struct PeerTest : LogIPsTestingSetup { /** Create a peer and connect to it. If the optional `address` (IP/CJDNS only) isn't passed, a random address is created. */ -static void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, ConnmanTestMsg& connman, ConnectionType conn_type, bool onion_peer = false, std::optional<std::string> address = std::nullopt) +void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman, ConnmanTestMsg& connman, ConnectionType conn_type, bool onion_peer = false, std::optional<std::string> address = std::nullopt) { CAddress addr{}; if (address.has_value()) { addr = CAddress{MaybeFlipIPv6toCJDNS(LookupNumeric(address.value(), Params().GetDefaultPort())), NODE_NONE}; } else if (onion_peer) { - auto tor_addr{g_insecure_rand_ctx.randbytes(ADDR_TORV3_SIZE)}; + auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)}; BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr))); } while (!addr.IsLocal() && !addr.IsRoutable()) { - addr = CAddress{ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE}; + addr = CAddress{ip(m_rng.randbits(32)), NODE_NONE}; } BOOST_REQUIRE(addr.IsValid()); @@ -80,8 +81,9 @@ static void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman connman.AddTestNode(node); } +}; // struct PeerTest -BOOST_AUTO_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection) +BOOST_FIXTURE_TEST_CASE(test_addnode_getaddednodeinfo_and_connection_detection, PeerTest) { auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); auto peerman = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {}); diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp index 26c52013fa..5b2f6d386e 100644 --- a/src/test/net_tests.cpp +++ b/src/test/net_tests.cpp @@ -1011,10 +1011,10 @@ BOOST_AUTO_TEST_CASE(advertise_local_address) namespace { -CKey GenerateRandomTestKey() noexcept +CKey GenerateRandomTestKey(FastRandomContext& rng) noexcept { CKey key; - uint256 key_data = InsecureRand256(); + uint256 key_data = rng.rand256(); key.Set(key_data.begin(), key_data.end(), true); return key; } @@ -1029,6 +1029,7 @@ CKey GenerateRandomTestKey() noexcept */ class V2TransportTester { + FastRandomContext& m_rng; V2Transport m_transport; //!< V2Transport being tested BIP324Cipher m_cipher; //!< Cipher to help with the other side bool m_test_initiator; //!< Whether m_transport is the initiator (true) or responder (false) @@ -1042,9 +1043,10 @@ class V2TransportTester public: /** Construct a tester object. test_initiator: whether the tested transport is initiator. */ - explicit V2TransportTester(bool test_initiator) - : m_transport{0, test_initiator}, - m_cipher{GenerateRandomTestKey(), MakeByteSpan(InsecureRand256())}, + explicit V2TransportTester(FastRandomContext& rng, bool test_initiator) + : m_rng{rng}, + m_transport{0, test_initiator}, + m_cipher{GenerateRandomTestKey(m_rng), MakeByteSpan(m_rng.rand256())}, m_test_initiator(test_initiator) {} /** Data type returned by Interact: @@ -1068,7 +1070,7 @@ public: bool progress{false}; // Send bytes from m_to_send to the transport. if (!m_to_send.empty()) { - Span<const uint8_t> to_send = Span{m_to_send}.first(1 + InsecureRandRange(m_to_send.size())); + Span<const uint8_t> to_send = Span{m_to_send}.first(1 + m_rng.randrange(m_to_send.size())); size_t old_len = to_send.size(); if (!m_transport.ReceivedBytes(to_send)) { return std::nullopt; // transport error occurred @@ -1079,7 +1081,7 @@ public: } } // Retrieve messages received by the transport. - if (m_transport.ReceivedMessageComplete() && (!progress || InsecureRandBool())) { + if (m_transport.ReceivedMessageComplete() && (!progress || m_rng.randbool())) { bool reject{false}; auto msg = m_transport.GetReceivedMessage({}, reject); if (reject) { @@ -1090,7 +1092,7 @@ public: progress = true; } // Enqueue a message to be sent by the transport to us. - if (!m_msg_to_send.empty() && (!progress || InsecureRandBool())) { + if (!m_msg_to_send.empty() && (!progress || m_rng.randbool())) { if (m_transport.SetMessageToSend(m_msg_to_send.front())) { m_msg_to_send.pop_front(); progress = true; @@ -1098,8 +1100,8 @@ public: } // Receive bytes from the transport. const auto& [recv_bytes, _more, _msg_type] = m_transport.GetBytesToSend(!m_msg_to_send.empty()); - if (!recv_bytes.empty() && (!progress || InsecureRandBool())) { - size_t to_receive = 1 + InsecureRandRange(recv_bytes.size()); + if (!recv_bytes.empty() && (!progress || m_rng.randbool())) { + size_t to_receive = 1 + m_rng.randrange(recv_bytes.size()); m_received.insert(m_received.end(), recv_bytes.begin(), recv_bytes.begin() + to_receive); progress = true; m_transport.MarkBytesSent(to_receive); @@ -1121,7 +1123,7 @@ public: /** Send V1 version message header to the transport. */ void SendV1Version(const MessageStartChars& magic) { - CMessageHeader hdr(magic, "version", 126 + InsecureRandRange(11)); + CMessageHeader hdr(magic, "version", 126 + m_rng.randrange(11)); DataStream ser{}; ser << hdr; m_to_send.insert(m_to_send.end(), UCharCast(ser.data()), UCharCast(ser.data() + ser.size())); @@ -1146,13 +1148,13 @@ public: void SendGarbage(size_t garbage_len) { // Generate random garbage and send it. - SendGarbage(g_insecure_rand_ctx.randbytes<uint8_t>(garbage_len)); + SendGarbage(m_rng.randbytes<uint8_t>(garbage_len)); } /** Schedule garbage (with valid random length) to be sent to the transport. */ void SendGarbage() { - SendGarbage(InsecureRandRange(V2Transport::MAX_GARBAGE_LEN + 1)); + SendGarbage(m_rng.randrange(V2Transport::MAX_GARBAGE_LEN + 1)); } /** Schedule a message to be sent to us by the transport. */ @@ -1335,7 +1337,7 @@ public: /** Introduce a bit error in the data scheduled to be sent. */ void Damage() { - m_to_send[InsecureRandRange(m_to_send.size())] ^= (uint8_t{1} << InsecureRandRange(8)); + m_to_send[m_rng.randrange(m_to_send.size())] ^= (uint8_t{1} << m_rng.randrange(8)); } }; @@ -1345,7 +1347,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) { // A mostly normal scenario, testing a transport in initiator mode. for (int i = 0; i < 10; ++i) { - V2TransportTester tester(true); + V2TransportTester tester(m_rng, true); auto ret = tester.Interact(); BOOST_REQUIRE(ret && ret->empty()); tester.SendKey(); @@ -1358,8 +1360,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveGarbage(); tester.ReceiveVersion(); tester.CompareSessionIDs(); - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000)); - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(100000)); + auto msg_data_2 = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendMessage(uint8_t(4), msg_data_1); // cmpctblock short id tester.SendMessage(0, {}); // Invalidly encoded message tester.SendMessage("tx", msg_data_2); // 12-character encoded message type @@ -1379,14 +1381,14 @@ BOOST_AUTO_TEST_CASE(v2transport_test) if (!ret) break; // failure BOOST_CHECK(ret->size() == 0); // no message can be delivered // Send another message. - auto msg_data_3 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(10000)); + auto msg_data_3 = m_rng.randbytes<uint8_t>(m_rng.randrange(10000)); tester.SendMessage(uint8_t(12), msg_data_3); // getheaders short id } } // Normal scenario, with a transport in responder node. for (int i = 0; i < 10; ++i) { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendKey(); tester.SendGarbage(); auto ret = tester.Interact(); @@ -1399,8 +1401,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveGarbage(); tester.ReceiveVersion(); tester.CompareSessionIDs(); - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000)); - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(100000)); + auto msg_data_2 = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendMessage(uint8_t(14), msg_data_1); // inv short id tester.SendMessage(uint8_t(19), msg_data_2); // pong short id ret = tester.Interact(); @@ -1409,7 +1411,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) BOOST_CHECK((*ret)[1] && (*ret)[1]->m_type == "pong" && std::ranges::equal((*ret)[1]->m_recv, MakeByteSpan(msg_data_2))); // Then send a too-large message. - auto msg_data_3 = g_insecure_rand_ctx.randbytes<uint8_t>(4005000); + auto msg_data_3 = m_rng.randbytes<uint8_t>(4005000); tester.SendMessage(uint8_t(11), msg_data_3); // getdata short id ret = tester.Interact(); BOOST_CHECK(!ret); @@ -1418,18 +1420,18 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Various valid but unusual scenarios. for (int i = 0; i < 50; ++i) { /** Whether an initiator or responder is being tested. */ - bool initiator = InsecureRandBool(); + bool initiator = m_rng.randbool(); /** Use either 0 bytes or the maximum possible (4095 bytes) garbage length. */ - size_t garb_len = InsecureRandBool() ? 0 : V2Transport::MAX_GARBAGE_LEN; + size_t garb_len = m_rng.randbool() ? 0 : V2Transport::MAX_GARBAGE_LEN; /** How many decoy packets to send before the version packet. */ - unsigned num_ignore_version = InsecureRandRange(10); + unsigned num_ignore_version = m_rng.randrange(10); /** What data to send in the version packet (ignored by BIP324 peers, but reserved for future extensions). */ - auto ver_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandBool() ? 0 : InsecureRandRange(1000)); + auto ver_data = m_rng.randbytes<uint8_t>(m_rng.randbool() ? 0 : m_rng.randrange(1000)); /** Whether to immediately send key and garbage out (required for responders, optional otherwise). */ - bool send_immediately = !initiator || InsecureRandBool(); + bool send_immediately = !initiator || m_rng.randbool(); /** How many decoy packets to send before the first and second real message. */ - unsigned num_decoys_1 = InsecureRandRange(1000), num_decoys_2 = InsecureRandRange(1000); - V2TransportTester tester(initiator); + unsigned num_decoys_1 = m_rng.randrange(1000), num_decoys_2 = m_rng.randrange(1000); + V2TransportTester tester(m_rng, initiator); if (send_immediately) { tester.SendKey(); tester.SendGarbage(garb_len); @@ -1443,8 +1445,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveKey(); tester.SendGarbageTerm(); for (unsigned v = 0; v < num_ignore_version; ++v) { - size_t ver_ign_data_len = InsecureRandBool() ? 0 : InsecureRandRange(1000); - auto ver_ign_data = g_insecure_rand_ctx.randbytes<uint8_t>(ver_ign_data_len); + size_t ver_ign_data_len = m_rng.randbool() ? 0 : m_rng.randrange(1000); + auto ver_ign_data = m_rng.randbytes<uint8_t>(ver_ign_data_len); tester.SendVersion(ver_ign_data, true); } tester.SendVersion(ver_data, false); @@ -1454,16 +1456,16 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveVersion(); tester.CompareSessionIDs(); for (unsigned d = 0; d < num_decoys_1; ++d) { - auto decoy_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto decoy_data = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendPacket(/*content=*/decoy_data, /*aad=*/{}, /*ignore=*/true); } - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(4000000)); + auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(4000000)); tester.SendMessage(uint8_t(28), msg_data_1); for (unsigned d = 0; d < num_decoys_2; ++d) { - auto decoy_data = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto decoy_data = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendPacket(/*content=*/decoy_data, /*aad=*/{}, /*ignore=*/true); } - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(1000)); + auto msg_data_2 = m_rng.randbytes<uint8_t>(m_rng.randrange(1000)); tester.SendMessage(uint8_t(13), msg_data_2); // headers short id // Send invalidly-encoded message tester.SendMessage(std::string("blocktxn\x00\x00\x00a", CMessageHeader::COMMAND_SIZE), {}); @@ -1480,7 +1482,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Too long garbage (initiator). { - V2TransportTester tester(true); + V2TransportTester tester(m_rng, true); auto ret = tester.Interact(); BOOST_REQUIRE(ret && ret->empty()); tester.SendKey(); @@ -1493,7 +1495,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Too long garbage (responder). { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendKey(); tester.SendGarbage(V2Transport::MAX_GARBAGE_LEN + 1); auto ret = tester.Interact(); @@ -1506,23 +1508,23 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Send garbage that includes the first 15 garbage terminator bytes somewhere. { - V2TransportTester tester(true); + V2TransportTester tester(m_rng, true); auto ret = tester.Interact(); BOOST_REQUIRE(ret && ret->empty()); tester.SendKey(); tester.ReceiveKey(); /** The number of random garbage bytes before the included first 15 bytes of terminator. */ - size_t len_before = InsecureRandRange(V2Transport::MAX_GARBAGE_LEN - 16 + 1); + size_t len_before = m_rng.randrange(V2Transport::MAX_GARBAGE_LEN - 16 + 1); /** The number of random garbage bytes after it. */ - size_t len_after = InsecureRandRange(V2Transport::MAX_GARBAGE_LEN - 16 - len_before + 1); + size_t len_after = m_rng.randrange(V2Transport::MAX_GARBAGE_LEN - 16 - len_before + 1); // Construct len_before + 16 + len_after random bytes. - auto garbage = g_insecure_rand_ctx.randbytes<uint8_t>(len_before + 16 + len_after); + auto garbage = m_rng.randbytes<uint8_t>(len_before + 16 + len_after); // Replace the designed 16 bytes in the middle with the to-be-sent garbage terminator. auto garb_term = MakeUCharSpan(tester.GetCipher().GetSendGarbageTerminator()); std::copy(garb_term.begin(), garb_term.begin() + 16, garbage.begin() + len_before); // Introduce a bit error in the last byte of that copied garbage terminator, making only // the first 15 of them match. - garbage[len_before + 15] ^= (uint8_t(1) << InsecureRandRange(8)); + garbage[len_before + 15] ^= (uint8_t(1) << m_rng.randrange(8)); tester.SendGarbage(garbage); tester.SendGarbageTerm(); tester.SendVersion(); @@ -1531,9 +1533,9 @@ BOOST_AUTO_TEST_CASE(v2transport_test) tester.ReceiveGarbage(); tester.ReceiveVersion(); tester.CompareSessionIDs(); - auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(4000000); // test that receiving 4M payload works - auto msg_data_2 = g_insecure_rand_ctx.randbytes<uint8_t>(4000000); // test that sending 4M payload works - tester.SendMessage(uint8_t(InsecureRandRange(223) + 33), {}); // unknown short id + auto msg_data_1 = m_rng.randbytes<uint8_t>(4000000); // test that receiving 4M payload works + auto msg_data_2 = m_rng.randbytes<uint8_t>(4000000); // test that sending 4M payload works + tester.SendMessage(uint8_t(m_rng.randrange(223) + 33), {}); // unknown short id tester.SendMessage(uint8_t(2), msg_data_1); // "block" short id tester.AddMessage("blocktxn", msg_data_2); // schedule blocktxn to be sent to us ret = tester.Interact(); @@ -1545,7 +1547,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Send correct network's V1 header { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendV1Version(Params().MessageStart()); auto ret = tester.Interact(); BOOST_CHECK(ret); @@ -1553,7 +1555,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test) // Send wrong network's V1 header { - V2TransportTester tester(false); + V2TransportTester tester(m_rng, false); tester.SendV1Version(CChainParams::Main()->MessageStart()); auto ret = tester.Interact(); BOOST_CHECK(!ret); diff --git a/src/test/orphanage_tests.cpp b/src/test/orphanage_tests.cpp index d2dab94526..d4c52d7fe1 100644 --- a/src/test/orphanage_tests.cpp +++ b/src/test/orphanage_tests.cpp @@ -21,6 +21,8 @@ BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup) class TxOrphanageTest : public TxOrphanage { public: + TxOrphanageTest(FastRandomContext& rng) : m_rng{rng} {} + inline size_t CountOrphans() const { return m_orphans.size(); @@ -29,14 +31,16 @@ public: CTransactionRef RandomOrphan() { std::map<Wtxid, OrphanTx>::iterator it; - it = m_orphans.lower_bound(Wtxid::FromUint256(InsecureRand256())); + it = m_orphans.lower_bound(Wtxid::FromUint256(m_rng.rand256())); if (it == m_orphans.end()) it = m_orphans.begin(); return it->second.tx; } + + FastRandomContext& m_rng; }; -static void MakeNewKeyWithFastRandomContext(CKey& key, FastRandomContext& rand_ctx = g_insecure_rand_ctx) +static void MakeNewKeyWithFastRandomContext(CKey& key, FastRandomContext& rand_ctx) { std::vector<unsigned char> keydata; keydata = rand_ctx.randbytes(32); @@ -104,11 +108,11 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) // ecdsa_signature_parse_der_lax are executed during this test. // Specifically branches that run only when an ECDSA // signature's R and S values have leading zeros. - g_insecure_rand_ctx.Reseed(uint256{33}); + m_rng.Reseed(uint256{33}); - TxOrphanageTest orphanage; + TxOrphanageTest orphanage{m_rng}; CKey key; - MakeNewKeyWithFastRandomContext(key); + MakeNewKeyWithFastRandomContext(key, m_rng); FillableSigningProvider keystore; BOOST_CHECK(keystore.AddKey(key)); @@ -122,7 +126,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans) CMutableTransaction tx; tx.vin.resize(1); tx.vin[0].prevout.n = 0; - tx.vin[0].prevout.hash = Txid::FromUint256(InsecureRand256()); + tx.vin[0].prevout.hash = Txid::FromUint256(m_rng.rand256()); tx.vin[0].scriptSig << OP_1; tx.vout.resize(1); tx.vout[0].nValue = 1*CENT; diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index 5b7ccc8e7a..2ba48d717a 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -17,12 +17,16 @@ class CPartialMerkleTreeTester : public CPartialMerkleTree { public: + CPartialMerkleTreeTester(FastRandomContext& rng) : m_rng{rng} {} + // flip one bit in one of the hashes - this should break the authentication void Damage() { - unsigned int n = InsecureRandRange(vHash.size()); - int bit = InsecureRandBits(8); + unsigned int n = m_rng.randrange(vHash.size()); + int bit = m_rng.randbits(8); *(vHash[n].begin() + (bit>>3)) ^= 1<<(bit&7); } + + FastRandomContext& m_rng; }; BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup) @@ -59,7 +63,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) std::vector<bool> vMatch(nTx, false); std::vector<uint256> vMatchTxid1; for (unsigned int j=0; j<nTx; j++) { - bool fInclude = InsecureRandBits(att / 2) == 0; + bool fInclude = m_rng.randbits(att / 2) == 0; vMatch[j] = fInclude; if (fInclude) vMatchTxid1.push_back(vTxid[j]); @@ -77,7 +81,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1) BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8); // deserialize into a tester copy - CPartialMerkleTreeTester pmt2; + CPartialMerkleTreeTester pmt2{m_rng}; ss >> pmt2; // extract merkle root and matched txids from copy diff --git a/src/test/pool_tests.cpp b/src/test/pool_tests.cpp index 5ad4afa3a1..9d15660126 100644 --- a/src/test/pool_tests.cpp +++ b/src/test/pool_tests.cpp @@ -129,17 +129,17 @@ BOOST_AUTO_TEST_CASE(random_allocations) std::vector<PtrSizeAlignment> ptr_size_alignment{}; for (size_t i = 0; i < 1000; ++i) { // make it a bit more likely to allocate than deallocate - if (ptr_size_alignment.empty() || 0 != InsecureRandRange(4)) { + if (ptr_size_alignment.empty() || 0 != m_rng.randrange(4)) { // allocate a random item - std::size_t alignment = std::size_t{1} << InsecureRandRange(8); // 1, 2, ..., 128 - std::size_t size = (InsecureRandRange(200) / alignment + 1) * alignment; // multiple of alignment + std::size_t alignment = std::size_t{1} << m_rng.randrange(8); // 1, 2, ..., 128 + std::size_t size = (m_rng.randrange(200) / alignment + 1) * alignment; // multiple of alignment void* ptr = resource.Allocate(size, alignment); BOOST_TEST(ptr != nullptr); BOOST_TEST((reinterpret_cast<uintptr_t>(ptr) & (alignment - 1)) == 0); ptr_size_alignment.push_back({ptr, size, alignment}); } else { // deallocate a random item - auto& x = ptr_size_alignment[InsecureRandRange(ptr_size_alignment.size())]; + auto& x = ptr_size_alignment[m_rng.randrange(ptr_size_alignment.size())]; resource.Deallocate(x.ptr, x.bytes, x.alignment); x = ptr_size_alignment.back(); ptr_size_alignment.pop_back(); diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 4af66af283..edbc1de91f 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -147,9 +147,9 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test) } for (int j = 0; j < 1000; j++) { - CBlockIndex *p1 = &blocks[InsecureRandRange(10000)]; - CBlockIndex *p2 = &blocks[InsecureRandRange(10000)]; - CBlockIndex *p3 = &blocks[InsecureRandRange(10000)]; + CBlockIndex *p1 = &blocks[m_rng.randrange(10000)]; + CBlockIndex *p2 = &blocks[m_rng.randrange(10000)]; + CBlockIndex *p3 = &blocks[m_rng.randrange(10000)]; int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, chainParams->GetConsensus()); BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime()); diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp index f5f0cbee58..0588bf9b4a 100644 --- a/src/test/prevector_tests.cpp +++ b/src/test/prevector_tests.cpp @@ -27,7 +27,6 @@ class prevector_tester { typedef typename pretype::size_type Size; bool passed = true; - FastRandomContext rand_cache; uint256 rand_seed; @@ -208,84 +207,83 @@ public: BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString()); } - prevector_tester() { - SeedRandomForTest(); - rand_seed = InsecureRand256(); - rand_cache.Reseed(rand_seed); + prevector_tester(FastRandomContext& rng) { + rand_seed = rng.rand256(); + rng.Reseed(rand_seed); } }; BOOST_AUTO_TEST_CASE(PrevectorTestInt) { for (int j = 0; j < 64; j++) { - prevector_tester<8, int> test; + prevector_tester<8, int> test{m_rng}; for (int i = 0; i < 2048; i++) { - if (InsecureRandBits(2) == 0) { - test.insert(InsecureRandRange(test.size() + 1), int(InsecureRand32())); + if (m_rng.randbits(2) == 0) { + test.insert(m_rng.randrange(test.size() + 1), int(m_rng.rand32())); } - if (test.size() > 0 && InsecureRandBits(2) == 1) { - test.erase(InsecureRandRange(test.size())); + if (test.size() > 0 && m_rng.randbits(2) == 1) { + test.erase(m_rng.randrange(test.size())); } - if (InsecureRandBits(3) == 2) { - int new_size = std::max(0, std::min(30, (int)test.size() + (int)InsecureRandRange(5) - 2)); + if (m_rng.randbits(3) == 2) { + int new_size = std::max(0, std::min(30, (int)test.size() + (int)m_rng.randrange(5) - 2)); test.resize(new_size); } - if (InsecureRandBits(3) == 3) { - test.insert(InsecureRandRange(test.size() + 1), 1 + InsecureRandBool(), int(InsecureRand32())); + if (m_rng.randbits(3) == 3) { + test.insert(m_rng.randrange(test.size() + 1), 1 + m_rng.randbool(), int(m_rng.rand32())); } - if (InsecureRandBits(3) == 4) { - int del = std::min<int>(test.size(), 1 + (InsecureRandBool())); - int beg = InsecureRandRange(test.size() + 1 - del); + if (m_rng.randbits(3) == 4) { + int del = std::min<int>(test.size(), 1 + (m_rng.randbool())); + int beg = m_rng.randrange(test.size() + 1 - del); test.erase(beg, beg + del); } - if (InsecureRandBits(4) == 5) { - test.push_back(int(InsecureRand32())); + if (m_rng.randbits(4) == 5) { + test.push_back(int(m_rng.rand32())); } - if (test.size() > 0 && InsecureRandBits(4) == 6) { + if (test.size() > 0 && m_rng.randbits(4) == 6) { test.pop_back(); } - if (InsecureRandBits(5) == 7) { + if (m_rng.randbits(5) == 7) { int values[4]; - int num = 1 + (InsecureRandBits(2)); + int num = 1 + (m_rng.randbits(2)); for (int k = 0; k < num; k++) { - values[k] = int(InsecureRand32()); + values[k] = int(m_rng.rand32()); } - test.insert_range(InsecureRandRange(test.size() + 1), values, values + num); + test.insert_range(m_rng.randrange(test.size() + 1), values, values + num); } - if (InsecureRandBits(5) == 8) { - int del = std::min<int>(test.size(), 1 + (InsecureRandBits(2))); - int beg = InsecureRandRange(test.size() + 1 - del); + if (m_rng.randbits(5) == 8) { + int del = std::min<int>(test.size(), 1 + (m_rng.randbits(2))); + int beg = m_rng.randrange(test.size() + 1 - del); test.erase(beg, beg + del); } - if (InsecureRandBits(5) == 9) { - test.reserve(InsecureRandBits(5)); + if (m_rng.randbits(5) == 9) { + test.reserve(m_rng.randbits(5)); } - if (InsecureRandBits(6) == 10) { + if (m_rng.randbits(6) == 10) { test.shrink_to_fit(); } if (test.size() > 0) { - test.update(InsecureRandRange(test.size()), int(InsecureRand32())); + test.update(m_rng.randrange(test.size()), int(m_rng.rand32())); } - if (InsecureRandBits(10) == 11) { + if (m_rng.randbits(10) == 11) { test.clear(); } - if (InsecureRandBits(9) == 12) { - test.assign(InsecureRandBits(5), int(InsecureRand32())); + if (m_rng.randbits(9) == 12) { + test.assign(m_rng.randbits(5), int(m_rng.rand32())); } - if (InsecureRandBits(3) == 3) { + if (m_rng.randbits(3) == 3) { test.swap(); } - if (InsecureRandBits(4) == 8) { + if (m_rng.randbits(4) == 8) { test.copy(); } - if (InsecureRandBits(5) == 18) { + if (m_rng.randbits(5) == 18) { test.move(); } - if (InsecureRandBits(5) == 19) { - unsigned int num = 1 + (InsecureRandBits(4)); + if (m_rng.randbits(5) == 19) { + unsigned int num = 1 + (m_rng.randbits(4)); std::vector<int> values(num); for (int& v : values) { - v = int(InsecureRand32()); + v = int(m_rng.rand32()); } test.resize_uninitialized(values); } diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index c5a8f2dfbc..531ea268ef 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -110,8 +110,7 @@ static ScriptError_t ParseScriptError(const std::string& name) return SCRIPT_ERR_UNKNOWN_ERROR; } -BOOST_FIXTURE_TEST_SUITE(script_tests, BasicTestingSetup) - +struct ScriptTest : BasicTestingSetup { void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScriptWitness& scriptWitness, uint32_t flags, const std::string& message, int scriptError, CAmount nValue = 0) { bool expect = (scriptError == SCRIPT_ERR_OK); @@ -128,7 +127,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript // Verify that removing flags from a passing test or adding flags to a failing test does not change the result. for (int i = 0; i < 16; ++i) { - uint32_t extra_flags(InsecureRandBits(16)); + uint32_t extra_flags(m_rng.randbits(16)); uint32_t combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)}; // Weed out some invalid flag combinations. if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue; @@ -136,6 +135,7 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, &scriptWitness, combined_flags, MutableTransactionSignatureChecker(&tx, 0, txCredit.vout[0].nValue, MissingDataBehavior::ASSERT_FAIL), &err) == expect, message + strprintf(" (with flags %x)", combined_flags)); } } +}; // struct ScriptTest void static NegateSignatureS(std::vector<unsigned char>& vchSig) { // Parse the signature. @@ -369,11 +369,11 @@ public: return *this; } - TestBuilder& Test() + TestBuilder& Test(ScriptTest& test) { TestBuilder copy = *this; // Make a copy so we can rollback the push. DoPush(); - DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, scriptWitness, flags, comment, scriptError, nValue); + test.DoTest(creditTx->vout[0].scriptPubKey, spendTx.vin[0].scriptSig, scriptWitness, flags, comment, scriptError, nValue); *this = copy; return *this; } @@ -425,6 +425,8 @@ std::string JSONPrettyPrint(const UniValue& univalue) } } // namespace +BOOST_FIXTURE_TEST_SUITE(script_tests, ScriptTest) + BOOST_AUTO_TEST_CASE(script_build) { const KeyData keys; @@ -884,7 +886,7 @@ BOOST_AUTO_TEST_CASE(script_build) std::string strGen; #endif for (TestBuilder& test : tests) { - test.Test(); + test.Test(*this); std::string str = JSONPrettyPrint(test.GetJSON()); #ifdef UPDATE_JSON_TESTS strGen += str + ",\n"; diff --git a/src/test/serfloat_tests.cpp b/src/test/serfloat_tests.cpp index 51c026e2ed..4464b0a089 100644 --- a/src/test/serfloat_tests.cpp +++ b/src/test/serfloat_tests.cpp @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(double_serfloat_tests) { // These specific bits are the sign bit, and the 2 top and bottom bits of // exponent and mantissa in the IEEE754 binary64 format. for (int x = 0; x < 512; ++x) { - uint64_t v = InsecureRandBits(64); + uint64_t v = m_rng.randbits(64); int x_pos = 0; for (int v_pos : {0, 1, 50, 51, 52, 53, 61, 62, 63}) { v &= ~(uint64_t{1} << v_pos); diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp index 70a18835d2..d3320878ec 100644 --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -82,39 +82,41 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un return ss.GetHash(); } -void static RandomScript(CScript &script) { +struct SigHashTest : BasicTestingSetup { +void RandomScript(CScript &script) { static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR}; script = CScript(); - int ops = (InsecureRandRange(10)); + int ops = (m_rng.randrange(10)); for (int i=0; i<ops; i++) - script << oplist[InsecureRandRange(std::size(oplist))]; + script << oplist[m_rng.randrange(std::size(oplist))]; } -void static RandomTransaction(CMutableTransaction& tx, bool fSingle) +void RandomTransaction(CMutableTransaction& tx, bool fSingle) { - tx.version = InsecureRand32(); + tx.version = m_rng.rand32(); tx.vin.clear(); tx.vout.clear(); - tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0; - int ins = (InsecureRandBits(2)) + 1; - int outs = fSingle ? ins : (InsecureRandBits(2)) + 1; + tx.nLockTime = (m_rng.randbool()) ? m_rng.rand32() : 0; + int ins = (m_rng.randbits(2)) + 1; + int outs = fSingle ? ins : (m_rng.randbits(2)) + 1; for (int in = 0; in < ins; in++) { tx.vin.emplace_back(); CTxIn &txin = tx.vin.back(); - txin.prevout.hash = Txid::FromUint256(InsecureRand256()); - txin.prevout.n = InsecureRandBits(2); + txin.prevout.hash = Txid::FromUint256(m_rng.rand256()); + txin.prevout.n = m_rng.randbits(2); RandomScript(txin.scriptSig); - txin.nSequence = (InsecureRandBool()) ? InsecureRand32() : std::numeric_limits<uint32_t>::max(); + txin.nSequence = (m_rng.randbool()) ? m_rng.rand32() : std::numeric_limits<uint32_t>::max(); } for (int out = 0; out < outs; out++) { tx.vout.emplace_back(); CTxOut &txout = tx.vout.back(); - txout.nValue = InsecureRandMoneyAmount(); + txout.nValue = RandMoney(m_rng); RandomScript(txout.scriptPubKey); } } +}; // struct SigHashTest -BOOST_FIXTURE_TEST_SUITE(sighash_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(sighash_tests, SigHashTest) BOOST_AUTO_TEST_CASE(sighash_test) { @@ -126,12 +128,12 @@ BOOST_AUTO_TEST_CASE(sighash_test) int nRandomTests = 50000; #endif for (int i=0; i<nRandomTests; i++) { - int nHashType{int(InsecureRand32())}; + int nHashType{int(m_rng.rand32())}; CMutableTransaction txTo; RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); CScript scriptCode; RandomScript(scriptCode); - int nIn = InsecureRandRange(txTo.vin.size()); + int nIn = m_rng.randrange(txTo.vin.size()); uint256 sh, sho; sho = SignatureHashOld(scriptCode, CTransaction(txTo), nIn, nHashType); diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp index 050033e43a..7ffa6f641e 100644 --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -34,8 +34,8 @@ BOOST_AUTO_TEST_CASE(skiplist_test) } for (int i=0; i < 1000; i++) { - int from = InsecureRandRange(SKIPLIST_LENGTH - 1); - int to = InsecureRandRange(from + 1); + int from = m_rng.randrange(SKIPLIST_LENGTH - 1); + int to = m_rng.randrange(from + 1); BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]); BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]); @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test) // Test 100 random starting points for locators. for (int n=0; n<100; n++) { - int r = InsecureRandRange(150000); + int r = m_rng.randrange(150000); CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000]; CBlockLocator locator = GetLocator(tip); @@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test) } else { // randomly choose something in the range [MTP, MTP*2] int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast(); - int r{int(InsecureRandRange(medianTimePast))}; + int r{int(m_rng.randrange(medianTimePast))}; vBlocksMain[i].nTime = uint32_t(r + medianTimePast); vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax); } @@ -134,7 +134,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test) // Verify that FindEarliestAtLeast is correct. for (unsigned int i=0; i<10000; ++i) { // Pick a random element in vBlocksMain. - int r = InsecureRandRange(vBlocksMain.size()); + int r = m_rng.randrange(vBlocksMain.size()); int64_t test_time = vBlocksMain[r].nTime; CBlockIndex* ret = chain.FindEarliestAtLeast(test_time, 0); BOOST_CHECK(ret->nTimeMax >= test_time); diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp index 9296cbb41c..9217f05945 100644 --- a/src/test/streams_tests.cpp +++ b/src/test/streams_tests.cpp @@ -440,14 +440,14 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp"; for (int rep = 0; rep < 50; ++rep) { AutoFile file{fsbridge::fopen(streams_test_filename, "w+b")}; - size_t fileSize = InsecureRandRange(256); + size_t fileSize = m_rng.randrange(256); for (uint8_t i = 0; i < fileSize; ++i) { file << i; } std::rewind(file.Get()); - size_t bufSize = InsecureRandRange(300) + 1; - size_t rewindSize = InsecureRandRange(bufSize); + size_t bufSize = m_rng.randrange(300) + 1; + size_t rewindSize = m_rng.randrange(bufSize); BufferedFile bf{file, bufSize, rewindSize}; size_t currentPos = 0; size_t maxPos = 0; @@ -463,7 +463,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) // sizes; the boundaries of the objects can interact arbitrarily // with the CBufferFile's internal buffer. These first three // cases simulate objects of various sizes (1, 2, 5 bytes). - switch (InsecureRandRange(6)) { + switch (m_rng.randrange(6)) { case 0: { uint8_t a[1]; if (currentPos + 1 > fileSize) @@ -503,7 +503,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) case 3: { // SkipTo is similar to the "read" cases above, except // we don't receive the data. - size_t skip_length{static_cast<size_t>(InsecureRandRange(5))}; + size_t skip_length{static_cast<size_t>(m_rng.randrange(5))}; if (currentPos + skip_length > fileSize) continue; bf.SetLimit(currentPos + skip_length); bf.SkipTo(currentPos + skip_length); @@ -512,7 +512,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) } case 4: { // Find a byte value (that is at or ahead of the current position). - size_t find = currentPos + InsecureRandRange(8); + size_t find = currentPos + m_rng.randrange(8); if (find >= fileSize) find = fileSize - 1; bf.FindByte(std::byte(find)); @@ -528,7 +528,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand) break; } case 5: { - size_t requestPos = InsecureRandRange(maxPos + 4); + size_t requestPos = m_rng.randrange(maxPos + 4); bool okay = bf.SetPos(requestPos); // The new position may differ from the requested position // because we may not be able to rewind beyond the rewind diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 5622632e97..575f414731 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest); } // Removing random combinations of flags - flags = TrimFlags(~(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size()))); + flags = TrimFlags(~(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size()))); if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) { BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags) << ": " << strTest); } @@ -354,7 +354,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest); } // Adding random combinations of flags - flags = FillFlags(verify_flags | (unsigned int)InsecureRandBits(mapFlagNames.size())); + flags = FillFlags(verify_flags | (unsigned int)m_rng.randbits(mapFlagNames.size())); if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) { BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest); } diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp index ca9dc5527d..43276a7a97 100644 --- a/src/test/txpackage_tests.cpp +++ b/src/test/txpackage_tests.cpp @@ -20,20 +20,20 @@ #include <boost/test/unit_test.hpp> -BOOST_AUTO_TEST_SUITE(txpackage_tests) // A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these // unit tests. static const CAmount low_fee_amt{200}; +struct TxPackageTest : TestChain100Setup { // Create placeholder transactions that have no meaning. inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs) { CMutableTransaction mtx = CMutableTransaction(); mtx.vin.resize(num_inputs); mtx.vout.resize(num_outputs); - auto random_script = CScript() << ToByteVector(InsecureRand256()) << ToByteVector(InsecureRand256()); + auto random_script = CScript() << ToByteVector(m_rng.rand256()) << ToByteVector(m_rng.rand256()); for (size_t i{0}; i < num_inputs; ++i) { - mtx.vin[i].prevout.hash = Txid::FromUint256(InsecureRand256()); + mtx.vin[i].prevout.hash = Txid::FromUint256(m_rng.rand256()); mtx.vin[i].prevout.n = 0; mtx.vin[i].scriptSig = random_script; } @@ -43,7 +43,11 @@ inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outpu } return MakeTransactionRef(mtx); } -BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup) +}; // struct TxPackageTest + +BOOST_FIXTURE_TEST_SUITE(txpackage_tests, TxPackageTest) + +BOOST_AUTO_TEST_CASE(package_hash_tests) { // Random real segwit transaction DataStream stream_1{ @@ -124,7 +128,7 @@ BOOST_FIXTURE_TEST_CASE(package_hash_tests, TestChain100Setup) BOOST_CHECK_EQUAL(calculated_hash_123, GetPackageHash(package_321)); } -BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_sanitization_tests) { // Packages can't have more than 25 transactions. Package package_too_many; @@ -167,7 +171,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) // Packages can't have transactions spending the same prevout CMutableTransaction tx_zero_1; CMutableTransaction tx_zero_2; - COutPoint same_prevout{Txid::FromUint256(InsecureRand256()), 0}; + COutPoint same_prevout{Txid::FromUint256(m_rng.rand256()), 0}; tx_zero_1.vin.emplace_back(same_prevout); tx_zero_2.vin.emplace_back(same_prevout); // Different vouts (not the same tx) @@ -185,7 +189,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) // IsConsistentPackage only cares about conflicts between transactions, not about a transaction // conflicting with itself (i.e. duplicate prevouts in vin). CMutableTransaction dup_tx; - const COutPoint rand_prevout{Txid::FromUint256(InsecureRand256()), 0}; + const COutPoint rand_prevout{Txid::FromUint256(m_rng.rand256()), 0}; dup_tx.vin.emplace_back(rand_prevout); dup_tx.vin.emplace_back(rand_prevout); Package package_with_dup_tx{MakeTransactionRef(dup_tx)}; @@ -194,7 +198,7 @@ BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup) BOOST_CHECK(IsConsistentPackage(package_with_dup_tx)); } -BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_validation_tests) { LOCK(cs_main); unsigned int initialPoolSize = m_node.mempool->size(); @@ -249,7 +253,7 @@ BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize); } -BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(noncontextual_package_tests) { // The signatures won't be verified so we can just use a placeholder CKey placeholder_key = GenerateRandomKey(); @@ -345,7 +349,7 @@ BOOST_FIXTURE_TEST_CASE(noncontextual_package_tests, TestChain100Setup) } } -BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_submission_tests) { LOCK(cs_main); unsigned int expected_pool_size = m_node.mempool->size(); @@ -488,7 +492,7 @@ BOOST_FIXTURE_TEST_CASE(package_submission_tests, TestChain100Setup) // Tests for packages containing transactions that have same-txid-different-witness equivalents in // the mempool. -BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_witness_swap_tests) { // Mine blocks to mature coinbases. mineBlocks(5); @@ -722,7 +726,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) } } -BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_cpfp_tests) { mineBlocks(5); MockMempoolMinFee(CFeeRate(5000)); @@ -933,7 +937,7 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup) } } -BOOST_FIXTURE_TEST_CASE(package_rbf_tests, TestChain100Setup) +BOOST_AUTO_TEST_CASE(package_rbf_tests) { mineBlocks(5); LOCK(::cs_main); diff --git a/src/test/txrequest_tests.cpp b/src/test/txrequest_tests.cpp index 0ca70d2c7a..6bb732ba69 100644 --- a/src/test/txrequest_tests.cpp +++ b/src/test/txrequest_tests.cpp @@ -15,10 +15,23 @@ #include <boost/test/unit_test.hpp> -BOOST_FIXTURE_TEST_SUITE(txrequest_tests, BasicTestingSetup) - namespace { +class Scenario; + +struct TxRequestTest : BasicTestingSetup { + std::chrono::microseconds RandomTime8s(); + std::chrono::microseconds RandomTime1y(); + void BuildSingleTest(Scenario& scenario, int config); + void BuildPriorityTest(Scenario& scenario, int config); + void BuildBigPriorityTest(Scenario& scenario, int peers); + void BuildRequestOrderTest(Scenario& scenario, int config); + void BuildWtxidTest(Scenario& scenario, int config); + void BuildTimeBackwardsTest(Scenario& scenario); + void BuildWeirdRequestsTest(Scenario& scenario); + void TestInterleavedScenarios(); +}; + constexpr std::chrono::microseconds MIN_TIME = std::chrono::microseconds::min(); constexpr std::chrono::microseconds MAX_TIME = std::chrono::microseconds::max(); constexpr std::chrono::microseconds MICROSECOND = std::chrono::microseconds{1}; @@ -51,8 +64,8 @@ struct Runner std::multiset<std::pair<NodeId, GenTxid>> expired; }; -std::chrono::microseconds RandomTime8s() { return std::chrono::microseconds{1 + InsecureRandBits(23)}; } -std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 + InsecureRandBits(45)}; } +std::chrono::microseconds TxRequestTest::RandomTime8s() { return std::chrono::microseconds{1 + m_rng.randbits(23)}; } +std::chrono::microseconds TxRequestTest::RandomTime1y() { return std::chrono::microseconds{1 + m_rng.randbits(45)}; } /** A proxy for a Runner that helps build a sequence of consecutive test actions on a TxRequestTracker. * @@ -65,12 +78,13 @@ std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 + */ class Scenario { + FastRandomContext& m_rng; Runner& m_runner; std::chrono::microseconds m_now; std::string m_testname; public: - Scenario(Runner& runner, std::chrono::microseconds starttime) : m_runner(runner), m_now(starttime) {} + Scenario(FastRandomContext& rng, Runner& runner, std::chrono::microseconds starttime) : m_rng(rng), m_runner(runner), m_now(starttime) {} /** Set a name for the current test, to give more clear error messages. */ void SetTestName(std::string testname) @@ -199,7 +213,7 @@ public: uint256 ret; bool ok; do { - ret = InsecureRand256(); + ret = m_rng.rand256(); ok = true; for (const auto& order : orders) { for (size_t pos = 1; pos < order.size(); ++pos) { @@ -222,7 +236,7 @@ public: /** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */ GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {}) { - return InsecureRandBool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders)); + return m_rng.randbool() ? GenTxid::Wtxid(NewTxHash(orders)) : GenTxid::Txid(NewTxHash(orders)); } /** Generate a new random NodeId to use as peer. The same NodeId is never returned twice @@ -232,7 +246,7 @@ public: bool ok; NodeId ret; do { - ret = InsecureRandBits(63); + ret = m_rng.randbits(63); ok = m_runner.peerset.insert(ret).second; } while(!ok); return ret; @@ -245,7 +259,7 @@ public: * * config is an integer in [0, 32), which controls which variant of the test is used. */ -void BuildSingleTest(Scenario& scenario, int config) +void TxRequestTest::BuildSingleTest(Scenario& scenario, int config) { auto peer = scenario.NewPeer(); auto gtxid = scenario.NewGTxid(); @@ -282,7 +296,7 @@ void BuildSingleTest(Scenario& scenario, int config) scenario.CheckExpired(peer, gtxid); return; } else { - scenario.AdvanceTime(std::chrono::microseconds{InsecureRandRange(expiry.count())}); + scenario.AdvanceTime(std::chrono::microseconds{m_rng.randrange(expiry.count())}); scenario.Check(peer, {}, 0, 1, 0, "s9"); if ((config >> 3) == 3) { // A response will arrive for the transaction scenario.ReceivedResponse(peer, gtxid.GetHash()); @@ -305,7 +319,7 @@ void BuildSingleTest(Scenario& scenario, int config) * * config is an integer in [0, 32), which controls which variant of the test is used. */ -void BuildPriorityTest(Scenario& scenario, int config) +void TxRequestTest::BuildPriorityTest(Scenario& scenario, int config) { scenario.SetTestName(strprintf("Priority(config=%i)", config)); @@ -319,7 +333,7 @@ void BuildPriorityTest(Scenario& scenario, int config) scenario.ReceivedInv(peer1, gtxid, pref1, MIN_TIME); scenario.Check(peer1, {gtxid}, 1, 0, 0, "p1"); - if (InsecureRandBool()) { + if (m_rng.randbool()) { scenario.AdvanceTime(RandomTime8s()); scenario.Check(peer1, {gtxid}, 1, 0, 0, "p2"); } @@ -335,7 +349,7 @@ void BuildPriorityTest(Scenario& scenario, int config) NodeId priopeer = stage2_prio ? peer2 : peer1, otherpeer = stage2_prio ? peer1 : peer2; scenario.Check(otherpeer, {}, 1, 0, 0, "p3"); scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p4"); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.Check(otherpeer, {}, 1, 0, 0, "p5"); scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p6"); @@ -344,7 +358,7 @@ void BuildPriorityTest(Scenario& scenario, int config) scenario.RequestedTx(priopeer, gtxid.GetHash(), MAX_TIME); scenario.Check(priopeer, {}, 0, 1, 0, "p7"); scenario.Check(otherpeer, {}, 1, 0, 0, "p8"); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); } // The peer which was selected (or requested from) now goes offline, or a NOTFOUND is received from them. @@ -353,28 +367,28 @@ void BuildPriorityTest(Scenario& scenario, int config) } else { scenario.ReceivedResponse(priopeer, gtxid.GetHash()); } - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.Check(priopeer, {}, 0, 0, !(config & 16), "p8"); scenario.Check(otherpeer, {gtxid}, 1, 0, 0, "p9"); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); // Now the other peer goes offline. scenario.DisconnectedPeer(otherpeer); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.Check(peer1, {}, 0, 0, 0, "p10"); scenario.Check(peer2, {}, 0, 0, 0, "p11"); } /** Add to scenario a randomized test in which N peers announce the same transaction, to verify * the order in which they are requested. */ -void BuildBigPriorityTest(Scenario& scenario, int peers) +void TxRequestTest::BuildBigPriorityTest(Scenario& scenario, int peers) { scenario.SetTestName(strprintf("BigPriority(peers=%i)", peers)); // We will have N peers announce the same transaction. std::map<NodeId, bool> preferred; std::vector<NodeId> pref_peers, npref_peers; - int num_pref = InsecureRandRange(peers + 1) ; // Some preferred, ... + int num_pref = m_rng.randrange(peers + 1) ; // Some preferred, ... int num_npref = peers - num_pref; // some not preferred. for (int i = 0; i < num_pref; ++i) { pref_peers.push_back(scenario.NewPeer()); @@ -392,7 +406,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers) // Determine the announcement order randomly. std::vector<NodeId> announce_order = request_order; - std::shuffle(announce_order.begin(), announce_order.end(), g_insecure_rand_ctx); + std::shuffle(announce_order.begin(), announce_order.end(), m_rng); // Find a gtxid whose txhash prioritization is consistent with the required ordering within pref_peers and // within npref_peers. @@ -427,11 +441,11 @@ void BuildBigPriorityTest(Scenario& scenario, int peers) // Peers now in random order go offline, or send NOTFOUNDs. At every point in time the new to-be-requested-from // peer should be the best remaining one, so verify this after every response. for (int i = 0; i < peers; ++i) { - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); - const int pos = InsecureRandRange(request_order.size()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); + const int pos = m_rng.randrange(request_order.size()); const auto peer = request_order[pos]; request_order.erase(request_order.begin() + pos); - if (InsecureRandBool()) { + if (m_rng.randbool()) { scenario.DisconnectedPeer(peer); scenario.Check(peer, {}, 0, 0, 0, "b4"); } else { @@ -454,7 +468,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers) * * config is an integer in [0, 4) inclusive, and selects the variant of the test. */ -void BuildRequestOrderTest(Scenario& scenario, int config) +void TxRequestTest::BuildRequestOrderTest(Scenario& scenario, int config) { scenario.SetTestName(strprintf("RequestOrder(config=%i)", config)); @@ -489,7 +503,7 @@ void BuildRequestOrderTest(Scenario& scenario, int config) * * config is an integer in [0, 4) inclusive, and selects the variant of the test used. */ -void BuildWtxidTest(Scenario& scenario, int config) +void TxRequestTest::BuildWtxidTest(Scenario& scenario, int config) { scenario.SetTestName(strprintf("Wtxid(config=%i)", config)); @@ -499,17 +513,17 @@ void BuildWtxidTest(Scenario& scenario, int config) auto txid{GenTxid::Txid(txhash)}; auto wtxid{GenTxid::Wtxid(txhash)}; - auto reqtimeT = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); - auto reqtimeW = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); + auto reqtimeT = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s(); + auto reqtimeW = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s(); // Announce txid first or wtxid first. if (config & 1) { scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW); } else { scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW); - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT); } @@ -552,14 +566,14 @@ void BuildWtxidTest(Scenario& scenario, int config) // If a good transaction with either that hash as wtxid or txid arrives, both // announcements are gone. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ForgetTxHash(txhash); scenario.Check(peerT, {}, 0, 0, 0, "w13"); scenario.Check(peerW, {}, 0, 0, 0, "w14"); } /** Add to scenario a test that exercises clocks that go backwards. */ -void BuildTimeBackwardsTest(Scenario& scenario) +void TxRequestTest::BuildTimeBackwardsTest(Scenario& scenario) { auto peer1 = scenario.NewPeer(); auto peer2 = scenario.NewPeer(); @@ -577,13 +591,13 @@ void BuildTimeBackwardsTest(Scenario& scenario) scenario.Check(peer2, {gtxid}, 1, 0, 0, "r4"); // Announce from peer1. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peer1, gtxid, true, MAX_TIME); scenario.Check(peer2, {gtxid}, 1, 0, 0, "r5"); scenario.Check(peer1, {}, 1, 0, 0, "r6"); // Request from peer1. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); auto expiry = scenario.Now() + RandomTime8s(); scenario.RequestedTx(peer1, gtxid.GetHash(), expiry); scenario.Check(peer1, {}, 0, 1, 0, "r7"); @@ -598,14 +612,14 @@ void BuildTimeBackwardsTest(Scenario& scenario) scenario.Check(peer2, {gtxid}, 1, 0, 0, "r12", -MICROSECOND); // Peer2 goes offline, meaning no viable announcements remain. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.DisconnectedPeer(peer2); scenario.Check(peer1, {}, 0, 0, 0, "r13"); scenario.Check(peer2, {}, 0, 0, 0, "r14"); } /** Add to scenario a test that involves RequestedTx() calls for txhashes not returned by GetRequestable. */ -void BuildWeirdRequestsTest(Scenario& scenario) +void TxRequestTest::BuildWeirdRequestsTest(Scenario& scenario) { auto peer1 = scenario.NewPeer(); auto peer2 = scenario.NewPeer(); @@ -617,19 +631,19 @@ void BuildWeirdRequestsTest(Scenario& scenario) scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q1"); // Announce gtxid2 by peer2. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peer2, gtxid2, true, MIN_TIME); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q2"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q3"); // We request gtxid2 from *peer1* - no effect. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5"); // Now request gtxid1 from peer1 - marks it as REQUESTED. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); auto expiryA = scenario.Now() + RandomTime8s(); scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA); scenario.Check(peer1, {}, 0, 1, 0, "q6"); @@ -653,25 +667,25 @@ void BuildWeirdRequestsTest(Scenario& scenario) scenario.CheckExpired(peer1, gtxid1); // Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer1, gtxid1.GetHash(), MAX_TIME); scenario.Check(peer1, {}, 0, 0, 1, "q14"); scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15"); // Now announce gtxid2 from peer1. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.ReceivedInv(peer1, gtxid2, true, MIN_TIME); scenario.Check(peer1, {}, 1, 0, 1, "q16"); scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q17"); // And request it from peer1 (weird as peer2 has the preference). - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME); scenario.Check(peer1, {}, 0, 1, 1, "q18"); scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19"); // If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED. - if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); + if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s()); scenario.RequestedTx(peer2, gtxid2.GetHash(), MAX_TIME); scenario.Check(peer1, {}, 0, 0, 2, "q20"); scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21"); @@ -682,22 +696,22 @@ void BuildWeirdRequestsTest(Scenario& scenario) scenario.Check(peer2, {}, 0, 0, 0, "q23"); } -void TestInterleavedScenarios() +void TxRequestTest::TestInterleavedScenarios() { // Create a list of functions which add tests to scenarios. std::vector<std::function<void(Scenario&)>> builders; // Add instances of every test, for every configuration. for (int n = 0; n < 64; ++n) { - builders.emplace_back([n](Scenario& scenario){ BuildWtxidTest(scenario, n); }); - builders.emplace_back([n](Scenario& scenario){ BuildRequestOrderTest(scenario, n & 3); }); - builders.emplace_back([n](Scenario& scenario){ BuildSingleTest(scenario, n & 31); }); - builders.emplace_back([n](Scenario& scenario){ BuildPriorityTest(scenario, n & 31); }); - builders.emplace_back([n](Scenario& scenario){ BuildBigPriorityTest(scenario, (n & 7) + 1); }); - builders.emplace_back([](Scenario& scenario){ BuildTimeBackwardsTest(scenario); }); - builders.emplace_back([](Scenario& scenario){ BuildWeirdRequestsTest(scenario); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildWtxidTest(scenario, n); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildRequestOrderTest(scenario, n & 3); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildSingleTest(scenario, n & 31); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildPriorityTest(scenario, n & 31); }); + builders.emplace_back([this, n](Scenario& scenario) { BuildBigPriorityTest(scenario, (n & 7) + 1); }); + builders.emplace_back([this](Scenario& scenario) { BuildTimeBackwardsTest(scenario); }); + builders.emplace_back([this](Scenario& scenario) { BuildWeirdRequestsTest(scenario); }); } // Randomly shuffle all those functions. - std::shuffle(builders.begin(), builders.end(), g_insecure_rand_ctx); + std::shuffle(builders.begin(), builders.end(), m_rng); Runner runner; auto starttime = RandomTime1y(); @@ -706,7 +720,7 @@ void TestInterleavedScenarios() // Introduce some variation in the start time of each scenario, so they don't all start off // concurrently, but get a more random interleaving. auto scenario_start = starttime + RandomTime8s() + RandomTime8s() + RandomTime8s(); - Scenario scenario(runner, scenario_start); + Scenario scenario(m_rng, runner, scenario_start); for (int j = 0; builders.size() && j < 10; ++j) { builders.back()(scenario); builders.pop_back(); @@ -730,6 +744,8 @@ void TestInterleavedScenarios() } // namespace +BOOST_FIXTURE_TEST_SUITE(txrequest_tests, TxRequestTest) + BOOST_AUTO_TEST_CASE(TxRequestTest) { for (int i = 0; i < 5; ++i) { diff --git a/src/test/util/coins.cpp b/src/test/util/coins.cpp index 742dbc04d1..7e10c7c58d 100644 --- a/src/test/util/coins.cpp +++ b/src/test/util/coins.cpp @@ -13,12 +13,12 @@ #include <stdint.h> #include <utility> -COutPoint AddTestCoin(CCoinsViewCache& coins_view) +COutPoint AddTestCoin(FastRandomContext& rng, CCoinsViewCache& coins_view) { Coin new_coin; - COutPoint outpoint{Txid::FromUint256(InsecureRand256()), /*nIn=*/0}; + COutPoint outpoint{Txid::FromUint256(rng.rand256()), /*nIn=*/0}; new_coin.nHeight = 1; - new_coin.out.nValue = InsecureRandMoneyAmount(); + new_coin.out.nValue = RandMoney(rng); new_coin.out.scriptPubKey.assign(uint32_t{56}, 1); coins_view.AddCoin(outpoint, std::move(new_coin), /*possible_overwrite=*/false); diff --git a/src/test/util/coins.h b/src/test/util/coins.h index 5e6f4293ae..89a9e7b329 100644 --- a/src/test/util/coins.h +++ b/src/test/util/coins.h @@ -8,12 +8,13 @@ #include <primitives/transaction.h> class CCoinsViewCache; +class FastRandomContext; /** * Create a Coin with DynamicMemoryUsage of 80 bytes and add it to the given view. * @param[in,out] coins_view The coins view cache to add the new coin to. * @returns the COutPoint of the created coin. */ -COutPoint AddTestCoin(CCoinsViewCache& coins_view); +COutPoint AddTestCoin(FastRandomContext& rng, CCoinsViewCache& coins_view); #endif // BITCOIN_TEST_UTIL_COINS_H diff --git a/src/test/util/random.cpp b/src/test/util/random.cpp index 8e0623ea06..b568f275a5 100644 --- a/src/test/util/random.cpp +++ b/src/test/util/random.cpp @@ -12,11 +12,9 @@ #include <cstdlib> #include <iostream> -FastRandomContext g_insecure_rand_ctx; - extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; -void SeedRandomForTest(SeedRand seedtype) +void SeedRandomStateForTest(SeedRand seedtype) { constexpr auto RANDOM_CTX_SEED{"RANDOM_CTX_SEED"}; @@ -41,5 +39,4 @@ void SeedRandomForTest(SeedRand seedtype) const uint256& seed{seedtype == SeedRand::SEED ? ctx_seed : uint256::ZERO}; LogInfo("Setting random seed for current tests to %s=%s\n", RANDOM_CTX_SEED, seed.GetHex()); MakeRandDeterministicDANGEROUS(seed); - g_insecure_rand_ctx.Reseed(GetRandHash()); } diff --git a/src/test/util/random.h b/src/test/util/random.h index 09a475f8b3..c458534d48 100644 --- a/src/test/util/random.h +++ b/src/test/util/random.h @@ -1,4 +1,4 @@ -// Copyright (c) 2023 The Bitcoin Core developers +// Copyright (c) 2023-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -11,50 +11,18 @@ #include <cstdint> -/** - * This global and the helpers that use it are not thread-safe. - * - * If thread-safety is needed, a per-thread instance could be - * used in the multi-threaded test. - */ -extern FastRandomContext g_insecure_rand_ctx; - enum class SeedRand { ZEROS, //!< Seed with a compile time constant of zeros SEED, //!< Use (and report) random seed from environment, or a (truly) random one. }; -/** Seed the RNG for testing. This affects all randomness, except GetStrongRandBytes(). */ -void SeedRandomForTest(SeedRand seed = SeedRand::SEED); - -static inline uint32_t InsecureRand32() -{ - return g_insecure_rand_ctx.rand32(); -} - -static inline uint256 InsecureRand256() -{ - return g_insecure_rand_ctx.rand256(); -} - -static inline uint64_t InsecureRandBits(int bits) -{ - return g_insecure_rand_ctx.randbits(bits); -} - -static inline uint64_t InsecureRandRange(uint64_t range) -{ - return g_insecure_rand_ctx.randrange(range); -} - -static inline bool InsecureRandBool() -{ - return g_insecure_rand_ctx.randbool(); -} +/** Seed the global RNG state for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */ +void SeedRandomStateForTest(SeedRand seed); -static inline CAmount InsecureRandMoneyAmount() +template <RandomNumberGenerator Rng> +inline CAmount RandMoney(Rng&& rng) { - return static_cast<CAmount>(InsecureRandRange(MAX_MONEY + 1)); + return CAmount{rng.randrange(MAX_MONEY + 1)}; } #endif // BITCOIN_TEST_UTIL_RANDOM_H diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 62ff61b227..dcf72cf627 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -75,8 +75,8 @@ using node::VerifyLoadedChainstate; const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; -/** Random context to get unique temp data dirs. Separate from g_insecure_rand_ctx, which can be seeded from a const env var */ -static FastRandomContext g_insecure_rand_ctx_temp_path; +/** Random context to get unique temp data dirs. Separate from m_rng, which can be seeded from a const env var */ +static FastRandomContext g_rng_temp_path; std::ostream& operator<<(std::ostream& os, const arith_uint256& num) { @@ -158,7 +158,7 @@ BasicTestingSetup::BasicTestingSetup(const ChainType chainType, TestOpts opts) if (!m_node.args->IsArgSet("-testdatadir")) { // By default, the data directory has a random name - const auto rand_str{g_insecure_rand_ctx_temp_path.rand256().ToString()}; + const auto rand_str{g_rng_temp_path.rand256().ToString()}; m_path_root = fs::temp_directory_path() / "test_common_" PACKAGE_NAME / rand_str; TryCreateDirectories(m_path_root); } else { @@ -580,7 +580,7 @@ void TestChain100Setup::MockMempoolMinFee(const CFeeRate& target_feerate) // Manually create an invalid transaction. Manually set the fee in the CTxMemPoolEntry to // achieve the exact target feerate. CMutableTransaction mtx = CMutableTransaction(); - mtx.vin.emplace_back(COutPoint{Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0}); + mtx.vin.emplace_back(COutPoint{Txid::FromUint256(m_rng.rand256()), 0}); mtx.vout.emplace_back(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE))); const auto tx{MakeTransactionRef(mtx)}; LockPoints lp; diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index b73acc1de5..d995549ca6 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -13,6 +13,7 @@ #include <primitives/transaction.h> #include <pubkey.h> #include <stdexcept> +#include <test/util/random.h> #include <util/chaintype.h> // IWYU pragma: export #include <util/check.h> #include <util/fs.h> @@ -65,6 +66,14 @@ struct BasicTestingSetup { util::SignalInterrupt m_interrupt; node::NodeContext m_node; // keep as first member to be destructed last + FastRandomContext m_rng; + /** Seed the global RNG state and m_rng for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */ + void SeedRandomForTest(SeedRand seed = SeedRand::SEED) + { + SeedRandomStateForTest(seed); + m_rng.Reseed(GetRandHash()); + } + explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {}); ~BasicTestingSetup(); diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index c2c725d676..9598b9c182 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -448,7 +448,7 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand) for (int i = 0; i < 10000; i++) { uint32_t rval; do{ - rval=InsecureRand32()&mask; + rval=m_rng.rand32()&mask; }while(rval>=(uint32_t)mod); count += rval==0; } diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 588ac60498..015a5941ed 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2022 The Bitcoin Core developers +// Copyright (c) 2018-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -133,8 +133,8 @@ void MinerTestingSetup::BuildChain(const uint256& root, int height, const unsign { if (height <= 0 || blocks.size() >= max_size) return; - bool gen_invalid = InsecureRandRange(100) < invalid_rate; - bool gen_fork = InsecureRandRange(100) < branch_rate; + bool gen_invalid = m_rng.randrange(100U) < invalid_rate; + bool gen_fork = m_rng.randrange(100U) < branch_rate; const std::shared_ptr<const CBlock> pblock = gen_invalid ? BadBlock(root) : GoodBlock(root); blocks.push_back(pblock); diff --git a/src/test/validation_chainstate_tests.cpp b/src/test/validation_chainstate_tests.cpp index 1c02066047..30c5982b17 100644 --- a/src/test/validation_chainstate_tests.cpp +++ b/src/test/validation_chainstate_tests.cpp @@ -36,11 +36,11 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches) // Add a coin to the in-memory cache, upsize once, then downsize. { LOCK(::cs_main); - const auto outpoint = AddTestCoin(c1.CoinsTip()); + const auto outpoint = AddTestCoin(m_rng, c1.CoinsTip()); // Set a meaningless bestblock value in the coinsview cache - otherwise we won't // flush during ResizecoinsCaches() and will subsequently hit an assertion. - c1.CoinsTip().SetBestBlock(InsecureRand256()); + c1.CoinsTip().SetBestBlock(m_rng.rand256()); BOOST_CHECK(c1.CoinsTip().HaveCoinInCache(outpoint)); diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 2ed59ab2d3..68563f9c7d 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -718,10 +718,10 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, Sna CCoinsViewCache& ibd_coins = WITH_LOCK(::cs_main, return validation_chainstate.CoinsTip()); Coin badcoin; - badcoin.out.nValue = InsecureRand32(); + badcoin.out.nValue = m_rng.rand32(); badcoin.nHeight = 1; - badcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); - Txid txid = Txid::FromUint256(InsecureRand256()); + badcoin.out.scriptPubKey.assign(m_rng.randbits(6), 0); + Txid txid = Txid::FromUint256(m_rng.rand256()); ibd_coins.AddCoin(COutPoint(txid, 0), std::move(badcoin), false); fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot"; diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp index 7398091215..c325f7deb2 100644 --- a/src/test/validation_flush_tests.cpp +++ b/src/test/validation_flush_tests.cpp @@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Add a bunch of coins to see that we at least flip over to CRITICAL. for (int i{0}; i < 1000; ++i) { - const COutPoint res = AddTestCoin(view); + const COutPoint res = AddTestCoin(m_rng, view); BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); } @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) CoinsCacheSizeState::OK); for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) { - const COutPoint res = AddTestCoin(view); + const COutPoint res = AddTestCoin(m_rng, view); print_view_mem_usage(view); BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Adding some additional coins will push us over the edge to CRITICAL. for (int i{0}; i < 4; ++i) { - AddTestCoin(view); + AddTestCoin(m_rng, view); print_view_mem_usage(view); if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0) == CoinsCacheSizeState::CRITICAL) { @@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) CoinsCacheSizeState::OK); for (int i{0}; i < 3; ++i) { - AddTestCoin(view); + AddTestCoin(m_rng, view); print_view_mem_usage(view); BOOST_CHECK_EQUAL( chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/ 1 << 19), @@ -117,7 +117,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Adding another coin with the additional mempool room will put us >90% // but not yet critical. - AddTestCoin(view); + AddTestCoin(m_rng, view); print_view_mem_usage(view); // Only perform these checks on 64 bit hosts; I haven't done the math for 32. @@ -133,7 +133,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) // Using the default max_* values permits way more coins to be added. for (int i{0}; i < 1000; ++i) { - AddTestCoin(view); + AddTestCoin(m_rng, view); BOOST_CHECK_EQUAL( chainstate.GetCoinsCacheSizeState(), CoinsCacheSizeState::OK); @@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate) chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0), CoinsCacheSizeState::CRITICAL); - view.SetBestBlock(InsecureRand256()); + view.SetBestBlock(m_rng.rand256()); BOOST_CHECK(view.Flush()); print_view_mem_usage(view); diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp index 896840b0f3..29240a45f0 100644 --- a/src/test/versionbits_tests.cpp +++ b/src/test/versionbits_tests.cpp @@ -67,6 +67,7 @@ public: class VersionBitsTester { + FastRandomContext& m_rng; // A fake blockchain std::vector<CBlockIndex*> vpblock; @@ -85,6 +86,8 @@ class VersionBitsTester int num{1000}; public: + VersionBitsTester(FastRandomContext& rng) : m_rng{rng} {} + VersionBitsTester& Reset() { // Have each group of tests be counted by the 1000s part, starting at 1000 num = num - (num % 1000) + 1000; @@ -128,7 +131,7 @@ public: { const CBlockIndex* tip = Tip(); for (int i = 0; i < CHECKERS; i++) { - if (InsecureRandBits(i) == 0) { + if (m_rng.randbits(i) == 0) { BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(tip) == height, strprintf("Test %i for StateSinceHeight", num)); BOOST_CHECK_MESSAGE(checker_delayed[i].GetStateSinceHeightFor(tip) == height_delayed, strprintf("Test %i for StateSinceHeight (delayed)", num)); BOOST_CHECK_MESSAGE(checker_always[i].GetStateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (always active)", num)); @@ -154,7 +157,7 @@ public: const CBlockIndex* pindex = Tip(); for (int i = 0; i < CHECKERS; i++) { - if (InsecureRandBits(i) == 0) { + if (m_rng.randbits(i) == 0) { ThresholdState got = checker[i].GetStateFor(pindex); ThresholdState got_delayed = checker_delayed[i].GetStateFor(pindex); ThresholdState got_always = checker_always[i].GetStateFor(pindex); @@ -190,7 +193,7 @@ BOOST_AUTO_TEST_CASE(versionbits_test) { for (int i = 0; i < 64; i++) { // DEFINED -> STARTED after timeout reached -> FAILED - VersionBitsTester().TestDefined().TestStateSinceHeight(0) + VersionBitsTester(m_rng).TestDefined().TestStateSinceHeight(0) .Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0) .Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0) .Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0) @@ -256,8 +259,9 @@ BOOST_AUTO_TEST_CASE(versionbits_test) } } +struct BlockVersionTest : BasicTestingSetup { /** Check that ComputeBlockVersion will set the appropriate bit correctly */ -static void check_computeblockversion(VersionBitsCache& versionbitscache, const Consensus::Params& params, Consensus::DeploymentPos dep) +void check_computeblockversion(VersionBitsCache& versionbitscache, const Consensus::Params& params, Consensus::DeploymentPos dep) { // Clear the cache every time versionbitscache.Clear(); @@ -295,7 +299,7 @@ static void check_computeblockversion(VersionBitsCache& versionbitscache, const // In the first chain, test that the bit is set by CBV until it has failed. // In the second chain, test the bit is set by CBV while STARTED and // LOCKED-IN, and then no longer set while ACTIVE. - VersionBitsTester firstChain, secondChain; + VersionBitsTester firstChain{m_rng}, secondChain{m_rng}; int64_t nTime = nStartTime; @@ -412,8 +416,9 @@ static void check_computeblockversion(VersionBitsCache& versionbitscache, const // Check that we don't signal after activation BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); } +}; // struct BlockVersionTest -BOOST_AUTO_TEST_CASE(versionbits_computeblockversion) +BOOST_FIXTURE_TEST_CASE(versionbits_computeblockversion, BlockVersionTest) { VersionBitsCache vbcache; diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp index d5e75bb892..e413bc1fa0 100644 --- a/src/wallet/test/wallet_crypto_tests.cpp +++ b/src/wallet/test/wallet_crypto_tests.cpp @@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(passphrase) { std::string hash(GetRandHash().ToString()); std::vector<unsigned char> vchSalt(8); GetRandBytes(vchSalt); - uint32_t rounds = InsecureRand32(); + uint32_t rounds = m_rng.rand32(); if (rounds > 30000) rounds = 30000; TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds); diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 1918233e47..5a520cbfe9 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -980,7 +980,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup) CMutableTransaction mtx; mtx.vout.emplace_back(COIN, GetScriptForDestination(op_dest)); - mtx.vin.emplace_back(Txid::FromUint256(g_insecure_rand_ctx.rand256()), 0); + mtx.vin.emplace_back(Txid::FromUint256(m_rng.rand256()), 0); const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash(); { |