2
2
# Copyright (c) 2016 The Bitcoin Core developers
3
3
# Distributed under the MIT software license, see the accompanying
4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
- """Test the bumpfee RPC."""
5
+ """Test the bumpfee RPC.
6
+
7
+ Verifies that the bumpfee RPC creates replacement transactions successfully when
8
+ its preconditions are met, and returns appropriate errors in other cases.
9
+
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 the future, they should try to follow the same convention and not
14
+ make assumptions about execution order.
15
+ """
6
16
7
17
from segwit import send_to_witness
8
18
from test_framework .test_framework import BitcoinTestFramework
@@ -57,13 +67,13 @@ def run_test(self):
57
67
58
68
self .log .info ("Running tests" )
59
69
dest_address = peer_node .getnewaddress ()
60
- test_small_output_fails (rbf_node , dest_address )
61
- test_dust_to_fee (rbf_node , dest_address )
62
70
test_simple_bumpfee_succeeds (rbf_node , peer_node , dest_address )
63
71
test_segwit_bumpfee_succeeds (rbf_node , dest_address )
64
72
test_nonrbf_bumpfee_fails (peer_node , dest_address )
65
73
test_notmine_bumpfee_fails (rbf_node , peer_node , dest_address )
66
74
test_bumpfee_with_descendant_fails (rbf_node , rbf_node_address , dest_address )
75
+ test_small_output_fails (rbf_node , dest_address )
76
+ test_dust_to_fee (rbf_node , dest_address )
67
77
test_settxfee (rbf_node , dest_address )
68
78
test_rebumping (rbf_node , dest_address )
69
79
test_rebumping_not_replaceable (rbf_node , dest_address )
@@ -74,7 +84,7 @@ def run_test(self):
74
84
75
85
76
86
def test_simple_bumpfee_succeeds (rbf_node , peer_node , dest_address ):
77
- rbfid = create_fund_sign_send (rbf_node , { dest_address : 0.00090000 } )
87
+ rbfid = spend_one_input (rbf_node , dest_address )
78
88
rbftx = rbf_node .gettransaction (rbfid )
79
89
sync_mempools ((rbf_node , peer_node ))
80
90
assert rbfid in rbf_node .getrawmempool () and rbfid in peer_node .getrawmempool ()
@@ -115,7 +125,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
115
125
'vout' : 0 ,
116
126
"sequence" : BIP125_SEQUENCE_NUMBER
117
127
}], {dest_address : Decimal ("0.0005" ),
118
- get_change_address ( rbf_node ): Decimal ("0.0003" )})
128
+ rbf_node . getrawchangeaddress ( ): Decimal ("0.0003" )})
119
129
rbfsigned = rbf_node .signrawtransaction (rbfraw )
120
130
rbfid = rbf_node .sendrawtransaction (rbfsigned ["hex" ])
121
131
assert rbfid in rbf_node .getrawmempool ()
@@ -127,7 +137,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
127
137
128
138
def test_nonrbf_bumpfee_fails (peer_node , dest_address ):
129
139
# cannot replace a non RBF transaction (from node which did not enable RBF)
130
- not_rbfid = create_fund_sign_send ( peer_node , { dest_address : 0.00090000 } )
140
+ not_rbfid = peer_node . sendtoaddress ( dest_address , Decimal ( " 0.00090000" ) )
131
141
assert_raises_jsonrpc (- 4 , "not BIP 125 replaceable" , peer_node .bumpfee , not_rbfid )
132
142
133
143
@@ -155,7 +165,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
155
165
def test_bumpfee_with_descendant_fails (rbf_node , rbf_node_address , dest_address ):
156
166
# cannot bump fee if the transaction has a descendant
157
167
# parent is send-to-self, so we don't have to check which output is change when creating the child tx
158
- parent_id = create_fund_sign_send (rbf_node , { rbf_node_address : 0.00050000 } )
168
+ parent_id = spend_one_input (rbf_node , rbf_node_address )
159
169
tx = rbf_node .createrawtransaction ([{"txid" : parent_id , "vout" : 0 }], {dest_address : 0.00020000 })
160
170
tx = rbf_node .signrawtransaction (tx )
161
171
txid = rbf_node .sendrawtransaction (tx ["hex" ])
@@ -164,66 +174,58 @@ def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
164
174
165
175
def test_small_output_fails (rbf_node , dest_address ):
166
176
# cannot bump fee with a too-small output
167
- rbfid = spend_one_input (rbf_node ,
168
- Decimal ("0.00100000" ),
169
- {dest_address : 0.00080000 ,
170
- get_change_address (rbf_node ): Decimal ("0.00010000" )})
171
- rbf_node .bumpfee (rbfid , {"totalFee" : 20000 })
177
+ rbfid = spend_one_input (rbf_node , dest_address )
178
+ rbf_node .bumpfee (rbfid , {"totalFee" : 50000 })
172
179
173
- rbfid = spend_one_input (rbf_node ,
174
- Decimal ("0.00100000" ),
175
- {dest_address : 0.00080000 ,
176
- get_change_address (rbf_node ): Decimal ("0.00010000" )})
177
- assert_raises_jsonrpc (- 4 , "Change output is too small" , rbf_node .bumpfee , rbfid , {"totalFee" : 20001 })
180
+ rbfid = spend_one_input (rbf_node , dest_address )
181
+ assert_raises_jsonrpc (- 4 , "Change output is too small" , rbf_node .bumpfee , rbfid , {"totalFee" : 50001 })
178
182
179
183
180
184
def test_dust_to_fee (rbf_node , dest_address ):
181
185
# check that if output is reduced to dust, it will be converted to fee
182
- # the bumped tx sets fee=9900, but it converts to 10,000
183
- rbfid = spend_one_input (rbf_node ,
184
- Decimal ("0.00100000" ),
185
- {dest_address : 0.00080000 ,
186
- get_change_address (rbf_node ): Decimal ("0.00010000" )})
186
+ # the bumped tx sets fee=49,900, but it converts to 50,000
187
+ rbfid = spend_one_input (rbf_node , dest_address )
187
188
fulltx = rbf_node .getrawtransaction (rbfid , 1 )
188
- bumped_tx = rbf_node .bumpfee (rbfid , {"totalFee" : 19900 })
189
+ bumped_tx = rbf_node .bumpfee (rbfid , {"totalFee" : 49900 })
189
190
full_bumped_tx = rbf_node .getrawtransaction (bumped_tx ["txid" ], 1 )
190
- assert_equal (bumped_tx ["fee" ], Decimal ("0.00020000 " ))
191
+ assert_equal (bumped_tx ["fee" ], Decimal ("0.00050000 " ))
191
192
assert_equal (len (fulltx ["vout" ]), 2 )
192
193
assert_equal (len (full_bumped_tx ["vout" ]), 1 ) #change output is eliminated
193
194
194
195
195
196
def test_settxfee (rbf_node , dest_address ):
196
197
# check that bumpfee reacts correctly to the use of settxfee (paytxfee)
197
- # increase feerate by 2.5x, test that fee increased at least 2x
198
- rbf_node .settxfee (Decimal ("0.00001000" ))
199
- rbfid = create_fund_sign_send (rbf_node , {dest_address : 0.00090000 })
198
+ rbfid = spend_one_input (rbf_node , dest_address )
200
199
rbftx = rbf_node .gettransaction (rbfid )
201
- rbf_node .settxfee (Decimal ("0.00002500" ))
200
+ requested_feerate = Decimal ("0.00025000" )
201
+ rbf_node .settxfee (requested_feerate )
202
202
bumped_tx = rbf_node .bumpfee (rbfid )
203
- assert bumped_tx ["fee" ] > 2 * abs (rbftx ["fee" ])
203
+ actual_feerate = bumped_tx ["fee" ] * 1000 / rbf_node .getrawtransaction (bumped_tx ["txid" ], True )["size" ]
204
+ # Assert that the difference between the requested feerate and the actual
205
+ # feerate of the bumped transaction is small.
206
+ assert_greater_than (Decimal ("0.00001000" ), abs (requested_feerate - actual_feerate ))
204
207
rbf_node .settxfee (Decimal ("0.00000000" )) # unset paytxfee
205
208
206
209
207
210
def test_rebumping (rbf_node , dest_address ):
208
211
# check that re-bumping the original tx fails, but bumping the bumper succeeds
209
- rbf_node .settxfee (Decimal ("0.00001000" ))
210
- rbfid = create_fund_sign_send (rbf_node , {dest_address : 0.00090000 })
211
- bumped = rbf_node .bumpfee (rbfid , {"totalFee" : 1000 })
212
- assert_raises_jsonrpc (- 4 , "already bumped" , rbf_node .bumpfee , rbfid , {"totalFee" : 2000 })
213
- rbf_node .bumpfee (bumped ["txid" ], {"totalFee" : 2000 })
212
+ rbfid = spend_one_input (rbf_node , dest_address )
213
+ bumped = rbf_node .bumpfee (rbfid , {"totalFee" : 2000 })
214
+ assert_raises_jsonrpc (- 4 , "already bumped" , rbf_node .bumpfee , rbfid , {"totalFee" : 3000 })
215
+ rbf_node .bumpfee (bumped ["txid" ], {"totalFee" : 3000 })
214
216
215
217
216
218
def test_rebumping_not_replaceable (rbf_node , dest_address ):
217
219
# check that re-bumping a non-replaceable bump tx fails
218
- rbfid = create_fund_sign_send (rbf_node , { dest_address : 0.00090000 } )
220
+ rbfid = spend_one_input (rbf_node , dest_address )
219
221
bumped = rbf_node .bumpfee (rbfid , {"totalFee" : 10000 , "replaceable" : False })
220
222
assert_raises_jsonrpc (- 4 , "Transaction is not BIP 125 replaceable" , rbf_node .bumpfee , bumped ["txid" ],
221
223
{"totalFee" : 20000 })
222
224
223
225
224
226
def test_unconfirmed_not_spendable (rbf_node , rbf_node_address ):
225
227
# check that unconfirmed outputs from bumped transactions are not spendable
226
- rbfid = create_fund_sign_send (rbf_node , { rbf_node_address : 0.00090000 } )
228
+ rbfid = spend_one_input (rbf_node , rbf_node_address )
227
229
rbftx = rbf_node .gettransaction (rbfid )["hex" ]
228
230
assert rbfid in rbf_node .getrawmempool ()
229
231
bumpid = rbf_node .bumpfee (rbfid )["txid" ]
@@ -258,51 +260,31 @@ def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
258
260
259
261
260
262
def test_bumpfee_metadata (rbf_node , dest_address ):
261
- rbfid = rbf_node .sendtoaddress (dest_address , 0.00090000 , "comment value" , "to value" )
263
+ rbfid = rbf_node .sendtoaddress (dest_address , Decimal ( "0.00100000" ) , "comment value" , "to value" )
262
264
bumped_tx = rbf_node .bumpfee (rbfid )
263
265
bumped_wtx = rbf_node .gettransaction (bumped_tx ["txid" ])
264
266
assert_equal (bumped_wtx ["comment" ], "comment value" )
265
267
assert_equal (bumped_wtx ["to" ], "to value" )
266
268
267
269
268
270
def test_locked_wallet_fails (rbf_node , dest_address ):
269
- rbfid = create_fund_sign_send (rbf_node , { dest_address : 0.00090000 } )
271
+ rbfid = spend_one_input (rbf_node , dest_address )
270
272
rbf_node .walletlock ()
271
273
assert_raises_jsonrpc (- 13 , "Please enter the wallet passphrase with walletpassphrase first." ,
272
274
rbf_node .bumpfee , rbfid )
273
275
274
276
275
- def create_fund_sign_send (node , outputs ):
276
- rawtx = node .createrawtransaction ([], outputs )
277
- fundtx = node .fundrawtransaction (rawtx )
278
- signedtx = node .signrawtransaction (fundtx ["hex" ])
279
- txid = node .sendrawtransaction (signedtx ["hex" ])
280
- return txid
281
-
282
-
283
- def spend_one_input (node , input_amount , outputs ):
284
- input = dict (sequence = BIP125_SEQUENCE_NUMBER , ** next (u for u in node .listunspent () if u ["amount" ] == input_amount ))
285
- rawtx = node .createrawtransaction ([input ], outputs )
277
+ def spend_one_input (node , dest_address ):
278
+ tx_input = dict (
279
+ sequence = BIP125_SEQUENCE_NUMBER , ** next (u for u in node .listunspent () if u ["amount" ] == Decimal ("0.00100000" )))
280
+ rawtx = node .createrawtransaction (
281
+ [tx_input ], {dest_address : Decimal ("0.00050000" ),
282
+ node .getrawchangeaddress (): Decimal ("0.00049000" )})
286
283
signedtx = node .signrawtransaction (rawtx )
287
284
txid = node .sendrawtransaction (signedtx ["hex" ])
288
285
return txid
289
286
290
287
291
- def get_change_address (node ):
292
- """Get a wallet change address.
293
-
294
- There is no wallet RPC to access unused change addresses, so this creates a
295
- dummy transaction, calls fundrawtransaction to give add an input and change
296
- output, then returns the change address."""
297
- dest_address = node .getnewaddress ()
298
- dest_amount = Decimal ("0.00012345" )
299
- rawtx = node .createrawtransaction ([], {dest_address : dest_amount })
300
- fundtx = node .fundrawtransaction (rawtx )
301
- info = node .decoderawtransaction (fundtx ["hex" ])
302
- return next (address for out in info ["vout" ]
303
- if out ["value" ] != dest_amount for address in out ["scriptPubKey" ]["addresses" ])
304
-
305
-
306
288
def submit_block_with_tx (node , tx ):
307
289
ctx = CTransaction ()
308
290
ctx .deserialize (io .BytesIO (hex_str_to_bytes (tx )))
0 commit comments