Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13711236
D1860.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Subscribers
None
D1860.diff
View Options
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
Details
Attached
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)
Attached To
D1860: Introduce and track a billable size in addition to real txn size
Event Timeline
Log In to Comment