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 {
242 Assert(!mempool_outpoints.empty());
243
244 std::vector<CTransactionRef> txs;
245
246 // Find something we may want to double-spend with two input single tx
247 std::optional<COutPoint> outpoint_to_rbf{fuzzed_data_provider.ConsumeBool() ? GetChildEvictingPrevout(tx_pool) : std::nullopt};
248
249 // Make small packages
250 const auto num_txs = outpoint_to_rbf ? 1 : fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4);
251
252 std::set<COutPoint> package_outpoints;
253 while (txs.size() < num_txs) {
254 // Create transaction to add to the mempool
255 txs.emplace_back([&] {
256 CMutableTransaction tx_mut;
258 tx_mut.nLockTime = 0;
259 // Last transaction in a package needs to be a child of parents to get further in validation
260 // so the last transaction to be generated(in a >1 package) must spend all package-made outputs
261 // Note that this test currently only spends package outputs in last transaction.
262 bool last_tx = num_txs > 1 && txs.size() == num_txs - 1;
263 const auto num_in = outpoint_to_rbf ? 2 :
264 last_tx ? fuzzed_data_provider.ConsumeIntegralInRange<int>(package_outpoints.size()/2 + 1, package_outpoints.size()) :
266 const auto num_out = outpoint_to_rbf ? 1 : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, 4);
267
268 auto& outpoints = last_tx ? package_outpoints : mempool_outpoints;
269
270 Assert((int)outpoints.size() >= num_in && num_in > 0);
271
272 CAmount amount_in{0};
273 for (int i = 0; i < num_in; ++i) {
274 // Pop random outpoint. We erase them to avoid double-spending
275 // while in this loop, but later add them back (unless last_tx).
276 auto pop = outpoints.begin();
277 std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints.size() - 1));
278 auto outpoint = *pop;
279
280 if (i == 0 && outpoint_to_rbf) {
281 outpoint = *outpoint_to_rbf;
282 outpoints.erase(outpoint);
283 } else {
284 outpoints.erase(pop);
285 }
286 // no need to update or erase from outpoints_value
287 amount_in += outpoints_value.at(outpoint);
288
289 // Create input
290 CTxIn in;
291 in.prevout = outpoint;
293
294 tx_mut.vin.push_back(in);
295 }
296
297 const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, amount_in);
298 const auto amount_out = (amount_in - amount_fee) / num_out;
299 for (int i = 0; i < num_out; ++i) {
300 tx_mut.vout.emplace_back(amount_out, P2WSH_EMPTY);
301 }
302
303 // Note output amounts can naturally drop to dust on their own.
304 if (!outpoint_to_rbf && fuzzed_data_provider.ConsumeBool()) {
305 uint32_t dust_index = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(0, num_out);
306 tx_mut.vout.insert(tx_mut.vout.begin() + dust_index, CTxOut(0, P2WSH_EMPTY));
307 }
308
309 auto tx = MakeTransactionRef(tx_mut);
310 // Restore previously removed outpoints, except in-package outpoints (to allow RBF)
311 if (!last_tx) {
312 for (const auto& in : tx->vin) {
313 Assert(outpoints.insert(in.prevout).second);
314 }
315 // Cache the in-package outpoints being made
316 for (size_t i = 0; i < tx->vout.size(); ++i) {
317 package_outpoints.emplace(tx->GetHash(), i);
318 }
319 }
320 // We need newly-created values for the duration of this run
321 for (size_t i = 0; i < tx->vout.size(); ++i) {
322 outpoints_value[COutPoint(tx->GetHash(), i)] = tx->vout[i].nValue;
323 }
324 return tx;
325 }());
326 }
327
329 const auto& txid = fuzzed_data_provider.ConsumeBool() ?
330 txs.back()->GetHash() :
331 PickValue(fuzzed_data_provider, mempool_outpoints).hash;
332 const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
333 // We only prioritise out of mempool transactions since PrioritiseTransaction doesn't
334 // filter for ephemeral dust
335 if (tx_pool.exists(txid)) {
336 const auto tx_info{tx_pool.info(txid)};
337 if (GetDust(*tx_info.tx, tx_pool.m_opts.dust_relay_feerate).empty()) {
338 tx_pool.PrioritiseTransaction(txid, delta);
339 }
340 }
341 }
342
343 auto single_submit = txs.size() == 1;
344
345 const auto result_package = WITH_LOCK(::cs_main,
346 return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, /*client_maxfeerate=*/{}));
347
348 const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(),
349 /*bypass_limits=*/false, /*test_accept=*/!single_submit));
350
351 if (!single_submit && result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
352 // We don't know anything about the validity since transactions were randomly generated, so
353 // just use result_package.m_state here. This makes the expect_valid check meaningless, but
354 // we can still verify that the contents of m_tx_results are consistent with m_state.
355 const bool expect_valid{result_package.m_state.IsValid()};
356 Assert(!CheckPackageMempoolAcceptResult(txs, result_package, expect_valid, &tx_pool));
357 }
358
359 node.validation_signals->SyncWithValidationInterfaceQueue();
360
362 }
363
364 node.validation_signals->UnregisterSharedValidationInterface(outpoints_updater);
365
366 WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1));
367}
368
369
370FUZZ_TARGET(tx_package_eval, .init = initialize_tx_pool)
371{
373 FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
374 const auto& node = g_setup->m_node;
375 auto& chainstate{static_cast<DummyChainState&>(node.chainman->ActiveChainstate())};
376
377 MockTime(fuzzed_data_provider, chainstate);
378
379 // All RBF-spendable outpoints outside of the unsubmitted package
380 std::set<COutPoint> mempool_outpoints;
381 std::unordered_map<COutPoint, CAmount, SaltedOutpointHasher> outpoints_value;
382 for (const auto& outpoint : g_outpoints_coinbase_init_mature) {
383 Assert(mempool_outpoints.insert(outpoint).second);
384 outpoints_value[outpoint] = 50 * COIN;
385 }
386
387 auto outpoints_updater = std::make_shared<OutpointsUpdater>(mempool_outpoints);
388 node.validation_signals->RegisterSharedValidationInterface(outpoints_updater);
389
390 auto tx_pool_{MakeMempool(fuzzed_data_provider, node)};
391 MockedTxPool& tx_pool = *static_cast<MockedTxPool*>(tx_pool_.get());
392
393 chainstate.SetMempool(&tx_pool);
394
396 {
397 Assert(!mempool_outpoints.empty());
398
399 std::vector<CTransactionRef> txs;
400
401 // Make packages of 1-to-26 transactions
402 const auto num_txs = fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 26);
403 std::set<COutPoint> package_outpoints;
404 while (txs.size() < num_txs) {
405 // Create transaction to add to the mempool
406 txs.emplace_back([&] {
407 CMutableTransaction tx_mut;
410 // Last transaction in a package needs to be a child of parents to get further in validation
411 // so the last transaction to be generated(in a >1 package) must spend all package-made outputs
412 // Note that this test currently only spends package outputs in last transaction.
413 bool last_tx = num_txs > 1 && txs.size() == num_txs - 1;
414 const auto num_in = last_tx ? package_outpoints.size() : fuzzed_data_provider.ConsumeIntegralInRange<int>(1, mempool_outpoints.size());
415 auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<int>(1, mempool_outpoints.size() * 2);
416
417 auto& outpoints = last_tx ? package_outpoints : mempool_outpoints;
418
419 Assert(!outpoints.empty());
420
421 CAmount amount_in{0};
422 for (size_t i = 0; i < num_in; ++i) {
423 // Pop random outpoint. We erase them to avoid double-spending
424 // while in this loop, but later add them back (unless last_tx).
425 auto pop = outpoints.begin();
426 std::advance(pop, fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, outpoints.size() - 1));
427 const auto outpoint = *pop;
428 outpoints.erase(pop);
429 // no need to update or erase from outpoints_value
430 amount_in += outpoints_value.at(outpoint);
431
432 // Create input
434 const auto script_sig = CScript{};
436
437 CTxIn in;
438 in.prevout = outpoint;
439 in.nSequence = sequence;
440 in.scriptSig = script_sig;
441 in.scriptWitness.stack = script_wit_stack;
442
443 tx_mut.vin.push_back(in);
444 }
445
446 // Duplicate an input
447 bool dup_input = fuzzed_data_provider.ConsumeBool();
448 if (dup_input) {
449 tx_mut.vin.push_back(tx_mut.vin.back());
450 }
451
452 // Refer to a non-existent input
454 tx_mut.vin.emplace_back();
455 }
456
457 // Make a p2pk output to make sigops adjusted vsize to violate TRUC rules, potentially, which is never spent
458 if (last_tx && amount_in > 1000 && fuzzed_data_provider.ConsumeBool()) {
459 tx_mut.vout.emplace_back(1000, CScript() << std::vector<unsigned char>(33, 0x02) << OP_CHECKSIG);
460 // Don't add any other outputs.
461 num_out = 1;
462 amount_in -= 1000;
463 }
464
465 const auto amount_fee = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(0, amount_in);
466 const auto amount_out = (amount_in - amount_fee) / num_out;
467 for (int i = 0; i < num_out; ++i) {
468 tx_mut.vout.emplace_back(amount_out, P2WSH_EMPTY);
469 }
470 auto tx = MakeTransactionRef(tx_mut);
471 // Restore previously removed outpoints, except in-package outpoints
472 if (!last_tx) {
473 for (const auto& in : tx->vin) {
474 // It's a fake input, or a new input, or a duplicate
475 Assert(in == CTxIn() || outpoints.insert(in.prevout).second || dup_input);
476 }
477 // Cache the in-package outpoints being made
478 for (size_t i = 0; i < tx->vout.size(); ++i) {
479 package_outpoints.emplace(tx->GetHash(), i);
480 }
481 }
482 // We need newly-created values for the duration of this run
483 for (size_t i = 0; i < tx->vout.size(); ++i) {
484 outpoints_value[COutPoint(tx->GetHash(), i)] = tx->vout[i].nValue;
485 }
486 return tx;
487 }());
488 }
489
491 MockTime(fuzzed_data_provider, chainstate);
492 }
494 tx_pool.RollingFeeUpdate();
495 }
497 const auto& txid = fuzzed_data_provider.ConsumeBool() ?
498 txs.back()->GetHash() :
499 PickValue(fuzzed_data_provider, mempool_outpoints).hash;
500 const auto delta = fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-50 * COIN, +50 * COIN);
501 tx_pool.PrioritiseTransaction(txid, delta);
502 }
503
504 // Remember all added transactions
505 std::set<CTransactionRef> added;
506 auto txr = std::make_shared<TransactionsDelta>(added);
507 node.validation_signals->RegisterSharedValidationInterface(txr);
508
509 // When there are multiple transactions in the package, we call ProcessNewPackage(txs, test_accept=false)
510 // and AcceptToMemoryPool(txs.back(), test_accept=true). When there is only 1 transaction, we might flip it
511 // (the package is a test accept and ATMP is a submission).
512 auto single_submit = txs.size() == 1 && fuzzed_data_provider.ConsumeBool();
513
514 // Exercise client_maxfeerate logic
515 std::optional<CFeeRate> client_maxfeerate{};
517 client_maxfeerate = CFeeRate(fuzzed_data_provider.ConsumeIntegralInRange<CAmount>(-1, 50 * COIN), 100);
518 }
519
520 const auto result_package = WITH_LOCK(::cs_main,
521 return ProcessNewPackage(chainstate, tx_pool, txs, /*test_accept=*/single_submit, client_maxfeerate));
522
523 // Always set bypass_limits to false because it is not supported in ProcessNewPackage and
524 // can be a source of divergence.
525 const auto res = WITH_LOCK(::cs_main, return AcceptToMemoryPool(chainstate, txs.back(), GetTime(),
526 /*bypass_limits=*/false, /*test_accept=*/!single_submit));
527 const bool passed = res.m_result_type == MempoolAcceptResult::ResultType::VALID;
528
529 node.validation_signals->SyncWithValidationInterfaceQueue();
530 node.validation_signals->UnregisterSharedValidationInterface(txr);
531
532 // There is only 1 transaction in the package. We did a test-package-accept and a ATMP
533 if (single_submit) {
534 Assert(passed != added.empty());
535 Assert(passed == res.m_state.IsValid());
536 if (passed) {
537 Assert(added.size() == 1);
538 Assert(txs.back() == *added.begin());
539 }
540 } else if (result_package.m_state.GetResult() != PackageValidationResult::PCKG_POLICY) {
541 // We don't know anything about the validity since transactions were randomly generated, so
542 // just use result_package.m_state here. This makes the expect_valid check meaningless, but
543 // we can still verify that the contents of m_tx_results are consistent with m_state.
544 const bool expect_valid{result_package.m_state.IsValid()};
545 Assert(!CheckPackageMempoolAcceptResult(txs, result_package, expect_valid, &tx_pool));
546 } else {
547 // This is empty if it fails early checks, or "full" if transactions are looked at deeper
548 Assert(result_package.m_tx_results.size() == txs.size() || result_package.m_tx_results.empty());
549 }
550
552
553 // Dust checks only make sense when dust is enforced
554 if (tx_pool.m_opts.require_standard) {
556 }
557 }
558
559 node.validation_signals->UnregisterSharedValidationInterface(outpoints_updater);
560
561 WITH_LOCK(::cs_main, tx_pool.check(chainstate.CoinsTip(), chainstate.m_chain.Height() + 1));
562}
563} // 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:551
CChain m_chain
The current chain of blockheaders we consult and build on.
Definition: validation.h:625
T ConsumeIntegralInRange(T min, T max)
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
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
Definition: fuzz.h:22
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
Definition: common.h:30
@ 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:58
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:113
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
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:49
COutPoint MineBlock(const NodeContext &node, const node::BlockCreateOptions &assembler_options)
Returns the generated coin.
Definition: mining.cpp:78
void SeedRandomStateForTest(SeedRand seedtype)
Seed the global RNG state for testing and log the seed value.
Definition: random.cpp:19
@ 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