0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-09 10:43:19 -05:00

Merge bitcoin/bitcoin#27405: util: Use steady clock instead of system clock to measure durations

fa83fb3161 wallet: Use steady clock to calculate number of derive iterations (MarcoFalke)
fa2c099cec wallet: Use steady clock to measure scanning duration (MarcoFalke)
fa97621804 qt: Use steady clock to throttle GUI notifications (MarcoFalke)
fa1d8044ab test: Use steady clock in index tests (MarcoFalke)
fa454dcb20 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 fa83fb3161
  martinus:
    Code review ACK fa83fb3161, 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
This commit is contained in:
fanquake 2023-05-06 11:49:34 +01:00
commit e460c0a24a
No known key found for this signature in database
GPG key ID: 2EEB9F5CC09526C1
8 changed files with 37 additions and 35 deletions

View file

@ -36,8 +36,8 @@ static Proxy nameProxy GUARDED_BY(g_proxyinfo_mutex);
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
bool fNameLookup = DEFAULT_NAME_LOOKUP; bool fNameLookup = DEFAULT_NAME_LOOKUP;
// Need ample time for negotiation for very slow proxies such as Tor (milliseconds) // Need ample time for negotiation for very slow proxies such as Tor
int g_socks5_recv_timeout = 20 * 1000; std::chrono::milliseconds g_socks5_recv_timeout = 20s;
static std::atomic<bool> interruptSocks5Recv(false); static std::atomic<bool> interruptSocks5Recv(false);
std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup) std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup)
@ -296,7 +296,7 @@ enum class IntrRecvError {
* *
* @param data The buffer where the read bytes should be stored. * @param data The buffer where the read bytes should be stored.
* @param len The number of bytes to read into the specified buffer. * @param len The number of bytes to read into the specified buffer.
* @param timeout The total timeout in milliseconds for this read. * @param timeout The total timeout for this read.
* @param sock The socket (has to be in non-blocking mode) from which to read bytes. * @param sock The socket (has to be in non-blocking mode) from which to read bytes.
* *
* @returns An IntrRecvError indicating the resulting status of this read. * @returns An IntrRecvError indicating the resulting status of this read.
@ -306,10 +306,10 @@ enum class IntrRecvError {
* @see This function can be interrupted by calling InterruptSocks5(bool). * @see This function can be interrupted by calling InterruptSocks5(bool).
* Sockets can be made non-blocking with Sock::SetNonBlocking(). * Sockets can be made non-blocking with Sock::SetNonBlocking().
*/ */
static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, const Sock& sock) static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, std::chrono::milliseconds timeout, const Sock& sock)
{ {
int64_t curTime = GetTimeMillis(); auto curTime{Now<SteadyMilliseconds>()};
int64_t endTime = curTime + timeout; const auto endTime{curTime + timeout};
while (len > 0 && curTime < endTime) { while (len > 0 && curTime < endTime) {
ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first ssize_t ret = sock.Recv(data, len, 0); // Optimistically try the recv first
if (ret > 0) { if (ret > 0) {
@ -333,7 +333,7 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c
} }
if (interruptSocks5Recv) if (interruptSocks5Recv)
return IntrRecvError::Interrupted; return IntrRecvError::Interrupted;
curTime = GetTimeMillis(); curTime = Now<SteadyMilliseconds>();
} }
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout; return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
} }

View file

@ -28,8 +28,8 @@
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
static int64_t nLastHeaderTipUpdateNotification = 0; static SteadyClock::time_point g_last_header_tip_update_notification{};
static int64_t nLastBlockTipUpdateNotification = 0; static SteadyClock::time_point g_last_block_tip_update_notification{};
ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) : ClientModel::ClientModel(interfaces::Node& node, OptionsModel *_optionsModel, QObject *parent) :
QObject(parent), QObject(parent),
@ -222,9 +222,9 @@ void ClientModel::TipChanged(SynchronizationState sync_state, interfaces::BlockT
// Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex. // Throttle GUI notifications about (a) blocks during initial sync, and (b) both blocks and headers during reindex.
const bool throttle = (sync_state != SynchronizationState::POST_INIT && synctype == SyncType::BLOCK_SYNC) || sync_state == SynchronizationState::INIT_REINDEX; const bool throttle = (sync_state != SynchronizationState::POST_INIT && synctype == SyncType::BLOCK_SYNC) || sync_state == SynchronizationState::INIT_REINDEX;
const int64_t now = throttle ? GetTimeMillis() : 0; const auto now{throttle ? SteadyClock::now() : SteadyClock::time_point{}};
int64_t& nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC ? nLastHeaderTipUpdateNotification : nLastBlockTipUpdateNotification; auto& nLastUpdateNotification = synctype != SyncType::BLOCK_SYNC ? g_last_header_tip_update_notification : g_last_block_tip_update_notification;
if (throttle && now < nLastUpdateNotification + count_milliseconds(MODEL_UPDATE_DELAY)) { if (throttle && now < nLastUpdateNotification + MODEL_UPDATE_DELAY) {
return; return;
} }

View file

@ -141,10 +141,10 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
BOOST_REQUIRE(filter_index.Start()); BOOST_REQUIRE(filter_index.Start());
// Allow filter index to catch up with the block index. // Allow filter index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000; constexpr auto timeout{10s};
int64_t time_start = GetTimeMillis(); const auto time_start{SteadyClock::now()};
while (!filter_index.BlockUntilSyncedToCurrentChain()) { while (!filter_index.BlockUntilSyncedToCurrentChain()) {
BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis()); BOOST_REQUIRE(time_start + timeout > SteadyClock::now());
UninterruptibleSleep(std::chrono::milliseconds{100}); UninterruptibleSleep(std::chrono::milliseconds{100});
} }

View file

@ -14,11 +14,11 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace { extern std::chrono::milliseconds g_socks5_recv_timeout;
int default_socks5_recv_timeout;
};
extern int g_socks5_recv_timeout; namespace {
decltype(g_socks5_recv_timeout) default_socks5_recv_timeout;
};
void initialize_socks5() void initialize_socks5()
{ {
@ -35,7 +35,7 @@ FUZZ_TARGET_INIT(socks5, initialize_socks5)
InterruptSocks5(fuzzed_data_provider.ConsumeBool()); InterruptSocks5(fuzzed_data_provider.ConsumeBool());
// Set FUZZED_SOCKET_FAKE_LATENCY=1 to exercise recv timeout code paths. This // Set FUZZED_SOCKET_FAKE_LATENCY=1 to exercise recv timeout code paths. This
// will slow down fuzzing. // will slow down fuzzing.
g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1 : default_socks5_recv_timeout; g_socks5_recv_timeout = (fuzzed_data_provider.ConsumeBool() && std::getenv("FUZZED_SOCKET_FAKE_LATENCY") != nullptr) ? 1ms : default_socks5_recv_timeout;
FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider); FuzzedSock fuzzed_sock = ConsumeSock(fuzzed_data_provider);
// This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within // This Socks5(...) fuzzing harness would have caught CVE-2017-18350 within
// a few seconds of fuzzing. // a few seconds of fuzzing.

View file

@ -32,10 +32,10 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
BOOST_REQUIRE(txindex.Start()); BOOST_REQUIRE(txindex.Start());
// Allow tx index to catch up with the block index. // Allow tx index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000; constexpr auto timeout{10s};
int64_t time_start = GetTimeMillis(); const auto time_start{SteadyClock::now()};
while (!txindex.BlockUntilSyncedToCurrentChain()) { while (!txindex.BlockUntilSyncedToCurrentChain()) {
BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis()); BOOST_REQUIRE(time_start + timeout > SteadyClock::now());
UninterruptibleSleep(std::chrono::milliseconds{100}); UninterruptibleSleep(std::chrono::milliseconds{100});
} }

View file

@ -122,7 +122,7 @@ static RPCHelpMan getwalletinfo()
obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)); obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
if (pwallet->IsScanning()) { if (pwallet->IsScanning()) {
UniValue scanning(UniValue::VOBJ); UniValue scanning(UniValue::VOBJ);
scanning.pushKV("duration", pwallet->ScanningDuration() / 1000); scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
scanning.pushKV("progress", pwallet->ScanningProgress()); scanning.pushKV("progress", pwallet->ScanningProgress());
obj.pushKV("scanning", scanning); obj.pushKV("scanning", scanning);
} else { } else {

View file

@ -559,13 +559,14 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
return false; return false;
if (Unlock(_vMasterKey)) if (Unlock(_vMasterKey))
{ {
int64_t nStartTime = GetTimeMillis(); constexpr MillisecondsDouble target{100};
auto start{SteadyClock::now()};
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)))); pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start));
nStartTime = GetTimeMillis(); start = SteadyClock::now();
crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2; pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
if (pMasterKey.second.nDeriveIterations < 25000) if (pMasterKey.second.nDeriveIterations < 25000)
pMasterKey.second.nDeriveIterations = 25000; pMasterKey.second.nDeriveIterations = 25000;
@ -762,13 +763,14 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
GetStrongRandBytes(kMasterKey.vchSalt); GetStrongRandBytes(kMasterKey.vchSalt);
CCrypter crypter; CCrypter crypter;
int64_t nStartTime = GetTimeMillis(); constexpr MillisecondsDouble target{100};
auto start{SteadyClock::now()};
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = static_cast<unsigned int>(2500000 / ((double)(GetTimeMillis() - nStartTime))); kMasterKey.nDeriveIterations = static_cast<unsigned int>(25000 * target / (SteadyClock::now() - start));
nStartTime = GetTimeMillis(); start = SteadyClock::now();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2; kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + static_cast<unsigned int>(kMasterKey.nDeriveIterations * target / (SteadyClock::now() - start))) / 2;
if (kMasterKey.nDeriveIterations < 25000) if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000; kMasterKey.nDeriveIterations = 25000;

View file

@ -284,7 +284,7 @@ private:
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::atomic<bool> m_attaching_chain{false}; std::atomic<bool> m_attaching_chain{false};
std::atomic<bool> m_scanning_with_passphrase{false}; std::atomic<bool> m_scanning_with_passphrase{false};
std::atomic<int64_t> m_scanning_start{0}; std::atomic<SteadyClock::time_point> m_scanning_start{SteadyClock::time_point{}};
std::atomic<double> m_scanning_progress{0}; std::atomic<double> m_scanning_progress{0};
friend class WalletRescanReserver; friend class WalletRescanReserver;
@ -505,7 +505,7 @@ public:
bool IsAbortingRescan() const { return fAbortRescan; } bool IsAbortingRescan() const { return fAbortRescan; }
bool IsScanning() const { return fScanningWallet; } bool IsScanning() const { return fScanningWallet; }
bool IsScanningWithPassphrase() const { return m_scanning_with_passphrase; } bool IsScanningWithPassphrase() const { return m_scanning_with_passphrase; }
int64_t ScanningDuration() const { return fScanningWallet ? GetTimeMillis() - m_scanning_start : 0; } SteadyClock::duration ScanningDuration() const { return fScanningWallet ? SteadyClock::now() - m_scanning_start.load() : SteadyClock::duration{}; }
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; } double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo //! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
@ -1014,7 +1014,7 @@ public:
return false; return false;
} }
m_wallet.m_scanning_with_passphrase.exchange(with_passphrase); m_wallet.m_scanning_with_passphrase.exchange(with_passphrase);
m_wallet.m_scanning_start = GetTimeMillis(); m_wallet.m_scanning_start = SteadyClock::now();
m_wallet.m_scanning_progress = 0; m_wallet.m_scanning_progress = 0;
m_could_reserve = true; m_could_reserve = true;
return true; return true;