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

Code before:

    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()};
        // Fail if the tip updated before the lock was taken
        if (block.hashPrevBlock != tip->GetBlockHash()) {
            state.Error("Block does not connect to current chain tip.");
            return false;

Review comment (refactor):
Since C++17 we can [safely compare](https://en.cppreference.com/w/cpp/utility/optional/operator_cmp) an `optional<T>` with another `T`:
```C++
template< class T, class U >
constexpr bool operator!=(const optional<T>& opt, const U& value);
(23) (since C++17)
```
If you modify again, consider simplifying to:
```suggestion
                return (notifications().m_tip_block && notifications().m_tip_block != current_tip) || chainman().m_interrupt;
```


Code after:

    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) {
                // We need to wait for m_tip_block to be set AND for the value
                // to differ from the current_tip value.
                return (notifications().TipBlock() && notifications().TipBlock() != current_tip) || 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()};
        // Fail if the tip updated before the lock was taken
        if (block.hashPrevBlock != tip->GetBlockHash()) {