mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-26 15:36:19 +01:00
Rework RBF and TRUC validation
Calculating mempool ancestors for a new transaction should not be done until after cluster size limits have been enforced, to limit CPU DoS potential. Achieve this by reworking TRUC and RBF validation logic: - TRUC policy enforcement is now done using only mempool parents of new transactions, not all mempool ancestors (note that it's fine to calculate ancestors of in-mempool transactions, if the number of such calls is reasonably bounded). - RBF replacement checks are performed earlier (which allows for checking cluster size limits earlier, because cluster size checks cannot happen until after all conflicts are staged for removal). - Verifying that a new transaction doesn't conflict with an ancestor now happens later, in AcceptSingleTransaction() rather than in PreChecks(). This means that the test is not performed at all in AcceptMultipleTransactions(), but in package acceptance we already disallow RBF in situations where a package transaction has in-mempool parents. Also to ensure that all RBF validation logic is applied in both the single transaction and multiple transaction cases, remove the optimization that skips the PackageMempoolChecks() in the case of a single transaction being validated in AcceptMultipleTransactions().
This commit is contained in:
@@ -115,7 +115,6 @@ BOOST_FIXTURE_TEST_CASE(ephemeral_tests, RegTestingSetup)
|
||||
CTxMemPool& pool = *Assert(m_node.mempool);
|
||||
LOCK2(cs_main, pool.cs);
|
||||
TestMemPoolEntryHelper entry;
|
||||
CTxMemPool::setEntries empty_ancestors;
|
||||
|
||||
TxValidationState child_state;
|
||||
Wtxid child_wtxid;
|
||||
@@ -279,7 +278,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
LOCK2(cs_main, pool.cs);
|
||||
TestMemPoolEntryHelper entry;
|
||||
std::set<Txid> empty_conflicts_set;
|
||||
CTxMemPool::setEntries empty_ancestors;
|
||||
std::vector<CTxMemPoolEntry::CTxMemPoolEntryRef> empty_parents;
|
||||
|
||||
auto mempool_tx_v3 = make_tx(random_outpoints(1), /*version=*/3);
|
||||
AddToMempool(pool, entry.FromTx(mempool_tx_v3));
|
||||
@@ -292,33 +291,32 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
// ^
|
||||
// tx_v2_from_v3
|
||||
auto tx_v2_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/2);
|
||||
auto ancestors_v2_from_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v3))};
|
||||
auto parents_v2_from_v3 = pool.GetParents(entry.FromTx(tx_v2_from_v3));
|
||||
const auto expected_error_str{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
|
||||
tx_v2_from_v3->GetHash().ToString(), tx_v2_from_v3->GetWitnessHash().ToString(),
|
||||
mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
|
||||
auto result_v2_from_v3{SingleTRUCChecks(pool, tx_v2_from_v3, ancestors_v2_from_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v3))};
|
||||
auto result_v2_from_v3{SingleTRUCChecks(pool, tx_v2_from_v3, parents_v2_from_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v3))};
|
||||
BOOST_CHECK_EQUAL(result_v2_from_v3->first, expected_error_str);
|
||||
BOOST_CHECK_EQUAL(result_v2_from_v3->second, nullptr);
|
||||
|
||||
Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str);
|
||||
CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash()).value()};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str);
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_parents), expected_error_str);
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, parents_v2_from_v3), expected_error_str);
|
||||
|
||||
// mempool_tx_v3 mempool_tx_v2
|
||||
// ^ ^
|
||||
// tx_v2_from_v2_and_v3
|
||||
auto tx_v2_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
|
||||
auto ancestors_v2_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2_and_v3))};
|
||||
auto parents_2_from_both{pool.GetParents(entry.FromTx(tx_v2_from_v2_and_v3))};
|
||||
const auto expected_error_str_2{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
|
||||
tx_v2_from_v2_and_v3->GetHash().ToString(), tx_v2_from_v2_and_v3->GetWitnessHash().ToString(),
|
||||
mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
|
||||
auto result_v2_from_both{SingleTRUCChecks(pool, tx_v2_from_v2_and_v3, ancestors_v2_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3))};
|
||||
auto result_v2_from_both{SingleTRUCChecks(pool, tx_v2_from_v2_and_v3, parents_2_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3))};
|
||||
BOOST_CHECK_EQUAL(result_v2_from_both->first, expected_error_str_2);
|
||||
BOOST_CHECK_EQUAL(result_v2_from_both->second, nullptr);
|
||||
|
||||
Package package_v3_v2_v2{mempool_tx_v3, mempool_tx_v2, tx_v2_from_v2_and_v3};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v2_from_v2_and_v3, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3), package_v3_v2_v2, empty_ancestors), expected_error_str_2);
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v2_from_v2_and_v3, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3), package_v3_v2_v2, empty_parents), expected_error_str_2);
|
||||
}
|
||||
|
||||
// TRUC cannot spend from an unconfirmed non-TRUC transaction.
|
||||
@@ -327,28 +325,27 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
// ^
|
||||
// tx_v3_from_v2
|
||||
auto tx_v3_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
|
||||
auto ancestors_v3_from_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2))};
|
||||
auto parents_v3_from_v2{pool.GetParents(entry.FromTx(tx_v3_from_v2))};
|
||||
const auto expected_error_str{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
|
||||
tx_v3_from_v2->GetHash().ToString(), tx_v3_from_v2->GetWitnessHash().ToString(),
|
||||
mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
|
||||
auto result_v3_from_v2{SingleTRUCChecks(pool, tx_v3_from_v2, ancestors_v3_from_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2))};
|
||||
auto result_v3_from_v2{SingleTRUCChecks(pool, tx_v3_from_v2, parents_v3_from_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2))};
|
||||
BOOST_CHECK_EQUAL(result_v3_from_v2->first, expected_error_str);
|
||||
BOOST_CHECK_EQUAL(result_v3_from_v2->second, nullptr);
|
||||
|
||||
Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str);
|
||||
CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash()).value()};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str);
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_parents), expected_error_str);
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, parents_v3_from_v2), expected_error_str);
|
||||
|
||||
// mempool_tx_v3 mempool_tx_v2
|
||||
// ^ ^
|
||||
// tx_v3_from_v2_and_v3
|
||||
auto tx_v3_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
|
||||
auto ancestors_v3_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2_and_v3))};
|
||||
auto parents_v3_from_both{pool.GetParents(entry.FromTx(tx_v3_from_v2_and_v3))};
|
||||
const auto expected_error_str_2{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
|
||||
tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString(),
|
||||
mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
|
||||
auto result_v3_from_both{SingleTRUCChecks(pool, tx_v3_from_v2_and_v3, ancestors_v3_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3))};
|
||||
auto result_v3_from_both{SingleTRUCChecks(pool, tx_v3_from_v2_and_v3, parents_v3_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3))};
|
||||
BOOST_CHECK_EQUAL(result_v3_from_both->first, expected_error_str_2);
|
||||
BOOST_CHECK_EQUAL(result_v3_from_both->second, nullptr);
|
||||
|
||||
@@ -356,7 +353,7 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
const auto expected_error_str_3{strprintf("tx %s (wtxid=%s) would have too many ancestors",
|
||||
tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString())};
|
||||
Package package_v3_v2_v3{mempool_tx_v3, mempool_tx_v2, tx_v3_from_v2_and_v3};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_from_v2_and_v3, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3), package_v3_v2_v3, empty_ancestors), expected_error_str_3);
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_from_v2_and_v3, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3), package_v3_v2_v3, empty_parents), expected_error_str_3);
|
||||
}
|
||||
// V3 from V3 is ok, and non-V3 from non-V3 is ok.
|
||||
{
|
||||
@@ -364,23 +361,23 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
// ^
|
||||
// tx_v3_from_v3
|
||||
auto tx_v3_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
|
||||
auto ancestors_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v3))};
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_v3_from_v3, ancestors_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v3))
|
||||
auto parents_v3{pool.GetParents(entry.FromTx(tx_v3_from_v3))};
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_v3_from_v3, parents_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v3))
|
||||
== std::nullopt);
|
||||
|
||||
Package package_v3_v3{mempool_tx_v3, tx_v3_from_v3};
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_v3_from_v3, GetVirtualTransactionSize(*tx_v3_from_v3), package_v3_v3, empty_ancestors) == std::nullopt);
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_v3_from_v3, GetVirtualTransactionSize(*tx_v3_from_v3), package_v3_v3, empty_parents) == std::nullopt);
|
||||
|
||||
// mempool_tx_v2
|
||||
// ^
|
||||
// tx_v2_from_v2
|
||||
auto tx_v2_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
|
||||
auto ancestors_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2))};
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_v2_from_v2, ancestors_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2))
|
||||
auto parents_v2{pool.GetParents(entry.FromTx(tx_v2_from_v2))};
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_v2_from_v2, parents_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2))
|
||||
== std::nullopt);
|
||||
|
||||
Package package_v2_v2{mempool_tx_v2, tx_v2_from_v2};
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_v2_from_v2, GetVirtualTransactionSize(*tx_v2_from_v2), package_v2_v2, empty_ancestors) == std::nullopt);
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_v2_from_v2, GetVirtualTransactionSize(*tx_v2_from_v2), package_v2_v2, empty_parents) == std::nullopt);
|
||||
}
|
||||
|
||||
// Tx spending TRUC cannot have too many mempool ancestors
|
||||
@@ -398,15 +395,15 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
}
|
||||
auto tx_v3_multi_parent = make_tx(mempool_outpoints, /*version=*/3);
|
||||
package_multi_parents.emplace_back(tx_v3_multi_parent);
|
||||
auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_parent))};
|
||||
BOOST_CHECK_EQUAL(ancestors.size(), 3);
|
||||
auto parents{pool.GetParents(entry.FromTx(tx_v3_multi_parent))};
|
||||
BOOST_CHECK_EQUAL(parents.size(), 3);
|
||||
const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
|
||||
tx_v3_multi_parent->GetHash().ToString(), tx_v3_multi_parent->GetWitnessHash().ToString())};
|
||||
auto result{SingleTRUCChecks(pool, tx_v3_multi_parent, ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_parent))};
|
||||
auto result{SingleTRUCChecks(pool, tx_v3_multi_parent, parents, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_parent))};
|
||||
BOOST_CHECK_EQUAL(result->first, expected_error_str);
|
||||
BOOST_CHECK_EQUAL(result->second, nullptr);
|
||||
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_multi_parent, GetVirtualTransactionSize(*tx_v3_multi_parent), package_multi_parents, empty_ancestors),
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_multi_parent, GetVirtualTransactionSize(*tx_v3_multi_parent), package_multi_parents, empty_parents),
|
||||
expected_error_str);
|
||||
}
|
||||
|
||||
@@ -424,16 +421,16 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
}
|
||||
auto tx_v3_multi_gen = make_tx({last_outpoint}, /*version=*/3);
|
||||
package_multi_gen.emplace_back(tx_v3_multi_gen);
|
||||
auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_gen))};
|
||||
auto parents{pool.GetParents(entry.FromTx(tx_v3_multi_gen))};
|
||||
const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
|
||||
tx_v3_multi_gen->GetHash().ToString(), tx_v3_multi_gen->GetWitnessHash().ToString())};
|
||||
auto result{SingleTRUCChecks(pool, tx_v3_multi_gen, ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_gen))};
|
||||
auto result{SingleTRUCChecks(pool, tx_v3_multi_gen, parents, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_gen))};
|
||||
BOOST_CHECK_EQUAL(result->first, expected_error_str);
|
||||
BOOST_CHECK_EQUAL(result->second, nullptr);
|
||||
|
||||
// Middle tx is what triggers a failure for the grandchild:
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, middle_tx, GetVirtualTransactionSize(*middle_tx), package_multi_gen, empty_ancestors), expected_error_str);
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_v3_multi_gen, GetVirtualTransactionSize(*tx_v3_multi_gen), package_multi_gen, empty_ancestors) == std::nullopt);
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, middle_tx, GetVirtualTransactionSize(*middle_tx), package_multi_gen, empty_parents), expected_error_str);
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_v3_multi_gen, GetVirtualTransactionSize(*tx_v3_multi_gen), package_multi_gen, empty_parents) == std::nullopt);
|
||||
}
|
||||
|
||||
// Tx spending TRUC cannot be too large in virtual size.
|
||||
@@ -442,15 +439,15 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
{
|
||||
auto tx_v3_child_big = make_tx(many_inputs, /*version=*/3);
|
||||
const auto vsize{GetVirtualTransactionSize(*tx_v3_child_big)};
|
||||
auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child_big))};
|
||||
auto parents{pool.GetParents(entry.FromTx(tx_v3_child_big))};
|
||||
const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
|
||||
tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE)};
|
||||
auto result{SingleTRUCChecks(pool, tx_v3_child_big, ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child_big))};
|
||||
auto result{SingleTRUCChecks(pool, tx_v3_child_big, parents, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child_big))};
|
||||
BOOST_CHECK_EQUAL(result->first, expected_error_str);
|
||||
BOOST_CHECK_EQUAL(result->second, nullptr);
|
||||
|
||||
Package package_child_big{mempool_tx_v3, tx_v3_child_big};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_child_big, GetVirtualTransactionSize(*tx_v3_child_big), package_child_big, empty_ancestors),
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_child_big, GetVirtualTransactionSize(*tx_v3_child_big), package_child_big, empty_parents),
|
||||
expected_error_str);
|
||||
}
|
||||
|
||||
@@ -477,24 +474,24 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
mtx_many_sigops.vout.back().nValue = 10000;
|
||||
auto tx_many_sigops{MakeTransactionRef(mtx_many_sigops)};
|
||||
|
||||
auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_many_sigops))};
|
||||
auto parents{pool.GetParents(entry.FromTx(tx_many_sigops))};
|
||||
// legacy uses fAccurate = false, and the maximum number of multisig keys is used
|
||||
const int64_t total_sigops{static_cast<int64_t>(tx_many_sigops->vin.size()) * static_cast<int64_t>(script_multisig.GetSigOpCount(/*fAccurate=*/false))};
|
||||
BOOST_CHECK_EQUAL(total_sigops, tx_many_sigops->vin.size() * MAX_PUBKEYS_PER_MULTISIG);
|
||||
const int64_t bip141_vsize{GetVirtualTransactionSize(*tx_many_sigops)};
|
||||
// Weight limit is not reached...
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_many_sigops, ancestors, empty_conflicts_set, bip141_vsize) == std::nullopt);
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_many_sigops, parents, empty_conflicts_set, bip141_vsize) == std::nullopt);
|
||||
// ...but sigop limit is.
|
||||
const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
|
||||
tx_many_sigops->GetHash().ToString(), tx_many_sigops->GetWitnessHash().ToString(),
|
||||
total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, TRUC_CHILD_MAX_VSIZE)};
|
||||
auto result{SingleTRUCChecks(pool, tx_many_sigops, ancestors, empty_conflicts_set,
|
||||
auto result{SingleTRUCChecks(pool, tx_many_sigops, parents, empty_conflicts_set,
|
||||
GetVirtualTransactionSize(*tx_many_sigops, /*nSigOpCost=*/total_sigops, /*bytes_per_sigop=*/ DEFAULT_BYTES_PER_SIGOP))};
|
||||
BOOST_CHECK_EQUAL(result->first, expected_error_str);
|
||||
BOOST_CHECK_EQUAL(result->second, nullptr);
|
||||
|
||||
Package package_child_sigops{mempool_tx_v3, tx_many_sigops};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_many_sigops, total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, package_child_sigops, empty_ancestors),
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_many_sigops, total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, package_child_sigops, empty_parents),
|
||||
expected_error_str);
|
||||
}
|
||||
|
||||
@@ -502,32 +499,32 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
auto tx_mempool_v3_child = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
|
||||
{
|
||||
BOOST_CHECK(GetTransactionWeight(*tx_mempool_v3_child) <= TRUC_CHILD_MAX_VSIZE * WITNESS_SCALE_FACTOR);
|
||||
auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_mempool_v3_child))};
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_mempool_v3_child, ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_mempool_v3_child)) == std::nullopt);
|
||||
auto parents{pool.GetParents(entry.FromTx(tx_mempool_v3_child))};
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_mempool_v3_child, parents, empty_conflicts_set, GetVirtualTransactionSize(*tx_mempool_v3_child)) == std::nullopt);
|
||||
AddToMempool(pool, entry.FromTx(tx_mempool_v3_child));
|
||||
|
||||
Package package_v3_1p1c{mempool_tx_v3, tx_mempool_v3_child};
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_mempool_v3_child, GetVirtualTransactionSize(*tx_mempool_v3_child), package_v3_1p1c, empty_ancestors) == std::nullopt);
|
||||
BOOST_CHECK(PackageTRUCChecks(pool, tx_mempool_v3_child, GetVirtualTransactionSize(*tx_mempool_v3_child), package_v3_1p1c, empty_parents) == std::nullopt);
|
||||
}
|
||||
|
||||
// A TRUC transaction cannot have more than 1 descendant. Sibling is returned when exactly 1 exists.
|
||||
{
|
||||
auto tx_v3_child2 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 1}}, /*version=*/3);
|
||||
// Configuration where parent already has 1 other child in mempool
|
||||
auto ancestors_1sibling{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child2))};
|
||||
auto parents_1sibling{pool.GetParents(entry.FromTx(tx_v3_child2))};
|
||||
const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
|
||||
mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
|
||||
auto result_with_sibling_eviction{SingleTRUCChecks(pool, tx_v3_child2, ancestors_1sibling, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child2))};
|
||||
auto result_with_sibling_eviction{SingleTRUCChecks(pool, tx_v3_child2, parents_1sibling, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child2))};
|
||||
BOOST_CHECK_EQUAL(result_with_sibling_eviction->first, expected_error_str);
|
||||
// The other mempool child is returned to allow for sibling eviction.
|
||||
BOOST_CHECK_EQUAL(result_with_sibling_eviction->second, tx_mempool_v3_child);
|
||||
|
||||
// If directly replacing the child, make sure there is no double-counting.
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_v3_child2, ancestors_1sibling, {tx_mempool_v3_child->GetHash()}, GetVirtualTransactionSize(*tx_v3_child2))
|
||||
BOOST_CHECK(SingleTRUCChecks(pool, tx_v3_child2, parents_1sibling, {tx_mempool_v3_child->GetHash()}, GetVirtualTransactionSize(*tx_v3_child2))
|
||||
== std::nullopt);
|
||||
|
||||
Package package_v3_1p2c{mempool_tx_v3, tx_mempool_v3_child, tx_v3_child2};
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_child2, GetVirtualTransactionSize(*tx_v3_child2), package_v3_1p2c, empty_ancestors),
|
||||
BOOST_CHECK_EQUAL(*PackageTRUCChecks(pool, tx_v3_child2, GetVirtualTransactionSize(*tx_v3_child2), package_v3_1p2c, empty_parents),
|
||||
expected_error_str);
|
||||
|
||||
// Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg.
|
||||
@@ -535,9 +532,9 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
auto tx_v3_child3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 24}}, /*version=*/3);
|
||||
auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash()).value();
|
||||
BOOST_CHECK_EQUAL(pool.GetDescendantCount(entry_mempool_parent), 3);
|
||||
auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3))};
|
||||
auto parents_2siblings{pool.GetParents(entry.FromTx(tx_v3_child3))};
|
||||
|
||||
auto result_2children{SingleTRUCChecks(pool, tx_v3_child3, ancestors_2siblings, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child3))};
|
||||
auto result_2children{SingleTRUCChecks(pool, tx_v3_child3, parents_2siblings, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child3))};
|
||||
BOOST_CHECK_EQUAL(result_2children->first, expected_error_str);
|
||||
// The other mempool child is not returned because sibling eviction is not allowed.
|
||||
BOOST_CHECK_EQUAL(result_2children->second, nullptr);
|
||||
@@ -554,10 +551,10 @@ BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
|
||||
AddToMempool(pool, entry.FromTx(tx_mempool_sibling));
|
||||
AddToMempool(pool, entry.FromTx(tx_mempool_nibling));
|
||||
|
||||
auto ancestors_3gen{pool.CalculateMemPoolAncestors(entry.FromTx(tx_to_submit))};
|
||||
auto parents_3gen{pool.GetParents(entry.FromTx(tx_to_submit))};
|
||||
const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
|
||||
tx_mempool_grandparent->GetHash().ToString(), tx_mempool_grandparent->GetWitnessHash().ToString())};
|
||||
auto result_3gen{SingleTRUCChecks(pool, tx_to_submit, ancestors_3gen, empty_conflicts_set, GetVirtualTransactionSize(*tx_to_submit))};
|
||||
auto result_3gen{SingleTRUCChecks(pool, tx_to_submit, parents_3gen, empty_conflicts_set, GetVirtualTransactionSize(*tx_to_submit))};
|
||||
BOOST_CHECK_EQUAL(result_3gen->first, expected_error_str);
|
||||
// The other mempool child is not returned because sibling eviction is not allowed.
|
||||
BOOST_CHECK_EQUAL(result_3gen->second, nullptr);
|
||||
|
||||
Reference in New Issue
Block a user