mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 23:09:44 -04:00
random: convert GetExponentialRand into rand_exp_duration
This commit is contained in:
parent
4eaa239dc3
commit
cfb0dfe2cf
4 changed files with 33 additions and 25 deletions
12
src/net.cpp
12
src/net.cpp
|
@ -2481,9 +2481,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||||
auto start = GetTime<std::chrono::microseconds>();
|
auto start = GetTime<std::chrono::microseconds>();
|
||||||
|
|
||||||
// Minimum time before next feeler connection (in microseconds).
|
// Minimum time before next feeler connection (in microseconds).
|
||||||
auto next_feeler = GetExponentialRand(start, FEELER_INTERVAL);
|
auto next_feeler = start + FastRandomContext().rand_exp_duration(FEELER_INTERVAL);
|
||||||
auto next_extra_block_relay = GetExponentialRand(start, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
|
auto next_extra_block_relay = start + FastRandomContext().rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
|
||||||
auto next_extra_network_peer{GetExponentialRand(start, EXTRA_NETWORK_PEER_INTERVAL)};
|
auto next_extra_network_peer{start + FastRandomContext().rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL)};
|
||||||
const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
|
const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);
|
||||||
bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
|
bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);
|
||||||
const bool use_seednodes{gArgs.IsArgSet("-seednode")};
|
const bool use_seednodes{gArgs.IsArgSet("-seednode")};
|
||||||
|
@ -2642,10 +2642,10 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||||
// Because we can promote these connections to block-relay-only
|
// Because we can promote these connections to block-relay-only
|
||||||
// connections, they do not get their own ConnectionType enum
|
// connections, they do not get their own ConnectionType enum
|
||||||
// (similar to how we deal with extra outbound peers).
|
// (similar to how we deal with extra outbound peers).
|
||||||
next_extra_block_relay = GetExponentialRand(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
|
next_extra_block_relay = now + FastRandomContext().rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
|
||||||
conn_type = ConnectionType::BLOCK_RELAY;
|
conn_type = ConnectionType::BLOCK_RELAY;
|
||||||
} else if (now > next_feeler) {
|
} else if (now > next_feeler) {
|
||||||
next_feeler = GetExponentialRand(now, FEELER_INTERVAL);
|
next_feeler = now + FastRandomContext().rand_exp_duration(FEELER_INTERVAL);
|
||||||
conn_type = ConnectionType::FEELER;
|
conn_type = ConnectionType::FEELER;
|
||||||
fFeeler = true;
|
fFeeler = true;
|
||||||
} else if (nOutboundFullRelay == m_max_outbound_full_relay &&
|
} else if (nOutboundFullRelay == m_max_outbound_full_relay &&
|
||||||
|
@ -2658,7 +2658,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
|
||||||
// This is not attempted if the user changed -maxconnections to a value
|
// This is not attempted if the user changed -maxconnections to a value
|
||||||
// so low that less than MAX_OUTBOUND_FULL_RELAY_CONNECTIONS are made,
|
// so low that less than MAX_OUTBOUND_FULL_RELAY_CONNECTIONS are made,
|
||||||
// to prevent interactions with otherwise protected outbound peers.
|
// to prevent interactions with otherwise protected outbound peers.
|
||||||
next_extra_network_peer = GetExponentialRand(now, EXTRA_NETWORK_PEER_INTERVAL);
|
next_extra_network_peer = now + FastRandomContext().rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL);
|
||||||
} else {
|
} else {
|
||||||
// skip to next iteration of while loop
|
// skip to next iteration of while loop
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -1244,7 +1244,7 @@ std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::micros
|
||||||
// If this function were called from multiple threads simultaneously
|
// If this function were called from multiple threads simultaneously
|
||||||
// it would possible that both update the next send variable, and return a different result to their caller.
|
// it would possible that both update the next send variable, and return a different result to their caller.
|
||||||
// This is not possible in practice as only the net processing thread invokes this function.
|
// This is not possible in practice as only the net processing thread invokes this function.
|
||||||
m_next_inv_to_inbounds = GetExponentialRand(now, average_interval);
|
m_next_inv_to_inbounds = now + FastRandomContext().rand_exp_duration(average_interval);
|
||||||
}
|
}
|
||||||
return m_next_inv_to_inbounds;
|
return m_next_inv_to_inbounds;
|
||||||
}
|
}
|
||||||
|
@ -5654,13 +5654,13 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
|
||||||
CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()};
|
CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()};
|
||||||
PushAddress(peer, local_addr);
|
PushAddress(peer, local_addr);
|
||||||
}
|
}
|
||||||
peer.m_next_local_addr_send = GetExponentialRand(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
|
peer.m_next_local_addr_send = current_time + FastRandomContext().rand_exp_duration(AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We sent an `addr` message to this peer recently. Nothing more to do.
|
// We sent an `addr` message to this peer recently. Nothing more to do.
|
||||||
if (current_time <= peer.m_next_addr_send) return;
|
if (current_time <= peer.m_next_addr_send) return;
|
||||||
|
|
||||||
peer.m_next_addr_send = GetExponentialRand(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
|
peer.m_next_addr_send = current_time + FastRandomContext().rand_exp_duration(AVG_ADDRESS_BROADCAST_INTERVAL);
|
||||||
|
|
||||||
if (!Assume(peer.m_addrs_to_send.size() <= MAX_ADDR_TO_SEND)) {
|
if (!Assume(peer.m_addrs_to_send.size() <= MAX_ADDR_TO_SEND)) {
|
||||||
// Should be impossible since we always check size before adding to
|
// 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
|
||||||
MakeAndPushMessage(pto, NetMsgType::FEEFILTER, filterToSend);
|
MakeAndPushMessage(pto, NetMsgType::FEEFILTER, filterToSend);
|
||||||
peer.m_fee_filter_sent = filterToSend;
|
peer.m_fee_filter_sent = filterToSend;
|
||||||
}
|
}
|
||||||
peer.m_next_send_feefilter = GetExponentialRand(current_time, AVG_FEEFILTER_BROADCAST_INTERVAL);
|
peer.m_next_send_feefilter = current_time + FastRandomContext().rand_exp_duration(AVG_FEEFILTER_BROADCAST_INTERVAL);
|
||||||
}
|
}
|
||||||
// If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
|
// If the fee filter has changed substantially and it's still more than MAX_FEEFILTER_CHANGE_DELAY
|
||||||
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
|
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
|
||||||
|
@ -6059,7 +6059,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
|
||||||
if (pto->IsInboundConn()) {
|
if (pto->IsInboundConn()) {
|
||||||
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
|
tx_relay->m_next_inv_send_time = NextInvToInbounds(current_time, INBOUND_INVENTORY_BROADCAST_INTERVAL);
|
||||||
} else {
|
} else {
|
||||||
tx_relay->m_next_inv_send_time = GetExponentialRand(current_time, OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
|
tx_relay->m_next_inv_send_time = current_time + FastRandomContext().rand_exp_duration(OUTBOUND_INVENTORY_BROADCAST_INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -773,8 +773,7 @@ void RandomInit()
|
||||||
ReportHardwareRand();
|
ReportHardwareRand();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval)
|
double MakeExponentiallyDistributed(uint64_t uniform) noexcept
|
||||||
{
|
{
|
||||||
double unscaled = -std::log1p(FastRandomContext().randbits<48>() * -0.0000000000000035527136788 /* -1/2^48 */);
|
return -std::log1p((uniform >> 16) * -0.0000000000000035527136788 /* -1/2^48 */);
|
||||||
return now + std::chrono::duration_cast<std::chrono::microseconds>(unscaled * average_interval + 0.5us);
|
|
||||||
}
|
}
|
||||||
|
|
31
src/random.h
31
src/random.h
|
@ -81,17 +81,6 @@
|
||||||
*/
|
*/
|
||||||
void GetRandBytes(Span<unsigned char> bytes) noexcept;
|
void GetRandBytes(Span<unsigned char> bytes) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a timestamp in the future sampled from an exponential distribution
|
|
||||||
* (https://en.wikipedia.org/wiki/Exponential_distribution). This distribution
|
|
||||||
* is memoryless and should be used for repeated network events (e.g. sending a
|
|
||||||
* certain type of message) to minimize leaking information to observers.
|
|
||||||
*
|
|
||||||
* The probability of an event occurring before time x is 1 - e^-(x/a) where a
|
|
||||||
* is the average interval between events.
|
|
||||||
* */
|
|
||||||
std::chrono::microseconds GetExponentialRand(std::chrono::microseconds now, std::chrono::seconds average_interval);
|
|
||||||
|
|
||||||
uint256 GetRandHash() noexcept;
|
uint256 GetRandHash() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,6 +128,9 @@ concept StdChronoDuration = requires {
|
||||||
std::type_identity<T>());
|
std::type_identity<T>());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Given a uniformly random uint64_t, return an exponentially distributed double with mean 1. */
|
||||||
|
double MakeExponentiallyDistributed(uint64_t uniform) noexcept;
|
||||||
|
|
||||||
/** Mixin class that provides helper randomness functions.
|
/** Mixin class that provides helper randomness functions.
|
||||||
*
|
*
|
||||||
* Intended to be used through CRTP: https://en.cppreference.com/w/cpp/language/crtp.
|
* Intended to be used through CRTP: https://en.cppreference.com/w/cpp/language/crtp.
|
||||||
|
@ -327,6 +319,23 @@ public:
|
||||||
return Dur{Impl().randrange(range.count())};
|
return Dur{Impl().randrange(range.count())};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a duration sampled from an exponential distribution
|
||||||
|
* (https://en.wikipedia.org/wiki/Exponential_distribution). Successive events
|
||||||
|
* whose intervals are distributed according to this form a memoryless Poisson
|
||||||
|
* process. This should be used for repeated network events (e.g. sending a
|
||||||
|
* certain type of message) to minimize leaking information to observers.
|
||||||
|
*
|
||||||
|
* The probability of an event occurring before time x is 1 - e^-(x/a) where a
|
||||||
|
* is the average interval between events.
|
||||||
|
* */
|
||||||
|
std::chrono::microseconds rand_exp_duration(std::chrono::microseconds mean) noexcept
|
||||||
|
{
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
auto unscaled = MakeExponentiallyDistributed(Impl().rand64());
|
||||||
|
return std::chrono::duration_cast<std::chrono::microseconds>(unscaled * mean + 0.5us);
|
||||||
|
}
|
||||||
|
|
||||||
// Compatibility with the UniformRandomBitGenerator concept
|
// Compatibility with the UniformRandomBitGenerator concept
|
||||||
typedef uint64_t result_type;
|
typedef uint64_t result_type;
|
||||||
static constexpr uint64_t min() noexcept { return 0; }
|
static constexpr uint64_t min() noexcept { return 0; }
|
||||||
|
|
Loading…
Add table
Reference in a new issue