Merge #9602: Remove coin age priority and free transactions - implementation

b421e6d Update example bitcoin.conf (Alex Morcos)
7d4e950 Allow setting minrelaytxfee to 0 (Alex Morcos)
359e8a0 [cleanup] Remove coin age priority completely. (Alex Morcos)
f9b9371 [rpc] Remove priorityDelta from prioritisetransaction (Alex Morcos)
49be7e1 [rpc] Remove priority information from mempool RPC calls (Alex Morcos)
0315888 [test] Remove priority from tests (Alex Morcos)
f838005 No longer allow "free" transactions (Alex Morcos)
ad727f4 [rpc] sendrawtransaction no longer bypasses minRelayTxFee (Alex Morcos)
fe282ac [cleanup] Remove estimatePriority and estimateSmartPriority (Alex Morcos)
400b151 [debug] Change -printpriority option (Alex Morcos)
272b25a [mining] Remove -blockprioritysize. (Alex Morcos)
12839cd [rpc] Remove estimatepriority and estimatesmartpriority. (Alex Morcos)
ddf58c7 wallet: Remove sendfree (MarcoFalke)

Tree-SHA512: a9a4499405923ce794ef18f9e334dbbd59dfc73a3dc2df6f85cc9c62af6f353ec2eed9c2d5e58e904f918d0d7ab738f403dd4939d9bc2276136864fe63710782
This commit is contained in:
Wladimir J. van der Laan 2017-03-07 19:12:58 +01:00
commit 30ff3a2fc9
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
40 changed files with 119 additions and 682 deletions

View file

@ -116,12 +116,7 @@
# running on another host using this option: # running on another host using this option:
#rpcconnect=127.0.0.1 #rpcconnect=127.0.0.1
# Transaction Fee Changes in 0.10.0 # Create transactions that have enough fees so they are likely to begin confirmation within n blocks (default: 6).
# Send transactions as zero-fee transactions if possible (default: 0)
#sendfreetransactions=0
# Create transactions that have enough fees (or priority) so they are likely to begin confirmation within n blocks (default: 1).
# This setting is over-ridden by the -paytxfee option. # This setting is over-ridden by the -paytxfee option.
#txconfirmtarget=n #txconfirmtarget=n

View file

@ -21,7 +21,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' %s" % (CMD_RO
REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"') REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"')
REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")') REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")')
# list unsupported, deprecated and duplicate args as they need no documentation # list unsupported, deprecated and duplicate args as they need no documentation
SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize']) SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions'])
def main(): def main():
used = check_output(CMD_GREP_ARGS, shell=True) used = check_output(CMD_GREP_ARGS, shell=True)

View file

@ -80,7 +80,6 @@ class AbandonConflictTest(BitcoinTestFramework):
# Restart the node with a higher min relay fee so the parent tx is no longer in mempool # Restart the node with a higher min relay fee so the parent tx is no longer in mempool
# TODO: redo with eviction # TODO: redo with eviction
# Note had to make sure tx did not have AllowFree priority
stop_node(self.nodes[0],0) stop_node(self.nodes[0],0)
self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"]) self.nodes[0]=start_node(0, self.options.tmpdir, ["-debug","-logtimemicros","-minrelaytxfee=0.0001"])

View file

@ -24,8 +24,8 @@ class BIP68Test(BitcoinTestFramework):
def setup_network(self): def setup_network(self):
self.nodes = [] self.nodes = []
self.nodes.append(start_node(0, self.options.tmpdir, ["-debug", "-blockprioritysize=0"])) self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"]))
self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-blockprioritysize=0", "-acceptnonstdtxn=0"])) self.nodes.append(start_node(1, self.options.tmpdir, ["-debug", "-acceptnonstdtxn=0"]))
self.is_network_split = False self.is_network_split = False
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"] self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
connect_nodes(self.nodes[0], 1) connect_nodes(self.nodes[0], 1)
@ -254,7 +254,7 @@ class BIP68Test(BitcoinTestFramework):
# Now mine some blocks, but make sure tx2 doesn't get mined. # Now mine some blocks, but make sure tx2 doesn't get mined.
# Use prioritisetransaction to lower the effective feerate to 0 # Use prioritisetransaction to lower the effective feerate to 0
self.nodes[0].prioritisetransaction(tx2.hash, -1e15, int(-self.relayfee*COIN)) self.nodes[0].prioritisetransaction(tx2.hash, int(-self.relayfee*COIN))
cur_time = int(time.time()) cur_time = int(time.time())
for i in range(10): for i in range(10):
self.nodes[0].setmocktime(cur_time + 600) self.nodes[0].setmocktime(cur_time + 600)
@ -267,7 +267,7 @@ class BIP68Test(BitcoinTestFramework):
test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False) test_nonzero_locks(tx2, self.nodes[0], self.relayfee, use_height_lock=False)
# Mine tx2, and then try again # Mine tx2, and then try again
self.nodes[0].prioritisetransaction(tx2.hash, 1e15, int(self.relayfee*COIN)) self.nodes[0].prioritisetransaction(tx2.hash, int(self.relayfee*COIN))
# Advance the time on the node so that we can test timelocks # Advance the time on the node so that we can test timelocks
self.nodes[0].setmocktime(cur_time+600) self.nodes[0].setmocktime(cur_time+600)

View file

@ -103,7 +103,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
# Check that descendant modified fees includes fee deltas from # Check that descendant modified fees includes fee deltas from
# prioritisetransaction # prioritisetransaction
self.nodes[0].prioritisetransaction(chain[-1], 0, 1000) self.nodes[0].prioritisetransaction(chain[-1], 1000)
mempool = self.nodes[0].getrawmempool(True) mempool = self.nodes[0].getrawmempool(True)
descendant_fees = 0 descendant_fees = 0
@ -124,7 +124,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(len(self.nodes[0].getrawmempool()), 0)
# Prioritise a transaction that has been mined, then add it back to the # Prioritise a transaction that has been mined, then add it back to the
# mempool by using invalidateblock. # mempool by using invalidateblock.
self.nodes[0].prioritisetransaction(chain[-1], 0, 2000) self.nodes[0].prioritisetransaction(chain[-1], 2000)
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
# Keep node1's tip synced with node0 # Keep node1's tip synced with node0
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash()) self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())

View file

@ -74,7 +74,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.block_submit(self.nodes[0], test1txs, False, True) self.block_submit(self.nodes[0], test1txs, False, True)
print ("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation") print ("Test 2: Non-NULLDUMMY base multisig transaction should not be accepted to mempool before activation")
test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 48) test2tx = self.create_transaction(self.nodes[0], txid2, self.ms_address, 47)
trueDummy(test2tx) trueDummy(test2tx)
txid4 = self.tx_submit(self.nodes[0], test2tx, NULLDUMMY_ERROR) txid4 = self.tx_submit(self.nodes[0], test2tx, NULLDUMMY_ERROR)
@ -82,7 +82,7 @@ class NULLDUMMYTest(BitcoinTestFramework):
self.block_submit(self.nodes[0], [test2tx], False, True) self.block_submit(self.nodes[0], [test2tx], False, True)
print ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation") print ("Test 4: Non-NULLDUMMY base multisig transaction is invalid after activation")
test4tx = self.create_transaction(self.nodes[0], txid4, self.address, 47) test4tx = self.create_transaction(self.nodes[0], txid4, self.address, 46)
test6txs=[CTransaction(test4tx)] test6txs=[CTransaction(test4tx)]
trueDummy(test4tx) trueDummy(test4tx)
self.tx_submit(self.nodes[0], test4tx, NULLDUMMY_ERROR) self.tx_submit(self.nodes[0], test4tx, NULLDUMMY_ERROR)

View file

@ -50,10 +50,8 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
assert(sizes[i] > MAX_BLOCK_BASE_SIZE) # Fail => raise utxo_count assert(sizes[i] > MAX_BLOCK_BASE_SIZE) # Fail => raise utxo_count
# add a fee delta to something in the cheapest bucket and make sure it gets mined # add a fee delta to something in the cheapest bucket and make sure it gets mined
# also check that a different entry in the cheapest bucket is NOT mined (lower # also check that a different entry in the cheapest bucket is NOT mined
# the priority to ensure its not mined due to priority) self.nodes[0].prioritisetransaction(txids[0][0], int(3*base_fee*COIN))
self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN))
self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0)
self.nodes[0].generate(1) self.nodes[0].generate(1)
@ -72,7 +70,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
# Add a prioritisation before a tx is in the mempool (de-prioritising a # Add a prioritisation before a tx is in the mempool (de-prioritising a
# high-fee transaction so that it's now low fee). # high-fee transaction so that it's now low fee).
self.nodes[0].prioritisetransaction(high_fee_tx, -1e15, -int(2*base_fee*COIN)) self.nodes[0].prioritisetransaction(high_fee_tx, -int(2*base_fee*COIN))
# Add everything back to mempool # Add everything back to mempool
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
@ -96,7 +94,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
if (x != high_fee_tx): if (x != high_fee_tx):
assert(x not in mempool) assert(x not in mempool)
# Create a free, low priority transaction. Should be rejected. # Create a free transaction. Should be rejected.
utxo_list = self.nodes[0].listunspent() utxo_list = self.nodes[0].listunspent()
assert(len(utxo_list) > 0) assert(len(utxo_list) > 0)
utxo = utxo_list[0] utxo = utxo_list[0]
@ -104,37 +102,27 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
inputs = [] inputs = []
outputs = {} outputs = {}
inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]}) inputs.append({"txid" : utxo["txid"], "vout" : utxo["vout"]})
outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee outputs[self.nodes[0].getnewaddress()] = utxo["amount"]
raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) raw_tx = self.nodes[0].createrawtransaction(inputs, outputs)
tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"] tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"]
txid = self.nodes[0].sendrawtransaction(tx_hex) tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"]
# A tx that spends an in-mempool tx has 0 priority, so we can use it to
# test the effect of using prioritise transaction for mempool acceptance
inputs = []
inputs.append({"txid": txid, "vout": 0})
outputs = {}
outputs[self.nodes[0].getnewaddress()] = utxo["amount"] - self.relayfee
raw_tx2 = self.nodes[0].createrawtransaction(inputs, outputs)
tx2_hex = self.nodes[0].signrawtransaction(raw_tx2)["hex"]
tx2_id = self.nodes[0].decoderawtransaction(tx2_hex)["txid"]
try: try:
self.nodes[0].sendrawtransaction(tx2_hex) self.nodes[0].sendrawtransaction(tx_hex)
except JSONRPCException as exp: except JSONRPCException as exp:
assert_equal(exp.error['code'], -26) # insufficient fee assert_equal(exp.error['code'], -26) # insufficient fee
assert(tx2_id not in self.nodes[0].getrawmempool()) assert(tx_id not in self.nodes[0].getrawmempool())
else: else:
assert(False) assert(False)
# This is a less than 1000-byte transaction, so just set the fee # This is a less than 1000-byte transaction, so just set the fee
# to be the minimum for a 1000 byte transaction and check that it is # to be the minimum for a 1000 byte transaction and check that it is
# accepted. # accepted.
self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN)) self.nodes[0].prioritisetransaction(tx_id, int(self.relayfee*COIN))
print("Assert that prioritised free transaction is accepted to mempool") print("Assert that prioritised free transaction is accepted to mempool")
assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id) assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id)
assert(tx2_id in self.nodes[0].getrawmempool()) assert(tx_id in self.nodes[0].getrawmempool())
if __name__ == '__main__': if __name__ == '__main__':
PrioritiseTransactionTest().main() PrioritiseTransactionTest().main()

View file

@ -543,7 +543,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert(False) assert(False)
# Use prioritisetransaction to set tx1a's fee to 0. # Use prioritisetransaction to set tx1a's fee to 0.
self.nodes[0].prioritisetransaction(tx1a_txid, 0, int(-0.1*COIN)) self.nodes[0].prioritisetransaction(tx1a_txid, int(-0.1*COIN))
# Now tx1b should be able to replace tx1a # Now tx1b should be able to replace tx1a
tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True)
@ -575,7 +575,7 @@ class ReplaceByFeeTest(BitcoinTestFramework):
assert(False) assert(False)
# Now prioritise tx2b to have a higher modified fee # Now prioritise tx2b to have a higher modified fee
self.nodes[0].prioritisetransaction(tx2b.hash, 0, int(0.1*COIN)) self.nodes[0].prioritisetransaction(tx2b.hash, int(0.1*COIN))
# tx2b should now be accepted # tx2b should now be accepted
tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True) tx2b_txid = self.nodes[0].sendrawtransaction(tx2b_hex, True)

View file

@ -69,10 +69,11 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
def split_inputs(from_node, txins, txouts, initial_split = False): def split_inputs(from_node, txins, txouts, initial_split = False):
""" """
We need to generate a lot of very small inputs so we can generate a ton of transactions We need to generate a lot of inputs so we can generate a ton of transactions.
and they will have low priority.
This function takes an input from txins, and creates and sends a transaction This function takes an input from txins, and creates and sends a transaction
which splits the value into 2 outputs which are appended to txouts. which splits the value into 2 outputs which are appended to txouts.
Previously this was designed to be small inputs so they wouldn't have
a high coin age when the notion of priority still existed.
""" """
prevtxout = txins.pop() prevtxout = txins.pop()
inputs = [] inputs = []
@ -150,7 +151,7 @@ class EstimateFeeTest(BitcoinTestFramework):
def setup_network(self): def setup_network(self):
""" """
We'll setup the network to have 3 nodes that all mine with different parameters. We'll setup the network to have 3 nodes that all mine with different parameters.
But first we need to use one node to create a lot of small low priority outputs But first we need to use one node to create a lot of outputs
which we will use to generate our transactions. which we will use to generate our transactions.
""" """
self.nodes = [] self.nodes = []
@ -159,7 +160,7 @@ class EstimateFeeTest(BitcoinTestFramework):
"-whitelist=127.0.0.1"])) "-whitelist=127.0.0.1"]))
print("This test is time consuming, please be patient") print("This test is time consuming, please be patient")
print("Splitting inputs to small size so we can generate low priority tx's") print("Splitting inputs so we can generate tx's")
self.txouts = [] self.txouts = []
self.txouts2 = [] self.txouts2 = []
# Split a coinbase into two transaction puzzle outputs # Split a coinbase into two transaction puzzle outputs
@ -188,18 +189,17 @@ class EstimateFeeTest(BitcoinTestFramework):
# Now we can connect the other nodes, didn't want to connect them earlier # Now we can connect the other nodes, didn't want to connect them earlier
# so the estimates would not be affected by the splitting transactions # so the estimates would not be affected by the splitting transactions
# Node1 mines small blocks but that are bigger than the expected transaction rate, # Node1 mines small blocks but that are bigger than the expected transaction rate.
# and allows free transactions.
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
# (17k is room enough for 110 or so transactions) # (17k is room enough for 110 or so transactions)
self.nodes.append(start_node(1, self.options.tmpdir, self.nodes.append(start_node(1, self.options.tmpdir,
["-blockprioritysize=1500", "-blockmaxsize=17000", ["-blockmaxsize=17000",
"-maxorphantx=1000", "-debug=estimatefee"])) "-maxorphantx=1000", "-debug=estimatefee"]))
connect_nodes(self.nodes[1], 0) connect_nodes(self.nodes[1], 0)
# Node2 is a stingy miner, that # Node2 is a stingy miner, that
# produces too small blocks (room for only 55 or so transactions) # produces too small blocks (room for only 55 or so transactions)
node2args = ["-blockprioritysize=0", "-blockmaxsize=8000", "-maxorphantx=1000"] node2args = ["-blockmaxsize=8000", "-maxorphantx=1000"]
self.nodes.append(start_node(2, self.options.tmpdir, node2args)) self.nodes.append(start_node(2, self.options.tmpdir, node2args))
connect_nodes(self.nodes[0], 2) connect_nodes(self.nodes[0], 2)

View file

@ -442,47 +442,6 @@ def make_change(from_node, amount_in, amount_out, fee):
outputs[from_node.getnewaddress()] = change outputs[from_node.getnewaddress()] = change
return outputs return outputs
def send_zeropri_transaction(from_node, to_node, amount, fee):
"""
Create&broadcast a zero-priority transaction.
Returns (txid, hex-encoded-txdata)
Ensures transaction is zero-priority by first creating a send-to-self,
then using its output
"""
# Create a send-to-self with confirmed inputs:
self_address = from_node.getnewaddress()
(total_in, inputs) = gather_inputs(from_node, amount+fee*2)
outputs = make_change(from_node, total_in, amount+fee, fee)
outputs[self_address] = float(amount+fee)
self_rawtx = from_node.createrawtransaction(inputs, outputs)
self_signresult = from_node.signrawtransaction(self_rawtx)
self_txid = from_node.sendrawtransaction(self_signresult["hex"], True)
vout = find_output(from_node, self_txid, amount+fee)
# Now immediately spend the output to create a 1-input, 1-output
# zero-priority transaction:
inputs = [ { "txid" : self_txid, "vout" : vout } ]
outputs = { to_node.getnewaddress() : float(amount) }
rawtx = from_node.createrawtransaction(inputs, outputs)
signresult = from_node.signrawtransaction(rawtx)
txid = from_node.sendrawtransaction(signresult["hex"], True)
return (txid, signresult["hex"])
def random_zeropri_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
"""
Create a random zero-priority transaction.
Returns (txid, hex-encoded-transaction-data, fee)
"""
from_node = random.choice(nodes)
to_node = random.choice(nodes)
fee = min_fee + fee_increment*random.randint(0,fee_variants)
(txid, txhex) = send_zeropri_transaction(from_node, to_node, amount, fee)
return (txid, txhex, fee)
def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants): def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants):
""" """
Create a random transaction. Create a random transaction.

View file

@ -12,14 +12,13 @@
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool) static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
{ {
int64_t nTime = 0; int64_t nTime = 0;
double dPriority = 10.0;
unsigned int nHeight = 1; unsigned int nHeight = 1;
bool spendsCoinbase = false; bool spendsCoinbase = false;
unsigned int sigOpCost = 4; unsigned int sigOpCost = 4;
LockPoints lp; LockPoints lp;
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry( pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight, MakeTransactionRef(tx), nFee, nTime, nHeight,
tx.GetValueOut(), spendsCoinbase, sigOpCost, lp)); spendsCoinbase, sigOpCost, lp));
} }
// Right now this is only testing eviction performance in an extremely small // Right now this is only testing eviction performance in an extremely small

View file

@ -295,25 +295,6 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
return true; return true;
} }
double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
{
inChainInputValue = 0;
if (tx.IsCoinBase())
return 0.0;
double dResult = 0.0;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
const CCoins* coins = AccessCoins(txin.prevout.hash);
assert(coins);
if (!coins->IsAvailable(txin.prevout.n)) continue;
if (coins->nHeight <= nHeight) {
dResult += (double)(coins->vout[txin.prevout.n].nValue) * (nHeight-coins->nHeight);
inChainInputValue += coins->vout[txin.prevout.n].nValue;
}
}
return tx.ComputePriority(dResult);
}
CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) { CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) {
assert(!cache.hasModifier); assert(!cache.hasModifier);
cache.hasModifier = true; cache.hasModifier = true;

View file

@ -460,13 +460,6 @@ public:
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const; bool HaveInputs(const CTransaction& tx) 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; const CTxOut &GetOutputFor(const CTxIn& input) const;
friend class CCoinsModifier; friend class CCoinsModifier;

View file

@ -444,8 +444,6 @@ std::string HelpMessage(HelpMessageMode mode)
{ {
strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)"); strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)");
strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", DEFAULT_LIMITFREERELAY));
strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", DEFAULT_RELAYPRIORITY));
strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE));
strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
} }
@ -456,7 +454,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file")); strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
if (showDebug) if (showDebug)
{ {
strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY)); strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction fee per kB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY));
} }
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)")); strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
@ -476,7 +474,6 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Block creation options:")); strUsage += HelpMessageGroup(_("Block creation options:"));
strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT));
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE))); strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)));
if (showDebug) if (showDebug)
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios"); strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
@ -998,17 +995,18 @@ bool AppInitParameterInteraction()
if (nConnectTimeout <= 0) if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
// Fee-per-kilobyte amount considered the same as "free" // Fee-per-kilobyte amount required for mempool acceptance and relay
// If you are mining, be careful setting this: // If you are mining, be careful setting this:
// if you set it to zero then // if you set it to zero then
// a transaction spammer can cheaply fill blocks using // a transaction spammer can cheaply fill blocks using
// 1-satoshi-fee transactions. It should be set above the real // 0-fee transactions. It should be set above the real
// cost to you of processing a transaction. // cost to you of processing a transaction.
if (IsArgSet("-minrelaytxfee")) if (IsArgSet("-minrelaytxfee"))
{ {
CAmount n = 0; CAmount n = 0;
if (!ParseMoney(GetArg("-minrelaytxfee", ""), n) || 0 == n) if (!ParseMoney(GetArg("-minrelaytxfee", ""), n)) {
return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", ""))); return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
}
// High fee check is done afterward in CWallet::ParameterInteraction() // High fee check is done afterward in CWallet::ParameterInteraction()
::minRelayTxFee = CFeeRate(n); ::minRelayTxFee = CFeeRate(n);
} else if (incrementalRelayFee > ::minRelayTxFee) { } else if (incrementalRelayFee > ::minRelayTxFee) {

View file

@ -39,8 +39,8 @@
// //
// Unconfirmed transactions in the memory pool often depend on other // Unconfirmed transactions in the memory pool often depend on other
// transactions in the memory pool. When we select transactions from the // transactions in the memory pool. When we select transactions from the
// pool, we select by highest priority or fee rate, so we might consider // pool, we select by highest fee rate of a transaction combined with all
// transactions that depend on transactions that aren't yet in the block. // its ancestors.
uint64_t nLastBlockTx = 0; uint64_t nLastBlockTx = 0;
uint64_t nLastBlockSize = 0; uint64_t nLastBlockSize = 0;
@ -135,9 +135,6 @@ void BlockAssembler::resetBlock()
// These counters do not include coinbase tx // These counters do not include coinbase tx
nBlockTx = 0; nBlockTx = 0;
nFees = 0; nFees = 0;
lastFewTxs = 0;
blockFinished = false;
} }
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn) std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
@ -180,7 +177,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// transaction (which in most cases can be a no-op). // transaction (which in most cases can be a no-op).
fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus()); fIncludeWitness = IsWitnessEnabled(pindexPrev, chainparams.GetConsensus());
addPriorityTxs();
addPackageTxs(); addPackageTxs();
nLastBlockTx = nBlockTx; nLastBlockTx = nBlockTx;
@ -217,17 +213,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
return std::move(pblocktemplate); return std::move(pblocktemplate);
} }
bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter)
{
BOOST_FOREACH(CTxMemPool::txiter parent, mempool.GetMemPoolParents(iter))
{
if (!inBlock.count(parent)) {
return true;
}
}
return false;
}
void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet) void BlockAssembler::onlyUnconfirmed(CTxMemPool::setEntries& testSet)
{ {
for (CTxMemPool::setEntries::iterator iit = testSet.begin(); iit != testSet.end(); ) { for (CTxMemPool::setEntries::iterator iit = testSet.begin(); iit != testSet.end(); ) {
@ -275,58 +260,6 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
return true; return true;
} }
bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter)
{
if (nBlockWeight + iter->GetTxWeight() >= nBlockMaxWeight) {
// If the block is so close to full that no more txs will fit
// or if we've tried more than 50 times to fill remaining space
// then flag that the block is finished
if (nBlockWeight > nBlockMaxWeight - 400 || lastFewTxs > 50) {
blockFinished = true;
return false;
}
// Once we're within 4000 weight of a full block, only look at 50 more txs
// to try to fill the remaining space.
if (nBlockWeight > nBlockMaxWeight - 4000) {
lastFewTxs++;
}
return false;
}
if (fNeedSizeAccounting) {
if (nBlockSize + ::GetSerializeSize(iter->GetTx(), SER_NETWORK, PROTOCOL_VERSION) >= nBlockMaxSize) {
if (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) {
blockFinished = true;
return false;
}
if (nBlockSize > nBlockMaxSize - 1000) {
lastFewTxs++;
}
return false;
}
}
if (nBlockSigOpsCost + iter->GetSigOpCost() >= MAX_BLOCK_SIGOPS_COST) {
// If the block has room for no more sig ops then
// flag that the block is finished
if (nBlockSigOpsCost > MAX_BLOCK_SIGOPS_COST - 8) {
blockFinished = true;
return false;
}
// Otherwise attempt to find another tx with fewer sigops
// to put in the block.
return false;
}
// Must check that lock times are still valid
// This can be removed once MTP is always enforced
// as long as reorgs keep the mempool consistent.
if (!IsFinalTx(iter->GetTx(), nHeight, nLockTimeCutoff))
return false;
return true;
}
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
{ {
pblock->vtx.emplace_back(iter->GetSharedTx()); pblock->vtx.emplace_back(iter->GetSharedTx());
@ -343,11 +276,7 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY); bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
if (fPrintPriority) { if (fPrintPriority) {
double dPriority = iter->GetPriority(nHeight); LogPrintf("fee %s txid %s\n",
CAmount dummy;
mempool.ApplyDeltas(iter->GetTx().GetHash(), dPriority, dummy);
LogPrintf("priority %.1f fee %s txid %s\n",
dPriority,
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(), CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
iter->GetTx().GetHash().ToString()); iter->GetTx().GetHash().ToString());
} }
@ -525,88 +454,6 @@ void BlockAssembler::addPackageTxs()
} }
} }
void BlockAssembler::addPriorityTxs()
{
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay
unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);
if (nBlockPrioritySize == 0) {
return;
}
bool fSizeAccounting = fNeedSizeAccounting;
fNeedSizeAccounting = true;
// This vector will be sorted into a priority queue:
std::vector<TxCoinAgePriority> vecPriority;
TxCoinAgePriorityCompare pricomparer;
std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash> waitPriMap;
typedef std::map<CTxMemPool::txiter, double, CTxMemPool::CompareIteratorByHash>::iterator waitPriIter;
double actualPriority = -1;
vecPriority.reserve(mempool.mapTx.size());
for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
mi != mempool.mapTx.end(); ++mi)
{
double dPriority = mi->GetPriority(nHeight);
CAmount dummy;
mempool.ApplyDeltas(mi->GetTx().GetHash(), dPriority, dummy);
vecPriority.push_back(TxCoinAgePriority(dPriority, mi));
}
std::make_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
CTxMemPool::txiter iter;
while (!vecPriority.empty() && !blockFinished) { // add a tx from priority queue to fill the blockprioritysize
iter = vecPriority.front().second;
actualPriority = vecPriority.front().first;
std::pop_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
vecPriority.pop_back();
// If tx already in block, skip
if (inBlock.count(iter)) {
assert(false); // shouldn't happen for priority txs
continue;
}
// cannot accept witness transactions into a non-witness block
if (!fIncludeWitness && iter->GetTx().HasWitness())
continue;
// If tx is dependent on other mempool txs which haven't yet been included
// then put it in the waitSet
if (isStillDependent(iter)) {
waitPriMap.insert(std::make_pair(iter, actualPriority));
continue;
}
// If this tx fits in the block add it, otherwise keep looping
if (TestForBlock(iter)) {
AddToBlock(iter);
// If now that this txs is added we've surpassed our desired priority size
// or have dropped below the AllowFreeThreshold, then we're done adding priority txs
if (nBlockSize >= nBlockPrioritySize || !AllowFree(actualPriority)) {
break;
}
// This tx was successfully added, so
// add transactions that depend on this one to the priority queue to try again
BOOST_FOREACH(CTxMemPool::txiter child, mempool.GetMemPoolChildren(iter))
{
waitPriIter wpiter = waitPriMap.find(child);
if (wpiter != waitPriMap.end()) {
vecPriority.push_back(TxCoinAgePriority(wpiter->second,child));
std::push_heap(vecPriority.begin(), vecPriority.end(), pricomparer);
waitPriMap.erase(wpiter);
}
}
}
}
fNeedSizeAccounting = fSizeAccounting;
}
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce) void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{ {
// Update nExtraNonce // Update nExtraNonce

View file

@ -158,10 +158,6 @@ private:
int64_t nLockTimeCutoff; int64_t nLockTimeCutoff;
const CChainParams& chainparams; const CChainParams& chainparams;
// Variables used for addPriorityTxs
int lastFewTxs;
bool blockFinished;
public: public:
struct Options { struct Options {
Options(); Options();
@ -184,17 +180,9 @@ private:
void AddToBlock(CTxMemPool::txiter iter); void AddToBlock(CTxMemPool::txiter iter);
// Methods for how to add transactions to a block. // Methods for how to add transactions to a block.
/** Add transactions based on tx "priority" */
void addPriorityTxs();
/** Add transactions based on feerate including unconfirmed ancestors */ /** Add transactions based on feerate including unconfirmed ancestors */
void addPackageTxs(); void addPackageTxs();
// helper function for addPriorityTxs
/** Test if tx will still "fit" in the block */
bool TestForBlock(CTxMemPool::txiter iter);
/** Test if tx still has unconfirmed parents not yet in block */
bool isStillDependent(CTxMemPool::txiter iter);
// helper functions for addPackageTxs() // helper functions for addPackageTxs()
/** Remove confirmed (inBlock) entries from given set */ /** Remove confirmed (inBlock) entries from given set */
void onlyUnconfirmed(CTxMemPool::setEntries& testSet); void onlyUnconfirmed(CTxMemPool::setEntries& testSet);

View file

@ -1853,7 +1853,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
} }
// Has inputs but not accepted to mempool // Has inputs but not accepted to mempool
// Probably non-standard or insufficient fee/priority // Probably non-standard or insufficient fee
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
vEraseQueue.push_back(orphanHash); vEraseQueue.push_back(orphanHash);
if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) { if (!orphanTx.HasWitness() && !stateDummy.CorruptionPossible()) {
@ -3249,9 +3249,8 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
static CFeeRate default_feerate(DEFAULT_MIN_RELAY_TX_FEE); static CFeeRate default_feerate(DEFAULT_MIN_RELAY_TX_FEE);
static FeeFilterRounder filterRounder(default_feerate); static FeeFilterRounder filterRounder(default_feerate);
CAmount filterToSend = filterRounder.round(currentFilter); CAmount filterToSend = filterRounder.round(currentFilter);
// If we don't allow free transactions, then we always have a fee filter of at least minRelayTxFee // We always have a fee filter of at least minRelayTxFee
if (GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0) filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK());
if (filterToSend != pto->lastSentFeeFilter) { if (filterToSend != pto->lastSentFeeFilter) {
connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); connman.PushMessage(pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend));
pto->lastSentFeeFilter = filterToSend; pto->lastSentFeeFilter = filterToSend;

View file

@ -452,24 +452,6 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
return CFeeRate(median); return CFeeRate(median);
} }
double CBlockPolicyEstimator::estimatePriority(int confTarget)
{
return -1;
}
double CBlockPolicyEstimator::estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool)
{
if (answerFoundAtTarget)
*answerFoundAtTarget = confTarget;
// If mempool is limiting txs, no priority txs are allowed
CAmount minPoolFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
if (minPoolFee > 0)
return INF_PRIORITY;
return -1;
}
void CBlockPolicyEstimator::Write(CAutoFile& fileout) void CBlockPolicyEstimator::Write(CAutoFile& fileout)
{ {
fileout << nBestSeenHeight; fileout << nBestSeenHeight;

View file

@ -182,7 +182,6 @@ static const double SUFFICIENT_FEETXS = 1;
static constexpr double MIN_FEERATE = 10; static constexpr double MIN_FEERATE = 10;
static const double MAX_FEERATE = 1e7; static const double MAX_FEERATE = 1e7;
static const double INF_FEERATE = MAX_MONEY; static const double INF_FEERATE = MAX_MONEY;
static const double INF_PRIORITY = 1e9 * MAX_MONEY;
// We have to lump transactions into buckets based on feerate, but we want to be able // We have to lump transactions into buckets based on feerate, but we want to be able
// to give accurate estimates over a large range of potential feerates // to give accurate estimates over a large range of potential feerates
@ -223,20 +222,6 @@ public:
*/ */
CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool); CFeeRate estimateSmartFee(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
/** Return a priority estimate.
* DEPRECATED
* Returns -1
*/
double estimatePriority(int confTarget);
/** Estimate priority needed to get be included in a block within
* confTarget blocks.
* DEPRECATED
* Returns -1 unless mempool is currently limited then returns INF_PRIORITY
* answerFoundAtTarget is set to confTarget
*/
double estimateSmartPriority(int confTarget, int *answerFoundAtTarget, const CTxMemPool& pool);
/** Write estimation data to a file */ /** Write estimation data to a file */
void Write(CAutoFile& fileout); void Write(CAutoFile& fileout);

View file

@ -16,8 +16,6 @@ class CCoinsViewCache;
/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/ /** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 0;
/** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/ /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000; static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = 3000000;
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/

View file

@ -92,32 +92,6 @@ CAmount CTransaction::GetValueOut() const
return nValueOut; return nValueOut;
} }
double CTransaction::ComputePriority(double dPriorityInputs, unsigned int nTxSize) const
{
nTxSize = CalculateModifiedSize(nTxSize);
if (nTxSize == 0) return 0.0;
return dPriorityInputs / nTxSize;
}
unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const
{
// In order to avoid disincentivizing cleaning up the UTXO set we don't count
// the constant overhead for each txin and up to 110 bytes of scriptSig (which
// is enough to cover a compressed pubkey p2sh redemption) for priority.
// Providing any more cleanup incentive than making additional inputs free would
// risk encouraging people to create junk outputs to redeem later.
if (nTxSize == 0)
nTxSize = (GetTransactionWeight(*this) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it)
{
unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size());
if (nTxSize > offset)
nTxSize -= offset;
}
return nTxSize;
}
unsigned int CTransaction::GetTotalSize() const unsigned int CTransaction::GetTotalSize() const
{ {
return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);

View file

@ -361,12 +361,6 @@ public:
// GetValueIn() is a method on CCoinsViewCache, because // GetValueIn() is a method on CCoinsViewCache, because
// inputs must be known to compute value in. // inputs must be known to compute value in.
// Compute priority, given priority of inputs and (optionally) tx size
double ComputePriority(double dPriorityInputs, unsigned int nTxSize=0) const;
// Compute modified tx size for priority calculation (optionally given tx size)
unsigned int CalculateModifiedSize(unsigned int nTxSize=0) const;
/** /**
* Get the total transaction size in bytes, including witness data. * Get the total transaction size in bytes, including witness data.
* "Total Size" defined in BIP141 and BIP144. * "Total Size" defined in BIP141 and BIP144.

View file

@ -444,11 +444,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
CAmount nChange = 0; CAmount nChange = 0;
unsigned int nBytes = 0; unsigned int nBytes = 0;
unsigned int nBytesInputs = 0; unsigned int nBytesInputs = 0;
double dPriority = 0;
double dPriorityInputs = 0;
unsigned int nQuantity = 0; unsigned int nQuantity = 0;
int nQuantityUncompressed = 0;
bool fAllowFree = false;
bool fWitness = false; bool fWitness = false;
std::vector<COutPoint> vCoinControl; std::vector<COutPoint> vCoinControl;
@ -473,9 +469,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Amount // Amount
nAmount += out.tx->tx->vout[out.i].nValue; nAmount += out.tx->tx->vout[out.i].nValue;
// Priority
dPriorityInputs += (double)out.tx->tx->vout[out.i].nValue * (out.nDepth+1);
// Bytes // Bytes
CTxDestination address; CTxDestination address;
int witnessversion = 0; int witnessversion = 0;
@ -492,8 +485,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (keyid && model->getPubKey(*keyid, pubkey)) if (keyid && model->getPubKey(*keyid, pubkey))
{ {
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180); nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
if (!pubkey.IsCompressed())
nQuantityUncompressed++;
} }
else else
nBytesInputs += 148; // in all error cases, simply assume 148 here nBytesInputs += 148; // in all error cases, simply assume 148 here
@ -525,17 +516,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee) if (nPayFee > 0 && coinControl->nMinimumTotalFee > nPayFee)
nPayFee = coinControl->nMinimumTotalFee; nPayFee = coinControl->nMinimumTotalFee;
// Allow free? (require at least hard-coded threshold and default to that if no estimate)
double mempoolEstimatePriority = mempool.estimateSmartPriority(nTxConfirmTarget);
dPriority = dPriorityInputs / (nBytes - nBytesInputs + (nQuantityUncompressed * 29)); // 29 = 180 - 151 (uncompressed public keys are over the limit. max 151 bytes of the input are ignored for priority)
double dPriorityNeeded = std::max(mempoolEstimatePriority, AllowFreeThreshold());
fAllowFree = (dPriority >= dPriorityNeeded);
if (fSendFreeTransactions)
if (fAllowFree && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
nPayFee = 0;
if (nPayAmount > 0) if (nPayAmount > 0)
{ {
nChange = nAmount - nPayAmount; nChange = nAmount - nPayAmount;

View file

@ -341,8 +341,6 @@ std::string EntryDescriptionString()
" \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n" " \"height\" : n, (numeric) block height when transaction entered pool\n"
" \"startingpriority\" : n, (numeric) DEPRECATED. Priority when transaction entered pool\n"
" \"currentpriority\" : n, (numeric) DEPRECATED. Transaction priority now\n"
" \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
" \"descendantsize\" : n, (numeric) virtual transaction size of in-mempool descendants (including this one)\n" " \"descendantsize\" : n, (numeric) virtual transaction size of in-mempool descendants (including this one)\n"
" \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
@ -363,8 +361,6 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee()))); info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee())));
info.push_back(Pair("time", e.GetTime())); info.push_back(Pair("time", e.GetTime()));
info.push_back(Pair("height", (int)e.GetHeight())); info.push_back(Pair("height", (int)e.GetHeight()));
info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
info.push_back(Pair("descendantcount", e.GetCountWithDescendants())); info.push_back(Pair("descendantcount", e.GetCountWithDescendants()));
info.push_back(Pair("descendantsize", e.GetSizeWithDescendants())); info.push_back(Pair("descendantsize", e.GetSizeWithDescendants()));
info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants())); info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants()));

View file

@ -107,11 +107,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "keypoolrefill", 0, "newsize" }, { "keypoolrefill", 0, "newsize" },
{ "getrawmempool", 0, "verbose" }, { "getrawmempool", 0, "verbose" },
{ "estimatefee", 0, "nblocks" }, { "estimatefee", 0, "nblocks" },
{ "estimatepriority", 0, "nblocks" },
{ "estimatesmartfee", 0, "nblocks" }, { "estimatesmartfee", 0, "nblocks" },
{ "estimatesmartpriority", 0, "nblocks" }, { "prioritisetransaction", 1, "fee_delta" },
{ "prioritisetransaction", 1, "priority_delta" },
{ "prioritisetransaction", 2, "fee_delta" },
{ "setban", 2, "bantime" }, { "setban", 2, "bantime" },
{ "setban", 3, "absolute" }, { "setban", 3, "absolute" },
{ "setnetworkactive", 0, "state" }, { "setnetworkactive", 0, "state" },

View file

@ -258,31 +258,28 @@ UniValue getmininginfo(const JSONRPCRequest& request)
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
UniValue prioritisetransaction(const JSONRPCRequest& request) UniValue prioritisetransaction(const JSONRPCRequest& request)
{ {
if (request.fHelp || request.params.size() != 3) if (request.fHelp || request.params.size() != 2)
throw runtime_error( throw runtime_error(
"prioritisetransaction <txid> <priority delta> <fee delta>\n" "prioritisetransaction <txid> <fee delta>\n"
"Accepts the transaction into mined blocks at a higher (or lower) priority\n" "Accepts the transaction into mined blocks at a higher (or lower) priority\n"
"\nArguments:\n" "\nArguments:\n"
"1. \"txid\" (string, required) The transaction id.\n" "1. \"txid\" (string, required) The transaction id.\n"
"2. priority_delta (numeric, required) The priority to add or subtract.\n" "2. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
" The transaction selection algorithm considers the tx as it would have a higher priority.\n"
" (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n"
"3. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n"
" The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
" considers the transaction as it would have paid a higher (or lower) fee.\n" " considers the transaction as it would have paid a higher (or lower) fee.\n"
"\nResult:\n" "\nResult:\n"
"true (boolean) Returns true\n" "true (boolean) Returns true\n"
"\nExamples:\n" "\nExamples:\n"
+ HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + HelpExampleCli("prioritisetransaction", "\"txid\" 10000")
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") + HelpExampleRpc("prioritisetransaction", "\"txid\", 10000")
); );
LOCK(cs_main); LOCK(cs_main);
uint256 hash = ParseHashStr(request.params[0].get_str(), "txid"); uint256 hash = ParseHashStr(request.params[0].get_str(), "txid");
CAmount nAmount = request.params[2].get_int64(); CAmount nAmount = request.params[1].get_int64();
mempool.PrioritiseTransaction(hash, request.params[1].get_real(), nAmount); mempool.PrioritiseTransaction(hash, nAmount);
return true; return true;
} }
@ -811,33 +808,6 @@ UniValue estimatefee(const JSONRPCRequest& request)
return ValueFromAmount(feeRate.GetFeePerK()); return ValueFromAmount(feeRate.GetFeePerK());
} }
UniValue estimatepriority(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatepriority nblocks\n"
"\nDEPRECATED. Estimates the approximate priority a zero-fee transaction needs to begin\n"
"confirmation within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric, required)\n"
"\nResult:\n"
"n (numeric) estimated priority\n"
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate.\n"
"\nExample:\n"
+ HelpExampleCli("estimatepriority", "6")
);
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = request.params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
return mempool.estimatePriority(nBlocks);
}
UniValue estimatesmartfee(const JSONRPCRequest& request) UniValue estimatesmartfee(const JSONRPCRequest& request)
{ {
if (request.fHelp || request.params.size() != 1) if (request.fHelp || request.params.size() != 1)
@ -875,48 +845,12 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
return result; return result;
} }
UniValue estimatesmartpriority(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatesmartpriority nblocks\n"
"\nDEPRECATED. WARNING: This interface is unstable and may disappear or change!\n"
"\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
"confirmation within nblocks blocks if possible and return the number of blocks\n"
"for which the estimate is valid.\n"
"\nArguments:\n"
"1. nblocks (numeric, required)\n"
"\nResult:\n"
"{\n"
" \"priority\" : x.x, (numeric) estimated priority\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
"\n"
"A negative value is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
"However if the mempool reject fee is set it will return 1e9 * MAX_MONEY.\n"
"\nExample:\n"
+ HelpExampleCli("estimatesmartpriority", "6")
);
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = request.params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
double priority = mempool.estimateSmartPriority(nBlocks, &answerFound);
result.push_back(Pair("priority", priority));
result.push_back(Pair("blocks", answerFound));
return result;
}
static const CRPCCommand commands[] = static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode { // category name actor (function) okSafeMode
// --------------------- ------------------------ ----------------------- ---------- // --------------------- ------------------------ ----------------------- ----------
{ "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} }, { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
{ "mining", "getmininginfo", &getmininginfo, true, {} }, { "mining", "getmininginfo", &getmininginfo, true, {} },
{ "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","priority_delta","fee_delta"} }, { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","fee_delta"} },
{ "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} }, { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} },
{ "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} }, { "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} },
@ -924,9 +858,7 @@ static const CRPCCommand commands[] =
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} }, { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} }, { "util", "estimatefee", &estimatefee, true, {"nblocks"} },
{ "util", "estimatepriority", &estimatepriority, true, {"nblocks"} },
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} }, { "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} },
{ "util", "estimatesmartpriority", &estimatesmartpriority, true, {"nblocks"} },
}; };
void RegisterMiningRPCCommands(CRPCTable &t) void RegisterMiningRPCCommands(CRPCTable &t)

View file

@ -62,7 +62,7 @@ UniValue getinfo(const JSONRPCRequest& request)
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n" " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
" \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n" " \"relayfee\": x.xxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": \"...\" (string) any error messages\n" " \"errors\": \"...\" (string) any error messages\n"
"}\n" "}\n"
"\nExamples:\n" "\nExamples:\n"

View file

@ -417,7 +417,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
" }\n" " }\n"
" ,...\n" " ,...\n"
" ],\n" " ],\n"
" \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n" " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"incrementalfee\": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kB\n" " \"incrementalfee\": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n" " \"localaddresses\": [ (array) list of local addresses\n"
" {\n" " {\n"

View file

@ -897,7 +897,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
CTransactionRef tx(MakeTransactionRef(std::move(mtx))); CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
const uint256& hashTx = tx->GetHash(); const uint256& hashTx = tx->GetHash();
bool fLimitFree = false; bool fLimitFree = true;
CAmount nMaxRawTxFee = maxTxFee; CAmount nMaxRawTxFee = maxTxFee;
if (request.params.size() > 1 && request.params[1].get_bool()) if (request.params.size() > 1 && request.params[1].get_bool())
nMaxRawTxFee = 0; nMaxRawTxFee = 0;

View file

@ -126,28 +126,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx1.vout.resize(1); tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN; tx1.vout[0].nValue = 10 * COIN;
pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
/* highest fee */ /* highest fee */
CMutableTransaction tx2 = CMutableTransaction(); CMutableTransaction tx2 = CMutableTransaction();
tx2.vout.resize(1); tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx2.vout[0].nValue = 2 * COIN; tx2.vout[0].nValue = 2 * COIN;
pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
/* lowest fee */ /* lowest fee */
CMutableTransaction tx3 = CMutableTransaction(); CMutableTransaction tx3 = CMutableTransaction();
tx3.vout.resize(1); tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx3.vout[0].nValue = 5 * COIN; tx3.vout[0].nValue = 5 * COIN;
pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
/* 2nd highest fee */ /* 2nd highest fee */
CMutableTransaction tx4 = CMutableTransaction(); CMutableTransaction tx4 = CMutableTransaction();
tx4.vout.resize(1); tx4.vout.resize(1);
tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx4.vout[0].nValue = 6 * COIN; tx4.vout[0].nValue = 6 * COIN;
pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
/* equal fee rate to tx1, but newer */ /* equal fee rate to tx1, but newer */
CMutableTransaction tx5 = CMutableTransaction(); CMutableTransaction tx5 = CMutableTransaction();
@ -155,7 +155,6 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx5.vout[0].nValue = 11 * COIN; tx5.vout[0].nValue = 11 * COIN;
entry.nTime = 1; entry.nTime = 1;
entry.dPriority = 10.0;
pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5)); pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
BOOST_CHECK_EQUAL(pool.size(), 5); BOOST_CHECK_EQUAL(pool.size(), 5);
@ -328,14 +327,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx1.vout.resize(1); tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN; tx1.vout[0].nValue = 10 * COIN;
pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).Priority(10.0).FromTx(tx1)); pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
/* highest fee */ /* highest fee */
CMutableTransaction tx2 = CMutableTransaction(); CMutableTransaction tx2 = CMutableTransaction();
tx2.vout.resize(1); tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx2.vout[0].nValue = 2 * COIN; tx2.vout[0].nValue = 2 * COIN;
pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).Priority(9.0).FromTx(tx2)); pool.addUnchecked(tx2.GetHash(), entry.Fee(20000LL).FromTx(tx2));
uint64_t tx2Size = GetVirtualTransactionSize(tx2); uint64_t tx2Size = GetVirtualTransactionSize(tx2);
/* lowest fee */ /* lowest fee */
@ -343,14 +342,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
tx3.vout.resize(1); tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx3.vout[0].nValue = 5 * COIN; tx3.vout[0].nValue = 5 * COIN;
pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).Priority(100.0).FromTx(tx3)); pool.addUnchecked(tx3.GetHash(), entry.Fee(0LL).FromTx(tx3));
/* 2nd highest fee */ /* 2nd highest fee */
CMutableTransaction tx4 = CMutableTransaction(); CMutableTransaction tx4 = CMutableTransaction();
tx4.vout.resize(1); tx4.vout.resize(1);
tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL; tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
tx4.vout[0].nValue = 6 * COIN; tx4.vout[0].nValue = 6 * COIN;
pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).Priority(1.0).FromTx(tx4)); pool.addUnchecked(tx4.GetHash(), entry.Fee(15000LL).FromTx(tx4));
/* equal fee rate to tx1, but newer */ /* equal fee rate to tx1, but newer */
CMutableTransaction tx5 = CMutableTransaction(); CMutableTransaction tx5 = CMutableTransaction();
@ -408,7 +407,6 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
/* set the fee to just below tx2's feerate when including ancestor */ /* set the fee to just below tx2's feerate when including ancestor */
CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1; CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
//CTxMemPoolEntry entry7(tx7, fee, 2, 10.0, 1, true);
pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7)); pool.addUnchecked(tx7.GetHash(), entry.Fee(fee).FromTx(tx7));
BOOST_CHECK_EQUAL(pool.size(), 7); BOOST_CHECK_EQUAL(pool.size(), 7);
sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString()); sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
@ -434,7 +432,6 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
{ {
CTxMemPool pool(CFeeRate(1000)); CTxMemPool pool(CFeeRate(1000));
TestMemPoolEntryHelper entry; TestMemPoolEntryHelper entry;
entry.dPriority = 10.0;
CMutableTransaction tx1 = CMutableTransaction(); CMutableTransaction tx1 = CMutableTransaction();
tx1.vin.resize(1); tx1.vin.resize(1);
@ -442,7 +439,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx1.vout.resize(1); tx1.vout.resize(1);
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL; tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
tx1.vout[0].nValue = 10 * COIN; tx1.vout[0].nValue = 10 * COIN;
pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1, &pool)); pool.addUnchecked(tx1.GetHash(), entry.Fee(10000LL).FromTx(tx1));
CMutableTransaction tx2 = CMutableTransaction(); CMutableTransaction tx2 = CMutableTransaction();
tx2.vin.resize(1); tx2.vin.resize(1);
@ -450,7 +447,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx2.vout.resize(1); tx2.vout.resize(1);
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL; tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
tx2.vout[0].nValue = 10 * COIN; tx2.vout[0].nValue = 10 * COIN;
pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2, &pool)); pool.addUnchecked(tx2.GetHash(), entry.Fee(5000LL).FromTx(tx2));
pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
BOOST_CHECK(pool.exists(tx1.GetHash())); BOOST_CHECK(pool.exists(tx1.GetHash()));
@ -460,7 +457,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(tx1.GetHash())); BOOST_CHECK(pool.exists(tx1.GetHash()));
BOOST_CHECK(!pool.exists(tx2.GetHash())); BOOST_CHECK(!pool.exists(tx2.GetHash()));
pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2, &pool)); pool.addUnchecked(tx2.GetHash(), entry.FromTx(tx2));
CMutableTransaction tx3 = CMutableTransaction(); CMutableTransaction tx3 = CMutableTransaction();
tx3.vin.resize(1); tx3.vin.resize(1);
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0); tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
@ -468,7 +465,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx3.vout.resize(1); tx3.vout.resize(1);
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL; tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
tx3.vout[0].nValue = 10 * COIN; tx3.vout[0].nValue = 10 * COIN;
pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3, &pool)); pool.addUnchecked(tx3.GetHash(), entry.Fee(20000LL).FromTx(tx3));
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP) pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
BOOST_CHECK(!pool.exists(tx1.GetHash())); BOOST_CHECK(!pool.exists(tx1.GetHash()));
@ -531,10 +528,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
tx7.vout[1].nValue = 10 * COIN; tx7.vout[1].nValue = 10 * COIN;
pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool)); pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4));
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool)); pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6));
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
// we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that // we only require this remove, at max, 2 txn, because its not clear what we're really optimizing for aside from that
pool.TrimToSize(pool.DynamicMemoryUsage() - 1); pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
@ -543,8 +540,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(!pool.exists(tx7.GetHash())); BOOST_CHECK(!pool.exists(tx7.GetHash()));
if (!pool.exists(tx5.GetHash())) if (!pool.exists(tx5.GetHash()))
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7 pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
BOOST_CHECK(pool.exists(tx4.GetHash())); BOOST_CHECK(pool.exists(tx4.GetHash()));
@ -552,8 +549,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
BOOST_CHECK(pool.exists(tx6.GetHash())); BOOST_CHECK(pool.exists(tx6.GetHash()));
BOOST_CHECK(!pool.exists(tx7.GetHash())); BOOST_CHECK(!pool.exists(tx7.GetHash()));
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
std::vector<CTransactionRef> vtx; std::vector<CTransactionRef> vtx;
SetMockTime(42); SetMockTime(42);

View file

@ -88,7 +88,6 @@ bool TestSequenceLocks(const CTransaction &tx, int flags)
// Test suite for ancestor feerate transaction selection. // Test suite for ancestor feerate transaction selection.
// Implemented as an additional function, rather than a separate test case, // Implemented as an additional function, rather than a separate test case,
// to allow reusing the blockchain created in CreateNewBlock_validity. // to allow reusing the blockchain created in CreateNewBlock_validity.
// Note that this test assumes blockprioritysize is 0.
void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransactionRef>& txFirst) void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransactionRef>& txFirst)
{ {
// Test the ancestor feerate transaction selection. // Test the ancestor feerate transaction selection.
@ -203,7 +202,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
uint256 hash; uint256 hash;
TestMemPoolEntryHelper entry; TestMemPoolEntryHelper entry;
entry.nFee = 11; entry.nFee = 11;
entry.dPriority = 111.0;
entry.nHeight = 11; entry.nHeight = 11;
LOCK(cs_main); LOCK(cs_main);
@ -308,7 +306,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error); BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
mempool.clear(); mempool.clear();
// child with higher priority than parent // child with higher feerate than parent
tx.vin[0].scriptSig = CScript() << OP_1; tx.vin[0].scriptSig = CScript() << OP_1;
tx.vin[0].prevout.hash = txFirst[1]->GetHash(); tx.vin[0].prevout.hash = txFirst[1]->GetHash();
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE; tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;

View file

@ -56,7 +56,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool)); mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash); txHashes[j].push_back(hash);
} }
} }
@ -132,7 +132,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool)); mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
txHashes[j].push_back(hash); txHashes[j].push_back(hash);
} }
} }
@ -169,7 +169,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
for (int k = 0; k < 4; k++) { // add 4 fee txs for (int k = 0; k < 4; k++) { // add 4 fee txs
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool)); mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx));
CTransactionRef ptx = mpool.get(hash); CTransactionRef ptx = mpool.get(hash);
if (ptx) if (ptx)
block.push_back(ptx); block.push_back(ptx);
@ -185,15 +185,13 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
} }
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee // 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(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));
mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
// evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5] // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
mpool.TrimToSize(1); mpool.TrimToSize(1);
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]); BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK()); BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK());
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK()); BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
BOOST_CHECK(mpool.estimateSmartPriority(i) == INF_PRIORITY);
} }
} }

View file

@ -141,17 +141,14 @@ TestChain100Setup::~TestChain100Setup()
} }
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool) { CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
CTransaction txn(tx); CTransaction txn(tx);
return FromTx(txn, pool); return FromTx(txn);
} }
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool) { CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
// Hack to assume either it's completely dependent on other mempool txs or not at all return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
CAmount inChainValue = pool && pool->HasNoInputsOf(txn) ? txn.GetValueOut() : 0; spendsCoinbase, sigOpCost, lp);
return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight,
inChainValue, spendsCoinbase, sigOpCost, lp);
} }
void Shutdown(void* parg) void Shutdown(void* parg)

View file

@ -61,30 +61,27 @@ struct TestChain100Setup : public TestingSetup {
}; };
class CTxMemPoolEntry; class CTxMemPoolEntry;
class CTxMemPool;
struct TestMemPoolEntryHelper struct TestMemPoolEntryHelper
{ {
// Default values // Default values
CAmount nFee; CAmount nFee;
int64_t nTime; int64_t nTime;
double dPriority;
unsigned int nHeight; unsigned int nHeight;
bool spendsCoinbase; bool spendsCoinbase;
unsigned int sigOpCost; unsigned int sigOpCost;
LockPoints lp; LockPoints lp;
TestMemPoolEntryHelper() : TestMemPoolEntryHelper() :
nFee(0), nTime(0), dPriority(0.0), nHeight(1), nFee(0), nTime(0), nHeight(1),
spendsCoinbase(false), sigOpCost(4) { } spendsCoinbase(false), sigOpCost(4) { }
CTxMemPoolEntry FromTx(const CMutableTransaction &tx, CTxMemPool *pool = NULL); CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
CTxMemPoolEntry FromTx(const CTransaction &tx, CTxMemPool *pool = NULL); CTxMemPoolEntry FromTx(const CTransaction &tx);
// Change the default value // Change the default value
TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; } TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; }
TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; } TestMemPoolEntryHelper &Time(int64_t _time) { nTime = _time; return *this; }
TestMemPoolEntryHelper &Priority(double _priority) { dPriority = _priority; return *this; }
TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; } TestMemPoolEntryHelper &Height(unsigned int _height) { nHeight = _height; return *this; }
TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; } TestMemPoolEntryHelper &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; } TestMemPoolEntryHelper &SigOpsCost(unsigned int _sigopsCost) { sigOpCost = _sigopsCost; return *this; }

View file

@ -19,22 +19,17 @@
#include "version.h" #include "version.h"
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight, int64_t _nTime, unsigned int _entryHeight,
CAmount _inChainInputValue,
bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp):
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight),
inChainInputValue(_inChainInputValue),
spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp)
{ {
nTxWeight = GetTransactionWeight(*tx); nTxWeight = GetTransactionWeight(*tx);
nModSize = tx->CalculateModifiedSize(GetTxSize());
nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx); nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
nCountWithDescendants = 1; nCountWithDescendants = 1;
nSizeWithDescendants = GetTxSize(); nSizeWithDescendants = GetTxSize();
nModFeesWithDescendants = nFee; nModFeesWithDescendants = nFee;
CAmount nValueIn = tx->GetValueOut()+nFee;
assert(inChainInputValue <= nValueIn);
feeDelta = 0; feeDelta = 0;
@ -49,16 +44,6 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
*this = other; *this = other;
} }
double
CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
{
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;
}
void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta) void CTxMemPoolEntry::UpdateFeeDelta(int64_t newFeeDelta)
{ {
nModFeesWithDescendants += newFeeDelta - feeDelta; nModFeesWithDescendants += newFeeDelta - feeDelta;
@ -404,11 +389,11 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
// Update transaction for any feeDelta created by PrioritiseTransaction // Update transaction for any feeDelta created by PrioritiseTransaction
// TODO: refactor so that the fee delta is calculated before inserting // TODO: refactor so that the fee delta is calculated before inserting
// into mapTx. // into mapTx.
std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash); std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos != mapDeltas.end()) { if (pos != mapDeltas.end()) {
const std::pair<double, CAmount> &deltas = pos->second; const CAmount &delta = pos->second;
if (deltas.second) { if (delta) {
mapTx.modify(newit, update_fee_delta(deltas.second)); mapTx.modify(newit, update_fee_delta(delta));
} }
} }
@ -875,16 +860,6 @@ CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) con
LOCK(cs); LOCK(cs);
return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this); return minerPolicyEstimator->estimateSmartFee(nBlocks, answerFoundAtBlocks, *this);
} }
double CTxMemPool::estimatePriority(int nBlocks) const
{
LOCK(cs);
return minerPolicyEstimator->estimatePriority(nBlocks);
}
double CTxMemPool::estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks) const
{
LOCK(cs);
return minerPolicyEstimator->estimateSmartPriority(nBlocks, answerFoundAtBlocks, *this);
}
bool bool
CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
@ -920,16 +895,15 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
return true; return true;
} }
void CTxMemPool::PrioritiseTransaction(const uint256& hash, double dPriorityDelta, const CAmount& nFeeDelta) void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)
{ {
{ {
LOCK(cs); LOCK(cs);
std::pair<double, CAmount> &deltas = mapDeltas[hash]; CAmount &delta = mapDeltas[hash];
deltas.first += dPriorityDelta; delta += nFeeDelta;
deltas.second += nFeeDelta;
txiter it = mapTx.find(hash); txiter it = mapTx.find(hash);
if (it != mapTx.end()) { if (it != mapTx.end()) {
mapTx.modify(it, update_fee_delta(deltas.second)); mapTx.modify(it, update_fee_delta(delta));
// Now update all ancestors' modified fees with descendants // Now update all ancestors' modified fees with descendants
setEntries setAncestors; setEntries setAncestors;
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max(); uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
@ -940,18 +914,17 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, double dPriorityDelt
} }
} }
} }
LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", hash.ToString(), dPriorityDelta, FormatMoney(nFeeDelta)); LogPrintf("PrioritiseTransaction: %s feerate += %s\n", hash.ToString(), FormatMoney(nFeeDelta));
} }
void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const void CTxMemPool::ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const
{ {
LOCK(cs); LOCK(cs);
std::map<uint256, std::pair<double, CAmount> >::const_iterator pos = mapDeltas.find(hash); std::map<uint256, CAmount>::const_iterator pos = mapDeltas.find(hash);
if (pos == mapDeltas.end()) if (pos == mapDeltas.end())
return; return;
const std::pair<double, CAmount> &deltas = pos->second; const CAmount &delta = pos->second;
dPriorityDelta += deltas.first; nFeeDelta += delta;
nFeeDelta += deltas.second;
} }
void CTxMemPool::ClearPrioritisation(const uint256 hash) void CTxMemPool::ClearPrioritisation(const uint256 hash)

View file

@ -29,18 +29,6 @@
class CAutoFile; class CAutoFile;
class CBlockIndex; class CBlockIndex;
inline double AllowFreeThreshold()
{
return COIN * 144 / 250;
}
inline bool AllowFree(double dPriority)
{
// Large (in bytes) low-priority (new, small-coin) transactions
// need a fee.
return dPriority > AllowFreeThreshold();
}
/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */ /** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF; static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
@ -84,12 +72,9 @@ private:
CTransactionRef tx; CTransactionRef tx;
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize())
size_t nModSize; //!< ... and modified size for priority
size_t nUsageSize; //!< ... and total memory usage size_t nUsageSize; //!< ... and total memory usage
int64_t nTime; //!< Local time when entering the mempool int64_t nTime; //!< Local time when entering the mempool
double entryPriority; //!< Priority when entering the mempool
unsigned int entryHeight; //!< Chain height when entering the mempool unsigned int entryHeight; //!< Chain height when entering the mempool
CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain
bool spendsCoinbase; //!< keep track of transactions that spend a coinbase bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
int64_t sigOpCost; //!< Total sigop cost int64_t sigOpCost; //!< Total sigop cost
int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block
@ -112,19 +97,14 @@ private:
public: public:
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee, CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
int64_t _nTime, double _entryPriority, unsigned int _entryHeight, int64_t _nTime, unsigned int _entryHeight,
CAmount _inChainInputValue, bool spendsCoinbase, bool spendsCoinbase,
int64_t nSigOpsCost, LockPoints lp); int64_t nSigOpsCost, LockPoints lp);
CTxMemPoolEntry(const CTxMemPoolEntry& other); CTxMemPoolEntry(const CTxMemPoolEntry& other);
const CTransaction& GetTx() const { return *this->tx; } const CTransaction& GetTx() const { return *this->tx; }
CTransactionRef GetSharedTx() const { return this->tx; } CTransactionRef GetSharedTx() 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; } const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const; size_t GetTxSize() const;
size_t GetTxWeight() const { return nTxWeight; } size_t GetTxWeight() const { return nTxWeight; }
@ -512,7 +492,7 @@ private:
public: public:
indirectmap<COutPoint, const CTransaction*> mapNextTx; indirectmap<COutPoint, const CTransaction*> mapNextTx;
std::map<uint256, std::pair<double, CAmount> > mapDeltas; std::map<uint256, CAmount> mapDeltas;
/** Create a new CTxMemPool. /** Create a new CTxMemPool.
*/ */
@ -554,8 +534,8 @@ public:
bool HasNoInputsOf(const CTransaction& tx) const; bool HasNoInputsOf(const CTransaction& tx) const;
/** Affect CreateNewBlock prioritisation of transactions */ /** Affect CreateNewBlock prioritisation of transactions */
void PrioritiseTransaction(const uint256& hash, double dPriorityDelta, const CAmount& nFeeDelta); void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta);
void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const; void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;
void ClearPrioritisation(const uint256 hash); void ClearPrioritisation(const uint256 hash);
public: public:
@ -647,15 +627,6 @@ public:
/** Estimate fee rate needed to get into the next nBlocks */ /** Estimate fee rate needed to get into the next nBlocks */
CFeeRate estimateFee(int nBlocks) const; CFeeRate estimateFee(int nBlocks) const;
/** Estimate priority needed to get into the next nBlocks
* If no answer can be given at nBlocks, return an estimate
* at the lowest number of blocks where one can be given
*/
double estimateSmartPriority(int nBlocks, int *answerFoundAtBlocks = NULL) const;
/** Estimate priority needed to get into the next nBlocks */
double estimatePriority(int nBlocks) const;
/** Write/Read estimates to disk */ /** Write/Read estimates to disk */
bool WriteFeeEstimates(CAutoFile& fileout) const; bool WriteFeeEstimates(CAutoFile& fileout) const;
bool ReadFeeEstimates(CAutoFile& filein); bool ReadFeeEstimates(CAutoFile& filein);
@ -719,17 +690,4 @@ public:
bool HaveCoins(const uint256 &txid) const; bool HaveCoins(const uint256 &txid) const;
}; };
// We want to sort transactions by coin age priority
typedef std::pair<double, CTxMemPool::txiter> TxCoinAgePriority;
struct TxCoinAgePriorityCompare
{
bool operator()(const TxCoinAgePriority& a, const TxCoinAgePriority& b)
{
if (a.first == b.first)
return CompareTxMemPoolEntryByScore()(*(b.second), *(a.second)); //Reverse order to make sort less than
return a.first < b.first;
}
};
#endif // BITCOIN_TXMEMPOOL_H #endif // BITCOIN_TXMEMPOOL_H

View file

@ -720,11 +720,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CAmount nFees = nValueIn-nValueOut; CAmount nFees = nValueIn-nValueOut;
// nModifiedFees includes any fee deltas from PrioritiseTransaction // nModifiedFees includes any fee deltas from PrioritiseTransaction
CAmount nModifiedFees = nFees; CAmount nModifiedFees = nFees;
double nPriorityDummy = 0; pool.ApplyDelta(hash, nModifiedFees);
pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
CAmount inChainInputValue;
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
// Keep track of transactions that spend a coinbase, which we re-scan // Keep track of transactions that spend a coinbase, which we re-scan
// during reorgs to ensure COINBASE_MATURITY is still met. // during reorgs to ensure COINBASE_MATURITY is still met.
@ -737,8 +733,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
} }
} }
CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, chainActive.Height(), CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, chainActive.Height(),
inChainInputValue, fSpendsCoinbase, nSigOpsCost, lp); fSpendsCoinbase, nSigOpsCost, lp);
unsigned int nSize = entry.GetTxSize(); unsigned int nSize = entry.GetTxSize();
// Check that the transaction doesn't have an excessive number of // Check that the transaction doesn't have an excessive number of
@ -753,32 +749,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize); CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", 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) && nModifiedFees < ::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");
} }
// Continuously rate-limit free (really, very-low-fee) transactions // No transactions are allowed below minRelayTxFee except from disconnected blocks
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
// be annoying or make others' transactions take longer to confirm. return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize))
{
static CCriticalSection csFreeLimiter;
static double dFreeCount;
static int64_t nLastTime;
int64_t nNow = GetTime();
LOCK(csFreeLimiter);
// Use an exponentially decaying ~10-minute window:
dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime));
nLastTime = nNow;
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount + nSize >= GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000)
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction");
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
} }
if (nAbsurdFee && nFees > nAbsurdFee) if (nAbsurdFee && nFees > nAbsurdFee)
@ -4205,7 +4180,6 @@ bool LoadMempool(void)
} }
uint64_t num; uint64_t num;
file >> num; file >> num;
double prioritydummy = 0;
while (num--) { while (num--) {
CTransactionRef tx; CTransactionRef tx;
int64_t nTime; int64_t nTime;
@ -4216,7 +4190,7 @@ bool LoadMempool(void)
CAmount amountdelta = nFeeDelta; CAmount amountdelta = nFeeDelta;
if (amountdelta) { if (amountdelta) {
mempool.PrioritiseTransaction(tx->GetHash(), prioritydummy, amountdelta); mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);
} }
CValidationState state; CValidationState state;
if (nTime + nExpiryTimeout > nNow) { if (nTime + nExpiryTimeout > nNow) {
@ -4237,7 +4211,7 @@ bool LoadMempool(void)
file >> mapDeltas; file >> mapDeltas;
for (const auto& i : mapDeltas) { for (const auto& i : mapDeltas) {
mempool.PrioritiseTransaction(i.first, prioritydummy, i.second); mempool.PrioritiseTransaction(i.first, i.second);
} }
} catch (const std::exception& e) { } catch (const std::exception& e) {
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what()); LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
@ -4258,7 +4232,7 @@ void DumpMempool(void)
{ {
LOCK(mempool.cs); LOCK(mempool.cs);
for (const auto &i : mempool.mapDeltas) { for (const auto &i : mempool.mapDeltas) {
mapDeltas[i.first] = i.second.second; mapDeltas[i.first] = i.second;
} }
vinfo = mempool.infoAll(); vinfo = mempool.infoAll();
} }

View file

@ -122,8 +122,6 @@ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */ /** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000; static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
static const unsigned int DEFAULT_LIMITFREERELAY = 0;
static const bool DEFAULT_RELAYPRIORITY = true;
static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
/** Maximum age of our tip in seconds for us to be considered current for fee estimation */ /** Maximum age of our tip in seconds for us to be considered current for fee estimation */
static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60; static const int64_t MAX_FEE_ESTIMATION_TIP_AGE = 3 * 60 * 60;

View file

@ -40,7 +40,6 @@ CWallet* pwalletMain = NULL;
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE); CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET; unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE; bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
bool fWalletRbf = DEFAULT_WALLET_RBF; bool fWalletRbf = DEFAULT_WALLET_RBF;
const char * DEFAULT_WALLET_DAT = "wallet.dat"; const char * DEFAULT_WALLET_DAT = "wallet.dat";
@ -2379,7 +2378,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
CAmount nValueToSelect = nValue; CAmount nValueToSelect = nValue;
if (nSubtractFeeFromAmount == 0) if (nSubtractFeeFromAmount == 0)
nValueToSelect += nFeeRet; nValueToSelect += nFeeRet;
double dPriority = 0;
// vouts to the payees // vouts to the payees
for (const auto& recipient : vecSend) for (const auto& recipient : vecSend)
{ {
@ -2420,19 +2418,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
strFailReason = _("Insufficient funds"); strFailReason = _("Insufficient funds");
return false; return false;
} }
for (const auto& pcoin : setCoins)
{
CAmount nCredit = pcoin.first->tx->vout[pcoin.second].nValue;
//The coin age after the next block (depth+1) is used instead of the current,
//reflecting an assumption the user would accept a bit more delay for
//a chance at a free transaction.
//But mempool inputs might still be in the mempool, so their age stays 0
int age = pcoin.first->GetDepthInMainChain();
assert(age >= 0);
if (age != 0)
age += 1;
dPriority += (double)nCredit * age;
}
const CAmount nChange = nValueIn - nValueToSelect; const CAmount nChange = nValueIn - nValueToSelect;
if (nChange > 0) if (nChange > 0)
@ -2544,7 +2529,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
unsigned int nBytes = GetVirtualTransactionSize(txNew); unsigned int nBytes = GetVirtualTransactionSize(txNew);
CTransaction txNewConst(txNew); CTransaction txNewConst(txNew);
dPriority = txNewConst.ComputePriority(dPriority, nBytes);
// Remove scriptSigs to eliminate the fee calculation dummy signatures // Remove scriptSigs to eliminate the fee calculation dummy signatures
for (auto& vin : txNew.vin) { for (auto& vin : txNew.vin) {
@ -2557,16 +2541,6 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (coinControl && coinControl->nConfirmTarget > 0) if (coinControl && coinControl->nConfirmTarget > 0)
currentConfirmationTarget = coinControl->nConfirmTarget; currentConfirmationTarget = coinControl->nConfirmTarget;
// Can we complete this as a free transaction?
if (fSendFreeTransactions && nBytes <= MAX_FREE_TRANSACTION_CREATE_SIZE)
{
// Not enough fee: enough priority?
double dPriorityNeeded = mempool.estimateSmartPriority(currentConfirmationTarget);
// Require at least hard-coded AllowFree.
if (dPriority >= dPriorityNeeded && AllowFree(dPriority))
break;
}
CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool); CAmount nFeeNeeded = GetMinimumFee(nBytes, currentConfirmationTarget, mempool);
if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) { if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
nFeeNeeded = coinControl->nMinimumTotalFee; nFeeNeeded = coinControl->nMinimumTotalFee;
@ -2655,7 +2629,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
// Lastly, ensure this tx will pass the mempool's chain limits // Lastly, ensure this tx will pass the mempool's chain limits
LockPoints lp; LockPoints lp;
CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, 0, 0, false, 0, lp); CTxMemPoolEntry entry(wtxNew.tx, 0, 0, 0, false, 0, lp);
CTxMemPool::setEntries setAncestors; CTxMemPool::setEntries setAncestors;
size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
@ -3548,8 +3522,6 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup")); strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions on startup"));
strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup")); strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet on startup"));
if (showDebug)
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), DEFAULT_SEND_FREE_TRANSACTIONS));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE)); strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), DEFAULT_SPEND_ZEROCONF_CHANGE));
strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET)); strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET)); strUsage += HelpMessageOpt("-usehd", _("Use hierarchical deterministic key generation (HD) after BIP32. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
@ -3870,12 +3842,8 @@ bool CWallet::ParameterInteraction()
} }
nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
fWalletRbf = GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF); fWalletRbf = GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
if (fSendFreeTransactions && GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
return InitError("Creation of free transactions with their relay disabled is not supported.");
return true; return true;
} }

View file

@ -38,7 +38,6 @@ extern CWallet* pwalletMain;
extern CFeeRate payTxFee; extern CFeeRate payTxFee;
extern unsigned int nTxConfirmTarget; extern unsigned int nTxConfirmTarget;
extern bool bSpendZeroConfChange; extern bool bSpendZeroConfChange;
extern bool fSendFreeTransactions;
extern bool fWalletRbf; extern bool fWalletRbf;
static const unsigned int DEFAULT_KEYPOOL_SIZE = 100; static const unsigned int DEFAULT_KEYPOOL_SIZE = 100;
@ -56,16 +55,12 @@ static const CAmount MIN_CHANGE = CENT;
static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2; static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2;
//! Default for -spendzeroconfchange //! Default for -spendzeroconfchange
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true; static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
//! Default for -sendfreetransactions
static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
//! Default for -walletrejectlongchains //! Default for -walletrejectlongchains
static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false; static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
//! -txconfirmtarget default //! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6; static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default //! -walletrbf default
static const bool DEFAULT_WALLET_RBF = false; static const bool DEFAULT_WALLET_RBF = false;
//! Largest (in bytes) free transaction we're willing to create
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true; static const bool DEFAULT_WALLETBROADCAST = true;
static const bool DEFAULT_DISABLE_WALLET = false; static const bool DEFAULT_DISABLE_WALLET = false;
//! if set, all keys will be derived by using BIP32 //! if set, all keys will be derived by using BIP32