random.cpp raw

   1  // Copyright (c) 2023-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <test/util/random.h>
   6  
   7  #include <random.h>
   8  #include <uint256.h>
   9  #include <util/check.h>
  10  #include <util/log.h>
  11  
  12  #include <cstdlib>
  13  #include <iostream>
  14  
  15  std::atomic<bool> g_seeded_g_prng_zero{false};
  16  
  17  extern void MakeRandDeterministicDANGEROUS(const uint256& seed) noexcept;
  18  
  19  void SeedRandomStateForTest(SeedRand seedtype)
  20  {
  21      constexpr auto RANDOM_CTX_SEED{"RANDOM_CTX_SEED"};
  22  
  23      // Do this once, on the first call, regardless of seedtype, because once
  24      // MakeRandDeterministicDANGEROUS is called, the output of GetRandHash is
  25      // no longer truly random. It should be enough to get the seed once for the
  26      // process.
  27      static const auto g_ctx_seed = []() -> std::optional<uint256> {
  28          if (EnableFuzzDeterminism()) return {};
  29          // If RANDOM_CTX_SEED is set, use that as seed.
  30          if (const char* num{std::getenv(RANDOM_CTX_SEED)}) {
  31              if (auto num_parsed{uint256::FromUserHex(num)}) {
  32                  return *num_parsed;
  33              } else {
  34                  std::cerr << RANDOM_CTX_SEED << " must consist of up to " << uint256::size() * 2 << " hex digits (\"0x\" prefix allowed), it was set to: '" << num << "'.\n";
  35                  std::abort();
  36              }
  37          }
  38          // Otherwise use a (truly) random value.
  39          return GetRandHash();
  40      }();
  41  
  42      g_seeded_g_prng_zero = seedtype == SeedRand::ZEROS;
  43      if (EnableFuzzDeterminism()) {
  44          Assert(g_seeded_g_prng_zero); // Only SeedRandomStateForTest(SeedRand::ZEROS) is allowed in fuzz tests
  45          Assert(!g_used_g_prng);       // The global PRNG must not have been used before SeedRandomStateForTest(SeedRand::ZEROS)
  46      }
  47      const uint256& seed{seedtype == SeedRand::FIXED_SEED ? g_ctx_seed.value() : uint256::ZERO};
  48      LogInfo("Setting random seed for current tests to %s=%s\n", RANDOM_CTX_SEED, seed.GetHex());
  49      MakeRandDeterministicDANGEROUS(seed);
  50  }
  51