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

Code before:
    } while (now < deadline);

    return nullptr;
}

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

bool CooldownIfHeadersAhead(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const BlockRef& last_tip)
{
    constexpr auto COOLDOWN{1s};
    // Use a steady clock so cooldown is independent of mocktime.
    auto cooldown_deadline{SteadyClock::now() + COOLDOWN};
    uint256 last_tip_hash{last_tip.hash};
    while (true) {
        bool best_header_ahead{false};
        {
            LOCK(::cs_main);
            best_header_ahead = chainman.BestHeaderAheadOfActiveTip();
        }
        if (!best_header_ahead) break;

        WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
        kernel_notifications.m_tip_block_cv.wait_until(lock, cooldown_deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
            const auto tip_block = kernel_notifications.TipBlock();
            return chainman.m_interrupt || (tip_block && *tip_block != last_tip_hash);
        });
        if (chainman.m_interrupt) return false;

        // If the tip changed during the wait, extend the deadline
        const auto tip_block = kernel_notifications.TipBlock();
        if (tip_block && *tip_block != last_tip_hash) {
            last_tip_hash = *tip_block;
            cooldown_deadline = SteadyClock::now() + COOLDOWN;
            continue;
        }

        // No tip change and the cooldown window has expired.
        if (SteadyClock::now() >= cooldown_deadline) break;
    }

    return true;
}

std::optional<BlockRef> WaitTipChanged(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const uint256& current_tip, MillisecondsDouble& timeout)
{

Review comment (suggestion):
In commit "mining: createNewBlock() waits if tip is updating" (9817657d463ff1d8502a5edf0641e88b9b1d4853)

Could collapse lines 454-460 to just:

```c++
while (WITH_LOCK(::cs_main, return chainman.BestHeaderAheadOfActiveTip())) {
```

I feel like that would be easier to understand without the bool and break. Or maybe better just lock cs_main inside BestHeaderAheadOfActiveTip so this can be:


```c++
while (chainman.BestHeaderAheadOfActiveTip()) {
```


Code after:
                current_fees = std::accumulate(block_template->vTxFees.begin(), block_template->vTxFees.end(), CAmount{0});
            }

            // Check if fees increased enough to return the new template
            const CAmount new_fees = std::accumulate(new_tmpl->vTxFees.begin(), new_tmpl->vTxFees.end(), CAmount{0});
            Assume(options.fee_threshold != MAX_MONEY);
            if (new_fees >= current_fees + options.fee_threshold) return new_tmpl;
        }

        now = NodeClock::now();
    } while (now < deadline);

    return nullptr;
}

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

bool CooldownIfHeadersAhead(ChainstateManager& chainman, KernelNotifications& kernel_notifications, const BlockRef& last_tip, bool& interrupt_mining)
{
    uint256 last_tip_hash{last_tip.hash};

    while (const std::optional<int> remaining = chainman.BlocksAheadOfTip()) {
        const int cooldown_seconds = std::clamp(*remaining, 3, 20);
        const auto cooldown_deadline{MockableSteadyClock::now() + std::chrono::seconds{cooldown_seconds}};

        {
            WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
            kernel_notifications.m_tip_block_cv.wait_until(lock, cooldown_deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
                const auto tip_block = kernel_notifications.TipBlock();
                return chainman.m_interrupt || interrupt_mining || (tip_block && *tip_block != last_tip_hash);
            });
            if (chainman.m_interrupt || interrupt_mining) {
                interrupt_mining = false;
                return false;
            }

            // If the tip changed during the wait, extend the deadline
            const auto tip_block = kernel_notifications.TipBlock();
            if (tip_block && *tip_block != last_tip_hash) {
                last_tip_hash = *tip_block;
                continue;
            }
        }

        // No tip change and the cooldown window has expired.