Page MenuHomePhabricator

D12953.id37466.diff
No OneTemporary

D12953.id37466.diff

diff --git a/src/node/miner.h b/src/node/miner.h
--- a/src/node/miner.h
+++ b/src/node/miner.h
@@ -123,7 +123,7 @@
explicit update_for_parent_inclusion(CTxMemPool::txiter it) : iter(it) {}
void operator()(CTxMemPoolModifiedEntry &e) {
- e.nModFeesWithAncestors -= iter->GetFee();
+ e.nModFeesWithAncestors -= iter->GetModifiedFee();
e.nSizeWithAncestors -= iter->GetTxSize();
e.nSigChecksWithAncestors -= iter->GetSigChecks();
}
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -40,6 +40,14 @@
const CScript &scriptPubKey,
const std::vector<CTransactionRef> &txFirst)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
+ void TestBasicMining(const Config &config, const CScript &scriptPubKey,
+ const std::vector<CTransactionRef> &txFirst,
+ int baseheight)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
+ void TestPrioritisedMining(const CChainParams &chainparams,
+ const CScript &scriptPubKey,
+ const std::vector<CTransactionRef> &txFirst)
+ EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs);
bool TestSequenceLocks(const CTransaction &tx)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_node.mempool->cs) {
CCoinsViewMemPool view_mempool(
@@ -274,75 +282,19 @@
*m_node.chainman);
}
-// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
-BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) {
- // Note that by default, these tests run with size accounting enabled.
- GlobalConfig config;
+void MinerTestingSetup::TestBasicMining(
+ const Config &config, const CScript &scriptPubKey,
+ const std::vector<CTransactionRef> &txFirst, int baseheight) {
const CChainParams &chainparams = config.GetChainParams();
- CScript scriptPubKey =
- CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
- "a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
- "de5c384df7ba0b8d578a4c702b6bf11d5f")
- << OP_CHECKSIG;
- std::unique_ptr<CBlockTemplate> pblocktemplate;
CMutableTransaction tx;
- CScript script;
TestMemPoolEntryHelper entry;
entry.nFee = 11 * SATOSHI;
entry.nHeight = 11;
- fCheckpointsEnabled = false;
-
- // Simple block creation, nothing special yet:
- BOOST_CHECK(pblocktemplate =
- AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
-
- // We can't make transactions until we have inputs.
- // Therefore, load 110 blocks :)
- static_assert(std::size(blockinfo) == 110,
- "Should have 110 blocks to import");
- int baseheight = 0;
- std::vector<CTransactionRef> txFirst;
- for (const auto &bi : blockinfo) {
- // pointer for convenience
- CBlock *pblock = &pblocktemplate->block;
- {
- LOCK(cs_main);
- pblock->nVersion = 1;
- pblock->nTime =
- m_node.chainman->ActiveTip()->GetMedianTimePast() + 1;
- CMutableTransaction txCoinbase(*pblock->vtx[0]);
- txCoinbase.nVersion = 1;
- txCoinbase.vin[0].scriptSig = CScript();
- txCoinbase.vin[0].scriptSig.push_back(bi.extranonce);
- txCoinbase.vin[0].scriptSig.push_back(
- m_node.chainman->ActiveHeight());
- txCoinbase.vout.resize(1);
- txCoinbase.vout[0].scriptPubKey = CScript();
- pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
- if (txFirst.size() == 0) {
- baseheight = m_node.chainman->ActiveHeight();
- }
- if (txFirst.size() < 4) {
- txFirst.push_back(pblock->vtx[0]);
- }
- pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
- pblock->nNonce = bi.nonce;
- }
- std::shared_ptr<const CBlock> shared_pblock =
- std::make_shared<const CBlock>(*pblock);
- BOOST_CHECK(
- Assert(m_node.chainman)
- ->ProcessNewBlock(config, shared_pblock, true, nullptr));
- pblock->hashPrevBlock = pblock->GetHash();
- }
-
- LOCK(cs_main);
- LOCK(m_node.mempool->cs);
-
// Just to make sure we can still make simple blocks.
- BOOST_CHECK(pblocktemplate =
- AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+ auto pblocktemplate =
+ AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ BOOST_CHECK(pblocktemplate);
const Amount BLOCKSUBSIDY = 50 * COIN;
const Amount LOWFEE = CENT;
@@ -473,7 +425,7 @@
tx.vin[0].prevout = COutPoint(txFirst[0]->GetId(), 0);
tx.vin[0].scriptSig = CScript() << OP_1;
tx.vout[0].nValue = BLOCKSUBSIDY - LOWFEE;
- script = CScript() << OP_0;
+ CScript script = CScript() << OP_0;
tx.vout[0].scriptPubKey = GetScriptForDestination(ScriptHash(script));
txid = tx.GetId();
m_node.mempool->addUnchecked(
@@ -693,6 +645,170 @@
BOOST_CHECK(pblocktemplate =
AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5UL);
+}
+
+void MinerTestingSetup::TestPrioritisedMining(
+ const CChainParams &chainparams, const CScript &scriptPubKey,
+ const std::vector<CTransactionRef> &txFirst) {
+ TestMemPoolEntryHelper entry;
+
+ // Test that a tx below min fee but prioritised is included
+ CMutableTransaction tx;
+ tx.vin.resize(1);
+ tx.vin[0].prevout = COutPoint{txFirst[0]->GetId(), 0};
+ tx.vin[0].scriptSig = CScript() << OP_1;
+ tx.vout.resize(1);
+ // 0 fee
+ tx.vout[0].nValue = 5000000000 * SATOSHI;
+ const TxId hashFreePrioritisedTx = tx.GetId();
+ m_node.mempool->addUnchecked(entry.Fee(Amount::zero())
+ .Time(GetTime())
+ .SpendsCoinbase(true)
+ .FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashFreePrioritisedTx, 5 * COIN);
+
+ // This tx has a low fee: 1000 satoshis
+ tx.vin[0].prevout = COutPoint{txFirst[1]->GetId(), 0};
+ tx.vout[0].nValue = (5000000000 - 1000) * SATOSHI;
+ // save this txid for later use
+ const TxId hashParentTx = tx.GetId();
+ m_node.mempool->addUnchecked(entry.Fee(1000 * SATOSHI)
+ .Time(GetTime())
+ .SpendsCoinbase(true)
+ .FromTx(tx));
+
+ // This tx has a medium fee: 10000 satoshis
+ tx.vin[0].prevout = COutPoint{txFirst[2]->GetId(), 0};
+ tx.vout[0].nValue = (5000000000 - 10000) * SATOSHI;
+ const TxId hashMediumFeeTx = tx.GetId();
+ m_node.mempool->addUnchecked(entry.Fee(10000 * SATOSHI)
+ .Time(GetTime())
+ .SpendsCoinbase(true)
+ .FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashMediumFeeTx, -5 * COIN);
+
+ // This tx also has a low fee, but is prioritised
+ tx.vin[0].prevout = COutPoint{hashParentTx, 0};
+ // 1000 satoshi fee
+ tx.vout[0].nValue = (5000000000 - 1000 - 1000) * SATOSHI;
+ const TxId hashPrioritsedChild = tx.GetId();
+ m_node.mempool->addUnchecked(entry.Fee(1000 * SATOSHI)
+ .Time(GetTime())
+ .SpendsCoinbase(false)
+ .FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashPrioritsedChild, 2 * COIN);
+
+ // Test that transaction selection properly updates ancestor fee
+ // calculations as prioritised parents get included in a block. Create a
+ // transaction with two prioritised ancestors, each included by itself:
+ // FreeParent <- FreeChild <- FreeGrandchild. When FreeParent is added, a
+ // modified entry will be created for FreeChild + FreeGrandchild
+ // FreeParent's prioritisation should not be included in that entry.
+ // When FreeChild is included, FreeChild's prioritisation should also not be
+ // included.
+ tx.vin[0].prevout = COutPoint{txFirst[3]->GetId(), 0};
+ // 0 fee
+ tx.vout[0].nValue = 5000000000 * SATOSHI;
+ const TxId hashFreeParent = tx.GetId();
+ m_node.mempool->addUnchecked(
+ entry.Fee(Amount::zero()).SpendsCoinbase(true).FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashFreeParent, 10 * COIN);
+
+ tx.vin[0].prevout = COutPoint{hashFreeParent, 0};
+ // 0 fee
+ tx.vout[0].nValue = 5000000000 * SATOSHI;
+ const TxId hashFreeChild = tx.GetId();
+ m_node.mempool->addUnchecked(
+ entry.Fee(Amount::zero()).SpendsCoinbase(false).FromTx(tx));
+ m_node.mempool->PrioritiseTransaction(hashFreeChild, 1 * COIN);
+
+ tx.vin[0].prevout = COutPoint{hashFreeChild, 0};
+ // 0 fee
+ tx.vout[0].nValue = 5000000000 * SATOSHI;
+ const TxId hashFreeGrandchild = tx.GetId();
+ m_node.mempool->addUnchecked(
+ entry.Fee(Amount::zero()).SpendsCoinbase(false).FromTx(tx));
+
+ auto pblocktemplate =
+ AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey);
+ BOOST_REQUIRE_EQUAL(pblocktemplate->block.vtx.size(), 6U);
+ BOOST_CHECK(pblocktemplate->block.vtx[1]->GetId() == hashFreeParent);
+ BOOST_CHECK(pblocktemplate->block.vtx[2]->GetId() == hashFreePrioritisedTx);
+ BOOST_CHECK(pblocktemplate->block.vtx[3]->GetId() == hashParentTx);
+ BOOST_CHECK(pblocktemplate->block.vtx[4]->GetId() == hashPrioritsedChild);
+ BOOST_CHECK(pblocktemplate->block.vtx[5]->GetId() == hashFreeChild);
+ for (size_t i = 0; i < pblocktemplate->block.vtx.size(); ++i) {
+ // The FreeParent and FreeChild's prioritisations should not impact the
+ // child.
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() !=
+ hashFreeGrandchild);
+ // De-prioritised transaction should not be included.
+ BOOST_CHECK(pblocktemplate->block.vtx[i]->GetId() != hashMediumFeeTx);
+ }
+}
+
+// NOTE: These tests rely on CreateNewBlock doing its own self-validation!
+BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) {
+ // Note that by default, these tests run with size accounting enabled.
+ GlobalConfig config;
+ const CChainParams &chainparams = config.GetChainParams();
+ CScript scriptPubKey =
+ CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909"
+ "a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112"
+ "de5c384df7ba0b8d578a4c702b6bf11d5f")
+ << OP_CHECKSIG;
+ std::unique_ptr<CBlockTemplate> pblocktemplate;
+
+ fCheckpointsEnabled = false;
+
+ // Simple block creation, nothing special yet:
+ BOOST_CHECK(pblocktemplate =
+ AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey));
+
+ // We can't make transactions until we have inputs.
+ // Therefore, load 110 blocks :)
+ static_assert(std::size(blockinfo) == 110,
+ "Should have 110 blocks to import");
+ int baseheight = 0;
+ std::vector<CTransactionRef> txFirst;
+ for (const auto &bi : blockinfo) {
+ // pointer for convenience
+ CBlock *pblock = &pblocktemplate->block;
+ {
+ LOCK(cs_main);
+ pblock->nVersion = 1;
+ pblock->nTime =
+ m_node.chainman->ActiveTip()->GetMedianTimePast() + 1;
+ CMutableTransaction txCoinbase(*pblock->vtx[0]);
+ txCoinbase.nVersion = 1;
+ txCoinbase.vin[0].scriptSig = CScript();
+ txCoinbase.vin[0].scriptSig.push_back(bi.extranonce);
+ txCoinbase.vin[0].scriptSig.push_back(
+ m_node.chainman->ActiveHeight());
+ txCoinbase.vout.resize(1);
+ txCoinbase.vout[0].scriptPubKey = CScript();
+ pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
+ if (txFirst.size() == 0) {
+ baseheight = m_node.chainman->ActiveHeight();
+ }
+ if (txFirst.size() < 4) {
+ txFirst.push_back(pblock->vtx[0]);
+ }
+ pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
+ pblock->nNonce = bi.nonce;
+ }
+ std::shared_ptr<const CBlock> shared_pblock =
+ std::make_shared<const CBlock>(*pblock);
+ BOOST_CHECK(
+ Assert(m_node.chainman)
+ ->ProcessNewBlock(config, shared_pblock, true, nullptr));
+ pblock->hashPrevBlock = pblock->GetHash();
+ }
+
+ LOCK(cs_main);
+ LOCK(m_node.mempool->cs);
+
+ TestBasicMining(config, scriptPubKey, txFirst, baseheight);
m_node.chainman->ActiveTip()->nHeight--;
SetMockTime(0);
@@ -700,6 +816,12 @@
TestPackageSelection(chainparams, scriptPubKey, txFirst);
+ m_node.chainman->ActiveChain().Tip()->nHeight--;
+ SetMockTime(0);
+ m_node.mempool->clear();
+
+ TestPrioritisedMining(chainparams, scriptPubKey, txFirst);
+
fCheckpointsEnabled = true;
}

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 26, 11:16 (11 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573382
Default Alt Text
D12953.id37466.diff (13 KB)

Event Timeline