Skip to content

Commit 11d65a7

Browse files
fanquakeClaude Code
authored andcommitted
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
1 parent 54e2588 commit 11d65a7

File tree

8 files changed

+45
-30
lines changed

8 files changed

+45
-30
lines changed

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
@@ -31,8 +31,8 @@
3131
#include <QThread>
3232
#include <QTimer>
3333

34-
static int64_t nLastHeaderTipUpdateNotification = 0;
35-
static int64_t nLastBlockTipUpdateNotification = 0;
34+
static SteadyClock::time_point g_last_header_tip_update_notification{};
35+
static SteadyClock::time_point g_last_block_tip_update_notification{};
3636

3737
ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
3838
QObject(parent),
@@ -268,9 +268,9 @@ void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockT
268268

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

src/test/blockfilter_index_tests.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,12 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
142142
BOOST_REQUIRE(filter_index.Start(m_node.chainman->ActiveChainstate()));
143143

144144
// Allow filter index to catch up with the block index.
145-
IndexWaitSynced(filter_index);
145+
constexpr auto timeout{10s};
146+
const auto time_start{SteadyClock::now()};
147+
while (!filter_index.BlockUntilSyncedToCurrentChain()) {
148+
BOOST_REQUIRE(time_start + timeout > SteadyClock::now());
149+
UninterruptibleSleep(std::chrono::milliseconds{100});
150+
}
146151

147152
// Check that filter index has all blocks that were in the chain before it started.
148153
{

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/test/txindex_tests.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
3131
BOOST_REQUIRE(txindex.Start(m_node.chainman->ActiveChainstate()));
3232

3333
// Allow tx index to catch up with the block index.
34-
IndexWaitSynced(txindex);
34+
constexpr auto timeout{10s};
35+
const auto time_start{SteadyClock::now()};
36+
while (!txindex.BlockUntilSyncedToCurrentChain()) {
37+
BOOST_REQUIRE(time_start + timeout > SteadyClock::now());
38+
UninterruptibleSleep(std::chrono::milliseconds{100});
39+
}
3540

3641
// Check that txindex excludes genesis block transactions.
3742
const CBlock& genesis_block = Params().GenesisBlock();

src/wallet/rpc/wallet.cpp

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

src/wallet/wallet.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -494,13 +494,14 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
494494
return false;
495495
if (Unlock(_vMasterKey))
496496
{
497-
int64_t nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
497+
constexpr MillisecondsDouble target{100};
498+
auto start{SteadyClock::now()};
498499
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
499-
pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime))));
500+
pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
500501

501-
nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
502+
start = SteadyClock::now();
502503
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
503-
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime)))) / 2;
504+
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
504505

505506
if (pMasterKey.second.nDeriveIterations < 25000)
506507
pMasterKey.second.nDeriveIterations = 25000;
@@ -700,13 +701,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
700701
GetStrongRandBytes(kMasterKey.vchSalt);
701702

702703
CCrypter crypter;
703-
int64_t nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
704+
constexpr MillisecondsDouble target{100};
705+
auto start{SteadyClock::now()};
704706
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
705-
kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime)));
707+
kMasterKey.nDeriveIterations = static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
706708

707-
nStartTime = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
709+
start = SteadyClock::now();
708710
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
709-
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - nStartTime)))) / 2;
711+
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
710712

711713
if (kMasterKey.nDeriveIterations < 25000)
712714
kMasterKey.nDeriveIterations = 25000;

src/wallet/wallet.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
267267
std::atomic<bool> fAbortRescan{false}; // reset by WalletRescanReserver::reserve()
268268
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
269269
std::atomic<bool> m_attaching_chain{false};
270-
std::atomic<int64_t> m_scanning_start{0};
270+
std::atomic<bool> m_scanning_with_passphrase{false};
271+
std::atomic<SteadyClock::time_point> m_scanning_start{SteadyClock::time_point{}};
271272
std::atomic<double> m_scanning_progress{0};
272273
friend class WalletRescanReserver;
273274

@@ -576,7 +577,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
576577
void AbortRescan() { fAbortRescan = true; }
577578
bool IsAbortingRescan() const { return fAbortRescan; }
578579
bool IsScanning() const { return fScanningWallet; }
579-
int64_t ScanningDuration() const { return fScanningWallet ? TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now()) - m_scanning_start : 0; }
580+
bool IsScanningWithPassphrase() const { return m_scanning_with_passphrase; }
581+
SteadyClock::duration ScanningDuration() const { return fScanningWallet ? SteadyClock::now() - m_scanning_start.load() : SteadyClock::duration{}; }
580582
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
581583

582584
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
@@ -1085,7 +1087,8 @@ class WalletRescanReserver
10851087
if (m_wallet.fScanningWallet.exchange(true)) {
10861088
return false;
10871089
}
1088-
m_wallet.m_scanning_start = TicksSinceEpoch<std::chrono::milliseconds>(SystemClock::now());
1090+
m_wallet.m_scanning_with_passphrase.exchange(with_passphrase);
1091+
m_wallet.m_scanning_start = SteadyClock::now();
10891092
m_wallet.m_scanning_progress = 0;
10901093
m_wallet.fAbortRescan = false;
10911094
m_could_reserve = true;

0 commit comments

Comments
 (0)