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
This commit is contained in:
fanquake 2022-07-26 15:02:13 +01:00 committed by PastaPastaPasta
parent 6d534eebbc
commit 3a669676ec
5 changed files with 30 additions and 24 deletions

View File

@ -93,8 +93,8 @@ static constexpr int DNSSEEDS_DELAY_PEER_THRESHOLD = 1000; // "many" vs "few" pe
/** The default timeframe for -maxuploadtarget. 1 day. */ /** The default timeframe for -maxuploadtarget. 1 day. */
static constexpr std::chrono::seconds MAX_UPLOAD_TIMEFRAME{60 * 60 * 24}; 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. // A random time period (0 to 1 seconds) is added to feeler connections to prevent synchronization.
#define FEELER_SLEEP_WINDOW 1 static constexpr auto FEELER_SLEEP_WINDOW{1s};
/** Used to pass flags to the Bind() function */ /** Used to pass flags to the Bind() function */
enum BindFlags { enum BindFlags {
@ -2219,6 +2219,7 @@ int CConnman::GetExtraOutboundCount()
void CConnman::ThreadOpenConnections(const std::vector<std::string> connect) void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{ {
FastRandomContext rng;
// Connect to specific addresses // Connect to specific addresses
if (!connect.empty()) if (!connect.empty())
{ {
@ -2409,12 +2410,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
} }
if (addrConnect.IsValid()) { if (addrConnect.IsValid()) {
if (fFeeler) { if (fFeeler) {
// Add small amount of random noise before connection to avoid synchronization. // Add small amount of random noise before connection to avoid synchronization.
int randsleep = GetRandInt(FEELER_SLEEP_WINDOW * 1000); if (!interruptNet.sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {
if (!interruptNet.sleep_for(std::chrono::milliseconds(randsleep)))
return; return;
}
if (fLogIPs) { if (fLogIPs) {
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString()); LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
} else { } else {

View File

@ -10,6 +10,7 @@
#include <crypto/common.h> #include <crypto/common.h>
#include <uint256.h> #include <uint256.h>
#include <cassert>
#include <chrono> // For std::chrono::microseconds #include <chrono> // For std::chrono::microseconds
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
@ -213,13 +214,19 @@ public:
template <typename Tp> template <typename Tp>
Tp rand_uniform_delay(const Tp& time, typename Tp::duration range) Tp rand_uniform_delay(const Tp& time, typename Tp::duration range)
{ {
using Dur = typename Tp::duration; return time + rand_uniform_duration<Tp>(range);
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;
} }
/** Generate a uniform random duration in the range from 0 (inclusive) to range (exclusive). */
template <typename Chrono>
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 // Compatibility with the C++11 UniformRandomBitGenerator concept
typedef uint64_t result_type; typedef uint64_t result_type;
static constexpr uint64_t min() { return 0; } static constexpr uint64_t min() { return 0; }

View File

@ -50,6 +50,16 @@ BOOST_AUTO_TEST_CASE(fastrandom_tests)
BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3)); BOOST_CHECK_EQUAL(ctx1.randbits(3), ctx2.randbits(3));
BOOST_CHECK(ctx1.rand256() == ctx2.rand256()); BOOST_CHECK(ctx1.rand256() == ctx2.rand256());
BOOST_CHECK(ctx1.randbytes(50) == ctx2.randbytes(50)); 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<MicroClock>(1s).count());
// Check with time-point type
BOOST_CHECK_EQUAL(2782, ctx.rand_uniform_duration<SteadySeconds>(9h).count());
}
// Check that a nondeterministic ones are not // Check that a nondeterministic ones are not
g_mock_deterministic_tests = false; g_mock_deterministic_tests = false;

View File

@ -27,18 +27,8 @@ void CThreadInterrupt::operator()()
cond.notify_all(); cond.notify_all();
} }
bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time) bool CThreadInterrupt::sleep_for(Clock::duration rel_time)
{ {
WAIT_LOCK(mut, lock); WAIT_LOCK(mut, lock);
return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); }); 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<std::chrono::milliseconds>(rel_time));
}
bool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time)
{
return sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(rel_time));
}

View File

@ -19,13 +19,12 @@
class CThreadInterrupt class CThreadInterrupt
{ {
public: public:
using Clock = std::chrono::steady_clock;
CThreadInterrupt(); CThreadInterrupt();
explicit operator bool() const; explicit operator bool() const;
void operator()(); void operator()();
void reset(); void reset();
bool sleep_for(std::chrono::milliseconds rel_time); bool sleep_for(Clock::duration rel_time) EXCLUSIVE_LOCKS_REQUIRED(!mut);
bool sleep_for(std::chrono::seconds rel_time);
bool sleep_for(std::chrono::minutes rel_time);
private: private:
std::condition_variable cond; std::condition_variable cond;