Skip to content

Commit

Permalink
qa: Ensure consistent use of decimals instead of floats
Browse files Browse the repository at this point in the history
This change fixes tests for Python 3.12.8 and 3.13.1 on NetBSD.
  • Loading branch information
hebasto committed Jan 2, 2025
1 parent 228aba2 commit 7afbd9c
Show file tree
Hide file tree
Showing 18 changed files with 156 additions and 144 deletions.
3 changes: 2 additions & 1 deletion test/functional/feature_assumeutxo.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
The assumeutxo value generated and used here is committed to in
`CRegTestParams::m_assumeutxo_data` in `src/kernel/chainparams.cpp`.
"""
from decimal import Decimal
from shutil import rmtree

from dataclasses import dataclass
Expand Down Expand Up @@ -560,7 +561,7 @@ def check_tx_counts(final: bool) -> None:
prev_tx = n0.getblock(spend_coin_blockhash, 3)['tx'][0]
prevout = {"txid": prev_tx['txid'], "vout": 0, "scriptPubKey": prev_tx['vout'][0]['scriptPubKey']['hex']}
privkey = n0.get_deterministic_priv_key().key
raw_tx = n1.createrawtransaction([prevout], {getnewdestination()[2]: 24.99})
raw_tx = n1.createrawtransaction([prevout], {getnewdestination()[2]: Decimal("24.99")})
signed_tx = n1.signrawtransactionwithkey(raw_tx, [privkey], [prevout])['hex']
signed_txid = tx_from_hex(signed_tx).rehash()

Expand Down
44 changes: 22 additions & 22 deletions test/functional/rpc_psbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,17 @@ def test_psbt_incomplete_after_invalid_modification(self):
node = self.nodes[2]
wallet = node.get_wallet_rpc(self.default_wallet_name)
address = wallet.getnewaddress()
wallet.sendtoaddress(address=address, amount=1.0)
wallet.sendtoaddress(address=address, amount=Decimal("1.0"))
self.generate(node, nblocks=1, sync_fun=lambda: self.sync_all(self.nodes[:2]))

utxos = wallet.listunspent(addresses=[address])
psbt = wallet.createpsbt([{"txid": utxos[0]["txid"], "vout": utxos[0]["vout"]}], [{wallet.getnewaddress(): 0.9999}])
psbt = wallet.createpsbt([{"txid": utxos[0]["txid"], "vout": utxos[0]["vout"]}], [{wallet.getnewaddress(): Decimal("0.9999")}])
signed_psbt = wallet.walletprocesspsbt(psbt)["psbt"]

# Modify the raw transaction by changing the output address, so the signature is no longer valid
signed_psbt_obj = PSBT.from_base64(signed_psbt)
substitute_addr = wallet.getnewaddress()
raw = wallet.createrawtransaction([{"txid": utxos[0]["txid"], "vout": utxos[0]["vout"]}], [{substitute_addr: 0.9999}])
raw = wallet.createrawtransaction([{"txid": utxos[0]["txid"], "vout": utxos[0]["vout"]}], [{substitute_addr: Decimal("0.9999")}])
signed_psbt_obj.g.map[PSBT_GLOBAL_UNSIGNED_TX] = bytes.fromhex(raw)

# Check that the walletprocesspsbt call succeeds but also recognizes that the transaction is not complete
Expand Down Expand Up @@ -120,7 +120,7 @@ def test_utxo_conversion(self):

# Construct an unsigned PSBT on the online node
utxos = wonline.listunspent(addresses=[offline_addr])
raw = wonline.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:0.9999}])
raw = wonline.createrawtransaction([{"txid":utxos[0]["txid"], "vout":utxos[0]["vout"]}],[{online_addr:Decimal("0.9999")}])
psbt = wonline.walletprocesspsbt(online_node.converttopsbt(raw))["psbt"]
assert not "not_witness_utxo" in mining_node.decodepsbt(psbt)["inputs"][0]

Expand Down Expand Up @@ -154,11 +154,11 @@ def test_input_confs_control(self):
self.nodes[1].sendmany("", {wallet.getnewaddress():1, wallet.getnewaddress():1})
self.generate(self.nodes[1], 1)

unconfirmed_txid = wallet.sendtoaddress(wallet.getnewaddress(), 0.5)
unconfirmed_txid = wallet.sendtoaddress(wallet.getnewaddress(), Decimal("0.5"))

self.log.info("Crafting PSBT using an unconfirmed input")
target_address = self.nodes[1].getnewaddress()
psbtx1 = wallet.walletcreatefundedpsbt([], {target_address: 0.1}, 0, {'fee_rate': 1, 'maxconf': 0})['psbt']
psbtx1 = wallet.walletcreatefundedpsbt([], {target_address: Decimal("0.1")}, 0, {'fee_rate': 1, 'maxconf': 0})['psbt']

# Make sure we only had the one input
tx1_inputs = self.nodes[0].decodepsbt(psbtx1)['tx']['vin']
Expand Down Expand Up @@ -355,7 +355,7 @@ def run_test(self):
p2pkh_pos = out['n']

inputs = [{"txid": txid, "vout": p2wpkh_pos}, {"txid": txid, "vout": p2sh_p2wpkh_pos}, {"txid": txid, "vout": p2pkh_pos}]
outputs = [{self.nodes[1].getnewaddress(): 29.99}]
outputs = [{self.nodes[1].getnewaddress(): Decimal("29.99")}]

# spend single key from node 1
created_psbt = self.nodes[1].walletcreatefundedpsbt(inputs, outputs)
Expand All @@ -370,15 +370,15 @@ def run_test(self):
self.nodes[1].sendrawtransaction(walletprocesspsbt_out['hex'])

self.log.info("Test walletcreatefundedpsbt fee rate of 10000 sat/vB and 0.1 BTC/kvB produces a total fee at or slightly below -maxtxfee (~0.05290000)")
res1 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": 10000, "add_inputs": True})
res1 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": Decimal("10000"), "add_inputs": True})
assert_approx(res1["fee"], 0.055, 0.005)
res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": "0.1", "add_inputs": True})
res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": Decimal("0.1"), "add_inputs": True})
assert_approx(res2["fee"], 0.055, 0.005)

self.log.info("Test min fee rate checks with walletcreatefundedpsbt are bypassed, e.g. a fee_rate under 1 sat/vB is allowed")
res3 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": "0.999", "add_inputs": True})
res3 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"fee_rate": Decimal("0.999"), "add_inputs": True})
assert_approx(res3["fee"], 0.00000381, 0.0000001)
res4 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.00000999, "add_inputs": True})
res4 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": Decimal("0.00000999"), "add_inputs": True})
assert_approx(res4["fee"], 0.00000381, 0.0000001)

self.log.info("Test min fee rate checks with walletcreatefundedpsbt are bypassed and that funding non-standard 'zero-fee' transactions is valid")
Expand All @@ -394,21 +394,21 @@ def run_test(self):
assert_raises_rpc_error(-3, "Amount is not a number or string",
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {param: {"foo": "bar"}, "add_inputs": True})
# Test fee rate values that don't pass fixed-point parsing checks.
for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]:
for invalid_value in [""] + list(map(Decimal, "0.000000001 1e-09 1.111111111 1111111111111111 31.999999999999999999999".split())):
assert_raises_rpc_error(-3, "Invalid amount",
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {param: invalid_value, "add_inputs": True})
# Test fee_rate values that cannot be represented in sat/vB.
for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999]:
for invalid_value in list(map(Decimal, "0.0001 0.00000001 0.00099999 31.99999999".split())):
assert_raises_rpc_error(-3, "Invalid amount",
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": invalid_value, "add_inputs": True})

self.log.info("- raises RPC error if both feeRate and fee_rate are passed")
assert_raises_rpc_error(-8, "Cannot specify both fee_rate (sat/vB) and feeRate (BTC/kvB)",
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": 0.1, "feeRate": 0.1, "add_inputs": True})
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": Decimal("0.1"), "feeRate": Decimal("0.1"), "add_inputs": True})

self.log.info("- raises RPC error if both feeRate and estimate_mode passed")
assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and feeRate",
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": "economical", "feeRate": 0.1, "add_inputs": True})
self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": "economical", "feeRate": Decimal("0.1"), "add_inputs": True})

for param in ["feeRate", "fee_rate"]:
self.log.info("- raises RPC error if both {} and conf_target are passed".format(param))
Expand Down Expand Up @@ -447,7 +447,7 @@ def run_test(self):

self.log.info("Test various PSBT operations")
# partially sign multisig things with node 1
psbtx = wmulti.walletcreatefundedpsbt(inputs=[{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], outputs={self.nodes[1].getnewaddress():29.99}, changeAddress=self.nodes[1].getrawchangeaddress())['psbt']
psbtx = wmulti.walletcreatefundedpsbt(inputs=[{"txid":txid,"vout":p2wsh_pos},{"txid":txid,"vout":p2sh_pos},{"txid":txid,"vout":p2sh_p2wsh_pos}], outputs={self.nodes[1].getnewaddress():Decimal("29.99")}, changeAddress=self.nodes[1].getrawchangeaddress())['psbt']
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
psbtx = walletprocesspsbt_out['psbt']
assert_equal(walletprocesspsbt_out['complete'], False)
Expand All @@ -461,7 +461,7 @@ def run_test(self):
self.nodes[2].sendrawtransaction(walletprocesspsbt_out['hex'])

# check that walletprocesspsbt fails to decode a non-psbt
rawtx = self.nodes[1].createrawtransaction([{"txid":txid,"vout":p2wpkh_pos}], {self.nodes[1].getnewaddress():9.99})
rawtx = self.nodes[1].createrawtransaction([{"txid":txid,"vout":p2wpkh_pos}], {self.nodes[1].getnewaddress():Decimal("9.99")})
assert_raises_rpc_error(-22, "TX decode failed", self.nodes[1].walletprocesspsbt, rawtx)

# Convert a non-psbt to psbt and make sure we can decode it
Expand Down Expand Up @@ -492,7 +492,7 @@ def run_test(self):
self.generate(self.nodes[0], 6)[0]

# Create a psbt spending outputs from nodes 1 and 2
psbt_orig = self.nodes[0].createpsbt([utxo1, utxo2], {self.nodes[0].getnewaddress():25.999})
psbt_orig = self.nodes[0].createpsbt([utxo1, utxo2], {self.nodes[0].getnewaddress():Decimal("25.999")})

# Update psbts, should only have data for one input and not the other
psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig, False, "ALL")['psbt']
Expand Down Expand Up @@ -558,7 +558,7 @@ def run_test(self):
self.nodes[0].walletcreatefundedpsbt([], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"changeAddress":self.nodes[1].getnewaddress()}, False)

# Make sure the wallet's change type is respected by default
small_output = {self.nodes[0].getnewaddress():0.1}
small_output = {self.nodes[0].getnewaddress():Decimal("0.1")}
psbtx_native = self.nodes[0].walletcreatefundedpsbt([], [small_output])
self.assert_change_type(psbtx_native, "witness_v0_keyhash")
psbtx_legacy = self.nodes[1].walletcreatefundedpsbt([], [small_output])
Expand Down Expand Up @@ -680,7 +680,7 @@ def test_psbt_input_keys(psbt_input, keys):
assert_equal(set(keys), set(psbt_input.keys()))

# Create a PSBT. None of the inputs are filled initially
psbt = self.nodes[1].createpsbt([utxo1, utxo2, utxo3], {self.nodes[0].getnewaddress():32.999})
psbt = self.nodes[1].createpsbt([utxo1, utxo2, utxo3], {self.nodes[0].getnewaddress():Decimal("32.999")})
decoded = self.nodes[1].decodepsbt(psbt)
test_psbt_input_keys(decoded['inputs'][0], [])
test_psbt_input_keys(decoded['inputs'][1], [])
Expand Down Expand Up @@ -928,7 +928,7 @@ def test_psbt_input_keys(psbt_input, keys):
self.log.info("Test that walletprocesspsbt both updates and signs a non-updated psbt containing Taproot inputs")
addr = self.nodes[0].getnewaddress("", "bech32m")
utxo = self.create_outpoints(self.nodes[0], outputs=[{addr: 1}])[0]
psbt = self.nodes[0].createpsbt([utxo], [{self.nodes[0].getnewaddress(): 0.9999}])
psbt = self.nodes[0].createpsbt([utxo], [{self.nodes[0].getnewaddress(): Decimal("0.9999")}])
signed = self.nodes[0].walletprocesspsbt(psbt)
rawtx = signed["hex"]
self.nodes[0].sendrawtransaction(rawtx)
Expand Down Expand Up @@ -1019,7 +1019,7 @@ def test_psbt_input_keys(psbt_input, keys):
utxo = self.create_outpoints(self.nodes[0], outputs=[{address: 1}])[0]
self.sync_all()

psbt = self.nodes[2].createpsbt([utxo], {self.nodes[0].getnewaddress(): 0.99999})
psbt = self.nodes[2].createpsbt([utxo], {self.nodes[0].getnewaddress(): Decimal("0.99999")})
decoded = self.nodes[2].decodepsbt(psbt)
test_psbt_input_keys(decoded['inputs'][0], [])

Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_avoid_mixing_output_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
but still know when to expect mixing due to the wallet being close to empty.
"""
from decimal import Decimal

import random
from test_framework.test_framework import BitcoinTestFramework
Expand Down Expand Up @@ -172,7 +173,7 @@ def run_test(self):
self.generate(A, 1)
assert is_same_type(B, tx)

tx = self.make_payment(A, B, 30.99, random.choice(ADDRESS_TYPES))
tx = self.make_payment(A, B, Decimal("30.99"), random.choice(ADDRESS_TYPES))
assert not is_same_type(B, tx)


Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def test_balances(*, fee_node_1=0):
before = self.nodes[1].getbalances()['mine']['untrusted_pending']
dst = self.nodes[1].getnewaddress()
self.nodes[1].unloadwallet(self.default_wallet_name)
self.nodes[0].sendtoaddress(dst, 0.1)
self.nodes[0].sendtoaddress(dst, Decimal('0.1'))
self.sync_all()
self.nodes[1].loadwallet(self.default_wallet_name)
after = self.nodes[1].getbalances()['mine']['untrusted_pending']
Expand Down
2 changes: 1 addition & 1 deletion test/functional/wallet_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ def run_test(self):
# 4. check if recipient (node0) can list the zero value tx
usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0]
inputs = [{"txid": usp['txid'], "vout": usp['vout']}]
outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11}
outputs = {self.nodes[1].getnewaddress(): Decimal("49.998"), self.nodes[0].getnewaddress(): Decimal("11.11")}

raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32)
signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx)
Expand Down
Loading

0 comments on commit 7afbd9c

Please sign in to comment.