Skip to content

Commit cfb0dfe

Browse files
committed
random: convert GetExponentialRand into rand_exp_duration
1 parent 4eaa239 commit cfb0dfe

File tree

4 files changed

+33
-25
lines changed

4 files changed

+33
-25
lines changed

src/net.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2481,9 +2481,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
24812481
auto start = GetTime<std::chrono::microseconds>();
24822482

24832483
// Minimum time before next feeler connection (in microseconds).
2484-
auto next_feeler = GetExponentialRand(start, FEELER_INTERVAL);
2485-
auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
2486-
auto next_extra_network_peer{GetExponentialRand(start, EXTRA_NETWORK_PEER_INTERVAL)};
2484+
auto next_feeler = start + FastRandomContext().rand_exp_duration(FEELER_INTERVAL);
2485+
auto next_extra_block_relay = start + FastRandomContext().rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
2486+
auto next_extra_network_peer{start + FastRandomContext().rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL)};
24872487
const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
24882488
bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
24892489
const bool use_seednodes{gArgs.IsArgSet("-seednode")};
@@ -2642,10 +2642,10 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
26422642
// Because we can promote these connections to block-relay-only
26432643
// connections, they do not get their own ConnectionType enum
26442644
// (similar to how we deal with extra outbound peers).
2645-
next_extra_block_relay = GetExponentialRand(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
2645+
next_extra_block_relay = now + FastRandomContext().rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
26462646
conn_type = ConnectionType::BLOCK_RELAY;
26472647
} else if (now > next_feeler) {
2648-
next_feeler = GetExponentialRand(now, FEELER_INTERVAL);
2648+
next_feeler = now + FastRandomContext().rand_exp_duration(FEELER_INTERVAL);
26492649
conn_type = ConnectionType::FEELER;
26502650
fFeeler = true;
26512651
} else if (nOutboundFullRelay == m_max_outbound_full_relay &&
@@ -2658,7 +2658,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
26582658
// This is not attempted if the user changed -maxconnections to a value
26592659
// so low that less than MAX_OUTBOUND_FULL_RELAY_CONNECTIONS are made,
26602660
// to prevent interactions with otherwise protected outbound peers.
2661-
next_extra_network_peer = GetExponentialRand(now, EXTRA_NETWORK_PEER_INTERVAL);
2661+
next_extra_network_peer = now + FastRandomContext().rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL);
26622662
} else {
26632663
// skip to next iteration of while loop
26642664
continue;

src/net_processing.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::micros
12441244
// If this function were called from multiple threads simultaneously
12451245
// it would possible that both update the next send variable, and return a different result to their caller.
12461246
// This is not possible in practice as only the net processing thread invokes this function.
1247-
m_next_inv_to_inbounds = GetExponentialRand(now, average_interval);
1247+
m_next_inv_to_inbounds = now + FastRandomContext().rand_exp_duration(average_interval);
12481248
}
12491249
return m_next_inv_to_inbounds;
12501250
}
@@ -5654,13 +5654,13 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
56545654
CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()};
56555655
PushAddress(peer, local_addr);
56565656
}
5657-
peer.m_next_local_addr_send = GetExponentialRand(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
5657+
peer.m_next_local_addr_send = current_time + FastRandomContext().rand_exp_duration(AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
56585658
}
56595659

56605660
// We sent an `addr` message to this peer recently. Nothing more to do.
56615661
if (current_time <= peer.m_next_addr_send) return;
56625662

5663-
peer.m_next_addr_send = GetExponentialRand(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
5663+
peer.m_next_addr_send = current_time + FastRandomContext().rand_exp_duration(AVG_ADDRESS_BROADCAST_INTERVAL);
56645664

56655665
if (!Assume(peer.m_addrs_to_send.size() <= MAX_ADDR_TO_SEND)) {
56665666
// Should be impossible since we always check size before adding to
@@ -5747,7 +5747,7 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, Peer& peer, std::chrono::mi
57475747
MakeAndPushMessage(pto, NetMsgType::FEEFILTER, filterToSend);
57485748
peer.m_fee_filter_sent = filterToSend;
57495749
}
5750-
peer.m_next_send_feefilter = GetExponentialRand(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL);
5750+
peer.m_next_send_feefilter = current_time + FastRandomContext().rand_exp_duration(AVG_FEEFILTER_BROADCAST_INTERVAL);
57515751
}
57525752
// If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
57535753
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
@@ -6059,7 +6059,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
60596059
if (pto->IsInboundConn()) {
60606060
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
60616061
} else {
6062-
tx_relay->m_next_inv_send_time = GetExponentialRand(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
6062+
tx_relay->m_next_inv_send_time = current_time + FastRandomContext().rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
60636063
}
60646064
}
60656065

src/random.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -773,8 +773,7 @@ void RandomInit()
773773
ReportHardwareRand();
774774
}
775775

776-
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
776+
double MakeExponentiallyDistributed(uint64_t uniform) noexcept
777777
{
778-
double unscaled = -std::log1p(FastRandomContext().randbits<48>() * -0.0000000000000035527136788 /* -1/2^48 */);
779-
return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us);
778+
return -std::log1p((uniform >> 16) * -0.0000000000000035527136788 /* -1/2^48 */);
780779
}

src/random.h

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,17 +81,6 @@
8181
*/
8282
void GetRandBytes(Span<unsigned char> bytes) noexcept;
8383

84-
/**
85-
* Return a timestamp in the future sampled from an exponential distribution
86-
* (https://en.wikipedia.org/wiki/Exponential_distribution). This distribution
87-
* is memoryless and should be used for repeated network events (e.g. sending a
88-
* certain type of message) to minimize leaking information to observers.
89-
*
90-
* The probability of an event occurring before time x is 1 - e^-(x/a) where a
91-
* is the average interval between events.
92-
* */
93-
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval);
94-
9584
uint256 GetRandHash() noexcept;
9685

9786
/**
@@ -139,6 +128,9 @@ concept StdChronoDuration = requires {
139128
std::type_identity<T>());
140129
};
141130

131+
/** Given a uniformly random uint64_t, return an exponentially distributed double with mean 1. */
132+
double MakeExponentiallyDistributed(uint64_t uniform) noexcept;
133+
142134
/** Mixin class that provides helper randomness functions.
143135
*
144136
* Intended to be used through CRTP: https://en.cppreference.com/w/cpp/language/crtp.
@@ -327,6 +319,23 @@ class RandomMixin
327319
return Dur{Impl().randrange(range.count())};
328320
}
329321

322+
/**
323+
* Return a duration sampled from an exponential distribution
324+
* (https://en.wikipedia.org/wiki/Exponential_distribution). Successive events
325+
* whose intervals are distributed according to this form a memoryless Poisson
326+
* process. This should be used for repeated network events (e.g. sending a
327+
* certain type of message) to minimize leaking information to observers.
328+
*
329+
* The probability of an event occurring before time x is 1 - e^-(x/a) where a
330+
* is the average interval between events.
331+
* */
332+
std::chrono::microseconds rand_exp_duration(std::chrono::microseconds mean) noexcept
333+
{
334+
using namespace std::chrono_literals;
335+
auto unscaled = MakeExponentiallyDistributed(Impl().rand64());
336+
return std::chrono::duration_cast<std::chrono::microseconds>(unscaled * mean + 0.5us);
337+
}
338+
330339
// Compatibility with the UniformRandomBitGenerator concept
331340
typedef uint64_t result_type;
332341
static constexpr uint64_t min() noexcept { return 0; }

0 commit comments

Comments
 (0)