Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 4: [PATCH 04/17] feat(mining): preserve Roots priority and template policies

src/test/miner_tests.cpp

Before: src/test/miner_tests.cpp · After: src/test/miner_tests.cpp

File metadata
index 6b4e85a59e45ad84c4a8c7d1e6df912580638723..032ccc35cec02d754efb4386c22dabbd763b628c 100644

Download original patch · Release notes

Diff rows 1–336 of 336. 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
@@ -42,6 +42,7 @@ namespace miner_tests {
42
  struct MinerTestingSetup : public TestingSetup {
43
  void TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
44
  void TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
 
45
  void TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
46
  bool TestSequenceLocks(const CTransaction& tx, CTxMemPool& tx_mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
47
  {
@@ -116,6 +117,8 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
116
  CTxMemPool& tx_mempool{MakeMempool()};
117
  auto mining{MakeMining()};
118
  BlockAssembler::Options options;
 
 
119
  options.coinbase_output_script = scriptPubKey;
120
  options.include_dummy_extranonce = true;
121
 
@@ -250,7 +253,7 @@ void MinerTestingSetup::TestPackageSelection(const CScript& scriptPubKey, const
250
  // This tx can't be mined by itself
251
  tx.vin[0].prevout.hash = hashFreeTx2;
252
  tx.vout.resize(1);
253
- feeToUse = blockMinFeeRate.GetFee(freeTxSize);
254
  tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
255
  Txid hashLowFeeTx2 = tx.GetHash();
256
  TryAddToMempool(tx_mempool, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
@@ -335,6 +338,8 @@ void MinerTestingSetup::TestBasicMining(const CScript& scriptPubKey, const std::
335
  BOOST_REQUIRE(mining);
336
 
337
  BlockAssembler::Options options;
 
 
338
  options.coinbase_output_script = scriptPubKey;
339
  options.include_dummy_extranonce = true;
340
 
@@ -662,6 +667,8 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
662
  BOOST_REQUIRE(mining);
663
 
664
  BlockAssembler::Options options;
 
 
665
  options.coinbase_output_script = scriptPubKey;
666
  options.include_dummy_extranonce = true;
667
 
@@ -743,15 +750,290 @@ void MinerTestingSetup::TestPrioritisedMining(const CScript& scriptPubKey, const
743
  }
744
  }
745
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
746
  // NOTE: These tests rely on CreateNewBlock doing its own self-validation!
747
  BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
748
  {
 
 
749
  auto mining{MakeMining()};
750
  BOOST_REQUIRE(mining);
751
 
752
  // Note that by default, these tests run with size accounting enabled.
753
  CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG;
754
  BlockAssembler::Options options;
 
 
755
  options.coinbase_output_script = scriptPubKey;
756
  options.include_dummy_extranonce = true;
757
 
@@ -867,6 +1149,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
867
  SetMockTime(0);
868
 
869
  TestPrioritisedMining(scriptPubKey, txFirst);
 
870
  }
871
 
872
  BOOST_AUTO_TEST_SUITE_END()
 
42
  struct MinerTestingSetup : public TestingSetup {
43
  void TestPackageSelection(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
44
  void TestBasicMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
45
+ void TestPriorityPhaseStaleAncestors(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
46
  void TestPrioritisedMining(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
47
  bool TestSequenceLocks(const CTransaction& tx, CTxMemPool& tx_mempool) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
48
  {
 
117
  CTxMemPool& tx_mempool{MakeMempool()};
118
  auto mining{MakeMining()};
119
  BlockAssembler::Options options;
120
+ options.nBlockPrioritySize = 0;
121
+ options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
122
  options.coinbase_output_script = scriptPubKey;
123
  options.include_dummy_extranonce = true;
124
 
 
253
  // This tx can't be mined by itself
254
  tx.vin[0].prevout.hash = hashFreeTx2;
255
  tx.vout.resize(1);
256
+ feeToUse = blockMinFeeRate.GetFee(GetVirtualTransactionSize(CTransaction{tx}));
257
  tx.vout[0].nValue = 5000000000LL - 100000000 - feeToUse;
258
  Txid hashLowFeeTx2 = tx.GetHash();
259
  TryAddToMempool(tx_mempool, entry.Fee(feeToUse).SpendsCoinbase(false).FromTx(tx));
 
338
  BOOST_REQUIRE(mining);
339
 
340
  BlockAssembler::Options options;
341
+ options.nBlockPrioritySize = 0;
342
+ options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
343
  options.coinbase_output_script = scriptPubKey;
344
  options.include_dummy_extranonce = true;
345
 
 
667
  BOOST_REQUIRE(mining);
668
 
669
  BlockAssembler::Options options;
670
+ options.nBlockPrioritySize = 0;
671
+ options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
672
  options.coinbase_output_script = scriptPubKey;
673
  options.include_dummy_extranonce = true;
674
 
 
750
  }
751
  }
752
 
753
+ void MinerTestingSetup::TestPriorityPhaseStaleAncestors(const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
754
+ {
755
+ CTxMemPool& tx_mempool{MakeMempool()};
756
+ BlockAssembler::Options options;
757
+ options.coinbase_output_script = scriptPubKey;
758
+ options.include_dummy_extranonce = true;
759
+ options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
760
+
761
+ LOCK(tx_mempool.cs);
762
+ TestMemPoolEntryHelper entry;
763
+
764
+ CMutableTransaction tx;
765
+ tx.vin.resize(1);
766
+ tx.vin[0].scriptSig = CScript() << OP_1;
767
+ tx.vin[0].prevout.hash = txFirst[0]->GetHash();
768
+ tx.vin[0].prevout.n = 0;
769
+ tx.vout.resize(1);
770
+ tx.vout[0].nValue = 5000000000LL - 100000;
771
+ const Txid parent_txid = tx.GetHash();
772
+ TryAddToMempool(tx_mempool, entry.Fee(100000).Time(Now<NodeSeconds>()).SpendsCoinbase(true).FromTx(tx));
773
+
774
+ tx.vin[0].prevout.hash = parent_txid;
775
+ const Txid child_txid = tx.GetHash();
776
+ TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(false).FromTx(tx));
777
+
778
+ options.nBlockPrioritySize = DEFAULT_BLOCK_RESERVED_SIZE + GetSerializeSize(TX_WITH_WITNESS(tx_mempool.mapTx.find(parent_txid)->GetTx()));
779
+ const auto block_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
780
+ BOOST_REQUIRE(block_template);
781
+ const CBlock& block{block_template->block};
782
+ BOOST_REQUIRE_EQUAL(block.vtx.size(), 2U);
783
+ BOOST_CHECK(block.vtx[1]->GetHash() == parent_txid);
784
+ for (const auto& btx : block.vtx) BOOST_CHECK(btx->GetHash() != child_txid);
785
+
786
+ // Template policy must not make the otherwise-valid zero-fee child invalid.
787
+ CBlock block_with_child{block};
788
+ block_with_child.vtx.push_back(MakeTransactionRef(tx));
789
+ node::RegenerateCommitments(block_with_child, *m_node.chainman);
790
+ const BlockValidationState state{TestBlockValidity(m_node.chainman->ActiveChainstate(), block_with_child,
791
+ /*check_pow=*/false, /*check_merkle_root=*/true)};
792
+ BOOST_CHECK_MESSAGE(state.IsValid(), state.ToString());
793
+
794
+ // With the priority phase disabled, ordinary package selection must still
795
+ // include the parent and stop subsidising its zero-fee child afterwards.
796
+ options.nBlockPrioritySize = 0;
797
+ const auto no_priority_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
798
+ BOOST_REQUIRE(no_priority_template);
799
+ BOOST_REQUIRE_EQUAL(no_priority_template->block.vtx.size(), 2U);
800
+ BOOST_CHECK(no_priority_template->block.vtx[1]->GetHash() == parent_txid);
801
+
802
+ // A zero mining fee floor may still select the child.
803
+ options.blockMinFeeRate = CFeeRate{0};
804
+ const auto zero_floor_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
805
+ BOOST_REQUIRE(zero_floor_template);
806
+ BOOST_REQUIRE_EQUAL(zero_floor_template->block.vtx.size(), 3U);
807
+ BOOST_CHECK(zero_floor_template->block.vtx[2]->GetHash() == child_txid);
808
+
809
+ tx_mempool.removeRecursive(*block.vtx[1], MemPoolRemovalReason::REPLACED);
810
+
811
+ // Confirmed coin age selects zero-fee parents first. The child's own fee
812
+ // meets the mining floor, but its stale package including those parents
813
+ // does not. Exercise both one ancestor and a shared descendant of two
814
+ // ancestors, which must each be subtracted exactly once.
815
+ for (const size_t parent_count : {1U, 2U}) {
816
+ BOOST_TEST_CONTEXT("priority-selected parents: " << parent_count) {
817
+ options.blockMinFeeRate = CFeeRate{1000};
818
+ std::vector<CTransactionRef> parents;
819
+ size_t priority_tx_size{0};
820
+ for (size_t i{0}; i < parent_count; ++i) {
821
+ CMutableTransaction parent;
822
+ parent.vin.resize(1);
823
+ parent.vin[0].prevout = COutPoint{txFirst[i]->GetHash(), 0};
824
+ parent.vin[0].scriptSig = CScript() << OP_1;
825
+ parent.vout.emplace_back(50 * COIN, CScript{});
826
+ parents.push_back(MakeTransactionRef(parent));
827
+ TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(true).FromTx(parents.back()));
828
+ priority_tx_size += GetSerializeSize(TX_WITH_WITNESS(*parents.back()));
829
+ }
830
+
831
+ CMutableTransaction child;
832
+ for (const auto& parent : parents) {
833
+ child.vin.emplace_back(COutPoint{parent->GetHash(), 0}, CScript() << OP_1);
834
+ }
835
+ child.vout.emplace_back(parent_count * 50 * COIN, CScript{});
836
+ const CAmount child_fee = options.blockMinFeeRate.GetFee(GetVirtualTransactionSize(CTransaction{child}));
837
+ child.vout[0].nValue -= child_fee;
838
+ const auto child_ref = MakeTransactionRef(child);
839
+ TryAddToMempool(tx_mempool, entry.Fee(child_fee).SpendsCoinbase(false).FromTx(child_ref));
840
+
841
+ // Without priority selection the entire package is below the floor.
842
+ options.nBlockPrioritySize = 0;
843
+ const auto below_floor_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
844
+ BOOST_REQUIRE(below_floor_template);
845
+ BOOST_CHECK_EQUAL(below_floor_template->block.vtx.size(), 1U);
846
+
847
+ // The assembler reserves 1000 bytes before adding transactions;
848
+ // end the priority phase immediately after including the parents.
849
+ options.nBlockPrioritySize = DEFAULT_BLOCK_RESERVED_SIZE + priority_tx_size;
850
+ const auto priority_template = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
851
+ BOOST_REQUIRE(priority_template);
852
+ BOOST_REQUIRE_EQUAL(priority_template->block.vtx.size(), parent_count + 2);
853
+ BOOST_CHECK(priority_template->block.vtx.back()->GetHash() == child_ref->GetHash());
854
+ BOOST_CHECK_EQUAL(priority_template->vTxFees.back(), child_fee);
855
+ // Equality is excluded by Roots' conservative resource boundary.
856
+ const auto weight = *BlockAssembler::m_last_block_weight;
857
+ options.nBlockMaxWeight = weight;
858
+ const auto capped = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
859
+ BOOST_CHECK_EQUAL(capped->block.vtx.size(), parent_count + 1);
860
+ options.nBlockMaxWeight = weight + 1;
861
+ const auto fits = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
862
+ BOOST_CHECK_EQUAL(fits->block.vtx.size(), parent_count + 2);
863
+ options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
864
+ options.nBlockMaxSize = DEFAULT_BLOCK_RESERVED_SIZE + priority_tx_size + GetSerializeSize(TX_WITH_WITNESS(*child_ref));
865
+ const auto size_capped = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
866
+ BOOST_CHECK_EQUAL(size_capped->block.vtx.size(), parent_count + 1);
867
+ ++options.nBlockMaxSize;
868
+ const auto size_fits = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
869
+ BOOST_CHECK_EQUAL(size_fits->block.vtx.size(), parent_count + 2);
870
+ options.nBlockMaxSize = MAX_BLOCK_SERIALIZED_SIZE;
871
+ for (const auto& parent : parents) tx_mempool.removeRecursive(*parent, MemPoolRemovalReason::REPLACED);
872
+ }
873
+ }
874
+
875
+ // A child can outrank its parent using a second, older confirmed input.
876
+ // It must wait, then be revisited exactly once after its parent is selected.
877
+ options.nBlockPrioritySize = DEFAULT_BLOCK_PRIORITY_SIZE;
878
+ options.blockMinFeeRate = CFeeRate{1'000'000};
879
+ CMutableTransaction waiting_parent;
880
+ waiting_parent.vin.emplace_back(COutPoint{txFirst[1]->GetHash(), 0}, CScript() << OP_1);
881
+ waiting_parent.vout.emplace_back(50 * COIN, CScript{});
882
+ const auto parent_ref = MakeTransactionRef(waiting_parent);
883
+ TryAddToMempool(tx_mempool, entry.Fee(0).SpendsCoinbase(true).FromTx(parent_ref));
884
+ CMutableTransaction waiting_child;
885
+ waiting_child.vin.emplace_back(COutPoint{parent_ref->GetHash(), 0}, CScript() << OP_1);
886
+ waiting_child.vin.emplace_back(COutPoint{txFirst[0]->GetHash(), 0}, CScript() << OP_1);
887
+ waiting_child.vout.emplace_back(100 * COIN - 500, CScript{});
888
+ const auto waiting_child_ref = MakeTransactionRef(waiting_child);
889
+ TryAddToMempool(tx_mempool, entry.Fee(500).SpendsCoinbase(true).FromTx(waiting_child_ref));
890
+ const auto pool_size = tx_mempool.size();
891
+ const auto pool_fee = tx_mempool.GetTotalFee();
892
+ for (int repeat = 0; repeat < 2; ++repeat) {
893
+ const auto ready = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
894
+ BOOST_REQUIRE_EQUAL(ready->block.vtx.size(), 3U);
895
+ BOOST_CHECK(ready->block.vtx[1]->GetHash() == parent_ref->GetHash());
896
+ BOOST_CHECK(ready->block.vtx[2]->GetHash() == waiting_child_ref->GetHash());
897
+ BOOST_CHECK_EQUAL(ready->vTxFees[1], 500);
898
+ BOOST_CHECK_EQUAL(tx_mempool.size(), pool_size);
899
+ BOOST_CHECK_EQUAL(tx_mempool.GetTotalFee(), pool_fee);
900
+ }
901
+ options.nBlockPrioritySize = 0;
902
+ const auto disabled = BlockAssembler{m_node.chainman->ActiveChainstate(), &tx_mempool, options}.CreateNewBlock();
903
+ BOOST_CHECK_EQUAL(disabled->block.vtx.size(), 1U);
904
+ }
905
+
906
+ BOOST_AUTO_TEST_CASE(priority_tie_policy)
907
+ {
908
+ CTxMemPool& pool = MakeMempool();
909
+ LOCK2(cs_main, pool.cs);
910
+ BlockAssembler::Options options;
911
+ options.test_block_validity = false;
912
+ options.blockMinFeeRate = CFeeRate{1'000'000'000};
913
+ TestMemPoolEntryHelper entry;
914
+ CMutableTransaction high;
915
+ high.vin.emplace_back(COutPoint{Txid::FromUint256(uint256::ONE), 0});
916
+ high.vout.emplace_back(COIN, CScript{});
917
+ CMutableTransaction low = high;
918
+ low.vin[0].prevout.n = 1;
919
+ const auto high_ref = MakeTransactionRef(high);
920
+ const auto low_ref = MakeTransactionRef(low);
921
+ TryAddToMempool(pool, entry.Fee(100).FromTx(high_ref));
922
+ TryAddToMempool(pool, entry.Fee(10).FromTx(low_ref));
923
+ BOOST_REQUIRE(pool.PrioritiseTransaction(low_ref->GetHash(), 1'000'000));
924
+ // Both have zero coin age. Actual fee breaks the tie even when operator
925
+ // deltas reverse their modified-fee ordering. Threshold stops after one.
926
+ const auto actual_fee = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
927
+ BOOST_REQUIRE_EQUAL(actual_fee->block.vtx.size(), 2U);
928
+ BOOST_CHECK(actual_fee->block.vtx[1]->GetHash() == high_ref->GetHash());
929
+ pool.removeRecursive(*low_ref, MemPoolRemovalReason::REPLACED);
930
+ TryAddToMempool(pool, entry.Fee(100).FromTx(low_ref));
931
+ const auto hash_tie = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
932
+ BOOST_REQUIRE_EQUAL(hash_tie->block.vtx.size(), 2U);
933
+ BOOST_CHECK(hash_tie->block.vtx[1]->GetHash() == std::max(high_ref->GetHash(), low_ref->GetHash()));
934
+ options.nBlockPrioritySize = 0;
935
+ const auto disabled = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
936
+ BOOST_CHECK_EQUAL(disabled->block.vtx.size(), 1U);
937
+ }
938
+
939
+ BOOST_AUTO_TEST_CASE(residual_policy_accounting)
940
+ {
941
+ CTxMemPool& pool = MakeMempool();
942
+ LOCK2(cs_main, pool.cs);
943
+ BlockAssembler::Options options;
944
+ options.test_block_validity = false;
945
+ options.blockMinFeeRate = CFeeRate{1000};
946
+ CMutableTransaction parent;
947
+ parent.vin.emplace_back(COutPoint{Txid::FromUint256(uint256::ONE), 0});
948
+ parent.vout.emplace_back(COIN, CScript{});
949
+ const auto parent_ref = MakeTransactionRef(parent);
950
+ CMutableTransaction child;
951
+ child.vin.emplace_back(COutPoint{parent_ref->GetHash(), 0});
952
+ child.vout.emplace_back(COIN - 20000, CScript{});
953
+ const auto child_ref = MakeTransactionRef(child);
954
+ const int32_t extra_weight = 401;
955
+ const int64_t adjusted_weight = GetTransactionWeight(*child_ref) + extra_weight;
956
+ const CAmount policy_vsize = (adjusted_weight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
957
+ {
958
+ auto stage = pool.GetChangeSet();
959
+ stage->StageAddition(parent_ref, 100000, 0, 1, 0, false, 0, {}, 0, 110000);
960
+ stage->StageAddition(child_ref, 20000, 0, 1, 0, false, 0, {}, extra_weight, 20000 - policy_vsize);
961
+ BOOST_REQUIRE(stage->CheckMemPoolPolicyLimits());
962
+ stage->Apply();
963
+ }
964
+ // Priority uses actual fees on this zero-age tie and selects the parent.
965
+ // Its negative modified fee disappears; the child meets the exact rounded
966
+ // policy-vsize fee floor without stale ancestor debt or carrier resources.
967
+ const auto selected = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
968
+ BOOST_REQUIRE_EQUAL(selected->block.vtx.size(), 3U);
969
+ BOOST_CHECK(selected->block.vtx[1]->GetHash() == parent_ref->GetHash());
970
+ BOOST_CHECK(selected->block.vtx[2]->GetHash() == child_ref->GetHash());
971
+ BOOST_CHECK_EQUAL(selected->vTxFees[0], 100000);
972
+ BOOST_CHECK_EQUAL(selected->vTxFees[1], 20000);
973
+ BOOST_CHECK_EQUAL(selected->block.vtx[0]->vout[0].nValue,
974
+ GetBlockSubsidy(1, m_node.chainman->GetParams().GetConsensus()) + 120000);
975
+ BOOST_REQUIRE_EQUAL(selected->m_package_feerates.size(), 1U);
976
+ BOOST_CHECK(selected->m_package_feerates[0] == FeePerVSize(policy_vsize, policy_vsize));
977
+ BOOST_REQUIRE(pool.PrioritiseTransaction(child_ref->GetHash(), -1));
978
+ const auto below = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
979
+ BOOST_CHECK_EQUAL(below->block.vtx.size(), 2U);
980
+ BOOST_REQUIRE(pool.PrioritiseTransaction(child_ref->GetHash(), 1));
981
+ options.nBlockMaxWeight = DEFAULT_BLOCK_RESERVED_WEIGHT + GetTransactionWeight(*parent_ref) + adjusted_weight;
982
+ const auto capped = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
983
+ BOOST_CHECK_EQUAL(capped->block.vtx.size(), 2U);
984
+ ++options.nBlockMaxWeight;
985
+ const auto fits = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
986
+ BOOST_CHECK_EQUAL(fits->block.vtx.size(), 3U);
987
+ options.nBlockPrioritySize = 0;
988
+ const auto disabled = BlockAssembler{m_node.chainman->ActiveChainstate(), &pool, options}.CreateNewBlock();
989
+ BOOST_CHECK_EQUAL(disabled->block.vtx.size(), 1U);
990
+ }
991
+
992
+ BOOST_AUTO_TEST_CASE(template_option_normalization)
993
+ {
994
+ ArgsManager args;
995
+ BlockAssembler::Options options;
996
+ node::ApplyArgsManOptions(args, options);
997
+ BOOST_CHECK_EQUAL(options.nBlockMaxWeight, 1'200'000U);
998
+ BOOST_CHECK_EQUAL(options.nBlockMaxSize, MAX_BLOCK_SERIALIZED_SIZE);
999
+ BOOST_CHECK_EQUAL(options.nBlockPrioritySize, 100'000U);
1000
+ BOOST_CHECK_EQUAL(options.blockMinFeeRate.GetFeePerK(), 1000);
1001
+ args.ForceSetArg("-blockmaxsize", "120000");
1002
+ node::ApplyArgsManOptions(args, options);
1003
+ BOOST_CHECK_EQUAL(options.nBlockMaxWeight, MAX_BLOCK_WEIGHT);
1004
+ BOOST_CHECK_EQUAL(options.nBlockMaxSize, 120'000U);
1005
+ args.ForceSetArg("-blockmaxweight", "600000");
1006
+ args.ForceSetArg("-blockprioritysize", "0");
1007
+ args.ForceSetArg("-blockreservedweight", "9000");
1008
+ args.ForceSetArg("-blockmintxfee", "0.00002000");
1009
+ node::ApplyArgsManOptions(args, options);
1010
+ BOOST_CHECK_EQUAL(options.nBlockMaxWeight, 600'000U);
1011
+ BOOST_CHECK_EQUAL(options.nBlockMaxSize, 120'000U);
1012
+ BOOST_CHECK_EQUAL(options.nBlockPrioritySize, 0U);
1013
+ BOOST_REQUIRE(options.block_reserved_weight);
1014
+ BOOST_CHECK_EQUAL(*options.block_reserved_weight, 9000U);
1015
+ BOOST_CHECK_EQUAL(options.blockMinFeeRate.GetFeePerK(), 2000);
1016
+ ArgsManager weight_only;
1017
+ weight_only.ForceSetArg("-blockmaxweight", "700000");
1018
+ options = {};
1019
+ node::ApplyArgsManOptions(weight_only, options);
1020
+ BOOST_CHECK_EQUAL(options.nBlockMaxWeight, 700'000U);
1021
+ BOOST_CHECK_EQUAL(options.nBlockMaxSize, MAX_BLOCK_SERIALIZED_SIZE);
1022
+ }
1023
+
1024
  // NOTE: These tests rely on CreateNewBlock doing its own self-validation!
1025
  BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
1026
  {
1027
+ m_node.args->ForceSetArg("-blockprioritysize", "0");
1028
+ m_node.args->ForceSetArg("-blockmaxweight", "4000000");
1029
  auto mining{MakeMining()};
1030
  BOOST_REQUIRE(mining);
1031
 
1032
  // Note that by default, these tests run with size accounting enabled.
1033
  CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG;
1034
  BlockAssembler::Options options;
1035
+ options.nBlockPrioritySize = 0;
1036
+ options.nBlockMaxWeight = MAX_BLOCK_WEIGHT;
1037
  options.coinbase_output_script = scriptPubKey;
1038
  options.include_dummy_extranonce = true;
1039
 
 
1149
  SetMockTime(0);
1150
 
1151
  TestPrioritisedMining(scriptPubKey, txFirst);
1152
+ TestPriorityPhaseStaleAncestors(scriptPubKey, txFirst);
1153
  }
1154
 
1155
  BOOST_AUTO_TEST_SUITE_END()