Page MenuHomePhabricator

D1860.diff
No OneTemporary

D1860.diff

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
@@ -390,6 +390,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);
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -300,6 +300,10 @@
// size)
unsigned int CalculateModifiedSize(unsigned int nTxSize = 0) const;
+ // Computes an adjusted tx size so that the UTXIs are billed partially
+ // upfront.
+ size_t GetBillableSize() const;
+
/**
* Get the total transaction size in bytes.
* @return Total transaction size in bytes
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -114,6 +114,10 @@
return nTxSize;
}
+size_t CTransaction::GetBillableSize() const {
+ return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
+}
+
unsigned int CTransaction::GetTotalSize() const {
return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
}
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
@@ -40,6 +40,7 @@
Amount totalFee = Amount::zero();
size_t totalSize = CTransaction(parentOfAll).GetTotalSize();
+ size_t totalBillableSize = CTransaction(parentOfAll).GetBillableSize();
// Generate 100 transactions
for (size_t totalTransactions = 0; totalTransactions < 100;
@@ -52,6 +53,8 @@
Amount maxFees = Amount::zero();
uint64_t minSize = std::numeric_limits<size_t>::max();
uint64_t maxSize = 0;
+ uint64_t minBillableSize = std::numeric_limits<size_t>::max();
+ uint64_t maxBillableSize = 0;
// Consume random inputs, but make sure we don't consume more than
// available
for (size_t input = std::min(InsecureRandRange(maxOutputs) + 1,
@@ -76,6 +79,9 @@
maxFees += parent.GetModFeesWithAncestors();
minSize = std::min(minSize, parent.GetSizeWithAncestors());
maxSize += parent.GetSizeWithAncestors();
+ minBillableSize = std::min(minBillableSize,
+ parent.GetBillableSizeWithAncestors());
+ maxBillableSize += parent.GetBillableSizeWithAncestors();
}
// Produce random number of outputs
@@ -103,10 +109,13 @@
maxFees += randFee;
minSize += CTransaction(tx).GetTotalSize();
maxSize += CTransaction(tx).GetTotalSize();
+ minBillableSize += CTransaction(tx).GetBillableSize();
+ maxBillableSize += CTransaction(tx).GetBillableSize();
// Calculate overall values
totalFee += randFee;
totalSize += CTransaction(tx).GetTotalSize();
+ totalBillableSize += CTransaction(tx).GetBillableSize();
CTxMemPoolEntry parentEntry = *testPool.mapTx.find(parentOfAllId);
CTxMemPoolEntry latestEntry = *testPool.mapTx.find(curId);
@@ -117,12 +126,19 @@
BOOST_CHECK(latestEntry.GetSizeWithAncestors() >= minSize);
BOOST_CHECK(latestEntry.GetSizeWithAncestors() <= maxSize);
+ BOOST_CHECK(latestEntry.GetBillableSizeWithAncestors() >=
+ minBillableSize);
+ BOOST_CHECK(latestEntry.GetBillableSizeWithAncestors() <=
+ maxBillableSize);
+
BOOST_CHECK(latestEntry.GetModFeesWithAncestors() >= minFees);
BOOST_CHECK(latestEntry.GetModFeesWithAncestors() <= maxFees);
BOOST_CHECK_EQUAL(parentEntry.GetCountWithDescendants(),
testPool.mapTx.size());
BOOST_CHECK_EQUAL(parentEntry.GetSizeWithDescendants(), totalSize);
+ BOOST_CHECK_EQUAL(parentEntry.GetBillableSizeWithDescendants(),
+ totalBillableSize);
BOOST_CHECK_EQUAL(parentEntry.GetModFeesWithDescendants(), totalFee);
}
}
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
@@ -139,7 +139,7 @@
tx.vout[0].nValue = int64_t(5000000000LL - 1000 - 50000) * SATOSHI;
TxId freeTxId = tx.GetId();
mempool.addUnchecked(freeTxId, entry.Fee(Amount::zero()).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/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -788,4 +788,24 @@
BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-txns-undersize");
}
+BOOST_AUTO_TEST_CASE(tx_transaction_fee) {
+ std::vector<size_t> sizes = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512};
+ for (size_t inputs : sizes) {
+ for (size_t outputs : sizes) {
+ CMutableTransaction mtx;
+ mtx.vin.resize(inputs);
+ mtx.vout.resize(outputs);
+ CTransaction tx(mtx);
+ auto txBillableSize = tx.GetBillableSize();
+ auto txSize = tx.GetTotalSize();
+ BOOST_CHECK(txBillableSize > 0);
+ if (inputs > outputs) {
+ BOOST_CHECK(txBillableSize <= txSize);
+ } else {
+ BOOST_CHECK(txBillableSize >= txSize);
+ }
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/txmempool.h b/src/txmempool.h
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -86,6 +86,8 @@
Amount nFee;
//!< ... and avoid recomputing tx size
size_t nTxSize;
+ //!< ... and billable size for billing
+ size_t nTxBillableSize;
//!< ... and modified size for priority
size_t nModSize;
//!< ... and total memory usage
@@ -117,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;
@@ -143,6 +148,8 @@
double GetPriority(unsigned int currentHeight) const;
const Amount GetFee() const { return nFee; }
size_t GetTxSize() const { return nTxSize; }
+ size_t GetTxBillableSize() const { return nTxBillableSize; }
+
int64_t GetTime() const { return nTime; }
unsigned int GetHeight() const { return entryHeight; }
int64_t GetSigOpCount() const { return sigOpCount; }
@@ -151,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);
@@ -164,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;
@@ -181,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;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -33,11 +33,13 @@
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOpsCount),
lockPoints(lp) {
nTxSize = tx->GetTotalSize();
+ nTxBillableSize = tx->GetBillableSize();
nModSize = tx->CalculateModifiedSize(GetTxSize());
nUsageSize = RecursiveDynamicUsage(tx);
nCountWithDescendants = 1;
nSizeWithDescendants = GetTxSize();
+ nBillableSizeWithDescendants = GetTxBillableSize();
nModFeesWithDescendants = nFee;
Amount nValueIn = tx->GetValueOut() + nFee;
assert(inChainInputValue <= nValueIn);
@@ -46,6 +48,7 @@
nCountWithAncestors = 1;
nSizeWithAncestors = GetTxSize();
+ nBillableSizeWithAncestors = GetTxBillableSize();
nModFeesWithAncestors = nFee;
nSigOpCountWithAncestors = sigOpCount;
}
@@ -107,23 +110,27 @@
// setAllDescendants now contains all in-mempool descendants of updateIt.
// Update and add to cached descendant map
int64_t modifySize = 0;
- Amount modifyFee = Amount::zero();
+ int64_t modifyBillableSize = 0;
int64_t modifyCount = 0;
+ Amount modifyFee = Amount::zero();
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));
}
// txidsToUpdate is the set of transaction hashes from a disconnected block
@@ -271,10 +278,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));
}
}
@@ -282,14 +291,18 @@
const setEntries &setAncestors) {
int64_t updateCount = setAncestors.size();
int64_t updateSize = 0;
- Amount updateFee = Amount::zero();
+ int64_t updateBillableSize = 0;
int64_t updateSigOpsCount = 0;
+ Amount updateFee = Amount::zero();
+
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));
}
@@ -315,12 +328,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));
}
}
}
@@ -361,20 +377,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);
@@ -903,7 +925,7 @@
static TxMempoolInfo
GetInfo(CTxMemPool::indexed_transaction_set::const_iterator it) {
return TxMempoolInfo{it->GetSharedTx(), it->GetTime(),
- CFeeRate(it->GetFee(), it->GetTxSize()),
+ CFeeRate(it->GetFee(), it->GetTxBillableSize()),
it->GetModifiedFee() - it->GetFee()};
}
@@ -1007,7 +1029,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
@@ -1016,7 +1038,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));
}
}
}
diff --git a/src/validation.cpp b/src/validation.cpp
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -575,6 +575,9 @@
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
+
+ // NOTE: Use the actual size here, and not the fee size since this
+ // is counting real size for the rate limiter.
if (dFreeCount + nSize >=
gArgs.GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 *
1000) {

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 26, 11:06 (12 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5573357
Default Alt Text
D1860.diff (19 KB)

Event Timeline