Skip to content

Commit c035306

Browse files
committed
Change GetPriority calculation.
Compute the value of inputs that already are in the chain at time of mempool entry and only increase priority due to aging for those inputs. This effectively changes the CTxMemPoolEntry's GetPriority calculation from an upper bound to a lower bound.
1 parent 71f1d9f commit c035306

File tree

7 files changed

+37
-16
lines changed

7 files changed

+37
-16
lines changed

src/coins.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,9 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
243243
return true;
244244
}
245245

246-
double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
246+
double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
247247
{
248+
inChainInputValue = 0;
248249
if (tx.IsCoinBase())
249250
return 0.0;
250251
double dResult = 0.0;
@@ -253,8 +254,9 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
253254
const CCoins* coins = AccessCoins(txin.prevout.hash);
254255
assert(coins);
255256
if (!coins->IsAvailable(txin.prevout.n)) continue;
256-
if (coins->nHeight < nHeight) {
257+
if (coins->nHeight <= nHeight) {
257258
dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
259+
inChainInputValue += coins->vout[txin.prevout.n].nValue;
258260
}
259261
}
260262
return tx.ComputePriority(dResult);

src/coins.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,12 @@ class CCoinsViewCache : public CCoinsViewBacked
456456
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
457457
bool HaveInputs(const CTransaction& tx) const;
458458

459-
//! Return priority of tx at height nHeight
460-
double GetPriority(const CTransaction &tx, int nHeight) const;
459+
/**
460+
* Return priority of tx at height nHeight. Also calculate the sum of the values of the inputs
461+
* that are already in the chain. These are the inputs that will age and increase priority as
462+
* new blocks are added to the chain.
463+
*/
464+
double GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const;
461465

462466
const CTxOut &GetOutputFor(const CTxIn& input) const;
463467

src/main.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -950,9 +950,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
950950

951951
CAmount nValueOut = tx.GetValueOut();
952952
CAmount nFees = nValueIn-nValueOut;
953-
double dPriority = view.GetPriority(tx, chainActive.Height());
953+
CAmount inChainInputValue;
954+
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
954955

955-
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx));
956+
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue);
956957
unsigned int nSize = entry.GetTxSize();
957958

958959
// Don't accept it if it can't get into a block
@@ -964,7 +965,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
964965
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
965966
if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
966967
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
967-
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
968+
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
968969
// Require that free transactions have sufficient priority to be mined in the next block.
969970
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
970971
}

src/test/policyestimator_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
196196

197197
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
198198
// and that estimateSmartPriority returns essentially an infinite value
199-
mpool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, feeV[0][5], GetTime(), priV[1][5], blocknum, mpool.HasNoInputsOf(tx)));
199+
mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[0][5]).Time(GetTime()).Priority(priV[1][5]).Height(blocknum).FromTx(tx, &mpool));
200200
// evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5]
201201
mpool.TrimToSize(1);
202202
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]);

src/test/test_bitcoin.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,13 @@ TestChain100Setup::~TestChain100Setup()
144144

145145

146146
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) {
147-
return CTxMemPoolEntry(tx, nFee, nTime, dPriority, nHeight,
148-
pool ? pool->HasNoInputsOf(tx) : hadNoDependencies);
147+
CTransaction txn(tx);
148+
bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies;
149+
// Hack to assume either its completely dependent on other mempool txs or not at all
150+
CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
151+
152+
return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
153+
hasNoDependencies, inChainValue);
149154
}
150155

151156
void Shutdown(void* parg)

src/txmempool.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
using namespace std;
2020

2121
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
22-
int64_t _nTime, double _entryPriority,
23-
unsigned int _entryHeight, bool poolHasNoInputsOf):
22+
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
23+
bool poolHasNoInputsOf, CAmount _inChainInputValue):
2424
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
25-
hadNoDependencies(poolHasNoInputsOf)
25+
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue)
2626
{
2727
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
2828
nModSize = tx.CalculateModifiedSize(nTxSize);
@@ -31,6 +31,8 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
3131
nCountWithDescendants = 1;
3232
nSizeWithDescendants = nTxSize;
3333
nFeesWithDescendants = nFee;
34+
CAmount nValueIn = tx.GetValueOut()+nFee;
35+
assert(inChainInputValue <= nValueIn);
3436
}
3537

3638
CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
@@ -41,9 +43,10 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
4143
double
4244
CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
4345
{
44-
CAmount nValueIn = tx.GetValueOut()+nFee;
45-
double deltaPriority = ((double)(currentHeight-entryHeight)*nValueIn)/nModSize;
46+
double deltaPriority = ((double)(currentHeight-entryHeight)*inChainInputValue)/nModSize;
4647
double dResult = entryPriority + deltaPriority;
48+
if (dResult < 0) // This should only happen if it was called with a height below entry height
49+
dResult = 0;
4750
return dResult;
4851
}
4952

src/txmempool.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class CTxMemPoolEntry
6666
double entryPriority; //! Priority when entering the mempool
6767
unsigned int entryHeight; //! Chain height when entering the mempool
6868
bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
69+
CAmount inChainInputValue; //! Sum of all txin values that are already in blockchain
6970

7071
// Information about descendants of this transaction that are in the
7172
// mempool; if we remove this transaction we must remove all of these
@@ -78,10 +79,15 @@ class CTxMemPoolEntry
7879

7980
public:
8081
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
81-
int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf);
82+
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
83+
bool poolHasNoInputsOf, CAmount _inChainInputValue);
8284
CTxMemPoolEntry(const CTxMemPoolEntry& other);
8385

8486
const CTransaction& GetTx() const { return this->tx; }
87+
/**
88+
* Fast calculation of lower bound of current priority as update
89+
* from entry priority. Only inputs that were originally in-chain will age.
90+
*/
8591
double GetPriority(unsigned int currentHeight) const;
8692
const CAmount& GetFee() const { return nFee; }
8793
size_t GetTxSize() const { return nTxSize; }

0 commit comments

Comments
 (0)