16 #include <boost/test/unit_test.hpp>
24 mtx.
vin.resize(num_inputs);
25 mtx.
vout.resize(num_outputs);
27 for (
size_t i{0}; i < num_inputs; ++i) {
29 mtx.
vin[i].prevout.n = 0;
30 mtx.
vin[i].scriptSig = random_script;
32 for (
size_t o{0}; o < num_outputs; ++o) {
34 mtx.
vout[o].scriptPubKey = random_script;
58 package_too_large.push_back(large_ptx);
59 total_size += size_large;
77 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
79 parent_locking_script,
86 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
92 BOOST_CHECK_MESSAGE(result_parent_child.m_state.IsValid(),
93 "Package validation unexpectedly failed: " << result_parent_child.m_state.GetRejectReason());
94 BOOST_CHECK(result_parent_child.m_tx_results.size() == 2);
95 auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
96 auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
97 BOOST_CHECK(it_parent != result_parent_child.m_tx_results.end());
98 BOOST_CHECK_MESSAGE(it_parent->second.m_state.IsValid(),
99 "Package validation unexpectedly failed: " << it_parent->second.m_state.GetRejectReason());
101 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
102 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
103 BOOST_CHECK(it_child != result_parent_child.m_tx_results.end());
104 BOOST_CHECK_MESSAGE(it_child->second.m_state.IsValid(),
105 "Package validation unexpectedly failed: " << it_child->second.m_state.GetRejectReason());
108 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
114 BOOST_CHECK(result_single_large.m_state.IsInvalid());
116 BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(),
"transaction failed");
117 BOOST_CHECK(result_single_large.m_tx_results.size() == 1);
118 auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
119 BOOST_CHECK(it_giant_tx != result_single_large.m_tx_results.end());
129 CKey placeholder_key;
132 CKey placeholder_key_2;
138 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,
142 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,
158 for (
int i{0}; i < 24; ++i) {
159 auto parent =
MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],
160 0, 0, coinbaseKey, spk,
CAmount(48 *
COIN),
false));
161 package.emplace_back(parent);
171 Shuffle(package.begin(), package.end(), rng);
178 package.erase(package.begin());
182 package.insert(package.begin(), m_coinbase_txns[0]);
228 for (
size_t i{0}; i < 10; ++i) {
229 auto mtx = CreateValidMempoolTransaction(m_coinbase_txns[i + 25], 0,
231 parent_locking_script,
236 package_unrelated,
false);
237 BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());
239 BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(),
"package-not-child-with-parents");
245 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
247 parent_locking_script,
250 package_parent_child.push_back(tx_parent);
251 package_3gen.push_back(tx_parent);
256 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
258 child_locking_script,
261 package_parent_child.push_back(tx_child);
262 package_3gen.push_back(tx_child);
267 auto mtx_grandchild = CreateValidMempoolTransaction(tx_child, 0,
269 grandchild_locking_script,
272 package_3gen.push_back(tx_grandchild);
277 package_3gen,
false);
278 BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());
280 BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(),
"package-not-child-with-parents");
288 bad_witness.
stack.push_back(std::vector<unsigned char>(1));
290 mtx_parent_invalid.
vin[0].scriptWitness = bad_witness;
293 {tx_parent_invalid, tx_child},
false);
294 BOOST_CHECK(result_quit_early.m_state.IsInvalid());
296 BOOST_CHECK(!result_quit_early.m_tx_results.empty());
298 auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());
299 auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());
300 BOOST_CHECK(it_parent != result_quit_early.m_tx_results.end());
301 BOOST_CHECK(it_child != result_quit_early.m_tx_results.end());
303 BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(),
"bad-witness-nonstandard");
305 BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(),
"bad-txns-inputs-missingorspent");
309 mtx_child.vin.push_back(
CTxIn(
COutPoint(package_unrelated[0]->GetHash(), 0)));
310 Package package_missing_parent;
311 package_missing_parent.push_back(tx_parent);
315 package_missing_parent,
false);
316 BOOST_CHECK(result_missing_parent.m_state.IsInvalid());
318 BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(),
"package-not-child-with-unconfirmed-parents");
325 package_parent_child,
false);
326 expected_pool_size += 2;
327 BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
328 "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
329 BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());
330 auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
331 auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
332 BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
335 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
336 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
337 BOOST_CHECK(it_child != submit_parent_child.m_tx_results.end());
341 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
351 package_parent_child,
false);
352 BOOST_CHECK_MESSAGE(submit_deduped.m_state.IsValid(),
353 "Package validation unexpectedly failed: " << submit_deduped.m_state.GetRejectReason());
354 BOOST_CHECK_EQUAL(submit_deduped.m_tx_results.size(), package_parent_child.size());
355 auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());
356 auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
357 BOOST_CHECK(it_parent_deduped != submit_deduped.m_tx_results.end());
358 BOOST_CHECK(it_parent_deduped->second.m_state.IsValid());
360 BOOST_CHECK(it_child_deduped != submit_deduped.m_tx_results.end());
361 BOOST_CHECK(it_child_deduped->second.m_state.IsValid());
382 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
390 witness1.
stack.push_back(std::vector<unsigned char>(1));
391 witness1.
stack.push_back(std::vector<unsigned char>(witnessScript.
begin(), witnessScript.
end()));
394 witness2.
stack.push_back(std::vector<unsigned char>(2));
395 witness2.
stack.push_back(std::vector<unsigned char>(witnessScript.
begin(), witnessScript.
end()));
402 mtx_child1.
vin.resize(1);
403 mtx_child1.
vin[0].prevout.hash = ptx_parent->GetHash();
404 mtx_child1.
vin[0].prevout.n = 0;
406 mtx_child1.
vin[0].scriptWitness = witness1;
407 mtx_child1.
vout.resize(1);
409 mtx_child1.
vout[0].scriptPubKey = child_locking_script;
412 mtx_child2.
vin[0].scriptWitness = witness2;
420 BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash());
426 {ptx_parent, ptx_child1},
false);
427 BOOST_CHECK_MESSAGE(submit_witness1.m_state.IsValid(),
428 "Package validation unexpectedly failed: " << submit_witness1.m_state.GetRejectReason());
430 auto it_parent1 = submit_witness1.m_tx_results.find(ptx_parent->GetWitnessHash());
431 auto it_child1 = submit_witness1.m_tx_results.find(ptx_child1->GetWitnessHash());
432 BOOST_CHECK(it_parent1 != submit_witness1.m_tx_results.end());
433 BOOST_CHECK_MESSAGE(it_parent1->second.m_state.IsValid(),
434 "Transaction unexpectedly failed: " << it_parent1->second.m_state.GetRejectReason());
435 BOOST_CHECK(it_child1 != submit_witness1.m_tx_results.end());
436 BOOST_CHECK_MESSAGE(it_child1->second.m_state.IsValid(),
437 "Transaction unexpectedly failed: " << it_child1->second.m_state.GetRejectReason());
444 {ptx_parent, ptx_child2},
false);
445 BOOST_CHECK_MESSAGE(submit_witness2.m_state.IsValid(),
446 "Package validation unexpectedly failed: " << submit_witness2.m_state.GetRejectReason());
448 auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
449 auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
450 BOOST_CHECK(it_parent2_deduped != submit_witness2.m_tx_results.end());
452 BOOST_CHECK(it_child2 != submit_witness2.m_tx_results.end());
454 BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value());
462 {ptx_parent, ptx_child1},
false);
463 BOOST_CHECK_MESSAGE(submit_segwit_dedup.m_state.IsValid(),
464 "Package validation unexpectedly failed: " << submit_segwit_dedup.m_state.GetRejectReason());
466 auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash());
467 auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
482 auto mtx_grandchild = CreateValidMempoolTransaction(ptx_child2, 0,
484 grandchild_locking_script,
491 {ptx_child2, ptx_grandchild},
false);
492 BOOST_CHECK_MESSAGE(submit_spend_ignored.m_state.IsValid(),
493 "Package validation unexpectedly failed: " << submit_spend_ignored.m_state.GetRejectReason());
495 auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash());
496 auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
497 BOOST_CHECK(it_child2_ignored != submit_spend_ignored.m_tx_results.end());
499 BOOST_CHECK(it_grandchild != submit_spend_ignored.m_tx_results.end());
515 acs_witness.
stack.push_back(std::vector<unsigned char>(acs_script.
begin(), acs_script.
end()));
518 auto mtx_parent1 = CreateValidMempoolTransaction(m_coinbase_txns[1], 0,
523 package_mixed.push_back(ptx_parent1);
529 parent2_witness1.
stack.push_back(std::vector<unsigned char>(1));
530 parent2_witness1.
stack.push_back(std::vector<unsigned char>(grandparent2_script.
begin(), grandparent2_script.
end()));
532 parent2_witness2.
stack.push_back(std::vector<unsigned char>(2));
533 parent2_witness2.
stack.push_back(std::vector<unsigned char>(grandparent2_script.
begin(), grandparent2_script.
end()));
536 auto mtx_grandparent2 = CreateValidMempoolTransaction(m_coinbase_txns[2], 0,
544 mtx_parent2_v1.
vin.resize(1);
545 mtx_parent2_v1.
vin[0].prevout.hash = ptx_grandparent2->GetHash();
546 mtx_parent2_v1.
vin[0].prevout.n = 0;
548 mtx_parent2_v1.
vin[0].scriptWitness = parent2_witness1;
549 mtx_parent2_v1.
vout.resize(1);
551 mtx_parent2_v1.
vout[0].scriptPubKey = acs_spk;
554 mtx_parent2_v2.
vin[0].scriptWitness = parent2_witness2;
561 package_mixed.push_back(ptx_parent2_v1);
564 auto mtx_parent3 = CreateValidMempoolTransaction(m_coinbase_txns[3], 0,
569 package_mixed.push_back(ptx_parent3);
572 CKey mixed_grandchild_key;
580 mtx_mixed_child.
vin[0].scriptWitness = acs_witness;
581 mtx_mixed_child.
vin[1].scriptWitness = acs_witness;
582 mtx_mixed_child.
vin[2].scriptWitness = acs_witness;
583 mtx_mixed_child.
vout.push_back(
CTxOut((48 + 49 + 50 - 1) *
COIN, mixed_child_spk));
585 package_mixed.push_back(ptx_mixed_child);
594 BOOST_CHECK_MESSAGE(mixed_result.m_state.IsValid(), mixed_result.m_state.GetRejectReason());
596 auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash());
597 auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
598 auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
599 auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash());
600 BOOST_CHECK(it_parent1 != mixed_result.m_tx_results.end());
601 BOOST_CHECK(it_parent2 != mixed_result.m_tx_results.end());
602 BOOST_CHECK(it_parent3 != mixed_result.m_tx_results.end());
603 BOOST_CHECK(it_child != mixed_result.m_tx_results.end());
609 BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value());
619 BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate);
620 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
621 std::vector<uint256> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()});
622 BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids);
623 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
641 const CAmount parent_value{coinbase_value - 0};
645 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
648 parent_value,
false);
650 package_cpfp.push_back(tx_parent);
652 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
657 package_cpfp.push_back(tx_child);
666 package_cpfp,
false);
668 BOOST_CHECK_MESSAGE(submit_cpfp_deprio.m_state.IsInvalid(),
669 "Package validation unexpectedly succeeded: " << submit_cpfp_deprio.m_state.GetRejectReason());
670 BOOST_CHECK(submit_cpfp_deprio.m_tx_results.empty());
683 package_cpfp,
false);
684 expected_pool_size += 2;
685 BOOST_CHECK_MESSAGE(submit_cpfp.m_state.IsValid(),
686 "Package validation unexpectedly failed: " << submit_cpfp.m_state.GetRejectReason());
688 auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash());
689 auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
690 BOOST_CHECK(it_parent != submit_cpfp.m_tx_results.end());
692 BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
693 BOOST_CHECK(it_child != submit_cpfp.m_tx_results.end());
701 const CFeeRate expected_feerate(coinbase_value - child_value,
703 BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
704 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
705 std::vector<uint256> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()});
706 BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
707 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
715 auto mtx_parent_cheap = CreateValidMempoolTransaction(m_coinbase_txns[1], 0,
718 coinbase_value,
false);
720 package_still_too_low.push_back(tx_parent_cheap);
722 auto mtx_child_cheap = CreateValidMempoolTransaction(tx_parent_cheap, 0,
725 coinbase_value - 200,
false);
727 package_still_too_low.push_back(tx_child_cheap);
733 package_still_too_low,
false);
734 BOOST_CHECK_MESSAGE(submit_package_too_low.m_state.IsInvalid(),
"Package validation unexpectedly succeeded");
736 BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(),
"package-fee-too-low");
740 const CFeeRate expected_feerate(200,
751 package_still_too_low,
false);
752 expected_pool_size += 2;
753 BOOST_CHECK_MESSAGE(submit_prioritised_package.m_state.IsValid(),
754 "Package validation unexpectedly failed" << submit_prioritised_package.m_state.GetRejectReason());
757 BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
758 auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
759 auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
760 BOOST_CHECK(it_parent != submit_prioritised_package.m_tx_results.end());
762 BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
763 BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
764 BOOST_CHECK(it_child != submit_prioritised_package.m_tx_results.end());
766 BOOST_CHECK(it_child->second.m_base_fees.value() == 200);
767 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
768 std::vector<uint256> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
769 BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
770 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
780 auto mtx_parent_rich = CreateValidMempoolTransaction(m_coinbase_txns[2], 0,
783 coinbase_value - high_parent_fee,
false);
785 package_rich_parent.push_back(tx_parent_rich);
787 auto mtx_child_poor = CreateValidMempoolTransaction(tx_parent_rich, 0,
790 coinbase_value - high_parent_fee,
false);
792 package_rich_parent.push_back(tx_child_poor);
798 package_rich_parent,
false);
799 expected_pool_size += 1;
800 BOOST_CHECK_MESSAGE(submit_rich_parent.m_state.IsInvalid(),
"Package validation unexpectedly succeeded");
804 BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(),
"package-fee-too-low");
806 auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
807 BOOST_CHECK(it_parent != submit_rich_parent.m_tx_results.end());
809 BOOST_CHECK(it_parent->second.m_state.GetRejectReason() ==
"");
810 BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
811 strprintf(
"rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
int64_t CAmount
Amount in satoshis (Can be negative)
static constexpr CAmount COIN
The amount of satoshis in one BTC.
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
CAmount GetFeePerK() const
Return the fee in satoshis for a vsize of 1000 vbytes.
An encapsulated private key.
void MakeNewKey(bool fCompressed)
Generate a new private key using a cryptographic PRNG.
CPubKey GetPubKey() const
Compute the public key from a private key.
An outpoint - a combination of a transaction hash and an index n into its vout.
Serialized script, used inside transaction inputs and outputs.
An input of a transaction.
An output of a transaction.
static GenTxid Wtxid(const uint256 &hash)
static GenTxid Txid(const uint256 &hash)
std::string GetRejectReason() const
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_WITNESS_MUTATED
Transaction might have a witness prior to SegWit activation, or witness may have been malleated (whic...
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
BOOST_AUTO_TEST_SUITE(cuckoocache_tests)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
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...
bool CheckPackage(const Package &txns, PackageValidationState &state)
Context-free package policy checks:
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
static constexpr uint32_t MAX_PACKAGE_COUNT
Default maximum number of transactions in a package.
static constexpr uint32_t MAX_PACKAGE_SIZE
Default maximum total virtual size of transactions in a package in KvB.
@ PCKG_POLICY
The package itself is invalid (e.g. too many transactions).
@ PCKG_TX
At least one tx is invalid.
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
Compute the virtual transaction size (weight reinterpreted as bytes).
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
std::vector< unsigned char > ToByteVector(const T &in)
static constexpr CAmount CENT
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< std::vector< unsigned char > > stack
Validation result for a single transaction mempool acceptance.
const ResultType m_result_type
Result type.
@ DIFFERENT_WITNESS
Valid, transaction was already in the mempool.
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
std::unique_ptr< CTxMemPool > mempool
std::unique_ptr< ChainstateManager > chainman
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
static uint256 InsecureRand256()
BOOST_FIXTURE_TEST_CASE(package_sanitization_tests, TestChain100Setup)
CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept)
Validate (and maybe submit) a package to the mempool.