Skip to content

Commit 62fc42d

Browse files
interfaces: refactor: move waitTipChanged implementation to miner
- This commit creates a function `WaitTipChanged` that waits for the connected tip to change until timeout elapsed. - This function is now used by `waitTipChanged` Co-authored-by: Ryan Ofsky <[email protected]>
1 parent c39ca9d commit 62fc42d

File tree

3 files changed

+34
-26
lines changed

3 files changed

+34
-26
lines changed

src/node/interfaces.cpp

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -971,32 +971,7 @@ class MinerImpl : public Mining
971971

972972
std::optional<BlockRef> waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override
973973
{
974-
Assume(timeout >= 0ms); // No internal callers should use a negative timeout
975-
if (timeout < 0ms) timeout = 0ms;
976-
if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono
977-
auto deadline{std::chrono::steady_clock::now() + timeout};
978-
{
979-
WAIT_LOCK(notifications().m_tip_block_mutex, lock);
980-
// For callers convenience, wait longer than the provided timeout
981-
// during startup for the tip to be non-null. That way this function
982-
// always returns valid tip information when possible and only
983-
// returns null when shutting down, not when timing out.
984-
notifications().m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) {
985-
return notifications().TipBlock() || chainman().m_interrupt;
986-
});
987-
if (chainman().m_interrupt) return {};
988-
// At this point TipBlock is set, so continue to wait until it is
989-
// different then `current_tip` provided by caller.
990-
notifications().m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) {
991-
return Assume(notifications().TipBlock()) != current_tip || chainman().m_interrupt;
992-
});
993-
}
994-
995-
if (chainman().m_interrupt) return {};
996-
997-
// Must release m_tip_block_mutex before getTip() locks cs_main, to
998-
// avoid deadlocks.
999-
return getTip();
974+
return WaitTipChanged(chainman(), notifications(), current_tip, timeout);
1000975
}
1001976

1002977
std::unique_ptr<BlockTemplate> createNewBlock(const BlockCreateOptions& options) override

src/node/miner.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,4 +547,33 @@ std::optional<BlockRef> GetTip(ChainstateManager& chainman)
547547
if (!tip) return {};
548548
return BlockRef{tip->GetBlockHash(), tip->nHeight};
549549
}
550+
551+
std::optional<BlockRef> WaitTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout)
552+
{
553+
Assume(timeout >= 0ms); // No internal callers should use a negative timeout
554+
if (timeout < 0ms) timeout = 0ms;
555+
if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono
556+
auto deadline{std::chrono::steady_clock::now() + timeout};
557+
{
558+
WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
559+
// For callers convenience, wait longer than the provided timeout
560+
// during startup for the tip to be non-null. That way this function
561+
// always returns valid tip information when possible and only
562+
// returns null when shutting down, not when timing out.
563+
kernel_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
564+
return kernel_notifications.TipBlock() || chainman.m_interrupt;
565+
});
566+
if (chainman.m_interrupt) return {};
567+
// At this point TipBlock is set, so continue to wait until it is
568+
// different then `current_tip` provided by caller.
569+
kernel_notifications.m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
570+
return Assume(kernel_notifications.TipBlock()) != current_tip || chainman.m_interrupt;
571+
});
572+
}
573+
if (chainman.m_interrupt) return {};
574+
575+
// Must release m_tip_block_mutex before getTip() locks cs_main, to
576+
// avoid deadlocks.
577+
return GetTip(chainman);
578+
}
550579
} // namespace node

src/node/miner.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
251251

252252
/* Locks cs_main and returns the block hash and block height of the active chain if it exists; otherwise, returns nullopt.*/
253253
std::optional<BlockRef> GetTip(ChainstateManager& chainman);
254+
255+
/* Waits for the connected tip to change until timeout has elapsed. During node initialization, this will wait until the tip is connected (regardless of `timeout`).
256+
* Returns the current tip, or nullopt if the node is shutting down. */
257+
std::optional<BlockRef> WaitTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout);
254258
} // namespace node
255259

256260
#endif // BITCOIN_NODE_MINER_H

0 commit comments

Comments
 (0)