0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-10 10:52:31 -05:00

Merge bitcoin/bitcoin#30571: test: [refactor] Use m_rng directly

948238a683 test: Remove FastRandomContext global (Ryan Ofsky)
fa0fe08eca scripted-diff: [test] Use g_rng/m_rng directly (MarcoFalke)
fa54cab473 test: refactor: Accept any RandomNumberGenerator in RandMoney (MarcoFalke)
68f77dd21e test: refactor: Pass rng parameters to test functions (Ryan Ofsky)
fa19af555d test: refactor: Move g_insecure_rand_ctx.Reseed out of the helper that calls MakeRandDeterministicDANGEROUS (MarcoFalke)
3dc527f460 test: refactor: Give unit test functions access to test state (Ryan Ofsky)
fab023e177 test: refactor: Make unsigned promotion explicit (MarcoFalke)
fa2cb654ec test: Add m_rng alias for the global random context (MarcoFalke)
fae7e3791c test: Correct the random seed log on a prevector test failure (MarcoFalke)

Pull request description:

  This is mostly a style-cleanup for the tests' random generation:

  1) `g_insecure_rand_ctx` in the tests is problematic, because the name is a leftover when the generator was indeed insecure. However, now the generator is *deterministic*, because the seed is either passed in or printed (c.f. RANDOM_CTX_SEED). Stating that deterministic randomness is insecure in the tests seems redundant at best. Fix it by just using `m_rng` for the name.

  2) The global random context has many one-line aliases, such as `InsecureRand32`. This is problematic, because the same line of code may use the context directly and through a wrapper at the same time. For example in net_tests (see below). This inconsistency is harmless, but confusing. Fix it by just removing the one-line aliases.

  ```
  src/test/net_tests.cpp:        auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000));
  ````

  3) The wrapper for randmoney has the same problem that the same unit test uses the context directly and through a wrapper at the same time. Also, it has a single type of Rng hardcoded. Fix it by accepting any type.

ACKs for top commit:
  hodlinator:
    ACK 948238a683
  ryanofsky:
    Code review ACK 948238a683. Only changes since last review were changing a comments a little bit.
  marcofleon:
    Code review ACK 948238a683. Only changes since my last review are the improvements in `prevector_tests`.

Tree-SHA512: 69c6b46a42cb743138ee8c87ff26a588dbe083e3efb3dca49b8a133ba5d3b09e8bf01c590ec7e121a7d77cb1fd7dcacd927a9ca139ac65e1f7c6d1ec46f93b57
This commit is contained in:
merge-script 2024-08-28 16:56:32 +01:00
commit d184fc3ba4
No known key found for this signature in database
GPG key ID: 2EEB9F5CC09526C1
48 changed files with 514 additions and 459 deletions

View file

@ -75,12 +75,13 @@ static void SignTransactionSchnorr(benchmark::Bench& bench) { SignTransactionSin
static void SignSchnorrTapTweakBenchmark(benchmark::Bench& bench, bool use_null_merkle_root) static void SignSchnorrTapTweakBenchmark(benchmark::Bench& bench, bool use_null_merkle_root)
{ {
FastRandomContext rng;
ECC_Context ecc_context{}; ECC_Context ecc_context{};
auto key = GenerateRandomKey(); auto key = GenerateRandomKey();
auto msg = InsecureRand256(); auto msg = rng.rand256();
auto merkle_root = use_null_merkle_root ? uint256() : InsecureRand256(); auto merkle_root = use_null_merkle_root ? uint256() : rng.rand256();
auto aux = InsecureRand256(); auto aux = rng.rand256();
std::vector<unsigned char> sig(64); std::vector<unsigned char> sig(64);
bench.minEpochIterations(100).run([&] { bench.minEpochIterations(100).run([&] {

View file

@ -84,14 +84,14 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
BOOST_AUTO_TEST_CASE(base58_random_encode_decode) BOOST_AUTO_TEST_CASE(base58_random_encode_decode)
{ {
for (int n = 0; n < 1000; ++n) { for (int n = 0; n < 1000; ++n) {
unsigned int len = 1 + InsecureRandBits(8); unsigned int len = 1 + m_rng.randbits(8);
unsigned int zeroes = InsecureRandBool() ? InsecureRandRange(len + 1) : 0; unsigned int zeroes = m_rng.randbool() ? m_rng.randrange(len + 1) : 0;
auto data = Cat(std::vector<unsigned char>(zeroes, '\000'), g_insecure_rand_ctx.randbytes(len - zeroes)); auto data = Cat(std::vector<unsigned char>(zeroes, '\000'), m_rng.randbytes(len - zeroes));
auto encoded = EncodeBase58Check(data); auto encoded = EncodeBase58Check(data);
std::vector<unsigned char> decoded; 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); 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(ok);
BOOST_CHECK(data == decoded); BOOST_CHECK(data == decoded);
} }

View file

@ -21,6 +21,7 @@
namespace { namespace {
struct BIP324Test : BasicTestingSetup {
void TestBIP324PacketVector( void TestBIP324PacketVector(
uint32_t in_idx, uint32_t in_idx,
const std::string& in_priv_ours_hex, const std::string& in_priv_ours_hex,
@ -116,7 +117,7 @@ void TestBIP324PacketVector(
// Seek to the numbered packet. // Seek to the numbered packet.
if (in_idx == 0 && error == 12) continue; 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) { for (uint32_t i = 0; i < dec_idx; ++i) {
unsigned use_idx = i < in_idx ? i : 0; unsigned use_idx = i < in_idx ? i : 0;
bool dec_ignore{false}; bool dec_ignore{false};
@ -128,7 +129,7 @@ void TestBIP324PacketVector(
// Decrypt length // Decrypt length
auto to_decrypt = ciphertext; auto to_decrypt = ciphertext;
if (error >= 2 && error <= 9) { 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. // Decrypt length and resize ciphertext to accommodate.
@ -139,7 +140,7 @@ void TestBIP324PacketVector(
auto dec_aad = in_aad; auto dec_aad = in_aad;
if (error == 10) { if (error == 10) {
if (in_aad.size() == 0) continue; 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({}); if (error == 11) dec_aad.push_back({});
@ -156,10 +157,11 @@ void TestBIP324PacketVector(
} }
} }
} }
}; // struct BIP324Test
} // namespace } // namespace
BOOST_FIXTURE_TEST_SUITE(bip324_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(bip324_tests, BIP324Test)
BOOST_AUTO_TEST_CASE(packet_test_vectors) { BOOST_AUTO_TEST_CASE(packet_test_vectors) {
// BIP324 key derivation uses network magic in the HKDF process. We use mainnet params here // BIP324 key derivation uses network magic in the HKDF process. We use mainnet params here

View file

@ -356,7 +356,7 @@ BOOST_AUTO_TEST_CASE(ReceiveWithExtraTransactions) {
BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
BlockTransactionsRequest req1; BlockTransactionsRequest req1;
req1.blockhash = InsecureRand256(); req1.blockhash = m_rng.rand256();
req1.indexes.resize(4); req1.indexes.resize(4);
req1.indexes[0] = 0; req1.indexes[0] = 0;
req1.indexes[1] = 1; req1.indexes[1] = 1;
@ -380,7 +380,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) {
BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) { BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) {
// Check that the highest legal index is decoded correctly // Check that the highest legal index is decoded correctly
BlockTransactionsRequest req0; BlockTransactionsRequest req0;
req0.blockhash = InsecureRand256(); req0.blockhash = m_rng.rand256();
req0.indexes.resize(1); req0.indexes.resize(1);
req0.indexes[0] = 0xffff; req0.indexes[0] = 0xffff;
DataStream stream{}; DataStream stream{};
@ -398,7 +398,7 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) {
// a request cannot be created by serializing a real BlockTransactionsRequest // a request cannot be created by serializing a real BlockTransactionsRequest
// due to the overflow, so here we'll serialize from raw deltas. // due to the overflow, so here we'll serialize from raw deltas.
BlockTransactionsRequest req0; BlockTransactionsRequest req0;
req0.blockhash = InsecureRand256(); req0.blockhash = m_rng.rand256();
req0.indexes.resize(3); req0.indexes.resize(3);
req0.indexes[0] = 0x7000; req0.indexes[0] = 0x7000;
req0.indexes[1] = 0x10000 - 0x7000 - 2; req0.indexes[1] = 0x10000 - 0x7000 - 2;

View file

@ -22,7 +22,13 @@
#include <boost/test/unit_test.hpp> #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) 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))); 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()); return std::vector<unsigned char>(r.begin(), r.end());
} }

View file

@ -34,7 +34,9 @@ struct NoLockLoggingTestingSetup : public TestingSetup {
#endif #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 unsigned int QUEUE_BATCH_SIZE = 128;
static const int SCRIPT_CHECK_THREADS = 3; 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 /** This test case checks that the CCheckQueue works properly
* with each specified size_t Checks pushed. * 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); 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...) // 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()); CCheckQueueControl<FakeCheckCheckCompletion> control(small_queue.get());
while (total) { while (total) {
vChecks.clear(); 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(); total -= vChecks.size();
control.Add(std::move(vChecks)); 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 /** Test that 0 checks is correct
*/ */
BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero) 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; std::vector<size_t> range;
range.reserve(100000/1000); 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); range.push_back(i);
Correct_Queue_range(range); Correct_Queue_range(range);
} }
@ -221,7 +225,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)
CCheckQueueControl<FailingCheck> control(fail_queue.get()); CCheckQueueControl<FailingCheck> control(fail_queue.get());
size_t remaining = i; size_t remaining = i;
while (remaining) { while (remaining) {
size_t r = InsecureRandRange(10); size_t r = m_rng.randrange(10);
std::vector<FailingCheck> vChecks; std::vector<FailingCheck> vChecks;
vChecks.reserve(r); vChecks.reserve(r);
@ -268,7 +272,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_UniqueCheck)
{ {
CCheckQueueControl<UniqueCheck> control(queue.get()); CCheckQueueControl<UniqueCheck> control(queue.get());
while (total) { while (total) {
size_t r = InsecureRandRange(10); size_t r = m_rng.randrange(10);
std::vector<UniqueCheck> vChecks; std::vector<UniqueCheck> vChecks;
for (size_t k = 0; k < r && total; k++) for (size_t k = 0; k < r && total; k++)
vChecks.emplace_back(--total); vChecks.emplace_back(--total);
@ -300,7 +304,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueue_Memory)
{ {
CCheckQueueControl<MemoryCheck> control(queue.get()); CCheckQueueControl<MemoryCheck> control(queue.get());
while (total) { while (total) {
size_t r = InsecureRandRange(10); size_t r = m_rng.randrange(10);
std::vector<MemoryCheck> vChecks; std::vector<MemoryCheck> vChecks;
for (size_t k = 0; k < r && total; k++) { for (size_t k = 0; k < r && total; k++) {
total--; total--;

View file

@ -35,10 +35,13 @@ bool operator==(const Coin &a, const Coin &b) {
class CCoinsViewTest : public CCoinsView class CCoinsViewTest : public CCoinsView
{ {
FastRandomContext& m_rng;
uint256 hashBestBlock_; uint256 hashBestBlock_;
std::map<COutPoint, Coin> map_; std::map<COutPoint, Coin> map_;
public: public:
CCoinsViewTest(FastRandomContext& rng) : m_rng{rng} {}
[[nodiscard]] bool GetCoin(const COutPoint& outpoint, Coin& coin) const override [[nodiscard]] bool GetCoin(const COutPoint& outpoint, Coin& coin) const override
{ {
std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint);
@ -46,7 +49,7 @@ public:
return false; return false;
} }
coin = it->second; coin = it->second;
if (coin.IsSpent() && InsecureRandBool() == 0) { if (coin.IsSpent() && m_rng.randbool() == 0) {
// Randomly return false in case of an empty entry. // Randomly return false in case of an empty entry.
return false; return false;
} }
@ -61,7 +64,7 @@ public:
if (it->second.IsDirty()) { if (it->second.IsDirty()) {
// Same optimization used in CCoinsViewDB is to only write dirty entries. // Same optimization used in CCoinsViewDB is to only write dirty entries.
map_[it->first] = it->second.coin; 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. // Randomly delete empty entries on write.
map_.erase(it->first); map_.erase(it->first);
} }
@ -105,6 +108,7 @@ BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; static const unsigned int NUM_SIMULATION_ITERATIONS = 40000;
struct CacheTest : BasicTestingSetup {
// This is a large randomized insert/remove simulation test on a variable-size // This is a large randomized insert/remove simulation test on a variable-size
// stack of caches on top of CCoinsViewTest. // stack of caches on top of CCoinsViewTest.
// //
@ -144,26 +148,26 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
std::vector<Txid> txids; std::vector<Txid> txids;
txids.resize(NUM_SIMULATION_ITERATIONS / 8); txids.resize(NUM_SIMULATION_ITERATIONS / 8);
for (unsigned int i = 0; i < txids.size(); i++) { 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++) { for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
// Do a random modification. // 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)]; Coin& coin = result[COutPoint(txid, 0)];
// Determine whether to test HaveCoin before or after Access* (or both). As these functions // 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 // can influence each other's behaviour by pulling things into the cache, all combinations
// are tested. // are tested.
bool test_havecoin_before = InsecureRandBits(2) == 0; bool test_havecoin_before = m_rng.randbits(2) == 0;
bool test_havecoin_after = InsecureRandBits(2) == 0; bool test_havecoin_after = m_rng.randbits(2) == 0;
bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false; bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false;
// Infrequently, test usage of AccessByTxid instead of AccessCoin - the // Infrequently, test usage of AccessByTxid instead of AccessCoin - the
// former just delegates to the latter and returns the first unspent in a txn. // 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)); AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
BOOST_CHECK(coin == entry); BOOST_CHECK(coin == entry);
@ -176,23 +180,23 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
BOOST_CHECK(ret == !entry.IsSpent()); BOOST_CHECK(ret == !entry.IsSpent());
} }
if (InsecureRandRange(5) == 0 || coin.IsSpent()) { if (m_rng.randrange(5) == 0 || coin.IsSpent()) {
Coin newcoin; Coin newcoin;
newcoin.out.nValue = InsecureRandMoneyAmount(); newcoin.out.nValue = RandMoney(m_rng);
newcoin.nHeight = 1; newcoin.nHeight = 1;
// Infrequently test adding unspendable coins. // Infrequently test adding unspendable coins.
if (InsecureRandRange(16) == 0 && coin.IsSpent()) { if (m_rng.randrange(16) == 0 && coin.IsSpent()) {
newcoin.out.scriptPubKey.assign(1 + InsecureRandBits(6), OP_RETURN); newcoin.out.scriptPubKey.assign(1 + m_rng.randbits(6), OP_RETURN);
BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable()); BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable());
added_an_unspendable_entry = true; added_an_unspendable_entry = true;
} else { } else {
// Random sizes so we can test memory usage accounting // 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.IsSpent() ? added_an_entry : updated_an_entry) = true;
coin = newcoin; 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); stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), is_overwrite);
} else { } else {
// Spend the coin. // 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 // Once every 10 iterations, remove a random entry from the cache
if (InsecureRandRange(10) == 0) { if (m_rng.randrange(10) == 0) {
COutPoint out(txids[InsecureRand32() % txids.size()], 0); COutPoint out(txids[m_rng.rand32() % txids.size()], 0);
int cacheid = InsecureRand32() % stack.size(); int cacheid = m_rng.rand32() % stack.size();
stack[cacheid]->Uncache(out); stack[cacheid]->Uncache(out);
uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out);
} }
// Once every 1000 iterations and at the end, verify the full cache. // 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) { for (const auto& entry : result) {
bool have = stack.back()->HaveCoin(entry.first); bool have = stack.back()->HaveCoin(entry.first);
const Coin& coin = stack.back()->AccessCoin(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 // Every 100 iterations, flush an intermediate cache
if (stack.size() > 1 && InsecureRandBool() == 0) { if (stack.size() > 1 && m_rng.randbool() == 0) {
unsigned int flushIndex = InsecureRandRange(stack.size() - 1); unsigned int flushIndex = m_rng.randrange(stack.size() - 1);
if (fake_best_block) stack[flushIndex]->SetBestBlock(InsecureRand256()); if (fake_best_block) stack[flushIndex]->SetBestBlock(m_rng.rand256());
bool should_erase = InsecureRandRange(4) < 3; bool should_erase = m_rng.randrange(4) < 3;
BOOST_CHECK(should_erase ? stack[flushIndex]->Flush() : stack[flushIndex]->Sync()); BOOST_CHECK(should_erase ? stack[flushIndex]->Flush() : stack[flushIndex]->Sync());
flushed_without_erase |= !should_erase; flushed_without_erase |= !should_erase;
} }
} }
if (InsecureRandRange(100) == 0) { if (m_rng.randrange(100) == 0) {
// Every 100 iterations, change the cache stack. // 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 //Remove the top cache
if (fake_best_block) stack.back()->SetBestBlock(InsecureRand256()); if (fake_best_block) stack.back()->SetBestBlock(m_rng.rand256());
bool should_erase = InsecureRandRange(4) < 3; bool should_erase = m_rng.randrange(4) < 3;
BOOST_CHECK(should_erase ? stack.back()->Flush() : stack.back()->Sync()); BOOST_CHECK(should_erase ? stack.back()->Flush() : stack.back()->Sync());
flushed_without_erase |= !should_erase; flushed_without_erase |= !should_erase;
stack.pop_back(); 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 //Add a new cache
CCoinsView* tip = base; CCoinsView* tip = base;
if (stack.size() > 0) { if (stack.size() > 0) {
@ -277,24 +281,26 @@ void SimulationTest(CCoinsView* base, bool fake_best_block)
BOOST_CHECK(uncached_an_entry); BOOST_CHECK(uncached_an_entry);
BOOST_CHECK(flushed_without_erase); BOOST_CHECK(flushed_without_erase);
} }
}; // struct CacheTest
// Run the above simulation for multiple base types. // 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); SimulationTest(&base, false);
CCoinsViewDB db_base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}}; CCoinsViewDB db_base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}};
SimulationTest(&db_base, true); SimulationTest(&db_base, true);
} }
struct UpdateTest : BasicTestingSetup {
// Store of all necessary tx and undo data for next test // Store of all necessary tx and undo data for next test
typedef std::map<COutPoint, std::tuple<CTransaction,CTxUndo,Coin>> UtxoData; typedef std::map<COutPoint, std::tuple<CTransaction,CTxUndo,Coin>> UtxoData;
UtxoData utxoData; UtxoData utxoData;
UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
assert(utxoSet.size()); 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()) { if (utxoSetIt == utxoSet.end()) {
utxoSetIt = utxoSet.begin(); utxoSetIt = utxoSet.begin();
} }
@ -302,6 +308,7 @@ UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) {
assert(utxoDataIt != utxoData.end()); assert(utxoDataIt != utxoData.end());
return utxoDataIt; return utxoDataIt;
} }
}; // struct UpdateTest
// This test is similar to the previous test // 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 // random txs are created and UpdateCoins is used to update the cache stack
// In particular it is tested that spending a duplicate coinbase tx // In particular it is tested that spending a duplicate coinbase tx
// has the expected effect (the other duplicate is overwritten at all cache levels) // 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); SeedRandomForTest(SeedRand::ZEROS);
@ -318,7 +325,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
std::map<COutPoint, Coin> result; std::map<COutPoint, Coin> result;
// The cache stack. // 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. 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. 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; std::set<COutPoint> utxoset;
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { 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 // 19/20 txs add a new transaction
if (randiter % 20 < 19) { if (randiter % 20 < 19) {
@ -337,14 +344,14 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
tx.vin.resize(1); tx.vin.resize(1);
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate 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 tx.vout[0].scriptPubKey.assign(m_rng.rand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting
const int height{int(InsecureRand32() >> 1)}; const int height{int(m_rng.rand32() >> 1)};
Coin old_coin; Coin old_coin;
// 2/20 times create a new coinbase // 2/20 times create a new coinbase
if (randiter % 20 < 2 || coinbase_coins.size() < 10) { if (randiter % 20 < 2 || coinbase_coins.size() < 10) {
// 1/10 of those times create a duplicate coinbase // 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); auto utxod = FindRandomFrom(coinbase_coins);
// Reuse the exact same coinbase // Reuse the exact same coinbase
tx = CMutableTransaction{std::get<0>(utxod->second)}; 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. // 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) { for (const auto& entry : result) {
bool have = stack.back()->HaveCoin(entry.first); bool have = stack.back()->HaveCoin(entry.first);
const Coin& coin = stack.back()->AccessCoin(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 // One every 10 iterations, remove a random entry from the cache
if (utxoset.size() > 1 && InsecureRandRange(30) == 0) { if (utxoset.size() > 1 && m_rng.randrange(30) == 0) {
stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first);
} }
if (disconnected_coins.size() > 1 && InsecureRandRange(30) == 0) { if (disconnected_coins.size() > 1 && m_rng.randrange(30) == 0) {
stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first); stack[m_rng.rand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first);
} }
if (duplicate_coins.size() > 1 && InsecureRandRange(30) == 0) { if (duplicate_coins.size() > 1 && m_rng.randrange(30) == 0) {
stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first); 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 // Every 100 iterations, flush an intermediate cache
if (stack.size() > 1 && InsecureRandBool() == 0) { if (stack.size() > 1 && m_rng.randbool() == 0) {
unsigned int flushIndex = InsecureRandRange(stack.size() - 1); unsigned int flushIndex = m_rng.randrange(stack.size() - 1);
BOOST_CHECK(stack[flushIndex]->Flush()); BOOST_CHECK(stack[flushIndex]->Flush());
} }
} }
if (InsecureRandRange(100) == 0) { if (m_rng.randrange(100) == 0) {
// Every 100 iterations, change the cache stack. // 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()); BOOST_CHECK(stack.back()->Flush());
stack.pop_back(); stack.pop_back();
} }
if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) { if (stack.size() == 0 || (stack.size() < 4 && m_rng.randbool())) {
CCoinsView* tip = &base; CCoinsView* tip = &base;
if (stack.size() > 0) { if (stack.size() > 0) {
tip = stack.back().get(); tip = stack.back().get();
@ -888,11 +895,12 @@ BOOST_AUTO_TEST_CASE(ccoins_write)
} }
struct FlushTest : BasicTestingSetup {
Coin MakeCoin() Coin MakeCoin()
{ {
Coin coin; Coin coin;
coin.out.nValue = InsecureRand32(); coin.out.nValue = m_rng.rand32();
coin.nHeight = InsecureRandRange(4096); coin.nHeight = m_rng.randrange(4096);
coin.fCoinBase = 0; coin.fCoinBase = 0;
return coin; return coin;
} }
@ -919,19 +927,19 @@ void TestFlushBehavior(
size_t cache_usage; size_t cache_usage;
size_t cache_size; 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. // Flush in reverse order to ensure that flushes happen from children up.
for (auto i = all_caches.rbegin(); i != all_caches.rend(); ++i) { for (auto i = all_caches.rbegin(); i != all_caches.rend(); ++i) {
auto& cache = *i; auto& cache = *i;
cache->SanityCheck(); cache->SanityCheck();
// hashBlock must be filled before flushing to disk; value is // hashBlock must be filled before flushing to disk; value is
// unimportant here. This is normally done during connect/disconnect block. // unimportant here. This is normally done during connect/disconnect block.
cache->SetBestBlock(InsecureRand256()); cache->SetBestBlock(m_rng.rand256());
erase ? cache->Flush() : cache->Sync(); erase ? cache->Flush() : cache->Sync();
} }
}; };
Txid txid = Txid::FromUint256(InsecureRand256()); Txid txid = Txid::FromUint256(m_rng.rand256());
COutPoint outp = COutPoint(txid, 0); COutPoint outp = COutPoint(txid, 0);
Coin coin = MakeCoin(); Coin coin = MakeCoin();
// Ensure the coins views haven't seen this coin before. // 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 // --- 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. // 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); outp = COutPoint(txid, 0);
coin = MakeCoin(); coin = MakeCoin();
BOOST_CHECK(!base.HaveCoin(outp)); BOOST_CHECK(!base.HaveCoin(outp));
@ -1045,7 +1053,7 @@ void TestFlushBehavior(
// --- Bonus check 2: ensure that a FRESH, spent coin is deleted by Sync() // --- 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); outp = COutPoint(txid, 0);
coin = MakeCoin(); coin = MakeCoin();
CAmount coin_val = coin.out.nValue; CAmount coin_val = coin.out.nValue;
@ -1074,8 +1082,9 @@ void TestFlushBehavior(
BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp)); BOOST_CHECK(!all_caches[0]->HaveCoinInCache(outp));
BOOST_CHECK(!base.HaveCoin(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. // Create two in-memory caches atop a leveldb view.
CCoinsViewDB base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}}; CCoinsViewDB base{{.path = "test", .cache_bytes = 1 << 23, .memory_only = true}, {}};

View file

@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(compress_p2pk_scripts_not_on_curve)
{ {
XOnlyPubKey x_not_on_curve; XOnlyPubKey x_not_on_curve;
do { 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()); } while (x_not_on_curve.IsFullyValid());
// Check that P2PK script with uncompressed pubkey [=> OP_PUSH65 <0x04 .....> OP_CHECKSIG] // Check that P2PK script with uncompressed pubkey [=> OP_PUSH65 <0x04 .....> OP_CHECKSIG]

View file

@ -26,10 +26,11 @@
#include <boost/test/unit_test.hpp> #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> 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; Out hash;
BOOST_CHECK(out.size() == h.OUTPUT_SIZE); BOOST_CHECK(out.size() == h.OUTPUT_SIZE);
hash.resize(out.size()); hash.resize(out.size());
@ -43,7 +44,7 @@ static void TestVector(const Hasher &h, const In &in, const Out &out) {
Hasher hasher(h); Hasher hasher(h);
size_t pos = 0; size_t pos = 0;
while (pos < in.size()) { 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); hasher.Write((const uint8_t*)in.data() + pos, len);
pos += len; pos += len;
if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) { 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));} 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));} 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));} 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 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); std::vector<unsigned char> key = ParseHex(hexkey);
TestVector(CHMAC_SHA256(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); 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); std::vector<unsigned char> key = ParseHex(hexkey);
TestVector(CHMAC_SHA512(key.data(), key.size()), ParseHex(hexin), ParseHex(hexout)); 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> key = ParseHex(hexkey);
std::vector<unsigned char> in = ParseHex(hexin); 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); 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> key = ParseHex(hexkey);
std::vector<unsigned char> iv = ParseHex(hexiv); 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); auto key = ParseHex<std::byte>(hexkey);
assert(key.size() == 32); 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. // Repeat 10x, but fragmented into 3 chunks, to exercise the ChaCha20 class's caching.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
size_t lens[3]; size_t lens[3];
lens[0] = InsecureRandRange(hexout.size() / 2U + 1U); lens[0] = m_rng.randrange(hexout.size() / 2U + 1U);
lens[1] = InsecureRandRange(hexout.size() / 2U + 1U - lens[0]); lens[1] = m_rng.randrange(hexout.size() / 2U + 1U - lens[0]);
lens[2] = hexout.size() / 2U - lens[0] - lens[1]; lens[2] = hexout.size() / 2U - lens[0] - lens[1];
rng.Seek(nonce, seek); 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); auto key = ParseHex<std::byte>(hexkey);
BOOST_CHECK_EQUAL(FSChaCha20::KEYLEN, key.size()); 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); 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 key = ParseHex<std::byte>(hexkey);
auto m = ParseHex<std::byte>(hexmessage); 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}; auto data = Span{m};
Poly1305 poly1305{key}; Poly1305 poly1305{key};
for (int chunk = 0; chunk < splits; ++chunk) { 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)); poly1305.Update(data.first(now));
data = data.subspan(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 plain = ParseHex<std::byte>(plain_hex);
auto aad = ParseHex<std::byte>(aad_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) { for (int i = 0; i < 10; ++i) {
// During i=0, use single-plain Encrypt/Decrypt; others use a split at prefix. // 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. // Encrypt.
std::vector<std::byte> cipher(plain.size() + AEADChaCha20Poly1305::EXPANSION); std::vector<std::byte> cipher(plain.size() + AEADChaCha20Poly1305::EXPANSION);
AEADChaCha20Poly1305 aead{key}; 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 plain = ParseHex<std::byte>(plain_hex);
auto aad = ParseHex<std::byte>(aad_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) { for (int it = 0; it < 10; ++it) {
// During it==0 we use the single-plain Encrypt/Decrypt; others use a split at prefix. // 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] = {{}}; std::byte dummy_tag[FSChaCha20Poly1305::EXPANSION] = {{}};
// Do msg_idx dummy encryptions to seek to the correct packet. // 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> initial_key_material = ParseHex(ikm_hex);
std::vector<unsigned char> salt = ParseHex(salt_hex); std::vector<unsigned char> salt = ParseHex(salt_hex);
std::vector<unsigned char> info = ParseHex(info_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); 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() static std::string LongTestString()
{ {
std::string ret; std::string ret;
@ -366,6 +371,8 @@ static std::string LongTestString()
const std::string test1 = LongTestString(); const std::string test1 = LongTestString();
BOOST_FIXTURE_TEST_SUITE(crypto_tests, CryptoTest)
BOOST_AUTO_TEST_CASE(ripemd160_testvectors) { BOOST_AUTO_TEST_CASE(ripemd160_testvectors) {
TestRIPEMD160("", "9c1185a5c5e9fc54612808977ee8f548b2258d31"); TestRIPEMD160("", "9c1185a5c5e9fc54612808977ee8f548b2258d31");
TestRIPEMD160("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"); TestRIPEMD160("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc");
@ -1067,7 +1074,7 @@ BOOST_AUTO_TEST_CASE(sha256d64)
unsigned char in[64 * 32]; unsigned char in[64 * 32];
unsigned char out1[32 * 32], out2[32 * 32]; unsigned char out1[32 * 32], out2[32 * 32];
for (int j = 0; j < 64 * i; ++j) { 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) { for (int j = 0; j < i; ++j) {
CHash256().Write({in + 64 * j, 64}).Finalize({out1 + 32 * j, 32}); 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 in_bytes = ParseHex(input);
const auto out_bytes = ParseHex(output); 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 // Reset and split randomly in 3
sha.Reset(); sha.Reset();
int s1 = InsecureRandRange(in_bytes.size() + 1); int s1 = m_rng.randrange(in_bytes.size() + 1);
int s2 = InsecureRandRange(in_bytes.size() + 1 - s1); int s2 = m_rng.randrange(in_bytes.size() + 1 - s1);
int s3 = in_bytes.size() - s1 - s2; 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}.first(s1)).Write(Span{in_bytes}.subspan(s1, s2));
sha.Write(Span{in_bytes}.last(s3)).Finalize(out); sha.Write(Span{in_bytes}.last(s3)).Finalize(out);
@ -1196,7 +1203,7 @@ BOOST_AUTO_TEST_CASE(muhash_tests)
uint256 res; uint256 res;
int table[4]; int table[4];
for (int i = 0; i < 4; ++i) { 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) { for (int order = 0; order < 4; ++order) {
MuHash3072 acc; MuHash3072 acc;
@ -1216,8 +1223,8 @@ BOOST_AUTO_TEST_CASE(muhash_tests)
} }
} }
MuHash3072 x = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X MuHash3072 x = FromInt(m_rng.randbits<4>()); // x=X
MuHash3072 y = FromInt(g_insecure_rand_ctx.randbits<4>()); // x=X, y=Y MuHash3072 y = FromInt(m_rng.randbits<4>()); // x=X, y=Y
MuHash3072 z; // x=X, y=Y, z=1 MuHash3072 z; // x=X, y=Y, z=1
z *= x; // x=X, y=Y, z=X z *= x; // x=X, y=Y, z=X
z *= y; // x=X, y=Y, z=X*Y z *= y; // x=X, y=Y, z=X*Y

View file

@ -29,11 +29,11 @@
* using BOOST_CHECK_CLOSE to fail. * 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. /* 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) BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
{ {
@ -42,18 +42,19 @@ BOOST_AUTO_TEST_CASE(test_cuckoocache_no_fakes)
size_t megabytes = 4; size_t megabytes = 4;
cc.setup_bytes(megabytes << 20); cc.setup_bytes(megabytes << 20);
for (int x = 0; x < 100000; ++x) { for (int x = 0; x < 100000; ++x) {
cc.insert(InsecureRand256()); cc.insert(m_rng.rand256());
} }
for (int x = 0; x < 100000; ++x) { 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 /** This helper returns the hit rate when megabytes*load worth of entries are
* inserted into a megabytes sized cache * inserted into a megabytes sized cache
*/ */
template <typename Cache> template <typename Cache>
static double test_cache(size_t megabytes, double load) double test_cache(size_t megabytes, double load)
{ {
SeedRandomForTest(SeedRand::ZEROS); SeedRandomForTest(SeedRand::ZEROS);
std::vector<uint256> hashes; 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) { for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin(); uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j) 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 /** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is * 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); return hits * std::max(load, 1.0);
} }
}; // struct HitRateTest
/** Check the hit rate on loads ranging from 0.1 to 1.6 */ /** 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 /** Arbitrarily selected Hit Rate threshold that happens to work for this test
* as a lower bound on performance. * 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 /** This helper checks that erased elements are preferentially inserted onto and
* that the hit rate of "fresher" keys is reasonable*/ * that the hit rate of "fresher" keys is reasonable*/
template <typename Cache> template <typename Cache>
static void test_cache_erase(size_t megabytes) void test_cache_erase(size_t megabytes)
{ {
double load = 1; double load = 1;
SeedRandomForTest(SeedRand::ZEROS); SeedRandomForTest(SeedRand::ZEROS);
@ -136,7 +139,7 @@ static void test_cache_erase(size_t megabytes)
for (uint32_t i = 0; i < n_insert; ++i) { for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin(); uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j) 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 /** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is * cuckoocache may overwrite the inserted element, so the test is
@ -178,15 +181,17 @@ static void test_cache_erase(size_t megabytes)
// erased elements. // erased elements.
BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); 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; size_t megabytes = 4;
test_cache_erase<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes); test_cache_erase<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);
} }
struct EraseParallelTest : BasicTestingSetup {
template <typename Cache> template <typename Cache>
static void test_cache_erase_parallel(size_t megabytes) void test_cache_erase_parallel(size_t megabytes)
{ {
double load = 1; double load = 1;
SeedRandomForTest(SeedRand::ZEROS); 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) { for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)hashes[i].begin(); uint32_t* ptr = (uint32_t*)hashes[i].begin();
for (uint8_t j = 0; j < 8; ++j) 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 /** We make a copy of the hashes because future optimizations of the
* cuckoocache may overwrite the inserted element, so the test is * 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. // erased elements.
BOOST_CHECK(hit_rate_stale > 2 * hit_rate_erased_but_contained); 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; size_t megabytes = 4;
test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes); test_cache_erase_parallel<CuckooCache::cache<uint256, SignatureCacheHasher>>(megabytes);
} }
struct GenerationsTest : BasicTestingSetup {
template <typename Cache> 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 // 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 // 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. // immediately and never uses the other half.
struct block_activity { struct block_activity {
std::vector<uint256> reads; 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; std::vector<uint256> inserts;
inserts.resize(n_insert); inserts.resize(n_insert);
@ -310,7 +317,7 @@ static void test_cache_generations()
for (uint32_t i = 0; i < n_insert; ++i) { for (uint32_t i = 0; i < n_insert; ++i) {
uint32_t* ptr = (uint32_t*)inserts[i].begin(); uint32_t* ptr = (uint32_t*)inserts[i].begin();
for (uint8_t j = 0; j < 8; ++j) for (uint8_t j = 0; j < 8; ++j)
*(ptr++) = InsecureRand32(); *(ptr++) = rng.rand32();
} }
for (uint32_t i = 0; i < n_insert / 4; ++i) for (uint32_t i = 0; i < n_insert / 4; ++i)
reads.push_back(inserts[i]); reads.push_back(inserts[i]);
@ -344,7 +351,7 @@ static void test_cache_generations()
for (uint32_t i = 0; i < total; ++i) { for (uint32_t i = 0; i < total; ++i) {
if (last_few.size() == WINDOW_SIZE) if (last_few.size() == WINDOW_SIZE)
last_few.pop_front(); last_few.pop_front();
last_few.emplace_back(BLOCK_SIZE, set); last_few.emplace_back(BLOCK_SIZE, m_rng, set);
uint32_t count = 0; uint32_t count = 0;
for (auto& act : last_few) for (auto& act : last_few)
for (uint32_t k = 0; k < POP_AMOUNT; ++k) { 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 // 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_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>>(); test_cache_generations<CuckooCache::cache<uint256, SignatureCacheHasher>>();
} }

View file

@ -33,7 +33,7 @@ BOOST_AUTO_TEST_CASE(dbwrapper)
fs::path ph = m_args.GetDataDirBase() / (obfuscate ? "dbwrapper_obfuscate_true" : "dbwrapper_obfuscate_false"); 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}); CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate});
uint8_t key{'k'}; uint8_t key{'k'};
uint256 in = InsecureRand256(); uint256 in = m_rng.rand256();
uint256 res; uint256 res;
// Ensure that we're doing real obfuscation when obfuscate=true // 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))); BOOST_CHECK(obfuscate != is_null_key(dbwrapper_private::GetObfuscateKey(dbw)));
//Simulate block raw data - "b + block hash" //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.Write(key_block, in_block));
BOOST_CHECK(dbw.Read(key_block, res)); BOOST_CHECK(dbw.Read(key_block, res));
BOOST_CHECK_EQUAL(res.ToString(), in_block.ToString()); BOOST_CHECK_EQUAL(res.ToString(), in_block.ToString());
//Simulate file raw data - "f + file_number" //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.Write(key_file, in_file_info));
BOOST_CHECK(dbw.Read(key_file, res)); BOOST_CHECK(dbw.Read(key_file, res));
BOOST_CHECK_EQUAL(res.ToString(), in_file_info.ToString()); BOOST_CHECK_EQUAL(res.ToString(), in_file_info.ToString());
//Simulate transaction raw data - "t + transaction hash" //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.Write(key_transaction, in_transaction));
BOOST_CHECK(dbw.Read(key_transaction, res)); BOOST_CHECK(dbw.Read(key_transaction, res));
BOOST_CHECK_EQUAL(res.ToString(), in_transaction.ToString()); BOOST_CHECK_EQUAL(res.ToString(), in_transaction.ToString());
//Simulate UTXO raw data - "c + transaction hash" //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.Write(key_utxo, in_utxo));
BOOST_CHECK(dbw.Read(key_utxo, res)); BOOST_CHECK(dbw.Read(key_utxo, res));
BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString()); BOOST_CHECK_EQUAL(res.ToString(), in_utxo.ToString());
//Simulate last block file number - "l" //Simulate last block file number - "l"
uint8_t key_last_blockfile_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.Write(key_last_blockfile_number, lastblockfilenumber));
BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32)); BOOST_CHECK(dbw.Read(key_last_blockfile_number, res_uint_32));
BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32); BOOST_CHECK_EQUAL(lastblockfilenumber, res_uint_32);
//Simulate Is Reindexing - "R" //Simulate Is Reindexing - "R"
uint8_t key_IsReindexing{'R'}; uint8_t key_IsReindexing{'R'};
bool isInReindexing = InsecureRandBool(); bool isInReindexing = m_rng.randbool();
BOOST_CHECK(dbw.Write(key_IsReindexing, isInReindexing)); BOOST_CHECK(dbw.Write(key_IsReindexing, isInReindexing));
BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool)); BOOST_CHECK(dbw.Read(key_IsReindexing, res_bool));
BOOST_CHECK_EQUAL(isInReindexing, res_bool); BOOST_CHECK_EQUAL(isInReindexing, res_bool);
//Simulate last block hash up to which UXTO covers - 'B' //Simulate last block hash up to which UXTO covers - 'B'
uint8_t key_lastblockhash_uxto{'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.Write(key_lastblockhash_uxto, lastblock_hash));
BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res)); BOOST_CHECK(dbw.Read(key_lastblockhash_uxto, res));
BOOST_CHECK_EQUAL(lastblock_hash, res); BOOST_CHECK_EQUAL(lastblock_hash, res);
//Simulate file raw data - "F + filename_number + filename" //Simulate file raw data - "F + filename_number + filename"
std::string file_option_tag = "F"; 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 filename = "randomfilename";
std::string key_file_option = strprintf("%s%01x%s", file_option_tag,filename_length,filename); 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.Write(key_file_option, in_file_bool));
BOOST_CHECK(dbw.Read(key_file_option, res_bool)); BOOST_CHECK(dbw.Read(key_file_option, res_bool));
BOOST_CHECK_EQUAL(res_bool, in_file_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}); CDBWrapper dbw({.path = ph, .cache_bytes = 1 << 20, .memory_only = true, .wipe_data = false, .obfuscate = obfuscate});
uint8_t key{'i'}; uint8_t key{'i'};
uint256 in = InsecureRand256(); uint256 in = m_rng.rand256();
uint8_t key2{'j'}; uint8_t key2{'j'};
uint256 in2 = InsecureRand256(); uint256 in2 = m_rng.rand256();
uint8_t key3{'k'}; uint8_t key3{'k'};
uint256 in3 = InsecureRand256(); uint256 in3 = m_rng.rand256();
uint256 res; uint256 res;
CDBBatch batch(dbw); CDBBatch batch(dbw);
@ -171,10 +171,10 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator)
// The two keys are intentionally chosen for ordering // The two keys are intentionally chosen for ordering
uint8_t key{'j'}; uint8_t key{'j'};
uint256 in = InsecureRand256(); uint256 in = m_rng.rand256();
BOOST_CHECK(dbw.Write(key, in)); BOOST_CHECK(dbw.Write(key, in));
uint8_t key2{'k'}; uint8_t key2{'k'};
uint256 in2 = InsecureRand256(); uint256 in2 = m_rng.rand256();
BOOST_CHECK(dbw.Write(key2, in2)); BOOST_CHECK(dbw.Write(key2, in2));
std::unique_ptr<CDBIterator> it(const_cast<CDBWrapper&>(dbw).NewIterator()); 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. // 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}); 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'}; uint8_t key{'k'};
uint256 in = InsecureRand256(); uint256 in = m_rng.rand256();
uint256 res; uint256 res;
BOOST_CHECK(dbw->Write(key, in)); 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(!odbw.IsEmpty()); // There should be existing data
BOOST_CHECK(is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); // The key should be an empty string 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; uint256 res3;
// Check that we can write successfully // 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. // 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}); 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'}; uint8_t key{'k'};
uint256 in = InsecureRand256(); uint256 in = m_rng.rand256();
uint256 res; uint256 res;
BOOST_CHECK(dbw->Write(key, in)); 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(!odbw.Read(key, res2));
BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw))); BOOST_CHECK(!is_null_key(dbwrapper_private::GetObfuscateKey(odbw)));
uint256 in2 = InsecureRand256(); uint256 in2 = m_rng.rand256();
uint256 res3; uint256 res3;
// Check that we can write successfully // Check that we can write successfully

View file

@ -106,17 +106,18 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
peerman.FinalizeNode(dummyNode1); 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; CAddress addr;
if (onion_peer) { 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))); BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
} }
while (!addr.IsRoutable()) { 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++, vNodes.emplace_back(new CNode{id++,
@ -136,8 +137,9 @@ static void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerM
connman.AddTestNode(node); 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}; NodeId id{0};
auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); 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(); connman->ClearTestNodes();
} }
BOOST_AUTO_TEST_CASE(block_relay_only_eviction) BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest)
{ {
NodeId id{0}; NodeId id{0};
auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params()); auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());

View file

@ -106,7 +106,7 @@ void initialize()
// randomness during the fuzz test, except: // randomness during the fuzz test, except:
// - GetStrongRandBytes(), which is used for the creation of private key material. // - GetStrongRandBytes(), which is used for the creation of private key material.
// - Creating a BasicTestingSetup or derived class will switch to a random seed. // - 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. // Terminate immediately if a fuzzing harness ever tries to create a socket.
// Individual tests can override this by pointing CreateSock to a mocked alternative. // Individual tests can override this by pointing CreateSock to a mocked alternative.

View file

@ -11,7 +11,7 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(hash_tests) BOOST_FIXTURE_TEST_SUITE(hash_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(murmurhash3) BOOST_AUTO_TEST_CASE(murmurhash3)
{ {
@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(siphash)
for (int i = 0; i < 16; ++i) { for (int i = 0; i < 16; ++i) {
uint64_t k1 = ctx.rand64(); uint64_t k1 = ctx.rand64();
uint64_t k2 = ctx.rand64(); uint64_t k2 = ctx.rand64();
uint256 x = InsecureRand256(); uint256 x = m_rng.rand256();
uint32_t n = ctx.rand32(); uint32_t n = ctx.rand32();
uint8_t nb[4]; uint8_t nb[4];
WriteLE32(nb, n); WriteLE32(nb, n);

View file

@ -312,11 +312,11 @@ BOOST_AUTO_TEST_CASE(bip340_test_vectors)
// In iteration i=0 we tweak with empty Merkle tree. // In iteration i=0 we tweak with empty Merkle tree.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
uint256 merkle_root; uint256 merkle_root;
if (i) merkle_root = InsecureRand256(); if (i) merkle_root = m_rng.rand256();
auto tweaked = pubkey.CreateTapTweak(i ? &merkle_root : nullptr); auto tweaked = pubkey.CreateTapTweak(i ? &merkle_root : nullptr);
BOOST_CHECK(tweaked); BOOST_CHECK(tweaked);
XOnlyPubKey tweaked_key = tweaked->first; XOnlyPubKey tweaked_key = tweaked->first;
aux256 = InsecureRand256(); aux256 = m_rng.rand256();
bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, aux256); bool ok = key.SignSchnorr(msg256, sig64, &merkle_root, aux256);
BOOST_CHECK(ok); BOOST_CHECK(ok);
BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64)); BOOST_CHECK(tweaked_key.VerifySchnorr(msg256, sig64));
@ -336,7 +336,7 @@ BOOST_AUTO_TEST_CASE(key_ellswift)
CKey key = DecodeSecret(secret); CKey key = DecodeSecret(secret);
BOOST_CHECK(key.IsValid()); BOOST_CHECK(key.IsValid());
uint256 ent32 = InsecureRand256(); uint256 ent32 = m_rng.rand256();
auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32})); auto ellswift = key.EllSwiftCreate(AsBytes(Span{ent32}));
CPubKey decoded_pubkey = ellswift.Decode(); CPubKey decoded_pubkey = ellswift.Decode();
@ -366,7 +366,7 @@ BOOST_AUTO_TEST_CASE(key_schnorr_tweak_smoke_test)
CKey key; CKey key;
key.MakeNewKey(true); key.MakeNewKey(true);
uint256 merkle_root = InsecureRand256(); uint256 merkle_root = m_rng.rand256();
// secp256k1 functions // secp256k1 functions
secp256k1_keypair keypair; secp256k1_keypair keypair;

View file

@ -184,7 +184,7 @@ BOOST_AUTO_TEST_CASE(merkle_test)
{ {
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
// Try 32 block sizes: all sizes from 0 to 16 inclusive, and then 15 random sizes. // 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. // Try up to 3 mutations.
for (int mutate = 0; mutate <= 3; mutate++) { for (int mutate = 0; mutate <= 3; mutate++) {
int duplicate1 = mutate >= 1 ? 1 << ctz(ntx) : 0; // The last how many transactions to duplicate first. 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. // If ntx <= 16, try all branches. Otherwise, try 16 random ones.
int mtx = loop; int mtx = loop;
if (ntx > 16) { if (ntx > 16) {
mtx = InsecureRandRange(ntx); mtx = m_rng.randrange(ntx);
} }
std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx); std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx);
std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx);

View file

@ -367,7 +367,7 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) { while (m_node.chainman->ActiveChain().Tip()->nHeight < 209999) {
CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
CBlockIndex* next = new CBlockIndex(); CBlockIndex* next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256()); next->phashBlock = new uint256(m_rng.rand256());
m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
next->pprev = prev; next->pprev = prev;
next->nHeight = prev->nHeight + 1; 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) { while (m_node.chainman->ActiveChain().Tip()->nHeight < 210000) {
CBlockIndex* prev = m_node.chainman->ActiveChain().Tip(); CBlockIndex* prev = m_node.chainman->ActiveChain().Tip();
CBlockIndex* next = new CBlockIndex(); CBlockIndex* next = new CBlockIndex();
next->phashBlock = new uint256(InsecureRand256()); next->phashBlock = new uint256(m_rng.rand256());
m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash()); m_node.chainman->ActiveChainstate().CoinsTip().SetBestBlock(next->GetBlockHash());
next->pprev = prev; next->pprev = prev;
next->nHeight = prev->nHeight + 1; next->nHeight = prev->nHeight + 1;

View file

@ -341,13 +341,14 @@ void SatisfactionToWitness(miniscript::MiniscriptContext ctx, CScriptWitness& wi
witness.stack.push_back(*builder.GetSpendData().scripts.begin()->second.begin()); witness.stack.push_back(*builder.GetSpendData().scripts.begin()->second.begin());
} }
struct MiniScriptTest : BasicTestingSetup {
/** Run random satisfaction tests. */ /** Run random satisfaction tests. */
void TestSatisfy(const KeyConverter& converter, const std::string& testcase, const NodeRef& node) { void TestSatisfy(const KeyConverter& converter, const std::string& testcase, const NodeRef& node) {
auto script = node->ToScript(converter); auto script = node->ToScript(converter);
auto challenges = FindChallenges(node); // Find all challenges in the generated miniscript. auto challenges = FindChallenges(node); // Find all challenges in the generated miniscript.
std::vector<Challenge> challist(challenges.begin(), challenges.end()); std::vector<Challenge> challist(challenges.begin(), challenges.end());
for (int iter = 0; iter < 3; ++iter) { 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()); Satisfier satisfier(converter.MsContext());
TestSignatureChecker checker(satisfier); TestSignatureChecker checker(satisfier);
bool prev_mal_success = false, prev_nonmal_success = false; 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, /*opslimit=*/-1, /*stacklimit=*/-1,
/*max_wit_size=*/std::nullopt, /*max_tap_wit_size=*/std::nullopt, /*stack_exec=*/std::nullopt); /*max_wit_size=*/std::nullopt, /*max_tap_wit_size=*/std::nullopt, /*stack_exec=*/std::nullopt);
} }
}; // struct MiniScriptTest
} // namespace } // namespace
BOOST_FIXTURE_TEST_SUITE(miniscript_tests, BasicTestingSetup) BOOST_FIXTURE_TEST_SUITE(miniscript_tests, MiniScriptTest)
BOOST_AUTO_TEST_CASE(fixed_tests) BOOST_AUTO_TEST_CASE(fixed_tests)
{ {

View file

@ -14,16 +14,16 @@
using node::MakeMinisketch32; using node::MakeMinisketch32;
BOOST_AUTO_TEST_SUITE(minisketch_tests) BOOST_FIXTURE_TEST_SUITE(minisketch_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(minisketch_test) BOOST_AUTO_TEST_CASE(minisketch_test)
{ {
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
uint32_t errors = 0 + InsecureRandRange(11); uint32_t errors = 0 + m_rng.randrange(11);
uint32_t start_a = 1 + InsecureRandRange(1000000000); uint32_t start_a = 1 + m_rng.randrange(1000000000);
uint32_t a_not_b = InsecureRandRange(errors + 1); uint32_t a_not_b = m_rng.randrange(errors + 1);
uint32_t b_not_a = errors - a_not_b; 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 end_a = start_a + a_not_b + both;
uint32_t start_b = start_a + a_not_b; uint32_t start_b = start_a + a_not_b;
uint32_t end_b = start_b + both + b_not_a; uint32_t end_b = start_b + both + b_not_a;

View file

@ -43,20 +43,21 @@ static CService ip(uint32_t i)
return CService{CNetAddr{s}, Params().GetDefaultPort()}; 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. */ /** 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{}; CAddress addr{};
if (address.has_value()) { if (address.has_value()) {
addr = CAddress{MaybeFlipIPv6toCJDNS(LookupNumeric(address.value(), Params().GetDefaultPort())), NODE_NONE}; addr = CAddress{MaybeFlipIPv6toCJDNS(LookupNumeric(address.value(), Params().GetDefaultPort())), NODE_NONE};
} else if (onion_peer) { } 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))); BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
} }
while (!addr.IsLocal() && !addr.IsRoutable()) { 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()); BOOST_REQUIRE(addr.IsValid());
@ -80,8 +81,9 @@ static void AddPeer(NodeId& id, std::vector<CNode*>& nodes, PeerManager& peerman
connman.AddTestNode(node); 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 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, {}); auto peerman = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});

View file

@ -1011,10 +1011,10 @@ BOOST_AUTO_TEST_CASE(advertise_local_address)
namespace { namespace {
CKey GenerateRandomTestKey() noexcept CKey GenerateRandomTestKey(FastRandomContext& rng) noexcept
{ {
CKey key; CKey key;
uint256 key_data = InsecureRand256(); uint256 key_data = rng.rand256();
key.Set(key_data.begin(), key_data.end(), true); key.Set(key_data.begin(), key_data.end(), true);
return key; return key;
} }
@ -1029,6 +1029,7 @@ CKey GenerateRandomTestKey() noexcept
*/ */
class V2TransportTester class V2TransportTester
{ {
FastRandomContext& m_rng;
V2Transport m_transport; //!< V2Transport being tested V2Transport m_transport; //!< V2Transport being tested
BIP324Cipher m_cipher; //!< Cipher to help with the other side BIP324Cipher m_cipher; //!< Cipher to help with the other side
bool m_test_initiator; //!< Whether m_transport is the initiator (true) or responder (false) bool m_test_initiator; //!< Whether m_transport is the initiator (true) or responder (false)
@ -1042,9 +1043,10 @@ class V2TransportTester
public: public:
/** Construct a tester object. test_initiator: whether the tested transport is initiator. */ /** Construct a tester object. test_initiator: whether the tested transport is initiator. */
explicit V2TransportTester(bool test_initiator) explicit V2TransportTester(FastRandomContext& rng, bool test_initiator)
: m_transport{0, test_initiator}, : m_rng{rng},
m_cipher{GenerateRandomTestKey(), MakeByteSpan(InsecureRand256())}, m_transport{0, test_initiator},
m_cipher{GenerateRandomTestKey(m_rng), MakeByteSpan(m_rng.rand256())},
m_test_initiator(test_initiator) {} m_test_initiator(test_initiator) {}
/** Data type returned by Interact: /** Data type returned by Interact:
@ -1068,7 +1070,7 @@ public:
bool progress{false}; bool progress{false};
// Send bytes from m_to_send to the transport. // Send bytes from m_to_send to the transport.
if (!m_to_send.empty()) { 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(); size_t old_len = to_send.size();
if (!m_transport.ReceivedBytes(to_send)) { if (!m_transport.ReceivedBytes(to_send)) {
return std::nullopt; // transport error occurred return std::nullopt; // transport error occurred
@ -1079,7 +1081,7 @@ public:
} }
} }
// Retrieve messages received by the transport. // Retrieve messages received by the transport.
if (m_transport.ReceivedMessageComplete() && (!progress || InsecureRandBool())) { if (m_transport.ReceivedMessageComplete() && (!progress || m_rng.randbool())) {
bool reject{false}; bool reject{false};
auto msg = m_transport.GetReceivedMessage({}, reject); auto msg = m_transport.GetReceivedMessage({}, reject);
if (reject) { if (reject) {
@ -1090,7 +1092,7 @@ public:
progress = true; progress = true;
} }
// Enqueue a message to be sent by the transport to us. // 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())) { if (m_transport.SetMessageToSend(m_msg_to_send.front())) {
m_msg_to_send.pop_front(); m_msg_to_send.pop_front();
progress = true; progress = true;
@ -1098,8 +1100,8 @@ public:
} }
// Receive bytes from the transport. // Receive bytes from the transport.
const auto& [recv_bytes, _more, _msg_type] = m_transport.GetBytesToSend(!m_msg_to_send.empty()); const auto& [recv_bytes, _more, _msg_type] = m_transport.GetBytesToSend(!m_msg_to_send.empty());
if (!recv_bytes.empty() && (!progress || InsecureRandBool())) { if (!recv_bytes.empty() && (!progress || m_rng.randbool())) {
size_t to_receive = 1 + InsecureRandRange(recv_bytes.size()); 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); m_received.insert(m_received.end(), recv_bytes.begin(), recv_bytes.begin() + to_receive);
progress = true; progress = true;
m_transport.MarkBytesSent(to_receive); m_transport.MarkBytesSent(to_receive);
@ -1121,7 +1123,7 @@ public:
/** Send V1 version message header to the transport. */ /** Send V1 version message header to the transport. */
void SendV1Version(const MessageStartChars& magic) void SendV1Version(const MessageStartChars& magic)
{ {
CMessageHeader hdr(magic, "version", 126 + InsecureRandRange(11)); CMessageHeader hdr(magic, "version", 126 + m_rng.randrange(11));
DataStream ser{}; DataStream ser{};
ser << hdr; ser << hdr;
m_to_send.insert(m_to_send.end(), UCharCast(ser.data()), UCharCast(ser.data() + ser.size())); 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) void SendGarbage(size_t garbage_len)
{ {
// Generate random garbage and send it. // 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. */ /** Schedule garbage (with valid random length) to be sent to the transport. */
void SendGarbage() 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. */ /** 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. */ /** Introduce a bit error in the data scheduled to be sent. */
void Damage() 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. // A mostly normal scenario, testing a transport in initiator mode.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
V2TransportTester tester(true); V2TransportTester tester(m_rng, true);
auto ret = tester.Interact(); auto ret = tester.Interact();
BOOST_REQUIRE(ret && ret->empty()); BOOST_REQUIRE(ret && ret->empty());
tester.SendKey(); tester.SendKey();
@ -1358,8 +1360,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
tester.ReceiveGarbage(); tester.ReceiveGarbage();
tester.ReceiveVersion(); tester.ReceiveVersion();
tester.CompareSessionIDs(); tester.CompareSessionIDs();
auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000)); auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(100000));
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(4), msg_data_1); // cmpctblock short id tester.SendMessage(uint8_t(4), msg_data_1); // cmpctblock short id
tester.SendMessage(0, {}); // Invalidly encoded message tester.SendMessage(0, {}); // Invalidly encoded message
tester.SendMessage("tx", msg_data_2); // 12-character encoded message type 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 if (!ret) break; // failure
BOOST_CHECK(ret->size() == 0); // no message can be delivered BOOST_CHECK(ret->size() == 0); // no message can be delivered
// Send another message. // 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 tester.SendMessage(uint8_t(12), msg_data_3); // getheaders short id
} }
} }
// Normal scenario, with a transport in responder node. // Normal scenario, with a transport in responder node.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
V2TransportTester tester(false); V2TransportTester tester(m_rng, false);
tester.SendKey(); tester.SendKey();
tester.SendGarbage(); tester.SendGarbage();
auto ret = tester.Interact(); auto ret = tester.Interact();
@ -1399,8 +1401,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
tester.ReceiveGarbage(); tester.ReceiveGarbage();
tester.ReceiveVersion(); tester.ReceiveVersion();
tester.CompareSessionIDs(); tester.CompareSessionIDs();
auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(InsecureRandRange(100000)); auto msg_data_1 = m_rng.randbytes<uint8_t>(m_rng.randrange(100000));
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(14), msg_data_1); // inv short id tester.SendMessage(uint8_t(14), msg_data_1); // inv short id
tester.SendMessage(uint8_t(19), msg_data_2); // pong short id tester.SendMessage(uint8_t(19), msg_data_2); // pong short id
ret = tester.Interact(); 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))); 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. // 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 tester.SendMessage(uint8_t(11), msg_data_3); // getdata short id
ret = tester.Interact(); ret = tester.Interact();
BOOST_CHECK(!ret); BOOST_CHECK(!ret);
@ -1418,18 +1420,18 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
// Various valid but unusual scenarios. // Various valid but unusual scenarios.
for (int i = 0; i < 50; ++i) { for (int i = 0; i < 50; ++i) {
/** Whether an initiator or responder is being tested. */ /** 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. */ /** 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. */ /** 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). */ /** 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). */ /** 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. */ /** How many decoy packets to send before the first and second real message. */
unsigned num_decoys_1 = InsecureRandRange(1000), num_decoys_2 = InsecureRandRange(1000); unsigned num_decoys_1 = m_rng.randrange(1000), num_decoys_2 = m_rng.randrange(1000);
V2TransportTester tester(initiator); V2TransportTester tester(m_rng, initiator);
if (send_immediately) { if (send_immediately) {
tester.SendKey(); tester.SendKey();
tester.SendGarbage(garb_len); tester.SendGarbage(garb_len);
@ -1443,8 +1445,8 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
tester.ReceiveKey(); tester.ReceiveKey();
tester.SendGarbageTerm(); tester.SendGarbageTerm();
for (unsigned v = 0; v < num_ignore_version; ++v) { for (unsigned v = 0; v < num_ignore_version; ++v) {
size_t ver_ign_data_len = InsecureRandBool() ? 0 : InsecureRandRange(1000); size_t ver_ign_data_len = m_rng.randbool() ? 0 : m_rng.randrange(1000);
auto ver_ign_data = g_insecure_rand_ctx.randbytes<uint8_t>(ver_ign_data_len); auto ver_ign_data = m_rng.randbytes<uint8_t>(ver_ign_data_len);
tester.SendVersion(ver_ign_data, true); tester.SendVersion(ver_ign_data, true);
} }
tester.SendVersion(ver_data, false); tester.SendVersion(ver_data, false);
@ -1454,16 +1456,16 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
tester.ReceiveVersion(); tester.ReceiveVersion();
tester.CompareSessionIDs(); tester.CompareSessionIDs();
for (unsigned d = 0; d < num_decoys_1; ++d) { 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); 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); tester.SendMessage(uint8_t(28), msg_data_1);
for (unsigned d = 0; d < num_decoys_2; ++d) { 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); 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 tester.SendMessage(uint8_t(13), msg_data_2); // headers short id
// Send invalidly-encoded message // Send invalidly-encoded message
tester.SendMessage(std::string("blocktxn\x00\x00\x00a", CMessageHeader::COMMAND_SIZE), {}); 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). // Too long garbage (initiator).
{ {
V2TransportTester tester(true); V2TransportTester tester(m_rng, true);
auto ret = tester.Interact(); auto ret = tester.Interact();
BOOST_REQUIRE(ret && ret->empty()); BOOST_REQUIRE(ret && ret->empty());
tester.SendKey(); tester.SendKey();
@ -1493,7 +1495,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
// Too long garbage (responder). // Too long garbage (responder).
{ {
V2TransportTester tester(false); V2TransportTester tester(m_rng, false);
tester.SendKey(); tester.SendKey();
tester.SendGarbage(V2Transport::MAX_GARBAGE_LEN + 1); tester.SendGarbage(V2Transport::MAX_GARBAGE_LEN + 1);
auto ret = tester.Interact(); 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. // Send garbage that includes the first 15 garbage terminator bytes somewhere.
{ {
V2TransportTester tester(true); V2TransportTester tester(m_rng, true);
auto ret = tester.Interact(); auto ret = tester.Interact();
BOOST_REQUIRE(ret && ret->empty()); BOOST_REQUIRE(ret && ret->empty());
tester.SendKey(); tester.SendKey();
tester.ReceiveKey(); tester.ReceiveKey();
/** The number of random garbage bytes before the included first 15 bytes of terminator. */ /** 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. */ /** 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. // 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. // Replace the designed 16 bytes in the middle with the to-be-sent garbage terminator.
auto garb_term = MakeUCharSpan(tester.GetCipher().GetSendGarbageTerminator()); auto garb_term = MakeUCharSpan(tester.GetCipher().GetSendGarbageTerminator());
std::copy(garb_term.begin(), garb_term.begin() + 16, garbage.begin() + len_before); 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 // Introduce a bit error in the last byte of that copied garbage terminator, making only
// the first 15 of them match. // 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.SendGarbage(garbage);
tester.SendGarbageTerm(); tester.SendGarbageTerm();
tester.SendVersion(); tester.SendVersion();
@ -1531,9 +1533,9 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
tester.ReceiveGarbage(); tester.ReceiveGarbage();
tester.ReceiveVersion(); tester.ReceiveVersion();
tester.CompareSessionIDs(); tester.CompareSessionIDs();
auto msg_data_1 = g_insecure_rand_ctx.randbytes<uint8_t>(4000000); // test that receiving 4M payload works auto msg_data_1 = m_rng.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 auto msg_data_2 = m_rng.randbytes<uint8_t>(4000000); // test that sending 4M payload works
tester.SendMessage(uint8_t(InsecureRandRange(223) + 33), {}); // unknown short id tester.SendMessage(uint8_t(m_rng.randrange(223) + 33), {}); // unknown short id
tester.SendMessage(uint8_t(2), msg_data_1); // "block" 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 tester.AddMessage("blocktxn", msg_data_2); // schedule blocktxn to be sent to us
ret = tester.Interact(); ret = tester.Interact();
@ -1545,7 +1547,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
// Send correct network's V1 header // Send correct network's V1 header
{ {
V2TransportTester tester(false); V2TransportTester tester(m_rng, false);
tester.SendV1Version(Params().MessageStart()); tester.SendV1Version(Params().MessageStart());
auto ret = tester.Interact(); auto ret = tester.Interact();
BOOST_CHECK(ret); BOOST_CHECK(ret);
@ -1553,7 +1555,7 @@ BOOST_AUTO_TEST_CASE(v2transport_test)
// Send wrong network's V1 header // Send wrong network's V1 header
{ {
V2TransportTester tester(false); V2TransportTester tester(m_rng, false);
tester.SendV1Version(CChainParams::Main()->MessageStart()); tester.SendV1Version(CChainParams::Main()->MessageStart());
auto ret = tester.Interact(); auto ret = tester.Interact();
BOOST_CHECK(!ret); BOOST_CHECK(!ret);

View file

@ -21,6 +21,8 @@ BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup)
class TxOrphanageTest : public TxOrphanage class TxOrphanageTest : public TxOrphanage
{ {
public: public:
TxOrphanageTest(FastRandomContext& rng) : m_rng{rng} {}
inline size_t CountOrphans() const inline size_t CountOrphans() const
{ {
return m_orphans.size(); return m_orphans.size();
@ -29,14 +31,16 @@ public:
CTransactionRef RandomOrphan() CTransactionRef RandomOrphan()
{ {
std::map<Wtxid, OrphanTx>::iterator it; 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()) if (it == m_orphans.end())
it = m_orphans.begin(); it = m_orphans.begin();
return it->second.tx; 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; std::vector<unsigned char> keydata;
keydata = rand_ctx.randbytes(32); 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. // ecdsa_signature_parse_der_lax are executed during this test.
// Specifically branches that run only when an ECDSA // Specifically branches that run only when an ECDSA
// signature's R and S values have leading zeros. // 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; CKey key;
MakeNewKeyWithFastRandomContext(key); MakeNewKeyWithFastRandomContext(key, m_rng);
FillableSigningProvider keystore; FillableSigningProvider keystore;
BOOST_CHECK(keystore.AddKey(key)); BOOST_CHECK(keystore.AddKey(key));
@ -122,7 +126,7 @@ BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
CMutableTransaction tx; CMutableTransaction tx;
tx.vin.resize(1); tx.vin.resize(1);
tx.vin[0].prevout.n = 0; 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.vin[0].scriptSig << OP_1;
tx.vout.resize(1); tx.vout.resize(1);
tx.vout[0].nValue = 1*CENT; tx.vout[0].nValue = 1*CENT;

View file

@ -17,12 +17,16 @@
class CPartialMerkleTreeTester : public CPartialMerkleTree class CPartialMerkleTreeTester : public CPartialMerkleTree
{ {
public: public:
CPartialMerkleTreeTester(FastRandomContext& rng) : m_rng{rng} {}
// flip one bit in one of the hashes - this should break the authentication // flip one bit in one of the hashes - this should break the authentication
void Damage() { void Damage() {
unsigned int n = InsecureRandRange(vHash.size()); unsigned int n = m_rng.randrange(vHash.size());
int bit = InsecureRandBits(8); int bit = m_rng.randbits(8);
*(vHash[n].begin() + (bit>>3)) ^= 1<<(bit&7); *(vHash[n].begin() + (bit>>3)) ^= 1<<(bit&7);
} }
FastRandomContext& m_rng;
}; };
BOOST_FIXTURE_TEST_SUITE(pmt_tests, BasicTestingSetup) 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<bool> vMatch(nTx, false);
std::vector<uint256> vMatchTxid1; std::vector<uint256> vMatchTxid1;
for (unsigned int j=0; j<nTx; j++) { 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; vMatch[j] = fInclude;
if (fInclude) if (fInclude)
vMatchTxid1.push_back(vTxid[j]); vMatchTxid1.push_back(vTxid[j]);
@ -77,7 +81,7 @@ BOOST_AUTO_TEST_CASE(pmt_test1)
BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8); BOOST_CHECK(ss.size() <= 10 + (258*n+7)/8);
// deserialize into a tester copy // deserialize into a tester copy
CPartialMerkleTreeTester pmt2; CPartialMerkleTreeTester pmt2{m_rng};
ss >> pmt2; ss >> pmt2;
// extract merkle root and matched txids from copy // extract merkle root and matched txids from copy

View file

@ -129,17 +129,17 @@ BOOST_AUTO_TEST_CASE(random_allocations)
std::vector<PtrSizeAlignment> ptr_size_alignment{}; std::vector<PtrSizeAlignment> ptr_size_alignment{};
for (size_t i = 0; i < 1000; ++i) { for (size_t i = 0; i < 1000; ++i) {
// make it a bit more likely to allocate than deallocate // 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 // allocate a random item
std::size_t alignment = std::size_t{1} << InsecureRandRange(8); // 1, 2, ..., 128 std::size_t alignment = std::size_t{1} << m_rng.randrange(8); // 1, 2, ..., 128
std::size_t size = (InsecureRandRange(200) / alignment + 1) * alignment; // multiple of alignment std::size_t size = (m_rng.randrange(200) / alignment + 1) * alignment; // multiple of alignment
void* ptr = resource.Allocate(size, alignment); void* ptr = resource.Allocate(size, alignment);
BOOST_TEST(ptr != nullptr); BOOST_TEST(ptr != nullptr);
BOOST_TEST((reinterpret_cast<uintptr_t>(ptr) & (alignment - 1)) == 0); BOOST_TEST((reinterpret_cast<uintptr_t>(ptr) & (alignment - 1)) == 0);
ptr_size_alignment.push_back({ptr, size, alignment}); ptr_size_alignment.push_back({ptr, size, alignment});
} else { } else {
// deallocate a random item // 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); resource.Deallocate(x.ptr, x.bytes, x.alignment);
x = ptr_size_alignment.back(); x = ptr_size_alignment.back();
ptr_size_alignment.pop_back(); ptr_size_alignment.pop_back();

View file

@ -147,9 +147,9 @@ BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
} }
for (int j = 0; j < 1000; j++) { for (int j = 0; j < 1000; j++) {
CBlockIndex *p1 = &blocks[InsecureRandRange(10000)]; CBlockIndex *p1 = &blocks[m_rng.randrange(10000)];
CBlockIndex *p2 = &blocks[InsecureRandRange(10000)]; CBlockIndex *p2 = &blocks[m_rng.randrange(10000)];
CBlockIndex *p3 = &blocks[InsecureRandRange(10000)]; CBlockIndex *p3 = &blocks[m_rng.randrange(10000)];
int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, chainParams->GetConsensus()); int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, chainParams->GetConsensus());
BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime()); BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime());

View file

@ -27,7 +27,6 @@ class prevector_tester {
typedef typename pretype::size_type Size; typedef typename pretype::size_type Size;
bool passed = true; bool passed = true;
FastRandomContext rand_cache;
uint256 rand_seed; uint256 rand_seed;
@ -208,84 +207,83 @@ public:
BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString()); BOOST_CHECK_MESSAGE(passed, "insecure_rand: " + rand_seed.ToString());
} }
prevector_tester() { prevector_tester(FastRandomContext& rng) {
SeedRandomForTest(); rand_seed = rng.rand256();
rand_seed = InsecureRand256(); rng.Reseed(rand_seed);
rand_cache.Reseed(rand_seed);
} }
}; };
BOOST_AUTO_TEST_CASE(PrevectorTestInt) BOOST_AUTO_TEST_CASE(PrevectorTestInt)
{ {
for (int j = 0; j < 64; j++) { 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++) { for (int i = 0; i < 2048; i++) {
if (InsecureRandBits(2) == 0) { if (m_rng.randbits(2) == 0) {
test.insert(InsecureRandRange(test.size() + 1), int(InsecureRand32())); test.insert(m_rng.randrange(test.size() + 1), int(m_rng.rand32()));
} }
if (test.size() > 0 && InsecureRandBits(2) == 1) { if (test.size() > 0 && m_rng.randbits(2) == 1) {
test.erase(InsecureRandRange(test.size())); test.erase(m_rng.randrange(test.size()));
} }
if (InsecureRandBits(3) == 2) { if (m_rng.randbits(3) == 2) {
int new_size = std::max(0, std::min(30, (int)test.size() + (int)InsecureRandRange(5) - 2)); int new_size = std::max(0, std::min(30, (int)test.size() + (int)m_rng.randrange(5) - 2));
test.resize(new_size); test.resize(new_size);
} }
if (InsecureRandBits(3) == 3) { if (m_rng.randbits(3) == 3) {
test.insert(InsecureRandRange(test.size() + 1), 1 + InsecureRandBool(), int(InsecureRand32())); test.insert(m_rng.randrange(test.size() + 1), 1 + m_rng.randbool(), int(m_rng.rand32()));
} }
if (InsecureRandBits(3) == 4) { if (m_rng.randbits(3) == 4) {
int del = std::min<int>(test.size(), 1 + (InsecureRandBool())); int del = std::min<int>(test.size(), 1 + (m_rng.randbool()));
int beg = InsecureRandRange(test.size() + 1 - del); int beg = m_rng.randrange(test.size() + 1 - del);
test.erase(beg, beg + del); test.erase(beg, beg + del);
} }
if (InsecureRandBits(4) == 5) { if (m_rng.randbits(4) == 5) {
test.push_back(int(InsecureRand32())); 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(); test.pop_back();
} }
if (InsecureRandBits(5) == 7) { if (m_rng.randbits(5) == 7) {
int values[4]; int values[4];
int num = 1 + (InsecureRandBits(2)); int num = 1 + (m_rng.randbits(2));
for (int k = 0; k < num; k++) { 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) { if (m_rng.randbits(5) == 8) {
int del = std::min<int>(test.size(), 1 + (InsecureRandBits(2))); int del = std::min<int>(test.size(), 1 + (m_rng.randbits(2)));
int beg = InsecureRandRange(test.size() + 1 - del); int beg = m_rng.randrange(test.size() + 1 - del);
test.erase(beg, beg + del); test.erase(beg, beg + del);
} }
if (InsecureRandBits(5) == 9) { if (m_rng.randbits(5) == 9) {
test.reserve(InsecureRandBits(5)); test.reserve(m_rng.randbits(5));
} }
if (InsecureRandBits(6) == 10) { if (m_rng.randbits(6) == 10) {
test.shrink_to_fit(); test.shrink_to_fit();
} }
if (test.size() > 0) { 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(); test.clear();
} }
if (InsecureRandBits(9) == 12) { if (m_rng.randbits(9) == 12) {
test.assign(InsecureRandBits(5), int(InsecureRand32())); test.assign(m_rng.randbits(5), int(m_rng.rand32()));
} }
if (InsecureRandBits(3) == 3) { if (m_rng.randbits(3) == 3) {
test.swap(); test.swap();
} }
if (InsecureRandBits(4) == 8) { if (m_rng.randbits(4) == 8) {
test.copy(); test.copy();
} }
if (InsecureRandBits(5) == 18) { if (m_rng.randbits(5) == 18) {
test.move(); test.move();
} }
if (InsecureRandBits(5) == 19) { if (m_rng.randbits(5) == 19) {
unsigned int num = 1 + (InsecureRandBits(4)); unsigned int num = 1 + (m_rng.randbits(4));
std::vector<int> values(num); std::vector<int> values(num);
for (int& v : values) { for (int& v : values) {
v = int(InsecureRand32()); v = int(m_rng.rand32());
} }
test.resize_uninitialized(values); test.resize_uninitialized(values);
} }

View file

@ -110,8 +110,7 @@ static ScriptError_t ParseScriptError(const std::string& name)
return SCRIPT_ERR_UNKNOWN_ERROR; 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) 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); 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. // 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) { 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)}; uint32_t combined_flags{expect ? (flags & ~extra_flags) : (flags | extra_flags)};
// Weed out some invalid flag combinations. // Weed out some invalid flag combinations.
if (combined_flags & SCRIPT_VERIFY_CLEANSTACK && ~combined_flags & (SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS)) continue; 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)); 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) { void static NegateSignatureS(std::vector<unsigned char>& vchSig) {
// Parse the signature. // Parse the signature.
@ -369,11 +369,11 @@ public:
return *this; return *this;
} }
TestBuilder& Test() TestBuilder& Test(ScriptTest& test)
{ {
TestBuilder copy = *this; // Make a copy so we can rollback the push. TestBuilder copy = *this; // Make a copy so we can rollback the push.
DoPush(); 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; *this = copy;
return *this; return *this;
} }
@ -425,6 +425,8 @@ std::string JSONPrettyPrint(const UniValue& univalue)
} }
} // namespace } // namespace
BOOST_FIXTURE_TEST_SUITE(script_tests, ScriptTest)
BOOST_AUTO_TEST_CASE(script_build) BOOST_AUTO_TEST_CASE(script_build)
{ {
const KeyData keys; const KeyData keys;
@ -884,7 +886,7 @@ BOOST_AUTO_TEST_CASE(script_build)
std::string strGen; std::string strGen;
#endif #endif
for (TestBuilder& test : tests) { for (TestBuilder& test : tests) {
test.Test(); test.Test(*this);
std::string str = JSONPrettyPrint(test.GetJSON()); std::string str = JSONPrettyPrint(test.GetJSON());
#ifdef UPDATE_JSON_TESTS #ifdef UPDATE_JSON_TESTS
strGen += str + ",\n"; strGen += str + ",\n";

View file

@ -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 // These specific bits are the sign bit, and the 2 top and bottom bits of
// exponent and mantissa in the IEEE754 binary64 format. // exponent and mantissa in the IEEE754 binary64 format.
for (int x = 0; x < 512; ++x) { for (int x = 0; x < 512; ++x) {
uint64_t v = InsecureRandBits(64); uint64_t v = m_rng.randbits(64);
int x_pos = 0; int x_pos = 0;
for (int v_pos : {0, 1, 50, 51, 52, 53, 61, 62, 63}) { for (int v_pos : {0, 1, 50, 51, 52, 53, 61, 62, 63}) {
v &= ~(uint64_t{1} << v_pos); v &= ~(uint64_t{1} << v_pos);

View file

@ -82,39 +82,41 @@ uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, un
return ss.GetHash(); 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}; static const opcodetype oplist[] = {OP_FALSE, OP_1, OP_2, OP_3, OP_CHECKSIG, OP_IF, OP_VERIF, OP_RETURN, OP_CODESEPARATOR};
script = CScript(); script = CScript();
int ops = (InsecureRandRange(10)); int ops = (m_rng.randrange(10));
for (int i=0; i<ops; i++) 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.vin.clear();
tx.vout.clear(); tx.vout.clear();
tx.nLockTime = (InsecureRandBool()) ? InsecureRand32() : 0; tx.nLockTime = (m_rng.randbool()) ? m_rng.rand32() : 0;
int ins = (InsecureRandBits(2)) + 1; int ins = (m_rng.randbits(2)) + 1;
int outs = fSingle ? ins : (InsecureRandBits(2)) + 1; int outs = fSingle ? ins : (m_rng.randbits(2)) + 1;
for (int in = 0; in < ins; in++) { for (int in = 0; in < ins; in++) {
tx.vin.emplace_back(); tx.vin.emplace_back();
CTxIn &txin = tx.vin.back(); CTxIn &txin = tx.vin.back();
txin.prevout.hash = Txid::FromUint256(InsecureRand256()); txin.prevout.hash = Txid::FromUint256(m_rng.rand256());
txin.prevout.n = InsecureRandBits(2); txin.prevout.n = m_rng.randbits(2);
RandomScript(txin.scriptSig); 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++) { for (int out = 0; out < outs; out++) {
tx.vout.emplace_back(); tx.vout.emplace_back();
CTxOut &txout = tx.vout.back(); CTxOut &txout = tx.vout.back();
txout.nValue = InsecureRandMoneyAmount(); txout.nValue = RandMoney(m_rng);
RandomScript(txout.scriptPubKey); 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) BOOST_AUTO_TEST_CASE(sighash_test)
{ {
@ -126,12 +128,12 @@ BOOST_AUTO_TEST_CASE(sighash_test)
int nRandomTests = 50000; int nRandomTests = 50000;
#endif #endif
for (int i=0; i<nRandomTests; i++) { for (int i=0; i<nRandomTests; i++) {
int nHashType{int(InsecureRand32())}; int nHashType{int(m_rng.rand32())};
CMutableTransaction txTo; CMutableTransaction txTo;
RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE); RandomTransaction(txTo, (nHashType & 0x1f) == SIGHASH_SINGLE);
CScript scriptCode; CScript scriptCode;
RandomScript(scriptCode); RandomScript(scriptCode);
int nIn = InsecureRandRange(txTo.vin.size()); int nIn = m_rng.randrange(txTo.vin.size());
uint256 sh, sho; uint256 sh, sho;
sho = SignatureHashOld(scriptCode, CTransaction(txTo), nIn, nHashType); sho = SignatureHashOld(scriptCode, CTransaction(txTo), nIn, nHashType);

View file

@ -34,8 +34,8 @@ BOOST_AUTO_TEST_CASE(skiplist_test)
} }
for (int i=0; i < 1000; i++) { for (int i=0; i < 1000; i++) {
int from = InsecureRandRange(SKIPLIST_LENGTH - 1); int from = m_rng.randrange(SKIPLIST_LENGTH - 1);
int to = InsecureRandRange(from + 1); int to = m_rng.randrange(from + 1);
BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]); BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]);
BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]); 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. // Test 100 random starting points for locators.
for (int n=0; n<100; n++) { 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]; CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];
CBlockLocator locator = GetLocator(tip); CBlockLocator locator = GetLocator(tip);
@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(findearliestatleast_test)
} else { } else {
// randomly choose something in the range [MTP, MTP*2] // randomly choose something in the range [MTP, MTP*2]
int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast(); 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].nTime = uint32_t(r + medianTimePast);
vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax); 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. // Verify that FindEarliestAtLeast is correct.
for (unsigned int i=0; i<10000; ++i) { for (unsigned int i=0; i<10000; ++i) {
// Pick a random element in vBlocksMain. // 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; int64_t test_time = vBlocksMain[r].nTime;
CBlockIndex* ret = chain.FindEarliestAtLeast(test_time, 0); CBlockIndex* ret = chain.FindEarliestAtLeast(test_time, 0);
BOOST_CHECK(ret->nTimeMax >= test_time); BOOST_CHECK(ret->nTimeMax >= test_time);

View file

@ -440,14 +440,14 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp"; fs::path streams_test_filename = m_args.GetDataDirBase() / "streams_test_tmp";
for (int rep = 0; rep < 50; ++rep) { for (int rep = 0; rep < 50; ++rep) {
AutoFile file{fsbridge::fopen(streams_test_filename, "w+b")}; 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) { for (uint8_t i = 0; i < fileSize; ++i) {
file << i; file << i;
} }
std::rewind(file.Get()); std::rewind(file.Get());
size_t bufSize = InsecureRandRange(300) + 1; size_t bufSize = m_rng.randrange(300) + 1;
size_t rewindSize = InsecureRandRange(bufSize); size_t rewindSize = m_rng.randrange(bufSize);
BufferedFile bf{file, bufSize, rewindSize}; BufferedFile bf{file, bufSize, rewindSize};
size_t currentPos = 0; size_t currentPos = 0;
size_t maxPos = 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 // sizes; the boundaries of the objects can interact arbitrarily
// with the CBufferFile's internal buffer. These first three // with the CBufferFile's internal buffer. These first three
// cases simulate objects of various sizes (1, 2, 5 bytes). // cases simulate objects of various sizes (1, 2, 5 bytes).
switch (InsecureRandRange(6)) { switch (m_rng.randrange(6)) {
case 0: { case 0: {
uint8_t a[1]; uint8_t a[1];
if (currentPos + 1 > fileSize) if (currentPos + 1 > fileSize)
@ -503,7 +503,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
case 3: { case 3: {
// SkipTo is similar to the "read" cases above, except // SkipTo is similar to the "read" cases above, except
// we don't receive the data. // 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; if (currentPos + skip_length > fileSize) continue;
bf.SetLimit(currentPos + skip_length); bf.SetLimit(currentPos + skip_length);
bf.SkipTo(currentPos + skip_length); bf.SkipTo(currentPos + skip_length);
@ -512,7 +512,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
} }
case 4: { case 4: {
// Find a byte value (that is at or ahead of the current position). // 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) if (find >= fileSize)
find = fileSize - 1; find = fileSize - 1;
bf.FindByte(std::byte(find)); bf.FindByte(std::byte(find));
@ -528,7 +528,7 @@ BOOST_AUTO_TEST_CASE(streams_buffered_file_rand)
break; break;
} }
case 5: { case 5: {
size_t requestPos = InsecureRandRange(maxPos + 4); size_t requestPos = m_rng.randrange(maxPos + 4);
bool okay = bf.SetPos(requestPos); bool okay = bf.SetPos(requestPos);
// The new position may differ from the requested position // The new position may differ from the requested position
// because we may not be able to rewind beyond the rewind // because we may not be able to rewind beyond the rewind

View file

@ -263,7 +263,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest); BOOST_ERROR("Tx unexpectedly failed with flag " << name << " unset: " << strTest);
} }
// Removing random combinations of flags // 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)) { if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/true)) {
BOOST_ERROR("Tx unexpectedly failed with random flags " << ToString(flags) << ": " << strTest); 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); BOOST_ERROR("Tx unexpectedly passed with flag " << name << " set: " << strTest);
} }
// Adding random combinations of flags // 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)) { if (!CheckTxScripts(tx, mapprevOutScriptPubKeys, mapprevOutValues, flags, txdata, strTest, /*expect_valid=*/false)) {
BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest); BOOST_ERROR("Tx unexpectedly passed with random flags " << name << ": " << strTest);
} }

View file

@ -20,20 +20,20 @@
#include <boost/test/unit_test.hpp> #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 // A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these
// unit tests. // unit tests.
static const CAmount low_fee_amt{200}; static const CAmount low_fee_amt{200};
struct TxPackageTest : TestChain100Setup {
// Create placeholder transactions that have no meaning. // Create placeholder transactions that have no meaning.
inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs) inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
{ {
CMutableTransaction mtx = CMutableTransaction(); CMutableTransaction mtx = CMutableTransaction();
mtx.vin.resize(num_inputs); mtx.vin.resize(num_inputs);
mtx.vout.resize(num_outputs); 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) { 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].prevout.n = 0;
mtx.vin[i].scriptSig = random_script; 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); 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 // Random real segwit transaction
DataStream stream_1{ 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_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. // Packages can't have more than 25 transactions.
Package package_too_many; 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 // Packages can't have transactions spending the same prevout
CMutableTransaction tx_zero_1; CMutableTransaction tx_zero_1;
CMutableTransaction tx_zero_2; 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_1.vin.emplace_back(same_prevout);
tx_zero_2.vin.emplace_back(same_prevout); tx_zero_2.vin.emplace_back(same_prevout);
// Different vouts (not the same tx) // 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 // IsConsistentPackage only cares about conflicts between transactions, not about a transaction
// conflicting with itself (i.e. duplicate prevouts in vin). // conflicting with itself (i.e. duplicate prevouts in vin).
CMutableTransaction dup_tx; 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);
dup_tx.vin.emplace_back(rand_prevout); dup_tx.vin.emplace_back(rand_prevout);
Package package_with_dup_tx{MakeTransactionRef(dup_tx)}; 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_CHECK(IsConsistentPackage(package_with_dup_tx));
} }
BOOST_FIXTURE_TEST_CASE(package_validation_tests, TestChain100Setup) BOOST_AUTO_TEST_CASE(package_validation_tests)
{ {
LOCK(cs_main); LOCK(cs_main);
unsigned int initialPoolSize = m_node.mempool->size(); 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_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 // The signatures won't be verified so we can just use a placeholder
CKey placeholder_key = GenerateRandomKey(); 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); LOCK(cs_main);
unsigned int expected_pool_size = m_node.mempool->size(); 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 // Tests for packages containing transactions that have same-txid-different-witness equivalents in
// the mempool. // the mempool.
BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup) BOOST_AUTO_TEST_CASE(package_witness_swap_tests)
{ {
// Mine blocks to mature coinbases. // Mine blocks to mature coinbases.
mineBlocks(5); 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); mineBlocks(5);
MockMempoolMinFee(CFeeRate(5000)); 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); mineBlocks(5);
LOCK(::cs_main); LOCK(::cs_main);

View file

@ -15,10 +15,23 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(txrequest_tests, BasicTestingSetup)
namespace { 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 MIN_TIME = std::chrono::microseconds::min();
constexpr std::chrono::microseconds MAX_TIME = std::chrono::microseconds::max(); constexpr std::chrono::microseconds MAX_TIME = std::chrono::microseconds::max();
constexpr std::chrono::microseconds MICROSECOND = std::chrono::microseconds{1}; constexpr std::chrono::microseconds MICROSECOND = std::chrono::microseconds{1};
@ -51,8 +64,8 @@ struct Runner
std::multiset<std::pair<NodeId, GenTxid>> expired; std::multiset<std::pair<NodeId, GenTxid>> expired;
}; };
std::chrono::microseconds RandomTime8s() { return std::chrono::microseconds{1 + InsecureRandBits(23)}; } std::chrono::microseconds TxRequestTest::RandomTime8s() { return std::chrono::microseconds{1 + m_rng.randbits(23)}; }
std::chrono::microseconds RandomTime1y() { return std::chrono::microseconds{1 + InsecureRandBits(45)}; } 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. /** 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 class Scenario
{ {
FastRandomContext& m_rng;
Runner& m_runner; Runner& m_runner;
std::chrono::microseconds m_now; std::chrono::microseconds m_now;
std::string m_testname; std::string m_testname;
public: 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. */ /** Set a name for the current test, to give more clear error messages. */
void SetTestName(std::string testname) void SetTestName(std::string testname)
@ -199,7 +213,7 @@ public:
uint256 ret; uint256 ret;
bool ok; bool ok;
do { do {
ret = InsecureRand256(); ret = m_rng.rand256();
ok = true; ok = true;
for (const auto& order : orders) { for (const auto& order : orders) {
for (size_t pos = 1; pos < order.size(); ++pos) { 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. */ /** Generate a random GenTxid; the txhash follows NewTxHash; the is_wtxid flag is random. */
GenTxid NewGTxid(const std::vector<std::vector<NodeId>>& orders = {}) 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 /** Generate a new random NodeId to use as peer. The same NodeId is never returned twice
@ -232,7 +246,7 @@ public:
bool ok; bool ok;
NodeId ret; NodeId ret;
do { do {
ret = InsecureRandBits(63); ret = m_rng.randbits(63);
ok = m_runner.peerset.insert(ret).second; ok = m_runner.peerset.insert(ret).second;
} while(!ok); } while(!ok);
return ret; return ret;
@ -245,7 +259,7 @@ public:
* *
* config is an integer in [0, 32), which controls which variant of the test is used. * 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 peer = scenario.NewPeer();
auto gtxid = scenario.NewGTxid(); auto gtxid = scenario.NewGTxid();
@ -282,7 +296,7 @@ void BuildSingleTest(Scenario& scenario, int config)
scenario.CheckExpired(peer, gtxid); scenario.CheckExpired(peer, gtxid);
return; return;
} else { } 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"); scenario.Check(peer, {}, 0, 1, 0, "s9");
if ((config >> 3) == 3) { // A response will arrive for the transaction if ((config >> 3) == 3) { // A response will arrive for the transaction
scenario.ReceivedResponse(peer, gtxid.GetHash()); 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. * 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)); 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.ReceivedInv(peer1, gtxid, pref1, MIN_TIME);
scenario.Check(peer1, {gtxid}, 1, 0, 0, "p1"); scenario.Check(peer1, {gtxid}, 1, 0, 0, "p1");
if (InsecureRandBool()) { if (m_rng.randbool()) {
scenario.AdvanceTime(RandomTime8s()); scenario.AdvanceTime(RandomTime8s());
scenario.Check(peer1, {gtxid}, 1, 0, 0, "p2"); 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; NodeId priopeer = stage2_prio ? peer2 : peer1, otherpeer = stage2_prio ? peer1 : peer2;
scenario.Check(otherpeer, {}, 1, 0, 0, "p3"); scenario.Check(otherpeer, {}, 1, 0, 0, "p3");
scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p4"); 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(otherpeer, {}, 1, 0, 0, "p5");
scenario.Check(priopeer, {gtxid}, 1, 0, 0, "p6"); 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.RequestedTx(priopeer, gtxid.GetHash(), MAX_TIME);
scenario.Check(priopeer, {}, 0, 1, 0, "p7"); scenario.Check(priopeer, {}, 0, 1, 0, "p7");
scenario.Check(otherpeer, {}, 1, 0, 0, "p8"); 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. // 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 { } else {
scenario.ReceivedResponse(priopeer, gtxid.GetHash()); 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(priopeer, {}, 0, 0, !(config & 16), "p8");
scenario.Check(otherpeer, {gtxid}, 1, 0, 0, "p9"); 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. // Now the other peer goes offline.
scenario.DisconnectedPeer(otherpeer); scenario.DisconnectedPeer(otherpeer);
if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.Check(peer1, {}, 0, 0, 0, "p10"); scenario.Check(peer1, {}, 0, 0, 0, "p10");
scenario.Check(peer2, {}, 0, 0, 0, "p11"); scenario.Check(peer2, {}, 0, 0, 0, "p11");
} }
/** Add to scenario a randomized test in which N peers announce the same transaction, to verify /** Add to scenario a randomized test in which N peers announce the same transaction, to verify
* the order in which they are requested. */ * 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)); scenario.SetTestName(strprintf("BigPriority(peers=%i)", peers));
// We will have N peers announce the same transaction. // We will have N peers announce the same transaction.
std::map<NodeId, bool> preferred; std::map<NodeId, bool> preferred;
std::vector<NodeId> pref_peers, npref_peers; 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. int num_npref = peers - num_pref; // some not preferred.
for (int i = 0; i < num_pref; ++i) { for (int i = 0; i < num_pref; ++i) {
pref_peers.push_back(scenario.NewPeer()); pref_peers.push_back(scenario.NewPeer());
@ -392,7 +406,7 @@ void BuildBigPriorityTest(Scenario& scenario, int peers)
// Determine the announcement order randomly. // Determine the announcement order randomly.
std::vector<NodeId> announce_order = request_order; 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 // Find a gtxid whose txhash prioritization is consistent with the required ordering within pref_peers and
// within npref_peers. // 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 // 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. // peer should be the best remaining one, so verify this after every response.
for (int i = 0; i < peers; ++i) { for (int i = 0; i < peers; ++i) {
if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
const int pos = InsecureRandRange(request_order.size()); const int pos = m_rng.randrange(request_order.size());
const auto peer = request_order[pos]; const auto peer = request_order[pos];
request_order.erase(request_order.begin() + pos); request_order.erase(request_order.begin() + pos);
if (InsecureRandBool()) { if (m_rng.randbool()) {
scenario.DisconnectedPeer(peer); scenario.DisconnectedPeer(peer);
scenario.Check(peer, {}, 0, 0, 0, "b4"); scenario.Check(peer, {}, 0, 0, 0, "b4");
} else { } 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. * 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)); 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. * 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)); scenario.SetTestName(strprintf("Wtxid(config=%i)", config));
@ -499,17 +513,17 @@ void BuildWtxidTest(Scenario& scenario, int config)
auto txid{GenTxid::Txid(txhash)}; auto txid{GenTxid::Txid(txhash)};
auto wtxid{GenTxid::Wtxid(txhash)}; auto wtxid{GenTxid::Wtxid(txhash)};
auto reqtimeT = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); auto reqtimeT = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
auto reqtimeW = InsecureRandBool() ? MIN_TIME : scenario.Now() + RandomTime8s(); auto reqtimeW = m_rng.randbool() ? MIN_TIME : scenario.Now() + RandomTime8s();
// Announce txid first or wtxid first. // Announce txid first or wtxid first.
if (config & 1) { if (config & 1) {
scenario.ReceivedInv(peerT, txid, config & 2, reqtimeT); 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); scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW);
} else { } else {
scenario.ReceivedInv(peerW, wtxid, !(config & 2), reqtimeW); 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); 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 // If a good transaction with either that hash as wtxid or txid arrives, both
// announcements are gone. // announcements are gone.
if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ForgetTxHash(txhash); scenario.ForgetTxHash(txhash);
scenario.Check(peerT, {}, 0, 0, 0, "w13"); scenario.Check(peerT, {}, 0, 0, 0, "w13");
scenario.Check(peerW, {}, 0, 0, 0, "w14"); scenario.Check(peerW, {}, 0, 0, 0, "w14");
} }
/** Add to scenario a test that exercises clocks that go backwards. */ /** 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 peer1 = scenario.NewPeer();
auto peer2 = scenario.NewPeer(); auto peer2 = scenario.NewPeer();
@ -577,13 +591,13 @@ void BuildTimeBackwardsTest(Scenario& scenario)
scenario.Check(peer2, {gtxid}, 1, 0, 0, "r4"); scenario.Check(peer2, {gtxid}, 1, 0, 0, "r4");
// Announce from peer1. // Announce from peer1.
if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ReceivedInv(peer1, gtxid, true, MAX_TIME); scenario.ReceivedInv(peer1, gtxid, true, MAX_TIME);
scenario.Check(peer2, {gtxid}, 1, 0, 0, "r5"); scenario.Check(peer2, {gtxid}, 1, 0, 0, "r5");
scenario.Check(peer1, {}, 1, 0, 0, "r6"); scenario.Check(peer1, {}, 1, 0, 0, "r6");
// Request from peer1. // Request from peer1.
if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
auto expiry = scenario.Now() + RandomTime8s(); auto expiry = scenario.Now() + RandomTime8s();
scenario.RequestedTx(peer1, gtxid.GetHash(), expiry); scenario.RequestedTx(peer1, gtxid.GetHash(), expiry);
scenario.Check(peer1, {}, 0, 1, 0, "r7"); scenario.Check(peer1, {}, 0, 1, 0, "r7");
@ -598,14 +612,14 @@ void BuildTimeBackwardsTest(Scenario& scenario)
scenario.Check(peer2, {gtxid}, 1, 0, 0, "r12", -MICROSECOND); scenario.Check(peer2, {gtxid}, 1, 0, 0, "r12", -MICROSECOND);
// Peer2 goes offline, meaning no viable announcements remain. // Peer2 goes offline, meaning no viable announcements remain.
if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.DisconnectedPeer(peer2); scenario.DisconnectedPeer(peer2);
scenario.Check(peer1, {}, 0, 0, 0, "r13"); scenario.Check(peer1, {}, 0, 0, 0, "r13");
scenario.Check(peer2, {}, 0, 0, 0, "r14"); scenario.Check(peer2, {}, 0, 0, 0, "r14");
} }
/** Add to scenario a test that involves RequestedTx() calls for txhashes not returned by GetRequestable. */ /** 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 peer1 = scenario.NewPeer();
auto peer2 = scenario.NewPeer(); auto peer2 = scenario.NewPeer();
@ -617,19 +631,19 @@ void BuildWeirdRequestsTest(Scenario& scenario)
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q1"); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q1");
// Announce gtxid2 by peer2. // Announce gtxid2 by peer2.
if (InsecureRandBool()) scenario.AdvanceTime(RandomTime8s()); if (m_rng.randbool()) scenario.AdvanceTime(RandomTime8s());
scenario.ReceivedInv(peer2, gtxid2, true, MIN_TIME); scenario.ReceivedInv(peer2, gtxid2, true, MIN_TIME);
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q2"); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q2");
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q3"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q3");
// We request gtxid2 from *peer1* - no effect. // 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.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME);
scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4"); scenario.Check(peer1, {gtxid1}, 1, 0, 0, "q4");
scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5"); scenario.Check(peer2, {gtxid2}, 1, 0, 0, "q5");
// Now request gtxid1 from peer1 - marks it as REQUESTED. // 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(); auto expiryA = scenario.Now() + RandomTime8s();
scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA); scenario.RequestedTx(peer1, gtxid1.GetHash(), expiryA);
scenario.Check(peer1, {}, 0, 1, 0, "q6"); scenario.Check(peer1, {}, 0, 1, 0, "q6");
@ -653,25 +667,25 @@ void BuildWeirdRequestsTest(Scenario& scenario)
scenario.CheckExpired(peer1, gtxid1); scenario.CheckExpired(peer1, gtxid1);
// Requesting it yet again from peer1 doesn't do anything, as it's already COMPLETED. // 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.RequestedTx(peer1, gtxid1.GetHash(), MAX_TIME);
scenario.Check(peer1, {}, 0, 0, 1, "q14"); scenario.Check(peer1, {}, 0, 0, 1, "q14");
scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15"); scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q15");
// Now announce gtxid2 from peer1. // 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.ReceivedInv(peer1, gtxid2, true, MIN_TIME);
scenario.Check(peer1, {}, 1, 0, 1, "q16"); scenario.Check(peer1, {}, 1, 0, 1, "q16");
scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q17"); scenario.Check(peer2, {gtxid2, gtxid1}, 2, 0, 0, "q17");
// And request it from peer1 (weird as peer2 has the preference). // 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.RequestedTx(peer1, gtxid2.GetHash(), MAX_TIME);
scenario.Check(peer1, {}, 0, 1, 1, "q18"); scenario.Check(peer1, {}, 0, 1, 1, "q18");
scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19"); scenario.Check(peer2, {gtxid1}, 2, 0, 0, "q19");
// If peer2 now (normally) requests gtxid2, the existing request by peer1 becomes COMPLETED. // 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.RequestedTx(peer2, gtxid2.GetHash(), MAX_TIME);
scenario.Check(peer1, {}, 0, 0, 2, "q20"); scenario.Check(peer1, {}, 0, 0, 2, "q20");
scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21"); scenario.Check(peer2, {gtxid1}, 1, 1, 0, "q21");
@ -682,22 +696,22 @@ void BuildWeirdRequestsTest(Scenario& scenario)
scenario.Check(peer2, {}, 0, 0, 0, "q23"); scenario.Check(peer2, {}, 0, 0, 0, "q23");
} }
void TestInterleavedScenarios() void TxRequestTest::TestInterleavedScenarios()
{ {
// Create a list of functions which add tests to scenarios. // Create a list of functions which add tests to scenarios.
std::vector<std::function<void(Scenario&)>> builders; std::vector<std::function<void(Scenario&)>> builders;
// Add instances of every test, for every configuration. // Add instances of every test, for every configuration.
for (int n = 0; n < 64; ++n) { for (int n = 0; n < 64; ++n) {
builders.emplace_back([n](Scenario& scenario){ BuildWtxidTest(scenario, n); }); builders.emplace_back([this, n](Scenario& scenario) { BuildWtxidTest(scenario, n); });
builders.emplace_back([n](Scenario& scenario){ BuildRequestOrderTest(scenario, n & 3); }); builders.emplace_back([this, n](Scenario& scenario) { BuildRequestOrderTest(scenario, n & 3); });
builders.emplace_back([n](Scenario& scenario){ BuildSingleTest(scenario, n & 31); }); builders.emplace_back([this, n](Scenario& scenario) { BuildSingleTest(scenario, n & 31); });
builders.emplace_back([n](Scenario& scenario){ BuildPriorityTest(scenario, n & 31); }); builders.emplace_back([this, n](Scenario& scenario) { BuildPriorityTest(scenario, n & 31); });
builders.emplace_back([n](Scenario& scenario){ BuildBigPriorityTest(scenario, (n & 7) + 1); }); builders.emplace_back([this, n](Scenario& scenario) { BuildBigPriorityTest(scenario, (n & 7) + 1); });
builders.emplace_back([](Scenario& scenario){ BuildTimeBackwardsTest(scenario); }); builders.emplace_back([this](Scenario& scenario) { BuildTimeBackwardsTest(scenario); });
builders.emplace_back([](Scenario& scenario){ BuildWeirdRequestsTest(scenario); }); builders.emplace_back([this](Scenario& scenario) { BuildWeirdRequestsTest(scenario); });
} }
// Randomly shuffle all those functions. // 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; Runner runner;
auto starttime = RandomTime1y(); 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 // Introduce some variation in the start time of each scenario, so they don't all start off
// concurrently, but get a more random interleaving. // concurrently, but get a more random interleaving.
auto scenario_start = starttime + RandomTime8s() + RandomTime8s() + RandomTime8s(); 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) { for (int j = 0; builders.size() && j < 10; ++j) {
builders.back()(scenario); builders.back()(scenario);
builders.pop_back(); builders.pop_back();
@ -730,6 +744,8 @@ void TestInterleavedScenarios()
} // namespace } // namespace
BOOST_FIXTURE_TEST_SUITE(txrequest_tests, TxRequestTest)
BOOST_AUTO_TEST_CASE(TxRequestTest) BOOST_AUTO_TEST_CASE(TxRequestTest)
{ {
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {

View file

@ -13,12 +13,12 @@
#include <stdint.h> #include <stdint.h>
#include <utility> #include <utility>
COutPoint AddTestCoin(CCoinsViewCache& coins_view) COutPoint AddTestCoin(FastRandomContext& rng, CCoinsViewCache& coins_view)
{ {
Coin new_coin; Coin new_coin;
COutPoint outpoint{Txid::FromUint256(InsecureRand256()), /*nIn=*/0}; COutPoint outpoint{Txid::FromUint256(rng.rand256()), /*nIn=*/0};
new_coin.nHeight = 1; new_coin.nHeight = 1;
new_coin.out.nValue = InsecureRandMoneyAmount(); new_coin.out.nValue = RandMoney(rng);
new_coin.out.scriptPubKey.assign(uint32_t{56}, 1); new_coin.out.scriptPubKey.assign(uint32_t{56}, 1);
coins_view.AddCoin(outpoint, std::move(new_coin), /*possible_overwrite=*/false); coins_view.AddCoin(outpoint, std::move(new_coin), /*possible_overwrite=*/false);

View file

@ -8,12 +8,13 @@
#include <primitives/transaction.h> #include <primitives/transaction.h>
class CCoinsViewCache; class CCoinsViewCache;
class FastRandomContext;
/** /**
* Create a Coin with DynamicMemoryUsage of 80 bytes and add it to the given view. * 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. * @param[in,out] coins_view The coins view cache to add the new coin to.
* @returns the COutPoint of the created coin. * @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 #endif // BITCOIN_TEST_UTIL_COINS_H

View file

@ -12,11 +12,9 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
FastRandomContext g_insecure_rand_ctx;
extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept; extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept;
void SeedRandomForTest(SeedRand seedtype) void SeedRandomStateForTest(SeedRand seedtype)
{ {
constexpr auto RANDOM_CTX_SEED{"RANDOM_CTX_SEED"}; 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}; 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()); LogInfo("Setting random seed for current tests to %s=%s\n", RANDOM_CTX_SEED, seed.GetHex());
MakeRandDeterministicDANGEROUS(seed); MakeRandDeterministicDANGEROUS(seed);
g_insecure_rand_ctx.Reseed(GetRandHash());
} }

View file

@ -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 // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -11,50 +11,18 @@
#include <cstdint> #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 { enum class SeedRand {
ZEROS, //!< Seed with a compile time constant of zeros ZEROS, //!< Seed with a compile time constant of zeros
SEED, //!< Use (and report) random seed from environment, or a (truly) random one. SEED, //!< Use (and report) random seed from environment, or a (truly) random one.
}; };
/** Seed the RNG for testing. This affects all randomness, except GetStrongRandBytes(). */ /** Seed the global RNG state for testing and log the seed value. This affects all randomness, except GetStrongRandBytes(). */
void SeedRandomForTest(SeedRand seed = SeedRand::SEED); void SeedRandomStateForTest(SeedRand seed);
static inline uint32_t InsecureRand32() template <RandomNumberGenerator Rng>
inline CAmount RandMoney(Rng&& rng)
{ {
return g_insecure_rand_ctx.rand32(); return CAmount{rng.randrange(MAX_MONEY + 1)};
}
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();
}
static inline CAmount InsecureRandMoneyAmount()
{
return static_cast<CAmount>(InsecureRandRange(MAX_MONEY + 1));
} }
#endif // BITCOIN_TEST_UTIL_RANDOM_H #endif // BITCOIN_TEST_UTIL_RANDOM_H

View file

@ -75,8 +75,8 @@ using node::VerifyLoadedChainstate;
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; 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 */ /** Random context to get unique temp data dirs. Separate from m_rng, which can be seeded from a const env var */
static FastRandomContext g_insecure_rand_ctx_temp_path; static FastRandomContext g_rng_temp_path;
std::ostream& operator<<(std::ostream& os, const arith_uint256& num) 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")) { if (!m_node.args->IsArgSet("-testdatadir")) {
// By default, the data directory has a random name // 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; m_path_root = fs::temp_directory_path() / "test_common_" PACKAGE_NAME / rand_str;
TryCreateDirectories(m_path_root); TryCreateDirectories(m_path_root);
} else { } 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 // Manually create an invalid transaction. Manually set the fee in the CTxMemPoolEntry to
// achieve the exact target feerate. // achieve the exact target feerate.
CMutableTransaction mtx = CMutableTransaction(); 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))); mtx.vout.emplace_back(1 * COIN, GetScriptForDestination(WitnessV0ScriptHash(CScript() << OP_TRUE)));
const auto tx{MakeTransactionRef(mtx)}; const auto tx{MakeTransactionRef(mtx)};
LockPoints lp; LockPoints lp;

View file

@ -13,6 +13,7 @@
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <pubkey.h> #include <pubkey.h>
#include <stdexcept> #include <stdexcept>
#include <test/util/random.h>
#include <util/chaintype.h> // IWYU pragma: export #include <util/chaintype.h> // IWYU pragma: export
#include <util/check.h> #include <util/check.h>
#include <util/fs.h> #include <util/fs.h>
@ -65,6 +66,14 @@ struct BasicTestingSetup {
util::SignalInterrupt m_interrupt; util::SignalInterrupt m_interrupt;
node::NodeContext m_node; // keep as first member to be destructed last 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 = {}); explicit BasicTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {});
~BasicTestingSetup(); ~BasicTestingSetup();

View file

@ -448,7 +448,7 @@ BOOST_AUTO_TEST_CASE(util_seed_insecure_rand)
for (int i = 0; i < 10000; i++) { for (int i = 0; i < 10000; i++) {
uint32_t rval; uint32_t rval;
do{ do{
rval=InsecureRand32()&mask; rval=m_rng.rand32()&mask;
}while(rval>=(uint32_t)mod); }while(rval>=(uint32_t)mod);
count += rval==0; count += rval==0;
} }

View file

@ -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 // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // 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; if (height <= 0 || blocks.size() >= max_size) return;
bool gen_invalid = InsecureRandRange(100) < invalid_rate; bool gen_invalid = m_rng.randrange(100U) < invalid_rate;
bool gen_fork = InsecureRandRange(100) < branch_rate; bool gen_fork = m_rng.randrange(100U) < branch_rate;
const std::shared_ptr<const CBlock> pblock = gen_invalid ? BadBlock(root) : GoodBlock(root); const std::shared_ptr<const CBlock> pblock = gen_invalid ? BadBlock(root) : GoodBlock(root);
blocks.push_back(pblock); blocks.push_back(pblock);

View file

@ -36,11 +36,11 @@ BOOST_AUTO_TEST_CASE(validation_chainstate_resize_caches)
// Add a coin to the in-memory cache, upsize once, then downsize. // Add a coin to the in-memory cache, upsize once, then downsize.
{ {
LOCK(::cs_main); 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 // Set a meaningless bestblock value in the coinsview cache - otherwise we won't
// flush during ResizecoinsCaches() and will subsequently hit an assertion. // 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)); BOOST_CHECK(c1.CoinsTip().HaveCoinInCache(outpoint));

View file

@ -718,10 +718,10 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_completion_hash_mismatch, Sna
CCoinsViewCache& ibd_coins = WITH_LOCK(::cs_main, CCoinsViewCache& ibd_coins = WITH_LOCK(::cs_main,
return validation_chainstate.CoinsTip()); return validation_chainstate.CoinsTip());
Coin badcoin; Coin badcoin;
badcoin.out.nValue = InsecureRand32(); badcoin.out.nValue = m_rng.rand32();
badcoin.nHeight = 1; badcoin.nHeight = 1;
badcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); badcoin.out.scriptPubKey.assign(m_rng.randbits(6), 0);
Txid txid = Txid::FromUint256(InsecureRand256()); Txid txid = Txid::FromUint256(m_rng.rand256());
ibd_coins.AddCoin(COutPoint(txid, 0), std::move(badcoin), false); ibd_coins.AddCoin(COutPoint(txid, 0), std::move(badcoin), false);
fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot"; fs::path snapshot_chainstate_dir = gArgs.GetDataDirNet() / "chainstate_snapshot";

View file

@ -50,7 +50,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
// Add a bunch of coins to see that we at least flip over to CRITICAL. // Add a bunch of coins to see that we at least flip over to CRITICAL.
for (int i{0}; i < 1000; ++i) { 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); BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE);
} }
@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
CoinsCacheSizeState::OK); CoinsCacheSizeState::OK);
for (int i{0}; i < COINS_UNTIL_CRITICAL; ++i) { 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); print_view_mem_usage(view);
BOOST_CHECK_EQUAL(view.AccessCoin(res).DynamicMemoryUsage(), COIN_SIZE); 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. // Adding some additional coins will push us over the edge to CRITICAL.
for (int i{0}; i < 4; ++i) { for (int i{0}; i < 4; ++i) {
AddTestCoin(view); AddTestCoin(m_rng, view);
print_view_mem_usage(view); print_view_mem_usage(view);
if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0) == if (chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/0) ==
CoinsCacheSizeState::CRITICAL) { CoinsCacheSizeState::CRITICAL) {
@ -108,7 +108,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
CoinsCacheSizeState::OK); CoinsCacheSizeState::OK);
for (int i{0}; i < 3; ++i) { for (int i{0}; i < 3; ++i) {
AddTestCoin(view); AddTestCoin(m_rng, view);
print_view_mem_usage(view); print_view_mem_usage(view);
BOOST_CHECK_EQUAL( BOOST_CHECK_EQUAL(
chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, /*max_mempool_size_bytes=*/ 1 << 19), 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% // Adding another coin with the additional mempool room will put us >90%
// but not yet critical. // but not yet critical.
AddTestCoin(view); AddTestCoin(m_rng, view);
print_view_mem_usage(view); print_view_mem_usage(view);
// Only perform these checks on 64 bit hosts; I haven't done the math for 32. // 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. // Using the default max_* values permits way more coins to be added.
for (int i{0}; i < 1000; ++i) { for (int i{0}; i < 1000; ++i) {
AddTestCoin(view); AddTestCoin(m_rng, view);
BOOST_CHECK_EQUAL( BOOST_CHECK_EQUAL(
chainstate.GetCoinsCacheSizeState(), chainstate.GetCoinsCacheSizeState(),
CoinsCacheSizeState::OK); CoinsCacheSizeState::OK);
@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0), chainstate.GetCoinsCacheSizeState(MAX_COINS_CACHE_BYTES, 0),
CoinsCacheSizeState::CRITICAL); CoinsCacheSizeState::CRITICAL);
view.SetBestBlock(InsecureRand256()); view.SetBestBlock(m_rng.rand256());
BOOST_CHECK(view.Flush()); BOOST_CHECK(view.Flush());
print_view_mem_usage(view); print_view_mem_usage(view);

View file

@ -67,6 +67,7 @@ public:
class VersionBitsTester class VersionBitsTester
{ {
FastRandomContext& m_rng;
// A fake blockchain // A fake blockchain
std::vector<CBlockIndex*> vpblock; std::vector<CBlockIndex*> vpblock;
@ -85,6 +86,8 @@ class VersionBitsTester
int num{1000}; int num{1000};
public: public:
VersionBitsTester(FastRandomContext& rng) : m_rng{rng} {}
VersionBitsTester& Reset() { VersionBitsTester& Reset() {
// Have each group of tests be counted by the 1000s part, starting at 1000 // Have each group of tests be counted by the 1000s part, starting at 1000
num = num - (num % 1000) + 1000; num = num - (num % 1000) + 1000;
@ -128,7 +131,7 @@ public:
{ {
const CBlockIndex* tip = Tip(); const CBlockIndex* tip = Tip();
for (int i = 0; i < CHECKERS; i++) { 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[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_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)); 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(); const CBlockIndex* pindex = Tip();
for (int i = 0; i < CHECKERS; i++) { 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 = checker[i].GetStateFor(pindex);
ThresholdState got_delayed = checker_delayed[i].GetStateFor(pindex); ThresholdState got_delayed = checker_delayed[i].GetStateFor(pindex);
ThresholdState got_always = checker_always[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++) { for (int i = 0; i < 64; i++) {
// DEFINED -> STARTED after timeout reached -> FAILED // 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(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0)
.Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0) .Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0)
.Mine(989, TestTime(989), 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 */ /** 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 // Clear the cache every time
versionbitscache.Clear(); 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 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 // In the second chain, test the bit is set by CBV while STARTED and
// LOCKED-IN, and then no longer set while ACTIVE. // LOCKED-IN, and then no longer set while ACTIVE.
VersionBitsTester firstChain, secondChain; VersionBitsTester firstChain{m_rng}, secondChain{m_rng};
int64_t nTime = nStartTime; int64_t nTime = nStartTime;
@ -412,8 +416,9 @@ static void check_computeblockversion(VersionBitsCache& versionbitscache, const
// Check that we don't signal after activation // Check that we don't signal after activation
BOOST_CHECK_EQUAL(versionbitscache.ComputeBlockVersion(lastBlock, params) & (1 << bit), 0); 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; VersionBitsCache vbcache;

View file

@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(passphrase) {
std::string hash(GetRandHash().ToString()); std::string hash(GetRandHash().ToString());
std::vector<unsigned char> vchSalt(8); std::vector<unsigned char> vchSalt(8);
GetRandBytes(vchSalt); GetRandBytes(vchSalt);
uint32_t rounds = InsecureRand32(); uint32_t rounds = m_rng.rand32();
if (rounds > 30000) if (rounds > 30000)
rounds = 30000; rounds = 30000;
TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds); TestCrypter::TestPassphrase(vchSalt, SecureString(hash.begin(), hash.end()), rounds);

View file

@ -980,7 +980,7 @@ BOOST_FIXTURE_TEST_CASE(wallet_sync_tx_invalid_state_test, TestingSetup)
CMutableTransaction mtx; CMutableTransaction mtx;
mtx.vout.emplace_back(COIN, GetScriptForDestination(op_dest)); 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(); const auto& tx_id_to_spend = wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInMempool{})->GetHash();
{ {