Repository: bitcoin/bitcoin
File: src/node/interfaces.cpp (C++)

Code before:
public:
    explicit MinerImpl(NodeContext& node) : m_node(node) {}

    bool isTestChain() override
    {
        return chainman().GetParams().IsTestChain();
    }

    bool isInitialBlockDownload() override
    {
        return chainman().IsInitialBlockDownload();
    }

    std::optional<BlockRef> getTip() override
    {
        LOCK(::cs_main);
        CBlockIndex* tip{chainman().ActiveChain().Tip()};
        if (!tip) return {};
        return BlockRef{tip->GetBlockHash(), tip->nHeight};
    }

    BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override
    {
        // Interrupt check interval
        const MillisecondsDouble tick{1000};
        auto now{std::chrono::steady_clock::now()};
        auto deadline = now + timeout;
        // std::chrono does not check against overflow
        if (deadline < now) deadline = std::chrono::steady_clock::time_point::max();
        {
            WAIT_LOCK(notifications().m_tip_block_mutex, lock);
            while ((notifications().m_tip_block == uint256() || notifications().m_tip_block == current_tip) && !chainman().m_interrupt) {
                now = std::chrono::steady_clock::now();
                if (now >= deadline) break;
                notifications().m_tip_block_cv.wait_until(lock, std::min(deadline, now + tick));
            }
        }
        // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
        LOCK(::cs_main);
        return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight};
    }

    bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override
    {
        return chainman().ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/new_block);
    }

    unsigned int getTransactionsUpdated() override
    {
        return context()->mempool->GetTransactionsUpdated();
    }

Review comment (refactor):
In commit "refactor: Use wait_for predicate to check for interrupt" (faa3f411f6842bf1201b25d6391b1913e1b72439)

Might be better to avoid the 100 year hack by switching to wait_until

```diff
--- a/src/node/interfaces.cpp
+++ b/src/node/interfaces.cpp
@@ -940,10 +940,10 @@ public:
 
     BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override
     {
-        if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono
         {
             WAIT_LOCK(notifications().m_tip_block_mutex, lock);
-            notifications().m_tip_block_cv.wait_for(lock, timeout, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) {
+            const auto deadline{std::chrono::steady_clock::now() + timeout};
+            notifications().m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) {
                 return (notifications().m_tip_block != current_tip && notifications().m_tip_block != uint256::ZERO) || chainman().m_interrupt;
             });
         }
```

Code after:
class MinerImpl : public Mining
{
public:
    explicit MinerImpl(NodeContext& node) : m_node(node) {}

    bool isTestChain() override
    {
        return chainman().GetParams().IsTestChain();
    }

    bool isInitialBlockDownload() override
    {
        return chainman().IsInitialBlockDownload();
    }

    std::optional<BlockRef> getTip() override
    {
        LOCK(::cs_main);
        CBlockIndex* tip{chainman().ActiveChain().Tip()};
        if (!tip) return {};
        return BlockRef{tip->GetBlockHash(), tip->nHeight};
    }

    BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override
    {
        if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono
        {
            WAIT_LOCK(notifications().m_tip_block_mutex, lock);
            notifications().m_tip_block_cv.wait_for(lock, timeout, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) {
                return (notifications().m_tip_block != current_tip && notifications().m_tip_block != uint256::ZERO) || chainman().m_interrupt;
            });
        }
        // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
        LOCK(::cs_main);
        return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight};
    }

    bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override
    {
        return chainman().ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/new_block);
    }

    unsigned int getTransactionsUpdated() override
    {
        return context()->mempool->GetTransactionsUpdated();
    }

    bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override
    {
        LOCK(cs_main);
        CBlockIndex* tip{chainman().ActiveChain().Tip()};