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.
This commit is contained in:
parent
71f1d9fd4a
commit
c0353064dd
7 changed files with 37 additions and 16 deletions
|
@ -243,8 +243,9 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
|
|||
return true;
|
||||
}
|
||||
|
||||
double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
|
||||
double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
|
||||
{
|
||||
inChainInputValue = 0;
|
||||
if (tx.IsCoinBase())
|
||||
return 0.0;
|
||||
double dResult = 0.0;
|
||||
|
@ -253,8 +254,9 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
|
|||
const CCoins* coins = AccessCoins(txin.prevout.hash);
|
||||
assert(coins);
|
||||
if (!coins->IsAvailable(txin.prevout.n)) continue;
|
||||
if (coins->nHeight < nHeight) {
|
||||
if (coins->nHeight <= nHeight) {
|
||||
dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
|
||||
inChainInputValue += coins->vout[txin.prevout.n].nValue;
|
||||
}
|
||||
}
|
||||
return tx.ComputePriority(dResult);
|
||||
|
|
|
@ -456,8 +456,12 @@ public:
|
|||
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
|
||||
bool HaveInputs(const CTransaction& tx) const;
|
||||
|
||||
//! Return priority of tx at height nHeight
|
||||
double GetPriority(const CTransaction &tx, int nHeight) const;
|
||||
/**
|
||||
* Return priority of tx at height nHeight. Also calculate the sum of the values of the inputs
|
||||
* that are already in the chain. These are the inputs that will age and increase priority as
|
||||
* new blocks are added to the chain.
|
||||
*/
|
||||
double GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const;
|
||||
|
||||
const CTxOut &GetOutputFor(const CTxIn& input) const;
|
||||
|
||||
|
|
|
@ -950,9 +950,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
|
||||
CAmount nValueOut = tx.GetValueOut();
|
||||
CAmount nFees = nValueIn-nValueOut;
|
||||
double dPriority = view.GetPriority(tx, chainActive.Height());
|
||||
CAmount inChainInputValue;
|
||||
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
|
||||
|
||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx));
|
||||
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue);
|
||||
unsigned int nSize = entry.GetTxSize();
|
||||
|
||||
// Don't accept it if it can't get into a block
|
||||
|
@ -964,7 +965,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|||
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
|
||||
if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
|
||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
|
||||
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
|
||||
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
|
||||
// Require that free transactions have sufficient priority to be mined in the next block.
|
||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
|||
|
||||
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
|
||||
// and that estimateSmartPriority returns essentially an infinite value
|
||||
mpool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, feeV[0][5], GetTime(), priV[1][5], blocknum, mpool.HasNoInputsOf(tx)));
|
||||
mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[0][5]).Time(GetTime()).Priority(priV[1][5]).Height(blocknum).FromTx(tx, &mpool));
|
||||
// evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5]
|
||||
mpool.TrimToSize(1);
|
||||
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]);
|
||||
|
|
|
@ -144,8 +144,13 @@ TestChain100Setup::~TestChain100Setup()
|
|||
|
||||
|
||||
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) {
|
||||
return CTxMemPoolEntry(tx, nFee, nTime, dPriority, nHeight,
|
||||
pool ? pool->HasNoInputsOf(tx) : hadNoDependencies);
|
||||
CTransaction txn(tx);
|
||||
bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies;
|
||||
// Hack to assume either its completely dependent on other mempool txs or not at all
|
||||
CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
|
||||
|
||||
return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
|
||||
hasNoDependencies, inChainValue);
|
||||
}
|
||||
|
||||
void Shutdown(void* parg)
|
||||
|
|
|
@ -19,10 +19,10 @@
|
|||
using namespace std;
|
||||
|
||||
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
||||
int64_t _nTime, double _entryPriority,
|
||||
unsigned int _entryHeight, bool poolHasNoInputsOf):
|
||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||
bool poolHasNoInputsOf, CAmount _inChainInputValue):
|
||||
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
|
||||
hadNoDependencies(poolHasNoInputsOf)
|
||||
hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue)
|
||||
{
|
||||
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
nModSize = tx.CalculateModifiedSize(nTxSize);
|
||||
|
@ -31,6 +31,8 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
|||
nCountWithDescendants = 1;
|
||||
nSizeWithDescendants = nTxSize;
|
||||
nFeesWithDescendants = nFee;
|
||||
CAmount nValueIn = tx.GetValueOut()+nFee;
|
||||
assert(inChainInputValue <= nValueIn);
|
||||
}
|
||||
|
||||
CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
|
||||
|
@ -41,9 +43,10 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
|
|||
double
|
||||
CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
|
||||
{
|
||||
CAmount nValueIn = tx.GetValueOut()+nFee;
|
||||
double deltaPriority = ((double)(currentHeight-entryHeight)*nValueIn)/nModSize;
|
||||
double deltaPriority = ((double)(currentHeight-entryHeight)*inChainInputValue)/nModSize;
|
||||
double dResult = entryPriority + deltaPriority;
|
||||
if (dResult < 0) // This should only happen if it was called with a height below entry height
|
||||
dResult = 0;
|
||||
return dResult;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ private:
|
|||
double entryPriority; //! Priority when entering the mempool
|
||||
unsigned int entryHeight; //! Chain height when entering the mempool
|
||||
bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
|
||||
CAmount inChainInputValue; //! Sum of all txin values that are already in blockchain
|
||||
|
||||
// Information about descendants of this transaction that are in the
|
||||
// mempool; if we remove this transaction we must remove all of these
|
||||
|
@ -78,10 +79,15 @@ private:
|
|||
|
||||
public:
|
||||
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
|
||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf);
|
||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||
bool poolHasNoInputsOf, CAmount _inChainInputValue);
|
||||
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
||||
|
||||
const CTransaction& GetTx() const { return this->tx; }
|
||||
/**
|
||||
* Fast calculation of lower bound of current priority as update
|
||||
* from entry priority. Only inputs that were originally in-chain will age.
|
||||
*/
|
||||
double GetPriority(unsigned int currentHeight) const;
|
||||
const CAmount& GetFee() const { return nFee; }
|
||||
size_t GetTxSize() const { return nTxSize; }
|
||||
|
|
Loading…
Reference in a new issue