@@ -82,6 +82,7 @@ using interfaces::Mining;
82
82
using interfaces::Node;
83
83
using interfaces::WalletLoader;
84
84
using node::BlockAssembler;
85
+ using node::BlockWaitOptions;
85
86
using util::Join;
86
87
87
88
namespace node {
@@ -877,7 +878,11 @@ class ChainImpl : public Chain
877
878
class BlockTemplateImpl : public BlockTemplate
878
879
{
879
880
public:
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)
881
886
{
882
887
assert (m_block_template);
883
888
}
@@ -942,9 +947,94 @@ class BlockTemplateImpl : public BlockTemplate
942
947
return chainman ().ProcessNewBlock (block_ptr, /* force_processing=*/ true , /* min_pow_checked=*/ true , /* new_block=*/ nullptr );
943
948
}
944
949
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
+
945
1033
const std::unique_ptr<CBlockTemplate> m_block_template;
946
1034
1035
+ NodeContext* context () { return &m_node; }
947
1036
ChainstateManager& chainman () { return *Assert (m_node.chainman ); }
1037
+ KernelNotifications& notifications () { return *Assert (m_node.notifications ); }
948
1038
NodeContext& m_node;
949
1039
};
950
1040
@@ -991,7 +1081,7 @@ class MinerImpl : public Mining
991
1081
{
992
1082
BlockAssembler::Options assemble_options{options};
993
1083
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);
995
1085
}
996
1086
997
1087
NodeContext* context () override { return &m_node; }
0 commit comments