Merge #11121: TestNode tidyups
[bitcoinplatinum.git] / test / functional / bumpfee.py
blobdde87d5bd137be7fde706708c5af470071a0f9e8
1 #!/usr/bin/env python3
2 # Copyright (c) 2016 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.
7 Verifies that the bumpfee RPC creates replacement transactions successfully when
8 its preconditions are met, and returns appropriate errors in other cases.
10 This module consists of around a dozen individual test cases implemented in the
11 top-level functions named as test_<test_case_description>. The test functions
12 can be disabled or reordered if needed for debugging. If new test cases are
13 added in the future, they should try to follow the same convention and not
14 make assumptions about execution order.
15 """
17 from segwit import send_to_witness
18 from test_framework.test_framework import BitcoinTestFramework
19 from test_framework import blocktools
20 from test_framework.mininode import CTransaction
21 from test_framework.util import *
23 import io
25 # Sequence number that is BIP 125 opt-in and BIP 68-compliant
26 BIP125_SEQUENCE_NUMBER = 0xfffffffd
28 WALLET_PASSPHRASE = "test"
29 WALLET_PASSPHRASE_TIMEOUT = 3600
32 class BumpFeeTest(BitcoinTestFramework):
33 def set_test_params(self):
34 self.num_nodes = 2
35 self.setup_clean_chain = True
36 self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)]
37 for i in range(self.num_nodes)]
39 def run_test(self):
40 # Encrypt wallet for test_locked_wallet_fails test
41 self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE)
42 self.start_node(1)
43 self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT)
45 connect_nodes_bi(self.nodes, 0, 1)
46 self.sync_all()
48 peer_node, rbf_node = self.nodes
49 rbf_node_address = rbf_node.getnewaddress()
51 # fund rbf node with 10 coins of 0.001 btc (100,000 satoshis)
52 self.log.info("Mining blocks...")
53 peer_node.generate(110)
54 self.sync_all()
55 for i in range(25):
56 peer_node.sendtoaddress(rbf_node_address, 0.001)
57 self.sync_all()
58 peer_node.generate(1)
59 self.sync_all()
60 assert_equal(rbf_node.getbalance(), Decimal("0.025"))
62 self.log.info("Running tests")
63 dest_address = peer_node.getnewaddress()
64 test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address)
65 test_segwit_bumpfee_succeeds(rbf_node, dest_address)
66 test_nonrbf_bumpfee_fails(peer_node, dest_address)
67 test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address)
68 test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
69 test_small_output_fails(rbf_node, dest_address)
70 test_dust_to_fee(rbf_node, dest_address)
71 test_settxfee(rbf_node, dest_address)
72 test_rebumping(rbf_node, dest_address)
73 test_rebumping_not_replaceable(rbf_node, dest_address)
74 test_unconfirmed_not_spendable(rbf_node, rbf_node_address)
75 test_bumpfee_metadata(rbf_node, dest_address)
76 test_locked_wallet_fails(rbf_node, dest_address)
77 self.log.info("Success")
80 def test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address):
81 rbfid = spend_one_input(rbf_node, dest_address)
82 rbftx = rbf_node.gettransaction(rbfid)
83 sync_mempools((rbf_node, peer_node))
84 assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
85 bumped_tx = rbf_node.bumpfee(rbfid)
86 assert_equal(bumped_tx["errors"], [])
87 assert bumped_tx["fee"] - abs(rbftx["fee"]) > 0
88 # check that bumped_tx propagates, original tx was evicted and has a wallet conflict
89 sync_mempools((rbf_node, peer_node))
90 assert bumped_tx["txid"] in rbf_node.getrawmempool()
91 assert bumped_tx["txid"] in peer_node.getrawmempool()
92 assert rbfid not in rbf_node.getrawmempool()
93 assert rbfid not in peer_node.getrawmempool()
94 oldwtx = rbf_node.gettransaction(rbfid)
95 assert len(oldwtx["walletconflicts"]) > 0
96 # check wallet transaction replaces and replaced_by values
97 bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"])
98 assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"])
99 assert_equal(bumpedwtx["replaces_txid"], rbfid)
102 def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
103 # Create a transaction with segwit output, then create an RBF transaction
104 # which spends it, and make sure bumpfee can be called on it.
106 segwit_in = next(u for u in rbf_node.listunspent() if u["amount"] == Decimal("0.001"))
107 segwit_out = rbf_node.validateaddress(rbf_node.getnewaddress())
108 rbf_node.addwitnessaddress(segwit_out["address"])
109 segwitid = send_to_witness(
110 use_p2wsh=False,
111 node=rbf_node,
112 utxo=segwit_in,
113 pubkey=segwit_out["pubkey"],
114 encode_p2sh=False,
115 amount=Decimal("0.0009"),
116 sign=True)
118 rbfraw = rbf_node.createrawtransaction([{
119 'txid': segwitid,
120 'vout': 0,
121 "sequence": BIP125_SEQUENCE_NUMBER
122 }], {dest_address: Decimal("0.0005"),
123 rbf_node.getrawchangeaddress(): Decimal("0.0003")})
124 rbfsigned = rbf_node.signrawtransaction(rbfraw)
125 rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"])
126 assert rbfid in rbf_node.getrawmempool()
128 bumped_tx = rbf_node.bumpfee(rbfid)
129 assert bumped_tx["txid"] in rbf_node.getrawmempool()
130 assert rbfid not in rbf_node.getrawmempool()
133 def test_nonrbf_bumpfee_fails(peer_node, dest_address):
134 # cannot replace a non RBF transaction (from node which did not enable RBF)
135 not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000"))
136 assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
139 def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
140 # cannot bump fee unless the tx has only inputs that we own.
141 # here, the rbftx has a peer_node coin and then adds a rbf_node input
142 # Note that this test depends upon the RPC code checking input ownership prior to change outputs
143 # (since it can't use fundrawtransaction, it lacks a proper change output)
144 utxos = [node.listunspent()[-1] for node in (rbf_node, peer_node)]
145 inputs = [{
146 "txid": utxo["txid"],
147 "vout": utxo["vout"],
148 "address": utxo["address"],
149 "sequence": BIP125_SEQUENCE_NUMBER
150 } for utxo in utxos]
151 output_val = sum(utxo["amount"] for utxo in utxos) - Decimal("0.001")
152 rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val})
153 signedtx = rbf_node.signrawtransaction(rawtx)
154 signedtx = peer_node.signrawtransaction(signedtx["hex"])
155 rbfid = rbf_node.sendrawtransaction(signedtx["hex"])
156 assert_raises_jsonrpc(-4, "Transaction contains inputs that don't belong to this wallet",
157 rbf_node.bumpfee, rbfid)
160 def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address):
161 # cannot bump fee if the transaction has a descendant
162 # parent is send-to-self, so we don't have to check which output is change when creating the child tx
163 parent_id = spend_one_input(rbf_node, rbf_node_address)
164 tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000})
165 tx = rbf_node.signrawtransaction(tx)
166 rbf_node.sendrawtransaction(tx["hex"])
167 assert_raises_jsonrpc(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id)
170 def test_small_output_fails(rbf_node, dest_address):
171 # cannot bump fee with a too-small output
172 rbfid = spend_one_input(rbf_node, dest_address)
173 rbf_node.bumpfee(rbfid, {"totalFee": 50000})
175 rbfid = spend_one_input(rbf_node, dest_address)
176 assert_raises_jsonrpc(-4, "Change output is too small", rbf_node.bumpfee, rbfid, {"totalFee": 50001})
179 def test_dust_to_fee(rbf_node, dest_address):
180 # check that if output is reduced to dust, it will be converted to fee
181 # the bumped tx sets fee=49,900, but it converts to 50,000
182 rbfid = spend_one_input(rbf_node, dest_address)
183 fulltx = rbf_node.getrawtransaction(rbfid, 1)
184 bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 49900})
185 full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1)
186 assert_equal(bumped_tx["fee"], Decimal("0.00050000"))
187 assert_equal(len(fulltx["vout"]), 2)
188 assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated
191 def test_settxfee(rbf_node, dest_address):
192 # check that bumpfee reacts correctly to the use of settxfee (paytxfee)
193 rbfid = spend_one_input(rbf_node, dest_address)
194 requested_feerate = Decimal("0.00025000")
195 rbf_node.settxfee(requested_feerate)
196 bumped_tx = rbf_node.bumpfee(rbfid)
197 actual_feerate = bumped_tx["fee"] * 1000 / rbf_node.getrawtransaction(bumped_tx["txid"], True)["size"]
198 # Assert that the difference between the requested feerate and the actual
199 # feerate of the bumped transaction is small.
200 assert_greater_than(Decimal("0.00001000"), abs(requested_feerate - actual_feerate))
201 rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee
204 def test_rebumping(rbf_node, dest_address):
205 # check that re-bumping the original tx fails, but bumping the bumper succeeds
206 rbfid = spend_one_input(rbf_node, dest_address)
207 bumped = rbf_node.bumpfee(rbfid, {"totalFee": 2000})
208 assert_raises_jsonrpc(-4, "already bumped", rbf_node.bumpfee, rbfid, {"totalFee": 3000})
209 rbf_node.bumpfee(bumped["txid"], {"totalFee": 3000})
212 def test_rebumping_not_replaceable(rbf_node, dest_address):
213 # check that re-bumping a non-replaceable bump tx fails
214 rbfid = spend_one_input(rbf_node, dest_address)
215 bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
216 assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
217 {"totalFee": 20000})
220 def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
221 # check that unconfirmed outputs from bumped transactions are not spendable
222 rbfid = spend_one_input(rbf_node, rbf_node_address)
223 rbftx = rbf_node.gettransaction(rbfid)["hex"]
224 assert rbfid in rbf_node.getrawmempool()
225 bumpid = rbf_node.bumpfee(rbfid)["txid"]
226 assert bumpid in rbf_node.getrawmempool()
227 assert rbfid not in rbf_node.getrawmempool()
229 # check that outputs from the bump transaction are not spendable
230 # due to the replaces_txid check in CWallet::AvailableCoins
231 assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == bumpid], [])
233 # submit a block with the rbf tx to clear the bump tx out of the mempool,
234 # then call abandon to make sure the wallet doesn't attempt to resubmit the
235 # bump tx, then invalidate the block so the rbf tx will be put back in the
236 # mempool. this makes it possible to check whether the rbf tx outputs are
237 # spendable before the rbf tx is confirmed.
238 block = submit_block_with_tx(rbf_node, rbftx)
239 rbf_node.abandontransaction(bumpid)
240 rbf_node.invalidateblock(block.hash)
241 assert bumpid not in rbf_node.getrawmempool()
242 assert rbfid in rbf_node.getrawmempool()
244 # check that outputs from the rbf tx are not spendable before the
245 # transaction is confirmed, due to the replaced_by_txid check in
246 # CWallet::AvailableCoins
247 assert_equal([t for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == rbfid], [])
249 # check that the main output from the rbf tx is spendable after confirmed
250 rbf_node.generate(1)
251 assert_equal(
252 sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False)
253 if t["txid"] == rbfid and t["address"] == rbf_node_address and t["spendable"]), 1)
256 def test_bumpfee_metadata(rbf_node, dest_address):
257 rbfid = rbf_node.sendtoaddress(dest_address, Decimal("0.00100000"), "comment value", "to value")
258 bumped_tx = rbf_node.bumpfee(rbfid)
259 bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"])
260 assert_equal(bumped_wtx["comment"], "comment value")
261 assert_equal(bumped_wtx["to"], "to value")
264 def test_locked_wallet_fails(rbf_node, dest_address):
265 rbfid = spend_one_input(rbf_node, dest_address)
266 rbf_node.walletlock()
267 assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.",
268 rbf_node.bumpfee, rbfid)
271 def spend_one_input(node, dest_address):
272 tx_input = dict(
273 sequence=BIP125_SEQUENCE_NUMBER, **next(u for u in node.listunspent() if u["amount"] == Decimal("0.00100000")))
274 rawtx = node.createrawtransaction(
275 [tx_input], {dest_address: Decimal("0.00050000"),
276 node.getrawchangeaddress(): Decimal("0.00049000")})
277 signedtx = node.signrawtransaction(rawtx)
278 txid = node.sendrawtransaction(signedtx["hex"])
279 return txid
282 def submit_block_with_tx(node, tx):
283 ctx = CTransaction()
284 ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx)))
286 tip = node.getbestblockhash()
287 height = node.getblockcount() + 1
288 block_time = node.getblockheader(tip)["mediantime"] + 1
289 block = blocktools.create_block(int(tip, 16), blocktools.create_coinbase(height), block_time)
290 block.vtx.append(ctx)
291 block.rehash()
292 block.hashMerkleRoot = block.calc_merkle_root()
293 block.solve()
294 node.submitblock(bytes_to_hex_str(block.serialize(True)))
295 return block
298 if __name__ == "__main__":
299 BumpFeeTest().main()