aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/coins.cpp6
-rw-r--r--src/coins.h8
-rw-r--r--src/main.cpp7
-rw-r--r--src/test/policyestimator_tests.cpp2
-rw-r--r--src/test/test_bitcoin.cpp9
-rw-r--r--src/txmempool.cpp13
-rw-r--r--src/txmempool.h8
7 files changed, 37 insertions, 16 deletions
diff --git a/src/coins.cpp b/src/coins.cpp
index f0ea5c0459..723e114708 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -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);
diff --git a/src/coins.h b/src/coins.h
index 99b25de45b..d174422100 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -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;
diff --git a/src/main.cpp b/src/main.cpp
index 33bd2e0ce1..55b0517349 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -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");
}
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 1315146f10..644c3da213 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -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]);
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 2fe190f885..351870014d 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -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)
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index ea3aad34a3..6d1df0b3d1 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -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;
}
diff --git a/src/txmempool.h b/src/txmempool.h
index e189e2e463..c470bbe28f 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -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; }