From e976bd3045010ee217aa0f2dca4c962aabb789d5 Mon Sep 17 00:00:00 2001 From: Andrew Toth Date: Sun, 8 Sep 2024 11:51:13 -0400 Subject: [PATCH] validation: add randomness to periodic write interval Co-Authored-By: Pieter Wuille Co-Authored-By: l0rinc --- src/test/chainstate_write_tests.cpp | 8 ++++---- src/validation.cpp | 11 ++++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/test/chainstate_write_tests.cpp b/src/test/chainstate_write_tests.cpp index c76164099c2..ccca2f9be10 100644 --- a/src/test/chainstate_write_tests.cpp +++ b/src/test/chainstate_write_tests.cpp @@ -25,18 +25,18 @@ BOOST_FIXTURE_TEST_CASE(chainstate_write_interval, TestingSetup) auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()}; BlockValidationState state_dummy{}; - // The first periodic flush sets m_last_write and does not flush + // The first periodic flush sets m_next_write and does not flush chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC); m_node.validation_signals->SyncWithValidationInterfaceQueue(); BOOST_CHECK(!sub->m_did_flush); - // The periodic flush interval is 1 hour - SetMockTime(GetTime() + 59min); + // The periodic flush interval is between 50 and 70 minutes (inclusive) + SetMockTime(GetTime() + 49min); chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC); m_node.validation_signals->SyncWithValidationInterfaceQueue(); BOOST_CHECK(!sub->m_did_flush); - SetMockTime(GetTime() + 1h); + SetMockTime(GetTime() + 70min); chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC); m_node.validation_signals->SyncWithValidationInterfaceQueue(); BOOST_CHECK(sub->m_did_flush); diff --git a/src/validation.cpp b/src/validation.cpp index 978eacc2004..ff4d276121c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -90,8 +90,12 @@ using node::SnapshotMetadata; /** Size threshold for warning about slow UTXO set flush to disk. */ static constexpr size_t WARN_FLUSH_COINS_SIZE = 1 << 30; // 1 GiB -/** Time to wait between writing blocks/block index and chainstate to disk. */ -static constexpr std::chrono::hours DATABASE_WRITE_INTERVAL{1}; +/** Time window to wait between writing blocks/block index and chainstate to disk. + * Randomize writing time inside the window to prevent a situation where the + * network over time settles into a few cohorts of synchronized writers. +*/ +static constexpr auto DATABASE_WRITE_INTERVAL_MIN{50min}; +static constexpr auto DATABASE_WRITE_INTERVAL_MAX{70min}; /** Maximum age of our tip for us to be considered current for fee estimation */ static constexpr std::chrono::hours MAX_FEE_ESTIMATION_TIP_AGE{3}; const std::vector CHECKLEVEL_DOC { @@ -2945,7 +2949,8 @@ bool Chainstate::FlushStateToDisk( } if (should_write || m_next_write == NodeClock::time_point::max()) { - m_next_write = NodeClock::now() + DATABASE_WRITE_INTERVAL; + constexpr auto range{DATABASE_WRITE_INTERVAL_MAX - DATABASE_WRITE_INTERVAL_MIN}; + m_next_write = FastRandomContext().rand_uniform_delay(NodeClock::now() + DATABASE_WRITE_INTERVAL_MIN, range); } } if (full_flush_completed && m_chainman.m_options.signals) {