Skip to content

Commit dcb56fd

Browse files
committed
interfaces: add interruptWait method
- This method can be used to cancel a running waitNext(). - This commit also adds a test case for interruptWait method
1 parent 5637479 commit dcb56fd

File tree

6 files changed

+54
-4
lines changed

6 files changed

+54
-4
lines changed

src/interfaces/mining.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ class BlockTemplate
7272
* the tip is more than 20 minutes old.
7373
*/
7474
virtual std::unique_ptr<BlockTemplate> waitNext(const node::BlockWaitOptions options = {}) = 0;
75+
76+
/**
77+
* Interrupts the current wait for the next block template.
78+
*/
79+
virtual void interruptWait() = 0;
7580
};
7681

7782
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future)

src/ipc/capnp/mining.capnp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
3333
getCoinbaseMerklePath @8 (context: Proxy.Context) -> (result: List(Data));
3434
submitSolution @9 (context: Proxy.Context, version: UInt32, timestamp: UInt32, nonce: UInt32, coinbase :Data) -> (result: Bool);
3535
waitNext @10 (context: Proxy.Context, options: BlockWaitOptions) -> (result: BlockTemplate);
36+
interruptWait @11() -> ();
3637
}
3738

3839
struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") {

src/node/interfaces.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -918,15 +918,21 @@ class BlockTemplateImpl : public BlockTemplate
918918

919919
std::unique_ptr<BlockTemplate> waitNext(BlockWaitOptions options) override
920920
{
921-
auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options);
921+
auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options, m_interrupt_wait);
922922
if (new_template) return std::make_unique<BlockTemplateImpl>(m_assemble_options, std::move(new_template), m_node);
923923
return nullptr;
924924
}
925925

926+
void interruptWait() override
927+
{
928+
InterruptWait(notifications(), m_interrupt_wait);
929+
}
930+
926931
const BlockAssembler::Options m_assemble_options;
927932

928933
const std::unique_ptr<CBlockTemplate> m_block_template;
929934

935+
bool m_interrupt_wait{false};
930936
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
931937
KernelNotifications& notifications() { return *Assert(m_node.notifications); }
932938
NodeContext& m_node;

src/node/miner.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,12 +453,20 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
453453
block.hashMerkleRoot = BlockMerkleRoot(block);
454454
}
455455

456+
void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait)
457+
{
458+
LOCK(kernel_notifications.m_tip_block_mutex);
459+
interrupt_wait = true;
460+
kernel_notifications.m_tip_block_cv.notify_all();
461+
}
462+
456463
std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
457464
KernelNotifications& kernel_notifications,
458465
CTxMemPool* mempool,
459466
const std::unique_ptr<CBlockTemplate>& block_template,
460467
const BlockWaitOptions& options,
461-
const BlockAssembler::Options& assemble_options)
468+
const BlockAssembler::Options& assemble_options,
469+
bool& interrupt_wait)
462470
{
463471
// Delay calculating the current template fees, just in case a new block
464472
// comes in before the next tick.
@@ -483,8 +491,12 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
483491
// method on BlockTemplate and no template could have been
484492
// generated before a tip exists.
485493
tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock;
486-
return tip_changed || chainman.m_interrupt;
494+
return tip_changed || chainman.m_interrupt || interrupt_wait;
487495
});
496+
if (interrupt_wait) {
497+
interrupt_wait = false;
498+
return nullptr;
499+
}
488500
}
489501

490502
if (chainman.m_interrupt) return nullptr;

src/node/miner.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,9 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti
238238
/* Compute the block's merkle root, insert or replace the coinbase transaction and the merkle root into the block */
239239
void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
240240

241+
242+
/* Interrupt the current wait for the next block template. */
243+
void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait);
241244
/**
242245
* Return a new block template when fees rise to a certain threshold or after a
243246
* new tip; return nullopt if timeout is reached.
@@ -247,7 +250,8 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
247250
CTxMemPool* mempool,
248251
const std::unique_ptr<CBlockTemplate>& block_template,
249252
const BlockWaitOptions& options,
250-
const BlockAssembler::Options& assemble_options);
253+
const BlockAssembler::Options& assemble_options,
254+
bool& interrupt_wait);
251255

252256
/* Locks cs_main and returns the block hash and block height of the active chain if it exists; otherwise, returns nullopt.*/
253257
std::optional<BlockRef> GetTip(ChainstateManager& chainman);

test/functional/interface_ipc.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,28 @@ async def async_routine():
182182
template7 = await template6.result.waitNext(ctx, waitoptions)
183183
assert_equal(template7.to_dict(), {})
184184

185+
self.log.debug("interruptWait should abort the current wait")
186+
wait_started = asyncio.Event()
187+
async def wait_for_block():
188+
new_waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
189+
new_waitoptions.timeout = waitoptions.timeout * 60 # 1 minute wait
190+
new_waitoptions.feeThreshold = 1
191+
wait_started.set()
192+
return await template6.result.waitNext(ctx, new_waitoptions)
193+
194+
async def interrupt_wait():
195+
await wait_started.wait() # Wait for confirmation wait started
196+
await asyncio.sleep(0.1) # Minimal buffer
197+
template6.result.interruptWait()
198+
miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
199+
200+
wait_task = asyncio.create_task(wait_for_block())
201+
interrupt_task = asyncio.create_task(interrupt_wait())
202+
203+
result = await wait_task
204+
await interrupt_task
205+
assert_equal(result.to_dict(), {})
206+
185207
current_block_height = self.nodes[0].getchaintips()[0]["height"]
186208
check_opts = self.capnp_modules['mining'].BlockCheckOptions()
187209
template = await mining.result.createNewBlock(opts)

0 commit comments

Comments
 (0)