2016-03-19 20:58:06 +01:00
#!/usr/bin/env python3
2019-02-21 02:03:13 +01:00
# Copyright (c) 2015-2019 The Bitcoin Core developers
2015-11-19 02:55:52 +01:00
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-01-18 00:34:40 +01:00
""" Test the prioritisetransaction mining RPC. """
2015-11-19 02:55:52 +01:00
2018-07-07 00:10:35 +02:00
import time
2021-07-01 01:43:45 +02:00
from test_framework . messages import COIN , MAX_BLOCK_WEIGHT
2015-11-19 02:55:52 +01:00
from test_framework . test_framework import BitcoinTestFramework
2018-07-07 00:10:35 +02:00
from test_framework . util import assert_equal , assert_raises_rpc_error , create_confirmed_utxos , create_lots_of_big_transactions , gen_return_txouts
2015-11-19 02:55:52 +01:00
class PrioritiseTransactionTest ( BitcoinTestFramework ) :
2017-06-10 00:21:21 +02:00
def set_test_params ( self ) :
2016-05-14 13:01:31 +02:00
self . setup_clean_chain = True
2021-10-19 11:13:40 +02:00
self . num_nodes = 1
2019-04-24 23:55:58 +02:00
self . extra_args = [ [
" -printpriority=1 " ,
" -acceptnonstdtxn=1 " ,
] ] * self . num_nodes
2019-12-06 15:37:49 +01:00
self . supports_cli = False
2015-11-19 02:55:52 +01:00
2018-09-09 19:32:37 +02:00
def skip_test_if_missing_module ( self ) :
self . skip_if_no_wallet ( )
2017-04-03 15:34:04 +02:00
def run_test ( self ) :
2018-01-03 02:48:20 +01:00
# Test `prioritisetransaction` required parameters
assert_raises_rpc_error ( - 1 , " prioritisetransaction " , self . nodes [ 0 ] . prioritisetransaction )
assert_raises_rpc_error ( - 1 , " prioritisetransaction " , self . nodes [ 0 ] . prioritisetransaction , ' ' )
assert_raises_rpc_error ( - 1 , " prioritisetransaction " , self . nodes [ 0 ] . prioritisetransaction , ' ' , 0 )
# Test `prioritisetransaction` invalid extra parameters
assert_raises_rpc_error ( - 1 , " prioritisetransaction " , self . nodes [ 0 ] . prioritisetransaction , ' ' , 0 , 0 , 0 )
# Test `prioritisetransaction` invalid `txid`
2018-06-08 20:16:07 +02:00
assert_raises_rpc_error ( - 8 , " txid must be of length 64 (not 3, for ' foo ' ) " , self . nodes [ 0 ] . prioritisetransaction , txid = ' foo ' , fee_delta = 0 )
assert_raises_rpc_error ( - 8 , " txid must be hexadecimal string (not ' Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 ' ) " , self . nodes [ 0 ] . prioritisetransaction , txid = ' Zd1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 ' , fee_delta = 0 )
2018-01-03 02:48:20 +01:00
# Test `prioritisetransaction` invalid `dummy`
txid = ' 1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000 '
assert_raises_rpc_error ( - 1 , " JSON value is not a number as expected " , self . nodes [ 0 ] . prioritisetransaction , txid , ' foo ' , 0 )
assert_raises_rpc_error ( - 8 , " Priority is no longer supported, dummy argument to prioritisetransaction must be 0. " , self . nodes [ 0 ] . prioritisetransaction , txid , 1 , 0 )
# Test `prioritisetransaction` invalid `fee_delta`
assert_raises_rpc_error ( - 1 , " JSON value is not an integer as expected " , self . nodes [ 0 ] . prioritisetransaction , txid = txid , fee_delta = ' foo ' )
2016-05-14 13:01:31 +02:00
self . txouts = gen_return_txouts ( )
2015-11-19 02:55:52 +01:00
self . relayfee = self . nodes [ 0 ] . getnetworkinfo ( ) [ ' relayfee ' ]
2016-03-01 15:28:16 +01:00
utxo_count = 90
2021-07-27 20:04:51 +02:00
utxos = create_confirmed_utxos ( self , self . relayfee , self . nodes [ 0 ] , utxo_count )
2015-11-19 02:55:52 +01:00
base_fee = self . relayfee * 100 # our transactions are smaller than 100kb
txids = [ ]
# Create 3 batches of transactions at 3 different fee rate levels
2016-03-01 15:28:16 +01:00
range_size = utxo_count / / 3
2016-03-19 20:58:06 +01:00
for i in range ( 3 ) :
2015-11-19 02:55:52 +01:00
txids . append ( [ ] )
2016-03-01 15:28:16 +01:00
start_range = i * range_size
end_range = start_range + range_size
2016-12-04 16:16:11 +01:00
txids [ i ] = create_lots_of_big_transactions ( self . nodes [ 0 ] , self . txouts , utxos [ start_range : end_range ] , end_range - start_range , ( i + 1 ) * base_fee )
2016-03-01 15:28:16 +01:00
# Make sure that the size of each group of transactions exceeds
2021-07-01 01:43:45 +02:00
# MAX_BLOCK_WEIGHT // 4 -- otherwise the test needs to be revised to
# create more transactions.
2016-03-01 15:28:16 +01:00
mempool = self . nodes [ 0 ] . getrawmempool ( True )
sizes = [ 0 , 0 , 0 ]
2016-03-19 20:58:06 +01:00
for i in range ( 3 ) :
2016-03-01 15:28:16 +01:00
for j in txids [ i ] :
2019-02-19 23:43:44 +01:00
assert j in mempool
2018-04-17 20:17:13 +02:00
sizes [ i ] + = mempool [ j ] [ ' vsize ' ]
2021-07-01 01:43:45 +02:00
assert sizes [ i ] > MAX_BLOCK_WEIGHT / / 4 # Fail => raise utxo_count
2015-11-19 02:55:52 +01:00
# add a fee delta to something in the cheapest bucket and make sure it gets mined
2017-01-20 04:46:50 +01:00
# also check that a different entry in the cheapest bucket is NOT mined
2017-04-21 18:41:01 +02:00
self . nodes [ 0 ] . prioritisetransaction ( txid = txids [ 0 ] [ 0 ] , fee_delta = int ( 3 * base_fee * COIN ) )
2015-11-19 02:55:52 +01:00
2021-08-19 17:10:24 +02:00
self . generate ( self . nodes [ 0 ] , 1 )
2015-11-19 02:55:52 +01:00
mempool = self . nodes [ 0 ] . getrawmempool ( )
2017-03-08 00:46:17 +01:00
self . log . info ( " Assert that prioritised transaction was mined " )
2019-02-19 23:43:44 +01:00
assert txids [ 0 ] [ 0 ] not in mempool
assert txids [ 0 ] [ 1 ] in mempool
2015-11-19 02:55:52 +01:00
high_fee_tx = None
for x in txids [ 2 ] :
if x not in mempool :
high_fee_tx = x
# Something high-fee should have been mined!
2019-02-19 23:43:44 +01:00
assert high_fee_tx is not None
2015-11-19 02:55:52 +01:00
# Add a prioritisation before a tx is in the mempool (de-prioritising a
2016-03-01 15:28:16 +01:00
# high-fee transaction so that it's now low fee).
2017-04-21 18:41:01 +02:00
self . nodes [ 0 ] . prioritisetransaction ( txid = high_fee_tx , fee_delta = - int ( 2 * base_fee * COIN ) )
2015-11-19 02:55:52 +01:00
# Add everything back to mempool
self . nodes [ 0 ] . invalidateblock ( self . nodes [ 0 ] . getbestblockhash ( ) )
# Check to make sure our high fee rate tx is back in the mempool
mempool = self . nodes [ 0 ] . getrawmempool ( )
2019-02-19 23:43:44 +01:00
assert high_fee_tx in mempool
2015-11-19 02:55:52 +01:00
2016-03-01 15:28:16 +01:00
# Now verify the modified-high feerate transaction isn't mined before
# the other high fee transactions. Keep mining until our mempool has
# decreased by all the high fee size that we calculated above.
while ( self . nodes [ 0 ] . getmempoolinfo ( ) [ ' bytes ' ] > sizes [ 0 ] + sizes [ 1 ] ) :
2020-11-10 18:02:31 +01:00
self . generate ( self . nodes [ 0 ] , 1 , sync_fun = self . no_op )
2015-11-19 02:55:52 +01:00
# High fee transaction should not have been mined, but other high fee rate
# transactions should have been.
mempool = self . nodes [ 0 ] . getrawmempool ( )
2017-03-08 00:46:17 +01:00
self . log . info ( " Assert that de-prioritised transaction is still in mempool " )
2019-02-19 23:43:44 +01:00
assert high_fee_tx in mempool
2015-11-19 02:55:52 +01:00
for x in txids [ 2 ] :
if ( x != high_fee_tx ) :
2019-02-19 23:43:44 +01:00
assert x not in mempool
2015-11-19 02:55:52 +01:00
2017-01-20 04:46:50 +01:00
# Create a free transaction. Should be rejected.
2015-12-02 15:37:18 +01:00
utxo_list = self . nodes [ 0 ] . listunspent ( )
2019-02-19 23:43:44 +01:00
assert len ( utxo_list ) > 0
2015-12-02 15:37:18 +01:00
utxo = utxo_list [ 0 ]
inputs = [ ]
outputs = { }
inputs . append ( { " txid " : utxo [ " txid " ] , " vout " : utxo [ " vout " ] } )
2017-01-20 04:46:50 +01:00
outputs [ self . nodes [ 0 ] . getnewaddress ( ) ] = utxo [ " amount " ]
2015-12-02 15:37:18 +01:00
raw_tx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
2017-09-06 01:49:18 +02:00
tx_hex = self . nodes [ 0 ] . signrawtransactionwithwallet ( raw_tx ) [ " hex " ]
2017-01-20 04:46:50 +01:00
tx_id = self . nodes [ 0 ] . decoderawtransaction ( tx_hex ) [ " txid " ]
2015-12-02 15:37:18 +01:00
2017-03-07 20:08:59 +01:00
# This will raise an exception due to min relay fee not being met
2018-04-25 23:30:38 +02:00
assert_raises_rpc_error ( - 26 , " min relay fee not met " , self . nodes [ 0 ] . sendrawtransaction , tx_hex )
2019-02-19 23:43:44 +01:00
assert tx_id not in self . nodes [ 0 ] . getrawmempool ( )
2015-12-02 15:37:18 +01:00
# This is a less than 1000-byte transaction, so just set the fee
2018-03-18 15:26:45 +01:00
# to be the minimum for a 1000-byte transaction and check that it is
2015-12-02 15:37:18 +01:00
# accepted.
2017-04-21 18:41:01 +02:00
self . nodes [ 0 ] . prioritisetransaction ( txid = tx_id , fee_delta = int ( self . relayfee * COIN ) )
2015-12-02 15:37:18 +01:00
2017-03-08 00:46:17 +01:00
self . log . info ( " Assert that prioritised free transaction is accepted to mempool " )
2017-01-20 04:46:50 +01:00
assert_equal ( self . nodes [ 0 ] . sendrawtransaction ( tx_hex ) , tx_id )
2019-02-19 23:43:44 +01:00
assert tx_id in self . nodes [ 0 ] . getrawmempool ( )
2015-12-02 15:37:18 +01:00
2017-04-18 18:52:08 +02:00
# Test that calling prioritisetransaction is sufficient to trigger
# getblocktemplate to (eventually) return a new block.
mock_time = int ( time . time ( ) )
self . nodes [ 0 ] . setmocktime ( mock_time )
2018-11-26 17:17:38 +01:00
template = self . nodes [ 0 ] . getblocktemplate ( { ' rules ' : [ ' segwit ' ] } )
2017-04-21 18:41:01 +02:00
self . nodes [ 0 ] . prioritisetransaction ( txid = tx_id , fee_delta = - int ( self . relayfee * COIN ) )
2017-04-18 18:52:08 +02:00
self . nodes [ 0 ] . setmocktime ( mock_time + 10 )
2018-11-26 17:17:38 +01:00
new_template = self . nodes [ 0 ] . getblocktemplate ( { ' rules ' : [ ' segwit ' ] } )
2017-04-18 18:52:08 +02:00
2019-02-19 23:43:44 +01:00
assert template != new_template
2017-04-18 18:52:08 +02:00
2015-11-19 02:55:52 +01:00
if __name__ == ' __main__ ' :
PrioritiseTransactionTest ( ) . main ( )