diff --git a/src/miner.h b/src/miner.h --- a/src/miner.h +++ b/src/miner.h @@ -50,6 +50,34 @@ : tx(_tx), txFee(_fees), txSize(_size), txSigOps(_sigOps), packageOrder(0), packageFee(_fees), packageSize(_size), packageSigOps(_sigOps) {} + + /** + * Calculate the feerate for this transaction. Use the minimum of the + * package feerate, or the transaction itself. Parents TXNs should never + * end up "paying for" child transactions. + */ + CFeeRate FeeRate() const { + // In order to avoid numerical errors, we reorder to use multiplication + // instead of vision. + return int64_t(txSize) * packageFee < int64_t(packageSize) * txFee + ? CFeeRate(packageFee, packageSize) + : CFeeRate(txFee, txSize); + } + +private: + /** + * Include a parent transactions accounting into our own. + * We assume that this is used in topological order by BlockAssembler. + */ + void AccountForParent(const CBlockTemplateEntry &parent) { + packageOrder = std::max(parent.packageOrder + 1, packageOrder); + packageFee += parent.packageFee; + packageSize += parent.packageSize; + packageSigOps += parent.packageSigOps; + } + + friend class BlockAssembler; + friend struct CBlockTemplateEntryTest; }; struct CBlockTemplate { 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 @@ -28,6 +28,13 @@ #include +struct CBlockTemplateEntryTest { + static void AccountForParent(CBlockTemplateEntry &e, + const CBlockTemplateEntry &p) { + return e.AccountForParent(p); + } +}; + BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup) static CFeeRate blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE_PER_KB); @@ -781,6 +788,15 @@ BOOST_CHECK_EQUAL(txEntry.packageFee, 1 * SATOSHI); BOOST_CHECK_EQUAL(txEntry.packageSize, 200); BOOST_CHECK_EQUAL(txEntry.packageSigOps, 10); + + CBlockTemplateEntry txChildEntry(txRef, 10 * SATOSHI, 2000, 20); + CBlockTemplateEntryTest::AccountForParent(txChildEntry, txEntry); + BOOST_CHECK_EQUAL(txChildEntry.txFee, 10 * SATOSHI); + BOOST_CHECK_EQUAL(txChildEntry.txSize, 2000); + BOOST_CHECK_EQUAL(txChildEntry.txSigOps, 20); + BOOST_CHECK_EQUAL(txChildEntry.packageFee, 11 * SATOSHI); + BOOST_CHECK_EQUAL(txChildEntry.packageSize, 2200); + BOOST_CHECK_EQUAL(txChildEntry.packageSigOps, 30); } BOOST_AUTO_TEST_SUITE_END()