Fix: Allow block count > UINT32_MAX (#3979)

The method `ledger::hash_root_random()` required the block count to
fit into a uint32_t. This limit is too small to be future-proof. This
commit increases the limit to UINT64_MAX, so that it matches the other
places where block count is a uint64_t.
This commit is contained in:
Gustav Schauwecker 2022-10-27 13:27:54 +02:00 committed by GitHub
commit 18308657b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 2 deletions

View file

@ -600,3 +600,29 @@ TEST (random_pool, multithreading)
i.join ();
}
}
// Test that random 64bit numbers are within the given range
TEST (random_pool, generate_word64)
{
int occurrences[10] = { 0 };
for (auto i = 0; i < 1000; ++i)
{
auto random = nano::random_pool::generate_word64 (1, 9);
ASSERT_TRUE (random >= 1 && random <= 9);
occurrences[random] += 1;
}
for (auto i = 1; i < 10; ++i)
{
ASSERT_TRUE (occurrences[i] > 0);
}
}
// Test random numbers > uint32 max
TEST (random_pool, generate_word64_big_number)
{
uint64_t min = static_cast<uint64_t> (std::numeric_limits<uint32_t>::max ()) + 1;
uint64_t max = std::numeric_limits<uint64_t>::max ();
auto big_random = nano::random_pool::generate_word64 (min, max);
ASSERT_TRUE (big_random >= min);
}

View file

@ -1,5 +1,6 @@
#include <nano/crypto_lib/random_pool.hpp>
#include <crypto/cryptopp/misc.h>
#include <crypto/cryptopp/osrng.h>
void nano::random_pool::generate_block (unsigned char * output, size_t size)
@ -14,6 +15,24 @@ unsigned nano::random_pool::generate_word32 (unsigned min, unsigned max)
return pool.GenerateWord32 (min, max);
}
uint64_t nano::random_pool::generate_word64 (uint64_t min, uint64_t max)
{
auto & pool = get_pool ();
const auto range = max - min;
const auto max_bits = CryptoPP::BitPrecision (range);
uint64_t value;
do
{
pool.GenerateBlock ((unsigned char *)&value, sizeof (value));
value = CryptoPP::Crop (value, max_bits);
} while (value > range);
return value + min;
}
unsigned char nano::random_pool::generate_byte ()
{
auto & pool = get_pool ();

View file

@ -15,6 +15,8 @@ class random_pool
public:
static void generate_block (unsigned char * output, size_t size);
static unsigned generate_word32 (unsigned min, unsigned max);
/** Generates a random uint64_t in the range min to max. min and max are inclusive. */
static uint64_t generate_word64 (uint64_t min, uint64_t max);
static unsigned char generate_byte ();
random_pool () = delete;

View file

@ -1004,8 +1004,7 @@ std::pair<nano::block_hash, nano::block_hash> nano::ledger::hash_root_random (na
else
{
uint64_t count (cache.block_count);
release_assert (std::numeric_limits<CryptoPP::word32>::max () > count);
auto region = static_cast<size_t> (nano::random_pool::generate_word32 (0, static_cast<CryptoPP::word32> (count - 1)));
auto region = nano::random_pool::generate_word64 (0, count - 1);
// Pruned cache cannot guarantee that pruned blocks are already commited
if (region < cache.pruned_count)
{