15 #include <boost/test/unit_test.hpp> 23 mtx.
vin.resize(num_inputs);
24 mtx.
vout.resize(num_outputs);
26 for (
size_t i{0}; i < num_inputs; ++i) {
28 mtx.
vin[i].prevout.n = 0;
29 mtx.
vin[i].scriptSig = random_script;
31 for (
size_t o{0}; o < num_outputs; ++o) {
33 mtx.
vout[o].scriptPubKey = random_script;
57 package_too_large.push_back(large_ptx);
58 total_size += size_large;
76 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
78 parent_locking_script,
85 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
91 BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(),
92 "Package validation unexpectedly failed: " << result_parent_child.m_state.GetRejectReason());
93 auto it_parent = result_parent_child.
m_tx_results.find(tx_parent->GetWitnessHash());
94 auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
95 BOOST_CHECK(it_parent != result_parent_child.m_tx_results.end());
96 BOOST_CHECK_MESSAGE(it_parent->second.m_state.IsValid(),
97 "Package validation unexpectedly failed: " << it_parent->second.m_state.GetRejectReason());
98 BOOST_CHECK(it_child != result_parent_child.m_tx_results.end());
99 BOOST_CHECK_MESSAGE(it_child->second.m_state.IsValid(),
100 "Package validation unexpectedly failed: " << it_child->second.m_state.GetRejectReason());
101 BOOST_CHECK(result_parent_child.m_package_feerate.has_value());
102 BOOST_CHECK(result_parent_child.m_package_feerate.value() ==
109 BOOST_CHECK(result_single_large.m_state.IsInvalid());
111 BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(),
"transaction failed");
112 auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
113 BOOST_CHECK(it_giant_tx != result_single_large.m_tx_results.end());
115 BOOST_CHECK(result_single_large.m_package_feerate == std::nullopt);
124 CKey placeholder_key;
127 CKey placeholder_key_2;
133 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,
137 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,
153 for (
int i{0}; i < 24; ++i) {
154 auto parent =
MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],
155 0, 0, coinbaseKey, spk,
CAmount(48 *
COIN),
false));
156 package.emplace_back(parent);
166 Shuffle(package.begin(), package.end(), rng);
173 package.erase(package.begin());
177 package.insert(package.begin(), m_coinbase_txns[0]);
223 for (
size_t i{0}; i < 10; ++i) {
224 auto mtx = CreateValidMempoolTransaction(m_coinbase_txns[i + 25], 0,
226 parent_locking_script,
231 package_unrelated,
false);
232 BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());
234 BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(),
"package-not-child-with-parents");
236 BOOST_CHECK(result_unrelated_submit.m_package_feerate == std::nullopt);
241 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
243 parent_locking_script,
246 package_parent_child.push_back(tx_parent);
247 package_3gen.push_back(tx_parent);
252 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
254 child_locking_script,
257 package_parent_child.push_back(tx_child);
258 package_3gen.push_back(tx_child);
263 auto mtx_grandchild = CreateValidMempoolTransaction(tx_child, 0,
265 grandchild_locking_script,
268 package_3gen.push_back(tx_grandchild);
273 package_3gen,
false);
274 BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());
276 BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(),
"package-not-child-with-parents");
278 BOOST_CHECK(result_3gen_submit.m_package_feerate == std::nullopt);
282 mtx_child.vin.push_back(
CTxIn(
COutPoint(package_unrelated[0]->GetHash(), 0)));
283 Package package_missing_parent;
284 package_missing_parent.push_back(tx_parent);
288 package_missing_parent,
false);
289 BOOST_CHECK(result_missing_parent.m_state.IsInvalid());
291 BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(),
"package-not-child-with-unconfirmed-parents");
294 BOOST_CHECK(result_missing_parent.m_package_feerate == std::nullopt);
300 package_parent_child,
false);
301 expected_pool_size += 2;
302 BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
303 "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
304 auto it_parent = submit_parent_child.
m_tx_results.find(tx_parent->GetWitnessHash());
305 auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
306 BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
308 BOOST_CHECK(it_child != submit_parent_child.m_tx_results.end());
317 BOOST_CHECK(submit_parent_child.m_package_feerate == std::nullopt);
323 package_parent_child,
false);
324 BOOST_CHECK_MESSAGE(submit_deduped.m_state.IsValid(),
325 "Package validation unexpectedly failed: " << submit_deduped.m_state.GetRejectReason());
326 auto it_parent_deduped = submit_deduped.
m_tx_results.find(tx_parent->GetWitnessHash());
327 auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
328 BOOST_CHECK(it_parent_deduped != submit_deduped.m_tx_results.end());
329 BOOST_CHECK(it_parent_deduped->second.m_state.IsValid());
331 BOOST_CHECK(it_child_deduped != submit_deduped.m_tx_results.end());
332 BOOST_CHECK(it_child_deduped->second.m_state.IsValid());
339 BOOST_CHECK(submit_deduped.m_package_feerate == std::nullopt);
355 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
363 witness1.
stack.push_back(std::vector<unsigned char>(1));
364 witness1.
stack.push_back(std::vector<unsigned char>(witnessScript.
begin(), witnessScript.
end()));
367 witness2.
stack.push_back(std::vector<unsigned char>(2));
368 witness2.
stack.push_back(std::vector<unsigned char>(witnessScript.
begin(), witnessScript.
end()));
375 mtx_child1.
vin.resize(1);
376 mtx_child1.
vin[0].prevout.hash = ptx_parent->GetHash();
377 mtx_child1.
vin[0].prevout.n = 0;
379 mtx_child1.
vin[0].scriptWitness = witness1;
380 mtx_child1.
vout.resize(1);
382 mtx_child1.
vout[0].scriptPubKey = child_locking_script;
385 mtx_child2.
vin[0].scriptWitness = witness2;
393 BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash());
399 {ptx_parent, ptx_child1},
false);
400 BOOST_CHECK_MESSAGE(submit_witness1.m_state.IsValid(),
401 "Package validation unexpectedly failed: " << submit_witness1.m_state.GetRejectReason());
402 auto it_parent1 = submit_witness1.
m_tx_results.find(ptx_parent->GetWitnessHash());
403 auto it_child1 = submit_witness1.m_tx_results.find(ptx_child1->GetWitnessHash());
404 BOOST_CHECK(it_parent1 != submit_witness1.m_tx_results.end());
405 BOOST_CHECK_MESSAGE(it_parent1->second.m_state.IsValid(),
406 "Transaction unexpectedly failed: " << it_parent1->second.m_state.GetRejectReason());
407 BOOST_CHECK(it_child1 != submit_witness1.m_tx_results.end());
408 BOOST_CHECK_MESSAGE(it_child1->second.m_state.IsValid(),
409 "Transaction unexpectedly failed: " << it_child1->second.m_state.GetRejectReason());
415 BOOST_CHECK(submit_witness1.m_package_feerate == std::nullopt);
418 {ptx_parent, ptx_child2},
false);
419 BOOST_CHECK(submit_witness2.m_package_feerate == std::nullopt);
420 BOOST_CHECK_MESSAGE(submit_witness2.m_state.IsValid(),
421 "Package validation unexpectedly failed: " << submit_witness2.m_state.GetRejectReason());
422 auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
423 auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
424 BOOST_CHECK(it_parent2_deduped != submit_witness2.m_tx_results.end());
426 BOOST_CHECK(it_child2 != submit_witness2.m_tx_results.end());
428 BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value());
436 {ptx_parent, ptx_child1},
false);
437 BOOST_CHECK_MESSAGE(submit_segwit_dedup.m_state.IsValid(),
438 "Package validation unexpectedly failed: " << submit_segwit_dedup.m_state.GetRejectReason());
439 auto it_parent_dup = submit_segwit_dedup.
m_tx_results.find(ptx_parent->GetWitnessHash());
440 auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
443 BOOST_CHECK(submit_witness2.m_package_feerate == std::nullopt);
456 auto mtx_grandchild = CreateValidMempoolTransaction(ptx_child2, 0,
458 grandchild_locking_script,
465 {ptx_child2, ptx_grandchild},
false);
466 BOOST_CHECK_MESSAGE(submit_spend_ignored.m_state.IsValid(),
467 "Package validation unexpectedly failed: " << submit_spend_ignored.m_state.GetRejectReason());
468 auto it_child2_ignored = submit_spend_ignored.
m_tx_results.find(ptx_child2->GetWitnessHash());
469 auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
470 BOOST_CHECK(it_child2_ignored != submit_spend_ignored.m_tx_results.end());
472 BOOST_CHECK(it_grandchild != submit_spend_ignored.m_tx_results.end());
480 BOOST_CHECK(submit_spend_ignored.m_package_feerate == std::nullopt);
491 acs_witness.
stack.push_back(std::vector<unsigned char>(acs_script.
begin(), acs_script.
end()));
494 auto mtx_parent1 = CreateValidMempoolTransaction(m_coinbase_txns[1], 0,
499 package_mixed.push_back(ptx_parent1);
505 parent2_witness1.
stack.push_back(std::vector<unsigned char>(1));
506 parent2_witness1.
stack.push_back(std::vector<unsigned char>(grandparent2_script.
begin(), grandparent2_script.
end()));
508 parent2_witness2.
stack.push_back(std::vector<unsigned char>(2));
509 parent2_witness2.
stack.push_back(std::vector<unsigned char>(grandparent2_script.
begin(), grandparent2_script.
end()));
512 auto mtx_grandparent2 = CreateValidMempoolTransaction(m_coinbase_txns[2], 0,
520 mtx_parent2_v1.
vin.resize(1);
521 mtx_parent2_v1.
vin[0].prevout.hash = ptx_grandparent2->GetHash();
522 mtx_parent2_v1.
vin[0].prevout.n = 0;
524 mtx_parent2_v1.
vin[0].scriptWitness = parent2_witness1;
525 mtx_parent2_v1.
vout.resize(1);
527 mtx_parent2_v1.
vout[0].scriptPubKey = acs_spk;
530 mtx_parent2_v2.
vin[0].scriptWitness = parent2_witness2;
537 package_mixed.push_back(ptx_parent2_v1);
540 auto mtx_parent3 = CreateValidMempoolTransaction(m_coinbase_txns[3], 0,
545 package_mixed.push_back(ptx_parent3);
548 CKey mixed_grandchild_key;
556 mtx_mixed_child.
vin[0].scriptWitness = acs_witness;
557 mtx_mixed_child.
vin[1].scriptWitness = acs_witness;
558 mtx_mixed_child.
vin[2].scriptWitness = acs_witness;
559 mtx_mixed_child.
vout.push_back(
CTxOut((48 + 49 + 50 - 1) *
COIN, mixed_child_spk));
561 package_mixed.push_back(ptx_mixed_child);
570 BOOST_CHECK_MESSAGE(mixed_result.m_state.IsValid(), mixed_result.m_state.GetRejectReason());
571 auto it_parent1 = mixed_result.
m_tx_results.find(ptx_parent1->GetWitnessHash());
572 auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
573 auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
574 auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash());
575 BOOST_CHECK(it_parent1 != mixed_result.m_tx_results.end());
576 BOOST_CHECK(it_parent2 != mixed_result.m_tx_results.end());
577 BOOST_CHECK(it_parent3 != mixed_result.m_tx_results.end());
578 BOOST_CHECK(it_child != mixed_result.m_tx_results.end());
584 BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value());
593 BOOST_CHECK(mixed_result.m_package_feerate.has_value());
595 BOOST_CHECK_MESSAGE(mixed_result.m_package_feerate.value() == expected_feerate,
596 strprintf(
"Expected package feerate %s, got %s", expected_feerate.ToString(),
597 mixed_result.m_package_feerate.value().ToString()));
615 const CAmount parent_value{coinbase_value - 0};
619 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
622 parent_value,
false);
624 package_cpfp.push_back(tx_parent);
626 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
631 package_cpfp.push_back(tx_child);
640 package_cpfp,
false);
641 BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_state.IsInvalid(),
642 "Package validation unexpectedly succeeded: " << submit_cpfp_deprio.m_state.GetRejectReason());
643 BOOST_CHECK(submit_cpfp_deprio.m_tx_results.empty());
646 BOOST_CHECK(submit_cpfp_deprio.m_package_feerate.has_value());
648 BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_package_feerate.value() == expected_feerate,
649 strprintf(
"Expected package feerate %s, got %s", expected_feerate.ToString(),
650 submit_cpfp_deprio.m_package_feerate.value().ToString()));
661 package_cpfp,
false);
662 expected_pool_size += 2;
663 BOOST_CHECK_MESSAGE(submit_cpfp.m_state.IsValid(),
664 "Package validation unexpectedly failed: " << submit_cpfp.m_state.GetRejectReason());
665 auto it_parent = submit_cpfp.
m_tx_results.find(tx_parent->GetWitnessHash());
666 auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
667 BOOST_CHECK(it_parent != submit_cpfp.m_tx_results.end());
669 BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
670 BOOST_CHECK(it_child != submit_cpfp.m_tx_results.end());
678 const CFeeRate expected_feerate(coinbase_value - child_value,
681 BOOST_CHECK(submit_cpfp.m_package_feerate.has_value());
682 BOOST_CHECK_MESSAGE(submit_cpfp.m_package_feerate.value() == expected_feerate,
683 strprintf(
"Expected package feerate %s, got %s", expected_feerate.ToString(),
684 submit_cpfp.m_package_feerate.value().ToString()));
691 auto mtx_parent_cheap = CreateValidMempoolTransaction(m_coinbase_txns[1], 0,
694 coinbase_value,
false);
696 package_still_too_low.push_back(tx_parent_cheap);
698 auto mtx_child_cheap = CreateValidMempoolTransaction(tx_parent_cheap, 0,
701 coinbase_value - 200,
false);
703 package_still_too_low.push_back(tx_child_cheap);
709 package_still_too_low,
false);
710 BOOST_CHECK_MESSAGE(submit_package_too_low.m_state.IsInvalid(),
"Package validation unexpectedly succeeded");
712 BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(),
"package-fee-too-low");
716 const CFeeRate expected_feerate(200,
719 BOOST_CHECK(submit_package_too_low.m_package_feerate.has_value());
720 BOOST_CHECK_MESSAGE(submit_package_too_low.m_package_feerate.value() == expected_feerate,
721 strprintf(
"Expected package feerate %s, got %s", expected_feerate.ToString(),
722 submit_package_too_low.m_package_feerate.value().ToString()));
731 package_still_too_low,
false);
732 expected_pool_size += 2;
733 BOOST_CHECK_MESSAGE(submit_prioritised_package.m_state.IsValid(),
734 "Package validation unexpectedly failed" << submit_prioritised_package.m_state.GetRejectReason());
737 BOOST_CHECK(submit_prioritised_package.m_package_feerate.has_value());
738 BOOST_CHECK_MESSAGE(submit_prioritised_package.m_package_feerate.value() == expected_feerate,
739 strprintf(
"Expected package feerate %s, got %s", expected_feerate.ToString(),
740 submit_prioritised_package.m_package_feerate.value().ToString()));
750 auto mtx_parent_rich = CreateValidMempoolTransaction(m_coinbase_txns[2], 0,
753 coinbase_value - high_parent_fee,
false);
755 package_rich_parent.push_back(tx_parent_rich);
757 auto mtx_child_poor = CreateValidMempoolTransaction(tx_parent_rich, 0,
760 coinbase_value - high_parent_fee,
false);
762 package_rich_parent.push_back(tx_child_poor);
768 package_rich_parent,
false);
769 expected_pool_size += 1;
770 BOOST_CHECK_MESSAGE(submit_rich_parent.m_state.IsInvalid(),
"Package validation unexpectedly succeeded");
774 BOOST_CHECK(submit_rich_parent.m_package_feerate.has_value());
775 BOOST_CHECK_MESSAGE(submit_rich_parent.m_package_feerate.value() ==
CFeeRate(),
776 "expected 0, got " << submit_rich_parent.m_package_feerate.value().
ToString());
778 BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(),
"package-fee-too-low");
780 auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
781 BOOST_CHECK(it_parent != submit_rich_parent.m_tx_results.end());
783 BOOST_CHECK(it_parent->second.m_state.GetRejectReason() ==
"");
784 BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
785 strprintf(
"rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
std::shared_ptr< const CTransaction > CTransactionRef
static GenTxid Wtxid(const uint256 &hash)
static constexpr uint32_t MAX_PACKAGE_SIZE
Default maximum total virtual size of transactions in a package in KvB.
The package itself is invalid (e.g. too many transactions).
Valid, transaction was already in the mempool.
bool IsChildWithParents(const Package &package)
Context-free check that a package is exactly one child and its parents; not all parents need to be pr...
CPubKey GetPubKey() const
Compute the public key from a private key.
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
std::map< const uint256, const MempoolAcceptResult > m_tx_results
Map from wtxid to finished MempoolAcceptResults.
std::vector< std::vector< unsigned char > > stack
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
Compute the virtual transaction size (weight reinterpreted as bytes).
const ResultType m_result_type
Result type.
bool CheckPackage(const Package &txns, PackageValidationState &state)
Context-free package policy checks:
std::unique_ptr< CTxMemPool > mempool
int64_t CAmount
Amount in satoshis (Can be negative)
An input of a transaction.
BOOST_AUTO_TEST_SUITE_END()
std::string ToString(const FeeEstimateMode &fee_estimate_mode=FeeEstimateMode::BTC_KVB) const
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept)
Validate (and maybe submit) a package to the mempool.
An output of a transaction.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
At least one tx is invalid.
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
An outpoint - a combination of a transaction hash and an index n into its vout.
std::vector< CTxOut > vout
Validation result for a single transaction mempool acceptance.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::vector< unsigned char > ToByteVector(const T &in)
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
#define BOOST_CHECK_EQUAL(v1, v2)
Serialized script, used inside transaction inputs and outputs.
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
BOOST_AUTO_TEST_SUITE(cuckoocache_tests)
Test Suite for CuckooCache.
A mutable version of CTransaction.
static constexpr CAmount CENT
static constexpr uint32_t MAX_PACKAGE_COUNT
Default maximum number of transactions in a package.
An encapsulated private key.
std::string GetRejectReason() const
CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
static uint256 InsecureRand256()
std::unique_ptr< ChainstateManager > chainman
static GenTxid Txid(const uint256 &hash)
#define BOOST_CHECK(expr)
static constexpr CAmount COIN
The amount of satoshis in one BTC.