diff --git a/src/net.cpp b/src/net.cpp index ac665400228..9e969718b7d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -3475,7 +3475,8 @@ std::vector CConnman::GetAddresses(CNode& requestor, size_t max_addres // nodes to be "terrible" (see IsTerrible()) if the timestamps are older than 30 days, // max. 24 hours of "penalty" due to cache shouldn't make any meaningful difference // in terms of the freshness of the response. - cache_entry.m_cache_entry_expiration = current_time + std::chrono::hours(21) + GetRandMicros(std::chrono::hours(6)); + cache_entry.m_cache_entry_expiration = current_time + + 21h + FastRandomContext().randrange(6h); } return cache_entry.m_addrs_response_cache; } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index d674811ba73..ce3ff71df15 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1698,7 +1698,7 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) // Schedule next run for 10-15 minutes in the future. // We add randomness on every cycle to avoid the possibility of P2P fingerprinting. - const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); + const auto delta = 10min + FastRandomContext().randrange(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } @@ -2050,7 +2050,7 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler) scheduler.scheduleEvery([this] { this->CheckForStaleTipAndEvictPeers(); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL}); // schedule next run for 10-15 minutes in the future - const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); + const auto delta = 10min + FastRandomContext().randrange(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } @@ -5753,7 +5753,7 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::mi // until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. else if (current_time + MAX_FEEFILTER_CHANGE_DELAY < peer.m_next_send_feefilter && (currentFilter < 3 * peer.m_fee_filter_sent / 4 || currentFilter > 4 * peer.m_fee_filter_sent / 3)) { - peer.m_next_send_feefilter = current_time + GetRandomDuration(MAX_FEEFILTER_CHANGE_DELAY); + peer.m_next_send_feefilter = current_time + FastRandomContext().randrange(MAX_FEEFILTER_CHANGE_DELAY); } } diff --git a/src/random.h b/src/random.h index 1573e49ef7b..b9cba1d6029 100644 --- a/src/random.h +++ b/src/random.h @@ -132,6 +132,13 @@ concept RandomNumberGenerator = requires(T& rng, Span s) { requires std::derived_from, RandomMixin>>; }; +/** A concept for C++ std::chrono durations. */ +template +concept StdChronoDuration = requires { + [](std::type_identity>){}( + std::type_identity()); +}; + /** Mixin class that provides helper randomness functions. * * Intended to be used through CRTP: https://en.cppreference.com/w/cpp/language/crtp. @@ -300,7 +307,7 @@ public: } /** Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive). */ - template + template requires StdChronoDuration typename Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept { using Dur = typename Chrono::duration; @@ -309,6 +316,17 @@ public: /* interval [0..0] */ Dur{0}; }; + /** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */ + template + Dur randrange(typename std::common_type_t range) noexcept + // Having the compiler infer the template argument from the function argument + // is dangerous, because the desired return value generally has a different + // type than the function argument. So std::common_type is used to force the + // call site to specify the type of the return value. + { + return Dur{Impl().randrange(range.count())}; + } + // Compatibility with the UniformRandomBitGenerator concept typedef uint64_t result_type; static constexpr uint64_t min() noexcept { return 0; } @@ -426,19 +444,6 @@ void Shuffle(I first, I last, R&& rng) } } -/** Generate a uniform random duration in the range [0..max). Precondition: max.count() > 0 */ -template -D GetRandomDuration(typename std::common_type::type max) noexcept -// Having the compiler infer the template argument from the function argument -// is dangerous, because the desired return value generally has a different -// type than the function argument. So std::common_type is used to force the -// call site to specify the type of the return value. -{ - return D{FastRandomContext().randrange(max.count())}; -}; -constexpr auto GetRandMicros = GetRandomDuration; -constexpr auto GetRandMillis = GetRandomDuration; - /* Number of random bytes returned by GetOSRand. * When changing this constant make sure to change all call sites, and make * sure that the underlying OS APIs for all platforms support the number. diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 6932e186d56..b7479d310cc 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -30,18 +30,18 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests_deterministic) { BOOST_CHECK_EQUAL(FastRandomContext().rand(), uint64_t{9330418229102544152u}); BOOST_CHECK_EQUAL(FastRandomContext().rand(), int{618925161}); - BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 1271170921); - BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2803534); + BOOST_CHECK_EQUAL(FastRandomContext().randrange(1h).count(), 1271170921); + BOOST_CHECK_EQUAL(FastRandomContext().randrange(1h).count(), 2803534); BOOST_CHECK_EQUAL(FastRandomContext().rand(), uint64_t{10170981140880778086u}); BOOST_CHECK_EQUAL(FastRandomContext().rand(), int{1689082725}); - BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 2464643716); - BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 2312205); + BOOST_CHECK_EQUAL(FastRandomContext().randrange(1h).count(), 2464643716); + BOOST_CHECK_EQUAL(FastRandomContext().randrange(1h).count(), 2312205); BOOST_CHECK_EQUAL(FastRandomContext().rand(), uint64_t{5689404004456455543u}); BOOST_CHECK_EQUAL(FastRandomContext().rand(), int{785839937}); - BOOST_CHECK_EQUAL(GetRandMicros(std::chrono::hours{1}).count(), 93558804); - BOOST_CHECK_EQUAL(GetRandMillis(std::chrono::hours{1}).count(), 507022); + BOOST_CHECK_EQUAL(FastRandomContext().randrange(1h).count(), 93558804); + BOOST_CHECK_EQUAL(FastRandomContext().randrange(1h).count(), 507022); } { @@ -84,18 +84,18 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests_nondeterministic) { BOOST_CHECK(FastRandomContext().rand() != uint64_t{9330418229102544152u}); BOOST_CHECK(FastRandomContext().rand() != int{618925161}); - BOOST_CHECK(GetRandMicros(std::chrono::hours{1}).count() != 1271170921); - BOOST_CHECK(GetRandMillis(std::chrono::hours{1}).count() != 2803534); + BOOST_CHECK(FastRandomContext().randrange(1h).count() != 1271170921); + BOOST_CHECK(FastRandomContext().randrange(1h).count() != 2803534); BOOST_CHECK(FastRandomContext().rand() != uint64_t{10170981140880778086u}); BOOST_CHECK(FastRandomContext().rand() != int{1689082725}); - BOOST_CHECK(GetRandMicros(std::chrono::hours{1}).count() != 2464643716); - BOOST_CHECK(GetRandMillis(std::chrono::hours{1}).count() != 2312205); + BOOST_CHECK(FastRandomContext().randrange(1h).count() != 2464643716); + BOOST_CHECK(FastRandomContext().randrange(1h).count() != 2312205); BOOST_CHECK(FastRandomContext().rand() != uint64_t{5689404004456455543u}); BOOST_CHECK(FastRandomContext().rand() != int{785839937}); - BOOST_CHECK(GetRandMicros(std::chrono::hours{1}).count() != 93558804); - BOOST_CHECK(GetRandMillis(std::chrono::hours{1}).count() != 507022); + BOOST_CHECK(FastRandomContext().randrange(1h).count() != 93558804); + BOOST_CHECK(FastRandomContext().randrange(1h).count() != 507022); } {