mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-31 10:56:03 +02:00
[test] package cpfp bumps parents <mempoolminfee but >=minrelaytxfee
This commit is contained in:
@@ -16,6 +16,9 @@
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(txpackage_tests)
|
||||
// A fee amount that is above 1sat/vB but below 5sat/vB for most transactions created within these
|
||||
// unit tests.
|
||||
static const CAmount low_fee_amt{200};
|
||||
|
||||
// Create placeholder transactions that have no meaning.
|
||||
inline CTransactionRef create_placeholder_tx(size_t num_inputs, size_t num_outputs)
|
||||
@@ -373,6 +376,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
|
||||
{
|
||||
// Mine blocks to mature coinbases.
|
||||
mineBlocks(5);
|
||||
MockMempoolMinFee(CFeeRate(5000));
|
||||
LOCK(cs_main);
|
||||
|
||||
// Transactions with a same-txid-different-witness transaction in the mempool should be ignored,
|
||||
@@ -560,13 +564,15 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
|
||||
BOOST_CHECK(parent2_v2_result.m_result_type == MempoolAcceptResult::ResultType::VALID);
|
||||
package_mixed.push_back(ptx_parent2_v1);
|
||||
|
||||
// parent3 will be a new transaction. Put 0 fees on it to make it invalid on its own.
|
||||
// parent3 will be a new transaction. Put a low feerate to make it invalid on its own.
|
||||
auto mtx_parent3 = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[3], /*input_vout=*/0,
|
||||
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
|
||||
/*output_destination=*/acs_spk,
|
||||
/*output_amount=*/CAmount(50 * COIN), /*submit=*/false);
|
||||
/*output_amount=*/CAmount(50 * COIN - low_fee_amt), /*submit=*/false);
|
||||
CTransactionRef ptx_parent3 = MakeTransactionRef(mtx_parent3);
|
||||
package_mixed.push_back(ptx_parent3);
|
||||
BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*ptx_parent3)) > low_fee_amt);
|
||||
BOOST_CHECK(m_node.mempool->m_min_relay_feerate.GetFee(GetVirtualTransactionSize(*ptx_parent3)) <= low_fee_amt);
|
||||
|
||||
// child spends parent1, parent2, and parent3
|
||||
CKey mixed_grandchild_key;
|
||||
@@ -627,6 +633,7 @@ BOOST_FIXTURE_TEST_CASE(package_witness_swap_tests, TestChain100Setup)
|
||||
BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
{
|
||||
mineBlocks(5);
|
||||
MockMempoolMinFee(CFeeRate(5000));
|
||||
LOCK(::cs_main);
|
||||
size_t expected_pool_size = m_node.mempool->size();
|
||||
CKey child_key;
|
||||
@@ -636,9 +643,9 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
grandchild_key.MakeNewKey(true);
|
||||
CScript child_spk = GetScriptForDestination(WitnessV0KeyHash(grandchild_key.GetPubKey()));
|
||||
|
||||
// zero-fee parent and high-fee child package
|
||||
// low-fee parent and high-fee child package
|
||||
const CAmount coinbase_value{50 * COIN};
|
||||
const CAmount parent_value{coinbase_value - 0};
|
||||
const CAmount parent_value{coinbase_value - low_fee_amt};
|
||||
const CAmount child_value{parent_value - COIN};
|
||||
|
||||
Package package_cpfp;
|
||||
@@ -657,9 +664,9 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
package_cpfp.push_back(tx_child);
|
||||
|
||||
// Package feerate is calculated using modified fees, and prioritisetransaction accepts negative
|
||||
// fee deltas. This should be taken into account. De-prioritise the parent transaction by -1BTC,
|
||||
// bringing the package feerate to 0.
|
||||
m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), -1 * COIN);
|
||||
// fee deltas. This should be taken into account. De-prioritise the parent transaction
|
||||
// to bring the package feerate to 0.
|
||||
m_node.mempool->PrioritiseTransaction(tx_parent->GetHash(), child_value - coinbase_value);
|
||||
{
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
const auto submit_cpfp_deprio = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
|
||||
@@ -675,8 +682,8 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
// Clear the prioritisation of the parent transaction.
|
||||
WITH_LOCK(m_node.mempool->cs, m_node.mempool->ClearPrioritisation(tx_parent->GetHash()));
|
||||
|
||||
// Package CPFP: Even though the parent pays 0 absolute fees, the child pays 1 BTC which is
|
||||
// enough for the package feerate to meet the threshold.
|
||||
// Package CPFP: Even though the parent's feerate is below the mempool minimum feerate, the
|
||||
// child pays enough for the package feerate to meet the threshold.
|
||||
{
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
const auto submit_cpfp = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
|
||||
@@ -689,7 +696,7 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
auto it_child = submit_cpfp.m_tx_results.find(tx_child->GetWitnessHash());
|
||||
BOOST_CHECK(it_parent != submit_cpfp.m_tx_results.end());
|
||||
BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
|
||||
BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
|
||||
BOOST_CHECK(it_parent->second.m_base_fees.value() == coinbase_value - parent_value);
|
||||
BOOST_CHECK(it_child != submit_cpfp.m_tx_results.end());
|
||||
BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
|
||||
BOOST_CHECK(it_child->second.m_base_fees.value() == COIN);
|
||||
@@ -709,22 +716,28 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
}
|
||||
|
||||
// Just because we allow low-fee parents doesn't mean we allow low-feerate packages.
|
||||
// This package just pays 200 satoshis total. This would be enough to pay for the child alone,
|
||||
// but isn't enough for the entire package to meet the 1sat/vbyte minimum.
|
||||
// The mempool minimum feerate is 5sat/vB, but this package just pays 800 satoshis total.
|
||||
// The child fees would be able to pay for itself, but isn't enough for the entire package.
|
||||
Package package_still_too_low;
|
||||
const CAmount parent_fee{200};
|
||||
const CAmount child_fee{600};
|
||||
auto mtx_parent_cheap = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
|
||||
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
|
||||
/*output_destination=*/parent_spk,
|
||||
/*output_amount=*/coinbase_value, /*submit=*/false);
|
||||
/*output_amount=*/coinbase_value - parent_fee, /*submit=*/false);
|
||||
CTransactionRef tx_parent_cheap = MakeTransactionRef(mtx_parent_cheap);
|
||||
package_still_too_low.push_back(tx_parent_cheap);
|
||||
BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) > parent_fee);
|
||||
BOOST_CHECK(m_node.mempool->m_min_relay_feerate.GetFee(GetVirtualTransactionSize(*tx_parent_cheap)) <= parent_fee);
|
||||
|
||||
auto mtx_child_cheap = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent_cheap, /*input_vout=*/0,
|
||||
/*input_height=*/101, /*input_signing_key=*/child_key,
|
||||
/*output_destination=*/child_spk,
|
||||
/*output_amount=*/coinbase_value - 200, /*submit=*/false);
|
||||
/*output_amount=*/coinbase_value - parent_fee - child_fee, /*submit=*/false);
|
||||
CTransactionRef tx_child_cheap = MakeTransactionRef(mtx_child_cheap);
|
||||
package_still_too_low.push_back(tx_child_cheap);
|
||||
BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_child_cheap)) <= child_fee);
|
||||
BOOST_CHECK(m_node.mempool->GetMinFee().GetFee(GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap)) > parent_fee + child_fee);
|
||||
|
||||
// Cheap package should fail with package-fee-too-low.
|
||||
{
|
||||
@@ -735,11 +748,6 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetResult(), PackageValidationResult::PCKG_POLICY);
|
||||
BOOST_CHECK_EQUAL(submit_package_too_low.m_state.GetRejectReason(), "package-fee-too-low");
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
const CFeeRate child_feerate(200, GetVirtualTransactionSize(*tx_child_cheap));
|
||||
BOOST_CHECK(child_feerate.GetFeePerK() > 1000);
|
||||
const CFeeRate expected_feerate(200,
|
||||
GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
|
||||
BOOST_CHECK(expected_feerate.GetFeePerK() < 1000);
|
||||
}
|
||||
|
||||
// Package feerate includes the modified fees of the transactions.
|
||||
@@ -752,18 +760,18 @@ BOOST_FIXTURE_TEST_CASE(package_cpfp_tests, TestChain100Setup)
|
||||
expected_pool_size += 2;
|
||||
BOOST_CHECK_MESSAGE(submit_prioritised_package.m_state.IsValid(),
|
||||
"Package validation unexpectedly failed" << submit_prioritised_package.m_state.GetRejectReason());
|
||||
const CFeeRate expected_feerate(1 * COIN + 200,
|
||||
const CFeeRate expected_feerate(1 * COIN + parent_fee + child_fee,
|
||||
GetVirtualTransactionSize(*tx_parent_cheap) + GetVirtualTransactionSize(*tx_child_cheap));
|
||||
BOOST_CHECK_EQUAL(submit_prioritised_package.m_tx_results.size(), package_still_too_low.size());
|
||||
auto it_parent = submit_prioritised_package.m_tx_results.find(tx_parent_cheap->GetWitnessHash());
|
||||
auto it_child = submit_prioritised_package.m_tx_results.find(tx_child_cheap->GetWitnessHash());
|
||||
BOOST_CHECK(it_parent != submit_prioritised_package.m_tx_results.end());
|
||||
BOOST_CHECK(it_parent->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
|
||||
BOOST_CHECK(it_parent->second.m_base_fees.value() == 0);
|
||||
BOOST_CHECK(it_parent->second.m_base_fees.value() == parent_fee);
|
||||
BOOST_CHECK(it_parent->second.m_effective_feerate.value() == expected_feerate);
|
||||
BOOST_CHECK(it_child != submit_prioritised_package.m_tx_results.end());
|
||||
BOOST_CHECK(it_child->second.m_result_type == MempoolAcceptResult::ResultType::VALID);
|
||||
BOOST_CHECK(it_child->second.m_base_fees.value() == 200);
|
||||
BOOST_CHECK(it_child->second.m_base_fees.value() == child_fee);
|
||||
BOOST_CHECK(it_child->second.m_effective_feerate.value() == expected_feerate);
|
||||
std::vector<uint256> expected_wtxids({tx_parent_cheap->GetWitnessHash(), tx_child_cheap->GetWitnessHash()});
|
||||
BOOST_CHECK(it_parent->second.m_wtxids_fee_calculations.value() == expected_wtxids);
|
||||
|
||||
Reference in New Issue
Block a user