diff --git a/qa/rpc-tests/getrawmempool_priority.py b/qa/rpc-tests/getrawmempool_priority.py
new file mode 100755
index 0000000..1adf61d
--- /dev/null
+++ b/qa/rpc-tests/getrawmempool_priority.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python2
+# Copyright (c) 2016 The Bitcoin Core developers
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+
+from test_framework.blocktools import create_block, create_coinbase
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+
+from binascii import a2b_hex, b2a_hex
+
+def find_unspent(node, txid, amount):
+ for utxo in node.listunspent(0):
+ if utxo['txid'] != txid: continue
+ if float(utxo['amount']) != amount: continue
+ return {'txid': utxo['txid'], 'vout': utxo['vout']}
+
+def solve_template_hex(tmpl, txlist):
+ block = create_block(tmpl=tmpl, txlist=txlist)
+ block.solve()
+ b = block.serialize()
+ x = b2a_hex(b).decode('ascii')
+ return x
+
+def get_modified_size(node, txdata):
+ decoded = node.decoderawtransaction(txdata)
+ size = len(txdata) // 2
+ for inp in decoded['vin']:
+ offset = 41 + min(len(inp['scriptSig']['hex']) // 2, 110)
+ if offset <= size:
+ size -= offset
+ return size
+
+def assert_approximate(a, b):
+ assert_equal(int(a), int(b))
+
+class PriorityTest(BitcoinTestFramework):
+
+ def __init__(self):
+ self.num_nodes = 2
+
+ def setup_nodes(self):
+ nodes = []
+ nodes.append(start_node(0, self.options.tmpdir, ['-blockmaxsize=0']))
+ nodes.append(start_node(1, self.options.tmpdir, ['-blockminsize=1000000', '-blockmaxsize=1000000']))
+ return nodes
+
+ def setup_network(self, split=False):
+ self.nodes = self.setup_nodes()
+ connect_nodes_bi(self.nodes,0,1)
+ self.is_network_split = False
+ self.sync_all()
+
+ def run_test(self):
+ node = self.nodes[0]
+ miner = self.nodes[1]
+ node.generate(50)
+ miner.generate(101)
+ self.sync_all()
+
+ fee = 0.01
+ amt = 11
+
+ txid_a = node.sendtoaddress(node.getnewaddress(), amt)
+ txdata_b = node.createrawtransaction([find_unspent(node, txid_a, amt)], {node.getnewaddress(): amt - fee})
+ txdata_b = node.signrawtransaction(txdata_b)['hex']
+ txmodsize_b = get_modified_size(node, txdata_b)
+ txid_b = node.sendrawtransaction(txdata_b)
+
+ txid_b_mempoolentry = node.getrawmempool(True)[txid_b]
+ assert_approximate(txid_b_mempoolentry['startingpriority'], txid_b_mempoolentry['currentpriority'])
+ assert_approximate(txid_b_mempoolentry['currentpriority'], 0)
+
+ # Mine only the sendtoaddress transaction
+ tmpl = node.getblocktemplate()
+ rawblock = solve_template_hex(tmpl, [create_coinbase(tmpl['height']), a2b_hex(node.getrawtransaction(txid_a))])
+ assert_equal(node.submitblock(rawblock), None)
+
+ txid_b_mempoolentry = node.getrawmempool(True)[txid_b]
+ assert_approximate(txid_b_mempoolentry['startingpriority'], 0)
+ assert_approximate(txid_b_mempoolentry['currentpriority'], amt * 1e8 / txmodsize_b)
+
+ node.generate(2)
+
+ txid_b_mempoolentry = node.getrawmempool(True)[txid_b]
+ assert_approximate(txid_b_mempoolentry['startingpriority'], 0)
+ assert_approximate(txid_b_mempoolentry['currentpriority'], amt * 1e8 * 3 / txmodsize_b)
+
+ self.sync_all()
+ miner.generate(4)
+ self.sync_all()
+
+ txdata_c = node.createrawtransaction([find_unspent(node, txid_b, amt - fee)], {node.getnewaddress(): amt - (fee * 2)})
+ txdata_c = node.signrawtransaction(txdata_c)['hex']
+ txmodsize_c = get_modified_size(node, txdata_c)
+ txid_c = node.sendrawtransaction(txdata_c)
+ txid_c_mempoolentry = node.getrawmempool(True)[txid_c]
+ assert_approximate(txid_c_mempoolentry['startingpriority'], txid_c_mempoolentry['currentpriority'])
+ assert_approximate(txid_c_mempoolentry['currentpriority'], (amt - fee) * 1e8 * 4 / txmodsize_c)
+
+ node.generate(1)
+
+ txid_c_mempoolentry = node.getrawmempool(True)[txid_c]
+ assert_approximate(txid_c_mempoolentry['startingpriority'], (amt - fee) * 1e8 * 4 / txmodsize_c)
+ assert_approximate(txid_c_mempoolentry['currentpriority'], (amt - fee) * 1e8 * 5 / txmodsize_c)
+
+ node.generate(2)
+
+ txid_c_mempoolentry = node.getrawmempool(True)[txid_c]
+ assert_approximate(txid_c_mempoolentry['startingpriority'], (amt - fee) * 1e8 * 4 / txmodsize_c)
+ assert_approximate(txid_c_mempoolentry['currentpriority'], (amt - fee) * 1e8 * 7 / txmodsize_c)
+
+if __name__ == '__main__':
+ PriorityTest().main()
diff --git a/qa/rpc-tests/test_framework/blocktools.py b/qa/rpc-tests/test_framework/blocktools.py
index 59aa8c1..b3aa8af 100644
--- a/qa/rpc-tests/test_framework/blocktools.py
+++ b/qa/rpc-tests/test_framework/blocktools.py
@@ -4,20 +4,41 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
+from binascii import a2b_hex, b2a_hex
+import cStringIO
from mininode import *
from script import CScript, CScriptOp, OP_TRUE, OP_CHECKSIG
+import struct
# Create a block (with regtest difficulty)
-def create_block(hashprev, coinbase, nTime=None):
+def create_block(hashprev=None, coinbase=None, nTime=None, tmpl=None, txlist=None):
block = CBlock()
- if nTime is None:
+ if tmpl:
+ block.nVersion = tmpl.get('version', block.nVersion)
+ if not nTime is None:
+ block.nTime = nTime
+ elif tmpl and not tmpl.get('curtime') is None:
+ block.nTime = tmpl['curtime']
+ else:
import time
block.nTime = int(time.time()+600)
+ if not hashprev is None:
+ block.hashPrevBlock = hashprev
else:
- block.nTime = nTime
- block.hashPrevBlock = hashprev
- block.nBits = 0x207fffff # Will break after a difficulty adjustment...
- block.vtx.append(coinbase)
+ block.hashPrevBlock = int ("0x" + tmpl['previousblockhash'] + "L", 0)
+ if tmpl and not tmpl.get('bits') is None:
+ block.nBits = struct.unpack('>I', a2b_hex(tmpl['bits']))[0]
+ else:
+ block.nBits = 0x207fffff # Will break after a difficulty adjustment...
+ if not coinbase is None:
+ block.vtx.append(coinbase)
+ if txlist:
+ for tx in txlist:
+ if not hasattr(tx, 'calc_sha256'):
+ txo = CTransaction()
+ txo.deserialize(cStringIO.StringIO(tx))
+ tx = txo
+ block.vtx.append(tx)
block.hashMerkleRoot = block.calc_merkle_root()
block.calc_sha256()
return block
diff --git a/src/main.cpp b/src/main.cpp
index 37dfaaa..f02a53e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -948,7 +948,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
CAmount inChainInputValue;
- double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
+ // Priority is based on height+1 since it is used for mining the *next* block
+ double dPriority = view.GetPriority(tx, chainActive.Height() + 1, inChainInputValue);
// Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met.
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 3cd2b76..8d9c66b 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -194,7 +194,7 @@ UniValue mempoolToJSON(bool fVerbose = false)
info.push_back(Pair("time", e.GetTime()));
info.push_back(Pair("height", (int)e.GetHeight()));
info.push_back(Pair("startingpriority", e.GetStartingPriority()));
- info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
+ info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height() + 1)));
info.push_back(Pair("descendantcount", e.GetCountWithDescendants()));
info.push_back(Pair("descendantsize", e.GetSizeWithDescendants()));
info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants()));
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index ed44647..aed5fb4 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -39,7 +39,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
feeDelta = 0;
- cachedHeight = entryHeight;
+ cachedHeight = entryHeight + 1;
cachedPriority = entryPriority;
}
@@ -328,8 +328,9 @@ void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t
void CTxMemPoolEntry::UpdateCachedPriority(unsigned int currentHeight, CAmount valueInCurrentBlock)
{
+ ++currentHeight;
int heightDiff = currentHeight - cachedHeight;
- double deltaPriority = ((double)heightDiff*inChainInputValue)/nModSize;
+ double deltaPriority = (((double)heightDiff*inChainInputValue) + valueInCurrentBlock)/nModSize;
cachedPriority += deltaPriority;
cachedHeight = currentHeight;
inChainInputValue += valueInCurrentBlock;
@@ -648,11 +649,12 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins, unsigned int nBlockHeight)
unsigned int i = 0;
checkTotal += it->GetTxSize();
CAmount dummyValue;
- double freshPriority = view.GetPriority(it->GetTx(), nBlockHeight, dummyValue);
- double cachePriority = it->GetPriority(nBlockHeight);
+ double freshPriority = view.GetPriority(it->GetTx(), nBlockHeight + 1, dummyValue);
+ double cachePriority = it->GetPriority(nBlockHeight + 1);
double priDiff = cachePriority > freshPriority ? cachePriority - freshPriority : freshPriority - cachePriority;
// Verify that the difference between the on the fly calculation and a fresh calculation
- // is small enough to be a result of double imprecision.
+ // is small enough to be a result of double imprecision. nBlockHeight + 1 is the
+ // earliest reliable value to use.
assert(priDiff < .0001 * freshPriority + 1);
innerUsage += it->DynamicMemoryUsage();
const CTransaction& tx = it->GetTx();