diff --git a/src/miner.h b/src/miner.h --- a/src/miner.h +++ b/src/miner.h @@ -36,12 +36,14 @@ CTxMemPoolModifiedEntry(CTxMemPool::txiter entry) { iter = entry; nSizeWithAncestors = entry->GetSizeWithAncestors(); + nBillableSizeWithAncestors = entry->GetBillableSizeWithAncestors(); nModFeesWithAncestors = entry->GetModFeesWithAncestors(); nSigOpCountWithAncestors = entry->GetSigOpCountWithAncestors(); } CTxMemPool::txiter iter; uint64_t nSizeWithAncestors; + uint64_t nBillableSizeWithAncestors; Amount nModFeesWithAncestors; int64_t nSigOpCountWithAncestors; }; @@ -118,6 +120,7 @@ void operator()(CTxMemPoolModifiedEntry &e) { e.nModFeesWithAncestors -= iter->GetFee(); e.nSizeWithAncestors -= iter->GetTxSize(); + e.nBillableSizeWithAncestors -= iter->GetTxBillableSize(); e.nSigOpCountWithAncestors -= iter->GetSigOpCount(); } diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -380,6 +380,7 @@ if (mit == mapModifiedTx.end()) { CTxMemPoolModifiedEntry modEntry(desc); modEntry.nSizeWithAncestors -= it->GetTxSize(); + modEntry.nBillableSizeWithAncestors -= it->GetTxBillableSize(); modEntry.nModFeesWithAncestors -= it->GetModifiedFee(); modEntry.nSigOpCountWithAncestors -= it->GetSigOpCount(); mapModifiedTx.insert(modEntry); @@ -500,15 +501,18 @@ assert(!inBlock.count(iter)); uint64_t packageSize = iter->GetSizeWithAncestors(); + uint64_t packageBillableSize = iter->GetBillableSizeWithAncestors(); + Amount packageFees = iter->GetModFeesWithAncestors(); int64_t packageSigOps = iter->GetSigOpCountWithAncestors(); if (fUsingModified) { packageSize = modit->nSizeWithAncestors; + packageBillableSize = modit->nBillableSizeWithAncestors; packageFees = modit->nModFeesWithAncestors; packageSigOps = modit->nSigOpCountWithAncestors; } - if (packageFees < blockMinFeeRate.GetFee(packageSize)) { + if (packageFees < blockMinFeeRate.GetFee(packageBillableSize)) { // Everything else we might consider has a lower fee rate return; } diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -323,8 +323,8 @@ sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin() + 2); sortedOrder.insert(sortedOrder.begin() + 5, tx9.GetId().ToString()); sortedOrder.insert(sortedOrder.begin() + 6, tx8.GetId().ToString()); - // tx10 is just before tx6 - sortedOrder.insert(sortedOrder.begin() + 7, tx10.GetId().ToString()); + // tx10 is before tx7 + sortedOrder.insert(sortedOrder.begin() + 8, tx10.GetId().ToString()); CheckSort(pool, sortedOrder, "MempoolIndexingTest6"); // there should be 10 transactions in the mempool @@ -466,7 +466,7 @@ // CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true); pool.addUnchecked(tx7.GetId(), entry.Fee(Amount(fee)).FromTx(tx7)); BOOST_CHECK_EQUAL(pool.size(), 7UL); - sortedOrder.insert(sortedOrder.begin() + 1, tx7.GetId().ToString()); + sortedOrder.insert(sortedOrder.begin(), tx7.GetId().ToString()); CheckSort(pool, sortedOrder, "MempoolAncestorIndexingTest3"); @@ -475,7 +475,7 @@ vtx.push_back(MakeTransactionRef(tx6)); pool.removeForBlock(vtx, 1); - sortedOrder.erase(sortedOrder.begin() + 1); + sortedOrder.erase(sortedOrder.begin()); // Ties are broken by hash if (tx3.GetId() < tx6.GetId()) sortedOrder.pop_back(); 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 @@ -137,7 +137,7 @@ tx.vout[0].nValue = Amount(5000000000LL - 1000 - 50000); TxId freeTxId = tx.GetId(); mempool.addUnchecked(freeTxId, entry.Fee(Amount(0)).FromTx(tx)); - size_t freeTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + size_t freeTxSize = CTransaction(tx).GetBillableSize(); // Calculate a fee on child transaction that will put the package just // below the block min tx fee (assuming 1 child tx of the same size). diff --git a/src/txmempool.h b/src/txmempool.h --- a/src/txmempool.h +++ b/src/txmempool.h @@ -119,12 +119,15 @@ uint64_t nCountWithDescendants; //!< ... and size uint64_t nSizeWithDescendants; + uint64_t nBillableSizeWithDescendants; + //!< ... and total fees (all including us) Amount nModFeesWithDescendants; // Analogous statistics for ancestor transactions uint64_t nCountWithAncestors; uint64_t nSizeWithAncestors; + uint64_t nBillableSizeWithAncestors; Amount nModFeesWithAncestors; int64_t nSigOpCountWithAncestors; @@ -155,11 +158,12 @@ const LockPoints &GetLockPoints() const { return lockPoints; } // Adjusts the descendant state, if this entry is not dirty. - void UpdateDescendantState(int64_t modifySize, Amount modifyFee, - int64_t modifyCount); + void UpdateDescendantState(int64_t modifySize, int64_t modifyBillableSize, + Amount modifyFee, int64_t modifyCount); // Adjusts the ancestor state - void UpdateAncestorState(int64_t modifySize, Amount modifyFee, - int64_t modifyCount, int modifySigOps); + void UpdateAncestorState(int64_t modifySize, int64_t modifyBillableSize, + Amount modifyFee, int64_t modifyCount, + int modifySigOps); // Updates the fee delta used for mining priority score, and the // modified fees with descendants. void UpdateFeeDelta(Amount feeDelta); @@ -168,12 +172,18 @@ uint64_t GetCountWithDescendants() const { return nCountWithDescendants; } uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; } + uint64_t GetBillableSizeWithDescendants() const { + return nBillableSizeWithDescendants; + } Amount GetModFeesWithDescendants() const { return nModFeesWithDescendants; } bool GetSpendsCoinbase() const { return spendsCoinbase; } uint64_t GetCountWithAncestors() const { return nCountWithAncestors; } uint64_t GetSizeWithAncestors() const { return nSizeWithAncestors; } + uint64_t GetBillableSizeWithAncestors() const { + return nBillableSizeWithAncestors; + } Amount GetModFeesWithAncestors() const { return nModFeesWithAncestors; } int64_t GetSigOpCountWithAncestors() const { return nSigOpCountWithAncestors; @@ -185,34 +195,39 @@ // Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index. struct update_descendant_state { - update_descendant_state(int64_t _modifySize, Amount _modifyFee, - int64_t _modifyCount) - : modifySize(_modifySize), modifyFee(_modifyFee), - modifyCount(_modifyCount) {} + update_descendant_state(int64_t _modifySize, int64_t _modifyBillableSize, + Amount _modifyFee, int64_t _modifyCount) + : modifySize(_modifySize), modifyBillableSize(_modifyBillableSize), + modifyFee(_modifyFee), modifyCount(_modifyCount) {} void operator()(CTxMemPoolEntry &e) { - e.UpdateDescendantState(modifySize, modifyFee, modifyCount); + e.UpdateDescendantState(modifySize, modifyBillableSize, modifyFee, + modifyCount); } private: int64_t modifySize; + int64_t modifyBillableSize; Amount modifyFee; int64_t modifyCount; }; struct update_ancestor_state { - update_ancestor_state(int64_t _modifySize, Amount _modifyFee, - int64_t _modifyCount, int64_t _modifySigOpsCost) - : modifySize(_modifySize), modifyFee(_modifyFee), - modifyCount(_modifyCount), modifySigOpsCost(_modifySigOpsCost) {} + update_ancestor_state(int64_t _modifySize, int64_t _modifyBillableSize, + Amount _modifyFee, int64_t _modifyCount, + int64_t _modifySigOpsCost) + : modifySize(_modifySize), modifyBillableSize(_modifyBillableSize), + modifyFee(_modifyFee), modifyCount(_modifyCount), + modifySigOpsCost(_modifySigOpsCost) {} void operator()(CTxMemPoolEntry &e) { - e.UpdateAncestorState(modifySize, modifyFee, modifyCount, - modifySigOpsCost); + e.UpdateAncestorState(modifySize, modifyBillableSize, modifyFee, + modifyCount, modifySigOpsCost); } private: int64_t modifySize; + int64_t modifyBillableSize; Amount modifyFee; int64_t modifyCount; int64_t modifySigOpsCost; @@ -262,14 +277,14 @@ double aModFee = (fUseADescendants ? a.GetModFeesWithDescendants() : a.GetModifiedFee()) / SATOSHI; - double aSize = - fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize(); + double aSize = fUseADescendants ? a.GetBillableSizeWithDescendants() + : a.GetTxBillableSize(); double bModFee = (fUseBDescendants ? b.GetModFeesWithDescendants() : b.GetModifiedFee()) / SATOSHI; - double bSize = - fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize(); + double bSize = fUseBDescendants ? b.GetBillableSizeWithDescendants() + : b.GetTxBillableSize(); // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). double f1 = aModFee * bSize; @@ -283,8 +298,10 @@ // Calculate which score to use for an entry (avoiding division). bool UseDescendantScore(const CTxMemPoolEntry &a) const { - double f1 = a.GetSizeWithDescendants() * (a.GetModifiedFee() / SATOSHI); - double f2 = a.GetTxSize() * (a.GetModFeesWithDescendants() / SATOSHI); + double f1 = + a.GetBillableSizeWithDescendants() * (a.GetModifiedFee() / SATOSHI); + double f2 = + a.GetTxBillableSize() * (a.GetModFeesWithDescendants() / SATOSHI); return f2 > f1; } }; @@ -296,8 +313,8 @@ class CompareTxMemPoolEntryByScore { public: bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const { - double f1 = b.GetTxSize() * (a.GetModifiedFee() / SATOSHI); - double f2 = a.GetTxSize() * (b.GetModifiedFee() / SATOSHI); + double f1 = b.GetTxBillableSize() * (a.GetModifiedFee() / SATOSHI); + double f2 = a.GetTxBillableSize() * (b.GetModifiedFee() / SATOSHI); if (f1 == f2) { return b.GetTx().GetId() < a.GetTx().GetId(); } @@ -316,10 +333,10 @@ public: bool operator()(const CTxMemPoolEntry &a, const CTxMemPoolEntry &b) const { double aFees = a.GetModFeesWithAncestors() / SATOSHI; - double aSize = a.GetSizeWithAncestors(); + double aSize = a.GetBillableSizeWithAncestors(); double bFees = b.GetModFeesWithAncestors() / SATOSHI; - double bSize = b.GetSizeWithAncestors(); + double bSize = b.GetBillableSizeWithAncestors(); // Avoid division by rewriting (a/b > c/d) as (a*d > c*b). double f1 = aFees * bSize; diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -38,6 +38,7 @@ nCountWithDescendants = 1; nSizeWithDescendants = GetTxSize(); + nBillableSizeWithDescendants = GetTxBillableSize(); nModFeesWithDescendants = nFee; Amount nValueIn = tx->GetValueOut() + nFee; assert(inChainInputValue <= nValueIn); @@ -46,6 +47,7 @@ nCountWithAncestors = 1; nSizeWithAncestors = GetTxSize(); + nBillableSizeWithAncestors = GetTxBillableSize(); nModFeesWithAncestors = nFee; nSigOpCountWithAncestors = sigOpCount; } @@ -107,23 +109,27 @@ // setAllDescendants now contains all in-mempool descendants of updateIt. // Update and add to cached descendant map int64_t modifySize = 0; + int64_t modifyBillableSize = 0; Amount modifyFee(0); int64_t modifyCount = 0; for (txiter cit : setAllDescendants) { if (!setExclude.count(cit->GetTx().GetId())) { modifySize += cit->GetTxSize(); + modifyBillableSize += cit->GetTxBillableSize(); modifyFee += cit->GetModifiedFee(); modifyCount++; cachedDescendants[updateIt].insert(cit); // Update ancestor state for each descendant mapTx.modify(cit, update_ancestor_state(updateIt->GetTxSize(), + updateIt->GetTxBillableSize(), updateIt->GetModifiedFee(), 1, updateIt->GetSigOpCount())); } } mapTx.modify(updateIt, - update_descendant_state(modifySize, modifyFee, modifyCount)); + update_descendant_state(modifySize, modifyBillableSize, + modifyFee, modifyCount)); } // vHashesToUpdate is the set of transaction hashes from a disconnected block @@ -270,10 +276,12 @@ } const int64_t updateCount = (add ? 1 : -1); const int64_t updateSize = updateCount * it->GetTxSize(); + const int64_t updateBillableSize = updateCount * it->GetTxBillableSize(); const Amount updateFee = updateCount * it->GetModifiedFee(); for (txiter ancestorIt : setAncestors) { - mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, - updateCount)); + mapTx.modify(ancestorIt, + update_descendant_state(updateSize, updateBillableSize, + updateFee, updateCount)); } } @@ -281,14 +289,18 @@ const setEntries &setAncestors) { int64_t updateCount = setAncestors.size(); int64_t updateSize = 0; + int64_t updateBillableSize = 0; + Amount updateFee(0); int64_t updateSigOpsCount = 0; for (txiter ancestorIt : setAncestors) { updateSize += ancestorIt->GetTxSize(); + updateBillableSize += ancestorIt->GetTxBillableSize(); updateFee += ancestorIt->GetModifiedFee(); updateSigOpsCount += ancestorIt->GetSigOpCount(); } - mapTx.modify(it, update_ancestor_state(updateSize, updateFee, updateCount, + mapTx.modify(it, update_ancestor_state(updateSize, updateBillableSize, + updateFee, updateCount, updateSigOpsCount)); } @@ -314,12 +326,15 @@ setEntries setDescendants; CalculateDescendants(removeIt, setDescendants); setDescendants.erase(removeIt); // don't update state for self - int64_t modifySize = -((int64_t)removeIt->GetTxSize()); + int64_t modifySize = -int64_t(removeIt->GetTxSize()); + int64_t modifyBillableSize = + -int64_t(removeIt->GetTxBillableSize()); Amount modifyFee = -1 * removeIt->GetModifiedFee(); int modifySigOps = -removeIt->GetSigOpCount(); for (txiter dit : setDescendants) { - mapTx.modify(dit, update_ancestor_state(modifySize, modifyFee, - -1, modifySigOps)); + mapTx.modify( + dit, update_ancestor_state(modifySize, modifyBillableSize, + modifyFee, -1, modifySigOps)); } } } @@ -360,20 +375,26 @@ } void CTxMemPoolEntry::UpdateDescendantState(int64_t modifySize, + int64_t modifyBillableSize, Amount modifyFee, int64_t modifyCount) { nSizeWithDescendants += modifySize; assert(int64_t(nSizeWithDescendants) > 0); + nBillableSizeWithDescendants += modifyBillableSize; + assert(int64_t(nBillableSizeWithDescendants) >= 0); nModFeesWithDescendants += modifyFee; nCountWithDescendants += modifyCount; assert(int64_t(nCountWithDescendants) > 0); } -void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, Amount modifyFee, - int64_t modifyCount, +void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, + int64_t modifyBillableSize, + Amount modifyFee, int64_t modifyCount, int modifySigOps) { nSizeWithAncestors += modifySize; assert(int64_t(nSizeWithAncestors) > 0); + nBillableSizeWithAncestors += modifyBillableSize; + assert(int64_t(nBillableSizeWithAncestors) >= 0); nModFeesWithAncestors += modifyFee; nCountWithAncestors += modifyCount; assert(int64_t(nCountWithAncestors) > 0); @@ -998,7 +1019,7 @@ nNoLimit, nNoLimit, dummy, false); for (txiter ancestorIt : setAncestors) { mapTx.modify(ancestorIt, - update_descendant_state(0, nFeeDelta, 0)); + update_descendant_state(0, 0, nFeeDelta, 0)); } // Now update all descendants' modified fees with ancestors @@ -1007,7 +1028,7 @@ setDescendants.erase(it); for (txiter descendantIt : setDescendants) { mapTx.modify(descendantIt, - update_ancestor_state(0, nFeeDelta, 0, 0)); + update_ancestor_state(0, 0, nFeeDelta, 0, 0)); } } } @@ -1201,7 +1222,7 @@ // mempool with feerate equal to txn which were removed with no block in // between. CFeeRate removed(it->GetModFeesWithDescendants(), - it->GetSizeWithDescendants()); + it->GetBillableSizeWithDescendants()); removed += MEMPOOL_FULL_FEE_INCREMENT; trackPackageRemoved(removed);