1#!/usr/bin/env python3 2# Copyright (c) 2016-2018 The Bitcoin Core developers 3# Distributed under the MIT software license, see the accompanying 4# file COPYING or http://www.opensource.org/licenses/mit-license.php. 5"""Test the bumpfee RPC. 6 7Verifies that the bumpfee RPC creates replacement transactions successfully when 8its preconditions are met, and returns appropriate errors in other cases. 9 10This module consists of around a dozen individual test cases implemented in the 11top-level functions named as test_<test_case_description>. The test functions 12can be disabled or reordered if needed for debugging. If new test cases are 13added in the future, they should try to follow the same convention and not 14make assumptions about execution order. 15""" 16from decimal import Decimal 17import io 18 19from test_framework.blocktools import add_witness_commitment, create_block, create_coinbase, send_to_witness 20from test_framework.messages import BIP125_SEQUENCE_NUMBER, CTransaction 21from test_framework.test_framework import BitcoinTestFramework, SkipTest 22from test_framework.util import assert_equal, assert_greater_than, assert_raises_rpc_error, bytes_to_hex_str, connect_nodes_bi, hex_str_to_bytes, sync_mempools 23 24WALLET_PASSPHRASE = "test" 25WALLET_PASSPHRASE_TIMEOUT = 3600 26 27class BumpFeeTest(BitcoinTestFramework): 28 def set_test_params(self): 29 self.num_nodes = 2 30 self.setup_clean_chain = True 31 self.extra_args = [[ 32 "-walletrbf={}".format(i), 33 "-mintxfee=0.00002", 34 "-mempoolreplacement=1", 35 ] for i in range(self.num_nodes)] 36 37 def skip_test_if_missing_module(self): 38 self.skip_if_no_wallet() 39 40 def run_test(self): 41 if True: 42 raise SkipTest("Litecoin doesn't support RBF.") 43 44 # Encrypt wallet for test_locked_wallet_fails test 45 self.nodes[1].encryptwallet(WALLET_PASSPHRASE) 46 self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 47 48 connect_nodes_bi(self.nodes, 0, 1) 49 self.sync_all() 50 51 peer_node, rbf_node = self.nodes 52 rbf_node_address = rbf_node.getnewaddress() 53 54 # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis) 55 self.log.info("Mining blocks...") 56 peer_node.generate(110) 57 self.sync_all() 58 for i in range(25): 59 peer_node.sendtoaddress(rbf_node_address, 0.001) 60 self.sync_all() 61 peer_node.generate(1) 62 self.sync_all() 63 assert_equal(rbf_node.getbalance(), Decimal("0.025")) 64 65 self.log.info("Running tests") 66 dest_address = peer_node.getnewaddress() 67 test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address) 68 test_segwit_bumpfee_succeeds(rbf_node, dest_address) 69 test_nonrbf_bumpfee_fails(peer_node, dest_address) 70 test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address) 71 test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address) 72 test_small_output_fails(rbf_node, dest_address) 73 test_dust_to_fee(rbf_node, dest_address) 74 test_settxfee(rbf_node, dest_address) 75 test_rebumping(rbf_node, dest_address) 76 test_rebumping_not_replaceable(rbf_node, dest_address) 77 test_unconfirmed_not_spendable(rbf_node, rbf_node_address) 78 test_bumpfee_metadata(rbf_node, dest_address) 79 test_locked_wallet_fails(rbf_node, dest_address) 80 test_maxtxfee_fails(self, rbf_node, dest_address) 81 self.log.info("Success") 82 83 84def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address): 85 rbfid = spend_one_input(rbf_node, dest_address) 86 rbftx = rbf_node.gettransaction(rbfid) 87 sync_mempools((rbf_node, peer_node)) 88 assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() 89 bumped_tx = rbf_node.bumpfee(rbfid) 90 assert_equal(bumped_tx["errors"], []) 91 assert bumped_tx["fee"] - abs(rbftx["fee"]) > 0 92 # check that bumped_tx propagates, original tx was evicted and has a wallet conflict 93 sync_mempools((rbf_node, peer_node)) 94 assert bumped_tx["txid"] in rbf_node.getrawmempool() 95 assert bumped_tx["txid"] in peer_node.getrawmempool() 96 assert rbfid not in rbf_node.getrawmempool() 97 assert rbfid not in peer_node.getrawmempool() 98 oldwtx = rbf_node.gettransaction(rbfid) 99 assert len(oldwtx["walletconflicts"]) > 0 100 # check wallet transaction replaces and replaced_by values 101 bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"]) 102 assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"]) 103 assert_equal(bumpedwtx["replaces_txid"], rbfid) 104 105 106def test_segwit_bumpfee_succeeds(rbf_node, dest_address): 107 # Create a transaction with segwit output, then create an RBF transaction 108 # which spends it, and make sure bumpfee can be called on it. 109 110 segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001")) 111 segwit_out = rbf_node.getaddressinfo(rbf_node.getnewaddress(address_type='p2sh-segwit')) 112 segwitid = send_to_witness( 113 use_p2wsh=False, 114 node=rbf_node, 115 utxo=segwit_in, 116 pubkey=segwit_out["pubkey"], 117 encode_p2sh=False, 118 amount=Decimal("0.0009"), 119 sign=True) 120 121 rbfraw = rbf_node.createrawtransaction([{ 122 'txid': segwitid, 123 'vout': 0, 124 "sequence": BIP125_SEQUENCE_NUMBER 125 }], {dest_address: Decimal("0.0005"), 126 rbf_node.getrawchangeaddress(): Decimal("0.0003")}) 127 rbfsigned = rbf_node.signrawtransactionwithwallet(rbfraw) 128 rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"]) 129 assert rbfid in rbf_node.getrawmempool() 130 131 bumped_tx = rbf_node.bumpfee(rbfid) 132 assert bumped_tx["txid"] in rbf_node.getrawmempool() 133 assert rbfid not in rbf_node.getrawmempool() 134 135 136def test_nonrbf_bumpfee_fails(peer_node, dest_address): 137 # cannot replace a non RBF transaction (from node which did not enable RBF) 138 not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000")) 139 assert_raises_rpc_error(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) 140 141 142def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address): 143 # cannot bump fee unless the tx has only inputs that we own. 144 # here, the rbftx has a peer_node coin and then adds a rbf_node input 145 # Note that this test depends upon the RPC code checking input ownership prior to change outputs 146 # (since it can't use fundrawtransaction, it lacks a proper change output) 147 utxos = [node.listunspent()[-1] for node in (rbf_node, peer_node)] 148 inputs = [{ 149 "txid": utxo["txid"], 150 "vout": utxo["vout"], 151 "address": utxo["address"], 152 "sequence": BIP125_SEQUENCE_NUMBER 153 } for utxo in utxos] 154 output_val = sum(utxo["amount"] for utxo in utxos) - Decimal("0.001") 155 rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val}) 156 signedtx = rbf_node.signrawtransactionwithwallet(rawtx) 157 signedtx = peer_node.signrawtransactionwithwallet(signedtx["hex"]) 158 rbfid = rbf_node.sendrawtransaction(signedtx["hex"]) 159 assert_raises_rpc_error(-4, "Transaction contains inputs that don't belong to this wallet", 160 rbf_node.bumpfee, rbfid) 161 162 163def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address): 164 # cannot bump fee if the transaction has a descendant 165 # parent is send-to-self, so we don't have to check which output is change when creating the child tx 166 parent_id = spend_one_input(rbf_node, rbf_node_address) 167 tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000}) 168 tx = rbf_node.signrawtransactionwithwallet(tx) 169 rbf_node.sendrawtransaction(tx["hex"]) 170 assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) 171 172 173def test_small_output_fails(rbf_node, dest_address): 174 # cannot bump fee with a too-small output 175 rbfid = spend_one_input(rbf_node, dest_address) 176 rbf_node.bumpfee(rbfid, {"totalFee": 50000}) 177 178 rbfid = spend_one_input(rbf_node, dest_address) 179 assert_raises_rpc_error(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001}) 180 181 182def test_dust_to_fee(rbf_node, dest_address): 183 # check that if output is reduced to dust, it will be converted to fee 184 # the bumped tx sets fee=49,900, but it converts to 50,000 185 rbfid = spend_one_input(rbf_node, dest_address) 186 fulltx = rbf_node.getrawtransaction(rbfid, 1) 187 # (32-byte p2sh-pwpkh output size + 148 p2pkh spend estimate) * 10k(discard_rate) / 1000 = 1800 188 # P2SH outputs are slightly "over-discarding" due to the IsDust calculation assuming it will 189 # be spent as a P2PKH. 190 bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 50000 - 1800}) 191 full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1) 192 assert_equal(bumped_tx["fee"], Decimal("0.00050000")) 193 assert_equal(len(fulltx["vout"]), 2) 194 assert_equal(len(full_bumped_tx["vout"]), 1) # change output is eliminated 195 196 197def test_settxfee(rbf_node, dest_address): 198 assert_raises_rpc_error(-8, "txfee cannot be less than min relay tx fee", rbf_node.settxfee, Decimal('0.000005')) 199 assert_raises_rpc_error(-8, "txfee cannot be less than wallet min fee", rbf_node.settxfee, Decimal('0.000015')) 200 # check that bumpfee reacts correctly to the use of settxfee (paytxfee) 201 rbfid = spend_one_input(rbf_node, dest_address) 202 requested_feerate = Decimal("0.00025000") 203 rbf_node.settxfee(requested_feerate) 204 bumped_tx = rbf_node.bumpfee(rbfid) 205 actual_feerate = bumped_tx["fee"] * 1000 / rbf_node.getrawtransaction(bumped_tx["txid"], True)["vsize"] 206 # Assert that the difference between the requested feerate and the actual 207 # feerate of the bumped transaction is small. 208 assert_greater_than(Decimal("0.00001000"), abs(requested_feerate - actual_feerate)) 209 rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee 210 211 212def test_maxtxfee_fails(test, rbf_node, dest_address): 213 test.restart_node(1, ['-maxtxfee=0.00003'] + test.extra_args[1]) 214 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 215 rbfid = spend_one_input(rbf_node, dest_address) 216 assert_raises_rpc_error(-4, "Specified or calculated fee 0.0000332 is too high (cannot be higher than maxTxFee 0.00003)", rbf_node.bumpfee, rbfid) 217 test.restart_node(1, test.extra_args[1]) 218 rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) 219 220 221def test_rebumping(rbf_node, dest_address): 222 # check that re-bumping the original tx fails, but bumping the bumper succeeds 223 rbfid = spend_one_input(rbf_node, dest_address) 224 bumped = rbf_node.bumpfee(rbfid, {"totalFee": 2000}) 225 assert_raises_rpc_error(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 3000}) 226 rbf_node.bumpfee(bumped["txid"], {"totalFee": 3000}) 227 228 229def test_rebumping_not_replaceable(rbf_node, dest_address): 230 # check that re-bumping a non-replaceable bump tx fails 231 rbfid = spend_one_input(rbf_node, dest_address) 232 bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False}) 233 assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], 234 {"totalFee": 20000}) 235 236 237def test_unconfirmed_not_spendable(rbf_node, rbf_node_address): 238 # check that unconfirmed outputs from bumped transactions are not spendable 239 rbfid = spend_one_input(rbf_node, rbf_node_address) 240 rbftx = rbf_node.gettransaction(rbfid)["hex"] 241 assert rbfid in rbf_node.getrawmempool() 242 bumpid = rbf_node.bumpfee(rbfid)["txid"] 243 assert bumpid in rbf_node.getrawmempool() 244 assert rbfid not in rbf_node.getrawmempool() 245 246 # check that outputs from the bump transaction are not spendable 247 # due to the replaces_txid check in CWallet::AvailableCoins 248 assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], []) 249 250 # submit a block with the rbf tx to clear the bump tx out of the mempool, 251 # then invalidate the block so the rbf tx will be put back in the mempool. 252 # This makes it possible to check whether the rbf tx outputs are 253 # spendable before the rbf tx is confirmed. 254 block = submit_block_with_tx(rbf_node, rbftx) 255 # Can not abandon conflicted tx 256 assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: rbf_node.abandontransaction(txid=bumpid)) 257 rbf_node.invalidateblock(block.hash) 258 # Call abandon to make sure the wallet doesn't attempt to resubmit 259 # the bump tx and hope the wallet does not rebroadcast before we call. 260 rbf_node.abandontransaction(bumpid) 261 assert bumpid not in rbf_node.getrawmempool() 262 assert rbfid in rbf_node.getrawmempool() 263 264 # check that outputs from the rbf tx are not spendable before the 265 # transaction is confirmed, due to the replaced_by_txid check in 266 # CWallet::AvailableCoins 267 assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == rbfid], []) 268 269 # check that the main output from the rbf tx is spendable after confirmed 270 rbf_node.generate(1) 271 assert_equal( 272 sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False) 273 if t["txid"] == rbfid and t["address"] == rbf_node_address and t["spendable"]), 1) 274 275 276def test_bumpfee_metadata(rbf_node, dest_address): 277 rbfid = rbf_node.sendtoaddress(dest_address, Decimal("0.00100000"), "comment value", "to value") 278 bumped_tx = rbf_node.bumpfee(rbfid) 279 bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"]) 280 assert_equal(bumped_wtx["comment"], "comment value") 281 assert_equal(bumped_wtx["to"], "to value") 282 283 284def test_locked_wallet_fails(rbf_node, dest_address): 285 rbfid = spend_one_input(rbf_node, dest_address) 286 rbf_node.walletlock() 287 assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.", 288 rbf_node.bumpfee, rbfid) 289 290 291def spend_one_input(node, dest_address): 292 tx_input = dict( 293 sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u["amount"] == Decimal("0.00100000"))) 294 rawtx = node.createrawtransaction( 295 [tx_input], {dest_address: Decimal("0.00050000"), 296 node.getrawchangeaddress(): Decimal("0.00049000")}) 297 signedtx = node.signrawtransactionwithwallet(rawtx) 298 txid = node.sendrawtransaction(signedtx["hex"]) 299 return txid 300 301 302def submit_block_with_tx(node, tx): 303 ctx = CTransaction() 304 ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx))) 305 306 tip = node.getbestblockhash() 307 height = node.getblockcount() + 1 308 block_time = node.getblockheader(tip)["mediantime"] + 1 309 block = create_block(int(tip, 16), create_coinbase(height), block_time, version=0x20000000) 310 block.vtx.append(ctx) 311 block.rehash() 312 block.hashMerkleRoot = block.calc_merkle_root() 313 add_witness_commitment(block) 314 block.solve() 315 node.submitblock(bytes_to_hex_str(block.serialize(True))) 316 return block 317 318 319if __name__ == "__main__": 320 BumpFeeTest().main() 321