17 #include <boost/test/unit_test.hpp>
28 mtx.
vin.resize(num_inputs);
29 mtx.
vout.resize(num_outputs);
31 for (
size_t i{0}; i < num_inputs; ++i) {
33 mtx.
vin[i].prevout.n = 0;
34 mtx.
vin[i].scriptSig = random_script;
36 for (
size_t o{0}; o < num_outputs; ++o) {
38 mtx.
vout[o].scriptPubKey = random_script;
60 size_t total_weight{0};
62 package_too_large.push_back(large_ptx);
63 total_weight += size_large;
72 Package package_duplicate_txids_empty;
73 for (
auto i{0}; i < 3; ++i) {
87 tx_zero_1.
vin.emplace_back(same_prevout);
88 tx_zero_2.
vin.emplace_back(same_prevout);
105 dup_tx.
vin.emplace_back(rand_prevout);
106 dup_tx.
vin.emplace_back(rand_prevout);
121 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
123 parent_locking_script,
129 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
131 child_locking_script,
134 Package package_parent_child{tx_parent, tx_child};
137 BOOST_ERROR(err_parent_child.value());
139 auto it_parent = result_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
140 auto it_child = result_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
143 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
144 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
148 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
153 Package package_single_giant{giant_ptx};
156 BOOST_ERROR(err_single_large.value());
159 BOOST_CHECK_EQUAL(result_single_large.m_state.GetRejectReason(),
"transaction failed");
160 auto it_giant_tx = result_single_large.m_tx_results.find(giant_ptx->GetWitnessHash());
178 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0, 0, coinbaseKey, spk,
182 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0, 101, placeholder_key, spk2,
199 for (
int i{0}; i < 24; ++i) {
200 auto parent =
MakeTransactionRef(CreateValidMempoolTransaction(m_coinbase_txns[i + 1],
201 0, 0, coinbaseKey, spk,
CAmount(48 *
COIN),
false));
202 package.emplace_back(parent);
203 child.
vin.emplace_back(
COutPoint(parent->GetHash(), 0));
205 child.
vout.emplace_back(47 *
COIN, spk2);
212 Shuffle(package.begin(), package.end(), rng);
220 package.erase(package.begin());
224 package.insert(package.begin(), m_coinbase_txns[0]);
231 mtx_parent.
vin.emplace_back(
COutPoint(m_coinbase_txns[0]->GetHash(), 0));
232 mtx_parent.
vout.emplace_back(20 *
COIN, spk);
233 mtx_parent.
vout.emplace_back(20 *
COIN, spk2);
237 mtx_parent_also_child.
vin.emplace_back(
COutPoint(tx_parent->GetHash(), 0));
238 mtx_parent_also_child.
vout.emplace_back(20 *
COIN, spk);
242 mtx_child.
vin.emplace_back(
COutPoint(tx_parent->GetHash(), 1));
243 mtx_child.
vin.emplace_back(
COutPoint(tx_parent_also_child->GetHash(), 0));
244 mtx_child.
vout.emplace_back(39 *
COIN, spk);
270 for (
size_t i{0}; i < 10; ++i) {
271 auto mtx = CreateValidMempoolTransaction(m_coinbase_txns[i + 25], 0,
273 parent_locking_script,
278 package_unrelated,
false, {});
280 BOOST_CHECK(result_unrelated_submit.m_state.IsInvalid());
282 BOOST_CHECK_EQUAL(result_unrelated_submit.m_state.GetRejectReason(),
"package-not-child-with-parents");
288 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
290 parent_locking_script,
293 package_parent_child.push_back(tx_parent);
294 package_3gen.push_back(tx_parent);
298 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
300 child_locking_script,
303 package_parent_child.push_back(tx_child);
304 package_3gen.push_back(tx_child);
308 auto mtx_grandchild = CreateValidMempoolTransaction(tx_child, 0,
310 grandchild_locking_script,
313 package_3gen.push_back(tx_grandchild);
318 package_3gen,
false, {});
319 BOOST_CHECK(result_3gen_submit.m_state.IsInvalid());
321 BOOST_CHECK_EQUAL(result_3gen_submit.m_state.GetRejectReason(),
"package-not-child-with-parents");
329 bad_witness.
stack.emplace_back(1);
331 mtx_parent_invalid.
vin[0].scriptWitness = bad_witness;
333 Package package_invalid_parent{tx_parent_invalid, tx_child};
335 package_invalid_parent,
false, {});
337 BOOST_ERROR(err_parent_invalid.value());
339 auto it_parent = result_quit_early.m_tx_results.find(tx_parent_invalid->GetWitnessHash());
340 auto it_child = result_quit_early.m_tx_results.find(tx_child->GetWitnessHash());
342 BOOST_CHECK_EQUAL(it_parent->second.m_state.GetRejectReason(),
"bad-witness-nonstandard");
344 BOOST_CHECK_EQUAL(it_child->second.m_state.GetRejectReason(),
"bad-txns-inputs-missingorspent");
350 mtx_child.vin.emplace_back(
COutPoint(package_unrelated[0]->GetHash(), 0));
351 Package package_missing_parent;
352 package_missing_parent.push_back(tx_parent);
356 package_missing_parent,
false, {});
357 BOOST_CHECK(result_missing_parent.m_state.IsInvalid());
359 BOOST_CHECK_EQUAL(result_missing_parent.m_state.GetRejectReason(),
"package-not-child-with-unconfirmed-parents");
366 package_parent_child,
false, {});
367 expected_pool_size += 2;
368 BOOST_CHECK_MESSAGE(submit_parent_child.m_state.IsValid(),
369 "Package validation unexpectedly failed: " << submit_parent_child.m_state.GetRejectReason());
370 BOOST_CHECK_EQUAL(submit_parent_child.m_tx_results.size(), package_parent_child.size());
371 auto it_parent = submit_parent_child.m_tx_results.find(tx_parent->GetWitnessHash());
372 auto it_child = submit_parent_child.m_tx_results.find(tx_child->GetWitnessHash());
373 BOOST_CHECK(it_parent != submit_parent_child.m_tx_results.end());
376 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
377 BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
380 BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
388 package_parent_child,
false, {});
390 BOOST_ERROR(err_deduped.value());
392 auto it_parent_deduped = submit_deduped.m_tx_results.find(tx_parent->GetWitnessHash());
393 auto it_child_deduped = submit_deduped.m_tx_results.find(tx_child->GetWitnessHash());
415 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
423 witness1.
stack.emplace_back(1);
424 witness1.
stack.emplace_back(witnessScript.
begin(), witnessScript.
end());
427 witness2.
stack.emplace_back(2);
428 witness2.
stack.emplace_back(witnessScript.
begin(), witnessScript.
end());
434 mtx_child1.
vin.resize(1);
435 mtx_child1.
vin[0].prevout.hash = ptx_parent->GetHash();
436 mtx_child1.
vin[0].prevout.n = 0;
438 mtx_child1.
vin[0].scriptWitness = witness1;
439 mtx_child1.
vout.resize(1);
441 mtx_child1.
vout[0].scriptPubKey = child_locking_script;
444 mtx_child2.
vin[0].scriptWitness = witness2;
452 BOOST_CHECK(ptx_child1->GetWitnessHash() != ptx_child2->GetWitnessHash());
457 Package package_parent_child1{ptx_parent, ptx_child1};
459 package_parent_child1,
false, {});
461 BOOST_ERROR(err_witness1.value());
465 Package package_parent_child2{ptx_parent, ptx_child2};
467 package_parent_child2,
false, {});
469 BOOST_ERROR(err_witness2.value());
471 auto it_parent2_deduped = submit_witness2.m_tx_results.find(ptx_parent->GetWitnessHash());
472 auto it_child2 = submit_witness2.m_tx_results.find(ptx_child2->GetWitnessHash());
475 BOOST_CHECK_EQUAL(ptx_child1->GetWitnessHash(), it_child2->second.m_other_wtxid.value());
481 package_parent_child1,
false, {});
483 BOOST_ERROR(err_segwit_dedup.value());
485 auto it_parent_dup = submit_segwit_dedup.m_tx_results.find(ptx_parent->GetWitnessHash());
486 auto it_child_dup = submit_segwit_dedup.m_tx_results.find(ptx_child1->GetWitnessHash());
501 auto mtx_grandchild = CreateValidMempoolTransaction(ptx_child2, 0,
503 grandchild_locking_script,
509 Package package_child2_grandchild{ptx_child2, ptx_grandchild};
511 package_child2_grandchild,
false, {});
513 BOOST_ERROR(err_spend_ignored.value());
515 auto it_child2_ignored = submit_spend_ignored.m_tx_results.find(ptx_child2->GetWitnessHash());
516 auto it_grandchild = submit_spend_ignored.m_tx_results.find(ptx_grandchild->GetWitnessHash());
530 acs_witness.
stack.emplace_back(acs_script.
begin(), acs_script.
end());
533 auto mtx_parent1 = CreateValidMempoolTransaction(m_coinbase_txns[1], 0,
538 package_mixed.push_back(ptx_parent1);
544 parent2_witness1.
stack.emplace_back(1);
545 parent2_witness1.
stack.emplace_back(grandparent2_script.
begin(), grandparent2_script.
end());
547 parent2_witness2.
stack.emplace_back(2);
548 parent2_witness2.
stack.emplace_back(grandparent2_script.
begin(), grandparent2_script.
end());
551 auto mtx_grandparent2 = CreateValidMempoolTransaction(m_coinbase_txns[2], 0,
559 mtx_parent2_v1.
vin.resize(1);
560 mtx_parent2_v1.
vin[0].prevout.hash = ptx_grandparent2->GetHash();
561 mtx_parent2_v1.
vin[0].prevout.n = 0;
563 mtx_parent2_v1.
vin[0].scriptWitness = parent2_witness1;
564 mtx_parent2_v1.
vout.resize(1);
566 mtx_parent2_v1.
vout[0].scriptPubKey = acs_spk;
569 mtx_parent2_v2.
vin[0].scriptWitness = parent2_witness2;
576 package_mixed.push_back(ptx_parent2_v1);
579 auto mtx_parent3 = CreateValidMempoolTransaction(m_coinbase_txns[3], 0,
584 package_mixed.push_back(ptx_parent3);
593 mtx_mixed_child.
vin.emplace_back(
COutPoint(ptx_parent1->GetHash(), 0));
594 mtx_mixed_child.
vin.emplace_back(
COutPoint(ptx_parent2_v1->GetHash(), 0));
595 mtx_mixed_child.
vin.emplace_back(
COutPoint(ptx_parent3->GetHash(), 0));
596 mtx_mixed_child.
vin[0].scriptWitness = acs_witness;
597 mtx_mixed_child.
vin[1].scriptWitness = acs_witness;
598 mtx_mixed_child.
vin[2].scriptWitness = acs_witness;
599 mtx_mixed_child.
vout.emplace_back((48 + 49 + 50 - 1) *
COIN, mixed_child_spk);
601 package_mixed.push_back(ptx_mixed_child);
611 BOOST_ERROR(err_mixed.value());
613 auto it_parent1 = mixed_result.m_tx_results.find(ptx_parent1->GetWitnessHash());
614 auto it_parent2 = mixed_result.m_tx_results.find(ptx_parent2_v1->GetWitnessHash());
615 auto it_parent3 = mixed_result.m_tx_results.find(ptx_parent3->GetWitnessHash());
616 auto it_child = mixed_result.m_tx_results.find(ptx_mixed_child->GetWitnessHash());
622 BOOST_CHECK_EQUAL(ptx_parent2_v2->GetWitnessHash(), it_parent2->second.m_other_wtxid.value());
626 BOOST_CHECK(it_parent3->second.m_effective_feerate.value() == expected_feerate);
627 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
628 std::vector<Wtxid> expected_wtxids({ptx_parent3->GetWitnessHash(), ptx_mixed_child->GetWitnessHash()});
629 BOOST_CHECK(it_parent3->second.m_wtxids_fee_calculations.value() == expected_wtxids);
630 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
652 auto mtx_parent = CreateValidMempoolTransaction(m_coinbase_txns[0], 0,
655 parent_value,
false);
657 package_cpfp.push_back(tx_parent);
659 auto mtx_child = CreateValidMempoolTransaction(tx_parent, 0,
664 package_cpfp.push_back(tx_child);
669 m_node.
mempool->PrioritiseTransaction(tx_parent->GetHash(), child_value - coinbase_value);
673 package_cpfp,
false, {});
675 BOOST_ERROR(err_cpfp_deprio.value());
678 BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetResult(),
680 BOOST_CHECK_EQUAL(submit_cpfp_deprio.m_tx_results.find(tx_child->GetWitnessHash())->second.m_state.GetResult(),
682 BOOST_CHECK(submit_cpfp_deprio.m_tx_results.find(tx_parent->GetWitnessHash())->second.m_state.GetRejectReason() ==
"min relay fee not met");
695 package_cpfp,
false, {});
697 BOOST_ERROR(err_cpfp.value());
699 auto it_parent = submit_cpfp.m_tx_results.find(tx_parent->GetWitnessHash());
700 auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
702 BOOST_CHECK(it_parent->second.m_base_fees.value() == coinbase_value - parent_value);
706 const CFeeRate expected_feerate(coinbase_value - child_value,
708 BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
709 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
710 std::vector<Wtxid> expected_wtxids({tx_parent->GetWitnessHash(), tx_child->GetWitnessHash()});
711 BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
712 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
715 expected_pool_size += 2;
725 auto mtx_parent_cheap = CreateValidMempoolTransaction(m_coinbase_txns[1], 0,
728 coinbase_value - parent_fee,
false);
730 package_still_too_low.push_back(tx_parent_cheap);
734 auto mtx_child_cheap = CreateValidMempoolTransaction(tx_parent_cheap, 0,
737 coinbase_value - parent_fee - child_fee,
false);
739 package_still_too_low.push_back(tx_child_cheap);
747 package_still_too_low,
false, {});
749 BOOST_ERROR(err_package_too_low.value());
752 BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_state.GetResult(),
754 BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_parent_cheap->GetWitnessHash()).m_effective_feerate.value() ==
757 BOOST_CHECK_EQUAL(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_state.GetResult(),
759 BOOST_CHECK(submit_package_too_low.m_tx_results.at(tx_child_cheap->GetWitnessHash()).m_effective_feerate.value() ==
763 BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(),
"transaction failed");
773 package_still_too_low,
false, {});
775 BOOST_ERROR(err_prioritised.value());
777 const CFeeRate expected_feerate(1 *
COIN + parent_fee + child_fee,
779 BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
780 auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
781 auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
783 BOOST_CHECK(it_parent->second.m_base_fees.value() == parent_fee);
784 BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
786 BOOST_CHECK(it_child->second.m_base_fees.value() == child_fee);
787 BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
788 std::vector<Wtxid> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
789 BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
790 BOOST_CHECK(it_child->second.m_wtxids_fee_calculations.value() == expected_wtxids);
792 expected_pool_size += 2;
803 auto mtx_parent_rich = CreateValidMempoolTransaction(m_coinbase_txns[2], 0,
806 coinbase_value - high_parent_fee,
false);
808 package_rich_parent.push_back(tx_parent_rich);
810 auto mtx_child_poor = CreateValidMempoolTransaction(tx_parent_rich, 0,
813 coinbase_value - high_parent_fee,
false);
815 package_rich_parent.push_back(tx_child_poor);
821 package_rich_parent,
false, {});
823 BOOST_ERROR(err_rich_parent.value());
827 BOOST_CHECK_EQUAL(submit_rich_parent.m_state.GetRejectReason(),
"transaction failed");
829 auto it_parent = submit_rich_parent.m_tx_results.find(tx_parent_rich->GetWitnessHash());
830 auto it_child = submit_rich_parent.m_tx_results.find(tx_child_poor->GetWitnessHash());
833 BOOST_CHECK(it_parent->second.m_state.GetRejectReason() ==
"");
834 BOOST_CHECK_MESSAGE(it_parent->second.m_base_fees.value() == high_parent_fee,
835 strprintf(
"rich parent: expected fee %s, got %s", high_parent_fee, it_parent->second.m_base_fees.value()));
839 BOOST_CHECK(it_child->second.m_state.GetRejectReason() ==
"min relay fee not met");
841 expected_pool_size += 1;
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
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.
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.
std::string GetRejectReason() const
static transaction_identifier FromUint256(const uint256 &id)
static int32_t GetTransactionWeight(const CTransaction &tx)
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_MEMPOOL_POLICY
violated mempool's fee/size/descendant/RBF/etc limits
@ TX_WITNESS_MUTATED
Transaction might have a witness prior to SegWit activation, or witness may have been malleated (whic...
@ TX_RECONSIDERABLE
fails some policy, but might be acceptable if submitted in a (different) package
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()
CKey GenerateRandomKey(bool compressed) noexcept
#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 IsConsistentPackage(const Package &txns)
Checks that these transactions don't conflict, i.e., spend the same prevout.
bool IsWellFormedPackage(const Package &txns, PackageValidationState &state, bool require_sorted)
Context-free package policy checks:
bool IsChildWithParentsTree(const Package &package)
Context-free check that a package IsChildWithParents() and none of the parents depend on each other (...
bool IsTopoSortedPackage(const Package &txns, std::unordered_set< uint256, SaltedTxidHasher > &later_txids)
IsTopoSortedPackage where a set of txids has been pre-populated.
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
static constexpr uint32_t MAX_PACKAGE_WEIGHT
Default maximum total weight of transactions in a package in weight to allow for context-less checks.
static constexpr uint32_t MAX_PACKAGE_COUNT
Default maximum number of transactions in a package.
@ 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 constexpr unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT_KVB
Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors.
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
A mutable version of CTransaction.
std::vector< CTxOut > vout
std::vector< std::vector< unsigned char > > stack
Validation result for a transaction evaluated by MemPoolAccept (single or package).
const ResultType m_result_type
Result type.
@ DIFFERENT_WITNESS
Valid, transaction was already in the mempool.
@ INVALID
Fully validated, valid.
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()
static const CScript P2WSH_OP_TRUE
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.
static const CAmount low_fee_amt
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, const std::optional< CFeeRate > &client_maxfeerate)
Validate (and maybe submit) a package to the mempool.