v29.4-roots.4 · Commit 33: [PATCH 33/37] test(mining): cover priority ancestor accounting boundaries
src/test/miner_tests.cpp
Before: src/test/miner_tests.cpp · After: src/test/miner_tests.cpp
File metadata
index d84cb97e2465dc55ac32a5929bae5b76ee4f7b6b..57409da0c0894de3bee45b82398d1bb2ecf292f9 100644
Download original patch · Release notes
Diff rows 1–115 of 115. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.
src/test/miner_tests.cpp
CHANGED
|
@@ -10,6 +10,7 @@
|
|
| 10 |
#include <consensus/tx_verify.h>
|
| 11 |
#include <interfaces/mining.h>
|
| 12 |
#include <node/miner.h>
|
|
|
|
| 13 |
#include <policy/policy.h>
|
| 14 |
#include <test/util/random.h>
|
| 15 |
#include <test/util/transaction_utils.h>
|
|
@@ -27,6 +28,7 @@
|
|
| 27 |
#include <test/util/setup_common.h>
|
| 28 |
|
| 29 |
#include <memory>
|
|
|
|
| 30 |
#include <vector>
|
| 31 |
|
| 32 |
#include <boost/test/unit_test.hpp>
|
|
@@ -669,7 +671,7 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
|
|
| 669 |
// A transaction added by the coin-age priority phase must not keep subsidising
|
| 670 |
// its descendants in the ancestor-feerate phase.
|
| 671 |
//
|
| 672 |
-
// Test entries have no coin-age priority, so the priority phase ranks them by
|
| 673 |
// fee score, adds the fee-paying parent (the child still depends on it), and
|
| 674 |
// then stops at MINIMUM_TX_PRIORITY. The child pays no fee and must not be
|
| 675 |
// selected on the strength of its already-included parent's fee.
|
|
@@ -700,10 +702,92 @@ void MinerTestingSetup::TestPriorityPhaseStaleAncestors(const CScript& scriptPub
|
|
| 700 |
const auto block_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
| 701 |
BOOST_REQUIRE(block_template);
|
| 702 |
const CBlock& block{block_template->block};
|
| 703 |
-
BOOST_CHECK_EQUAL(block.vtx.size(), 2U);
|
| 704 |
BOOST_CHECK(block.vtx[1]->GetHash() == parent_txid);
|
| 705 |
for (const auto& btx : block.vtx) BOOST_CHECK(btx->GetHash() != child_txid);
|
| 706 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 707 |
gArgs.ForceSetArg("-blockprioritysize", "0");
|
| 708 |
}
|
| 709 |
|
|
|
|
| 10 |
#include <consensus/tx_verify.h>
|
| 11 |
#include <interfaces/mining.h>
|
| 12 |
#include <node/miner.h>
|
| 13 |
+
#include <policy/coin_age_priority.h>
|
| 14 |
#include <policy/policy.h>
|
| 15 |
#include <test/util/random.h>
|
| 16 |
#include <test/util/transaction_utils.h>
|
|
|
|
| 28 |
#include <test/util/setup_common.h>
|
| 29 |
|
| 30 |
#include <memory>
|
| 31 |
+
#include <string>
|
| 32 |
#include <vector>
|
| 33 |
|
| 34 |
#include <boost/test/unit_test.hpp>
|
|
|
|
| 671 |
// A transaction added by the coin-age priority phase must not keep subsidising
|
| 672 |
// its descendants in the ancestor-feerate phase.
|
| 673 |
//
|
| 674 |
+
// The first scenario's entries have no coin-age priority, so it ranks them by
|
| 675 |
// fee score, adds the fee-paying parent (the child still depends on it), and
|
| 676 |
// then stops at MINIMUM_TX_PRIORITY. The child pays no fee and must not be
|
| 677 |
// selected on the strength of its already-included parent's fee.
|
|
|
|
| 702 |
const auto block_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
| 703 |
BOOST_REQUIRE(block_template);
|
| 704 |
const CBlock& block{block_template->block};
|
| 705 |
+
BOOST_REQUIRE_EQUAL(block.vtx.size(), 2U);
|
| 706 |
BOOST_CHECK(block.vtx[1]->GetHash() == parent_txid);
|
| 707 |
for (const auto& btx : block.vtx) BOOST_CHECK(btx->GetHash() != child_txid);
|
| 708 |
|
| 709 |
+
// Template policy must not make the otherwise-valid zero-fee child invalid.
|
| 710 |
+
CBlock block_with_child{block};
|
| 711 |
+
block_with_child.vtx.push_back(MakeTransactionRef(tx));
|
| 712 |
+
node::RegenerateCommitments(block_with_child, *m_node.chainman);
|
| 713 |
+
BlockValidationState state;
|
| 714 |
+
BOOST_CHECK(TestBlockValidity(state, m_node.chainman->GetParams(), m_node.chainman->ActiveChainstate(),
|
| 715 |
+
block_with_child, m_node.chainman->ActiveChain().Tip(), /*fCheckPOW=*/false));
|
| 716 |
+
|
| 717 |
+
// With the priority phase disabled, ordinary package selection must still
|
| 718 |
+
// include the parent and stop subsidising its zero-fee child afterwards.
|
| 719 |
+
gArgs.ForceSetArg("-blockprioritysize", "0");
|
| 720 |
+
const auto no_priority_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
| 721 |
+
BOOST_REQUIRE(no_priority_template);
|
| 722 |
+
BOOST_REQUIRE_EQUAL(no_priority_template->block.vtx.size(), 2U);
|
| 723 |
+
BOOST_CHECK(no_priority_template->block.vtx[1]->GetHash() == parent_txid);
|
| 724 |
+
|
| 725 |
+
// A zero mining fee floor may still select the child.
|
| 726 |
+
options.blockMinFeeRate = CFeeRate{0};
|
| 727 |
+
const auto zero_floor_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
| 728 |
+
BOOST_REQUIRE(zero_floor_template);
|
| 729 |
+
BOOST_REQUIRE_EQUAL(zero_floor_template->block.vtx.size(), 3U);
|
| 730 |
+
BOOST_CHECK(zero_floor_template->block.vtx[2]->GetHash() == child_txid);
|
| 731 |
+
|
| 732 |
+
tx_mempool.removeRecursive(*block.vtx[1], MemPoolRemovalReason::REPLACED);
|
| 733 |
+
|
| 734 |
+
// Confirmed coin age selects zero-fee parents first. The child's own fee
|
| 735 |
+
// meets the mining floor, but its stale package including those parents
|
| 736 |
+
// does not. Exercise both one ancestor and a shared descendant of two
|
| 737 |
+
// ancestors, which must each be subtracted exactly once.
|
| 738 |
+
for (const size_t parent_count : {1U, 2U}) {
|
| 739 |
+
BOOST_TEST_CONTEXT("priority-selected parents: " << parent_count) {
|
| 740 |
+
options.blockMinFeeRate = CFeeRate{1000};
|
| 741 |
+
const unsigned int height = m_node.chainman->ActiveChain().Height();
|
| 742 |
+
std::vector<CTransactionRef> parents;
|
| 743 |
+
size_t priority_tx_size{0};
|
| 744 |
+
for (size_t i{0}; i < parent_count; ++i) {
|
| 745 |
+
CMutableTransaction parent;
|
| 746 |
+
parent.vin.resize(1);
|
| 747 |
+
parent.vin[0].prevout = COutPoint{txFirst[i]->GetHash(), 0};
|
| 748 |
+
parent.vin[0].scriptSig = CScript() << OP_1;
|
| 749 |
+
parent.vout.emplace_back(50 * COIN, CScript{});
|
| 750 |
+
parents.push_back(MakeTransactionRef(parent));
|
| 751 |
+
const auto coin_age = GetCoinAge(*parents.back(), m_node.chainman->ActiveChainstate().CoinsTip(), height + 1);
|
| 752 |
+
// AddToMempool does not preserve the coin-age cache.
|
| 753 |
+
auto changeset = tx_mempool.GetChangeSet();
|
| 754 |
+
changeset->StageAddition(parents.back(), /*fee=*/0, /*time=*/0, height, /*entry_sequence=*/0,
|
| 755 |
+
coin_age, /*spends_coinbase=*/true, /*extra_weight=*/0, /*sigops_cost=*/4, LockPoints{});
|
| 756 |
+
changeset->Apply();
|
| 757 |
+
const auto parent_iter = tx_mempool.mapTx.find(parents.back()->GetHash());
|
| 758 |
+
BOOST_REQUIRE(parent_iter != tx_mempool.mapTx.end());
|
| 759 |
+
BOOST_REQUIRE(parent_iter->GetPriority(height + 1) > MINIMUM_TX_PRIORITY);
|
| 760 |
+
priority_tx_size += GetSerializeSize(TX_WITH_WITNESS(*parents.back()));
|
| 761 |
+
}
|
| 762 |
+
|
| 763 |
+
CMutableTransaction child;
|
| 764 |
+
for (const auto& parent : parents) {
|
| 765 |
+
child.vin.emplace_back(COutPoint{parent->GetHash(), 0}, CScript() << OP_1);
|
| 766 |
+
}
|
| 767 |
+
child.vout.emplace_back(parent_count * 50 * COIN, CScript{});
|
| 768 |
+
const CAmount child_fee = options.blockMinFeeRate.GetFee(GetVirtualTransactionSize(CTransaction{child}));
|
| 769 |
+
child.vout[0].nValue -= child_fee;
|
| 770 |
+
const auto child_ref = MakeTransactionRef(child);
|
| 771 |
+
AddToMempool(tx_mempool, entry.Fee(child_fee).SpendsCoinbase(false).FromTx(child_ref));
|
| 772 |
+
|
| 773 |
+
// Without priority selection the entire package is below the floor.
|
| 774 |
+
gArgs.ForceSetArg("-blockprioritysize", "0");
|
| 775 |
+
const auto below_floor_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
| 776 |
+
BOOST_REQUIRE(below_floor_template);
|
| 777 |
+
BOOST_CHECK_EQUAL(below_floor_template->block.vtx.size(), 1U);
|
| 778 |
+
|
| 779 |
+
// The assembler reserves 1000 bytes before adding transactions;
|
| 780 |
+
// end the priority phase immediately after including the parents.
|
| 781 |
+
gArgs.ForceSetArg("-blockprioritysize", std::to_string(1000 + priority_tx_size));
|
| 782 |
+
const auto priority_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
|
| 783 |
+
BOOST_REQUIRE(priority_template);
|
| 784 |
+
BOOST_REQUIRE_EQUAL(priority_template->block.vtx.size(), parent_count + 2);
|
| 785 |
+
BOOST_CHECK(priority_template->block.vtx.back()->GetHash() == child_ref->GetHash());
|
| 786 |
+
BOOST_CHECK_EQUAL(priority_template->vTxFees.back(), child_fee);
|
| 787 |
+
for (const auto& parent : parents) tx_mempool.removeRecursive(*parent, MemPoolRemovalReason::REPLACED);
|
| 788 |
+
}
|
| 789 |
+
}
|
| 790 |
+
|
| 791 |
gArgs.ForceSetArg("-blockprioritysize", "0");
|
| 792 |
}
|
| 793 |
|