@@ -30,6 +30,8 @@ using node::CBlockTemplate;
30
30
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
+ 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);
33
35
bool TestSequenceLocks (const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs)
34
36
{
35
37
CCoinsViewMemPool view_mempool (&m_node.chainman ->ActiveChainstate ().CoinsTip (), *m_node.mempool );
@@ -191,60 +193,17 @@ void MinerTestingSetup::TestPackageSelection(const CChainParams& chainparams, co
191
193
BOOST_CHECK (pblocktemplate->block .vtx [8 ]->GetHash () == hashLowFeeTx2);
192
194
}
193
195
194
- // NOTE: These tests rely on CreateNewBlock doing its own self-validation!
195
- BOOST_AUTO_TEST_CASE (CreateNewBlock_validity)
196
+ void MinerTestingSetup::TestBasicMining (const CChainParams& chainparams, const CScript& scriptPubKey, const std::vector<CTransactionRef>& txFirst, int baseheight)
196
197
{
197
- // Note that by default, these tests run with size accounting enabled.
198
- const auto chainParams = CreateChainParams (*m_node.args , CBaseChainParams::MAIN);
199
- const CChainParams& chainparams = *chainParams;
200
- CScript scriptPubKey = CScript () << ParseHex (" 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f" ) << OP_CHECKSIG;
201
- std::unique_ptr<CBlockTemplate> pblocktemplate;
202
- CMutableTransaction tx;
203
- CScript script;
204
198
uint256 hash;
199
+ CMutableTransaction tx;
205
200
TestMemPoolEntryHelper entry;
206
201
entry.nFee = 11 ;
207
202
entry.nHeight = 11 ;
208
203
209
- fCheckpointsEnabled = false ;
210
-
211
- // Simple block creation, nothing special yet:
212
- BOOST_CHECK (pblocktemplate = AssemblerForTest (chainparams).CreateNewBlock (scriptPubKey));
213
-
214
- // We can't make transactions until we have inputs
215
- // Therefore, load 110 blocks :)
216
- static_assert (std::size (BLOCKINFO) == 110 , " Should have 110 blocks to import" );
217
- int baseheight = 0 ;
218
- std::vector<CTransactionRef> txFirst;
219
- for (const auto & bi : BLOCKINFO) {
220
- CBlock *pblock = &pblocktemplate->block ; // pointer for convenience
221
- {
222
- LOCK (cs_main);
223
- pblock->nVersion = VERSIONBITS_TOP_BITS;
224
- pblock->nTime = m_node.chainman ->ActiveChain ().Tip ()->GetMedianTimePast ()+1 ;
225
- CMutableTransaction txCoinbase (*pblock->vtx [0 ]);
226
- txCoinbase.nVersion = 1 ;
227
- txCoinbase.vin [0 ].scriptSig = CScript{} << (m_node.chainman ->ActiveChain ().Height () + 1 ) << bi.extranonce ;
228
- txCoinbase.vout .resize (1 ); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
229
- txCoinbase.vout [0 ].scriptPubKey = CScript ();
230
- pblock->vtx [0 ] = MakeTransactionRef (std::move (txCoinbase));
231
- if (txFirst.size () == 0 )
232
- baseheight = m_node.chainman ->ActiveChain ().Height ();
233
- if (txFirst.size () < 4 )
234
- txFirst.push_back (pblock->vtx [0 ]);
235
- pblock->hashMerkleRoot = BlockMerkleRoot (*pblock);
236
- pblock->nNonce = bi.nonce ;
237
- }
238
- std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
239
- BOOST_CHECK (Assert (m_node.chainman )->ProcessNewBlock (chainparams, shared_pblock, true , nullptr ));
240
- pblock->hashPrevBlock = pblock->GetHash ();
241
- }
242
-
243
- LOCK (cs_main);
244
- LOCK (m_node.mempool ->cs );
245
-
246
204
// Just to make sure we can still make simple blocks
247
- BOOST_CHECK (pblocktemplate = AssemblerForTest (chainparams).CreateNewBlock (scriptPubKey));
205
+ auto pblocktemplate = AssemblerForTest (chainparams).CreateNewBlock (scriptPubKey);
206
+ BOOST_CHECK (pblocktemplate);
248
207
249
208
const CAmount BLOCKSUBSIDY = 50 *COIN;
250
209
const CAmount LOWFEE = CENT;
@@ -386,7 +345,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
386
345
tx.vin [0 ].prevout .n = 0 ;
387
346
tx.vin [0 ].scriptSig = CScript () << OP_1;
388
347
tx.vout [0 ].nValue = BLOCKSUBSIDY-LOWFEE;
389
- script = CScript () << OP_0;
348
+ CScript script = CScript () << OP_0;
390
349
tx.vout [0 ].scriptPubKey = GetScriptForDestination (ScriptHash (script));
391
350
hash = tx.GetHash ();
392
351
m_node.mempool ->addUnchecked (entry.Fee (LOWFEE).Time (GetTime ()).SpendsCoinbase (true ).FromTx (tx));
@@ -508,13 +467,143 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
508
467
509
468
BOOST_CHECK (pblocktemplate = AssemblerForTest (chainparams).CreateNewBlock (scriptPubKey));
510
469
BOOST_CHECK_EQUAL (pblocktemplate->block .vtx .size (), 5U );
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
+
547
+ // NOTE: These tests rely on CreateNewBlock doing its own self-validation!
548
+ BOOST_AUTO_TEST_CASE (CreateNewBlock_validity)
549
+ {
550
+ // Note that by default, these tests run with size accounting enabled.
551
+ const auto chainParams = CreateChainParams (*m_node.args , CBaseChainParams::MAIN);
552
+ const CChainParams& chainparams = *chainParams;
553
+ CScript scriptPubKey = CScript () << ParseHex (" 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f" ) << OP_CHECKSIG;
554
+ std::unique_ptr<CBlockTemplate> pblocktemplate;
555
+
556
+ fCheckpointsEnabled = false ;
557
+
558
+ // Simple block creation, nothing special yet:
559
+ BOOST_CHECK (pblocktemplate = AssemblerForTest (chainparams).CreateNewBlock (scriptPubKey));
560
+
561
+ // We can't make transactions until we have inputs
562
+ // Therefore, load 110 blocks :)
563
+ static_assert (std::size (BLOCKINFO) == 110 , " Should have 110 blocks to import" );
564
+ int baseheight = 0 ;
565
+ std::vector<CTransactionRef> txFirst;
566
+ for (const auto & bi : BLOCKINFO) {
567
+ CBlock *pblock = &pblocktemplate->block ; // pointer for convenience
568
+ {
569
+ LOCK (cs_main);
570
+ pblock->nVersion = VERSIONBITS_TOP_BITS;
571
+ pblock->nTime = m_node.chainman ->ActiveChain ().Tip ()->GetMedianTimePast ()+1 ;
572
+ CMutableTransaction txCoinbase (*pblock->vtx [0 ]);
573
+ txCoinbase.nVersion = 1 ;
574
+ txCoinbase.vin [0 ].scriptSig = CScript{} << (m_node.chainman ->ActiveChain ().Height () + 1 ) << bi.extranonce ;
575
+ txCoinbase.vout .resize (1 ); // Ignore the (optional) segwit commitment added by CreateNewBlock (as the hardcoded nonces don't account for this)
576
+ txCoinbase.vout [0 ].scriptPubKey = CScript ();
577
+ pblock->vtx [0 ] = MakeTransactionRef (std::move (txCoinbase));
578
+ if (txFirst.size () == 0 )
579
+ baseheight = m_node.chainman ->ActiveChain ().Height ();
580
+ if (txFirst.size () < 4 )
581
+ txFirst.push_back (pblock->vtx [0 ]);
582
+ pblock->hashMerkleRoot = BlockMerkleRoot (*pblock);
583
+ pblock->nNonce = bi.nonce ;
584
+ }
585
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
586
+ BOOST_CHECK (Assert (m_node.chainman )->ProcessNewBlock (chainparams, shared_pblock, true , nullptr ));
587
+ pblock->hashPrevBlock = pblock->GetHash ();
588
+ }
589
+
590
+ LOCK (cs_main);
591
+ LOCK (m_node.mempool ->cs );
592
+
593
+ TestBasicMining (chainparams, scriptPubKey, txFirst, baseheight);
511
594
512
595
m_node.chainman ->ActiveChain ().Tip ()->nHeight --;
513
596
SetMockTime (0 );
514
597
m_node.mempool ->clear ();
515
598
516
599
TestPackageSelection (chainparams, scriptPubKey, txFirst);
517
600
601
+ m_node.chainman ->ActiveChain ().Tip ()->nHeight --;
602
+ SetMockTime (0 );
603
+ m_node.mempool ->clear ();
604
+
605
+ TestPrioritisedMining (chainparams, scriptPubKey, txFirst);
606
+
518
607
fCheckpointsEnabled = true ;
519
608
}
520
609
0 commit comments