Changeset View
Changeset View
Standalone View
Standalone View
test/functional/prioritise_transaction.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2015-2016 The Bitcoin Core developers | # Copyright (c) 2015-2016 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
# | # | ||||
# Test PrioritiseTransaction code | # Test PrioritiseTransaction code | ||||
# | # | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import * | from test_framework.util import * | ||||
# FIXME: review how this test needs to be adapted w.r.t _LEGACY_MAX_BLOCK_SIZE | |||||
from test_framework.mininode import COIN | from test_framework.mininode import COIN | ||||
# FIXME: review how this test needs to be adapted w.r.t _LEGACY_MAX_BLOCK_SIZE | |||||
from test_framework.cdefs import LEGACY_MAX_BLOCK_SIZE | from test_framework.cdefs import LEGACY_MAX_BLOCK_SIZE | ||||
from test_framework.blocktools import send_big_transactions | |||||
class PrioritiseTransactionTest(BitcoinTestFramework): | class PrioritiseTransactionTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.extra_args = [["-printpriority=1"]] | self.extra_args = [["-printpriority=1"]] | ||||
def run_test(self): | def run_test(self): | ||||
self.txouts = gen_return_txouts() | |||||
self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] | self.relayfee = self.nodes[0].getnetworkinfo()['relayfee'] | ||||
utxo_count = 90 | utxo_count = 90 | ||||
utxos = create_confirmed_utxos( | utxos = create_confirmed_utxos( | ||||
self.relayfee, self.nodes[0], utxo_count) | self.relayfee, self.nodes[0], utxo_count) | ||||
# our transactions are smaller than 100kb | # our transactions are smaller than 100kb | ||||
base_fee = self.relayfee * 100 | base_fee = self.relayfee * 100 | ||||
txids = [] | txids = [] | ||||
# Create 3 batches of transactions at 3 different fee rate levels | # Create 3 batches of transactions at 3 different fee rate levels | ||||
range_size = utxo_count // 3 | range_size = utxo_count // 3 | ||||
for i in range(3): | for i in range(3): | ||||
txids.append([]) | txids.append([]) | ||||
start_range = i * range_size | start_range = i * range_size | ||||
end_range = start_range + range_size | end_range = start_range + range_size | ||||
txids[i] = create_lots_of_big_transactions(self.nodes[0], self.txouts, utxos[ | txids[i] = send_big_transactions(self.nodes[0], utxos[start_range:end_range], | ||||
start_range:end_range], end_range - start_range, (i + 1) * base_fee) | end_range - start_range, 10 * (i + 1)) | ||||
# Make sure that the size of each group of transactions exceeds | # Make sure that the size of each group of transactions exceeds | ||||
# LEGACY_MAX_BLOCK_SIZE -- otherwise the test needs to be revised to create | # LEGACY_MAX_BLOCK_SIZE -- otherwise the test needs to be revised to create | ||||
# more transactions. | # more transactions. | ||||
mempool = self.nodes[0].getrawmempool(True) | mempool = self.nodes[0].getrawmempool(True) | ||||
sizes = [0, 0, 0] | sizes = [0, 0, 0] | ||||
for i in range(3): | for i in range(3): | ||||
for j in txids[i]: | for j in txids[i]: | ||||
assert(j in mempool) | assert(j in mempool) | ||||
sizes[i] += mempool[j]['size'] | sizes[i] += mempool[j]['size'] | ||||
# Fail => raise utxo_count | # Fail => raise utxo_count | ||||
assert(sizes[i] > LEGACY_MAX_BLOCK_SIZE) | assert(sizes[i] > LEGACY_MAX_BLOCK_SIZE) | ||||
# 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 (lower | ||||
# the priority to ensure its not mined due to priority) | # the priority to ensure its not mined due to priority) | ||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
txids[0][0], 0, int(3 * base_fee * COIN)) | txids[0][0], 0, 100 * self.nodes[0].calculate_fee_from_txid(txids[0][0])) | ||||
self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0) | self.nodes[0].prioritisetransaction(txids[0][1], -1e15, 0) | ||||
self.nodes[0].generate(1) | self.nodes[0].generate(1) | ||||
mempool = self.nodes[0].getrawmempool() | mempool = self.nodes[0].getrawmempool() | ||||
self.log.info("Assert that prioritised transaction was mined") | self.log.info("Assert that prioritised transaction was mined") | ||||
assert(txids[0][0] not in mempool) | assert(txids[0][0] not in mempool) | ||||
assert(txids[0][1] in mempool) | assert(txids[0][1] in mempool) | ||||
high_fee_tx = None | confirmed_transactions = self.nodes[0].getblock( | ||||
for x in txids[2]: | self.nodes[0].getbestblockhash())['tx'] | ||||
if x not in mempool: | |||||
high_fee_tx = x | # Pull the highest fee-rate transaction from a block | ||||
high_fee_tx = confirmed_transactions[1] | |||||
# Something high-fee should have been mined! | # Something high-fee should have been mined! | ||||
assert(high_fee_tx != None) | assert(high_fee_tx != None) | ||||
# 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). | ||||
# | |||||
# NOTE WELL: gettransaction returns the fee as a negative number and | |||||
# as fractional coins. However, the prioritisetransaction expects a | |||||
# number of satoshi to add or subtract from the actual fee. | |||||
# Thus the conversation here is simply int(tx_fee*COIN) to remove all fees, and then | |||||
# we add the minimum fee back. | |||||
tx_fee = self.nodes[0].gettransaction(high_fee_tx)['fee'] | |||||
self.nodes[0].prioritisetransaction( | self.nodes[0].prioritisetransaction( | ||||
high_fee_tx, -1e15, -int(2 * base_fee * COIN)) | high_fee_tx, -1e15, int(tx_fee*COIN) + self.nodes[0].calculate_fee_from_txid(high_fee_tx)) | ||||
# 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()) | ||||
# Check to make sure our high fee rate tx is back in the mempool | # Check to make sure our high fee rate tx is back in the mempool | ||||
mempool = self.nodes[0].getrawmempool() | mempool = self.nodes[0].getrawmempool() | ||||
assert(high_fee_tx in mempool) | assert(high_fee_tx in mempool) | ||||
▲ Show 20 Lines • Show All 59 Lines • Show Last 20 Lines |