Skip to content

Commit 27fae34

Browse files
committed
Use fee deltas for determining mempool acceptance
1 parent 9ef2a25 commit 27fae34

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

qa/rpc-tests/prioritise_transaction.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,5 +143,45 @@ def run_test(self):
143143
if (x != high_fee_tx):
144144
assert(x not in mempool)
145145

146+
# Create a free, low priority transaction. Should be rejected.
147+
utxo_list = self.nodes[0].listunspent()
148+
assert(len(utxo_list) > 0)
149+
utxo = utxo_list[0]
150+
151+
inputs = []
152+
outputs = {}
153+
inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]})
154+
outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
155+
raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
156+
tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"]
157+
txid = self.nodes[0].sendrawtransaction(tx_hex)
158+
159+
# A tx that spends an in-mempool tx has 0 priority, so we can use it to
160+
# test the effect of using prioritise transaction for mempool acceptance
161+
inputs = []
162+
inputs.append({"txid": txid, "vout": 0})
163+
outputs = {}
164+
outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
165+
raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs)
166+
tx2_hex = self.nodes[0].signrawtransaction(raw_tx2)["hex"]
167+
tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"]
168+
169+
try:
170+
self.nodes[0].sendrawtransaction(tx2_hex)
171+
except JSONRPCException as exp:
172+
assert_equal(exp.error['code'], -26) # insufficient fee
173+
assert(tx2_id not in self.nodes[0].getrawmempool())
174+
else:
175+
assert(False)
176+
177+
# This is a less than 1000-byte transaction, so just set the fee
178+
# to be the minimum for a 1000 byte transaction and check that it is
179+
# accepted.
180+
self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN))
181+
182+
print "Assert that prioritised free transaction is accepted to mempool"
183+
assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id)
184+
assert(tx2_id in self.nodes[0].getrawmempool())
185+
146186
if __name__ == '__main__':
147187
PrioritiseTransactionTest().main()

src/main.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
968968

969969
CAmount nValueOut = tx.GetValueOut();
970970
CAmount nFees = nValueIn-nValueOut;
971+
// nModifiedFees includes any fee deltas from PrioritiseTransaction
972+
CAmount nModifiedFees = nFees;
973+
double nPriorityDummy = 0;
974+
pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
975+
971976
CAmount inChainInputValue;
972977
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
973978

@@ -987,22 +992,25 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
987992

988993
// Don't accept it if it can't get into a block
989994
CAmount txMinFee = GetMinRelayFee(tx, pool, nSize, true);
995+
996+
// txMinFee takes into account priority/fee deltas, so compare using
997+
// nFees rather than nModifiedFees
990998
if (fLimitFree && nFees < txMinFee)
991999
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
9921000
strprintf("%d < %d", nFees, txMinFee));
9931001

9941002
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
995-
if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
1003+
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
9961004
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
997-
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
1005+
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nModifiedFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
9981006
// Require that free transactions have sufficient priority to be mined in the next block.
9991007
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
10001008
}
10011009

10021010
// Continuously rate-limit free (really, very-low-fee) transactions
10031011
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
10041012
// be annoying or make others' transactions take longer to confirm.
1005-
if (fLimitFree && nFees < ::minRelayTxFee.GetFee(nSize))
1013+
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
10061014
{
10071015
static CCriticalSection csFreeLimiter;
10081016
static double dFreeCount;
@@ -1061,10 +1069,6 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
10611069
uint64_t nConflictingCount = 0;
10621070
CTxMemPool::setEntries allConflicting;
10631071

1064-
CAmount nModifiedFees = nFees;
1065-
double nPriorityDummy = 0;
1066-
pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
1067-
10681072
// If we don't hold the lock allConflicting might be incomplete; the
10691073
// subsequent RemoveStaged() and addUnchecked() calls don't guarantee
10701074
// mempool consistency for us.

0 commit comments

Comments
 (0)