aboutsummaryrefslogtreecommitdiff
path: root/src/test/txpackage_tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/txpackage_tests.cpp')
-rw-r--r--src/test/txpackage_tests.cpp113
1 files changed, 112 insertions, 1 deletions
diff --git a/src/test/txpackage_tests.cpp b/src/test/txpackage_tests.cpp
index ea211aedf3..3c36b78260 100644
--- a/src/test/txpackage_tests.cpp
+++ b/src/test/txpackage_tests.cpp
@@ -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)
@@ -1078,7 +1171,25 @@ BOOST_AUTO_TEST_CASE(package_rbf_tests)
BOOST_CHECK_EQUAL(it_child_3->second.m_effective_feerate.value().GetFee(package3_total_vsize), 199 + 1300);
BOOST_CHECK_EQUAL(m_node.mempool->size(), expected_pool_size);
- }
+ // Finally, check that we can prioritise tx_child_1 to get package1 into the mempool.
+ // It should not be possible to resubmit package1 and get it in without prioritisation.
+ const auto submit4 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, false, std::nullopt);
+ if (auto err_4{CheckPackageMempoolAcceptResult(package1, submit4, /*expect_valid=*/false, m_node.mempool.get())}) {
+ BOOST_ERROR(err_4.value());
+ }
+ m_node.mempool->PrioritiseTransaction(tx_child_1->GetHash(), 1363);
+ const auto submit5 = ProcessNewPackage(m_node.chainman->ActiveChainstate(), *m_node.mempool, package1, false, std::nullopt);
+ if (auto err_5{CheckPackageMempoolAcceptResult(package1, submit5, /*expect_valid=*/true, m_node.mempool.get())}) {
+ BOOST_ERROR(err_5.value());
+ }
+ it_parent_1 = submit5.m_tx_results.find(tx_parent_1->GetWitnessHash());
+ it_child_1 = submit5.m_tx_results.find(tx_child_1->GetWitnessHash());
+ BOOST_CHECK_EQUAL(it_parent_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
+ BOOST_CHECK_EQUAL(it_child_1->second.m_result_type, MempoolAcceptResult::ResultType::VALID);
+ LOCK(m_node.mempool->cs);
+ BOOST_CHECK(m_node.mempool->GetIter(tx_parent_1->GetHash()).has_value());
+ BOOST_CHECK(m_node.mempool->GetIter(tx_child_1->GetHash()).has_value());
+ }
}
BOOST_AUTO_TEST_SUITE_END()