Bitcoin Core 32.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>
11#include <node/mining_types.h>
12#include <primitives/block.h>
14#include <pubkey.h>
15#include <script/interpreter.h>
16#include <script/script.h>
17#include <sync.h>
19#include <test/fuzz/fuzz.h>
20#include <test/fuzz/util.h>
21#include <test/util/mining.h>
22#include <test/util/script.h>
24#include <test/util/time.h>
25#include <txmempool.h>
26#include <uint256.h>
27#include <validation.h>
28#include <validationinterface.h>
29
30#include <algorithm>
31#include <cstdint>
32#include <memory>
33#include <utility>
34#include <vector>
35
36
37namespace {
38
40
42static std::vector<std::shared_ptr<CBlock>> g_blocks;
44static std::vector<CTxIn> g_spend_candidate_txins;
46static const CScript P2SH_OP_TRUE = CScript() << OP_HASH160 << ToByteVector(ScriptHash(CScript() << OP_TRUE)) << OP_EQUAL;
48static const CScript P2SH_OP_TRUE_UNLOCK = CScript() << MakeUCharSpan(CScript() << OP_TRUE);
50static CScript TAPROOT_OP_TRUE;
51static std::vector<std::vector<uint8_t>> TAPROOT_OP_TRUE_WITNESS;
52
56static void InitTaprootScript()
57{
59 uint256 internal_key{std::vector<uint8_t>(32, 1)};
60 auto res = XOnlyPubKey(internal_key).CreateTapTweak(&merkle_tree_hash);
61 Assert(res.has_value());
62 auto control = ToByteVector(internal_key);
63 control.insert(control.begin(), TAPROOT_LEAF_TAPSCRIPT | (res->second ? 1 : 0));
64
65 TAPROOT_OP_TRUE = CScript() << OP_1 << ToByteVector(res->first);
66 TAPROOT_OP_TRUE_WITNESS.clear();
67 TAPROOT_OP_TRUE_WITNESS.emplace_back(ToByteVector(CScript() << OP_TRUE));
68 TAPROOT_OP_TRUE_WITNESS.emplace_back(std::move(control));
69}
70
75static CTxIn GetSpendingScript(const CTransaction& tx, uint32_t vout_index)
76{
77 Assert(vout_index < tx.vout.size());
78 const CTxOut& output = tx.vout[vout_index];
79
80 CTxIn res{COutPoint(tx.GetHash(), vout_index)};
81 if (output.scriptPubKey == P2WSH_OP_TRUE) {
82 res.scriptSig = CScript();
83 res.scriptWitness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);
84 } else if (output.scriptPubKey == P2SH_OP_TRUE) {
85 res.scriptSig = P2SH_OP_TRUE_UNLOCK;
86 } else if (output.scriptPubKey == CScript()) {
87 res.scriptSig = CScript() << OP_TRUE;
88 } else if (output.scriptPubKey == TAPROOT_OP_TRUE) {
89 res.scriptSig = CScript();
90 res.scriptWitness.stack = TAPROOT_OP_TRUE_WITNESS;
91 }
92
93 return res;
94}
95
99static void MaybeAddSpendCandidate(std::vector<CTxIn>& pool, const CTransaction& tx, uint32_t vout_index)
100{
101 Assert(vout_index < tx.vout.size());
102 if (tx.vout[vout_index].scriptPubKey.IsUnspendable()) return;
103 pool.push_back(GetSpendingScript(tx, vout_index));
104}
105
106
110static void LoadCurrentBlock(Chainstate& chainstate, CBlockIndex* current_block)
111{
112 // Read the block from the BlockManager.
113 Assert(current_block->nHeight >= 0);
114 // Resize g_blocks if needed.
115 if (g_blocks.size() <= (size_t)current_block->nHeight) {
116 g_blocks.resize(current_block->nHeight + 1);
117 }
118
119 g_blocks[current_block->nHeight] = std::make_shared<CBlock>();
120 Assert(chainstate.m_blockman.ReadBlock(*g_blocks[current_block->nHeight], *current_block));
121
122 // Iterate all transaction outputs.
123 for (const auto& tx : g_blocks[current_block->nHeight]->vtx) {
124 for (uint32_t vout_index{0}; vout_index < tx->vout.size(); ++vout_index) {
125 MaybeAddSpendCandidate(g_spend_candidate_txins, *tx, vout_index);
126 }
127 }
128}
129
134static void LoadCurrentChain()
135{
136 // Clear existing data.
137 g_blocks.clear();
138 g_spend_candidate_txins.clear();
139
140 {
142 // Retrieve the current chainstate.
143 auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();
144 // Make sure it contains a valid mempool.
145 Assert(chainstate.GetMempool());
146
147 // Traverse the chain from tip to genesis.
148 auto current_block = chainstate.m_chain.Tip();
149
150 while (current_block != nullptr) {
151 LoadCurrentBlock(chainstate, current_block);
152 // Move to previous block.
153 current_block = current_block->pprev;
154 }
155 }
156
157 // Reverse the order of g_spend_candidate_txins to have them in ascending order of
158 // block height.
159 std::reverse(g_spend_candidate_txins.begin(), g_spend_candidate_txins.end());
160}
161
162
168void ResetChainman(TestingSetup& setup)
169{
170 SetMockTime(setup.m_node.chainman->GetParams().GenesisBlock().Time());
171 setup.m_node.block_template_manager.reset();
172 setup.m_node.chainman.reset();
173 setup.m_node.notifications->m_shutdown_on_fatal_error = false;
174 setup.m_make_chainman();
175 setup.CreateBlockTemplateManager();
176 setup.LoadVerifyActivateChainstate();
177
178 for (int i = 0; i < 2 * COINBASE_MATURITY; i++) {
181 MineBlock(setup.m_node, options);
182 }
183 setup.m_node.validation_signals->SyncWithValidationInterfaceQueue();
184}
185
190void AddExtraTxsToMempool(TestingSetup& setup)
191{
192 Assert(setup.m_node.chainman->ActiveChainstate().GetMempool()->size() == 0);
193 for (size_t i = 1; i <= 10; i++) {
196 ctx.vin.resize(1);
197 // CTxIn is spendable as g_spend_candidate_txins comes from early blocks whose
198 // coinbases are mature.
199 ctx.vin[0] = g_spend_candidate_txins[i];
200 ctx.vout.resize(4);
201 // Arbitrarily create various outputs of different kinds in the same tx.
202 // P2WSH
203 ctx.vout[0].nValue = CAmount(15 * COIN);
204 ctx.vout[0].scriptPubKey = P2WSH_OP_TRUE;
205 // P2SH
206 ctx.vout[1].nValue = CAmount(15 * COIN);
207 ctx.vout[1].scriptPubKey = P2SH_OP_TRUE;
208 // Taproot
209 ctx.vout[2].nValue = CAmount(10 * COIN);
210 ctx.vout[2].scriptPubKey = TAPROOT_OP_TRUE;
211 // Empty script
212 ctx.vout[3].nValue = CAmount(10 * COIN);
213 ctx.vout[3].scriptPubKey = CScript();
214
216 // Add transaction to the mempool.
217 const MempoolAcceptResult ctx_result = setup.m_node.chainman->ProcessTransaction(MakeTransactionRef(ctx));
219
220 Assert(setup.m_node.chainman->ActiveChainstate().GetMempool()->size() == i);
221 // Force the mempool to select this transaction even though its fee is zero.
222 setup.m_node.chainman->ActiveChainstate().GetMempool()->PrioritiseTransaction(ctx.GetHash(), COIN);
223 }
224}
225
227static void initialize_connect_block()
228{
229 // Instantiate REGTEST chain.
230 static auto testing_setup = MakeNoLogFileContext<TestingSetup>(
231 /*chain_type=*/ChainType::REGTEST, TestOpts{
232 .extra_args = {
233 "-minrelaytxfee=0",
234 "-acceptnonstdtxn",
235 },
236 });
237 g_setup = testing_setup.get();
238
239 // Reset the chainman in the testing setup object.
240 ResetChainman(*g_setup);
241
242 // Initialize Taproot script declared as static variables.
243 InitTaprootScript();
244
245 // Load the chain mined in ResetChainman in global variables g_blocks and
246 // g_spend_candidate_txins, to make them available to pick by the target.
247 LoadCurrentChain();
248
249 // Prepare multiple transactions for block 201. They spend coins
250 // from various coinbases that are now mature enough.
251 AddExtraTxsToMempool(*g_setup);
252 // Mine block 201, which contains the transactions added to the mempool.
255 MineBlock(g_setup->m_node, options);
256 Assert(g_setup->m_node.chainman->ActiveChainstate().GetMempool()->size() == 0);
257
258 // Load the 201st block into g_blocks.
260 auto& chainstate = Assert(g_setup->m_node.chainman)->ActiveChainstate();
261 auto current_block = chainstate.m_chain.Tip();
262 LoadCurrentBlock(chainstate, current_block);
263}
264
272 std::vector<CTxIn>& additional_txins,
273 bool coinbase = false,
274 int target_height = 0)
275{
281 0 :
283
284 // Some harnesses want to explicitly read coinbase transactions from input.
285 if (coinbase) {
286 // vin size is hardcoded.
287 tx.vin.resize(1);
288 tx.vin[0].prevout.SetNull();
290 // 1/2 probability of a valid vin.
291 tx.vin[0].scriptSig = CScript() << target_height;
292 } else {
293 // Read arbitrary data from input as scriptSig.
294 auto script_sig = ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100);
295 tx.vin[0].scriptSig.assign(script_sig.begin(), script_sig.end());
296 }
297 } else {
298 // Read a normal transaction, with up to 10 inputs.
300 auto& txin = tx.vin.emplace_back();
301 // Read an integer to choose a CTxIn or reuse one generated by the
302 // input. The content of the CTxIn is not read from the input per se.
303 uint32_t input_index = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, g_spend_candidate_txins.size() + additional_txins.size() - 1);
304 if (input_index < g_spend_candidate_txins.size()) {
305 // Pick it from the spend candidates.
306 txin = g_spend_candidate_txins[input_index];
307 } else {
308 // Pick it in the additional_txins set.
309 Assert((input_index - g_spend_candidate_txins.size()) < additional_txins.size());
310 txin = additional_txins[input_index - g_spend_candidate_txins.size()];
311 }
312
313 // Enable the fuzzer to mutate every CTxIn field after it is taken
314 // from the spend candidates.
316 txin.nSequence = ConsumeSequence(fuzzed_data_provider);
317 }
319 txin.prevout.n = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
320 }
323 }
325 txin.scriptSig = ConsumeScript(fuzzed_data_provider);
326 }
328 txin.scriptWitness.stack.clear();
330 txin.scriptWitness.stack.push_back(ConsumeRandomLengthByteVector<unsigned char>(fuzzed_data_provider, 100));
331 }
332 }
333 }
334 }
335
336 // Read between 1 and 10 outputs.
338 auto& txout = tx.vout.emplace_back();
339 // Read CAmount to spend.
340 txout.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 txout.scriptPubKey = P2WSH_OP_TRUE;
348 },
349 [&] {
350 // P2SH
351 txout.scriptPubKey = P2SH_OP_TRUE;
352 },
353 [&] {
354 // Taproot
355 txout.scriptPubKey = TAPROOT_OP_TRUE;
356 },
357 [&] {
358 // Empty script
359 txout.scriptPubKey = CScript();
360 },
361 [&] {
362 // Read arbitrary scriptPubKey.
363 txout.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 (uint32_t i{0}; i < res->vout.size(); ++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 5 transactions from the input.
416 block.vtx.push_back(ConsumeTransaction(fuzzed_data_provider, additional_txins));
417 }
418
419 // Commit witness.
421 g_setup->m_node.chainman->GenerateCoinbaseCommitment(block, nullptr);
422 }
423
424 // Set hashMerkleRoot to expected value.
425 block.hashMerkleRoot = BlockMerkleRoot(block);
426 // Let the fuzzer mutate hashMerkleRoot.
429 }
430
431 // Read the nonce from the input.
432 block.nNonce = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
433
434 return block;
435}
436
437
438FUZZ_TARGET(connect_block, .init = initialize_connect_block)
439{
441 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
442 FakeNodeClock clock{g_blocks.back()->Time() + 2s};
443
445 g_setup->m_node.chainman->m_validation_cache.m_script_execution_cache.TestOnlyReset();
446 Chainstate& active_chainstate = g_setup->m_node.chainman->ActiveChainstate();
447 CBlockIndex* active_tip = active_chainstate.m_chain.Tip();
448 Assert(active_tip->GetBlockHash() == g_blocks.back()->GetHash());
449 CCoinsViewCache active_coins(&active_chainstate.CoinsTip());
450
451 // Read a new block from the data provider.
452 std::vector<CTxIn> additional_txins;
453 CBlock block = ConsumeBlock(fuzzed_data_provider, *g_blocks.back(), active_tip->nHeight + 1, additional_txins);
454
455 // Duplicate a transaction (not the coinbase) from the previous block
456 // to hit the BIP30 check.
458 const auto& duplicates = g_blocks.back()->vtx;
459 block.vtx.push_back(duplicates[fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, duplicates.size() - 1)]);
460 }
461
462 // Compute new CBlockIndex object.
463 uint256 current_hash = block.GetHash();
464 CBlockIndex new_index(block);
465 new_index.pprev = active_tip;
466 new_index.nHeight = active_tip->nHeight + 1;
467 new_index.phashBlock = &current_hash;
468
469 // Try to connect the block.
471 bool connected = active_chainstate.ConnectBlock(block,
472 state,
473 &new_index,
474 active_coins,
475 /*fJustCheck=*/true);
476 Assert(connected == state.IsValid());
477}
478
479} // 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:30
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:287
static constexpr uint32_t CURRENT_VERSION
Definition: transaction.h:290
const std::vector< CTxOut > vout
Definition: transaction.h:298
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:334
An input of a transaction.
Definition: transaction.h:63
An output of a transaction.
Definition: transaction.h:141
CScript scriptPubKey
Definition: transaction.h:144
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:630
CTxMemPool * GetMempool()
Definition: validation.h:709
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:694
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:789
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:583
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:112
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
LIMITED_WHILE(provider.remaining_bytes(), 10000)
uint256 BlockMerkleRoot(const CBlock &block, bool *mutated)
Definition: merkle.cpp:76
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:418
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:417
@ 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:372
std::vector< CTxOut > vout
Definition: transaction.h:374
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:69
std::vector< CTxIn > vin
Definition: transaction.h:373
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:119
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:74
#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:120
@ ZEROS
Seed with a compile time constant of zeros.
static const std::vector< uint8_t > WITNESS_STACK_ELEM_OP_TRUE
Definition: script.h:12
static const CScript P2WSH_OP_TRUE
Definition: script.h:13
static int setup(void)
Definition: tests.c:8289
void SetMockTime(std::chrono::time_point< NodeClock, std::chrono::seconds > mock)
Definition: time.cpp:52
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:46
FakeNodeClock clock