Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13711267
D12953.id37466.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
13 KB
Subscribers
None
D12953.id37466.diff
View Options
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
Details
Attached
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)
Attached To
D12953: miner: bug fix? update for ancestor inclusion using modified fees, not base
Event Timeline
Log In to Comment