mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-18 08:32:30 +01:00
interfaces: add interruptWait method
- This method can be used to cancel a running waitNext(). - This commit also adds a test case for interruptWait method
This commit is contained in:
@@ -72,6 +72,11 @@ public:
|
||||
* the tip is more than 20 minutes old.
|
||||
*/
|
||||
virtual std::unique_ptr<BlockTemplate> waitNext(const node::BlockWaitOptions options = {}) = 0;
|
||||
|
||||
/**
|
||||
* Interrupts the current wait for the next block template.
|
||||
*/
|
||||
virtual void interruptWait() = 0;
|
||||
};
|
||||
|
||||
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future)
|
||||
|
||||
@@ -33,6 +33,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
|
||||
getCoinbaseMerklePath @8 (context: Proxy.Context) -> (result: List(Data));
|
||||
submitSolution @9 (context: Proxy.Context, version: UInt32, timestamp: UInt32, nonce: UInt32, coinbase :Data) -> (result: Bool);
|
||||
waitNext @10 (context: Proxy.Context, options: BlockWaitOptions) -> (result: BlockTemplate);
|
||||
interruptWait @11() -> ();
|
||||
}
|
||||
|
||||
struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") {
|
||||
|
||||
@@ -918,15 +918,21 @@ public:
|
||||
|
||||
std::unique_ptr<BlockTemplate> waitNext(BlockWaitOptions options) override
|
||||
{
|
||||
auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options);
|
||||
auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options, m_interrupt_wait);
|
||||
if (new_template) return std::make_unique<BlockTemplateImpl>(m_assemble_options, std::move(new_template), m_node);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void interruptWait() override
|
||||
{
|
||||
InterruptWait(notifications(), m_interrupt_wait);
|
||||
}
|
||||
|
||||
const BlockAssembler::Options m_assemble_options;
|
||||
|
||||
const std::unique_ptr<CBlockTemplate> m_block_template;
|
||||
|
||||
bool m_interrupt_wait{false};
|
||||
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
|
||||
KernelNotifications& notifications() { return *Assert(m_node.notifications); }
|
||||
NodeContext& m_node;
|
||||
|
||||
@@ -453,12 +453,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.
|
||||
@@ -483,8 +491,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;
|
||||
|
||||
@@ -238,6 +238,9 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti
|
||||
/* Compute the block's merkle root, insert or replace the coinbase transaction and the merkle root into the block */
|
||||
void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
|
||||
|
||||
|
||||
/* Interrupt the current wait for the next block template. */
|
||||
void InterruptWait(KernelNotifications& kernel_notifications, bool& interrupt_wait);
|
||||
/**
|
||||
* Return a new block template when fees rise to a certain threshold or after a
|
||||
* new tip; return nullopt if timeout is reached.
|
||||
@@ -247,7 +250,8 @@ std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainma
|
||||
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);
|
||||
|
||||
/* Locks cs_main and returns the block hash and block height of the active chain if it exists; otherwise, returns nullopt.*/
|
||||
std::optional<BlockRef> GetTip(ChainstateManager& chainman);
|
||||
|
||||
@@ -182,6 +182,28 @@ class IPCInterfaceTest(BitcoinTestFramework):
|
||||
template7 = await template6.result.waitNext(ctx, waitoptions)
|
||||
assert_equal(template7.to_dict(), {})
|
||||
|
||||
self.log.debug("interruptWait should abort the current wait")
|
||||
wait_started = asyncio.Event()
|
||||
async def wait_for_block():
|
||||
new_waitoptions = self.capnp_modules['mining'].BlockWaitOptions()
|
||||
new_waitoptions.timeout = waitoptions.timeout * 60 # 1 minute wait
|
||||
new_waitoptions.feeThreshold = 1
|
||||
wait_started.set()
|
||||
return await template6.result.waitNext(ctx, new_waitoptions)
|
||||
|
||||
async def interrupt_wait():
|
||||
await wait_started.wait() # Wait for confirmation wait started
|
||||
await asyncio.sleep(0.1) # Minimal buffer
|
||||
template6.result.interruptWait()
|
||||
miniwallet.send_self_transfer(fee_rate=10, from_node=self.nodes[0])
|
||||
|
||||
wait_task = asyncio.create_task(wait_for_block())
|
||||
interrupt_task = asyncio.create_task(interrupt_wait())
|
||||
|
||||
result = await wait_task
|
||||
await interrupt_task
|
||||
assert_equal(result.to_dict(), {})
|
||||
|
||||
current_block_height = self.nodes[0].getchaintips()[0]["height"]
|
||||
check_opts = self.capnp_modules['mining'].BlockCheckOptions()
|
||||
template = await mining.result.createNewBlock(opts)
|
||||
|
||||
Reference in New Issue
Block a user