Bitcoin Core 31.99.0
P2P Digital Currency
package_eval.cpp
Go to the documentation of this file.
1// Copyright (c) 2023-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 <chain.h>
6#include <consensus/amount.h>
9#include <node/mining_types.h>
10#include <policy/feerate.h>
11#include <policy/packages.h>
12#include <policy/policy.h>
13#include <policy/settings.h>
14#include <policy/truc_policy.h>
16#include <script/script.h>
17#include <sync.h>
19#include <test/fuzz/fuzz.h>
20#include <test/fuzz/util.h>
22#include <test/util/mining.h>
23#include <test/util/random.h>
24#include <test/util/script.h>
26#include <test/util/txmempool.h>
27#include <txmempool.h>
28#include <util/check.h>
29#include <util/hasher.h>
30#include <util/time.h>
31#include <util/translation.h>
32#include <validation.h>
33#include <validationinterface.h>
34
35#include <cstddef>
36#include <cstdint>
37#include <functional>
38#include <iterator>
39#include <limits>
40#include <map>
41#include <memory>
42#include <optional>
43#include <set>
44#include <span>
45#include <string>
46#include <unordered_map>
47#include <utility>
48#include <vector>
50
51namespace {
52
54std::vector<COutPoint> g_outpoints_coinbase_init_mature;
55
56struct MockedTxPool : public CTxMemPool {
57 void RollingFeeUpdate() EXCLUSIVE_LOCKS_REQUIRED(!cs)
58 {
59 LOCK(cs);
60 lastRollingFeeUpdate = GetTime();
61 blockSinceLastRollingFeeBump = true;
62 }
63};
64
65void initialize_tx_pool()
66{
67 static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
68 g_setup = testing_setup.get();
69 SetMockTime(WITH_LOCK(g_setup->m_node.chainman->GetMutex(), return g_setup->m_node.chainman->ActiveTip()->Time()));
70
71 for (int i = 0; i < 2 * COINBASE_MATURITY; ++i) {
73 .coinbase_output_script = P2WSH_EMPTY,
74 })};
75 if (i < COINBASE_MATURITY) {
76 // Remember the txids to avoid expensive disk access later on
77 g_outpoints_coinbase_init_mature.push_back(prevout);
78 }
79 }
80 g_setup->m_node.validation_signals->SyncWithValidationInterfaceQueue();
81}
82
83struct OutpointsUpdater final : public CValidationInterface {
84 std::set<COutPoint>& m_mempool_outpoints;
85
86 explicit OutpointsUpdater(std::set<COutPoint>& r)
87 : m_mempool_outpoints{r} {}
88
89 void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t /* mempool_sequence */) override
90 {
91 // for coins spent we always want to be able to rbf so they're not removed
92
93 // outputs from this tx can now be spent
94 for (uint32_t index{0}; index < tx.info.m_tx->vout.size(); ++index) {
95 m_mempool_outpoints.insert(COutPoint{tx.info.m_tx->GetHash(), index});
96 }
97 }
98
99 void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t /* mempool_sequence */) override
100 {
101 // outpoints spent by this tx are now available
102 for (const auto& input : tx->vin) {
103 // Could already exist if this was a replacement
104 m_mempool_outpoints.insert(input.prevout);
105 }
106 // outpoints created by this tx no longer exist
107 for (uint32_t index{0}; index < tx->vout.size(); ++index) {
108 m_mempool_outpoints.erase(COutPoint{tx->GetHash(), index});
109 }
110 }
111};
112
113struct TransactionsDelta final : public CValidationInterface {
114 std::set<CTransactionRef>& m_added;
115
116 explicit TransactionsDelta(std::set<CTransactionRef>& a)
117 : m_added{a} {}
118
119 void TransactionAddedToMempool(const NewMempoolTransactionInfo& tx, uint64_t /* mempool_sequence */) override
120 {
121 // Transactions may be entered and booted any number of times
122 m_added.insert(tx.info.m_tx);
123 }
124
125 void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t /* mempool_sequence */) override
126 {
127 // Transactions may be entered and booted any number of times
128 m_added.erase(tx);
129 }
130};
131
132void MockTime(FuzzedDataProvider& fuzzed_data_provider, const Chainstate& chainstate)
133{
134 const auto time = ConsumeTime(fuzzed_data_provider,
135 chainstate.m_chain.Tip()->GetMedianTimePast() + 1,
136 std::numeric_limits<decltype(chainstate.m_chain.Tip()->nTime)>::max());
137 SetMockTime(time);
138}
139
140std::unique_ptr<CTxMemPool> MakeMempool(FuzzedDataProvider& fuzzed_data_provider, const NodeContext& node)
141{
142 // Take the default options for tests...
144
145
146 // ...override specific options for this specific fuzz suite
148 mempool_opts.limits.descendant_count = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 50);
149 mempool_opts.max_size_bytes = fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 200) * 1'000'000;
150 mempool_opts.expiry = std::chrono::hours{fuzzed_data_provider.ConsumeIntegralInRange<unsigned>(0, 999)};
151 // Only interested in 2 cases: sigop cost 0 or when single legacy sigop cost is >> 1KvB
153
154 mempool_opts.check_ratio = 1;
155 mempool_opts.require_standard = fuzzed_data_provider.ConsumeBool();
156
157 bilingual_str error;
158 // ...and construct a CTxMemPool from it
159 auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)};
160 // ... ignore the error since it might be beneficial to fuzz even when the
161 // mempool size is unreasonably small
162 Assert(error.empty() || error.original.starts_with("-maxmempool must be at least "));
163 return mempool;
164}
165
166std::unique_ptr<CTxMemPool> MakeEphemeralMempool(const NodeContext& node)
167{
168 // Take the default options for tests...
170
171 mempool_opts.check_ratio = 1;
172
173 // Require standardness rules otherwise ephemeral dust is no-op
174 mempool_opts.require_standard = true;
175
176 // And set minrelay to 0 to allow ephemeral parent tx even with non-TRUC
177 mempool_opts.min_relay_feerate = CFeeRate(0);
178
179 bilingual_str error;
180 // ...and construct a CTxMemPool from it
181 auto mempool{std::make_unique<CTxMemPool>(std::move(mempool_opts), error)};
182 Assert(error.empty());
183 return mempool;
184}
185
186// Scan mempool for a tx that has spent dust and return a
187// prevout of the child that isn't the dusty parent itself.
188// This is used to double-spend the child out of the mempool,
189// leaving the parent childless.
190// This assumes CheckMempoolEphemeralInvariants has passed for tx_pool.
191std::optional<COutPoint> GetChildEvictingPrevout(const CTxMemPool& tx_pool)
192{
193 LOCK(tx_pool.cs);
194 for (const auto& tx_info : tx_pool.infoAll()) {
195 const auto& entry = *Assert(tx_pool.GetEntry(tx_info.tx->GetHash()));
196 std::vector<uint32_t> dust_indexes{GetDust(*tx_info.tx, tx_pool.m_opts.dust_relay_feerate)};
197 if (!dust_indexes.empty()) {
198 const auto& children = tx_pool.GetChildren(entry);
199 if (!children.empty()) {
200 Assert(children.size() == 1);
201 // Find an input that doesn't spend from parent's txid
202 const auto& only_child = children.begin()->get().GetTx();
203 for (const auto& tx_input : only_child.vin) {
204 if (tx_input.prevout.hash != tx_info.tx->GetHash()) {
205 return tx_input.prevout;
206 }
207 }
208 }
209 }
210 }
211
212 return std::nullopt;
213}
214
215FUZZ_TARGET(ephemeral_package_eval, .init = initialize_tx_pool)
216{
218 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
219 const auto& node = g_setup->m_node;
220 auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
221
222 MockTime(fuzzed_data_provider, chainstate);
223
224 // All RBF-spendable outpoints outside of the unsubmitted package
225 std::set<COutPoint> mempool_outpoints;
226 std::unordered_map<COutPoint, CAmount, SaltedOutpointHasher> outpoints_value;
227 for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
228 Assert(mempool_outpoints.insert(outpoint).second);
229 outpoints_value[outpoint] = 50 * COIN;
230 }
231
232 auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints);
233 node.validation_signals->RegisterSharedValidationInterface(outpoints_updater);
234
235 auto tx_pool_{MakeEphemeralMempool(node)};
236 MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
237
238 chainstate.SetMempool(&tx_pool);
239
241 Assert(!mempool_outpoints.empty());
242
243 std::vector<CTransactionRef> txs;
244
245 // Find something we may want to double-spend with two input single tx
246 std::optional<COutPoint> outpoint_to_rbf{fuzzed_data_provider.ConsumeBool() ? GetChildEvictingPrevout(tx_pool) : std::nullopt};
247
248 // Make small packages
249 const auto num_txs = outpoint_to_rbf ? 1 : fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4);
250
251 std::set<COutPoint> package_outpoints;
252 while (txs.size() < num_txs) {
253 // Create transaction to add to the mempool
254 txs.emplace_back([&] {
255 CMutableTransaction tx_mut;
257 tx_mut.nLockTime = 0;
258 // Last transaction in a package needs to be a child of parents to get further in validation
259 // so the last transaction to be generated(in a >1 package) must spend all package-made outputs
260 // Note that this test currently only spends package outputs in last transaction.
261 bool last_tx = num_txs > 1 && txs.size() == num_txs - 1;
262 const auto num_in = outpoint_to_rbf ? 2 :
263 last_tx ? fuzzed_data_provider.ConsumeIntegralInRange<int>(package_outpoints.size()/2 + 1, package_outpoints.size()) :
265 const auto num_out = outpoint_to_rbf ? 1 : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);
266
267 auto& outpoints = last_tx ? package_outpoints : mempool_outpoints;
268
269 Assert((int)outpoints.size() >= num_in && num_in > 0);
270
271 CAmount amount_in{0};
272 for (int i = 0; i < num_in; ++i) {
273 // Pop random outpoint. We erase them to avoid double-spending
274 // while in this loop, but later add them back (unless last_tx).
275 auto pop = outpoints.begin();
276 std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints.size() - 1));
277 auto outpoint = *pop;
278
279 if (i == 0 && outpoint_to_rbf) {
280 outpoint = *outpoint_to_rbf;
281 outpoints.erase(outpoint);
282 } else {
283 outpoints.erase(pop);
284 }
285 // no need to update or erase from outpoints_value
286 amount_in += outpoints_value.at(outpoint);
287
288 // Create input
289 CTxIn in;
290 in.prevout = outpoint;
292
293 tx_mut.vin.push_back(in);
294 }
295
296 const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, amount_in);
297 const auto amount_out = (amount_in - amount_fee) / num_out;
298 for (int i = 0; i < num_out; ++i) {
299 tx_mut.vout.emplace_back(amount_out, P2WSH_EMPTY);
300 }
301
302 // Note output amounts can naturally drop to dust on their own.
303 if (!outpoint_to_rbf && fuzzed_data_provider.ConsumeBool()) {
304 uint32_t dust_index = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, num_out);
305 tx_mut.vout.insert(tx_mut.vout.begin() + dust_index, CTxOut(0, P2WSH_EMPTY));
306 }
307
308 auto tx = MakeTransactionRef(tx_mut);
309 // Restore previously removed outpoints, except in-package outpoints (to allow RBF)
310 if (!last_tx) {
311 for (const auto& in : tx->vin) {
312 Assert(outpoints.insert(in.prevout).second);
313 }
314 // Cache the in-package outpoints being made
315 for (size_t i = 0; i < tx->vout.size(); ++i) {
316 package_outpoints.emplace(tx->GetHash(), i);
317 }
318 }
319 // We need newly-created values for the duration of this run
320 for (size_t i = 0; i < tx->vout.size(); ++i) {
321 outpoints_value[COutPoint(tx->GetHash(), i)] = tx->vout[i].nValue;
322 }
323 return tx;
324 }());
325 }
326
328 const auto& txid = fuzzed_data_provider.ConsumeBool() ?
329 txs.back()->GetHash() :
330 PickValue(fuzzed_data_provider, mempool_outpoints).hash;
331 const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
332 // We only prioritise out of mempool transactions since PrioritiseTransaction doesn't
333 // filter for ephemeral dust
334 if (tx_pool.exists(txid)) {
335 const auto tx_info{tx_pool.info(txid)};
336 if (GetDust(*tx_info.tx, tx_pool.m_opts.dust_relay_feerate).empty()) {
337 tx_pool.PrioritiseTransaction(txid, delta);
338 }
339 }
340 }
341
342 auto single_submit = txs.size() == 1;
343
344 const auto result_package = WITH_LOCK(::cs_main,
345 return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, /*client_maxfeerate=*/{}));
346
347 const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(),
348 /*bypass_limits=*/false, /*test_accept=*/!single_submit));
349
350 if (!single_submit && result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
351 // We don't know anything about the validity since transactions were randomly generated, so
352 // just use result_package.m_state here. This makes the expect_valid check meaningless, but
353 // we can still verify that the contents of m_tx_results are consistent with m_state.
354 const bool expect_valid{result_package.m_state.IsValid()};
355 Assert(!CheckPackageMempoolAcceptResult(txs, result_package, expect_valid, &tx_pool));
356 }
357
358 node.validation_signals->SyncWithValidationInterfaceQueue();
359
361 }
362
363 node.validation_signals->UnregisterSharedValidationInterface(outpoints_updater);
364
365 WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1));
366}
367
368
369FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
370{
372 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
373 const auto& node = g_setup->m_node;
374 auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
375
376 MockTime(fuzzed_data_provider, chainstate);
377
378 // All RBF-spendable outpoints outside of the unsubmitted package
379 std::set<COutPoint> mempool_outpoints;
380 std::unordered_map<COutPoint, CAmount, SaltedOutpointHasher> outpoints_value;
381 for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
382 Assert(mempool_outpoints.insert(outpoint).second);
383 outpoints_value[outpoint] = 50 * COIN;
384 }
385
386 auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints);
387 node.validation_signals->RegisterSharedValidationInterface(outpoints_updater);
388
389 auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
390 MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
391
392 chainstate.SetMempool(&tx_pool);
393
395 Assert(!mempool_outpoints.empty());
396
397 std::vector<CTransactionRef> txs;
398
399 // Make packages of 1-to-26 transactions
400 const auto num_txs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 26);
401 std::set<COutPoint> package_outpoints;
402 while (txs.size() < num_txs) {
403 // Create transaction to add to the mempool
404 txs.emplace_back([&] {
405 CMutableTransaction tx_mut;
408 // Last transaction in a package needs to be a child of parents to get further in validation
409 // so the last transaction to be generated(in a >1 package) must spend all package-made outputs
410 // Note that this test currently only spends package outputs in last transaction.
411 bool last_tx = num_txs > 1 && txs.size() == num_txs - 1;
412 const auto num_in = last_tx ? package_outpoints.size() : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, mempool_outpoints.size());
413 auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, mempool_outpoints.size() * 2);
414
415 auto& outpoints = last_tx ? package_outpoints : mempool_outpoints;
416
417 Assert(!outpoints.empty());
418
419 CAmount amount_in{0};
420 for (size_t i = 0; i < num_in; ++i) {
421 // Pop random outpoint. We erase them to avoid double-spending
422 // while in this loop, but later add them back (unless last_tx).
423 auto pop = outpoints.begin();
424 std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints.size() - 1));
425 const auto outpoint = *pop;
426 outpoints.erase(pop);
427 // no need to update or erase from outpoints_value
428 amount_in += outpoints_value.at(outpoint);
429
430 // Create input
432 const auto script_sig = CScript{};
434
435 CTxIn in;
436 in.prevout = outpoint;
437 in.nSequence = sequence;
438 in.scriptSig = script_sig;
439 in.scriptWitness.stack = script_wit_stack;
440
441 tx_mut.vin.push_back(in);
442 }
443
444 // Duplicate an input
445 bool dup_input = fuzzed_data_provider.ConsumeBool();
446 if (dup_input) {
447 tx_mut.vin.push_back(tx_mut.vin.back());
448 }
449
450 // Refer to a non-existent input
452 tx_mut.vin.emplace_back();
453 }
454
455 // Make a p2pk output to make sigops adjusted vsize to violate TRUC rules, potentially, which is never spent
456 if (last_tx && amount_in > 1000 && fuzzed_data_provider.ConsumeBool()) {
457 tx_mut.vout.emplace_back(1000, CScript() << std::vector<unsigned char>(33, 0x02) << OP_CHECKSIG);
458 // Don't add any other outputs.
459 num_out = 1;
460 amount_in -= 1000;
461 }
462
463 const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, amount_in);
464 const auto amount_out = (amount_in - amount_fee) / num_out;
465 for (int i = 0; i < num_out; ++i) {
466 tx_mut.vout.emplace_back(amount_out, P2WSH_EMPTY);
467 }
468 auto tx = MakeTransactionRef(tx_mut);
469 // Restore previously removed outpoints, except in-package outpoints
470 if (!last_tx) {
471 for (const auto& in : tx->vin) {
472 // It's a fake input, or a new input, or a duplicate
473 Assert(in == CTxIn() || outpoints.insert(in.prevout).second || dup_input);
474 }
475 // Cache the in-package outpoints being made
476 for (size_t i = 0; i < tx->vout.size(); ++i) {
477 package_outpoints.emplace(tx->GetHash(), i);
478 }
479 }
480 // We need newly-created values for the duration of this run
481 for (size_t i = 0; i < tx->vout.size(); ++i) {
482 outpoints_value[COutPoint(tx->GetHash(), i)] = tx->vout[i].nValue;
483 }
484 return tx;
485 }());
486 }
487
489 MockTime(fuzzed_data_provider, chainstate);
490 }
492 tx_pool.RollingFeeUpdate();
493 }
495 const auto& txid = fuzzed_data_provider.ConsumeBool() ?
496 txs.back()->GetHash() :
497 PickValue(fuzzed_data_provider, mempool_outpoints).hash;
498 const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
499 tx_pool.PrioritiseTransaction(txid, delta);
500 }
501
502 // Remember all added transactions
503 std::set<CTransactionRef> added;
504 auto txr = std::make_shared<TransactionsDelta>(added);
505 node.validation_signals->RegisterSharedValidationInterface(txr);
506
507 // When there are multiple transactions in the package, we call ProcessNewPackage(txs, test_accept=false)
508 // and AcceptToMemoryPool(txs.back(), test_accept=true). When there is only 1 transaction, we might flip it
509 // (the package is a test accept and ATMP is a submission).
510 auto single_submit = txs.size() == 1 && fuzzed_data_provider.ConsumeBool();
511
512 // Exercise client_maxfeerate logic
513 std::optional<CFeeRate> client_maxfeerate{};
515 client_maxfeerate = CFeeRate(fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-1, 50 * COIN), 100);
516 }
517
518 const auto result_package = WITH_LOCK(::cs_main,
519 return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, client_maxfeerate));
520
521 // Always set bypass_limits to false because it is not supported in ProcessNewPackage and
522 // can be a source of divergence.
523 const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(),
524 /*bypass_limits=*/false, /*test_accept=*/!single_submit));
525 const bool passed = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
526
527 node.validation_signals->SyncWithValidationInterfaceQueue();
528 node.validation_signals->UnregisterSharedValidationInterface(txr);
529
530 // There is only 1 transaction in the package. We did a test-package-accept and a ATMP
531 if (single_submit) {
532 Assert(passed != added.empty());
533 Assert(passed == res.m_state.IsValid());
534 if (passed) {
535 Assert(added.size() == 1);
536 Assert(txs.back() == *added.begin());
537 }
538 } else if (result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
539 // We don't know anything about the validity since transactions were randomly generated, so
540 // just use result_package.m_state here. This makes the expect_valid check meaningless, but
541 // we can still verify that the contents of m_tx_results are consistent with m_state.
542 const bool expect_valid{result_package.m_state.IsValid()};
543 Assert(!CheckPackageMempoolAcceptResult(txs, result_package, expect_valid, &tx_pool));
544 } else {
545 // This is empty if it fails early checks, or "full" if transactions are looked at deeper
546 Assert(result_package.m_tx_results.size() == txs.size() || result_package.m_tx_results.empty());
547 }
548
550
551 // Dust checks only make sense when dust is enforced
552 if (tx_pool.m_opts.require_standard) {
554 }
555 }
556
557 node.validation_signals->UnregisterSharedValidationInterface(outpoints_updater);
558
559 WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1));
560}
561} // namespace
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Definition: amount.h:15
static void pool cs
const TestingSetup * g_setup
#define Assert(val)
Identity function.
Definition: check.h:116
uint32_t nTime
Definition: chain.h:142
int64_t GetMedianTimePast() const
Definition: chain.h:233
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:396
Fee rate in satoshis per virtualbyte: CAmount / vB the feerate is represented internally as FeeFrac.
Definition: feerate.h:32
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
static const uint32_t CURRENT_VERSION
Definition: transaction.h:284
An input of a transaction.
Definition: transaction.h:62
uint32_t nSequence
Definition: transaction.h:66
CScript scriptSig
Definition: transaction.h:65
CScriptWitness scriptWitness
Only serialized through CTransaction.
Definition: transaction.h:67
COutPoint prevout
Definition: transaction.h:64
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:187
const Options m_opts
Definition: txmempool.h:301
std::vector< TxMempoolInfo > infoAll() const
Definition: txmempool.cpp:600
std::vector< CTxMemPoolEntry::CTxMemPoolEntryRef > GetChildren(const CTxMemPoolEntry &entry) const
Definition: txmempool.cpp:57
const CTxMemPoolEntry * GetEntry(const Txid &txid) const LIFETIMEBOUND EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.cpp:614
An output of a transaction.
Definition: transaction.h:140
Implement this to subscribe to events generated in validation and mempool.
virtual void TransactionRemovedFromMempool(const CTransactionRef &tx, MemPoolRemovalReason reason, uint64_t mempool_sequence)
Notifies listeners of a transaction leaving mempool.
virtual void TransactionAddedToMempool(const NewMempoolTransactionInfo &tx, uint64_t mempool_sequence)
Notifies listeners of a transaction having been added to mempool.
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:554
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:628
T ConsumeIntegralInRange(T min, T max)
LIMITED_WHILE(provider.remaining_bytes(), 10000)
static const 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
uint64_t sequence
MemPoolRemovalReason
Reason why a transaction was removed from the mempool, this is passed to the notification signal.
is used externally by mining IPC clients, so it should only declare simple data definitions.
Definition: basic.cpp:8
Definition: messages.h:21
@ PCKG_POLICY
The package itself is invalid (e.g. too many transactions).
unsigned int nBytesPerSigOp
Definition: settings.cpp:10
std::vector< uint32_t > GetDust(const CTransaction &tx, CFeeRate dust_relay_rate)
Get the vout index numbers of all dust outputs.
Definition: policy.cpp:71
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
@ OP_CHECKSIG
Definition: script.h:191
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
std::vector< CTxIn > vin
Definition: transaction.h:359
std::vector< std::vector< unsigned char > > stack
Definition: script.h:581
Testing setup that configures a complete environment.
Definition: setup_common.h:115
const CTransactionRef m_tx
Bilingual messages:
Definition: translation.h:24
bool empty() const
Definition: translation.h:35
std::string original
Definition: translation.h:25
int64_t ancestor_count
The maximum allowed number of transactions in a package including the entry and its ancestors.
Options struct containing options for constructing a CTxMemPool.
NodeContext struct containing references to chain state and connection state.
Definition: context.h:59
std::unique_ptr< ValidationSignals > validation_signals
Issues calls about blocks and transactions.
Definition: context.h:97
std::unique_ptr< ChainstateManager > chainman
Definition: context.h:76
#define LOCK(cs)
Definition: sync.h:268
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:299
SeedRandomStateForTest(SeedRand::ZEROS)
NodeSeconds ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
Definition: util.cpp:34
uint32_t ConsumeSequence(FuzzedDataProvider &fuzzed_data_provider) noexcept
Definition: util.cpp:155
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.h:57
COutPoint MineBlock(const NodeContext &node, const node::BlockCreateOptions &assembler_options)
Returns the generated coin.
Definition: mining.cpp:78
@ ZEROS
Seed with a compile time constant of zeros.
static const std::vector< std::vector< uint8_t > > P2WSH_EMPTY_TRUE_STACK
Definition: script.h:31
static const std::vector< std::vector< uint8_t > > P2WSH_EMPTY_TWO_STACK
Definition: script.h:32
static const CScript P2WSH_EMPTY
Definition: script.h:23
void CheckMempoolTRUCInvariants(const CTxMemPool &tx_pool)
For every transaction in tx_pool, check TRUC invariants:
Definition: txmempool.cpp:182
CTxMemPool::Options MemPoolOptionsForTest(const NodeContext &node)
Definition: txmempool.cpp:21
std::optional< std::string > CheckPackageMempoolAcceptResult(const Package &txns, const PackageMempoolAcceptResult &result, bool expect_valid, const CTxMemPool *mempool)
Check expected properties for every PackageMempoolAcceptResult, regardless of value.
Definition: txmempool.cpp:44
void CheckMempoolEphemeralInvariants(const CTxMemPool &tx_pool)
Check that we never get into a state where an ephemeral dust transaction would be mined without the s...
Definition: txmempool.cpp:145
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
static constexpr decltype(CTransaction::version) TRUC_VERSION
Definition: truc_policy.h:20
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:89
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:52
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept, const std::optional< CFeeRate > &client_maxfeerate)
Validate (and maybe submit) a package to the mempool.
MempoolAcceptResult AcceptToMemoryPool(Chainstate &active_chainstate, const CTransactionRef &tx, int64_t accept_time, bool bypass_limits, bool test_accept)
Try to add a transaction to the mempool.
FuzzedDataProvider & fuzzed_data_provider
Definition: fees.cpp:39