Merge #6466: backport: merge bitcoin#18642, #25102, #25100, #25157, #25101, #25245, #25456, #24697, #24662, #25499 (clock backports)

e905ae0f4b merge bitcoin#25499: Use steady clock for all millis bench logging (Kittywhiskers Van Gogh)
492654db49 merge bitcoin#24662: Use system time instead of adjusted network time (Kittywhiskers Van Gogh)
bc3ec30144 merge bitcoin#24697: refactor address relay time (Kittywhiskers Van Gogh)
730cdf241a test: remove leftovers missed in bitcoin#25514 (dash#6097) (Kittywhiskers Van Gogh)
c7cb26ba05 merge bitcoin#25456: Use steady_clock for getrpcinfo durations (Kittywhiskers Van Gogh)
ea3c727e02 merge bitcoin#25245: Remove no-op TIME_INIT on deser (Kittywhiskers Van Gogh)
2d33cfba41 merge bitcoin#25101: Add mockable clock type (Kittywhiskers Van Gogh)
ccde10b914 merge bitcoin#25157: Fix -rpcwait with -netinfo returning negative time durations (Kittywhiskers Van Gogh)
484447cc86 merge bitcoin#25100: Switch scheduler to steady_clock (Kittywhiskers Van Gogh)
cc7d2b8d0a merge bitcoin#25102: Remove unused GetTimeSeconds (Kittywhiskers Van Gogh)
8f8e73242d net: use `GetTime<T>()` in leftover `GetTimeSeconds()` usage (Kittywhiskers Van Gogh)
b114718240 merge bitcoin#18642: Use std::chrono for the time to rotate destination of addr messages + tests (Kittywhiskers Van Gogh)

Pull request description:

  ## Breaking Changes

  None expected.

  ## Checklist

  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)**
  - [x] I have added or updated relevant unit/integration/functional/e2e tests
  - [x] I have made corresponding changes to the documentation **(note: N/A)**
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  PastaPastaPasta:
    utACK e905ae0f4b
  UdjinM6:
    utACK e905ae0f4b

Tree-SHA512: 022b8fac41315726e622b887ef5f5f5d011c947048d144f6f54c7c596d9e90286b77ec6f91dfc9bdb60ecc21dfa791afe4aba3d97f962eb1e86cd750831275bd
This commit is contained in:
pasta 2024-12-10 22:22:29 -06:00
commit 1140e4358b
No known key found for this signature in database
GPG Key ID: E2F3D7916E722D38
37 changed files with 413 additions and 290 deletions

View File

@ -188,11 +188,11 @@ std::optional<bilingual_str> LoadAddrman(const NetGroupManager& netgroupman, con
auto check_addrman = std::clamp<int32_t>(args.GetArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000); auto check_addrman = std::clamp<int32_t>(args.GetArg("-checkaddrman", DEFAULT_ADDRMAN_CONSISTENCY_CHECKS), 0, 1000000);
addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman); addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
const auto path_addr{gArgs.GetDataDirNet() / "peers.dat"}; const auto path_addr{gArgs.GetDataDirNet() / "peers.dat"};
try { try {
DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION); DeserializeFileDB(path_addr, *addrman, CLIENT_VERSION);
LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->Size(), GetTimeMillis() - nStart); LogPrintf("Loaded %i addresses from peers.dat %dms\n", addrman->Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} catch (const DbNotFoundError&) { } catch (const DbNotFoundError&) {
// Addrman can be in an inconsistent state after failure, reset it // Addrman can be in an inconsistent state after failure, reset it
addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman); addrman = std::make_unique<AddrMan>(netgroupman, /*deterministic=*/false, /*consistency_check_ratio=*/check_addrman);

View File

@ -14,10 +14,10 @@
#include <random.h> #include <random.h>
#include <serialize.h> #include <serialize.h>
#include <streams.h> #include <streams.h>
#include <timedata.h>
#include <tinyformat.h> #include <tinyformat.h>
#include <uint256.h> #include <uint256.h>
#include <util/check.h> #include <util/check.h>
#include <util/time.h>
#include <cmath> #include <cmath>
#include <optional> #include <optional>
@ -29,19 +29,19 @@ static constexpr uint32_t ADDRMAN_NEW_BUCKETS_PER_SOURCE_GROUP{64};
/** Maximum number of times an address can occur in the new table */ /** Maximum number of times an address can occur in the new table */
static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8}; static constexpr int32_t ADDRMAN_NEW_BUCKETS_PER_ADDRESS{8};
/** How old addresses can maximally be */ /** How old addresses can maximally be */
static constexpr int64_t ADDRMAN_HORIZON_DAYS{30}; static constexpr auto ADDRMAN_HORIZON{30 * 24h};
/** After how many failed attempts we give up on a new node */ /** After how many failed attempts we give up on a new node */
static constexpr int32_t ADDRMAN_RETRIES{3}; static constexpr int32_t ADDRMAN_RETRIES{3};
/** How many successive failures are allowed ... */ /** How many successive failures are allowed ... */
static constexpr int32_t ADDRMAN_MAX_FAILURES{10}; static constexpr int32_t ADDRMAN_MAX_FAILURES{10};
/** ... in at least this many days */ /** ... in at least this duration */
static constexpr int64_t ADDRMAN_MIN_FAIL_DAYS{7}; static constexpr auto ADDRMAN_MIN_FAIL{7 * 24h};
/** How recent a successful connection should be before we allow an address to be evicted from tried */ /** How recent a successful connection should be before we allow an address to be evicted from tried */
static constexpr int64_t ADDRMAN_REPLACEMENT_HOURS{4}; static constexpr auto ADDRMAN_REPLACEMENT{4h};
/** The maximum number of tried addr collisions to store */ /** The maximum number of tried addr collisions to store */
static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10}; static constexpr size_t ADDRMAN_SET_TRIED_COLLISION_SIZE{10};
/** The maximum time we'll spend trying to resolve a tried table collision, in seconds */ /** The maximum time we'll spend trying to resolve a tried table collision */
static constexpr int64_t ADDRMAN_TEST_WINDOW{40*60}; // 40 minutes static constexpr auto ADDRMAN_TEST_WINDOW{40min};
int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const int AddrInfo::GetTriedBucket(const uint256& nKey, const NetGroupManager& netgroupman) const
{ {
@ -64,36 +64,39 @@ int AddrInfo::GetBucketPosition(const uint256& nKey, bool fNew, int bucket) cons
return hash1 % ADDRMAN_BUCKET_SIZE; return hash1 % ADDRMAN_BUCKET_SIZE;
} }
bool AddrInfo::IsTerrible(int64_t nNow) const bool AddrInfo::IsTerrible(NodeSeconds now) const
{ {
if (nNow - nLastTry <= 60) { // never remove things tried in the last minute if (now - m_last_try <= 1min) { // never remove things tried in the last minute
return false; return false;
} }
if (nTime > nNow + 10 * 60) // came in a flying DeLorean if (nTime > now + 10min) { // came in a flying DeLorean
return true;
if (nNow - nTime > ADDRMAN_HORIZON_DAYS * 24 * 60 * 60) { // not seen in recent history
return true; return true;
} }
if (nLastSuccess == 0 && nAttempts >= ADDRMAN_RETRIES) // tried N times and never a success if (now - nTime > ADDRMAN_HORIZON) { // not seen in recent history
return true; return true;
}
if (nNow - nLastSuccess > ADDRMAN_MIN_FAIL_DAYS * 24 * 60 * 60 && nAttempts >= ADDRMAN_MAX_FAILURES) // N successive failures in the last week if (TicksSinceEpoch<std::chrono::seconds>(m_last_success) == 0 && nAttempts >= ADDRMAN_RETRIES) { // tried N times and never a success
return true; return true;
}
if (now - m_last_success > ADDRMAN_MIN_FAIL && nAttempts >= ADDRMAN_MAX_FAILURES) { // N successive failures in the last week
return true;
}
return false; return false;
} }
double AddrInfo::GetChance(int64_t nNow) const double AddrInfo::GetChance(NodeSeconds now) const
{ {
double fChance = 1.0; double fChance = 1.0;
int64_t nSinceLastTry = std::max<int64_t>(nNow - nLastTry, 0);
// deprioritize very recent attempts away // deprioritize very recent attempts away
if (nSinceLastTry < 60 * 10) if (now - m_last_try < 10min) {
fChance *= 0.01; fChance *= 0.01;
}
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages. // deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
fChance *= pow(0.66, std::min(nAttempts, 8)); fChance *= pow(0.66, std::min(nAttempts, 8));
@ -547,7 +550,7 @@ void AddrManImpl::MakeTried(AddrInfo& info, int nId)
m_network_counts[info.GetNetwork()].n_tried++; m_network_counts[info.GetNetwork()].n_tried++;
} }
bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
@ -559,15 +562,15 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
// Do not set a penalty for a source's self-announcement // Do not set a penalty for a source's self-announcement
if (addr == source) { if (addr == source) {
nTimePenalty = 0; time_penalty = 0s;
} }
if (pinfo) { if (pinfo) {
// periodically update nTime // periodically update nTime
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60); const bool currently_online{NodeClock::now() - addr.nTime < 24h};
int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60); const auto update_interval{currently_online ? 1h : 24h};
if (pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty) { if (pinfo->nTime < addr.nTime - update_interval - time_penalty) {
pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); pinfo->nTime = std::max(NodeSeconds{0s}, addr.nTime - time_penalty);
} }
// add services // add services
@ -593,7 +596,7 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
} }
} else { } else {
pinfo = Create(addr, source, &nId); pinfo = Create(addr, source, &nId);
pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty); pinfo->nTime = std::max(NodeSeconds{0s}, pinfo->nTime - time_penalty);
} }
int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman); int nUBucket = pinfo->GetNewBucket(nKey, source, m_netgroupman);
@ -622,13 +625,13 @@ bool AddrManImpl::AddSingle(const CAddress& addr, const CNetAddr& source, int64_
return fInsert; return fInsert;
} }
bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nTime) bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, NodeSeconds time)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
int nId; int nId;
nLastGood = nTime; m_last_good = time;
AddrInfo* pinfo = Find(addr, &nId); AddrInfo* pinfo = Find(addr, &nId);
@ -638,8 +641,8 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
AddrInfo& info = *pinfo; AddrInfo& info = *pinfo;
// update info // update info
info.nLastSuccess = nTime; info.m_last_success = time;
info.nLastTry = nTime; info.m_last_try = time;
info.nAttempts = 0; info.nAttempts = 0;
// nTime is not updated here, to avoid leaking information about // nTime is not updated here, to avoid leaking information about
// currently-connected peers. // currently-connected peers.
@ -680,11 +683,11 @@ bool AddrManImpl::Good_(const CService& addr, bool test_before_evict, int64_t nT
} }
} }
bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty) bool AddrManImpl::Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{ {
int added{0}; int added{0};
for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) { for (std::vector<CAddress>::const_iterator it = vAddr.begin(); it != vAddr.end(); it++) {
added += AddSingle(*it, source, nTimePenalty) ? 1 : 0; added += AddSingle(*it, source, time_penalty) ? 1 : 0;
} }
if (added > 0) { if (added > 0) {
LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToStringAddr(), nTried, nNew); LogPrint(BCLog::ADDRMAN, "Added %i addresses (of %i) from %s: %i tried, %i new\n", added, vAddr.size(), source.ToStringAddr(), nTried, nNew);
@ -692,7 +695,7 @@ bool AddrManImpl::Add_(const std::vector<CAddress> &vAddr, const CNetAddr& sourc
return added > 0; return added > 0;
} }
void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
@ -705,14 +708,14 @@ void AddrManImpl::Attempt_(const CService& addr, bool fCountFailure, int64_t nTi
AddrInfo& info = *pinfo; AddrInfo& info = *pinfo;
// update info // update info
info.nLastTry = nTime; info.m_last_try = time;
if (fCountFailure && info.nLastCountAttempt < nLastGood) { if (fCountFailure && info.m_last_count_attempt < m_last_good) {
info.nLastCountAttempt = nTime; info.m_last_count_attempt = time;
info.nAttempts++; info.nAttempts++;
} }
} }
std::pair<CAddress, int64_t> AddrManImpl::Select_(bool new_only, std::optional<Network> network) const std::pair<CAddress, NodeSeconds> AddrManImpl::Select_(bool new_only, std::optional<Network> network) const
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
@ -780,7 +783,7 @@ std::pair<CAddress, int64_t> AddrManImpl::Select_(bool new_only, std::optional<N
// With probability GetChance() * chance_factor, return the entry. // With probability GetChance() * chance_factor, return the entry.
if (insecure_rand.randbits(30) < chance_factor * info.GetChance() * (1 << 30)) { if (insecure_rand.randbits(30) < chance_factor * info.GetChance() * (1 << 30)) {
LogPrint(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new"); LogPrint(BCLog::ADDRMAN, "Selected %s from %s\n", info.ToStringAddrPort(), search_tried ? "tried" : "new");
return {info, info.nLastTry}; return {info, info.m_last_try};
} }
// Otherwise start over with a (likely) different bucket, and increased chance factor. // Otherwise start over with a (likely) different bucket, and increased chance factor.
@ -818,7 +821,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
} }
// gather a list of random nodes, skipping those of low quality // gather a list of random nodes, skipping those of low quality
const int64_t now{GetAdjustedTime()}; const auto now{Now<NodeSeconds>()};
std::vector<CAddress> addresses; std::vector<CAddress> addresses;
for (unsigned int n = 0; n < vRandom.size(); n++) { for (unsigned int n = 0; n < vRandom.size(); n++) {
if (addresses.size() >= nNodes) if (addresses.size() >= nNodes)
@ -843,7 +846,7 @@ std::vector<CAddress> AddrManImpl::GetAddr_(size_t max_addresses, size_t max_pct
return addresses; return addresses;
} }
void AddrManImpl::Connected_(const CService& addr, int64_t nTime) void AddrManImpl::Connected_(const CService& addr, NodeSeconds time)
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
@ -856,9 +859,10 @@ void AddrManImpl::Connected_(const CService& addr, int64_t nTime)
AddrInfo& info = *pinfo; AddrInfo& info = *pinfo;
// update info // update info
int64_t nUpdateInterval = 20 * 60; const auto update_interval{20min};
if (nTime - info.nTime > nUpdateInterval) if (time - info.nTime > update_interval) {
info.nTime = nTime; info.nTime = time;
}
} }
void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices) void AddrManImpl::SetServices_(const CService& addr, ServiceFlags nServices)
@ -914,22 +918,22 @@ void AddrManImpl::ResolveCollisions_()
int id_old = vvTried[tried_bucket][tried_bucket_pos]; int id_old = vvTried[tried_bucket][tried_bucket_pos];
AddrInfo& info_old = mapInfo[id_old]; AddrInfo& info_old = mapInfo[id_old];
const auto current_time{GetAdjustedTime()}; const auto current_time{Now<NodeSeconds>()};
// Has successfully connected in last X hours // Has successfully connected in last X hours
if (current_time - info_old.nLastSuccess < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { if (current_time - info_old.m_last_success < ADDRMAN_REPLACEMENT) {
erase_collision = true; erase_collision = true;
} else if (current_time - info_old.nLastTry < ADDRMAN_REPLACEMENT_HOURS*(60*60)) { // attempted to connect and failed in last X hours } else if (current_time - info_old.m_last_try < ADDRMAN_REPLACEMENT) { // attempted to connect and failed in last X hours
// Give address at least 60 seconds to successfully connect // Give address at least 60 seconds to successfully connect
if (current_time - info_old.nLastTry > 60) { if (current_time - info_old.m_last_try > 60s) {
LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort()); LogPrint(BCLog::ADDRMAN, "Replacing %s with %s in tried table\n", info_old.ToStringAddrPort(), info_new.ToStringAddrPort());
// Replaces an existing address already in the tried table with the new address // Replaces an existing address already in the tried table with the new address
Good_(info_new, false, current_time); Good_(info_new, false, current_time);
erase_collision = true; erase_collision = true;
} }
} else if (current_time - info_new.nLastSuccess > ADDRMAN_TEST_WINDOW) { } else if (current_time - info_new.m_last_success > ADDRMAN_TEST_WINDOW) {
// If the collision hasn't resolved in some reasonable amount of time, // If the collision hasn't resolved in some reasonable amount of time,
// just evict the old entry -- we must not be able to // just evict the old entry -- we must not be able to
// connect to it for some reason. // connect to it for some reason.
@ -938,7 +942,7 @@ void AddrManImpl::ResolveCollisions_()
erase_collision = true; erase_collision = true;
} }
} else { // Collision is not actually a collision anymore } else { // Collision is not actually a collision anymore
Good_(info_new, false, GetAdjustedTime()); Good_(info_new, false, Now<NodeSeconds>());
erase_collision = true; erase_collision = true;
} }
} }
@ -951,7 +955,7 @@ void AddrManImpl::ResolveCollisions_()
} }
} }
std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_() std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision_()
{ {
AssertLockHeld(cs); AssertLockHeld(cs);
@ -976,7 +980,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision_()
int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket); int tried_bucket_pos = newInfo.GetBucketPosition(nKey, false, tried_bucket);
const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]]; const AddrInfo& info_old = mapInfo[vvTried[tried_bucket][tried_bucket_pos]];
return {info_old, info_old.nLastTry}; return {info_old, info_old.m_last_try};
} }
std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr) std::optional<AddressPosition> AddrManImpl::FindAddressEntry_(const CAddress& addr)
@ -1057,8 +1061,9 @@ int AddrManImpl::CheckAddrman() const
int n = entry.first; int n = entry.first;
const AddrInfo& info = entry.second; const AddrInfo& info = entry.second;
if (info.fInTried) { if (info.fInTried) {
if (!info.nLastSuccess) if (!TicksSinceEpoch<std::chrono::seconds>(info.m_last_success)) {
return -1; return -1;
}
if (info.nRefCount) if (info.nRefCount)
return -2; return -2;
setTried.insert(n); setTried.insert(n);
@ -1077,11 +1082,13 @@ int AddrManImpl::CheckAddrman() const
} }
if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n) if (info.nRandomPos < 0 || (size_t)info.nRandomPos >= vRandom.size() || vRandom[info.nRandomPos] != n)
return -14; return -14;
if (info.nLastTry < 0) if (info.m_last_try < NodeSeconds{0s}) {
return -6; return -6;
if (info.nLastSuccess < 0) }
if (info.m_last_success < NodeSeconds{0s}) {
return -8; return -8;
} }
}
if (setTried.size() != (size_t)nTried) if (setTried.size() != (size_t)nTried)
return -9; return -9;
@ -1150,29 +1157,29 @@ size_t AddrManImpl::Size(std::optional<Network> net, std::optional<bool> in_new)
return ret; return ret;
} }
bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty) bool AddrManImpl::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{ {
LOCK(cs); LOCK(cs);
Check(); Check();
auto ret = Add_(vAddr, source, nTimePenalty); auto ret = Add_(vAddr, source, time_penalty);
Check(); Check();
return ret; return ret;
} }
bool AddrManImpl::Good(const CService& addr, int64_t nTime) bool AddrManImpl::Good(const CService& addr, NodeSeconds time)
{ {
LOCK(cs); LOCK(cs);
Check(); Check();
auto ret = Good_(addr, /*test_before_evict=*/true, nTime); auto ret = Good_(addr, /*test_before_evict=*/true, time);
Check(); Check();
return ret; return ret;
} }
void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, int64_t nTime) void AddrManImpl::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
{ {
LOCK(cs); LOCK(cs);
Check(); Check();
Attempt_(addr, fCountFailure, nTime); Attempt_(addr, fCountFailure, time);
Check(); Check();
} }
@ -1184,7 +1191,7 @@ void AddrManImpl::ResolveCollisions()
Check(); Check();
} }
std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision() std::pair<CAddress, NodeSeconds> AddrManImpl::SelectTriedCollision()
{ {
LOCK(cs); LOCK(cs);
Check(); Check();
@ -1193,7 +1200,7 @@ std::pair<CAddress, int64_t> AddrManImpl::SelectTriedCollision()
return ret; return ret;
} }
std::pair<CAddress, int64_t> AddrManImpl::Select(bool new_only, std::optional<Network> network) const std::pair<CAddress, NodeSeconds> AddrManImpl::Select(bool new_only, std::optional<Network> network) const
{ {
LOCK(cs); LOCK(cs);
Check(); Check();
@ -1211,11 +1218,11 @@ std::vector<CAddress> AddrManImpl::GetAddr(size_t max_addresses, size_t max_pct,
return addresses; return addresses;
} }
void AddrManImpl::Connected(const CService& addr, int64_t nTime) void AddrManImpl::Connected(const CService& addr, NodeSeconds time)
{ {
LOCK(cs); LOCK(cs);
Check(); Check();
Connected_(addr, nTime); Connected_(addr, time);
Check(); Check();
} }
@ -1278,19 +1285,19 @@ size_t AddrMan::Size(std::optional<Network> net, std::optional<bool> in_new) con
return m_impl->Size(net, in_new); return m_impl->Size(net, in_new);
} }
bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty) bool AddrMan::Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
{ {
return m_impl->Add(vAddr, source, nTimePenalty); return m_impl->Add(vAddr, source, time_penalty);
} }
bool AddrMan::Good(const CService& addr, int64_t nTime) bool AddrMan::Good(const CService& addr, NodeSeconds time)
{ {
return m_impl->Good(addr, nTime); return m_impl->Good(addr, time);
} }
void AddrMan::Attempt(const CService& addr, bool fCountFailure, int64_t nTime) void AddrMan::Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
{ {
m_impl->Attempt(addr, fCountFailure, nTime); m_impl->Attempt(addr, fCountFailure, time);
} }
void AddrMan::ResolveCollisions() void AddrMan::ResolveCollisions()
@ -1298,12 +1305,12 @@ void AddrMan::ResolveCollisions()
m_impl->ResolveCollisions(); m_impl->ResolveCollisions();
} }
std::pair<CAddress, int64_t> AddrMan::SelectTriedCollision() std::pair<CAddress, NodeSeconds> AddrMan::SelectTriedCollision()
{ {
return m_impl->SelectTriedCollision(); return m_impl->SelectTriedCollision();
} }
std::pair<CAddress, int64_t> AddrMan::Select(bool new_only, std::optional<Network> network) const std::pair<CAddress, NodeSeconds> AddrMan::Select(bool new_only, std::optional<Network> network) const
{ {
return m_impl->Select(new_only, network); return m_impl->Select(new_only, network);
} }
@ -1313,9 +1320,9 @@ std::vector<CAddress> AddrMan::GetAddr(size_t max_addresses, size_t max_pct, std
return m_impl->GetAddr(max_addresses, max_pct, network); return m_impl->GetAddr(max_addresses, max_pct, network);
} }
void AddrMan::Connected(const CService& addr, int64_t nTime) void AddrMan::Connected(const CService& addr, NodeSeconds time)
{ {
m_impl->Connected(addr, nTime); m_impl->Connected(addr, time);
} }
void AddrMan::SetServices(const CService& addr, ServiceFlags nServices) void AddrMan::SetServices(const CService& addr, ServiceFlags nServices)

View File

@ -10,7 +10,7 @@
#include <netgroup.h> #include <netgroup.h>
#include <protocol.h> #include <protocol.h>
#include <streams.h> #include <streams.h>
#include <timedata.h> #include <util/time.h>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
@ -124,23 +124,23 @@ public:
* *
* @param[in] vAddr Address records to attempt to add. * @param[in] vAddr Address records to attempt to add.
* @param[in] source The address of the node that sent us these addr records. * @param[in] source The address of the node that sent us these addr records.
* @param[in] nTimePenalty A "time penalty" to apply to the address record's nTime. If a peer * @param[in] time_penalty A "time penalty" to apply to the address record's nTime. If a peer
* sends us an address record with nTime=n, then we'll add it to our * sends us an address record with nTime=n, then we'll add it to our
* addrman with nTime=(n - nTimePenalty). * addrman with nTime=(n - time_penalty).
* @return true if at least one address is successfully added. */ * @return true if at least one address is successfully added. */
bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty = 0); bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty = 0s);
/** /**
* Mark an address record as accessible and attempt to move it to addrman's tried table. * Mark an address record as accessible and attempt to move it to addrman's tried table.
* *
* @param[in] addr Address record to attempt to move to tried table. * @param[in] addr Address record to attempt to move to tried table.
* @param[in] nTime The time that we were last connected to this peer. * @param[in] time The time that we were last connected to this peer.
* @return true if the address is successfully moved from the new table to the tried table. * @return true if the address is successfully moved from the new table to the tried table.
*/ */
bool Good(const CService& addr, int64_t nTime = GetAdjustedTime()); bool Good(const CService& addr, NodeSeconds time = Now<NodeSeconds>());
//! Mark an entry as connection attempted to. //! Mark an entry as connection attempted to.
void Attempt(const CService& addr, bool fCountFailure, int64_t nTime = GetAdjustedTime()); void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time = Now<NodeSeconds>());
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions. //! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
void ResolveCollisions(); void ResolveCollisions();
@ -150,9 +150,9 @@ public:
* attempting to evict. * attempting to evict.
* *
* @return CAddress The record for the selected tried peer. * @return CAddress The record for the selected tried peer.
* int64_t The last time we attempted to connect to that peer. * seconds The last time we attempted to connect to that peer.
*/ */
std::pair<CAddress, int64_t> SelectTriedCollision(); std::pair<CAddress, NodeSeconds> SelectTriedCollision();
/** /**
* Choose an address to connect to. * Choose an address to connect to.
@ -164,9 +164,9 @@ public:
* @param[in] network Select only addresses of this network (nullopt = all). Passing a network may * @param[in] network Select only addresses of this network (nullopt = all). Passing a network may
* slow down the search. * slow down the search.
* @return CAddress The record for the selected peer. * @return CAddress The record for the selected peer.
* int64_t The last time we attempted to connect to that peer. * seconds The last time we attempted to connect to that peer.
*/ */
std::pair<CAddress, int64_t> Select(bool new_only = false, std::optional<Network> network = std::nullopt) const; std::pair<CAddress, NodeSeconds> Select(bool new_only = false, std::optional<Network> network = std::nullopt) const;
/** /**
* Return all or many randomly selected addresses, optionally by network. * Return all or many randomly selected addresses, optionally by network.
@ -188,9 +188,9 @@ public:
* not leak information about currently connected peers. * not leak information about currently connected peers.
* *
* @param[in] addr The address of the peer we were connected to * @param[in] addr The address of the peer we were connected to
* @param[in] nTime The time that we were last connected to this peer * @param[in] time The time that we were last connected to this peer
*/ */
void Connected(const CService& addr, int64_t nTime = GetAdjustedTime()); void Connected(const CService& addr, NodeSeconds time = Now<NodeSeconds>());
//! Update an entry's service bits. //! Update an entry's service bits.
void SetServices(const CService& addr, ServiceFlags nServices); void SetServices(const CService& addr, ServiceFlags nServices);

View File

@ -11,7 +11,9 @@
#include <protocol.h> #include <protocol.h>
#include <serialize.h> #include <serialize.h>
#include <sync.h> #include <sync.h>
#include <timedata.h>
#include <uint256.h> #include <uint256.h>
#include <util/time.h>
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
@ -38,16 +40,16 @@ class AddrInfo : public CAddress
{ {
public: public:
//! last try whatsoever by us (memory only) //! last try whatsoever by us (memory only)
int64_t nLastTry{0}; NodeSeconds m_last_try{0s};
//! last counted attempt (memory only) //! last counted attempt (memory only)
int64_t nLastCountAttempt{0}; NodeSeconds m_last_count_attempt{0s};
//! where knowledge about this address first came from //! where knowledge about this address first came from
CNetAddr source; CNetAddr source;
//! last successful connection by us //! last successful connection by us
int64_t nLastSuccess{0}; NodeSeconds m_last_success{0s};
//! connection attempts since last successful attempt //! connection attempts since last successful attempt
int nAttempts{0}; int nAttempts{0};
@ -64,7 +66,7 @@ public:
SERIALIZE_METHODS(AddrInfo, obj) SERIALIZE_METHODS(AddrInfo, obj)
{ {
READWRITEAS(CAddress, obj); READWRITEAS(CAddress, obj);
READWRITE(obj.source, obj.nLastSuccess, obj.nAttempts); READWRITE(obj.source, Using<ChronoFormatter<int64_t>>(obj.m_last_success), obj.nAttempts);
} }
AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource) AddrInfo(const CAddress &addrIn, const CNetAddr &addrSource) : CAddress(addrIn), source(addrSource)
@ -91,10 +93,10 @@ public:
int GetBucketPosition(const uint256 &nKey, bool fNew, int bucket) const; int GetBucketPosition(const uint256 &nKey, bool fNew, int bucket) const;
//! Determine whether the statistics about this entry are bad enough so that it can just be deleted //! Determine whether the statistics about this entry are bad enough so that it can just be deleted
bool IsTerrible(int64_t nNow = GetAdjustedTime()) const; bool IsTerrible(NodeSeconds now = Now<NodeSeconds>()) const;
//! Calculate the relative chance this entry should be given when selecting nodes to connect to //! Calculate the relative chance this entry should be given when selecting nodes to connect to
double GetChance(int64_t nNow = GetAdjustedTime()) const; double GetChance(NodeSeconds now = Now<NodeSeconds>()) const;
}; };
class AddrManImpl class AddrManImpl
@ -112,26 +114,26 @@ public:
size_t Size(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(!cs); size_t Size(std::optional<Network> net, std::optional<bool> in_new) const EXCLUSIVE_LOCKS_REQUIRED(!cs);
bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, int64_t nTimePenalty) bool Add(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty)
EXCLUSIVE_LOCKS_REQUIRED(!cs); EXCLUSIVE_LOCKS_REQUIRED(!cs);
bool Good(const CService& addr, int64_t nTime) bool Good(const CService& addr, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs); EXCLUSIVE_LOCKS_REQUIRED(!cs);
void Attempt(const CService& addr, bool fCountFailure, int64_t nTime) void Attempt(const CService& addr, bool fCountFailure, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs); EXCLUSIVE_LOCKS_REQUIRED(!cs);
void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs); void ResolveCollisions() EXCLUSIVE_LOCKS_REQUIRED(!cs);
std::pair<CAddress, int64_t> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs); std::pair<CAddress, NodeSeconds> SelectTriedCollision() EXCLUSIVE_LOCKS_REQUIRED(!cs);
std::pair<CAddress, int64_t> Select(bool new_only, std::optional<Network> network) const std::pair<CAddress, NodeSeconds> Select(bool new_only, std::optional<Network> network) const
EXCLUSIVE_LOCKS_REQUIRED(!cs); EXCLUSIVE_LOCKS_REQUIRED(!cs);
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network) const
EXCLUSIVE_LOCKS_REQUIRED(!cs); EXCLUSIVE_LOCKS_REQUIRED(!cs);
void Connected(const CService& addr, int64_t nTime) void Connected(const CService& addr, NodeSeconds time)
EXCLUSIVE_LOCKS_REQUIRED(!cs); EXCLUSIVE_LOCKS_REQUIRED(!cs);
void SetServices(const CService& addr, ServiceFlags nServices) void SetServices(const CService& addr, ServiceFlags nServices)
@ -205,7 +207,7 @@ private:
int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs); int vvNew[ADDRMAN_NEW_BUCKET_COUNT][ADDRMAN_BUCKET_SIZE] GUARDED_BY(cs);
//! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse. //! last time Good was called (memory only). Initially set to 1 so that "never" is strictly worse.
int64_t nLastGood GUARDED_BY(cs){1}; NodeSeconds m_last_good GUARDED_BY(cs){1s};
//! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions. //! Holds addrs inserted into tried table that collide with existing entries. Test-before-evict discipline used to resolve these collisions.
std::set<int> m_tried_collisions; std::set<int> m_tried_collisions;
@ -244,15 +246,15 @@ private:
/** Attempt to add a single address to addrman's new table. /** Attempt to add a single address to addrman's new table.
* @see AddrMan::Add() for parameters. */ * @see AddrMan::Add() for parameters. */
bool AddSingle(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs); bool AddSingle(const CAddress& addr, const CNetAddr& source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
bool Good_(const CService& addr, bool test_before_evict, int64_t time) EXCLUSIVE_LOCKS_REQUIRED(cs); bool Good_(const CService& addr, bool test_before_evict, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
bool Add_(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty) EXCLUSIVE_LOCKS_REQUIRED(cs); bool Add_(const std::vector<CAddress>& vAddr, const CNetAddr& source, std::chrono::seconds time_penalty) EXCLUSIVE_LOCKS_REQUIRED(cs);
void Attempt_(const CService& addr, bool fCountFailure, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs); void Attempt_(const CService& addr, bool fCountFailure, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
std::pair<CAddress, int64_t> Select_(bool new_only, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs); std::pair<CAddress, NodeSeconds> Select_(bool new_only, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
/** Helper to generalize looking up an addrman entry from either table. /** Helper to generalize looking up an addrman entry from either table.
* *
@ -262,7 +264,7 @@ private:
std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs); std::vector<CAddress> GetAddr_(size_t max_addresses, size_t max_pct, std::optional<Network> network) const EXCLUSIVE_LOCKS_REQUIRED(cs);
void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs); void Connected_(const CService& addr, NodeSeconds time) EXCLUSIVE_LOCKS_REQUIRED(cs);
void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs); void SetServices_(const CService& addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
@ -270,7 +272,7 @@ private:
void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs); void ResolveCollisions_() EXCLUSIVE_LOCKS_REQUIRED(cs);
std::pair<CAddress, int64_t> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs); std::pair<CAddress, NodeSeconds> SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs); std::optional<AddressPosition> FindAddressEntry_(const CAddress& addr) EXCLUSIVE_LOCKS_REQUIRED(cs);

View File

@ -31,12 +31,12 @@ void BanMan::LoadBanlist()
if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated); if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist…").translated);
int64_t n_start = GetTimeMillis(); const auto start{SteadyClock::now()};
if (m_ban_db.Read(m_banned)) { if (m_ban_db.Read(m_banned)) {
SweepBanned(); // sweep out unused entries SweepBanned(); // sweep out unused entries
LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(), LogPrint(BCLog::NET, "Loaded %d banned node addresses/subnets %dms\n", m_banned.size(),
GetTimeMillis() - n_start); Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} else { } else {
LogPrintf("Recreating the banlist database\n"); LogPrintf("Recreating the banlist database\n");
m_banned = {}; m_banned = {};
@ -58,13 +58,13 @@ void BanMan::DumpBanlist()
SetBannedSetDirty(false); SetBannedSetDirty(false);
} }
int64_t n_start = GetTimeMillis(); const auto start{SteadyClock::now()};
if (!m_ban_db.Write(banmap)) { if (!m_ban_db.Write(banmap)) {
SetBannedSetDirty(true); SetBannedSetDirty(true);
} }
LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(), LogPrint(BCLog::NET, "Flushed %d banned node addresses/subnets to disk %dms\n", banmap.size(),
GetTimeMillis() - n_start); Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} }
void BanMan::ClearBanned() void BanMan::ClearBanned()

View File

@ -42,7 +42,7 @@ static void CreateAddresses()
CAddress ret(CService(addr, port), NODE_NETWORK); CAddress ret(CService(addr, port), NODE_NETWORK);
ret.nTime = GetAdjustedTime(); ret.nTime = Now<NodeSeconds>();
return ret; return ret;
}; };
@ -118,7 +118,7 @@ static void AddrManSelectByNetwork(benchmark::Bench& bench)
CService i2p_service; CService i2p_service;
i2p_service.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p"); i2p_service.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
CAddress i2p_address(i2p_service, NODE_NONE); CAddress i2p_address(i2p_service, NODE_NONE);
i2p_address.nTime = GetAdjustedTime(); i2p_address.nTime = Now<NodeSeconds>();
const CNetAddr source{LookupHost("252.2.2.2", false).value()}; const CNetAddr source{LookupHost("252.2.2.2", false).value()};
addrman.Add({i2p_address}, source); addrman.Add({i2p_address}, source);

View File

@ -11,6 +11,7 @@
#include <chainparamsbase.h> #include <chainparamsbase.h>
#include <clientversion.h> #include <clientversion.h>
#include <compat.h> #include <compat.h>
#include <compat/stdin.h>
#include <policy/feerate.h> #include <policy/feerate.h>
#include <rpc/client.h> #include <rpc/client.h>
#include <rpc/mining.h> #include <rpc/mining.h>
@ -18,17 +19,19 @@
#include <rpc/request.h> #include <rpc/request.h>
#include <stacktraces.h> #include <stacktraces.h>
#include <tinyformat.h> #include <tinyformat.h>
#include <univalue.h>
#include <util/strencodings.h> #include <util/strencodings.h>
#include <util/system.h> #include <util/system.h>
#include <util/translation.h> #include <util/translation.h>
#include <util/url.h> #include <util/url.h>
#include <algorithm> #include <algorithm>
#include <chrono>
#include <cmath> #include <cmath>
#include <cstdio>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <stdio.h>
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -40,8 +43,10 @@
#include <event2/keyvalq_struct.h> #include <event2/keyvalq_struct.h>
#include <support/events.h> #include <support/events.h>
#include <univalue.h> // The server returns time values from a mockable system clock, but it is not
#include <compat/stdin.h> // trivial to get the mocked time from the server, nor is it needed for now, so
// just use a plain system_clock.
using CliClock = std::chrono::system_clock;
const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
UrlDecodeFn* const URL_DECODE = urlDecode; UrlDecodeFn* const URL_DECODE = urlDecode;
@ -454,7 +459,6 @@ private:
if (conn_type == "addr-fetch") return "addr"; if (conn_type == "addr-fetch") return "addr";
return ""; return "";
} }
const int64_t m_time_now{GetTimeSeconds()};
public: public:
static constexpr int ID_PEERINFO = 0; static constexpr int ID_PEERINFO = 0;
@ -486,6 +490,7 @@ public:
if (networkinfo["version"].get_int() < 200000) { if (networkinfo["version"].get_int() < 200000) {
throw std::runtime_error("-netinfo requires dashd server to be running v20.0 and up"); throw std::runtime_error("-netinfo requires dashd server to be running v20.0 and up");
} }
const int64_t time_now{TicksSinceEpoch<std::chrono::seconds>(CliClock::now())};
// Count peer connection totals, and if DetailsRequested(), store peer data in a vector of structs. // Count peer connection totals, and if DetailsRequested(), store peer data in a vector of structs.
for (const UniValue& peer : batch[ID_PEERINFO]["result"].getValues()) { for (const UniValue& peer : batch[ID_PEERINFO]["result"].getValues()) {
@ -516,7 +521,7 @@ public:
const double min_ping{peer["minping"].isNull() ? -1 : peer["minping"].get_real()}; const double min_ping{peer["minping"].isNull() ? -1 : peer["minping"].get_real()};
const double ping{peer["pingtime"].isNull() ? -1 : peer["pingtime"].get_real()}; const double ping{peer["pingtime"].isNull() ? -1 : peer["pingtime"].get_real()};
const std::string addr{peer["addr"].get_str()}; const std::string addr{peer["addr"].get_str()};
const std::string age{conn_time == 0 ? "" : ToString((m_time_now - conn_time) / 60)}; const std::string age{conn_time == 0 ? "" : ToString((time_now - conn_time) / 60)};
const std::string sub_version{peer["subver"].get_str()}; const std::string sub_version{peer["subver"].get_str()};
const std::string transport{peer["transport_protocol_type"].isNull() ? "v1" : peer["transport_protocol_type"].get_str()}; const std::string transport{peer["transport_protocol_type"].isNull() ? "v1" : peer["transport_protocol_type"].get_str()};
const bool is_addr_relay_enabled{peer["addr_relay_enabled"].isNull() ? false : peer["addr_relay_enabled"].get_bool()}; const bool is_addr_relay_enabled{peer["addr_relay_enabled"].isNull() ? false : peer["addr_relay_enabled"].get_bool()};
@ -554,10 +559,10 @@ public:
peer.transport_protocol_type.rfind('v', 0) == 0 ? peer.transport_protocol_type[1] : ' ', peer.transport_protocol_type.rfind('v', 0) == 0 ? peer.transport_protocol_type[1] : ' ',
PingTimeToString(peer.min_ping), PingTimeToString(peer.min_ping),
PingTimeToString(peer.ping), PingTimeToString(peer.ping),
peer.last_send ? ToString(m_time_now - peer.last_send) : "", peer.last_send ? ToString(time_now - peer.last_send) : "",
peer.last_recv ? ToString(m_time_now - peer.last_recv) : "", peer.last_recv ? ToString(time_now - peer.last_recv) : "",
peer.last_trxn ? ToString((m_time_now - peer.last_trxn) / 60) : peer.is_block_relay ? "*" : "", peer.last_trxn ? ToString((time_now - peer.last_trxn) / 60) : peer.is_block_relay ? "*" : "",
peer.last_blck ? ToString((m_time_now - peer.last_blck) / 60) : "", peer.last_blck ? ToString((time_now - peer.last_blck) / 60) : "",
strprintf("%s%s", peer.is_bip152_hb_to ? "." : " ", peer.is_bip152_hb_from ? "*" : " "), strprintf("%s%s", peer.is_bip152_hb_to ? "." : " ", peer.is_bip152_hb_from ? "*" : " "),
m_max_addr_processed_length, // variable spacing m_max_addr_processed_length, // variable spacing
peer.addr_processed ? ToString(peer.addr_processed) : peer.is_addr_relay_enabled ? "" : ".", peer.addr_processed ? ToString(peer.addr_processed) : peer.is_addr_relay_enabled ? "" : ".",
@ -869,7 +874,7 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str
// Execute and handle connection failures with -rpcwait. // Execute and handle connection failures with -rpcwait.
const bool fWait = gArgs.GetBoolArg("-rpcwait", false); const bool fWait = gArgs.GetBoolArg("-rpcwait", false);
const int timeout = gArgs.GetArg("-rpcwaittimeout", DEFAULT_WAIT_CLIENT_TIMEOUT); const int timeout = gArgs.GetArg("-rpcwaittimeout", DEFAULT_WAIT_CLIENT_TIMEOUT);
const auto deadline{GetTime<std::chrono::microseconds>() + 1s * timeout}; const auto deadline{std::chrono::steady_clock::now() + 1s * timeout};
do { do {
try { try {
@ -882,8 +887,7 @@ static UniValue ConnectAndCallRPC(BaseRequestHandler* rh, const std::string& str
} }
break; // Connection succeeded, no need to retry. break; // Connection succeeded, no need to retry.
} catch (const CConnectionFailed& e) { } catch (const CConnectionFailed& e) {
const auto now{GetTime<std::chrono::microseconds>()}; if (fWait && (timeout <= 0 || std::chrono::steady_clock::now() < deadline)) {
if (fWait && (timeout <= 0 || now < deadline)) {
UninterruptibleSleep(1s); UninterruptibleSleep(1s);
} else { } else {
throw CConnectionFailed(strprintf("timeout on transient error: %s", e.what())); throw CConnectionFailed(strprintf("timeout on transient error: %s", e.what()));

View File

@ -39,7 +39,7 @@ private:
{ {
// LOCK(objToSave.cs); // LOCK(objToSave.cs);
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
// serialize, checksum data up to that point, then append checksum // serialize, checksum data up to that point, then append checksum
CDataStream ssObj(SER_DISK, CLIENT_VERSION); CDataStream ssObj(SER_DISK, CLIENT_VERSION);
@ -65,7 +65,7 @@ private:
} }
fileout.fclose(); fileout.fclose();
LogPrintf("Written info to %s %dms\n", strFilename, GetTimeMillis() - nStart); LogPrintf("Written info to %s %dms\n", strFilename, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
LogPrintf(" %s\n", objToSave.ToString()); LogPrintf(" %s\n", objToSave.ToString());
return true; return true;
@ -75,7 +75,7 @@ private:
{ {
//LOCK(objToLoad.cs); //LOCK(objToLoad.cs);
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
// open input file, and associate with CAutoFile // open input file, and associate with CAutoFile
FILE *file = fsbridge::fopen(pathDB, "rb"); FILE *file = fsbridge::fopen(pathDB, "rb");
CAutoFile filein(file, SER_DISK, CLIENT_VERSION); CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
@ -149,7 +149,7 @@ private:
return ReadResult::IncorrectFormat; return ReadResult::IncorrectFormat;
} }
LogPrintf("Loaded info from %s %dms\n", strFilename, GetTimeMillis() - nStart); LogPrintf("Loaded info from %s %dms\n", strFilename, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
LogPrintf(" %s\n", objToLoad.ToString()); LogPrintf(" %s\n", objToLoad.ToString());
return ReadResult::Ok; return ReadResult::Ok;
@ -193,11 +193,11 @@ public:
T tmpObjToLoad; T tmpObjToLoad;
if (!Read(tmpObjToLoad)) return false; if (!Read(tmpObjToLoad)) return false;
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
LogPrintf("Writing info to %s...\n", strFilename); LogPrintf("Writing info to %s...\n", strFilename);
const bool ret = CoreWrite(objToSave); const bool ret = CoreWrite(objToSave);
LogPrintf("%s dump finished %dms\n", strFilename, GetTimeMillis() - nStart); LogPrintf("%s dump finished %dms\n", strFilename, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
return ret; return ret;
} }

View File

@ -1432,11 +1432,12 @@ void CGovernanceManager::AddCachedTriggers()
void CGovernanceManager::InitOnLoad() void CGovernanceManager::InitOnLoad()
{ {
LOCK(cs); LOCK(cs);
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
LogPrintf("Preparing masternode indexes and governance triggers...\n"); LogPrintf("Preparing masternode indexes and governance triggers...\n");
RebuildIndexes(); RebuildIndexes();
AddCachedTriggers(); AddCachedTriggers();
LogPrintf("Masternode indexes and governance triggers prepared %dms\n", GetTimeMillis() - nStart); LogPrintf("Masternode indexes and governance triggers prepared %dms\n",
Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
LogPrintf(" %s\n", ToString()); LogPrintf(" %s\n", ToString());
} }

View File

@ -1870,7 +1870,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
do { do {
bool failed_verification = false; bool failed_verification = false;
const int64_t load_block_index_start_time = GetTimeMillis(); const auto load_block_index_start_time{SteadyClock::now()};
try { try {
LOCK(cs_main); LOCK(cs_main);
@ -2131,7 +2131,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
if (!failed_verification) { if (!failed_verification) {
fLoaded = true; fLoaded = true;
LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time); LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time));
} }
} while(false); } while(false);

View File

@ -232,7 +232,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
// it'll get a pile of addresses with newer timestamps. // it'll get a pile of addresses with newer timestamps.
// Seed nodes are given a random 'last seen time' of between one and two // Seed nodes are given a random 'last seen time' of between one and two
// weeks ago. // weeks ago.
const int64_t nOneWeek = 7*24*60*60; const auto one_week{7 * 24h};
std::vector<CAddress> vSeedsOut; std::vector<CAddress> vSeedsOut;
FastRandomContext rng; FastRandomContext rng;
CDataStream s(vSeedsIn, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT); CDataStream s(vSeedsIn, SER_NETWORK, PROTOCOL_VERSION | ADDRV2_FORMAT);
@ -240,7 +240,7 @@ static std::vector<CAddress> ConvertSeeds(const std::vector<uint8_t> &vSeedsIn)
CService endpoint; CService endpoint;
s >> endpoint; s >> endpoint;
CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)}; CAddress addr{endpoint, GetDesirableServiceFlags(NODE_NONE)};
addr.nTime = GetTime() - rng.randrange(nOneWeek) - nOneWeek; addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - one_week, -one_week);
LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort()); LogPrint(BCLog::NET, "Added hardcoded seed: %s\n", addr.ToStringAddrPort());
vSeedsOut.push_back(addr); vSeedsOut.push_back(addr);
} }
@ -512,11 +512,11 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying %s connection %s lastseen=%.1fhrs\n", LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying %s connection %s lastseen=%.1fhrs\n",
use_v2transport ? "v2" : "v1", use_v2transport ? "v2" : "v1",
pszDest ? pszDest : addrConnect.ToStringAddrPort(), pszDest ? pszDest : addrConnect.ToStringAddrPort(),
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); Ticks<HoursDouble>(pszDest ? 0h : Now<NodeSeconds>() - addrConnect.nTime));
} else { } else {
LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying %s connection lastseen=%.1fhrs\n", LogPrintLevel(BCLog::NET, BCLog::Level::Debug, "trying %s connection lastseen=%.1fhrs\n",
use_v2transport ? "v2" : "v1", use_v2transport ? "v2" : "v1",
pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); Ticks<HoursDouble>(pszDest ? 0h : Now<NodeSeconds>() - addrConnect.nTime));
} }
// Resolve // Resolve
@ -1901,7 +1901,7 @@ bool CConnman::AttemptToEvictConnection()
// follow when the incoming connection is from another masternode. When a message other than MNAUTH // follow when the incoming connection is from another masternode. When a message other than MNAUTH
// is received after VERSION/VERACK, the protection is lifted immediately. // is received after VERSION/VERACK, the protection is lifted immediately.
bool isProtected = GetTime<std::chrono::seconds>() - node->m_connected < INBOUND_EVICTION_PROTECTION_TIME; bool isProtected = GetTime<std::chrono::seconds>() - node->m_connected < INBOUND_EVICTION_PROTECTION_TIME;
if (node->nTimeFirstMessageReceived != 0 && !node->fFirstMessageIsMNAUTH) { if (node->nTimeFirstMessageReceived.load() != 0s && !node->fFirstMessageIsMNAUTH) {
isProtected = false; isProtected = false;
} }
// if MNAUTH was valid, the node is always protected (and at the same time not accounted when // if MNAUTH was valid, the node is always protected (and at the same time not accounted when
@ -3080,9 +3080,8 @@ void CConnman::ThreadDNSAddressSeed()
const auto addresses{LookupHost(host, nMaxIPs, true)}; const auto addresses{LookupHost(host, nMaxIPs, true)};
if (!addresses.empty()) { if (!addresses.empty()) {
for (const CNetAddr& ip : addresses) { for (const CNetAddr& ip : addresses) {
int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits); CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()), requiredServiceBits);
addr.nTime = GetTime() - 3*nOneDay - rng.randrange(4*nOneDay); // use a random age between 3 and 7 days old addr.nTime = rng.rand_uniform_delay(Now<NodeSeconds>() - 3 * 24h, -4 * 24h); // use a random age between 3 and 7 days old
vAdd.push_back(addr); vAdd.push_back(addr);
found++; found++;
} }
@ -3101,12 +3100,12 @@ void CConnman::ThreadDNSAddressSeed()
void CConnman::DumpAddresses() void CConnman::DumpAddresses()
{ {
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
DumpPeerAddresses(::gArgs, addrman); DumpPeerAddresses(::gArgs, addrman);
LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n", LogPrint(BCLog::NET, "Flushed %d addresses to peers.dat %dms\n",
addrman.Size(), GetTimeMillis() - nStart); addrman.Size(), Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} }
void CConnman::ProcessAddrFetch() void CConnman::ProcessAddrFetch()
@ -3451,7 +3450,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
auto mnList = dmnman.GetListAtChainTip(); auto mnList = dmnman.GetListAtChainTip();
int64_t nANow = GetAdjustedTime(); const auto current_time{NodeClock::now()};
int nTries = 0; int nTries = 0;
while (!interruptNet) while (!interruptNet)
{ {
@ -3474,7 +3473,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
break; break;
CAddress addr; CAddress addr;
int64_t addr_last_try{0}; NodeSeconds addr_last_try{0s};
if (fFeeler) { if (fFeeler) {
// First, try to get a tried table collision address. This returns // First, try to get a tried table collision address. This returns
@ -3530,8 +3529,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, CDe
if (onion_only && !addr.IsTor()) continue; if (onion_only && !addr.IsTor()) continue;
// only consider very recently tried nodes after 30 failed attempts // only consider very recently tried nodes after 30 failed attempts
if (nANow - addr_last_try < 600 && nTries < 30) if (current_time - addr_last_try < 10min && nTries < 30) {
continue; continue;
}
// for non-feelers, require all the services we'll want, // for non-feelers, require all the services we'll want,
// for feelers, only require they be a full node (only because most // for feelers, only require they be a full node (only because most
@ -3754,7 +3754,7 @@ void CConnman::ThreadOpenMasternodeConnections(CDeterministicMNManager& dmnman,
// we probably connected to it before it became a masternode // we probably connected to it before it became a masternode
// or maybe we are still waiting for mnauth // or maybe we are still waiting for mnauth
(void)ForNode(addr2, [&](CNode* pnode) { (void)ForNode(addr2, [&](CNode* pnode) {
if (pnode->nTimeFirstMessageReceived != 0 && GetTimeSeconds() - pnode->nTimeFirstMessageReceived > 5) { if (pnode->nTimeFirstMessageReceived.load() != 0s && GetTime<std::chrono::seconds>() - pnode->nTimeFirstMessageReceived.load() > 5s) {
// clearly not expecting mnauth to take that long even if it wasn't the first message // clearly not expecting mnauth to take that long even if it wasn't the first message
// we received (as it should normally), disconnect // we received (as it should normally), disconnect
LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- dropping non-mnauth connection to %s, service=%s\n", _func_, proRegTxHash.ToString(), addr2.ToStringAddrPort()); LogPrint(BCLog::NET_NETCONN, "CConnman::%s -- dropping non-mnauth connection to %s, service=%s\n", _func_, proRegTxHash.ToString(), addr2.ToStringAddrPort());

View File

@ -766,7 +766,7 @@ public:
const std::chrono::seconds m_connected; const std::chrono::seconds m_connected;
std::atomic<int64_t> nTimeOffset{0}; std::atomic<int64_t> nTimeOffset{0};
std::atomic<int64_t> nLastWarningTime{0}; std::atomic<int64_t> nLastWarningTime{0};
std::atomic<int64_t> nTimeFirstMessageReceived{0}; std::atomic<std::chrono::seconds> nTimeFirstMessageReceived{0s};
std::atomic<bool> fFirstMessageIsMNAUTH{false}; std::atomic<bool> fFirstMessageIsMNAUTH{false};
// Address of this peer // Address of this peer
const CAddress addr; const CAddress addr;

View File

@ -28,6 +28,7 @@
#include <reverse_iterator.h> #include <reverse_iterator.h>
#include <scheduler.h> #include <scheduler.h>
#include <streams.h> #include <streams.h>
#include <timedata.h>
#include <tinyformat.h> #include <tinyformat.h>
#include <index/txindex.h> #include <index/txindex.h>
#include <txmempool.h> #include <txmempool.h>
@ -156,6 +157,8 @@ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24h}; static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24h};
/** Average delay between peer address broadcasts */ /** Average delay between peer address broadcasts */
static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL{30s}; static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL{30s};
/** Delay between rotating the peers we relay a particular address to */
static constexpr auto ROTATE_ADDR_RELAY_DEST_INTERVAL{24h};
/** Average delay between trickled inventory transmissions for inbound peers. /** Average delay between trickled inventory transmissions for inbound peers.
* Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */ * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */
static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s}; static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s};
@ -2462,7 +2465,10 @@ void PeerManagerImpl::RelayAddress(NodeId originator,
// Use deterministic randomness to send to the same nodes for 24 hours // Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the m_addr_knowns of the chosen nodes prevent repeats // at a time so the m_addr_knowns of the chosen nodes prevent repeats
const uint64_t hashAddr{addr.GetHash()}; const uint64_t hashAddr{addr.GetHash()};
const CSipHasher hasher{m_connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr).Write((GetTime() + hashAddr) / (24 * 60 * 60))}; const auto current_time{GetTime<std::chrono::seconds>()};
// Adding address hash makes exact rotation time different per address, while preserving periodicity.
const uint64_t time_addr{(static_cast<uint64_t>(count_seconds(current_time)) + hashAddr) / count_seconds(ROTATE_ADDR_RELAY_DEST_INTERVAL)};
const CSipHasher hasher{m_connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr).Write(time_addr)};
FastRandomContext insecure_rand; FastRandomContext insecure_rand;
// Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers. // Relay reachable addresses to 2 peers. Unreachable addresses are relayed randomly to 1 or 2 peers.
@ -3690,7 +3696,7 @@ void PeerManagerImpl::ProcessMessage(
// indicate to the peer that we will participate in addr relay. // indicate to the peer that we will participate in addr relay.
if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload()) if (fListen && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
{ {
CAddress addr{GetLocalAddress(pfrom), peer->m_our_services, (uint32_t)GetAdjustedTime()}; CAddress addr{GetLocalAddress(pfrom), peer->m_our_services, Now<NodeSeconds>()};
FastRandomContext insecure_rand; FastRandomContext insecure_rand;
if (addr.IsRoutable()) if (addr.IsRoutable())
{ {
@ -3931,9 +3937,9 @@ void PeerManagerImpl::ProcessMessage(
return; return;
} }
if (pfrom.nTimeFirstMessageReceived == 0) { if (pfrom.nTimeFirstMessageReceived.load() == 0s) {
// First message after VERSION/VERACK // First message after VERSION/VERACK
pfrom.nTimeFirstMessageReceived = GetTimeSeconds(); pfrom.nTimeFirstMessageReceived = GetTime<std::chrono::seconds>();
pfrom.fFirstMessageIsMNAUTH = msg_type == NetMsgType::MNAUTH; pfrom.fFirstMessageIsMNAUTH = msg_type == NetMsgType::MNAUTH;
// Note: do not break the flow here // Note: do not break the flow here
@ -3977,8 +3983,7 @@ void PeerManagerImpl::ProcessMessage(
// Store the new addresses // Store the new addresses
std::vector<CAddress> vAddrOk; std::vector<CAddress> vAddrOk;
int64_t nNow = GetAdjustedTime(); const auto current_a_time{Now<NodeSeconds>()};
int64_t nSince = nNow - 10 * 60;
// Update/increment addr rate limiting bucket. // Update/increment addr rate limiting bucket.
const auto current_time{GetTime<std::chrono::microseconds>()}; const auto current_time{GetTime<std::chrono::microseconds>()};
@ -4014,8 +4019,9 @@ void PeerManagerImpl::ProcessMessage(
if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices)) if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices))
continue; continue;
if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) if (addr.nTime <= NodeSeconds{100000000s} || addr.nTime > current_a_time + 10min) {
addr.nTime = nNow - 5 * 24 * 60 * 60; addr.nTime = current_a_time - 5 * 24h;
}
AddAddressKnown(*peer, addr); AddAddressKnown(*peer, addr);
if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) { if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) {
// Do not process banned/discouraged addresses beyond remembering we received them // Do not process banned/discouraged addresses beyond remembering we received them
@ -4023,7 +4029,7 @@ void PeerManagerImpl::ProcessMessage(
} }
++num_proc; ++num_proc;
bool fReachable = IsReachable(addr); bool fReachable = IsReachable(addr);
if (addr.nTime > nSince && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) { if (addr.nTime > current_a_time - 10min && !peer->m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {
// Relay to a limited number of other nodes // Relay to a limited number of other nodes
RelayAddress(pfrom.GetId(), addr, fReachable); RelayAddress(pfrom.GetId(), addr, fReachable);
} }
@ -4036,7 +4042,7 @@ void PeerManagerImpl::ProcessMessage(
LogPrint(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n", LogPrint(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n",
vAddr.size(), num_proc, num_rate_limit, pfrom.GetId()); vAddr.size(), num_proc, num_rate_limit, pfrom.GetId());
m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60); m_addrman.Add(vAddrOk, pfrom.addr, 2h);
if (vAddr.size() < 1000) peer->m_getaddr_sent = false; if (vAddr.size() < 1000) peer->m_getaddr_sent = false;
// AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements // AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements
@ -5662,7 +5668,7 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
peer.m_addr_known->reset(); peer.m_addr_known->reset();
} }
if (std::optional<CService> local_service = GetLocalAddrForPeer(node)) { if (std::optional<CService> local_service = GetLocalAddrForPeer(node)) {
CAddress local_addr{*local_service, peer.m_our_services, (uint32_t)GetAdjustedTime()}; CAddress local_addr{*local_service, peer.m_our_services, Now<NodeSeconds>()};
FastRandomContext insecure_rand; FastRandomContext insecure_rand;
PushAddress(peer, local_addr, insecure_rand); PushAddress(peer, local_addr, insecure_rand);
} }

View File

@ -908,13 +908,13 @@ void ThreadImport(ChainstateManager& chainman, CDeterministicMNManager& dmnman,
// and reduce further locking overhead for cs_main in other parts of code including GUI // and reduce further locking overhead for cs_main in other parts of code including GUI
LogPrintf("Filling coin cache with masternode UTXOs...\n"); LogPrintf("Filling coin cache with masternode UTXOs...\n");
LOCK(cs_main); LOCK(cs_main);
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
auto mnList = dmnman.GetListAtChainTip(); auto mnList = dmnman.GetListAtChainTip();
mnList.ForEachMN(false, [&](auto& dmn) { mnList.ForEachMN(false, [&](auto& dmn) {
Coin coin; Coin coin;
GetUTXOCoin(chainman.ActiveChainstate(), dmn.collateralOutpoint, coin); GetUTXOCoin(chainman.ActiveChainstate(), dmn.collateralOutpoint, coin);
}); });
LogPrintf("Filling coin cache with masternode UTXOs: done in %dms\n", GetTimeMillis() - nStart); LogPrintf("Filling coin cache with masternode UTXOs: done in %dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} }
if (mn_activeman != nullptr) { if (mn_activeman != nullptr) {

View File

@ -43,7 +43,6 @@
#include <shutdown.h> #include <shutdown.h>
#include <support/allocators/secure.h> #include <support/allocators/secure.h>
#include <sync.h> #include <sync.h>
#include <timedata.h>
#include <txmempool.h> #include <txmempool.h>
#include <uint256.h> #include <uint256.h>
#include <util/check.h> #include <util/check.h>

View File

@ -3,10 +3,6 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef __cplusplus
#error This header can only be compiled as C++.
#endif
#ifndef BITCOIN_PROTOCOL_H #ifndef BITCOIN_PROTOCOL_H
#define BITCOIN_PROTOCOL_H #define BITCOIN_PROTOCOL_H
@ -15,13 +11,11 @@
#include <serialize.h> #include <serialize.h>
#include <streams.h> #include <streams.h>
#include <uint256.h> #include <uint256.h>
#include <version.h>
#include <util/expected.h> #include <util/expected.h>
#include <util/time.h>
#include <cstdint>
#include <limits> #include <limits>
#include <stdint.h>
#include <string> #include <string>
/** Message header. /** Message header.
@ -404,7 +398,7 @@ static inline bool MayHaveUsefulAddressDB(ServiceFlags services)
/** A CService with information about it as peer */ /** A CService with information about it as peer */
class CAddress : public CService class CAddress : public CService
{ {
static constexpr uint32_t TIME_INIT{100000000}; static constexpr std::chrono::seconds TIME_INIT{100000000};
/** Historically, CAddress disk serialization stored the CLIENT_VERSION, optionally OR'ed with /** Historically, CAddress disk serialization stored the CLIENT_VERSION, optionally OR'ed with
* the ADDRV2_FORMAT flag to indicate V2 serialization. The first field has since been * the ADDRV2_FORMAT flag to indicate V2 serialization. The first field has since been
@ -434,7 +428,7 @@ class CAddress : public CService
public: public:
CAddress() : CService{} {}; CAddress() : CService{} {};
explicit CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {}; explicit CAddress(CService ipIn, ServiceFlags nServicesIn) : CService{ipIn}, nServices{nServicesIn} {};
CAddress(CService ipIn, ServiceFlags nServicesIn, uint32_t nTimeIn) : CService{ipIn}, nTime{nTimeIn}, nServices{nServicesIn} {}; CAddress(CService ipIn, ServiceFlags nServicesIn, NodeSeconds time) : CService{ipIn}, nTime{time}, nServices{nServicesIn} {};
SERIALIZE_METHODS(CAddress, obj) SERIALIZE_METHODS(CAddress, obj)
{ {
@ -467,8 +461,7 @@ public:
use_v2 = s.GetVersion() & ADDRV2_FORMAT; use_v2 = s.GetVersion() & ADDRV2_FORMAT;
} }
SER_READ(obj, obj.nTime = TIME_INIT); READWRITE(Using<LossyChronoFormatter<uint32_t>>(obj.nTime));
READWRITE(obj.nTime);
// nServices is serialized as CompactSize in V2; as uint64_t in V1. // nServices is serialized as CompactSize in V2; as uint64_t in V1.
if (use_v2) { if (use_v2) {
uint64_t services_tmp; uint64_t services_tmp;
@ -483,8 +476,8 @@ public:
SerReadWriteMany(os, ser_action, ReadWriteAsHelper<CService>(obj)); SerReadWriteMany(os, ser_action, ReadWriteAsHelper<CService>(obj));
} }
//! Always included in serialization. //! Always included in serialization. The behavior is unspecified if the value is not representable as uint32_t.
uint32_t nTime{TIME_INIT}; NodeSeconds nTime{TIME_INIT};
//! Serialized as uint64_t in V1, and as CompactSize in V2. //! Serialized as uint64_t in V1, and as CompactSize in V2.
ServiceFlags nServices{NODE_NONE}; ServiceFlags nServices{NODE_NONE};

View File

@ -24,6 +24,7 @@
#include <timedata.h> #include <timedata.h>
#include <util/strencodings.h> #include <util/strencodings.h>
#include <util/string.h> #include <util/string.h>
#include <util/time.h>
#include <util/translation.h> #include <util/translation.h>
#include <validation.h> #include <validation.h>
#include <version.h> #include <version.h>
@ -968,7 +969,7 @@ static RPCHelpMan getnodeaddresses()
for (const CAddress& addr : vAddr) { for (const CAddress& addr : vAddr) {
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.pushKV("time", (int)addr.nTime); obj.pushKV("time", int64_t{TicksSinceEpoch<std::chrono::seconds>(addr.nTime)});
obj.pushKV("services", (uint64_t)addr.nServices); obj.pushKV("services", (uint64_t)addr.nServices);
obj.pushKV("address", addr.ToStringAddr()); obj.pushKV("address", addr.ToStringAddr());
obj.pushKV("port", addr.GetPort()); obj.pushKV("port", addr.GetPort());
@ -1017,7 +1018,7 @@ static RPCHelpMan addpeeraddress()
if (net_addr.has_value()) { if (net_addr.has_value()) {
CAddress address{{net_addr.value(), port}, ServiceFlags{NODE_NETWORK}}; CAddress address{{net_addr.value(), port}, ServiceFlags{NODE_NETWORK}};
address.nTime = GetAdjustedTime(); address.nTime = Now<NodeSeconds>();
// The source address is set equal to the address. This is equivalent to the peer // The source address is set equal to the address. This is equivalent to the peer
// announcing itself. // announcing itself.
if (node.addrman->Add({address}, address)) { if (node.addrman->Add({address}, address)) {

View File

@ -16,13 +16,15 @@
#include <util/strencodings.h> #include <util/strencodings.h>
#include <util/string.h> #include <util/string.h>
#include <util/system.h> #include <util/system.h>
#include <util/time.h>
#include <boost/signals2/signal.hpp> #include <boost/signals2/signal.hpp>
#include <algorithm> #include <algorithm>
#include <atomic> #include <atomic>
#include <cassert> #include <cassert>
#include <memory> // for unique_ptr #include <chrono>
#include <memory>
#include <mutex> #include <mutex>
#include <unordered_map> #include <unordered_map>
@ -43,7 +45,7 @@ static const std::string defaultPlatformUser = "platform-user";
struct RPCCommandExecutionInfo struct RPCCommandExecutionInfo
{ {
std::string method; std::string method;
int64_t start; SteadyClock::time_point start;
}; };
struct RPCServerInfo struct RPCServerInfo
@ -60,7 +62,7 @@ struct RPCCommandExecution
explicit RPCCommandExecution(const std::string& method) explicit RPCCommandExecution(const std::string& method)
{ {
LOCK(g_rpc_server_info.mutex); LOCK(g_rpc_server_info.mutex);
it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, GetTimeMicros()}); it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.end(), {method, SteadyClock::now()});
} }
~RPCCommandExecution() ~RPCCommandExecution()
{ {
@ -272,7 +274,7 @@ static RPCHelpMan getrpcinfo()
for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) { for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) {
UniValue entry(UniValue::VOBJ); UniValue entry(UniValue::VOBJ);
entry.pushKV("method", info.method); entry.pushKV("method", info.method);
entry.pushKV("duration", GetTimeMicros() - info.start); entry.pushKV("duration", int64_t{Ticks<std::chrono::microseconds>(SteadyClock::now() - info.start)});
active_commands.push_back(entry); active_commands.push_back(entry);
} }

View File

@ -4,10 +4,10 @@
#include <scheduler.h> #include <scheduler.h>
#include <random.h> #include <sync.h>
#include <util/time.h> #include <util/time.h>
#include <assert.h> #include <cassert>
#include <functional> #include <functional>
#include <utility> #include <utility>
@ -41,7 +41,7 @@ void CScheduler::serviceQueue()
// the time of the first item on the queue: // the time of the first item on the queue:
while (!shouldStop() && !taskQueue.empty()) { while (!shouldStop() && !taskQueue.empty()) {
std::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; std::chrono::steady_clock::time_point timeToWaitFor = taskQueue.begin()->first;
if (newTaskScheduled.wait_until(lock, timeToWaitFor) == std::cv_status::timeout) { if (newTaskScheduled.wait_until(lock, timeToWaitFor) == std::cv_status::timeout) {
break; // Exit loop after timeout, it means we reached the time of the event break; // Exit loop after timeout, it means we reached the time of the event
} }
@ -70,7 +70,7 @@ void CScheduler::serviceQueue()
newTaskScheduled.notify_one(); newTaskScheduled.notify_one();
} }
void CScheduler::schedule(CScheduler::Function f, std::chrono::system_clock::time_point t) void CScheduler::schedule(CScheduler::Function f, std::chrono::steady_clock::time_point t)
{ {
{ {
LOCK(newTaskMutex); LOCK(newTaskMutex);
@ -87,7 +87,7 @@ void CScheduler::MockForward(std::chrono::seconds delta_seconds)
LOCK(newTaskMutex); LOCK(newTaskMutex);
// use temp_queue to maintain updated schedule // use temp_queue to maintain updated schedule
std::multimap<std::chrono::system_clock::time_point, Function> temp_queue; std::multimap<std::chrono::steady_clock::time_point, Function> temp_queue;
for (const auto& element : taskQueue) { for (const auto& element : taskQueue) {
temp_queue.emplace_hint(temp_queue.cend(), element.first - delta_seconds, element.second); temp_queue.emplace_hint(temp_queue.cend(), element.first - delta_seconds, element.second);
@ -112,8 +112,8 @@ void CScheduler::scheduleEvery(CScheduler::Function f, std::chrono::milliseconds
scheduleFromNow([this, f, delta] { Repeat(*this, f, delta); }, delta); scheduleFromNow([this, f, delta] { Repeat(*this, f, delta); }, delta);
} }
size_t CScheduler::getQueueInfo(std::chrono::system_clock::time_point& first, size_t CScheduler::getQueueInfo(std::chrono::steady_clock::time_point& first,
std::chrono::system_clock::time_point& last) const std::chrono::steady_clock::time_point& last) const
{ {
LOCK(newTaskMutex); LOCK(newTaskMutex);
size_t result = taskQueue.size(); size_t result = taskQueue.size();
@ -141,7 +141,7 @@ void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue()
if (m_are_callbacks_running) return; if (m_are_callbacks_running) return;
if (m_callbacks_pending.empty()) return; if (m_callbacks_pending.empty()) return;
} }
m_scheduler.schedule([this] { this->ProcessQueue(); }, std::chrono::system_clock::now()); m_scheduler.schedule([this] { this->ProcessQueue(); }, std::chrono::steady_clock::now());
} }
void SingleThreadedSchedulerClient::ProcessQueue() void SingleThreadedSchedulerClient::ProcessQueue()

View File

@ -46,12 +46,12 @@ public:
typedef std::function<void()> Function; typedef std::function<void()> Function;
/** Call func at/after time t */ /** Call func at/after time t */
void schedule(Function f, std::chrono::system_clock::time_point t) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); void schedule(Function f, std::chrono::steady_clock::time_point t) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex);
/** Call f once after the delta has passed */ /** Call f once after the delta has passed */
void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex) void scheduleFromNow(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
{ {
schedule(std::move(f), std::chrono::system_clock::now() + delta); schedule(std::move(f), std::chrono::steady_clock::now() + delta);
} }
/** /**
@ -93,8 +93,8 @@ public:
* Returns number of tasks waiting to be serviced, * Returns number of tasks waiting to be serviced,
* and first and last task times * and first and last task times
*/ */
size_t getQueueInfo(std::chrono::system_clock::time_point& first, size_t getQueueInfo(std::chrono::steady_clock::time_point& first,
std::chrono::system_clock::time_point& last) const std::chrono::steady_clock::time_point& last) const
EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex); EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex);
/** Returns true if there are threads actively running in serviceQueue() */ /** Returns true if there are threads actively running in serviceQueue() */
@ -103,7 +103,7 @@ public:
private: private:
mutable Mutex newTaskMutex; mutable Mutex newTaskMutex;
std::condition_variable newTaskScheduled; std::condition_variable newTaskScheduled;
std::multimap<std::chrono::system_clock::time_point, Function> taskQueue GUARDED_BY(newTaskMutex); std::multimap<std::chrono::steady_clock::time_point, Function> taskQueue GUARDED_BY(newTaskMutex);
int nThreadsServicingQueue GUARDED_BY(newTaskMutex){0}; int nThreadsServicingQueue GUARDED_BY(newTaskMutex){0};
bool stopRequested GUARDED_BY(newTaskMutex){false}; bool stopRequested GUARDED_BY(newTaskMutex){false};
bool stopWhenEmpty GUARDED_BY(newTaskMutex){false}; bool stopWhenEmpty GUARDED_BY(newTaskMutex){false};

View File

@ -704,6 +704,29 @@ struct CompactSizeFormatter
} }
}; };
template <typename U, bool LOSSY = false>
struct ChronoFormatter {
template <typename Stream, typename Tp>
void Unser(Stream& s, Tp& tp)
{
U u;
s >> u;
// Lossy deserialization does not make sense, so force Wnarrowing
tp = Tp{typename Tp::duration{typename Tp::duration::rep{u}}};
}
template <typename Stream, typename Tp>
void Ser(Stream& s, Tp tp)
{
if constexpr (LOSSY) {
s << U(tp.time_since_epoch().count());
} else {
s << U{tp.time_since_epoch().count()};
}
}
};
template <typename U>
using LossyChronoFormatter = ChronoFormatter<U, true>;
template<size_t Limit> template<size_t Limit>
struct LimitedStringFormatter struct LimitedStringFormatter
{ {

View File

@ -309,7 +309,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{ {
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)); auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)}; CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
int64_t start_time{GetAdjustedTime()}; const auto start_time{Now<NodeSeconds>()};
addr.nTime = start_time; addr.nTime = start_time;
// test that multiplicity stays at 1 if nTime doesn't increase // test that multiplicity stays at 1 if nTime doesn't increase
@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
for (unsigned int i = 1; i < 400; ++i) { for (unsigned int i = 1; i < 400; ++i) {
std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"}; std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
CNetAddr source{ResolveIP(addr_ip)}; CNetAddr source{ResolveIP(addr_ip)};
addr.nTime = start_time + i; addr.nTime = start_time + std::chrono::seconds{i};
addrman->Add({addr}, source); addrman->Add({addr}, source);
} }
AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value(); AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
@ -379,15 +379,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
BOOST_CHECK_EQUAL(vAddr1.size(), 0U); BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE); CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false addr1.nTime = Now<NodeSeconds>(); // Set time so isTerrible = false
CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE); CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
addr2.nTime = GetAdjustedTime(); addr2.nTime = Now<NodeSeconds>();
CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE); CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
addr3.nTime = GetAdjustedTime(); addr3.nTime = Now<NodeSeconds>();
CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE); CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
addr4.nTime = GetAdjustedTime(); addr4.nTime = Now<NodeSeconds>();
CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE); CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
addr5.nTime = GetAdjustedTime(); addr5.nTime = Now<NodeSeconds>();
CNetAddr source1 = ResolveIP("250.1.2.1"); CNetAddr source1 = ResolveIP("250.1.2.1");
CNetAddr source2 = ResolveIP("250.2.3.3"); CNetAddr source2 = ResolveIP("250.2.3.3");
@ -413,7 +413,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr)
CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE); CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
// Ensure that for all addrs in addrman, isTerrible == false. // Ensure that for all addrs in addrman, isTerrible == false.
addr.nTime = GetAdjustedTime(); addr.nTime = Now<NodeSeconds>();
addrman->Add({addr}, ResolveIP(strAddr)); addrman->Add({addr}, ResolveIP(strAddr));
if (i % 8 == 0) if (i % 8 == 0)
addrman->Good(addr); addrman->Good(addr);
@ -905,8 +905,8 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks)
// Ensure test of address fails, so that it is evicted. // Ensure test of address fails, so that it is evicted.
// Update entry in tried by setting last good connection in the deep past. // Update entry in tried by setting last good connection in the deep past.
BOOST_CHECK(!addrman->Good(info, /*nTime=*/1)); BOOST_CHECK(!addrman->Good(info, NodeSeconds{1s}));
addrman->Attempt(info, /*fCountFailure=*/false, /*nTime=*/GetAdjustedTime() - 61); addrman->Attempt(info, /*fCountFailure=*/false, Now<NodeSeconds>() - 61s);
// Should swap 36 for 19. // Should swap 36 for 19.
addrman->ResolveCollisions(); addrman->ResolveCollisions();
@ -1053,7 +1053,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
CNetAddr source{ResolveIP("252.2.2.2")}; CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)}; CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
int64_t start_time{GetAdjustedTime() - 10000}; const auto start_time{Now<NodeSeconds>() - 10000s};
addr.nTime = start_time; addr.nTime = start_time;
BOOST_CHECK(addrman->Add({addr}, source)); BOOST_CHECK(addrman->Add({addr}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 1U); BOOST_CHECK_EQUAL(addrman->Size(), 1U);
@ -1065,7 +1065,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED); addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr1{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)}; std::vector<CAddress> vAddr1{addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt)};
BOOST_CHECK_EQUAL(vAddr1.size(), 1U); BOOST_CHECK_EQUAL(vAddr1.size(), 1U);
BOOST_CHECK_EQUAL(vAddr1.at(0).nTime, start_time); BOOST_CHECK(vAddr1.at(0).nTime == start_time);
BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE); BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE);
// Updating an addrman entry with the correct port is successful // Updating an addrman entry with the correct port is successful
@ -1073,7 +1073,7 @@ BOOST_AUTO_TEST_CASE(addrman_update_address)
addrman->SetServices(addr, NODE_NETWORK_LIMITED); addrman->SetServices(addr, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr2 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt); std::vector<CAddress> vAddr2 = addrman->GetAddr(/*max_addresses=*/0, /*max_pct=*/0, /*network=*/std::nullopt);
BOOST_CHECK_EQUAL(vAddr2.size(), 1U); BOOST_CHECK_EQUAL(vAddr2.size(), 1U);
BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000); BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000s);
BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED); BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
} }

View File

@ -114,11 +114,11 @@ void FillAddrman(AddrMan& addrman, FuzzedDataProvider& fuzzed_data_provider)
for (size_t j = 0; j < num_addresses; ++j) { for (size_t j = 0; j < num_addresses; ++j) {
const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK}; const auto addr = CAddress{CService{RandAddr(fuzzed_data_provider, fast_random_context), 8333}, NODE_NETWORK};
const auto time_penalty = fast_random_context.randrange(100000001); const std::chrono::seconds time_penalty{fast_random_context.randrange(100000001)};
addrman.Add({addr}, source, time_penalty); addrman.Add({addr}, source, time_penalty);
if (n > 0 && addrman.Size() % n == 0) { if (n > 0 && addrman.Size() % n == 0) {
addrman.Good(addr, GetTime()); addrman.Good(addr, Now<NodeSeconds>());
} }
// Add 10% of the addresses from more than one source. // Add 10% of the addresses from more than one source.
@ -162,7 +162,7 @@ public:
CSipHasher hasher(0, 0); CSipHasher hasher(0, 0);
auto addr_key = a.GetKey(); auto addr_key = a.GetKey();
auto source_key = a.source.GetAddrBytes(); auto source_key = a.source.GetAddrBytes();
hasher.Write(a.nLastSuccess); hasher.Write(TicksSinceEpoch<std::chrono::seconds>(a.m_last_success));
hasher.Write(a.nAttempts); hasher.Write(a.nAttempts);
hasher.Write(a.nRefCount); hasher.Write(a.nRefCount);
hasher.Write(a.fInTried); hasher.Write(a.fInTried);
@ -176,8 +176,8 @@ public:
}; };
auto addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) { auto addrinfo_eq = [](const AddrInfo& lhs, const AddrInfo& rhs) {
return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.nLastSuccess, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) == return std::tie(static_cast<const CService&>(lhs), lhs.source, lhs.m_last_success, lhs.nAttempts, lhs.nRefCount, lhs.fInTried) ==
std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.nLastSuccess, rhs.nAttempts, rhs.nRefCount, rhs.fInTried); std::tie(static_cast<const CService&>(rhs), rhs.source, rhs.m_last_success, rhs.nAttempts, rhs.nRefCount, rhs.fInTried);
}; };
using Addresses = std::unordered_set<AddrInfo, decltype(addrinfo_hasher), decltype(addrinfo_eq)>; using Addresses = std::unordered_set<AddrInfo, decltype(addrinfo_hasher), decltype(addrinfo_eq)>;
@ -279,25 +279,25 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
} }
const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider); const std::optional<CNetAddr> opt_net_addr = ConsumeDeserializable<CNetAddr>(fuzzed_data_provider);
if (opt_net_addr) { if (opt_net_addr) {
addr_man.Add(addresses, *opt_net_addr, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, 100000000)); addr_man.Add(addresses, *opt_net_addr, std::chrono::seconds{ConsumeTime(fuzzed_data_provider, 0, 100000000)});
} }
}, },
[&] { [&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) { if (opt_service) {
addr_man.Good(*opt_service, ConsumeTime(fuzzed_data_provider)); addr_man.Good(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
} }
}, },
[&] { [&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) { if (opt_service) {
addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), ConsumeTime(fuzzed_data_provider)); addr_man.Attempt(*opt_service, fuzzed_data_provider.ConsumeBool(), NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
} }
}, },
[&] { [&] {
const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider); const std::optional<CService> opt_service = ConsumeDeserializable<CService>(fuzzed_data_provider);
if (opt_service) { if (opt_service) {
addr_man.Connected(*opt_service, ConsumeTime(fuzzed_data_provider)); addr_man.Connected(*opt_service, NodeSeconds{std::chrono::seconds{ConsumeTime(fuzzed_data_provider)}});
} }
}, },
[&] { [&] {

View File

@ -188,7 +188,7 @@ int main(int argc, char** argv)
return 0; return 0;
} }
std::signal(SIGABRT, signal_handler); std::signal(SIGABRT, signal_handler);
int64_t start_time = GetTimeSeconds(); const auto start_time{Now<SteadySeconds>()};
int tested = 0; int tested = 0;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
fs::path input_path(*(argv + i)); fs::path input_path(*(argv + i));
@ -209,8 +209,8 @@ int main(int argc, char** argv)
buffer.clear(); buffer.clear();
} }
} }
int64_t end_time = GetTimeSeconds(); const auto end_time{Now<SteadySeconds>()};
std::cout << g_fuzz_target << ": succeeded against " << tested << " files in " << (end_time - start_time) << "s." << std::endl; std::cout << g_fuzz_target << ": succeeded against " << tested << " files in " << count_seconds(end_time - start_time) << "s." << std::endl;
#endif #endif
return 0; return 0;
} }

View File

@ -390,6 +390,11 @@ bool ContainsSpentInput(const CTransaction& tx, const CCoinsViewCache& inputs) n
return false; return false;
} }
CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept
{
return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), NodeSeconds{std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}}};
}
FILE* FuzzedFileProvider::open() FILE* FuzzedFileProvider::open()
{ {
SetFuzzedErrNo(m_fuzzed_data_provider); SetFuzzedErrNo(m_fuzzed_data_provider);

View File

@ -307,10 +307,7 @@ inline CService ConsumeService(FuzzedDataProvider& fuzzed_data_provider) noexcep
return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()}; return {ConsumeNetAddr(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<uint16_t>()};
} }
inline CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept CAddress ConsumeAddress(FuzzedDataProvider& fuzzed_data_provider) noexcept;
{
return {ConsumeService(fuzzed_data_provider), ConsumeWeakEnum(fuzzed_data_provider, ALL_SERVICE_FLAGS), fuzzed_data_provider.ConsumeIntegral<uint32_t>()};
}
template <bool ReturnUniquePtr = false> template <bool ReturnUniquePtr = false>
auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept auto ConsumeNode(FuzzedDataProvider& fuzzed_data_provider, const std::optional<NodeId>& node_id_in = std::nullopt) noexcept

View File

@ -670,9 +670,6 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
const uint16_t bind_port = 20001; const uint16_t bind_port = 20001;
m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port)); m_node.args->ForceSetArg("-bind", strprintf("3.4.5.6:%u", bind_port));
const uint32_t current_time = static_cast<uint32_t>(GetAdjustedTime());
SetMockTime(current_time);
// Our address:port as seen from the peer, completely different from the above. // Our address:port as seen from the peer, completely different from the above.
in_addr peer_us_addr; in_addr peer_us_addr;
peer_us_addr.s_addr = htonl(0x02030405); peer_us_addr.s_addr = htonl(0x02030405);
@ -696,7 +693,7 @@ BOOST_AUTO_TEST_CASE(get_local_addr_for_peer_port)
// Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port. // Without the fix peer_us:8333 is chosen instead of the proper peer_us:bind_port.
auto chosen_local_addr = GetLocalAddrForPeer(peer_out); auto chosen_local_addr = GetLocalAddrForPeer(peer_out);
BOOST_REQUIRE(chosen_local_addr); BOOST_REQUIRE(chosen_local_addr);
const CAddress expected{CService{peer_us_addr, bind_port}, NODE_NETWORK, current_time}; const CService expected{peer_us_addr, bind_port};
BOOST_CHECK(*chosen_local_addr == expected); BOOST_CHECK(*chosen_local_addr == expected);
// Create a peer with a routable IPv4 address (inbound). // Create a peer with a routable IPv4 address (inbound).

View File

@ -337,21 +337,21 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
// try a few edge cases for port, service flags and time. // try a few edge cases for port, service flags and time.
static const std::vector<CAddress> fixture_addresses({ static const std::vector<CAddress> fixture_addresses({
CAddress( CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0 /* port */), CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0 /* port */),
NODE_NONE, NODE_NONE,
0x4966bc61U /* Fri Jan 9 02:54:25 UTC 2009 */ NodeSeconds{0x4966bc61s}, /* Fri Jan 9 02:54:25 UTC 2009 */
), },
CAddress( CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0x00f1 /* port */), CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0x00f1 /* port */),
NODE_NETWORK, NODE_NETWORK,
0x83766279U /* Tue Nov 22 11:22:33 UTC 2039 */ NodeSeconds{0x83766279s}, /* Tue Nov 22 11:22:33 UTC 2039 */
), },
CAddress( CAddress{
CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0xf1f2 /* port */), CService(CNetAddr(in6_addr(IN6ADDR_LOOPBACK_INIT)), 0xf1f2 /* port */),
static_cast<ServiceFlags>(NODE_NETWORK_LIMITED), static_cast<ServiceFlags>(NODE_NETWORK_LIMITED),
0xffffffffU /* Sun Feb 7 06:28:15 UTC 2106 */ NodeSeconds{0xffffffffs}, /* Sun Feb 7 06:28:15 UTC 2106 */
) },
}); });
// fixture_addresses should equal to this when serialized in V1 format. // fixture_addresses should equal to this when serialized in V1 format.

View File

@ -15,13 +15,13 @@
BOOST_AUTO_TEST_SUITE(scheduler_tests) BOOST_AUTO_TEST_SUITE(scheduler_tests)
static void microTask(CScheduler& s, std::mutex& mutex, int& counter, int delta, std::chrono::system_clock::time_point rescheduleTime) static void microTask(CScheduler& s, std::mutex& mutex, int& counter, int delta, std::chrono::steady_clock::time_point rescheduleTime)
{ {
{ {
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
counter += delta; counter += delta;
} }
std::chrono::system_clock::time_point noTime = std::chrono::system_clock::time_point::min(); auto noTime = std::chrono::steady_clock::time_point::min();
if (rescheduleTime != noTime) { if (rescheduleTime != noTime) {
CScheduler::Function f = std::bind(&microTask, std::ref(s), std::ref(mutex), std::ref(counter), -delta + 1, noTime); CScheduler::Function f = std::bind(&microTask, std::ref(s), std::ref(mutex), std::ref(counter), -delta + 1, noTime);
s.schedule(f, rescheduleTime); s.schedule(f, rescheduleTime);
@ -49,15 +49,15 @@ BOOST_AUTO_TEST_CASE(manythreads)
auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000] auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000]
auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000] auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000]
std::chrono::system_clock::time_point start = std::chrono::system_clock::now(); auto start = std::chrono::steady_clock::now();
std::chrono::system_clock::time_point now = start; auto now = start;
std::chrono::system_clock::time_point first, last; std::chrono::steady_clock::time_point first, last;
size_t nTasks = microTasks.getQueueInfo(first, last); size_t nTasks = microTasks.getQueueInfo(first, last);
BOOST_CHECK(nTasks == 0); BOOST_CHECK(nTasks == 0);
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
std::chrono::system_clock::time_point t = now + std::chrono::microseconds(randomMsec(rng)); auto t = now + std::chrono::microseconds(randomMsec(rng));
std::chrono::system_clock::time_point tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng)); auto tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng));
int whichCounter = zeroToNine(rng); int whichCounter = zeroToNine(rng);
CScheduler::Function f = std::bind(&microTask, std::ref(microTasks), CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),
std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]), std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),
@ -75,14 +75,14 @@ BOOST_AUTO_TEST_CASE(manythreads)
microThreads.emplace_back(std::bind(&CScheduler::serviceQueue, &microTasks)); microThreads.emplace_back(std::bind(&CScheduler::serviceQueue, &microTasks));
UninterruptibleSleep(std::chrono::microseconds{600}); UninterruptibleSleep(std::chrono::microseconds{600});
now = std::chrono::system_clock::now(); now = std::chrono::steady_clock::now();
// More threads and more tasks: // More threads and more tasks:
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
microThreads.emplace_back(std::bind(&CScheduler::serviceQueue, &microTasks)); microThreads.emplace_back(std::bind(&CScheduler::serviceQueue, &microTasks));
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
std::chrono::system_clock::time_point t = now + std::chrono::microseconds(randomMsec(rng)); auto t = now + std::chrono::microseconds(randomMsec(rng));
std::chrono::system_clock::time_point tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng)); auto tReschedule = now + std::chrono::microseconds(500 + randomMsec(rng));
int whichCounter = zeroToNine(rng); int whichCounter = zeroToNine(rng);
CScheduler::Function f = std::bind(&microTask, std::ref(microTasks), CScheduler::Function f = std::bind(&microTask, std::ref(microTasks),
std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]), std::ref(counterMutex[whichCounter]), std::ref(counter[whichCounter]),
@ -111,8 +111,8 @@ BOOST_AUTO_TEST_CASE(wait_until_past)
Mutex mtx; Mutex mtx;
WAIT_LOCK(mtx, lock); WAIT_LOCK(mtx, lock);
const auto no_wait= [&](const std::chrono::seconds& d) { const auto no_wait = [&](const std::chrono::seconds& d) {
return condvar.wait_until(lock, std::chrono::system_clock::now() - d); return condvar.wait_until(lock, std::chrono::steady_clock::now() - d);
}; };
BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::seconds{1})); BOOST_CHECK(std::cv_status::timeout == no_wait(std::chrono::seconds{1}));
@ -184,7 +184,7 @@ BOOST_AUTO_TEST_CASE(mockforward)
scheduler.scheduleFromNow(dummy, std::chrono::minutes{8}); scheduler.scheduleFromNow(dummy, std::chrono::minutes{8});
// check taskQueue // check taskQueue
std::chrono::system_clock::time_point first, last; std::chrono::steady_clock::time_point first, last;
size_t num_tasks = scheduler.getQueueInfo(first, last); size_t num_tasks = scheduler.getQueueInfo(first, last);
BOOST_CHECK_EQUAL(num_tasks, 3ul); BOOST_CHECK_EQUAL(num_tasks, 3ul);
@ -205,7 +205,7 @@ BOOST_AUTO_TEST_CASE(mockforward)
BOOST_CHECK_EQUAL(counter, 2); BOOST_CHECK_EQUAL(counter, 2);
// check that the time of the remaining job has been updated // check that the time of the remaining job has been updated
std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); auto now = std::chrono::steady_clock::now();
int delta = std::chrono::duration_cast<std::chrono::seconds>(first - now).count(); int delta = std::chrono::duration_cast<std::chrono::seconds>(first - now).count();
// should be between 2 & 3 minutes from now // should be between 2 & 3 minutes from now
BOOST_CHECK(delta > 2*60 && delta < 3*60); BOOST_CHECK(delta > 2*60 && delta < 3*60);

View File

@ -297,9 +297,6 @@ BOOST_AUTO_TEST_CASE(util_FormatParseISO8601DateTime)
BOOST_CHECK_EQUAL(ParseISO8601DateTime("1970-01-01T00:00:00Z"), 0); BOOST_CHECK_EQUAL(ParseISO8601DateTime("1970-01-01T00:00:00Z"), 0);
BOOST_CHECK_EQUAL(ParseISO8601DateTime("1960-01-01T00:00:00Z"), 0); BOOST_CHECK_EQUAL(ParseISO8601DateTime("1960-01-01T00:00:00Z"), 0);
BOOST_CHECK_EQUAL(ParseISO8601DateTime("2011-09-30T23:36:17Z"), 1317425777); BOOST_CHECK_EQUAL(ParseISO8601DateTime("2011-09-30T23:36:17Z"), 1317425777);
auto time = GetTimeSeconds();
BOOST_CHECK_EQUAL(ParseISO8601DateTime(FormatISO8601DateTime(time)), time);
} }
BOOST_AUTO_TEST_CASE(util_FormatISO8601Date) BOOST_AUTO_TEST_CASE(util_FormatISO8601Date)
@ -1528,8 +1525,12 @@ BOOST_AUTO_TEST_CASE(util_time_GetTime)
for (const auto& num_sleep : {0ms, 1ms}) { for (const auto& num_sleep : {0ms, 1ms}) {
UninterruptibleSleep(num_sleep); UninterruptibleSleep(num_sleep);
BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter BOOST_CHECK_EQUAL(111, GetTime()); // Deprecated time getter
BOOST_CHECK_EQUAL(111, Now<NodeSeconds>().time_since_epoch().count());
BOOST_CHECK_EQUAL(111, TicksSinceEpoch<std::chrono::seconds>(NodeClock::now()));
BOOST_CHECK_EQUAL(111, TicksSinceEpoch<SecondsDouble>(Now<NodeSeconds>()));
BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count()); BOOST_CHECK_EQUAL(111, GetTime<std::chrono::seconds>().count());
BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count()); BOOST_CHECK_EQUAL(111000, GetTime<std::chrono::milliseconds>().count());
BOOST_CHECK_EQUAL(111000, TicksSinceEpoch<std::chrono::milliseconds>(NodeClock::now()));
BOOST_CHECK_EQUAL(111000000, GetTime<std::chrono::microseconds>().count()); BOOST_CHECK_EQUAL(111000000, GetTime<std::chrono::microseconds>().count());
} }

View File

@ -5,9 +5,12 @@
#ifndef BITCOIN_TIMEDATA_H #ifndef BITCOIN_TIMEDATA_H
#define BITCOIN_TIMEDATA_H #define BITCOIN_TIMEDATA_H
#include <util/time.h>
#include <algorithm> #include <algorithm>
#include <assert.h> #include <cassert>
#include <stdint.h> #include <chrono>
#include <cstdint>
#include <vector> #include <vector>
static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 70 * 60; static const int64_t DEFAULT_MAX_TIME_ADJUSTMENT = 70 * 60;

View File

@ -66,20 +66,16 @@ bool ChronoSanityCheck()
return true; return true;
} }
template <typename T> NodeClock::time_point NodeClock::now() noexcept
T GetTime()
{ {
const auto mocktime{g_mock_time.load(std::memory_order_relaxed)}; const auto mocktime{g_mock_time.load(std::memory_order_relaxed)};
const auto ret{ const auto ret{
mocktime.count() ? mocktime.count() ?
mocktime : mocktime :
std::chrono::duration_cast<T>(std::chrono::system_clock::now().time_since_epoch())}; std::chrono::system_clock::now().time_since_epoch()};
assert(ret > 0s); assert(ret > 0s);
return ret; return time_point{ret};
} };
template std::chrono::seconds GetTime();
template std::chrono::milliseconds GetTime();
template std::chrono::microseconds GetTime();
template <typename T> template <typename T>
static T GetSystemTime() static T GetSystemTime()
@ -111,11 +107,6 @@ int64_t GetTimeMicros()
return int64_t{GetSystemTime<std::chrono::microseconds>().count()}; return int64_t{GetSystemTime<std::chrono::microseconds>().count()};
} }
int64_t GetTimeSeconds()
{
return int64_t{GetSystemTime<std::chrono::seconds>().count()};
}
int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); } int64_t GetTime() { return GetTime<std::chrono::seconds>().count(); }
std::string FormatISO8601DateTime(int64_t nTime) { std::string FormatISO8601DateTime(int64_t nTime) {

View File

@ -14,6 +14,16 @@
using namespace std::chrono_literals; using namespace std::chrono_literals;
/** Mockable clock in the context of tests, otherwise the system clock */
struct NodeClock : public std::chrono::system_clock {
using time_point = std::chrono::time_point<NodeClock>;
/** Return current system time or mocked time, if set */
static time_point now() noexcept;
static std::time_t to_time_t(const time_point&) = delete; // unused
static time_point from_time_t(std::time_t) = delete; // unused
};
using NodeSeconds = std::chrono::time_point<NodeClock, std::chrono::seconds>;
using SteadyClock = std::chrono::steady_clock; using SteadyClock = std::chrono::steady_clock;
using SteadySeconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::seconds>; using SteadySeconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::seconds>;
using SteadyMilliseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds>; using SteadyMilliseconds = std::chrono::time_point<std::chrono::steady_clock, std::chrono::milliseconds>;
@ -22,19 +32,30 @@ using SteadyMicroseconds = std::chrono::time_point<std::chrono::steady_clock, st
void UninterruptibleSleep(const std::chrono::microseconds& n); void UninterruptibleSleep(const std::chrono::microseconds& n);
/** /**
* Helper to count the seconds of a duration. * Helper to count the seconds of a duration/time_point.
* *
* All durations should be using std::chrono and calling this should generally * All durations/time_points should be using std::chrono and calling this should generally
* be avoided in code. Though, it is still preferred to an inline t.count() to * be avoided in code. Though, it is still preferred to an inline t.count() to
* protect against a reliance on the exact type of t. * protect against a reliance on the exact type of t.
* *
* This helper is used to convert durations before passing them over an * This helper is used to convert durations/time_points before passing them over an
* interface that doesn't support std::chrono (e.g. RPC, debug log, or the GUI) * interface that doesn't support std::chrono (e.g. RPC, debug log, or the GUI)
*/ */
template <typename Dur1, typename Dur2>
constexpr auto Ticks(Dur2 d)
{
return std::chrono::duration_cast<Dur1>(d).count();
}
template <typename Duration, typename Timepoint>
constexpr auto TicksSinceEpoch(Timepoint t)
{
return Ticks<Duration>(t.time_since_epoch());
}
constexpr int64_t count_seconds(std::chrono::seconds t) { return t.count(); } constexpr int64_t count_seconds(std::chrono::seconds t) { return t.count(); }
constexpr int64_t count_milliseconds(std::chrono::milliseconds t) { return t.count(); } constexpr int64_t count_milliseconds(std::chrono::milliseconds t) { return t.count(); }
constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.count(); } constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.count(); }
using HoursDouble = std::chrono::duration<double, std::chrono::hours::period>;
using SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>; using SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>;
/** /**
@ -44,7 +65,11 @@ inline double CountSecondsDouble(SecondsDouble t) { return t.count(); }
/** /**
* DEPRECATED * DEPRECATED
* Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable) * Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
* ClockType is
* - std::chrono::steady_clock for steady time
* - std::chrono::system_clock for system time
* - NodeClock for mockable system time
*/ */
int64_t GetTime(); int64_t GetTime();
@ -52,8 +77,6 @@ int64_t GetTime();
int64_t GetTimeMillis(); int64_t GetTimeMillis();
/** Returns the system time (not mockable) */ /** Returns the system time (not mockable) */
int64_t GetTimeMicros(); int64_t GetTimeMicros();
/** Returns the system time (not mockable) */
int64_t GetTimeSeconds(); // Like GetTime(), but not mockable
/** /**
* DEPRECATED * DEPRECATED
@ -69,9 +92,6 @@ void SetMockTime(std::chrono::seconds mock_time_in);
/** For testing */ /** For testing */
std::chrono::seconds GetMockTime(); std::chrono::seconds GetMockTime();
/** Return system time (or mocked time, if set) */
template <typename T>
T GetTime();
/** /**
* Return the current time point cast to the given precicion. Only use this * Return the current time point cast to the given precicion. Only use this
* when an exact precicion is needed, otherwise use T::clock::now() directly. * when an exact precicion is needed, otherwise use T::clock::now() directly.
@ -81,6 +101,12 @@ T Now()
{ {
return std::chrono::time_point_cast<typename T::duration>(T::clock::now()); return std::chrono::time_point_cast<typename T::duration>(T::clock::now());
} }
/** DEPRECATED, see GetTime */
template <typename T>
T GetTime()
{
return Now<std::chrono::time_point<NodeClock, T>>().time_since_epoch();
}
/** /**
* ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date,Time} * ISO 8601 formatting is preferred. Use the FormatISO8601{DateTime,Date,Time}

View File

@ -4603,7 +4603,7 @@ void CChainState::LoadExternalBlockFile(
// Either both should be specified (-reindex), or neither (-loadblock). // Either both should be specified (-reindex), or neither (-loadblock).
assert(!dbp == !blocks_with_unknown_parent); assert(!dbp == !blocks_with_unknown_parent);
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
int nLoaded = 0; int nLoaded = 0;
try { try {
@ -4739,7 +4739,7 @@ void CChainState::LoadExternalBlockFile(
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
AbortNode(std::string("System error: ") + e.what()); AbortNode(std::string("System error: ") + e.what());
} }
LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
} }
void CChainState::CheckBlockIndex() void CChainState::CheckBlockIndex()

View File

@ -533,7 +533,7 @@ bool BerkeleyDatabase::Rewrite(const char* pszSkip)
void BerkeleyEnvironment::Flush(bool fShutdown) void BerkeleyEnvironment::Flush(bool fShutdown)
{ {
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
// Flush log data to the actual data file on all files that are not in use // Flush log data to the actual data file on all files that are not in use
LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started"); LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: [%s] Flush(%s)%s\n", strPath, fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started");
if (!fDbEnvInit) if (!fDbEnvInit)
@ -560,7 +560,7 @@ void BerkeleyEnvironment::Flush(bool fShutdown)
no_dbs_accessed = false; no_dbs_accessed = false;
} }
} }
LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", GetTimeMillis() - nStart); LogPrint(BCLog::WALLETDB, "BerkeleyEnvironment::Flush: Flush(%s)%s took %15dms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " database not started", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
if (fShutdown) { if (fShutdown) {
char** listp; char** listp;
if (no_dbs_accessed) { if (no_dbs_accessed) {
@ -589,14 +589,14 @@ bool BerkeleyDatabase::PeriodicFlush()
if (m_refcount < 0) return false; if (m_refcount < 0) return false;
LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile); LogPrint(BCLog::WALLETDB, "Flushing %s\n", strFile);
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
// Flush wallet file so it's self contained // Flush wallet file so it's self contained
env->CloseDb(strFile); env->CloseDb(strFile);
env->CheckpointLSN(strFile); env->CheckpointLSN(strFile);
m_refcount = -1; m_refcount = -1;
LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, GetTimeMillis() - nStart); LogPrint(BCLog::WALLETDB, "Flushed %s %dms\n", strFile, Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
return true; return true;
} }

View File

@ -4725,7 +4725,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain* chain, interfaces::C
{ {
const std::string& walletFile = database->Filename(); const std::string& walletFile = database->Filename();
int64_t nStart = GetTimeMillis(); const auto start{SteadyClock::now()};
// TODO: Can't use std::make_shared because we need a custom deleter but // TODO: Can't use std::make_shared because we need a custom deleter but
// should be possible to use std::allocate_shared. // should be possible to use std::allocate_shared.
std::shared_ptr<CWallet> walletInstance(new CWallet(chain, coinjoin_loader, name, std::move(database)), ReleaseWallet); std::shared_ptr<CWallet> walletInstance(new CWallet(chain, coinjoin_loader, name, std::move(database)), ReleaseWallet);
@ -4971,7 +4971,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain* chain, interfaces::C
walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
walletInstance->m_spend_zero_conf_change = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); walletInstance->m_spend_zero_conf_change = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nStart); walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - start));
// Try to top up keypool. No-op if the wallet is locked. // Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool(); walletInstance->TopUpKeyPool();

View File

@ -6,6 +6,8 @@
Test addr relay Test addr relay
""" """
import random
from test_framework.messages import ( from test_framework.messages import (
CAddress, CAddress,
NODE_NETWORK, NODE_NETWORK,
@ -18,9 +20,19 @@ from test_framework.p2p import (
p2p_lock, p2p_lock,
) )
from test_framework.test_framework import BitcoinTestFramework from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_greater_than from test_framework.util import (
import random assert_equal,
assert_greater_than,
assert_greater_than_or_equal
)
ONE_MINUTE = 60
TEN_MINUTES = 10 * ONE_MINUTE
ONE_HOUR = 60 * ONE_MINUTE
TWO_HOURS = 2 * ONE_HOUR
ONE_DAY = 24 * ONE_HOUR
ADDR_DESTINATIONS_THRESHOLD = 4
class AddrReceiver(P2PInterface): class AddrReceiver(P2PInterface):
num_ipv4_received = 0 num_ipv4_received = 0
@ -82,6 +94,9 @@ class AddrTest(BitcoinTestFramework):
self.relay_tests() self.relay_tests()
self.inbound_blackhole_tests() self.inbound_blackhole_tests()
self.destination_rotates_once_in_24_hours_test()
self.destination_rotates_more_than_once_over_several_days_test()
# This test populates the addrman, which can impact the node's behavior # This test populates the addrman, which can impact the node's behavior
# in subsequent tests # in subsequent tests
self.getaddr_tests() self.getaddr_tests()
@ -361,6 +376,56 @@ class AddrTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps() self.nodes[0].disconnect_p2ps()
def get_nodes_that_received_addr(self, peer, receiver_peer, addr_receivers,
time_interval_1, time_interval_2):
# Clean addr response related to the initial getaddr. There is no way to avoid initial
# getaddr because the peer won't self-announce then.
for addr_receiver in addr_receivers:
addr_receiver.num_ipv4_received = 0
for _ in range(10):
self.mocktime += time_interval_1
self.msg.addrs[0].time = self.mocktime + TEN_MINUTES
self.nodes[0].setmocktime(self.mocktime)
with self.nodes[0].assert_debug_log(['received: addr (31 bytes) peer=0']):
peer.send_and_ping(self.msg)
self.mocktime += time_interval_2
self.nodes[0].setmocktime(self.mocktime)
receiver_peer.sync_with_ping()
return [node for node in addr_receivers if node.addr_received()]
def destination_rotates_once_in_24_hours_test(self):
self.restart_node(0, [])
self.log.info('Test within 24 hours an addr relay destination is rotated at most once')
self.nodes[0].setmocktime(self.mocktime)
self.msg = self.setup_addr_msg(1)
self.addr_receivers = []
peer = self.nodes[0].add_p2p_connection(P2PInterface())
receiver_peer = self.nodes[0].add_p2p_connection(AddrReceiver())
addr_receivers = [self.nodes[0].add_p2p_connection(AddrReceiver()) for _ in range(20)]
nodes_received_addr = self.get_nodes_that_received_addr(peer, receiver_peer, addr_receivers, 0, TWO_HOURS) # 10 intervals of 2 hours
# Per RelayAddress, we would announce these addrs to 2 destinations per day.
# Since it's at most one rotation, at most 4 nodes can receive ADDR.
assert_greater_than_or_equal(ADDR_DESTINATIONS_THRESHOLD, len(nodes_received_addr))
self.nodes[0].disconnect_p2ps()
def destination_rotates_more_than_once_over_several_days_test(self):
self.restart_node(0, [])
self.log.info('Test after several days an addr relay destination is rotated more than once')
self.msg = self.setup_addr_msg(1)
peer = self.nodes[0].add_p2p_connection(P2PInterface())
receiver_peer = self.nodes[0].add_p2p_connection(AddrReceiver())
addr_receivers = [self.nodes[0].add_p2p_connection(AddrReceiver()) for _ in range(20)]
# 10 intervals of 1 day (+ 1 hour, which should be enough to cover 30-min Poisson in most cases)
nodes_received_addr = self.get_nodes_that_received_addr(peer, receiver_peer, addr_receivers, ONE_DAY, ONE_HOUR)
# Now that there should have been more than one rotation, more than
# ADDR_DESTINATIONS_THRESHOLD nodes should have received ADDR.
assert_greater_than(len(nodes_received_addr), ADDR_DESTINATIONS_THRESHOLD)
self.nodes[0].disconnect_p2ps()
if __name__ == '__main__': if __name__ == '__main__':
AddrTest().main() AddrTest().main()