Skip to content
Bitcoin Roots

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. The two line-number columns refer to before and after.

src/test/miner_tests.cpp CHANGED
@@ -10,6 +10,7 @@
10
10
  #include <consensus/tx_verify.h>
11
11
  #include <interfaces/mining.h>
12
12
  #include <node/miner.h>
13
+ #include <policy/coin_age_priority.h>
13
14
  #include <policy/policy.h>
14
15
  #include <test/util/random.h>
15
16
  #include <test/util/transaction_utils.h>
@@ -27,6 +28,7 @@
27
28
  #include <test/util/setup_common.h>
28
29
 
29
30
  #include <memory>
31
+ #include <string>
30
32
  #include <vector>
31
33
 
32
34
  #include <boost/test/unit_test.hpp>
@@ -669,7 +671,7 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
669
671
  // A transaction added by the coin-age priority phase must not keep subsidising
670
672
  // its descendants in the ancestor-feerate phase.
671
673
  //
672
- // Test entries have no coin-age priority, so the priority phase ranks them by
674
+ // The first scenario's entries have no coin-age priority, so it ranks them by
673
675
  // fee score, adds the fee-paying parent (the child still depends on it), and
674
676
  // then stops at MINIMUM_TX_PRIORITY. The child pays no fee and must not be
675
677
  // selected on the strength of its already-included parent's fee.
@@ -700,10 +702,92 @@ void MinerTestingSetup::TestPriorityPhaseStaleAncestors(const CScript& scriptPub
700
702
  const auto block_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
701
703
  BOOST_REQUIRE(block_template);
702
704
  const CBlock& block{block_template->block};
703
- BOOST_CHECK_EQUAL(block.vtx.size(), 2U);
705
+ BOOST_REQUIRE_EQUAL(block.vtx.size(), 2U);
704
706
  BOOST_CHECK(block.vtx[1]->GetHash() == parent_txid);
705
707
  for (const auto& btx : block.vtx) BOOST_CHECK(btx->GetHash() != child_txid);
706
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
+
707
791
  gArgs.ForceSetArg("-blockprioritysize", "0");
708
792
  }
709
793