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>
15#include <node/miner.h>
16#include <node/mining_args.h>
17#include <primitives/block.h>
18#include <sync.h>
19#include <uint256.h>
20#include <util/check.h>
22#include <validation.h>
23#include <validationinterface.h>
24
25#include <algorithm>
26#include <compare>
27#include <condition_variable>
28#include <numeric>
29#include <utility>
30#include <vector>
31
32namespace node {
33
35
37 KernelNotifications& notifications,
38 BlockCreateOptions block_create_args)
39 : m_mempool(mempool), m_chainman(chainman), m_notifications(notifications), m_block_create_args(std::move(block_create_args))
40{
41}
42
43std::unique_ptr<CBlockTemplate> BlockTemplateManager::CreateNewTemplate(const BlockCreateOptions& options)
44{
45 return BlockAssembler{
47 &m_mempool,
49 }.CreateNewBlock();
50}
51
52bool BlockTemplateManager::SubmitBlock(const std::shared_ptr<const CBlock>& block, std::string& reason, std::string& debug)
53{
54 reason.clear();
55 debug.clear();
56
57 // This follows the submitblock RPC's validation-state capture pattern, but
58 // is intentionally kept separate from the RPC implementation. The RPC entry
59 // point decodes hex, formats BIP22/JSONRPC results, and calls
60 // UpdateUncommittedBlockStructures() for legacy witness handling. IPC
61 // callers submit already-formed blocks and need bool + reason/debug
62 // results.
63 auto sc = std::make_shared<BlockValidationStateCatcher>(block->GetHash());
64 CHECK_NONFATAL(m_chainman.m_options.signals)->RegisterSharedValidationInterface(sc);
65 bool new_block;
66 bool accepted = m_chainman.ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
67 // No queue drain is needed. The BlockChecked notification used above is
68 // emitted synchronously by ProcessNewBlock, unlike most validation signals.
69 CHECK_NONFATAL(m_chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);
70
71 if (!new_block && accepted) {
72 reason = "duplicate";
73 } else if (!accepted && (!sc->m_state || sc->m_state->IsValid())) {
74 // ProcessNewBlock can fail without a validation result, for example
75 // from an activation or system error. It can also fail after a valid
76 // BlockChecked result. In these cases the validation result is
77 // inconclusive.
78 reason = "inconclusive";
79 } else if (!sc->m_state) {
80 // The block was accepted but not connected, for example if it does not
81 // have more work than the current tip.
82 reason = "inconclusive";
83 } else if (!sc->m_state->IsValid()) {
84 reason = sc->m_state->GetRejectReason();
85 debug = sc->m_state->GetDebugMessage();
86 }
87 const bool result{accepted && new_block && reason.empty()};
88 CHECK_NONFATAL(result == reason.empty());
89 return result;
90}
91
92std::optional<BlockRef> BlockTemplateManager::GetTip()
93{
96 if (!tip) return {};
97 return BlockRef{tip->GetBlockHash(), tip->nHeight};
98}
99
100void BlockTemplateManager::InterruptWait(bool& interrupt_wait)
101{
103 interrupt_wait = true;
104 m_notifications.m_tip_block_cv.notify_all();
105}
106
107std::unique_ptr<CBlockTemplate> BlockTemplateManager::WaitAndCreateNewBlock(
108 const std::unique_ptr<CBlockTemplate>& block_template,
109 const BlockWaitOptions& wait_options,
110 const BlockCreateOptions& create_options,
111 bool& interrupt_wait)
112{
113 // Delay calculating the current template fees, just in case a new block
114 // comes in before the next tick.
115 CAmount current_fees = -1;
116
117 // Alternate waiting for a new tip and checking if fees have risen.
118 // The latter check is expensive so we only run it once per second.
119 auto now{NodeClock::now()};
120 const auto deadline = now + wait_options.timeout;
121 const MillisecondsDouble tick{1000};
122 const bool allow_min_difficulty{m_chainman.GetParams().GetConsensus().fPowAllowMinDifficultyBlocks};
123
124 do {
125 bool tip_changed{false};
126 {
128 // Note that wait_until() checks the predicate before waiting
129 m_notifications.m_tip_block_cv.wait_until(lock, std::min(now + tick, deadline), [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
130 AssertLockHeld(m_notifications.m_tip_block_mutex);
131 const auto tip_block{m_notifications.TipBlock()};
132 // We assume tip_block is set, because this is an instance
133 // method on BlockTemplate and no template could have been
134 // generated before a tip exists.
135 tip_changed = Assume(tip_block) && tip_block != block_template->block.hashPrevBlock;
136 return tip_changed || m_chainman.m_interrupt || interrupt_wait;
137 });
138 if (interrupt_wait) {
139 interrupt_wait = false;
140 return nullptr;
141 }
142 }
143
144 if (m_chainman.m_interrupt) return nullptr;
145 // At this point the tip changed, a full tick went by or we reached
146 // the deadline.
147
148 // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
150
151 // On test networks return a minimum difficulty block after 20 minutes
152 if (!tip_changed && allow_min_difficulty) {
153 const NodeClock::time_point tip_time{std::chrono::seconds{m_chainman.ActiveChain().Tip()->GetBlockTime()}};
154 if (now > tip_time + 20min) {
155 tip_changed = true;
156 }
157 }
158
167 if (wait_options.fee_threshold < MAX_MONEY || tip_changed) {
168 auto new_tmpl{CreateNewTemplate(create_options)};
169
170 // If the tip changed, return the new template regardless of its fees.
171 if (tip_changed) return new_tmpl;
172
173 // Calculate the original template total fees if we haven't already
174 if (current_fees == -1) {
175 current_fees = std::accumulate(block_template->vTxFees.begin(), block_template->vTxFees.end(), CAmount{0});
176 }
177
178 // Check if fees increased enough to return the new template
179 const CAmount new_fees = std::accumulate(new_tmpl->vTxFees.begin(), new_tmpl->vTxFees.end(), CAmount{0});
180 Assume(wait_options.fee_threshold != MAX_MONEY);
181 if (new_fees >= current_fees + wait_options.fee_threshold) return new_tmpl;
182 }
183
184 now = NodeClock::now();
185 } while (now < deadline);
186
187 return nullptr;
188}
189
190bool BlockTemplateManager::CooldownIfHeadersAhead(const BlockRef& last_tip, bool& interrupt_mining)
191{
192 uint256 last_tip_hash{last_tip.hash};
193
194 while (const std::optional<int> remaining = m_chainman.BlocksAheadOfTip()) {
195 const int cooldown_seconds = std::clamp(*remaining, 3, 20);
196 const auto cooldown_deadline{MockableSteadyClock::now() + std::chrono::seconds{cooldown_seconds}};
197
198 {
199 WAIT_LOCK(m_notifications.m_tip_block_mutex, lock);
200 m_notifications.m_tip_block_cv.wait_until(lock, cooldown_deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
201 const auto tip_block = m_notifications.TipBlock();
202 return m_chainman.m_interrupt || interrupt_mining || (tip_block && *tip_block != last_tip_hash);
203 });
204 if (m_chainman.m_interrupt || interrupt_mining) {
205 interrupt_mining = false;
206 return false;
207 }
208
209 // If the tip changed during the wait, extend the deadline
210 const auto tip_block = m_notifications.TipBlock();
211 if (tip_block && *tip_block != last_tip_hash) {
212 last_tip_hash = *tip_block;
213 continue;
214 }
215 }
216
217 // No tip change and the cooldown window has expired.
218 if (MockableSteadyClock::now() >= cooldown_deadline) break;
219 }
220
221 return true;
222}
223
224std::optional<BlockRef> BlockTemplateManager::WaitTipChanged(const uint256& current_tip, MillisecondsDouble timeout)
225{
226 bool interrupt_wait{false};
227 return WaitTipChanged(current_tip, timeout, interrupt_wait);
228}
229
230std::optional<BlockRef> BlockTemplateManager::WaitTipChanged(const uint256& current_tip, MillisecondsDouble& timeout, bool& interrupt)
231{
232 Assume(timeout >= 0ms); // No internal callers should use a negative timeout
233 if (timeout < 0ms) timeout = 0ms;
234 if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono
235 auto deadline{std::chrono::steady_clock::now() + timeout};
236 {
237 WAIT_LOCK(m_notifications.m_tip_block_mutex, lock);
238 // For callers convenience, wait longer than the provided timeout
239 // during startup for the tip to be non-null. That way this function
240 // always returns valid tip information when possible and only
241 // returns null when shutting down, not when timing out.
242 m_notifications.m_tip_block_cv.wait(lock, [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
243 AssertLockHeld(m_notifications.m_tip_block_mutex);
244 return m_notifications.TipBlock() || m_chainman.m_interrupt || interrupt;
245 });
246 if (m_chainman.m_interrupt || interrupt) {
247 interrupt = false;
248 return {};
249 }
250 // At this point TipBlock is set, so continue to wait until it is
251 // different from `current_tip` provided by caller.
252 m_notifications.m_tip_block_cv.wait_until(lock, deadline, [&]() EXCLUSIVE_LOCKS_REQUIRED(m_notifications.m_tip_block_mutex) {
253 return Assume(m_notifications.TipBlock()) != current_tip || m_chainman.m_interrupt || interrupt;
254 });
255 if (m_chainman.m_interrupt || interrupt) {
256 interrupt = false;
257 return {};
258 }
259 }
260
261 // Must release m_tip_block_mutex before GetTip() locks cs_main, to
262 // avoid deadlocks.
263 return GetTip();
264}
265
266} // 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
#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:188
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:492
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