From 3a669676ec6595f395094ed9f1f06550485fed7d Mon Sep 17 00:00:00 2001 From: fanquake Date: Tue, 26 Jul 2022 15:02:13 +0100 Subject: [PATCH] Merge bitcoin/bitcoin#24974: refactor: Make FEELER_SLEEP_WINDOW type safe (std::chrono) fa74e726c414f5f7a1e63126a69463491f66e0ec refactor: Make FEELER_SLEEP_WINDOW type safe (std::chrono) (MacroFake) fa3b3cb9b5d944d34b1d5ac3e102ac333482a475 Expose underlying clock in CThreadInterrupt (MacroFake) Pull request description: This gets rid of the `value*1000` manual conversion. ACKs for top commit: naumenkogs: utACK fa74e726c414f5f7a1e63126a69463491f66e0ec dergoegge: Code review ACK fa74e726c414f5f7a1e63126a69463491f66e0ec Tree-SHA512: 90409c05c25f0dd2f1c4dead78f707ebfd78b7d84ea4db9fcefd9c4958a1a3338ac657cd9e99eb8b47d52d4485fa3c947dce4ee1559fb56ae65878685e1ed9a3 --- src/net.cpp | 10 +++++----- src/random.h | 17 ++++++++++++----- src/test/random_tests.cpp | 10 ++++++++++ src/threadinterrupt.cpp | 12 +----------- src/threadinterrupt.h | 5 ++--- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index dd31caddd3..0c505eee99 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -93,8 +93,8 @@ static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" pe /** The default timeframe for -maxuploadtarget. 1 day. */ static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24}; -// We add a random period time (0 to 1 seconds) to feeler connections to prevent synchronization. -#define FEELER_SLEEP_WINDOW 1 +// A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization. +static constexpr auto FEELER_SLEEP_WINDOW{1s}; /** Used to pass flags to the Bind() function */ enum BindFlags { @@ -2219,6 +2219,7 @@ int CConnman::GetExtraOutboundCount() void CConnman::ThreadOpenConnections(const std::vector connect) { + FastRandomContext rng; // Connect to specific addresses if (!connect.empty()) { @@ -2409,12 +2410,11 @@ void CConnman::ThreadOpenConnections(const std::vector connect) } if (addrConnect.IsValid()) { - if (fFeeler) { // Add small amount of random noise before connection to avoid synchronization. - int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000); - if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep))) + if (!interruptNet.sleep_for(rng.rand_uniform_duration(FEELER_SLEEP_WINDOW))) { return; + } if (fLogIPs) { LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString()); } else { diff --git a/src/random.h b/src/random.h index d5455bcffd..8bbf1d4d0c 100644 --- a/src/random.h +++ b/src/random.h @@ -10,6 +10,7 @@ #include #include +#include #include // For std::chrono::microseconds #include #include @@ -213,13 +214,19 @@ public: template Tp rand_uniform_delay(const Tp& time, typename Tp::duration range) { - using Dur = typename Tp::duration; - Dur dur{range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} : - range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} : - /* interval [0..0] */ Dur{0}}; - return time + dur; + return time + rand_uniform_duration(range); } + /** Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive). */ + template + typename Chrono::duration rand_uniform_duration(typename Chrono::duration range) noexcept + { + using Dur = typename Chrono::duration; + return range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} : + range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} : + /* interval [0..0] */ Dur{0}; + }; + // Compatibility with the C++11 UniformRandomBitGenerator concept typedef uint64_t result_type; static constexpr uint64_t min() { return 0; } diff --git a/src/test/random_tests.cpp b/src/test/random_tests.cpp index 4113521aee..d8cc0a564c 100644 --- a/src/test/random_tests.cpp +++ b/src/test/random_tests.cpp @@ -50,6 +50,16 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests) BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3)); BOOST_CHECK(ctx1.rand256() == ctx2.rand256()); BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50)); + { + struct MicroClock { + using duration = std::chrono::microseconds; + }; + FastRandomContext ctx{true}; + // Check with clock type + BOOST_CHECK_EQUAL(47222, ctx.rand_uniform_duration(1s).count()); + // Check with time-point type + BOOST_CHECK_EQUAL(2782, ctx.rand_uniform_duration(9h).count()); + } // Check that a nondeterministic ones are not g_mock_deterministic_tests = false; diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp index 9a449b84cd..9f755054f6 100644 --- a/src/threadinterrupt.cpp +++ b/src/threadinterrupt.cpp @@ -27,18 +27,8 @@ void CThreadInterrupt::operator()() cond.notify_all(); } -bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time) +bool CThreadInterrupt::sleep_for(Clock::duration rel_time) { WAIT_LOCK(mut, lock); return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); }); } - -bool CThreadInterrupt::sleep_for(std::chrono::seconds rel_time) -{ - return sleep_for(std::chrono::duration_cast(rel_time)); -} - -bool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time) -{ - return sleep_for(std::chrono::duration_cast(rel_time)); -} diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h index 783780e73d..11d89b98a8 100644 --- a/src/threadinterrupt.h +++ b/src/threadinterrupt.h @@ -19,13 +19,12 @@ class CThreadInterrupt { public: + using Clock = std::chrono::steady_clock; CThreadInterrupt(); explicit operator bool() const; void operator()(); void reset(); - bool sleep_for(std::chrono::milliseconds rel_time); - bool sleep_for(std::chrono::seconds rel_time); - bool sleep_for(std::chrono::minutes rel_time); + bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut); private: std::condition_variable cond;