mirror of
https://github.com/dashpay/dash.git
synced 2024-12-24 19:42:46 +01:00
Merge bitcoin#9602: Remove coin age priority and free transactions - implementation (#2768)
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 Signed-off-by: Pasta <Pasta@dash.org> Fix backport and fix dash specific priority code
This commit is contained in:
parent
6350adf1b9
commit
6f90cf7a17
@ -104,7 +104,7 @@
|
||||
# because the rpcpassword is transmitted over the network unencrypted.
|
||||
|
||||
# server=1 tells Dash-Qt to accept JSON-RPC commands.
|
||||
# it is also read by dashd to determine if RPC should be enabled
|
||||
# it is also read by dashd to determine if RPC should be enabled
|
||||
#rpcallowip=10.1.1.34/255.255.255.0
|
||||
#rpcallowip=1.2.3.4/24
|
||||
#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96
|
||||
@ -116,12 +116,7 @@
|
||||
# running on another host using this option:
|
||||
#rpcconnect=127.0.0.1
|
||||
|
||||
# Transaction Fee Changes in 0.12.0
|
||||
|
||||
# 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).
|
||||
# Create transactions that have enough fees so they are likely to begin confirmation within n blocks (default: 6).
|
||||
# This setting is over-ridden by the -paytxfee option.
|
||||
#txconfirmtarget=n
|
||||
|
||||
|
@ -21,7 +21,7 @@ CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' {}".format(CM
|
||||
REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"')
|
||||
REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")')
|
||||
# list unsupported, deprecated and duplicate args as they need no documentation
|
||||
SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-blockminsize'])
|
||||
SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-blockminsize', '-sendfreetransactions'])
|
||||
|
||||
def main():
|
||||
used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True)
|
||||
|
@ -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
|
||||
# TODO: redo with eviction
|
||||
# Note had to make sure tx did not have AllowFree priority
|
||||
stop_node(self.nodes[0],0)
|
||||
self.nodes[0]=start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"])
|
||||
|
||||
|
@ -24,8 +24,8 @@ class BIP68Test(BitcoinTestFramework):
|
||||
|
||||
def setup_network(self):
|
||||
self.nodes = []
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-blockprioritysize=0"]))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-blockprioritysize=0", "-acceptnonstdtxn=0"]))
|
||||
self.nodes.append(start_node(0, self.options.tmpdir, []))
|
||||
self.nodes.append(start_node(1, self.options.tmpdir, ["-acceptnonstdtxn=0"]))
|
||||
self.is_network_split = False
|
||||
self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
|
||||
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.
|
||||
# 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 = get_mocktime()
|
||||
for i in range(10):
|
||||
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)
|
||||
|
||||
# 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
|
||||
self.nodes[0].setmocktime(cur_time+600)
|
||||
|
@ -103,7 +103,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
||||
|
||||
# Check that ancestor modified fees includes fee deltas from
|
||||
# prioritisetransaction
|
||||
self.nodes[0].prioritisetransaction(chain[0], 0, 1000)
|
||||
self.nodes[0].prioritisetransaction(chain[0], 1000)
|
||||
mempool = self.nodes[0].getrawmempool(True)
|
||||
ancestor_fees = 0
|
||||
for x in chain:
|
||||
@ -111,11 +111,11 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
||||
assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN + 1000)
|
||||
|
||||
# Undo the prioritisetransaction for later tests
|
||||
self.nodes[0].prioritisetransaction(chain[0], 0, -1000)
|
||||
self.nodes[0].prioritisetransaction(chain[0], -1000)
|
||||
|
||||
# Check that descendant modified fees includes fee deltas from
|
||||
# prioritisetransaction
|
||||
self.nodes[0].prioritisetransaction(chain[-1], 0, 1000)
|
||||
self.nodes[0].prioritisetransaction(chain[-1], 1000)
|
||||
mempool = self.nodes[0].getrawmempool(True)
|
||||
|
||||
descendant_fees = 0
|
||||
@ -136,7 +136,7 @@ class MempoolPackagesTest(BitcoinTestFramework):
|
||||
assert_equal(len(self.nodes[0].getrawmempool()), 0)
|
||||
# Prioritise a transaction that has been mined, then add it back to the
|
||||
# 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())
|
||||
# Keep node1's tip synced with node0
|
||||
self.nodes[1].invalidateblock(self.nodes[1].getbestblockhash())
|
||||
|
@ -52,10 +52,8 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
||||
assert(sizes[i] > MAX_BLOCK_SIZE) # Fail => raise utxo_count
|
||||
|
||||
# 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
|
||||
# the priority to ensure its not mined due to priority)
|
||||
self.nodes[0].prioritisetransaction(txids[0][0], 0, int(3*base_fee*COIN))
|
||||
self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0)
|
||||
# also check that a different entry in the cheapest bucket is NOT mined
|
||||
self.nodes[0].prioritisetransaction(txids[0][0], int(3*base_fee*COIN))
|
||||
|
||||
self.nodes[0].generate(1)
|
||||
|
||||
@ -74,7 +72,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
||||
|
||||
# Add a prioritisation before a tx is in the mempool (de-prioritising a
|
||||
# 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
|
||||
self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash())
|
||||
@ -98,7 +96,7 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
||||
if (x != high_fee_tx):
|
||||
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()
|
||||
assert(len(utxo_list) > 0)
|
||||
utxo = utxo_list[0]
|
||||
@ -106,44 +104,34 @@ class PrioritiseTransactionTest(BitcoinTestFramework):
|
||||
inputs = []
|
||||
outputs = {}
|
||||
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)
|
||||
tx_hex = self.nodes[0].signrawtransaction(raw_tx)["hex"]
|
||||
txid = self.nodes[0].sendrawtransaction(tx_hex)
|
||||
|
||||
# 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"]
|
||||
tx_id = self.nodes[0].decoderawtransaction(tx_hex)["txid"]
|
||||
|
||||
try:
|
||||
self.nodes[0].sendrawtransaction(tx2_hex)
|
||||
self.nodes[0].sendrawtransaction(tx_hex)
|
||||
except JSONRPCException as exp:
|
||||
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:
|
||||
assert(False)
|
||||
|
||||
# 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
|
||||
# accepted.
|
||||
self.nodes[0].prioritisetransaction(tx2_id, 0, int(self.relayfee*COIN))
|
||||
self.nodes[0].prioritisetransaction(tx_id, int(self.relayfee*COIN))
|
||||
|
||||
self.log.info("Assert that prioritised free transaction is accepted to mempool")
|
||||
assert_equal(self.nodes[0].sendrawtransaction(tx2_hex), tx2_id)
|
||||
assert(tx2_id in self.nodes[0].getrawmempool())
|
||||
assert_equal(self.nodes[0].sendrawtransaction(tx_hex), tx_id)
|
||||
assert(tx_id in self.nodes[0].getrawmempool())
|
||||
|
||||
# Test that calling prioritisetransaction is sufficient to trigger
|
||||
# getblocktemplate to (eventually) return a new block.
|
||||
mock_time = get_mocktime()
|
||||
self.nodes[0].setmocktime(mock_time)
|
||||
template = self.nodes[0].getblocktemplate()
|
||||
self.nodes[0].prioritisetransaction(tx2_id, 0, -int(self.relayfee*COIN))
|
||||
self.nodes[0].prioritisetransaction(tx2_id, -int(self.relayfee*COIN))
|
||||
self.nodes[0].setmocktime(mock_time+10)
|
||||
new_template = self.nodes[0].getblocktemplate()
|
||||
|
||||
|
@ -66,10 +66,11 @@ def small_txpuzzle_randfee(from_node, conflist, unconflist, amount, min_fee, fee
|
||||
|
||||
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
|
||||
and they will have low priority.
|
||||
We need to generate a lot of inputs so we can generate a ton of transactions.
|
||||
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.
|
||||
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()
|
||||
tx = CTransaction()
|
||||
@ -150,7 +151,7 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
def setup_network(self):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
self.nodes = []
|
||||
@ -159,7 +160,7 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
"-whitelist=127.0.0.1"]))
|
||||
|
||||
self.log.info("This test is time consuming, please be patient")
|
||||
self.log.info("Splitting inputs to small size so we can generate low priority tx's")
|
||||
self.log.info("Splitting inputs so we can generate tx's")
|
||||
self.txouts = []
|
||||
self.txouts2 = []
|
||||
# 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
|
||||
# so the estimates would not be affected by the splitting transactions
|
||||
# Node1 mines small blocks but that are bigger than the expected transaction rate,
|
||||
# and allows free transactions.
|
||||
# Node1 mines small blocks but that are bigger than the expected transaction rate.
|
||||
# NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes,
|
||||
# (17k is room enough for 110 or so transactions)
|
||||
self.nodes.append(start_node(1, self.options.tmpdir,
|
||||
["-blockprioritysize=1500", "-blockmaxsize=17000",
|
||||
["-blockmaxsize=17000",
|
||||
"-maxorphantx=1000"]))
|
||||
connect_nodes(self.nodes[1], 0)
|
||||
|
||||
# Node2 is a stingy miner, that
|
||||
# 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))
|
||||
connect_nodes(self.nodes[0], 2)
|
||||
|
@ -501,47 +501,6 @@ def make_change(from_node, amount_in, amount_out, fee):
|
||||
outputs[from_node.getnewaddress()] = change
|
||||
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):
|
||||
"""
|
||||
Create a random transaction.
|
||||
|
@ -12,14 +12,13 @@
|
||||
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
|
||||
{
|
||||
int64_t nTime = 0;
|
||||
double dPriority = 10.0;
|
||||
unsigned int nHeight = 1;
|
||||
bool spendsCoinbase = false;
|
||||
unsigned int sigOpCost = 4;
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
|
||||
MakeTransactionRef(tx), nFee, nTime, dPriority, nHeight,
|
||||
tx.GetValueOut(), spendsCoinbase, sigOpCost, lp));
|
||||
MakeTransactionRef(tx), nFee, nTime, nHeight,
|
||||
spendsCoinbase, sigOpCost, lp));
|
||||
}
|
||||
|
||||
// Right now this is only testing eviction performance in an extremely small
|
||||
|
@ -243,24 +243,6 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
|
||||
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 Coin& coin = AccessCoin(txin.prevout);
|
||||
if (coin.IsSpent()) continue;
|
||||
if (coin.nHeight <= nHeight) {
|
||||
dResult += (double)coin.out.nValue * (nHeight-coin.nHeight);
|
||||
inChainInputValue += coin.out.nValue;
|
||||
}
|
||||
}
|
||||
return tx.ComputePriority(dResult);
|
||||
}
|
||||
|
||||
static const size_t MAX_OUTPUTS_PER_BLOCK = MaxBlockSize(true) / ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.
|
||||
|
||||
const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
|
||||
|
@ -280,13 +280,6 @@ public:
|
||||
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
|
||||
bool HaveInputs(const CTransaction& tx) const;
|
||||
|
||||
/**
|
||||
* Return priority of tx at height nHeight. 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;
|
||||
|
||||
private:
|
||||
CCoinsMap::iterator FetchCoin(const COutPoint &outpoint) const;
|
||||
|
||||
|
12
src/init.cpp
12
src/init.cpp
@ -568,8 +568,6 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS));
|
||||
strUsage += HelpMessageOpt("-logthreadnames", strprintf("Add thread names to debug messages (default: %u)", DEFAULT_LOGTHREADNAMES));
|
||||
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("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE));
|
||||
}
|
||||
@ -581,7 +579,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-printtodebuglog", strprintf(_("Send trace/debug info to debug.log file (default: %u)"), 1));
|
||||
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)"));
|
||||
AppendParamsHelpMessages(strUsage, showDebug);
|
||||
@ -621,7 +619,6 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
|
||||
strUsage += HelpMessageGroup(_("Block creation options:"));
|
||||
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)));
|
||||
if (showDebug)
|
||||
strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios");
|
||||
@ -1231,17 +1228,18 @@ bool AppInitParameterInteraction()
|
||||
if (nConnectTimeout <= 0)
|
||||
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 set it to zero then
|
||||
// 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.
|
||||
if (IsArgSet("-minrelaytxfee"))
|
||||
{
|
||||
CAmount n = 0;
|
||||
if (!ParseMoney(GetArg("-minrelaytxfee", ""), n) || 0 == n)
|
||||
if (!ParseMoney(GetArg("-minrelaytxfee", ""), n)) {
|
||||
return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", "")));
|
||||
}
|
||||
// High fee check is done afterward in CWallet::ParameterInteraction()
|
||||
::minRelayTxFee = CFeeRate(n);
|
||||
} else if (incrementalRelayFee > ::minRelayTxFee) {
|
||||
|
144
src/miner.cpp
144
src/miner.cpp
@ -50,8 +50,8 @@
|
||||
//
|
||||
// Unconfirmed transactions in the memory pool often depend on other
|
||||
// transactions in the memory pool. When we select transactions from the
|
||||
// pool, we select by highest priority or fee rate, so we might consider
|
||||
// transactions that depend on transactions that aren't yet in the block.
|
||||
// pool, we select by highest fee rate of a transaction combined with all
|
||||
// its ancestors.
|
||||
|
||||
uint64_t nLastBlockTx = 0;
|
||||
uint64_t nLastBlockSize = 0;
|
||||
@ -125,9 +125,6 @@ void BlockAssembler::resetBlock()
|
||||
// These counters do not include coinbase tx
|
||||
nBlockTx = 0;
|
||||
nFees = 0;
|
||||
|
||||
lastFewTxs = 0;
|
||||
blockFinished = false;
|
||||
}
|
||||
|
||||
std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
|
||||
@ -180,8 +177,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
||||
}
|
||||
}
|
||||
|
||||
addPriorityTxs();
|
||||
|
||||
int nPackagesSelected = 0;
|
||||
int nDescendantsUpdated = 0;
|
||||
addPackageTxs(nPackagesSelected, nDescendantsUpdated);
|
||||
@ -252,17 +247,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
||||
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)
|
||||
{
|
||||
for (CTxMemPool::setEntries::iterator iit = testSet.begin(); iit != testSet.end(); ) {
|
||||
@ -300,50 +284,6 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter)
|
||||
{
|
||||
if (nBlockSize + iter->GetTxSize() >= nBlockMaxSize) {
|
||||
// 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 (nBlockSize > nBlockMaxSize - 100 || lastFewTxs > 50) {
|
||||
blockFinished = true;
|
||||
return false;
|
||||
}
|
||||
// Once we're within 1000 bytes of a full block, only look at 50 more txs
|
||||
// to try to fill the remaining space.
|
||||
if (nBlockSize > nBlockMaxSize - 1000) {
|
||||
lastFewTxs++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int nMaxBlockSigOps = MaxBlockSigOps(fDIP0001ActiveAtTip);
|
||||
if (nBlockSigOps + iter->GetSigOpCount() >= nMaxBlockSigOps) {
|
||||
// If the block has room for no more sig ops then
|
||||
// flag that the block is finished
|
||||
if (nBlockSigOps > nMaxBlockSigOps - 2) {
|
||||
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;
|
||||
|
||||
if (!llmq::chainLocksHandler->IsTxSafeForMining(iter->GetTx().GetHash())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
|
||||
{
|
||||
pblock->vtx.emplace_back(iter->GetSharedTx());
|
||||
@ -357,11 +297,7 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
|
||||
|
||||
bool fPrintPriority = GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
|
||||
if (fPrintPriority) {
|
||||
double dPriority = iter->GetPriority(nHeight);
|
||||
CAmount dummy;
|
||||
mempool.ApplyDeltas(iter->GetTx().GetHash(), dPriority, dummy);
|
||||
LogPrintf("priority %.1f fee %s txid %s\n",
|
||||
dPriority,
|
||||
LogPrintf("fee %s txid %s\n",
|
||||
CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
|
||||
iter->GetTx().GetHash().ToString());
|
||||
}
|
||||
@ -561,80 +497,6 @@ void BlockAssembler::addPackageTxs(int &nPackagesSelected, int &nDescendantsUpda
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
|
||||
{
|
||||
// Update nExtraNonce
|
||||
|
12
src/miner.h
12
src/miner.h
@ -158,10 +158,6 @@ private:
|
||||
int64_t nLockTimeCutoff;
|
||||
const CChainParams& chainparams;
|
||||
|
||||
// Variables used for addPriorityTxs
|
||||
int lastFewTxs;
|
||||
bool blockFinished;
|
||||
|
||||
public:
|
||||
struct Options {
|
||||
Options();
|
||||
@ -183,19 +179,11 @@ private:
|
||||
void AddToBlock(CTxMemPool::txiter iter);
|
||||
|
||||
// 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
|
||||
* Increments nPackagesSelected / nDescendantsUpdated with corresponding
|
||||
* statistics from the package selection (for logging statistics). */
|
||||
void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated);
|
||||
|
||||
// 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()
|
||||
/** Remove confirmed (inBlock) entries from given set */
|
||||
void onlyUnconfirmed(CTxMemPool::setEntries& testSet);
|
||||
|
@ -972,12 +972,12 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
case MSG_BLOCK:
|
||||
return mapBlockIndex.count(inv.hash);
|
||||
|
||||
/*
|
||||
/*
|
||||
Dash Related Inventory Messages
|
||||
|
||||
--
|
||||
|
||||
We shouldn't update the sync times for each of the messages when we already have it.
|
||||
We shouldn't update the sync times for each of the messages when we already have it.
|
||||
We're going to be asking many nodes upfront for the full inventory list, so we'll get duplicates of these.
|
||||
We want to only update the time on new hits, so that we can time out appropriately if needed.
|
||||
*/
|
||||
@ -2142,7 +2142,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
}
|
||||
|
||||
LogPrintf("DSTX -- Got Masternode transaction %s\n", hashTx.ToString());
|
||||
mempool.PrioritiseTransaction(hashTx, 1000, 0.1*COIN);
|
||||
mempool.PrioritiseTransaction(hashTx, 0.1*COIN);
|
||||
mmetaman.DisallowMixing(dmn->proTxHash);
|
||||
}
|
||||
|
||||
@ -2226,7 +2226,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
||||
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
|
||||
}
|
||||
// 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());
|
||||
vEraseQueue.push_back(orphanHash);
|
||||
if (!stateDummy.CorruptionPossible()) {
|
||||
|
@ -450,24 +450,6 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, int *answerFoun
|
||||
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)
|
||||
{
|
||||
fileout << nBestSeenHeight;
|
||||
|
@ -187,7 +187,6 @@ static const double SUFFICIENT_FEETXS = 1;
|
||||
static constexpr double MIN_BUCKET_FEERATE = 1000;
|
||||
static const double MAX_BUCKET_FEERATE = 1e7;
|
||||
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
|
||||
// to give accurate estimates over a large range of potential feerates
|
||||
@ -228,20 +227,6 @@ public:
|
||||
*/
|
||||
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 */
|
||||
void Write(CAutoFile& fileout);
|
||||
|
||||
|
@ -16,8 +16,6 @@ class CCoinsViewCache;
|
||||
|
||||
/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/
|
||||
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 2000000;
|
||||
/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
|
||||
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 10000; // was 50000 in 0.12.0 and it is 0 in Bitcoin since 0.12
|
||||
/** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
|
||||
static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;
|
||||
/** The maximum size for transactions we're willing to relay/mine */
|
||||
|
@ -108,32 +108,6 @@ CAmount CTransaction::GetValueOut() const
|
||||
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 = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
|
||||
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
|
||||
{
|
||||
return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
@ -283,12 +283,6 @@ public:
|
||||
// GetValueIn() is a method on CCoinsViewCache, because
|
||||
// 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.
|
||||
* "Total Size" defined in BIP141 and BIP144.
|
||||
|
@ -348,7 +348,7 @@ void CPrivateSendServer::CommitFinalTransaction(CConnman& connman)
|
||||
// See if the transaction is valid
|
||||
TRY_LOCK(cs_main, lockMain);
|
||||
CValidationState validationState;
|
||||
mempool.PrioritiseTransaction(hashTx, 1000, 0.1 * COIN);
|
||||
mempool.PrioritiseTransaction(hashTx, 0.1 * COIN);
|
||||
if (!lockMain || !AcceptToMemoryPool(mempool, validationState, finalTransaction, false, NULL, false, maxTxFee, true)) {
|
||||
LogPrintf("CPrivateSendServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n");
|
||||
SetNull();
|
||||
|
@ -54,7 +54,7 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge
|
||||
platformStyle(_platformStyle)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
||||
/* Open CSS when configured */
|
||||
this->setStyleSheet(GUIUtil::loadStyleSheet());
|
||||
|
||||
@ -499,11 +499,8 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||
CAmount nChange = 0;
|
||||
unsigned int nBytes = 0;
|
||||
unsigned int nBytesInputs = 0;
|
||||
double dPriority = 0;
|
||||
double dPriorityInputs = 0;
|
||||
unsigned int nQuantity = 0;
|
||||
int nQuantityUncompressed = 0;
|
||||
bool fAllowFree = false;
|
||||
|
||||
std::vector<COutPoint> vCoinControl;
|
||||
std::vector<COutput> vOutputs;
|
||||
@ -527,9 +524,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||
// Amount
|
||||
nAmount += out.tx->tx->vout[out.i].nValue;
|
||||
|
||||
// Priority
|
||||
dPriorityInputs += (double)out.tx->tx->vout[out.i].nValue * (out.nDepth+1);
|
||||
|
||||
// Bytes
|
||||
CTxDestination address;
|
||||
if(ExtractDestination(out.tx->tx->vout[out.i].scriptPubKey, address))
|
||||
@ -539,8 +533,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||
if (keyid && model->getPubKey(*keyid, pubkey))
|
||||
{
|
||||
nBytesInputs += (pubkey.IsCompressed() ? 148 : 180);
|
||||
if (!pubkey.IsCompressed())
|
||||
nQuantityUncompressed++;
|
||||
}
|
||||
else
|
||||
nBytesInputs += 148; // in all error cases, simply assume 148 here
|
||||
@ -571,16 +563,6 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
|
||||
// InstantSend Fee
|
||||
if (coinControl->fUseInstantSend) nPayFee = std::max(nPayFee, CTxLockRequest(txDummy).GetMinFee(true));
|
||||
|
||||
// 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)
|
||||
{
|
||||
nChange = nAmount - nPayAmount;
|
||||
@ -690,7 +672,7 @@ void CoinControlDialog::updateView()
|
||||
|
||||
bool treeMode = ui->radioTreeMode->isChecked();
|
||||
QString theme = GUIUtil::getThemeName();
|
||||
|
||||
|
||||
ui->treeWidget->clear();
|
||||
ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox
|
||||
ui->treeWidget->setAlternatingRowColors(!treeMode);
|
||||
|
@ -362,8 +362,6 @@ std::string EntryDescriptionString()
|
||||
" \"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"
|
||||
" \"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"
|
||||
" \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n"
|
||||
" \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n"
|
||||
@ -386,8 +384,6 @@ void entryToJSON(UniValue &info, const CTxMemPoolEntry &e)
|
||||
info.push_back(Pair("modifiedfee", ValueFromAmount(e.GetModifiedFee())));
|
||||
info.push_back(Pair("time", e.GetTime()));
|
||||
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("descendantsize", e.GetSizeWithDescendants()));
|
||||
info.push_back(Pair("descendantfees", e.GetModFeesWithDescendants()));
|
||||
|
@ -130,11 +130,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
||||
{ "keypoolrefill", 0, "newsize" },
|
||||
{ "getrawmempool", 0, "verbose" },
|
||||
{ "estimatefee", 0, "nblocks" },
|
||||
{ "estimatepriority", 0, "nblocks" },
|
||||
{ "estimatesmartfee", 0, "nblocks" },
|
||||
{ "estimatesmartpriority", 0, "nblocks" },
|
||||
{ "prioritisetransaction", 1, "priority_delta" },
|
||||
{ "prioritisetransaction", 2, "fee_delta" },
|
||||
{ "prioritisetransaction", 1, "fee_delta" },
|
||||
{ "setban", 2, "bantime" },
|
||||
{ "setban", 3, "absolute" },
|
||||
{ "setbip69enabled", 0, "enabled" },
|
||||
|
@ -264,31 +264,28 @@ UniValue getmininginfo(const JSONRPCRequest& request)
|
||||
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
|
||||
UniValue prioritisetransaction(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 3)
|
||||
if (request.fHelp || request.params.size() != 2)
|
||||
throw std::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"
|
||||
"\nArguments:\n"
|
||||
"1. \"txid\" (string, required) The transaction id.\n"
|
||||
"2. priority_delta (numeric, required) The priority to add or subtract.\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_duffs / txsize) \n"
|
||||
"3. fee_delta (numeric, required) The fee value (in duffs) to add (or subtract, if negative).\n"
|
||||
"2. fee_delta (numeric, required) The fee value (in duffs) to add (or subtract, if negative).\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"
|
||||
"\nResult:\n"
|
||||
"true (boolean) Returns true\n"
|
||||
"\nExamples:\n"
|
||||
+ HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
|
||||
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
|
||||
+ HelpExampleCli("prioritisetransaction", "\"txid\" 10000")
|
||||
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 10000")
|
||||
);
|
||||
|
||||
LOCK(cs_main);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -861,33 +858,6 @@ UniValue estimatefee(const JSONRPCRequest& request)
|
||||
return ValueFromAmount(feeRate.GetFeePerK());
|
||||
}
|
||||
|
||||
UniValue estimatepriority(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 1)
|
||||
throw std::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)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 1)
|
||||
@ -924,48 +894,12 @@ UniValue estimatesmartfee(const JSONRPCRequest& request)
|
||||
return result;
|
||||
}
|
||||
|
||||
UniValue estimatesmartpriority(const JSONRPCRequest& request)
|
||||
{
|
||||
if (request.fHelp || request.params.size() != 1)
|
||||
throw std::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[] =
|
||||
{ // category name actor (function) okSafeMode
|
||||
// --------------------- ------------------------ ----------------------- ----------
|
||||
{ "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} },
|
||||
{ "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", "submitblock", &submitblock, true, {"hexdata","parameters"} },
|
||||
|
||||
@ -973,9 +907,7 @@ static const CRPCCommand commands[] =
|
||||
{ "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} },
|
||||
|
||||
{ "util", "estimatefee", &estimatefee, true, {"nblocks"} },
|
||||
{ "util", "estimatepriority", &estimatepriority, true, {"nblocks"} },
|
||||
{ "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} },
|
||||
{ "util", "estimatesmartpriority", &estimatesmartpriority, true, {"nblocks"} },
|
||||
};
|
||||
|
||||
void RegisterMiningRPCCommands(CRPCTable &t)
|
||||
|
@ -67,7 +67,7 @@ UniValue getinfo(const JSONRPCRequest& request)
|
||||
" \"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"
|
||||
" \"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"
|
||||
"}\n"
|
||||
"\nExamples:\n"
|
||||
|
@ -416,7 +416,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request)
|
||||
" }\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"
|
||||
" \"localaddresses\": [ (array) list of local addresses\n"
|
||||
" {\n"
|
||||
|
@ -125,28 +125,28 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
|
||||
tx1.vout.resize(1);
|
||||
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 */
|
||||
CMutableTransaction tx2 = CMutableTransaction();
|
||||
tx2.vout.resize(1);
|
||||
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 */
|
||||
CMutableTransaction tx3 = CMutableTransaction();
|
||||
tx3.vout.resize(1);
|
||||
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 */
|
||||
CMutableTransaction tx4 = CMutableTransaction();
|
||||
tx4.vout.resize(1);
|
||||
tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 */
|
||||
CMutableTransaction tx5 = CMutableTransaction();
|
||||
@ -154,7 +154,6 @@ BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
|
||||
tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
tx5.vout[0].nValue = 11 * COIN;
|
||||
entry.nTime = 1;
|
||||
entry.dPriority = 10.0;
|
||||
pool.addUnchecked(tx5.GetHash(), entry.Fee(10000LL).FromTx(tx5));
|
||||
BOOST_CHECK_EQUAL(pool.size(), 5);
|
||||
|
||||
@ -327,14 +326,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
|
||||
tx1.vout.resize(1);
|
||||
tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 */
|
||||
CMutableTransaction tx2 = CMutableTransaction();
|
||||
tx2.vout.resize(1);
|
||||
tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 = ::GetSerializeSize(tx2, SER_NETWORK, PROTOCOL_VERSION);
|
||||
|
||||
/* lowest fee */
|
||||
@ -342,14 +341,14 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
|
||||
tx3.vout.resize(1);
|
||||
tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 */
|
||||
CMutableTransaction tx4 = CMutableTransaction();
|
||||
tx4.vout.resize(1);
|
||||
tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
|
||||
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 */
|
||||
CMutableTransaction tx5 = CMutableTransaction();
|
||||
@ -407,7 +406,6 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
|
||||
/* set the fee to just below tx2's feerate when including ancestor */
|
||||
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));
|
||||
BOOST_CHECK_EQUAL(pool.size(), 7);
|
||||
sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
|
||||
@ -433,7 +431,6 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
{
|
||||
CTxMemPool pool;
|
||||
TestMemPoolEntryHelper entry;
|
||||
entry.dPriority = 10.0;
|
||||
|
||||
CMutableTransaction tx1 = CMutableTransaction();
|
||||
tx1.vin.resize(1);
|
||||
@ -441,7 +438,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
tx1.vout.resize(1);
|
||||
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
|
||||
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();
|
||||
tx2.vin.resize(1);
|
||||
@ -449,7 +446,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
tx2.vout.resize(1);
|
||||
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
|
||||
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
|
||||
BOOST_CHECK(pool.exists(tx1.GetHash()));
|
||||
@ -459,7 +456,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
BOOST_CHECK(pool.exists(tx1.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();
|
||||
tx3.vin.resize(1);
|
||||
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
|
||||
@ -467,7 +464,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
tx3.vout.resize(1);
|
||||
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
|
||||
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)
|
||||
BOOST_CHECK(!pool.exists(tx1.GetHash()));
|
||||
@ -530,10 +527,10 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
|
||||
tx7.vout[1].nValue = 10 * COIN;
|
||||
|
||||
pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4, &pool));
|
||||
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
|
||||
pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6, &pool));
|
||||
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
|
||||
pool.addUnchecked(tx4.GetHash(), entry.Fee(7000LL).FromTx(tx4));
|
||||
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
|
||||
pool.addUnchecked(tx6.GetHash(), entry.Fee(1100LL).FromTx(tx6));
|
||||
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
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
|
||||
@ -542,8 +539,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
BOOST_CHECK(!pool.exists(tx7.GetHash()));
|
||||
|
||||
if (!pool.exists(tx5.GetHash()))
|
||||
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
|
||||
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
|
||||
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
|
||||
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
|
||||
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
|
||||
BOOST_CHECK(pool.exists(tx4.GetHash()));
|
||||
@ -551,8 +548,8 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
|
||||
BOOST_CHECK(pool.exists(tx6.GetHash()));
|
||||
BOOST_CHECK(!pool.exists(tx7.GetHash()));
|
||||
|
||||
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool));
|
||||
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
|
||||
pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5));
|
||||
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7));
|
||||
|
||||
std::vector<CTransactionRef> vtx;
|
||||
SetMockTime(42);
|
||||
|
@ -90,7 +90,6 @@ bool TestSequenceLocks(const CTransaction &tx, int flags)
|
||||
// Test suite for ancestor feerate transaction selection.
|
||||
// Implemented as an additional function, rather than a separate test case,
|
||||
// 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)
|
||||
{
|
||||
// Disable free transactions, otherwise TX selection is non-deterministic
|
||||
@ -207,7 +206,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
uint256 hash;
|
||||
TestMemPoolEntryHelper entry;
|
||||
entry.nFee = 11;
|
||||
entry.dPriority = 111.0;
|
||||
entry.nHeight = 11;
|
||||
|
||||
fCheckpointsEnabled = false;
|
||||
@ -328,7 +326,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
||||
BOOST_CHECK_THROW(AssemblerForTest(chainparams).CreateNewBlock(scriptPubKey), std::runtime_error);
|
||||
mempool.clear();
|
||||
|
||||
// child with higher priority than parent
|
||||
// child with higher feerate than parent
|
||||
tx.vin[0].scriptSig = CScript() << OP_1;
|
||||
tx.vin[0].prevout.hash = txFirst[1]->GetHash();
|
||||
tx.vout[0].nValue = BLOCKSUBSIDY-HIGHFEE;
|
||||
|
@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
||||
for (int k = 0; k < 4; k++) { // add 4 fee txs
|
||||
tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -131,7 +131,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
||||
for (int k = 0; k < 4; k++) { // add 4 fee txs
|
||||
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -168,7 +168,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
||||
for (int k = 0; k < 4; k++) { // add 4 fee txs
|
||||
tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
|
||||
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);
|
||||
if (ptx)
|
||||
block.push_back(ptx);
|
||||
@ -184,15 +184,13 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
|
||||
}
|
||||
|
||||
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
|
||||
// and that estimateSmartPriority returns essentially an infinite value
|
||||
mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool));
|
||||
mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx));
|
||||
// evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5]
|
||||
mpool.TrimToSize(1);
|
||||
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
|
||||
for (int i = 1; i < 10; i++) {
|
||||
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK());
|
||||
BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK());
|
||||
BOOST_CHECK(mpool.estimateSmartPriority(i) == INF_PRIORITY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,14 +203,14 @@ TestChainSetup::~TestChainSetup()
|
||||
}
|
||||
|
||||
|
||||
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool) {
|
||||
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) {
|
||||
CTransaction txn(tx);
|
||||
return FromTx(txn, pool);
|
||||
return FromTx(txn);
|
||||
}
|
||||
|
||||
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool) {
|
||||
return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, dPriority, nHeight,
|
||||
txn.GetValueOut(), spendsCoinbase, sigOpCount, lp);
|
||||
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn) {
|
||||
return CTxMemPoolEntry(MakeTransactionRef(txn), nFee, nTime, nHeight,
|
||||
spendsCoinbase, sigOpCount, lp);
|
||||
}
|
||||
|
||||
void Shutdown(void* parg)
|
||||
|
@ -82,30 +82,27 @@ struct TestChainDIP3BeforeActivationSetup : public TestChainSetup
|
||||
};
|
||||
|
||||
class CTxMemPoolEntry;
|
||||
class CTxMemPool;
|
||||
|
||||
struct TestMemPoolEntryHelper
|
||||
{
|
||||
// Default values
|
||||
CAmount nFee;
|
||||
int64_t nTime;
|
||||
double dPriority;
|
||||
unsigned int nHeight;
|
||||
bool spendsCoinbase;
|
||||
unsigned int sigOpCount;
|
||||
LockPoints lp;
|
||||
|
||||
TestMemPoolEntryHelper() :
|
||||
nFee(0), nTime(0), dPriority(0.0), nHeight(1),
|
||||
nFee(0), nTime(0), nHeight(1),
|
||||
spendsCoinbase(false), sigOpCount(4) { }
|
||||
|
||||
CTxMemPoolEntry FromTx(const CMutableTransaction &tx, CTxMemPool *pool = NULL);
|
||||
CTxMemPoolEntry FromTx(const CTransaction &tx, CTxMemPool *pool = NULL);
|
||||
CTxMemPoolEntry FromTx(const CMutableTransaction &tx);
|
||||
CTxMemPoolEntry FromTx(const CTransaction &tx);
|
||||
|
||||
// Change the default value
|
||||
TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; 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 &SpendsCoinbase(bool _flag) { spendsCoinbase = _flag; return *this; }
|
||||
TestMemPoolEntryHelper &SigOps(unsigned int _sigops) { sigOpCount = _sigops; return *this; }
|
||||
|
@ -27,22 +27,17 @@
|
||||
#include "llmq/quorums_instantsend.h"
|
||||
|
||||
CTxMemPoolEntry::CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
|
||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||
CAmount _inChainInputValue,
|
||||
int64_t _nTime, unsigned int _entryHeight,
|
||||
bool _spendsCoinbase, unsigned int _sigOps, LockPoints lp):
|
||||
tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
|
||||
inChainInputValue(_inChainInputValue),
|
||||
tx(_tx), nFee(_nFee), nTime(_nTime), entryHeight(_entryHeight),
|
||||
spendsCoinbase(_spendsCoinbase), sigOpCount(_sigOps), lockPoints(lp)
|
||||
{
|
||||
nTxSize = ::GetSerializeSize(*_tx, SER_NETWORK, PROTOCOL_VERSION);
|
||||
nModSize = _tx->CalculateModifiedSize(nTxSize);
|
||||
nUsageSize = RecursiveDynamicUsage(*tx) + memusage::DynamicUsage(tx);
|
||||
|
||||
nCountWithDescendants = 1;
|
||||
nSizeWithDescendants = nTxSize;
|
||||
nModFeesWithDescendants = nFee;
|
||||
CAmount nValueIn = tx->GetValueOut()+nFee;
|
||||
assert(inChainInputValue <= nValueIn);
|
||||
|
||||
feeDelta = 0;
|
||||
|
||||
@ -57,16 +52,6 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& 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)
|
||||
{
|
||||
nModFeesWithDescendants += newFeeDelta - feeDelta;
|
||||
@ -400,11 +385,11 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry,
|
||||
// Update transaction for any feeDelta created by PrioritiseTransaction
|
||||
// TODO: refactor so that the fee delta is calculated before inserting
|
||||
// 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()) {
|
||||
const std::pair<double, CAmount> &deltas = pos->second;
|
||||
if (deltas.second) {
|
||||
mapTx.modify(newit, update_fee_delta(deltas.second));
|
||||
const CAmount &delta = pos->second;
|
||||
if (delta) {
|
||||
mapTx.modify(newit, update_fee_delta(delta));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1350,16 +1335,6 @@ CFeeRate CTxMemPool::estimateSmartFee(int nBlocks, int *answerFoundAtBlocks) con
|
||||
LOCK(cs);
|
||||
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
|
||||
CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
|
||||
@ -1395,16 +1370,15 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTxMemPool::PrioritiseTransaction(const uint256& hash, double dPriorityDelta, const CAmount& nFeeDelta)
|
||||
void CTxMemPool::PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta)
|
||||
{
|
||||
{
|
||||
LOCK(cs);
|
||||
std::pair<double, CAmount> &deltas = mapDeltas[hash];
|
||||
deltas.first += dPriorityDelta;
|
||||
deltas.second += nFeeDelta;
|
||||
CAmount &delta = mapDeltas[hash];
|
||||
delta += nFeeDelta;
|
||||
txiter it = mapTx.find(hash);
|
||||
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
|
||||
setEntries setAncestors;
|
||||
uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
|
||||
@ -1423,18 +1397,17 @@ void CTxMemPool::PrioritiseTransaction(const uint256& hash, double dPriorityDelt
|
||||
++nTransactionsUpdated;
|
||||
}
|
||||
}
|
||||
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);
|
||||
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())
|
||||
return;
|
||||
const std::pair<double, CAmount> &deltas = pos->second;
|
||||
dPriorityDelta += deltas.first;
|
||||
nFeeDelta += deltas.second;
|
||||
const CAmount &delta = pos->second;
|
||||
nFeeDelta += delta;
|
||||
}
|
||||
|
||||
void CTxMemPool::ClearPrioritisation(const uint256 hash)
|
||||
|
@ -33,19 +33,6 @@
|
||||
class CAutoFile;
|
||||
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 Coin to signify they are only in the memory pool (since 0.8) */
|
||||
static const uint32_t MEMPOOL_HEIGHT = 0x7FFFFFFF;
|
||||
|
||||
@ -89,12 +76,9 @@ private:
|
||||
CTransactionRef tx;
|
||||
CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups
|
||||
size_t nTxSize; //!< ... and avoid recomputing tx size
|
||||
size_t nModSize; //!< ... and modified size for priority
|
||||
size_t nUsageSize; //!< ... and total memory usage
|
||||
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
|
||||
CAmount inChainInputValue; //!< Sum of all txin values that are already in blockchain
|
||||
bool spendsCoinbase; //!< keep track of transactions that spend a coinbase
|
||||
unsigned int sigOpCount; //!< Legacy sig ops plus P2SH sig op count
|
||||
int64_t feeDelta; //!< Used for determining the priority of the transaction for mining in a block
|
||||
@ -117,19 +101,14 @@ private:
|
||||
|
||||
public:
|
||||
CTxMemPoolEntry(const CTransactionRef& _tx, const CAmount& _nFee,
|
||||
int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
|
||||
CAmount _inChainInputValue, bool spendsCoinbase,
|
||||
int64_t _nTime, unsigned int _entryHeight,
|
||||
bool spendsCoinbase,
|
||||
unsigned int nSigOps, LockPoints lp);
|
||||
|
||||
CTxMemPoolEntry(const CTxMemPoolEntry& other);
|
||||
|
||||
const CTransaction& GetTx() 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; }
|
||||
size_t GetTxSize() const { return nTxSize; }
|
||||
int64_t GetTime() const { return nTime; }
|
||||
@ -550,7 +529,7 @@ private:
|
||||
|
||||
public:
|
||||
indirectmap<COutPoint, const CTransaction*> mapNextTx;
|
||||
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
|
||||
std::map<uint256, CAmount> mapDeltas;
|
||||
|
||||
/** Create a new CTxMemPool.
|
||||
*/
|
||||
@ -607,8 +586,8 @@ public:
|
||||
bool HasNoInputsOf(const CTransaction& tx) const;
|
||||
|
||||
/** Affect CreateNewBlock prioritisation of transactions */
|
||||
void PrioritiseTransaction(const uint256& hash, double dPriorityDelta, const CAmount& nFeeDelta);
|
||||
void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) const;
|
||||
void PrioritiseTransaction(const uint256& hash, const CAmount& nFeeDelta);
|
||||
void ApplyDelta(const uint256 hash, CAmount &nFeeDelta) const;
|
||||
void ClearPrioritisation(const uint256 hash);
|
||||
|
||||
public:
|
||||
@ -709,15 +688,6 @@ public:
|
||||
/** Estimate fee rate needed to get into the next nBlocks */
|
||||
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 */
|
||||
bool WriteFeeEstimates(CAutoFile& fileout) const;
|
||||
bool ReadFeeEstimates(CAutoFile& filein);
|
||||
@ -782,17 +752,4 @@ public:
|
||||
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override;
|
||||
};
|
||||
|
||||
// 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
|
||||
|
@ -639,7 +639,7 @@ static bool IsCurrentForFeeEstimation()
|
||||
}
|
||||
|
||||
bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const CTransactionRef& ptx, bool fLimitFree,
|
||||
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit,
|
||||
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit,
|
||||
const CAmount& nAbsurdFee, std::vector<COutPoint>& coins_to_uncache, bool fDryRun)
|
||||
{
|
||||
const CTransaction& tx = *ptx;
|
||||
@ -714,7 +714,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
if (itConflicting != pool.mapNextTx.end())
|
||||
{
|
||||
const CTransaction *ptxConflicting = itConflicting->second;
|
||||
|
||||
|
||||
// InstantSend txes are not replacable
|
||||
if(instantsend.HasTxLockRequest(ptxConflicting->GetHash())) {
|
||||
// this tx conflicts with a Transaction Lock Request candidate
|
||||
@ -797,11 +797,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
CAmount nFees = nValueIn-nValueOut;
|
||||
// nModifiedFees includes any fee deltas from PrioritiseTransaction
|
||||
CAmount nModifiedFees = nFees;
|
||||
double nPriorityDummy = 0;
|
||||
pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees);
|
||||
|
||||
CAmount inChainInputValue;
|
||||
double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
|
||||
pool.ApplyDelta(hash, nModifiedFees);
|
||||
|
||||
// Keep track of transactions that spend a coinbase, which we re-scan
|
||||
// during reorgs to ensure COINBASE_MATURITY is still met.
|
||||
@ -814,8 +810,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
}
|
||||
}
|
||||
|
||||
CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, dPriority, chainActive.Height(),
|
||||
inChainInputValue, fSpendsCoinbase, nSigOps, lp);
|
||||
CTxMemPoolEntry entry(ptx, nFees, nAcceptTime, chainActive.Height(),
|
||||
fSpendsCoinbase, nSigOps, lp);
|
||||
unsigned int nSize = entry.GetTxSize();
|
||||
|
||||
// Check that the transaction doesn't have an excessive number of
|
||||
@ -830,32 +826,11 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
|
||||
if (mempoolRejectFee > 0 && nModifiedFees < 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
|
||||
// This mitigates 'penny-flooding' -- sending thousands of free transactions just to
|
||||
// be annoying or make others' transactions take longer to confirm.
|
||||
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;
|
||||
// No transactions are allowed below minRelayTxFee except from disconnected blocks
|
||||
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) {
|
||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "min relay fee not met");
|
||||
}
|
||||
|
||||
if (nAbsurdFee && nFees > nAbsurdFee)
|
||||
@ -940,7 +915,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
||||
}
|
||||
|
||||
bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit,
|
||||
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit,
|
||||
const CAmount nAbsurdFee, bool fDryRun)
|
||||
{
|
||||
std::vector<COutPoint> coins_to_uncache;
|
||||
@ -4559,7 +4534,6 @@ bool LoadMempool(void)
|
||||
}
|
||||
uint64_t num;
|
||||
file >> num;
|
||||
double prioritydummy = 0;
|
||||
while (num--) {
|
||||
CTransactionRef tx;
|
||||
int64_t nTime;
|
||||
@ -4570,7 +4544,7 @@ bool LoadMempool(void)
|
||||
|
||||
CAmount amountdelta = nFeeDelta;
|
||||
if (amountdelta) {
|
||||
mempool.PrioritiseTransaction(tx->GetHash(), prioritydummy, amountdelta);
|
||||
mempool.PrioritiseTransaction(tx->GetHash(), amountdelta);
|
||||
}
|
||||
CValidationState state;
|
||||
if (nTime + nExpiryTimeout > nNow) {
|
||||
@ -4591,7 +4565,7 @@ bool LoadMempool(void)
|
||||
file >> mapDeltas;
|
||||
|
||||
for (const auto& i : mapDeltas) {
|
||||
mempool.PrioritiseTransaction(i.first, prioritydummy, i.second);
|
||||
mempool.PrioritiseTransaction(i.first, i.second);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
LogPrintf("Failed to deserialize mempool data on disk: %s. Continuing anyway.\n", e.what());
|
||||
@ -4612,7 +4586,7 @@ void DumpMempool(void)
|
||||
{
|
||||
LOCK(mempool.cs);
|
||||
for (const auto &i : mempool.mapDeltas) {
|
||||
mapDeltas[i.first] = i.second.second;
|
||||
mapDeltas[i.first] = i.second;
|
||||
}
|
||||
vinfo = mempool.infoAll();
|
||||
}
|
||||
|
@ -124,8 +124,6 @@ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
|
||||
/** Additional block download timeout per parallel downloading peer (i.e. 1.25 min) */
|
||||
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 = 6 * 60 * 60; // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin
|
||||
/** 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;
|
||||
@ -338,7 +336,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
|
||||
/** (try to) add transaction to memory pool with a specified acceptance time **/
|
||||
bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit=false,
|
||||
bool* pfMissingInputs, int64_t nAcceptTime, bool fOverrideMempoolLimit=false,
|
||||
const CAmount nAbsurdFee=0, bool fDryRun=false);
|
||||
|
||||
bool GetUTXOCoin(const COutPoint& outpoint, Coin& coin);
|
||||
|
@ -49,12 +49,11 @@ CWallet* pwalletMain = NULL;
|
||||
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
|
||||
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
|
||||
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
|
||||
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
|
||||
bool bBIP69Enabled = true;
|
||||
|
||||
const char * DEFAULT_WALLET_DAT = "wallet.dat";
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fees smaller than this (in duffs) are considered zero fee (for transaction creation)
|
||||
* Override with -mintxfee
|
||||
*/
|
||||
@ -3437,7 +3436,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
||||
CAmount nValueToSelect = nValue;
|
||||
if (nSubtractFeeFromAmount == 0)
|
||||
nValueToSelect += nFeeRet;
|
||||
double dPriority = 0;
|
||||
// vouts to the payees
|
||||
for (const auto& recipient : vecSend)
|
||||
{
|
||||
@ -3495,20 +3493,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
||||
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;
|
||||
CTxOut newTxOut;
|
||||
|
||||
@ -3666,7 +3650,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
||||
}
|
||||
|
||||
CTransaction txNewConst(txNew);
|
||||
dPriority = txNewConst.ComputePriority(dPriority, nBytes);
|
||||
|
||||
// Remove scriptSigs to eliminate the fee calculation dummy signatures
|
||||
for (auto& txin : txNew.vin) {
|
||||
@ -3678,20 +3661,6 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
||||
if (coinControl && coinControl->nConfirmTarget > 0)
|
||||
currentConfirmationTarget = coinControl->nConfirmTarget;
|
||||
|
||||
// Can we complete this as a free transaction?
|
||||
// Note: InstantSend transaction can't be a free one
|
||||
if (!fUseInstantSend && 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;
|
||||
|
||||
// Small enough, and priority high enough, to send for free
|
||||
// if (dPriorityNeeded > 0 && dPriority >= dPriorityNeeded)
|
||||
// break;
|
||||
}
|
||||
CAmount nFeeNeeded = std::max(nFeePay, GetMinimumFee(nBytes, currentConfirmationTarget, mempool));
|
||||
if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) {
|
||||
nFeeNeeded = coinControl->nMinimumTotalFee;
|
||||
@ -3774,7 +3743,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
|
||||
if (GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
|
||||
// Lastly, ensure this tx will pass the mempool's chain limits
|
||||
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;
|
||||
size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
|
||||
size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
|
||||
@ -4818,8 +4787,6 @@ std::string CWallet::GetWalletHelpString(bool showDebug)
|
||||
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
|
||||
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"));
|
||||
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("-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 BIP39/BIP44. Only has effect during wallet creation/first start") + " " + strprintf(_("(default: %u)"), DEFAULT_USE_HD_WALLET));
|
||||
@ -5177,10 +5144,6 @@ bool CWallet::ParameterInteraction()
|
||||
}
|
||||
nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
|
||||
bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
|
||||
fSendFreeTransactions = GetBoolArg("-sendfreetransactions", DEFAULT_SEND_FREE_TRANSACTIONS);
|
||||
|
||||
if (fSendFreeTransactions && GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) <= 0)
|
||||
return InitError("Creation of free transactions with their relay disabled is not supported.");
|
||||
|
||||
if (IsArgSet("-walletbackupsdir")) {
|
||||
if (!boost::filesystem::is_directory(GetArg("-walletbackupsdir", ""))) {
|
||||
|
@ -43,7 +43,6 @@ extern CWallet* pwalletMain;
|
||||
extern CFeeRate payTxFee;
|
||||
extern unsigned int nTxConfirmTarget;
|
||||
extern bool bSpendZeroConfChange;
|
||||
extern bool fSendFreeTransactions;
|
||||
extern bool bBIP69Enabled;
|
||||
|
||||
static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000;
|
||||
@ -61,14 +60,10 @@ static const CAmount MIN_CHANGE = CENT;
|
||||
static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2;
|
||||
//! Default for -spendzeroconfchange
|
||||
static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
|
||||
//! Default for -sendfreetransactions
|
||||
static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
|
||||
//! Default for -walletrejectlongchains
|
||||
static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
|
||||
//! -txconfirmtarget default
|
||||
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
|
||||
//! 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_DISABLE_WALLET = false;
|
||||
|
||||
@ -780,7 +775,7 @@ public:
|
||||
SetNull();
|
||||
}
|
||||
|
||||
CWallet(const std::string& strWalletFileIn)
|
||||
CWallet(const std::string& strWalletFileIn)
|
||||
: strWalletFile(strWalletFileIn)
|
||||
{
|
||||
SetNull();
|
||||
|
Loading…
Reference in New Issue
Block a user