Bitcoin Core 32.99.0
P2P Digital Currency
block_template_manager.cpp
Go to the documentation of this file.
1// Copyright (c) The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
6
7#include <chain.h>
8#include <consensus/amount.h>
9#include <consensus/params.h>
11#include <interfaces/types.h>
12#include <kernel/chainparams.h>
14#include <node/miner.h>
15#include <node/mining_args.h>
16#include <primitives/block.h>
17#include <sync.h>
18#include <uint256.h>
19#include <util/check.h>
21#include <validation.h>
22#include <validationinterface.h>
23
24#include <algorithm>
25#include <compare>
26#include <condition_variable>
27#include <numeric>
28#include <utility>
29#include <vector>
30
31namespace node {
32
34
36 KernelNotifications& notifications,
37 BlockCreateOptions block_create_args)
38 : m_mempool(mempool), m_chainman(chainman), m_notifications(notifications), m_block_create_args(std::move(block_create_args))
39{
40}
41
42std::unique_ptr<CBlockTemplate> BlockTemplateManager::CreateNewTemplate(const BlockCreateOptions& options)
43{
44 return BlockAssembler{
46 &m_mempool,
48 }.CreateNewBlock();
49}
50
51namespace {
52class SubmitBlockStateCatcher final : public CValidationInterface
53{
54public:
56 bool m_found{false};
58
59 explicit SubmitBlockStateCatcher(const uint256& hash) : m_hash{hash} {}
60
61protected:
62 void BlockChecked(const std::shared_ptr<const CBlock>& block, const BlockValidationState& state) override
63 {
64 if (block->GetHash() != m_hash) return;
65 // ProcessNewBlock emits BlockChecked synchronously while holding cs_main,
66 // so SubmitBlock can read these fields after ProcessNewBlock returns
67 // without extra synchronization.
68 m_found = true;
69 m_state = state;
70 }
71};
72} // namespace
73
74bool BlockTemplateManager::SubmitBlock(const std::shared_ptr<const CBlock>& block, std::string& reason, std::string& debug)
75{
76 reason.clear();
77 debug.clear();
78
79 // This follows the submitblock RPC's validation-state capture pattern, but
80 // is intentionally kept separate from the RPC implementation. The RPC entry
81 // point decodes hex, formats BIP22/JSONRPC results, and calls
82 // UpdateUncommittedBlockStructures() for legacy witness handling. IPC
83 // callers submit already-formed blocks and need bool + reason/debug
84 // results.
85 auto sc = std::make_shared<SubmitBlockStateCatcher>(block->GetHash());
86 CHECK_NONFATAL(m_chainman.m_options.signals)->RegisterSharedValidationInterface(sc);
87 bool new_block;
88 bool accepted = m_chainman.ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
89 // No queue drain is needed. The BlockChecked notification used above is
90 // emitted synchronously by ProcessNewBlock, unlike most validation signals.
91 CHECK_NONFATAL(m_chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);
92
93 if (!new_block && accepted) {
94 reason = "duplicate";
95 } else if (!accepted && (!sc->m_found || sc->m_state.IsValid())) {
96 // ProcessNewBlock can fail without a validation result, for example
97 // from an activation or system error. It can also fail after a valid
98 // BlockChecked result. In these cases the validation result is
99 // inconclusive.
100 reason = "inconclusive";
101 } else if (!sc->m_found) {
102 // The block was accepted but not connected, for example if it does not
103 // have more work than the current tip.
104 reason = "inconclusive";
105 } else if (!sc->m_state.IsValid()) {
106 reason = sc->m_state.GetRejectReason();
107 debug = sc->m_state.GetDebugMessage();
108 }
109 const bool result{accepted && new_block && reason.empty()};
110 CHECK_NONFATAL(result == reason.empty());
111 return result;
112}
113
114std::optional<BlockRef> BlockTemplateManager::GetTip()
115{
118 if (!tip) return {};
119 return BlockRef{tip->GetBlockHash(), tip->nHeight};
120}
121
122void BlockTemplateManager::InterruptWait(bool& interrupt_wait)
123{
125 interrupt_wait = true;
126 m_notifications.m_tip_block_cv.notify_all();
127}
128
129std::unique_ptr<CBlockTemplate> BlockTemplateManager::WaitAndCreateNewBlock(
130 const std::unique_ptr<CBlockTemplate>& block_template,
131 const BlockWaitOptions& wait_options,
132 const BlockCreateOptions& create_options,
133 bool& interrupt_wait)
134{
135 // Delay calculating the current template fees, just in case a new block
136 // comes in before the next tick.
137 CAmount current_fees = -1;
138
139 // Alternate waiting for a new tip and checking if fees have risen.
140 // The latter check is expensive so we only run it once per second.
141 auto now{NodeClock::now()};
142 const auto deadline = now + wait_options.timeout;
143 const MillisecondsDouble tick{1000};
144 const bool allow_min_difficulty{m_chainman.GetParams().GetConsensus().fPowAllowMinDifficultyBlocks};
145
146 do {
147 bool tip_changed{false};
148 {
150 // Note that wait_until() checks the predicate before waiting
151 m_notifications.m_tip_block_cv.wait_until(lock, std::min(now + tick, deadline), [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
152 AssertLockHeld(m_notifications.m_tip_block_mutex);
153 const auto tip_block{m_notifications.TipBlock()};
154 // We assume tip_block is set, because this is an instance
155 // method on BlockTemplate and no template could have been
156 // generated before a tip exists.
157 tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock;
158 return tip_changed || m_chainman.m_interrupt || interrupt_wait;
159 });
160 if (interrupt_wait) {
161 interrupt_wait = false;
162 return nullptr;
163 }
164 }
165
166 if (m_chainman.m_interrupt) return nullptr;
167 // At this point the tip changed, a full tick went by or we reached
168 // the deadline.
169
170 // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
172
173 // On test networks return a minimum difficulty block after 20 minutes
174 if (!tip_changed && allow_min_difficulty) {
175 const NodeClock::time_point tip_time{std::chrono::seconds{m_chainman.ActiveChain().Tip()->GetBlockTime()}};
176 if (now > tip_time + 20min) {
177 tip_changed = true;
178 }
179 }
180
189 if (wait_options.fee_threshold < MAX_MONEY || tip_changed) {
190 auto new_tmpl{CreateNewTemplate(create_options)};
191
192 // If the tip changed, return the new template regardless of its fees.
193 if (tip_changed) return new_tmpl;
194
195 // Calculate the original template total fees if we haven't already
196 if (current_fees == -1) {
197 current_fees = std::accumulate(block_template->vTxFees.begin(), block_template->vTxFees.end(), CAmount{0});
198 }
199
200 // Check if fees increased enough to return the new template
201 const CAmount new_fees = std::accumulate(new_tmpl->vTxFees.begin(), new_tmpl->vTxFees.end(), CAmount{0});
202 Assume(wait_options.fee_threshold != MAX_MONEY);
203 if (new_fees >= current_fees + wait_options.fee_threshold) return new_tmpl;
204 }
205
206 now = NodeClock::now();
207 } while (now < deadline);
208
209 return nullptr;
210}
211
212bool BlockTemplateManager::CooldownIfHeadersAhead(const BlockRef& last_tip, bool& interrupt_mining)
213{
214 uint256 last_tip_hash{last_tip.hash};
215
216 while (const std::optional<int> remaining = m_chainman.BlocksAheadOfTip()) {
217 const int cooldown_seconds = std::clamp(*remaining, 3, 20);
218 const auto cooldown_deadline{MockableSteadyClock::now() + std::chrono::seconds{cooldown_seconds}};
219
220 {
221 WAIT_LOCK(m_notifications.m_tip_block_mutex, lock);
222 m_notifications.m_tip_block_cv.wait_until(lock, cooldown_deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
223 const auto tip_block = m_notifications.TipBlock();
224 return m_chainman.m_interrupt || interrupt_mining || (tip_block && *tip_block != last_tip_hash);
225 });
226 if (m_chainman.m_interrupt || interrupt_mining) {
227 interrupt_mining = false;
228 return false;
229 }
230
231 // If the tip changed during the wait, extend the deadline
232 const auto tip_block = m_notifications.TipBlock();
233 if (tip_block && *tip_block != last_tip_hash) {
234 last_tip_hash = *tip_block;
235 continue;
236 }
237 }
238
239 // No tip change and the cooldown window has expired.
240 if (MockableSteadyClock::now() >= cooldown_deadline) break;
241 }
242
243 return true;
244}
245
246std::optional<BlockRef> BlockTemplateManager::WaitTipChanged(const uint256& current_tip, MillisecondsDouble timeout)
247{
248 bool interrupt_wait{false};
249 return WaitTipChanged(current_tip, timeout, interrupt_wait);
250}
251
252std::optional<BlockRef> BlockTemplateManager::WaitTipChanged(const uint256& current_tip, MillisecondsDouble& timeout, bool& interrupt)
253{
254 Assume(timeout >= 0ms); // No internal callers should use a negative timeout
255 if (timeout < 0ms) timeout = 0ms;
256 if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono
257 auto deadline{std::chrono::steady_clock::now() + timeout};
258 {
259 WAIT_LOCK(m_notifications.m_tip_block_mutex, lock);
260 // For callers convenience, wait longer than the provided timeout
261 // during startup for the tip to be non-null. That way this function
262 // always returns valid tip information when possible and only
263 // returns null when shutting down, not when timing out.
264 m_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
265 AssertLockHeld(m_notifications.m_tip_block_mutex);
266 return m_notifications.TipBlock() || m_chainman.m_interrupt || interrupt;
267 });
268 if (m_chainman.m_interrupt || interrupt) {
269 interrupt = false;
270 return {};
271 }
272 // At this point TipBlock is set, so continue to wait until it is
273 // different from `current_tip` provided by caller.
274 m_notifications.m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
275 return Assume(m_notifications.TipBlock()) != current_tip || m_chainman.m_interrupt || interrupt;
276 });
277 if (m_chainman.m_interrupt || interrupt) {
278 interrupt = false;
279 return {};
280 }
281 }
282
283 // Must release m_tip_block_mutex before GetTip() locks cs_main, to
284 // avoid deadlocks.
285 return GetTip();
286}
287
288} // namespace node
constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:26
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
BlockValidationState m_state
uint256 m_hash
bool m_found
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:112
#define Assume(val)
Assume is the identity function.
Definition: check.h:128
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:94
int64_t GetBlockTime() const
Definition: chain.h:221
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:396
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:89
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:187
Implement this to subscribe to events generated in validation and mempool.
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
Definition: validation.h:950
Chainstate & ActiveChainstate() const
Alternatives to CurrentChainstate() used by older code to query latest chainstate information without...
bool ProcessNewBlock(const std::shared_ptr< const CBlock > &block, bool force_processing, bool min_pow_checked, bool *new_block) LOCKS_EXCLUDED(cs_main)
Process an incoming block.
const util::SignalInterrupt & m_interrupt
Definition: validation.h:1044
const CChainParams & GetParams() const
Definition: validation.h:1017
const Options m_options
Definition: validation.h:1045
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Definition: validation.h:1178
Generate a new block, without valid proof-of-work.
Definition: miner.h:51
BlockTemplateManager(CTxMemPool &mempool, ChainstateManager &chainman, KernelNotifications &notifications, BlockCreateOptions block_create_args={})
std::unique_ptr< CBlockTemplate > CreateNewTemplate(const BlockCreateOptions &options)
Create a fresh block template, applying init-time defaults to any unset options.
bool SubmitBlock(const std::shared_ptr< const CBlock > &block, std::string &reason, std::string &debug)
Submit a block via ProcessNewBlock and capture validation state.
std::optional< interfaces::BlockRef > GetTip()
Locks cs_main.
const BlockCreateOptions m_block_create_args
KernelNotifications & m_notifications
void InterruptWait(bool &interrupt_wait)
Interrupt a blocking wait.
std::unique_ptr< CBlockTemplate > WaitAndCreateNewBlock(const std::unique_ptr< CBlockTemplate > &block_template, const BlockWaitOptions &wait_options, const BlockCreateOptions &create_options, bool &interrupt_wait)
Return a new block template when fees rise to a certain threshold or after a new tip; return nullptr ...
256-bit opaque blob.
Definition: uint256.h:196
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
Definition: messages.h:21
BlockCreateOptions MergeMiningOptions(BlockCreateOptions x, const BlockCreateOptions &y)
Merge two BlockCreateOptions structs, replacing null values in x with non-null values from y.
Definition: mining_args.cpp:90
std::shared_ptr< Chain::Notifications > m_notifications
Definition: interfaces.cpp:497
bool fPowAllowMinDifficultyBlocks
Definition: params.h:117
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:64
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:38
std::chrono::time_point< NodeClock > time_point
Definition: time.h:28
Hash/height pair to help track and identify blocks.
Definition: types.h:13
uint256 hash
Definition: types.h:14
Block template creation options.
Definition: mining_types.h:33
MillisecondsDouble timeout
How long to wait before returning nullptr instead of a new template.
Definition: mining_types.h:99
CAmount fee_threshold
The wait method will not return a new template unless it has fees at least fee_threshold sats higher ...
Definition: mining_types.h:112
#define WAIT_LOCK(cs, name)
Definition: sync.h:274
#define LOCK(cs)
Definition: sync.h:268
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
std::chrono::duration< double, std::chrono::milliseconds::period > MillisecondsDouble
Definition: time.h:103