@@ -82,6 +82,7 @@ using interfaces::Mining;
8282using interfaces::Node;
8383using interfaces::WalletLoader;
8484using node::BlockAssembler;
85+ using node::BlockWaitOptions;
8586using util::Join;
8687
8788namespace node {
@@ -877,7 +878,11 @@ class ChainImpl : public Chain
877878class BlockTemplateImpl : public BlockTemplate
878879{
879880public:
880- explicit BlockTemplateImpl (std::unique_ptr<CBlockTemplate> block_template, NodeContext& node) : m_block_template(std::move(block_template)), m_node(node)
881+ explicit BlockTemplateImpl (BlockAssembler::Options assemble_options,
882+ std::unique_ptr<CBlockTemplate> block_template,
883+ NodeContext& node) : m_assemble_options(std::move(assemble_options)),
884+ m_block_template(std::move(block_template)),
885+ m_node(node)
881886 {
882887 assert (m_block_template);
883888 }
@@ -942,9 +947,94 @@ class BlockTemplateImpl : public BlockTemplate
942947 return chainman ().ProcessNewBlock (block_ptr, /* force_processing=*/ true , /* min_pow_checked=*/ true , /* new_block=*/ nullptr );
943948 }
944949
950+ std::unique_ptr<BlockTemplate> waitNext (BlockWaitOptions options) override
951+ {
952+ // Delay calculating the current template fees, just in case a new block
953+ // comes in before the next tick.
954+ CAmount current_fees = -1 ;
955+
956+ // Alternate waiting for a new tip and checking if fees have risen.
957+ // The latter check is expensive so we only run it once per second.
958+ auto now{NodeClock::now ()};
959+ const auto deadline = now + options.timeout ;
960+ const MillisecondsDouble tick{1000 };
961+
962+ do {
963+ bool tip_changed{false };
964+ {
965+ WAIT_LOCK (notifications ().m_tip_block_mutex , lock);
966+ // Note that wait_until() checks the predicate before waiting
967+ notifications ().m_tip_block_cv .wait_until (lock, std::min (now + tick, deadline), [&]() EXCLUSIVE_LOCKS_REQUIRED (notifications ().m_tip_block_mutex ) {
968+ AssertLockHeld (notifications ().m_tip_block_mutex );
969+ const auto tip_block{notifications ().TipBlock ()};
970+ // We assume tip_block is set, because this is an instance
971+ // method on BlockTemplate and no template could have been
972+ // generated before a tip exists.
973+ tip_changed = Assume (tip_block) && tip_block != m_block_template->block .hashPrevBlock ;
974+ return tip_changed || chainman ().m_interrupt ;
975+ });
976+ }
977+
978+ if (chainman ().m_interrupt ) return nullptr ;
979+ // At this point the tip changed, a full tick went by or we reached
980+ // the deadline.
981+
982+ // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
983+ LOCK (::cs_main);
984+
985+ /* *
986+ * We determine if fees increased compared to the previous template by generating
987+ * a fresh template. There may be more efficient ways to determine how much
988+ * (approximate) fees for the next block increased, perhaps more so after
989+ * Cluster Mempool.
990+ *
991+ * We'll also create a new template if the tip changed during this iteration.
992+ */
993+ if (options.fee_threshold < MAX_MONEY || tip_changed) {
994+ auto tmpl{std::make_unique<BlockTemplateImpl>(m_assemble_options,
995+ BlockAssembler{
996+ chainman ().ActiveChainstate (),
997+ context ()->mempool .get (),
998+ m_assemble_options}
999+ .CreateNewBlock (),
1000+ m_node)};
1001+
1002+ // If the tip changed, return the new template regardless of its fees.
1003+ if (tip_changed) return tmpl;
1004+
1005+ // Calculate the original template total fees if we haven't already
1006+ if (current_fees == -1 ) {
1007+ current_fees = 0 ;
1008+ for (CAmount fee : m_block_template->vTxFees ) {
1009+ // Skip coinbase
1010+ if (fee < 0 ) continue ;
1011+ current_fees += fee;
1012+ }
1013+ }
1014+
1015+ CAmount new_fees = 0 ;
1016+ for (CAmount fee : tmpl->m_block_template ->vTxFees ) {
1017+ // Skip coinbase
1018+ if (fee < 0 ) continue ;
1019+ new_fees += fee;
1020+ Assume (options.fee_threshold != MAX_MONEY);
1021+ if (new_fees >= current_fees + options.fee_threshold ) return tmpl;
1022+ }
1023+ }
1024+
1025+ now = NodeClock::now ();
1026+ } while (now < deadline);
1027+
1028+ return nullptr ;
1029+ }
1030+
1031+ const BlockAssembler::Options m_assemble_options;
1032+
9451033 const std::unique_ptr<CBlockTemplate> m_block_template;
9461034
1035+ NodeContext* context () { return &m_node; }
9471036 ChainstateManager& chainman () { return *Assert (m_node.chainman ); }
1037+ KernelNotifications& notifications () { return *Assert (m_node.notifications ); }
9481038 NodeContext& m_node;
9491039};
9501040
@@ -991,7 +1081,7 @@ class MinerImpl : public Mining
9911081 {
9921082 BlockAssembler::Options assemble_options{options};
9931083 ApplyArgsManOptions (*Assert (m_node.args ), assemble_options);
994- return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman ().ActiveChainstate (), context ()->mempool .get (), assemble_options}.CreateNewBlock (), m_node);
1084+ return std::make_unique<BlockTemplateImpl>(assemble_options, BlockAssembler{chainman ().ActiveChainstate (), context ()->mempool .get (), assemble_options}.CreateNewBlock (), m_node);
9951085 }
9961086
9971087 NodeContext* context () override { return &m_node; }
0 commit comments