Skip to content

Commit f271bbe

Browse files
backport: bitcoin#27405 — util: Use steady clock instead of system clock to measure durations (#11)
* Merge bitcoin#27405: util: Use steady clock instead of system clock to measure durations fa83fb3 wallet: Use steady clock to calculate number of derive iterations (MarcoFalke) fa2c099 wallet: Use steady clock to measure scanning duration (MarcoFalke) fa97621 qt: Use steady clock to throttle GUI notifications (MarcoFalke) fa1d804 test: Use steady clock in index tests (MarcoFalke) fa454dc net: Use steady clock in InterruptibleRecv (MarcoFalke) Pull request description: `GetTimeMillis` has multiple issues: * It doesn't denote the underlying clock type * It isn't type-safe * It is used incorrectly in places that should use a steady clock Fix all issues here. ACKs for top commit: willcl-ark: ACK fa83fb3 martinus: Code review ACK bitcoin@fa83fb3, also ran all tests. All usages of the steady_clock are just for duration measurements, so the change to a different epoch is ok. Tree-SHA512: 5ec4fede8c7f97e2e08863c011856e8304f16ba30a68fdeb42f96a50a04961092cbe46ccf9ea6ac99ff5203c09f9e0924eb483eb38d7df0759addc85116c8a9f * fix: add MillisecondsDouble type alias for backport compatibility * fix: add missing util/time.h include to wallet.cpp The backport of bitcoin#27405 introduced usage of MillisecondsDouble and SteadyClock in wallet/wallet.cpp but didn't add the corresponding include for util/time.h, causing build failures across all CI platforms. --------- Co-authored-by: fanquake <fanquake@gmail.com> Co-authored-by: PastaClaw <thepastaclaw@users.noreply.github.com>
1 parent 443ae03 commit f271bbe

7 files changed

Lines changed: 32 additions & 28 deletions

File tree

src/netbase.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ static Proxy nameProxy GUARDED_BY(g_proxyinfo_mutex);
3535
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
3636
bool fNameLookup = DEFAULT_NAME_LOOKUP;
3737

38-
// Need ample time for negotiation for very slow proxies such as Tor (milliseconds)
39-
int g_socks5_recv_timeout = 20 * 1000;
38+
// Need ample time for negotiation for very slow proxies such as Tor
39+
std::chrono::milliseconds g_socks5_recv_timeout = 20s;
4040
static std::atomic<bool> interruptSocks5Recv(false);
4141

4242
ReachableNets g_reachable_nets;
@@ -300,7 +300,7 @@ enum class IntrRecvError {
300300
*
301301
* @param data The buffer where the read bytes should be stored.
302302
* @param len The number of bytes to read into the specified buffer.
303-
* @param timeout The total timeout in milliseconds for this read.
303+
* @param timeout The total timeout for this read.
304304
* @param sock The socket (has to be in non-blocking mode) from which to read bytes.
305305
*
306306
* @returns An IntrRecvError indicating the resulting status of this read.
@@ -310,10 +310,10 @@ enum class IntrRecvError {
310310
* @see This function can be interrupted by calling InterruptSocks5(bool).
311311
* Sockets can be made non-blocking with Sock::SetNonBlocking().
312312
*/
313-
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock)
313+
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, std::chrono::milliseconds timeout, const Sock& sock)
314314
{
315-
int64_t curTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
316-
int64_t endTime = curTime + timeout;
315+
auto curTime{Now<SteadyMilliseconds>()};
316+
const auto endTime{curTime + timeout};
317317
while (len > 0 && curTime < endTime) {
318318
ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first
319319
if (ret > 0) {
@@ -337,7 +337,7 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
337337
}
338338
if (interruptSocks5Recv)
339339
return IntrRecvError::Interrupted;
340-
curTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
340+
curTime = Now<SteadyMilliseconds>();
341341
}
342342
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
343343
}

src/qt/clientmodel.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
#include <QThread>
3535
#include <QTimer>
3636

37-
static int64_t nLastHeaderTipUpdateNotification = 0;
38-
static int64_t nLastBlockTipUpdateNotification = 0;
37+
static SteadyClock::time_point g_last_header_tip_update_notification{};
38+
static SteadyClock::time_point g_last_block_tip_update_notification{};
3939

4040
ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
4141
QObject(parent),
@@ -275,9 +275,9 @@ void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockT
275275

276276
// Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
277277
const bool throttle = (sync_state != SynchronizationState::POST_INIT && !header) || sync_state == SynchronizationState::INIT_REINDEX;
278-
const int64_t now = throttle ? TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) : 0;
279-
int64_t& nLastUpdateNotification = header ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification;
280-
if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) {
278+
const auto now{throttle ? SteadyClock::now() : SteadyClock::time_point{}};
279+
auto& nLastUpdateNotification = header ? g_last_header_tip_update_notification : g_last_block_tip_update_notification;
280+
if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
281281
return;
282282
}
283283

src/test/fuzz/socks5.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
#include <string>
1414
#include <vector>
1515

16+
extern std::chrono::milliseconds g_socks5_recv_timeout;
17+
1618
namespace {
17-
int default_socks5_recv_timeout;
19+
decltype(g_socks5_recv_timeout) default_socks5_recv_timeout;
1820
};
1921

20-
extern int g_socks5_recv_timeout;
21-
2222
void initialize_socks5()
2323
{
2424
static const auto testing_setup = MakeNoLogFileContext<>();
@@ -34,7 +34,7 @@ FUZZ_TARGET(socks5, .init = initialize_socks5)
3434
InterruptSocks5(fuzzed_data_provider.ConsumeBool());
3535
// Set FUZZED_SOCKET_FAKE_LATENCY=1 to exercise recv timeout code paths. This
3636
// will slow down fuzzing.
37-
g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1 : default_socks5_recv_timeout;
37+
g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1ms : default_socks5_recv_timeout;
3838
FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider);
3939
// This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within
4040
// a few seconds of fuzzing.

src/util/time.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ constexpr int64_t count_microseconds(std::chrono::microseconds t) { return t.cou
9393

9494
using HoursDouble = std::chrono::duration<double, std::chrono::hours::period>;
9595
using SecondsDouble = std::chrono::duration<double, std::chrono::seconds::period>;
96+
using MillisecondsDouble = std::chrono::duration<double, std::chrono::milliseconds::period>;
9697

9798
/**
9899
* DEPRECATED

src/wallet/rpc/wallet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ static RPCHelpMan getwalletinfo()
263263
obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
264264
if (pwallet->IsScanning()) {
265265
UniValue scanning(UniValue::VOBJ);
266-
scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
266+
scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
267267
scanning.pushKV("progress", pwallet->ScanningProgress());
268268
obj.pushKV("scanning", scanning);
269269
} else {

src/wallet/wallet.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <util/error.h>
3434
#include <util/moneystr.h>
3535
#include <util/string.h>
36+
#include <util/time.h>
3637
#include <util/translation.h>
3738
#ifdef USE_BDB
3839
#include <wallet/bdb.h>
@@ -570,13 +571,14 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
570571
return false;
571572
if (Unlock(_vMasterKey))
572573
{
573-
int64_t nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
574+
constexpr MillisecondsDouble target{100};
575+
auto start{SteadyClock::now()};
574576
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
575-
pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime))));
577+
pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
576578

577-
nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
579+
start = SteadyClock::now();
578580
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
579-
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime)))) / 2;
581+
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
580582

581583
if (pMasterKey.second.nDeriveIterations < 25000)
582584
pMasterKey.second.nDeriveIterations = 25000;
@@ -775,13 +777,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
775777
GetStrongRandBytes(kMasterKey.vchSalt);
776778

777779
CCrypter crypter;
778-
int64_t nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
780+
constexpr MillisecondsDouble target{100};
781+
auto start{SteadyClock::now()};
779782
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
780-
kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime)));
783+
kMasterKey.nDeriveIterations = static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
781784

782-
nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
785+
start = SteadyClock::now();
783786
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
784-
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime)))) / 2;
787+
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
785788

786789
if (kMasterKey.nDeriveIterations < 25000)
787790
kMasterKey.nDeriveIterations = 25000;

src/wallet/wallet.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
290290
std::atomic<bool> fAbortRescan{false}; // reset by WalletRescanReserver::reserve()
291291
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
292292
std::atomic<bool> m_attaching_chain{false};
293-
std::atomic<int64_t> m_scanning_start{0};
293+
std::atomic<SteadyClock::time_point> m_scanning_start{SteadyClock::time_point{}};
294294
std::atomic<double> m_scanning_progress{0};
295295
friend class WalletRescanReserver;
296296

@@ -608,7 +608,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
608608
void AbortRescan() { fAbortRescan = true; }
609609
bool IsAbortingRescan() const { return fAbortRescan; }
610610
bool IsScanning() const { return fScanningWallet; }
611-
int64_t ScanningDuration() const { return fScanningWallet ? TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - m_scanning_start : 0; }
611+
SteadyClock::duration ScanningDuration() const { return fScanningWallet ? SteadyClock::now() - m_scanning_start.load() : SteadyClock::duration{}; }
612612
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
613613

614614
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
@@ -1123,7 +1123,7 @@ class WalletRescanReserver
11231123
if (m_wallet.fScanningWallet.exchange(true)) {
11241124
return false;
11251125
}
1126-
m_wallet.m_scanning_start = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
1126+
m_wallet.m_scanning_start = SteadyClock::now();
11271127
m_wallet.m_scanning_progress = 0;
11281128
m_wallet.fAbortRescan = false;
11291129
m_could_reserve = true;

0 commit comments

Comments
 (0)