Merge bitcoin/bitcoin#33676: interfaces: enable cancelling running waitNext calls

dcb56fd4cb interfaces: add interruptWait method (ismaelsadeeq)

Pull request description:

  This is an attempt to fix #33575 see the issue for background and the usefulness of this feature.

  This PR uses one of the suggested approaches: adding a new `interruptWaitNext()` method to the mining interface.

  It introduces a new boolean variable, `m_interrupt_wait`, which is set to `false` when the thread starts waiting. The `interruptWaitNext()` method wakes the thread and sets `m_interrupt_wait` to `true`.
  Whenever the thread wakes up, it checks whether the wait was aborted; if so, it simply set ` m_interrupt_wait ` to false and return`nullptr`.

  This PR also adds a functional test for the new method. The test uses `asyncio` to spawn two tasks and attempts to ensure that the wait is executed before the interrupt by using an event monitor. It adds a 0.1-second buffer to ensure the wait has started executing.
  If that buffer elapses without `waitNext` executing, the test will fail because a transaction is created after the buffer.

ACKs for top commit:
  furszy:
    Code ACK dcb56fd4cb
  ryanofsky:
    Code review ACK dcb56fd4cb, just tweaking semantics slightly since last review so if an `interruptWait` call is made shortly after a `waitNext` call it will reliably cause the `waitNext` call to return right away without blocking, even if the `waitNext` call had not begun to execute or wait yet.
  Sjors:
    tACK dcb56fd4cb
  TheCharlatan:
    ACK dcb56fd4cb

Tree-SHA512: a03f049e1f303b174a9e5d125733b6583dfd8effa12e7b6c37bd9b2cff9541100f5f4514e80f89005c44a57d7e47804afe87aa5fdb6831f3b0cd9b01d83e42be
This commit is contained in:
merge-script
2025-11-10 09:56:27 +00:00
6 changed files with 54 additions and 4 deletions

View File

@@ -454,12 +454,20 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
block.hashMerkleRoot = BlockMerkleRoot(block);
}
void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait)
{
LOCK(kernel_notifications.m_tip_block_mutex);
interrupt_wait = true;
kernel_notifications.m_tip_block_cv.notify_all();
}
std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
KernelNotifications& kernel_notifications,
CTxMemPool* mempool,
const std::unique_ptr<CBlockTemplate>& block_template,
const BlockWaitOptions& options,
const BlockAssembler::Options& assemble_options)
const BlockAssembler::Options& assemble_options,
bool& interrupt_wait)
{
// Delay calculating the current template fees, just in case a new block
// comes in before the next tick.
@@ -484,8 +492,12 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
// method on BlockTemplate and no template could have been
// generated before a tip exists.
tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock;
return tip_changed || chainman.m_interrupt;
return tip_changed || chainman.m_interrupt || interrupt_wait;
});
if (interrupt_wait) {
interrupt_wait = false;
return nullptr;
}
}
if (chainman.m_interrupt) return nullptr;