mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-03 09:43:55 +02:00
Merge bitcoin/bitcoin#31096: Package validation: accept packages of size 1
32fc59796frpc: Allow single transaction through submitpackage (glozow) Pull request description: There's no particular reason to restrict single transaction submissions with submitpackage. This change relaxes the RPC checks as enables the `AcceptPackage` flow to accept packages of a single transaction. Resolves #31085 ACKs for top commit: naumenkogs: ACK32fc59796fachow101: ACK32fc59796fglozow: ACK32fc59796fTree-SHA512: ffed353bfdca610ffcfd53b40b76da05ffc26df6bac4b0421492e067bede930380e03399d2e2d1d17f0e88fb91cd8eb376e3aabebbabcc724590bf068d09807c
This commit is contained in:
@@ -283,6 +283,8 @@ BOOST_AUTO_TEST_CASE(noncontextual_package_tests)
|
||||
BOOST_CHECK(GetPackageHash({tx_parent}) != GetPackageHash({tx_child}));
|
||||
BOOST_CHECK(GetPackageHash({tx_child, tx_child}) != GetPackageHash({tx_child}));
|
||||
BOOST_CHECK(GetPackageHash({tx_child, tx_parent}) != GetPackageHash({tx_child, tx_child}));
|
||||
BOOST_CHECK(!IsChildWithParents({}));
|
||||
BOOST_CHECK(!IsChildWithParentsTree({}));
|
||||
}
|
||||
|
||||
// 24 Parents and 1 Child
|
||||
@@ -492,6 +494,97 @@ BOOST_AUTO_TEST_CASE(package_submission_tests)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests for packages containing a single transaction
|
||||
BOOST_AUTO_TEST_CASE(package_single_tx)
|
||||
{
|
||||
// Mine blocks to mature coinbases.
|
||||
mineBlocks(3);
|
||||
LOCK(cs_main);
|
||||
auto expected_pool_size{m_node.mempool->size()};
|
||||
|
||||
const CAmount high_fee{1000};
|
||||
|
||||
// No unconfirmed parents
|
||||
CKey single_key = GenerateRandomKey();
|
||||
CScript single_locking_script = GetScriptForDestination(PKHash(single_key.GetPubKey()));
|
||||
auto mtx_single = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
|
||||
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
|
||||
/*output_destination=*/single_locking_script,
|
||||
/*output_amount=*/CAmount(49 * COIN), /*submit=*/false);
|
||||
CTransactionRef tx_single = MakeTransactionRef(mtx_single);
|
||||
Package package_tx_single{tx_single};
|
||||
const auto result_single_tx = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
|
||||
package_tx_single, /*test_accept=*/false, /*client_maxfeerate=*/{});
|
||||
expected_pool_size += 1;
|
||||
BOOST_CHECK_MESSAGE(result_single_tx.m_state.IsValid(),
|
||||
"Package validation unexpectedly failed: " << result_single_tx.m_state.ToString());
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
|
||||
// Parent and Child. Both submitted by themselves through the ProcessNewPackage interface.
|
||||
CKey parent_key = GenerateRandomKey();
|
||||
CScript parent_locking_script = GetScriptForDestination(WitnessV0KeyHash(parent_key.GetPubKey()));
|
||||
auto mtx_parent = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[1], /*input_vout=*/0,
|
||||
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
|
||||
/*output_destination=*/parent_locking_script,
|
||||
/*output_amount=*/CAmount(50 * COIN) - high_fee, /*submit=*/false);
|
||||
CTransactionRef tx_parent = MakeTransactionRef(mtx_parent);
|
||||
Package package_just_parent{tx_parent};
|
||||
const auto result_just_parent = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_just_parent, /*test_accept=*/false, /*client_maxfeerate=*/{});
|
||||
if (auto err_parent_child{CheckPackageMempoolAcceptResult(package_just_parent, result_just_parent, /*expect_valid=*/true, nullptr)}) {
|
||||
BOOST_ERROR(err_parent_child.value());
|
||||
} else {
|
||||
auto it_parent = result_just_parent.m_tx_results.find(tx_parent->GetWitnessHash());
|
||||
BOOST_CHECK_MESSAGE(it_parent->second.m_state.IsValid(), it_parent->second.m_state.ToString());
|
||||
BOOST_CHECK(it_parent->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_parent)) == high_fee);
|
||||
BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().size(), 1);
|
||||
BOOST_CHECK_EQUAL(it_parent->second.m_wtxids_fee_calculations.value().front(), tx_parent->GetWitnessHash());
|
||||
}
|
||||
expected_pool_size += 1;
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
|
||||
CKey child_key = GenerateRandomKey();
|
||||
CScript child_locking_script = GetScriptForDestination(WitnessV0KeyHash(child_key.GetPubKey()));
|
||||
auto mtx_child = CreateValidMempoolTransaction(/*input_transaction=*/tx_parent, /*input_vout=*/0,
|
||||
/*input_height=*/101, /*input_signing_key=*/parent_key,
|
||||
/*output_destination=*/child_locking_script,
|
||||
/*output_amount=*/CAmount(50 * COIN) - 2 * high_fee, /*submit=*/false);
|
||||
CTransactionRef tx_child = MakeTransactionRef(mtx_child);
|
||||
Package package_just_child{tx_child};
|
||||
const auto result_just_child = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package_just_child, /*test_accept=*/false, /*client_maxfeerate=*/{});
|
||||
if (auto err_parent_child{CheckPackageMempoolAcceptResult(package_just_child, result_just_child, /*expect_valid=*/true, nullptr)}) {
|
||||
BOOST_ERROR(err_parent_child.value());
|
||||
} else {
|
||||
auto it_child = result_just_child.m_tx_results.find(tx_child->GetWitnessHash());
|
||||
BOOST_CHECK_MESSAGE(it_child->second.m_state.IsValid(), it_child->second.m_state.ToString());
|
||||
BOOST_CHECK(it_child->second.m_effective_feerate.value().GetFee(GetVirtualTransactionSize(*tx_child)) == high_fee);
|
||||
BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().size(), 1);
|
||||
BOOST_CHECK_EQUAL(it_child->second.m_wtxids_fee_calculations.value().front(), tx_child->GetWitnessHash());
|
||||
}
|
||||
expected_pool_size += 1;
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
|
||||
// Too-low fee to RBF tx_single
|
||||
auto mtx_single_low_fee = CreateValidMempoolTransaction(/*input_transaction=*/m_coinbase_txns[0], /*input_vout=*/0,
|
||||
/*input_height=*/0, /*input_signing_key=*/coinbaseKey,
|
||||
/*output_destination=*/single_locking_script,
|
||||
/*output_amount=*/CAmount(49 * COIN - 1), /*submit=*/false);
|
||||
CTransactionRef tx_single_low_fee = MakeTransactionRef(mtx_single_low_fee);
|
||||
Package package_tx_single_low_fee{tx_single_low_fee};
|
||||
const auto result_single_tx_low_fee = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool,
|
||||
package_tx_single_low_fee, /*test_accept=*/false, /*client_maxfeerate=*/{});
|
||||
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
|
||||
BOOST_CHECK(!result_single_tx_low_fee.m_state.IsValid());
|
||||
BOOST_CHECK_EQUAL(result_single_tx_low_fee.m_state.GetResult(), PackageValidationResult::PCKG_TX);
|
||||
auto it_low_fee = result_single_tx_low_fee.m_tx_results.find(tx_single_low_fee->GetWitnessHash());
|
||||
BOOST_CHECK_EQUAL(it_low_fee->second.m_state.GetResult(), TxValidationResult::TX_RECONSIDERABLE);
|
||||
if (auto err_single{CheckPackageMempoolAcceptResult(package_tx_single_low_fee, result_single_tx_low_fee, /*expect_valid=*/false, m_node.mempool.get())}) {
|
||||
BOOST_ERROR(err_single.value());
|
||||
}
|
||||
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
|
||||
}
|
||||
|
||||
// Tests for packages containing transactions that have same-txid-different-witness equivalents in
|
||||
// the mempool.
|
||||
BOOST_AUTO_TEST_CASE(package_witness_swap_tests)
|
||||
|
||||
Reference in New Issue
Block a user