Skip to content

Commit a230b05

Browse files
author
MarcoFalke
committed
Merge #9701: Make bumpfee tests less fragile
f85ac54 [qa] Expand bumpfee test docstring (Russell Yanofsky) 0b94e49 [qa] Rename python input variable to tx_input (Russell Yanofsky) 1dfd64f [qa] Make bumpfee.py test function order consistent (Russell Yanofsky) e6b2963 [qa] Get rid of nondeterminism in bumpfee.py (Russell Yanofsky) 94b528b [qa] Remove bumpfee.py get_change_address hack (Russell Yanofsky) Tree-SHA512: 4017d58fe73837a0dfcca69c43f804498833f946efd9bc394877be242aa40b03d60bd6c3672ed5d24db88b3318304c1f2838050ec5fa6458d1a7e1f566ccda3e
2 parents dfef6b6 + f85ac54 commit a230b05

File tree

1 file changed

+46
-64
lines changed

1 file changed

+46
-64
lines changed

test/functional/bumpfee.py

Lines changed: 46 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22
# Copyright (c) 2016 The Bitcoin Core developers
33
# Distributed under the MIT software license, see the accompanying
44
# 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+
"""
616

717
from segwit import send_to_witness
818
from test_framework.test_framework import BitcoinTestFramework
@@ -57,13 +67,13 @@ def run_test(self):
5767

5868
self.log.info("Running tests")
5969
dest_address = peer_node.getnewaddress()
60-
test_small_output_fails(rbf_node, dest_address)
61-
test_dust_to_fee(rbf_node, dest_address)
6270
test_simple_bumpfee_succeeds(rbf_node, peer_node, dest_address)
6371
test_segwit_bumpfee_succeeds(rbf_node, dest_address)
6472
test_nonrbf_bumpfee_fails(peer_node, dest_address)
6573
test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address)
6674
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)
6777
test_settxfee(rbf_node, dest_address)
6878
test_rebumping(rbf_node, dest_address)
6979
test_rebumping_not_replaceable(rbf_node, dest_address)
@@ -74,7 +84,7 @@ def run_test(self):
7484

7585

7686
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)
7888
rbftx = rbf_node.gettransaction(rbfid)
7989
sync_mempools((rbf_node, peer_node))
8090
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):
115125
'vout': 0,
116126
"sequence": BIP125_SEQUENCE_NUMBER
117127
}], {dest_address: Decimal("0.0005"),
118-
get_change_address(rbf_node): Decimal("0.0003")})
128+
rbf_node.getrawchangeaddress(): Decimal("0.0003")})
119129
rbfsigned = rbf_node.signrawtransaction(rbfraw)
120130
rbfid = rbf_node.sendrawtransaction(rbfsigned["hex"])
121131
assert rbfid in rbf_node.getrawmempool()
@@ -127,7 +137,7 @@ def test_segwit_bumpfee_succeeds(rbf_node, dest_address):
127137

128138
def test_nonrbf_bumpfee_fails(peer_node, dest_address):
129139
# 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"))
131141
assert_raises_jsonrpc(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
132142

133143

@@ -155,7 +165,7 @@ def test_notmine_bumpfee_fails(rbf_node, peer_node, dest_address):
155165
def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address):
156166
# cannot bump fee if the transaction has a descendant
157167
# 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)
159169
tx = rbf_node.createrawtransaction([{"txid": parent_id, "vout": 0}], {dest_address: 0.00020000})
160170
tx = rbf_node.signrawtransaction(tx)
161171
txid = rbf_node.sendrawtransaction(tx["hex"])
@@ -164,66 +174,58 @@ def test_bumpfee_with_descendant_fails(rbf_node, rbf_node_address, dest_address)
164174

165175
def test_small_output_fails(rbf_node, dest_address):
166176
# 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})
172179

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})
178182

179183

180184
def test_dust_to_fee(rbf_node, dest_address):
181185
# 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)
187188
fulltx = rbf_node.getrawtransaction(rbfid, 1)
188-
bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 19900})
189+
bumped_tx = rbf_node.bumpfee(rbfid, {"totalFee": 49900})
189190
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"))
191192
assert_equal(len(fulltx["vout"]), 2)
192193
assert_equal(len(full_bumped_tx["vout"]), 1) #change output is eliminated
193194

194195

195196
def test_settxfee(rbf_node, dest_address):
196197
# 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)
200199
rbftx = rbf_node.gettransaction(rbfid)
201-
rbf_node.settxfee(Decimal("0.00002500"))
200+
requested_feerate = Decimal("0.00025000")
201+
rbf_node.settxfee(requested_feerate)
202202
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))
204207
rbf_node.settxfee(Decimal("0.00000000")) # unset paytxfee
205208

206209

207210
def test_rebumping(rbf_node, dest_address):
208211
# 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})
214216

215217

216218
def test_rebumping_not_replaceable(rbf_node, dest_address):
217219
# 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)
219221
bumped = rbf_node.bumpfee(rbfid, {"totalFee": 10000, "replaceable": False})
220222
assert_raises_jsonrpc(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
221223
{"totalFee": 20000})
222224

223225

224226
def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
225227
# 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)
227229
rbftx = rbf_node.gettransaction(rbfid)["hex"]
228230
assert rbfid in rbf_node.getrawmempool()
229231
bumpid = rbf_node.bumpfee(rbfid)["txid"]
@@ -258,51 +260,31 @@ def test_unconfirmed_not_spendable(rbf_node, rbf_node_address):
258260

259261

260262
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")
262264
bumped_tx = rbf_node.bumpfee(rbfid)
263265
bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"])
264266
assert_equal(bumped_wtx["comment"], "comment value")
265267
assert_equal(bumped_wtx["to"], "to value")
266268

267269

268270
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)
270272
rbf_node.walletlock()
271273
assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first.",
272274
rbf_node.bumpfee, rbfid)
273275

274276

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")})
286283
signedtx = node.signrawtransaction(rawtx)
287284
txid = node.sendrawtransaction(signedtx["hex"])
288285
return txid
289286

290287

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-
306288
def submit_block_with_tx(node, tx):
307289
ctx = CTransaction()
308290
ctx.deserialize(io.BytesIO(hex_str_to_bytes(tx)))

0 commit comments

Comments
 (0)