Skip to content

Commit 720f201

Browse files
committed
interfaces: refactor: move waitNext implementation to miner
- We now assert for a valid chainman and notifications once when invoking WaitAndCreateNewBlock function.
1 parent e6c2f4c commit 720f201

File tree

3 files changed

+107
-82
lines changed

3 files changed

+107
-82
lines changed

src/node/interfaces.cpp

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -935,95 +935,15 @@ class BlockTemplateImpl : public BlockTemplate
935935

936936
std::unique_ptr<BlockTemplate> waitNext(BlockWaitOptions options) override
937937
{
938-
// Delay calculating the current template fees, just in case a new block
939-
// comes in before the next tick.
940-
CAmount current_fees = -1;
941-
942-
// Alternate waiting for a new tip and checking if fees have risen.
943-
// The latter check is expensive so we only run it once per second.
944-
auto now{NodeClock::now()};
945-
const auto deadline = now + options.timeout;
946-
const MillisecondsDouble tick{1000};
947-
const bool allow_min_difficulty{chainman().GetParams().GetConsensus().fPowAllowMinDifficultyBlocks};
948-
949-
do {
950-
bool tip_changed{false};
951-
{
952-
WAIT_LOCK(notifications().m_tip_block_mutex, lock);
953-
// Note that wait_until() checks the predicate before waiting
954-
notifications().m_tip_block_cv.wait_until(lock, std::min(now + tick, deadline), [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) {
955-
AssertLockHeld(notifications().m_tip_block_mutex);
956-
const auto tip_block{notifications().TipBlock()};
957-
// We assume tip_block is set, because this is an instance
958-
// method on BlockTemplate and no template could have been
959-
// generated before a tip exists.
960-
tip_changed = Assume(tip_block) && tip_block != m_block_template->block.hashPrevBlock;
961-
return tip_changed || chainman().m_interrupt;
962-
});
963-
}
964-
965-
if (chainman().m_interrupt) return nullptr;
966-
// At this point the tip changed, a full tick went by or we reached
967-
// the deadline.
968-
969-
// Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
970-
LOCK(::cs_main);
971-
972-
// On test networks return a minimum difficulty block after 20 minutes
973-
if (!tip_changed && allow_min_difficulty) {
974-
const NodeClock::time_point tip_time{std::chrono::seconds{chainman().ActiveChain().Tip()->GetBlockTime()}};
975-
if (now > tip_time + 20min) {
976-
tip_changed = true;
977-
}
978-
}
979-
980-
/**
981-
* We determine if fees increased compared to the previous template by generating
982-
* a fresh template. There may be more efficient ways to determine how much
983-
* (approximate) fees for the next block increased, perhaps more so after
984-
* Cluster Mempool.
985-
*
986-
* We'll also create a new template if the tip changed during this iteration.
987-
*/
988-
if (options.fee_threshold < MAX_MONEY || tip_changed) {
989-
auto tmpl{std::make_unique<BlockTemplateImpl>(m_assemble_options,
990-
BlockAssembler{
991-
chainman().ActiveChainstate(),
992-
context()->mempool.get(),
993-
m_assemble_options}
994-
.CreateNewBlock(),
995-
m_node)};
996-
997-
// If the tip changed, return the new template regardless of its fees.
998-
if (tip_changed) return tmpl;
999-
1000-
// Calculate the original template total fees if we haven't already
1001-
if (current_fees == -1) {
1002-
current_fees = 0;
1003-
for (CAmount fee : m_block_template->vTxFees) {
1004-
current_fees += fee;
1005-
}
1006-
}
1007-
1008-
CAmount new_fees = 0;
1009-
for (CAmount fee : tmpl->m_block_template->vTxFees) {
1010-
new_fees += fee;
1011-
Assume(options.fee_threshold != MAX_MONEY);
1012-
if (new_fees >= current_fees + options.fee_threshold) return tmpl;
1013-
}
1014-
}
1015-
1016-
now = NodeClock::now();
1017-
} while (now < deadline);
1018-
938+
auto new_template = WaitAndCreateNewBlock(chainman(), notifications(), m_node.mempool.get(), m_block_template, options, m_assemble_options);
939+
if (new_template) return std::make_unique<BlockTemplateImpl>(m_assemble_options, std::move(new_template), m_node);
1019940
return nullptr;
1020941
}
1021942

1022943
const BlockAssembler::Options m_assemble_options;
1023944

1024945
const std::unique_ptr<CBlockTemplate> m_block_template;
1025946

1026-
NodeContext* context() { return &m_node; }
1027947
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
1028948
KernelNotifications& notifications() { return *Assert(m_node.notifications); }
1029949
NodeContext& m_node;

src/node/miner.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616
#include <consensus/validation.h>
1717
#include <deploymentstatus.h>
1818
#include <logging.h>
19+
#include <node/context.h>
20+
#include <node/kernel_notifications.h>
1921
#include <policy/feerate.h>
2022
#include <policy/policy.h>
2123
#include <pow.h>
2224
#include <primitives/transaction.h>
2325
#include <util/moneystr.h>
26+
#include <util/signalinterrupt.h>
2427
#include <util/time.h>
2528
#include <validation.h>
2629

@@ -447,4 +450,93 @@ void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t
447450
block.nNonce = nonce;
448451
block.hashMerkleRoot = BlockMerkleRoot(block);
449452
}
453+
454+
std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
455+
KernelNotifications& kernel_notifications,
456+
CTxMemPool* mempool,
457+
const std::unique_ptr<CBlockTemplate>& block_template,
458+
const BlockWaitOptions& options,
459+
const BlockAssembler::Options& assemble_options)
460+
{
461+
// Delay calculating the current template fees, just in case a new block
462+
// comes in before the next tick.
463+
CAmount current_fees = -1;
464+
465+
// Alternate waiting for a new tip and checking if fees have risen.
466+
// The latter check is expensive so we only run it once per second.
467+
auto now{NodeClock::now()};
468+
const auto deadline = now + options.timeout;
469+
const MillisecondsDouble tick{1000};
470+
const bool allow_min_difficulty{chainman.GetParams().GetConsensus().fPowAllowMinDifficultyBlocks};
471+
472+
do {
473+
bool tip_changed{false};
474+
{
475+
WAIT_LOCK(kernel_notifications.m_tip_block_mutex, lock);
476+
// Note that wait_until() checks the predicate before waiting
477+
kernel_notifications.m_tip_block_cv.wait_until(lock, std::min(now + tick, deadline), [&]() EXCLUSIVE_LOCKS_REQUIRED(kernel_notifications.m_tip_block_mutex) {
478+
AssertLockHeld(kernel_notifications.m_tip_block_mutex);
479+
const auto tip_block{kernel_notifications.TipBlock()};
480+
// We assume tip_block is set, because this is an instance
481+
// method on BlockTemplate and no template could have been
482+
// generated before a tip exists.
483+
tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock;
484+
return tip_changed || chainman.m_interrupt;
485+
});
486+
}
487+
488+
if (chainman.m_interrupt) return nullptr;
489+
// At this point the tip changed, a full tick went by or we reached
490+
// the deadline.
491+
492+
// Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
493+
LOCK(::cs_main);
494+
495+
// On test networks return a minimum difficulty block after 20 minutes
496+
if (!tip_changed && allow_min_difficulty) {
497+
const NodeClock::time_point tip_time{std::chrono::seconds{chainman.ActiveChain().Tip()->GetBlockTime()}};
498+
if (now > tip_time + 20min) {
499+
tip_changed = true;
500+
}
501+
}
502+
503+
/**
504+
* We determine if fees increased compared to the previous template by generating
505+
* a fresh template. There may be more efficient ways to determine how much
506+
* (approximate) fees for the next block increased, perhaps more so after
507+
* Cluster Mempool.
508+
*
509+
* We'll also create a new template if the tip changed during this iteration.
510+
*/
511+
if (options.fee_threshold < MAX_MONEY || tip_changed) {
512+
auto new_tmpl{BlockAssembler{
513+
chainman.ActiveChainstate(),
514+
mempool,
515+
assemble_options}
516+
.CreateNewBlock()};
517+
518+
// If the tip changed, return the new template regardless of its fees.
519+
if (tip_changed) return new_tmpl;
520+
521+
// Calculate the original template total fees if we haven't already
522+
if (current_fees == -1) {
523+
current_fees = 0;
524+
for (CAmount fee : block_template->vTxFees) {
525+
current_fees += fee;
526+
}
527+
}
528+
529+
CAmount new_fees = 0;
530+
for (CAmount fee : new_tmpl->vTxFees) {
531+
new_fees += fee;
532+
Assume(options.fee_threshold != MAX_MONEY);
533+
if (new_fees >= current_fees + options.fee_threshold) return new_tmpl;
534+
}
535+
}
536+
537+
now = NodeClock::now();
538+
} while (now < deadline);
539+
540+
return nullptr;
541+
}
450542
} // namespace node

src/node/miner.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class ChainstateManager;
3232
namespace Consensus { struct Params; };
3333

3434
namespace node {
35+
class KernelNotifications;
36+
3537
static const bool DEFAULT_PRINT_MODIFIED_FEE = false;
3638

3739
struct CBlockTemplate
@@ -232,6 +234,17 @@ void ApplyArgsManOptions(const ArgsManager& gArgs, BlockAssembler::Options& opti
232234

233235
/* Compute the block's merkle root, insert or replace the coinbase transaction and the merkle root into the block */
234236
void AddMerkleRootAndCoinbase(CBlock& block, CTransactionRef coinbase, uint32_t version, uint32_t timestamp, uint32_t nonce);
237+
238+
/**
239+
* Return a new block template when fees rise to a certain threshold or after a
240+
* new tip; return nullopt if timeout is reached.
241+
*/
242+
std::unique_ptr<CBlockTemplate> WaitAndCreateNewBlock(ChainstateManager& chainman,
243+
KernelNotifications& kernel_notifications,
244+
CTxMemPool* mempool,
245+
const std::unique_ptr<CBlockTemplate>& block_template,
246+
const BlockWaitOptions& options,
247+
const BlockAssembler::Options& assemble_options);
235248
} // namespace node
236249

237250
#endif // BITCOIN_NODE_MINER_H

0 commit comments

Comments
 (0)