Bitcoin Core 31.99.0
P2P Digital Currency
connect_block.cpp
Go to the documentation of this file.
1// Copyright (c) 2026-present 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
5#include <addresstype.h>
6#include <chain.h>
7#include <consensus/amount.h>
8#include <consensus/merkle.h>
10#include <node/mining_types.h>
11#include <primitives/block.h>
13#include <pubkey.h>
14#include <script/interpreter.h>
15#include <script/script.h>
16#include <sync.h>
18#include <test/fuzz/fuzz.h>
19#include <test/fuzz/util.h>
20#include <test/util/mining.h>
21#include <test/util/script.h>
23#include <test/util/time.h>
24#include <txmempool.h>
25#include <uint256.h>
26#include <validation.h>
27#include <validationinterface.h>
28
29#include <algorithm>
30#include <cstdint>
31#include <memory>
32#include <utility>
33#include <vector>
34
35
36namespace {
37
39
41static std::vector<std::shared_ptr<CBlock>> g_blocks;
43static std::vector<CTxIn> g_spend_candidate_txins;
45static const CScript P2SH_OP_TRUE = CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScript() << OP_TRUE)) << OP_EQUAL;
47static const CScript P2SH_OP_TRUE_UNLOCK = CScript() << MakeUCharSpan(CScript() << OP_TRUE);
49static CScript TAPROOT_OP_TRUE;
50static std::vector<std::vector<uint8_t>> TAPROOT_OP_TRUE_WITNESS;
51
55static void InitTaprootScript()
56{
58 uint256 internal_key{std::vector<uint8_t>(32, 1)};
59 auto res = XOnlyPubKey(internal_key).CreateTapTweak(&merkle_tree_hash);
60 Assert(res.has_value());
61 auto control = ToByteVector(internal_key);
62 control.insert(control.begin(), TAPROOT_LEAF_TAPSCRIPT | (res->second ? 1 : 0));
63
64 TAPROOT_OP_TRUE = CScript() << OP_1 << ToByteVector(res->first);
65 TAPROOT_OP_TRUE_WITNESS.clear();
66 TAPROOT_OP_TRUE_WITNESS.emplace_back(ToByteVector(CScript() << OP_TRUE));
67 TAPROOT_OP_TRUE_WITNESS.emplace_back(std::move(control));
68}
69
74static CTxIn GetSpendingScript(const CTransaction& tx, uint32_t vout_index)
75{
76 Assert(vout_index < tx.vout.size());
77 const CTxOut& output = tx.vout[vout_index];
78
79 CTxIn res{COutPoint(tx.GetHash(), vout_index)};
80 if (output.scriptPubKey == P2WSH_OP_TRUE) {
81 res.scriptSig = CScript();
82 res.scriptWitness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);
83 } else if (output.scriptPubKey == P2SH_OP_TRUE) {
84 res.scriptSig = P2SH_OP_TRUE_UNLOCK;
85 } else if (output.scriptPubKey == CScript()) {
86 res.scriptSig = CScript() << OP_TRUE;
87 } else if (output.scriptPubKey == TAPROOT_OP_TRUE) {
88 res.scriptSig = CScript();
89 res.scriptWitness.stack = TAPROOT_OP_TRUE_WITNESS;
90 }
91
92 return res;
93}
94
98static void MaybeAddSpendCandidate(std::vector<CTxIn>& pool, const CTransaction& tx, uint32_t vout_index)
99{
100 Assert(vout_index < tx.vout.size());
101 if (tx.vout[vout_index].scriptPubKey.IsUnspendable()) return;
102 pool.push_back(GetSpendingScript(tx, vout_index));
103}
104
105
109static void LoadCurrentBlock(Chainstate& chainstate, CBlockIndex* current_block)
110{
111 // Read the block from the BlockManager.
112 Assert(current_block->nHeight >= 0);
113 // Resize g_blocks if needed.
114 if (g_blocks.size() <= (size_t)current_block->nHeight) {
115 g_blocks.resize(current_block->nHeight + 1);
116 }
117
118 g_blocks[current_block->nHeight] = std::make_shared<CBlock>();
119 Assert(chainstate.m_blockman.ReadBlock(*g_blocks[current_block->nHeight], *current_block));
120
121 // Iterate all transaction outputs.
122 for (const auto& tx : g_blocks[current_block->nHeight]->vtx) {
123 for (uint32_t vout_index{0}; vout_index < tx->vout.size(); ++vout_index) {
124 MaybeAddSpendCandidate(g_spend_candidate_txins, *tx, vout_index);
125 }
126 }
127}
128
133static void LoadCurrentChain()
134{
135 // Clear existing data.
136 g_blocks.clear();
137 g_spend_candidate_txins.clear();
138
139 {
141 // Retrieve the current chainstate.
142 auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();
143 // Make sure it contains a valid mempool.
144 Assert(chainstate.GetMempool());
145
146 // Traverse the chain from tip to genesis.
147 auto current_block = chainstate.m_chain.Tip();
148
149 while (current_block != nullptr) {
150 LoadCurrentBlock(chainstate, current_block);
151 // Move to previous block.
152 current_block = current_block->pprev;
153 }
154 }
155
156 // Reverse the order of g_spend_candidate_txins to have them in ascending order of
157 // block height.
158 std::reverse(g_spend_candidate_txins.begin(), g_spend_candidate_txins.end());
159}
160
161
167void ResetChainman(TestingSetup& setup)
168{
169 SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time());
170 setup.m_node.chainman.reset();
171 setup.m_node.notifications->m_shutdown_on_fatal_error = false;
172 setup.m_make_chainman();
173 setup.LoadVerifyActivateChainstate();
174
175 for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
178 MineBlock(setup.m_node, options);
179 }
180 setup.m_node.validation_signals->SyncWithValidationInterfaceQueue();
181}
182
187void AddExtraTxsToMempool(TestingSetup& setup)
188{
189 Assert(setup.m_node.chainman->ActiveChainstate().GetMempool()->size() == 0);
190 for (size_t i = 1; i <= 10; i++) {
193 ctx.vin.resize(1);
194 // CTxIn is spendable as g_spend_candidate_txins comes from early blocks whose
195 // coinbases are mature.
196 ctx.vin[0] = g_spend_candidate_txins[i];
197 ctx.vout.resize(4);
198 // Arbitrarily create various outputs of different kinds in the same tx.
199 // P2WSH
200 ctx.vout[0].nValue = CAmount(15 * COIN);
201 ctx.vout[0].scriptPubKey = P2WSH_OP_TRUE;
202 // P2SH
203 ctx.vout[1].nValue = CAmount(15 * COIN);
204 ctx.vout[1].scriptPubKey = P2SH_OP_TRUE;
205 // Taproot
206 ctx.vout[2].nValue = CAmount(10 * COIN);
207 ctx.vout[2].scriptPubKey = TAPROOT_OP_TRUE;
208 // Empty script
209 ctx.vout[3].nValue = CAmount(10 * COIN);
210 ctx.vout[3].scriptPubKey = CScript();
211
213 // Add transaction to the mempool.
214 const MempoolAcceptResult ctx_result = setup.m_node.chainman->ProcessTransaction(MakeTransactionRef(ctx));
216
217 Assert(setup.m_node.chainman->ActiveChainstate().GetMempool()->size() == i);
218 // Force the mempool to select this transaction even though its fee is zero.
219 setup.m_node.chainman->ActiveChainstate().GetMempool()->PrioritiseTransaction(ctx.GetHash(), COIN);
220 }
221}
222
224static void initialize_connect_block()
225{
226 // Instantiate REGTEST chain.
227 static auto testing_setup = MakeNoLogFileContext<TestingSetup>(
228 /*chain_type=*/ChainType::REGTEST, TestOpts{
229 .extra_args = {
230 "-minrelaytxfee=0",
231 "-acceptnonstdtxn",
232 },
233 });
234 g_setup = testing_setup.get();
235
236 // Reset the chainman in the testing setup object.
237 ResetChainman(*g_setup);
238
239 // Initialize Taproot script declared as static variables.
240 InitTaprootScript();
241
242 // Load the chain mined in ResetChainman in global variables g_blocks and
243 // g_spend_candidate_txins, to make them available to pick by the target.
244 LoadCurrentChain();
245
246 // Prepare multiple transactions for block 201. They spend coins
247 // from various coinbases that are now mature enough.
248 AddExtraTxsToMempool(*g_setup);
249 // Mine block 201, which contains the transactions added to the mempool.
252 MineBlock(g_setup->m_node, options);
253 Assert(g_setup->m_node.chainman->ActiveChainstate().GetMempool()->size() == 0);
254
255 // Load the 201st block into g_blocks.
257 auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();
258 auto current_block = chainstate.m_chain.Tip();
259 LoadCurrentBlock(chainstate, current_block);
260}
261
269 std::vector<CTxIn>& additional_txins,
270 bool coinbase = false,
271 int target_height = 0)
272{
278 0 :
280
281 // Some harnesses want to explicitly read coinbase transactions from input.
282 if (coinbase) {
283 // vin size is hardcoded.
284 tx.vin.resize(1);
285 tx.vin[0].prevout.SetNull();
287 // 1/2 probability of a valid vin.
288 tx.vin[0].scriptSig = CScript() << target_height;
289 } else {
290 // Read arbitrary data from input as scriptSig.
291 auto script_sig = ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100);
292 tx.vin[0].scriptSig.assign(script_sig.begin(), script_sig.end());
293 }
294 } else {
295 // Read a normal transaction, with up to 10 inputs.
296 int num_inputs = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10);
297 tx.vin.resize(num_inputs);
298 for (int i = 0; i < num_inputs; i++) {
299 // Read an integer to choose a CTxIn or reuse one generated by the
300 // input. The content of the CTxIn is not read from the input per se.
301 uint32_t input_index = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, g_spend_candidate_txins.size() + additional_txins.size() - 1);
302 if (input_index < g_spend_candidate_txins.size()) {
303 // Pick it from the spend candidates.
304 tx.vin[i] = g_spend_candidate_txins[input_index];
305 } else {
306 // Pick it in the additional_txins set.
307 Assert((input_index - g_spend_candidate_txins.size()) < additional_txins.size());
308 tx.vin[i] = additional_txins[input_index - g_spend_candidate_txins.size()];
309 }
310
311 // Enable the fuzzer to mutate every CTxIn field after it is taken
312 // from the spend candidates.
314 tx.vin[i].nSequence = ConsumeSequence(fuzzed_data_provider);
315 }
317 tx.vin[i].prevout.n = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
318 }
321 }
323 tx.vin[i].scriptSig = ConsumeScript(fuzzed_data_provider);
324 }
326 tx.vin[i].scriptWitness.stack.clear();
327 int num_wit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 10);
328 for (int j = 0; j < num_wit; j++) {
329 tx.vin[i].scriptWitness.stack.push_back(ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100));
330 }
331 }
332 }
333 }
334
335 // Read outputs.
336 int num_outputs = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 10);
337 tx.vout.resize(num_outputs);
338 for (int i = 0; i < num_outputs; i++) {
339 // Read CAmount to spend.
340 tx.vout[i].nValue = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-10, 50 * COIN + 10);
341
342 // Read scriptPubKey type into one of the valid types.
343 CallOneOf(
345 [&] {
346 // P2WSH
347 tx.vout[i].scriptPubKey = P2WSH_OP_TRUE;
348 },
349 [&] {
350 // P2SH
351 tx.vout[i].scriptPubKey = P2SH_OP_TRUE;
352 },
353 [&] {
354 // Taproot
355 tx.vout[i].scriptPubKey = TAPROOT_OP_TRUE;
356 },
357 [&] {
358 // Empty script
359 tx.vout[i].scriptPubKey = CScript();
360 },
361 [&] {
362 // Read arbitrary scriptPubKey.
363 tx.vout[i].scriptPubKey = ConsumeScript(fuzzed_data_provider);
364 });
365 }
366
367 // Create the shared pointer to the CTransaction object.
368 auto res = MakeTransactionRef(tx);
369
370 if (!coinbase) {
371 // Create spending scripts for CTxOuts so they can be spent in later
372 // transactions. Do it here as the transaction hash is definitive.
373 for (int i = 0; i < num_outputs; i++) {
374 MaybeAddSpendCandidate(additional_txins, *res, i);
375 }
376 }
377
378 return res;
379}
380
385CBlock ConsumeBlock(FuzzedDataProvider& fuzzed_data_provider, const CBlock& prev_block, int target_height,
386 std::vector<CTxIn>& additional_txins)
387{
388 CBlock block;
389
390 // Initialize header fields.
391 block.nVersion = g_blocks.back()->nVersion;
392 block.hashPrevBlock = prev_block.GetHash();
393 block.nTime = g_blocks.back()->nTime + 2;
394 block.nBits = g_blocks.back()->nBits;
395
396 // Give the fuzzer input the ability to mutate block header fields.
399 }
402 }
403
405 block.nTime = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
406 }
408 block.nBits = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
409 }
410
411 // Read the coinbase transaction from the input.
412 block.vtx.push_back(ConsumeTransaction(fuzzed_data_provider, additional_txins, true, target_height));
413
414 // Read up to num_tx transactions from the input.
415 int num_tx = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 5);
416 for (int i = 0; i < num_tx; i++) {
417 block.vtx.push_back(ConsumeTransaction(fuzzed_data_provider, additional_txins));
418 }
419
420 // Commit witness.
422 g_setup->m_node.chainman->GenerateCoinbaseCommitment(block, nullptr);
423 }
424
425 // Set hashMerkleRoot to expected value.
426 block.hashMerkleRoot = BlockMerkleRoot(block);
427 // Let the fuzzer mutate hashMerkleRoot.
430 }
431
432 // Read the nonce from the input.
433 block.nNonce = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
434
435 return block;
436}
437
438
439FUZZ_TARGET(connect_block, .init = initialize_connect_block)
440{
442 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
443 FakeNodeClock clock{g_blocks.back()->Time() + 2s};
444
446 g_setup->m_node.chainman->m_validation_cache.m_script_execution_cache.TestOnlyReset();
447 Chainstate& active_chainstate = g_setup->m_node.chainman->ActiveChainstate();
448 CBlockIndex* active_tip = active_chainstate.m_chain.Tip();
449 Assert(active_tip->GetBlockHash() == g_blocks.back()->GetHash());
450 CCoinsViewCache active_coins(&active_chainstate.CoinsTip());
451
452 // Read a new block from the data provider.
453 std::vector<CTxIn> additional_txins;
454 CBlock block = ConsumeBlock(fuzzed_data_provider, *g_blocks.back(), active_tip->nHeight + 1, additional_txins);
455
456 // Duplicate a transaction (not the coinbase) from the previous block
457 // to hit the BIP30 check.
459 const auto& duplicates = g_blocks.back()->vtx;
460 block.vtx.push_back(duplicates[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, duplicates.size() - 1)]);
461 }
462
463 // Compute new CBlockIndex object.
464 uint256 current_hash = block.GetHash();
465 CBlockIndex new_index(block);
466 new_index.pprev = active_tip;
467 new_index.nHeight = active_tip->nHeight + 1;
468 new_index.phashBlock = &current_hash;
469
470 // Try to connect the block.
472 bool connected = active_chainstate.ConnectBlock(block,
473 state,
474 &new_index,
475 active_coins,
476 /*fJustCheck=*/true);
477 Assert(connected == state.IsValid());
478}
479
480} // namespace
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition: amount.h:15
const TestingSetup * g_setup
#define Assert(val)
Identity function.
Definition: check.h:116
uint32_t nNonce
Definition: block.h:35
uint32_t nBits
Definition: block.h:34
uint32_t nTime
Definition: block.h:33
int32_t nVersion
Definition: block.h:30
uint256 hashPrevBlock
Definition: block.h:31
uint256 hashMerkleRoot
Definition: block.h:32
uint256 GetHash() const
Definition: block.cpp:14
Definition: block.h:74
std::vector< CTransactionRef > vtx
Definition: block.h:77
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:94
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:100
uint256 GetBlockHash() const
Definition: chain.h:198
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:106
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:396
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:437
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:406
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:281
static constexpr uint32_t CURRENT_VERSION
Definition: transaction.h:284
const std::vector< CTxOut > vout
Definition: transaction.h:292
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:328
An input of a transaction.
Definition: transaction.h:62
An output of a transaction.
Definition: transaction.h:140
CScript scriptPubKey
Definition: transaction.h:143
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:550
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:624
CTxMemPool * GetMempool()
Definition: validation.h:700
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:685
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr) LOCKS_EXCLUDED(DisconnectResult DisconnectBlock(const CBlock &block, const CBlockIndex *pindex, CCoinsViewCache &view) EXCLUSIVE_LOCKS_REQUIRED(boo ConnectBlock)(const CBlock &block, BlockValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool fJustCheck=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Find the best known block, and make it the tip of the block chain.
Definition: validation.h:780
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:577
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
Definition: time.h:54
T ConsumeIntegralInRange(T min, T max)
bool IsValid() const
Definition: validation.h:113
std::optional< std::pair< XOnlyPubKey, bool > > CreateTapTweak(const uint256 *merkle_root) const
Construct a Taproot tweaked output point with this point as internal key.
Definition: pubkey.cpp:265
bool ReadBlock(CBlock &block, const FlatFilePos &pos, const std::optional< uint256 > &expected_hash) const
Functions for disk access for blocks.
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:196
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
Definition: merkle.cpp:77
constexpr int COINBASE_MATURITY
Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
Definition: consensus.h:19
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
#define FUZZ_TARGET(...)
Definition: fuzz.h:35
uint256 ComputeTapleafHash(uint8_t leaf_version, std::span< const unsigned char > script)
Compute the BIP341 tapleaf hash from leaf version & script.
constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT
Definition: interpreter.h:243
is used externally by mining IPC clients, so it should only declare simple data definitions.
Definition: basic.cpp:11
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
@ OP_EQUAL
Definition: script.h:147
@ OP_HASH160
Definition: script.h:188
@ OP_1
Definition: script.h:84
@ OP_TRUE
Definition: script.h:85
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:68
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
Definition: span.h:111
node::NodeContext m_node
Definition: setup_common.h:60
A mutable version of CTransaction.
Definition: transaction.h:358
std::vector< CTxOut > vout
Definition: transaction.h:360
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxIn > vin
Definition: transaction.h:359
Validation result for a transaction evaluated by MemPoolAccept (single or package).
Definition: validation.h:134
const ResultType m_result_type
Result type.
Definition: validation.h:143
std::vector< const char * > extra_args
Definition: setup_common.h:47
Testing setup that configures a complete environment.
Definition: setup_common.h:115
Block template creation options.
Definition: mining_types.h:33
CScript coinbase_output_script
Script to put in the coinbase transaction.
Definition: mining_types.h:86
std::unique_ptr< ChainstateManager > chainman
Definition: context.h:76
#define LOCK(cs)
Definition: sync.h:268
SeedRandomStateForTest(SeedRand::ZEROS)
uint32_t ConsumeSequence(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.cpp:155
CScript ConsumeScript(FuzzedDataProvider &fuzzed_data_provider, const bool maybe_p2wsh) noexcept
Definition: util.cpp:93
CMutableTransaction ConsumeTransaction(FuzzedDataProvider &fuzzed_data_provider, const std::optional< std::vector< Txid > > &prevout_txids, const int max_num_in, const int max_num_out) noexcept
Definition: util.cpp:42
uint256 ConsumeUInt256(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.h:195
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition: util.h:37
COutPoint MineBlock(const NodeContext &node, const node::BlockCreateOptions &assembler_options)
Returns the generated coin.
Definition: mining.cpp:119
@ ZEROS
Seed with a compile time constant of zeros.
const std::vector< uint8_t > WITNESS_STACK_ELEM_OP_TRUE
Definition: script.h:12
const CScript P2WSH_OP_TRUE
Definition: script.h:13
static int setup(void)
Definition: tests.c:8154
void SetMockTime(std::chrono::time_point< NodeClock, std::chrono::seconds > mock)
Definition: time.cpp:52
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:45