@@ -31,6 +31,7 @@ namespace miner_tests {
31
31
struct MinerTestingSetup : public TestingSetup {
32
32
void TestPackageSelection (const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
33
33
void TestBasicMining (const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
34
+ void TestPrioritisedMining (const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
34
35
bool TestSequenceLocks (const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs)
35
36
{
36
37
CCoinsViewMemPool view_mempool (&m_node.chainman ->ActiveChainstate ().CoinsTip (), *m_node.mempool );
@@ -468,6 +469,81 @@ void MinerTestingSetup::TestBasicMining(const CChainParams& chainparams, const C
468
469
BOOST_CHECK_EQUAL (pblocktemplate->block .vtx .size (), 5U );
469
470
}
470
471
472
+ void MinerTestingSetup::TestPrioritisedMining (const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst)
473
+ {
474
+ TestMemPoolEntryHelper entry;
475
+
476
+ // Test that a tx below min fee but prioritised is included
477
+ CMutableTransaction tx;
478
+ tx.vin .resize (1 );
479
+ tx.vin [0 ].prevout .hash = txFirst[0 ]->GetHash ();
480
+ tx.vin [0 ].prevout .n = 0 ;
481
+ tx.vin [0 ].scriptSig = CScript () << OP_1;
482
+ tx.vout .resize (1 );
483
+ tx.vout [0 ].nValue = 5000000000LL ; // 0 fee
484
+ uint256 hashFreePrioritisedTx = tx.GetHash ();
485
+ m_node.mempool ->addUnchecked (entry.Fee (0 ).Time (GetTime ()).SpendsCoinbase (true ).FromTx (tx));
486
+ m_node.mempool ->PrioritiseTransaction (hashFreePrioritisedTx, 5 * COIN);
487
+
488
+ tx.vin [0 ].prevout .hash = txFirst[1 ]->GetHash ();
489
+ tx.vin [0 ].prevout .n = 0 ;
490
+ tx.vout [0 ].nValue = 5000000000LL - 1000 ;
491
+ // This tx has a low fee: 1000 satoshis
492
+ uint256 hashParentTx = tx.GetHash (); // save this txid for later use
493
+ m_node.mempool ->addUnchecked (entry.Fee (1000 ).Time (GetTime ()).SpendsCoinbase (true ).FromTx (tx));
494
+
495
+ // This tx has a medium fee: 10000 satoshis
496
+ tx.vin [0 ].prevout .hash = txFirst[2 ]->GetHash ();
497
+ tx.vout [0 ].nValue = 5000000000LL - 10000 ;
498
+ uint256 hashMediumFeeTx = tx.GetHash ();
499
+ m_node.mempool ->addUnchecked (entry.Fee (10000 ).Time (GetTime ()).SpendsCoinbase (true ).FromTx (tx));
500
+ m_node.mempool ->PrioritiseTransaction (hashMediumFeeTx, -5 * COIN);
501
+
502
+ // This tx also has a low fee, but is prioritised
503
+ tx.vin [0 ].prevout .hash = hashParentTx;
504
+ tx.vout [0 ].nValue = 5000000000LL - 1000 - 1000 ; // 1000 satoshi fee
505
+ uint256 hashPrioritsedChild = tx.GetHash ();
506
+ m_node.mempool ->addUnchecked (entry.Fee (1000 ).Time (GetTime ()).SpendsCoinbase (false ).FromTx (tx));
507
+ m_node.mempool ->PrioritiseTransaction (hashPrioritsedChild, 2 * COIN);
508
+
509
+ // Test that transaction selection properly updates ancestor fee calculations as prioritised
510
+ // parents get included in a block. Create a transaction with two prioritised ancestors, each
511
+ // included by itself: FreeParent <- FreeChild <- FreeGrandchild.
512
+ // When FreeParent is added, a modified entry will be created for FreeChild + FreeGrandchild
513
+ // FreeParent's prioritisation should not be included in that entry.
514
+ // When FreeChild is included, FreeChild's prioritisation should also not be included.
515
+ tx.vin [0 ].prevout .hash = txFirst[3 ]->GetHash ();
516
+ tx.vout [0 ].nValue = 5000000000LL ; // 0 fee
517
+ uint256 hashFreeParent = tx.GetHash ();
518
+ m_node.mempool ->addUnchecked (entry.Fee (0 ).SpendsCoinbase (true ).FromTx (tx));
519
+ m_node.mempool ->PrioritiseTransaction (hashFreeParent, 10 * COIN);
520
+
521
+ tx.vin [0 ].prevout .hash = hashFreeParent;
522
+ tx.vout [0 ].nValue = 5000000000LL ; // 0 fee
523
+ uint256 hashFreeChild = tx.GetHash ();
524
+ m_node.mempool ->addUnchecked (entry.Fee (0 ).SpendsCoinbase (false ).FromTx (tx));
525
+ m_node.mempool ->PrioritiseTransaction (hashFreeChild, 1 * COIN);
526
+
527
+ tx.vin [0 ].prevout .hash = hashFreeChild;
528
+ tx.vout [0 ].nValue = 5000000000LL ; // 0 fee
529
+ uint256 hashFreeGrandchild = tx.GetHash ();
530
+ m_node.mempool ->addUnchecked (entry.Fee (0 ).SpendsCoinbase (false ).FromTx (tx));
531
+
532
+ auto pblocktemplate = AssemblerForTest (chainparams).CreateNewBlock (scriptPubKey);
533
+ BOOST_REQUIRE_EQUAL (pblocktemplate->block .vtx .size (), 6U );
534
+ BOOST_CHECK (pblocktemplate->block .vtx [1 ]->GetHash () == hashFreeParent);
535
+ BOOST_CHECK (pblocktemplate->block .vtx [2 ]->GetHash () == hashFreePrioritisedTx);
536
+ BOOST_CHECK (pblocktemplate->block .vtx [3 ]->GetHash () == hashParentTx);
537
+ BOOST_CHECK (pblocktemplate->block .vtx [4 ]->GetHash () == hashPrioritsedChild);
538
+ BOOST_CHECK (pblocktemplate->block .vtx [5 ]->GetHash () == hashFreeChild);
539
+ for (size_t i=0 ; i<pblocktemplate->block .vtx .size (); ++i) {
540
+ // The FreeParent and FreeChild's prioritisations should not impact the child.
541
+ BOOST_CHECK (pblocktemplate->block .vtx [i]->GetHash () != hashFreeGrandchild);
542
+ // De-prioritised transaction should not be included.
543
+ BOOST_CHECK (pblocktemplate->block .vtx [i]->GetHash () != hashMediumFeeTx);
544
+ }
545
+ }
546
+
471
547
// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
472
548
BOOST_AUTO_TEST_CASE (CreateNewBlock_validity)
473
549
{
@@ -522,6 +598,12 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
522
598
523
599
TestPackageSelection (chainparams, scriptPubKey, txFirst);
524
600
601
+ m_node.chainman ->ActiveChain ().Tip ()->nHeight --;
602
+ SetMockTime (0 );
603
+ m_node.mempool ->clear ();
604
+
605
+ TestPrioritisedMining (chainparams, scriptPubKey, txFirst);
606
+
525
607
fCheckpointsEnabled = true ;
526
608
}
527
609
0 commit comments