0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-09 10:43:19 -05:00

test: Update python tests to use named parameters instead of options objects

This commit is contained in:
Ryan Ofsky 2022-11-10 12:04:07 -05:00
parent 96233146dd
commit 95d7de0964
13 changed files with 140 additions and 140 deletions

View file

@ -373,7 +373,7 @@ class PSBTTest(BitcoinTestFramework):
self.log.info("Test various PSBT operations") self.log.info("Test various PSBT operations")
# partially sign multisig things with node 1 # 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}, options={'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():29.99}, changeAddress=self.nodes[1].getrawchangeaddress())['psbt']
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx) walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(psbtx)
psbtx = walletprocesspsbt_out['psbt'] psbtx = walletprocesspsbt_out['psbt']
assert_equal(walletprocesspsbt_out['complete'], False) assert_equal(walletprocesspsbt_out['complete'], False)
@ -778,7 +778,7 @@ class PSBTTest(BitcoinTestFramework):
psbt = wallet.walletcreatefundedpsbt( psbt = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}], inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}],
outputs={self.nodes[0].getnewaddress(): 15}, outputs={self.nodes[0].getnewaddress(): 15},
options={"add_inputs": True} add_inputs=True,
) )
signed = wallet.walletprocesspsbt(psbt["psbt"]) signed = wallet.walletprocesspsbt(psbt["psbt"])
signed = self.nodes[0].walletprocesspsbt(signed["psbt"]) signed = self.nodes[0].walletprocesspsbt(signed["psbt"])
@ -788,21 +788,21 @@ class PSBTTest(BitcoinTestFramework):
psbt2 = wallet.walletcreatefundedpsbt( psbt2 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}], inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15}, outputs={self.nodes[0].getnewaddress(): 15},
options={"add_inputs": True} add_inputs=True,
) )
assert_greater_than(psbt["fee"], psbt2["fee"]) assert_greater_than(psbt["fee"], psbt2["fee"])
# Increasing the weight should have a higher fee # Increasing the weight should have a higher fee
psbt2 = wallet.walletcreatefundedpsbt( psbt2 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15}, outputs={self.nodes[0].getnewaddress(): 15},
options={"add_inputs": True} add_inputs=True,
) )
assert_greater_than(psbt2["fee"], psbt["fee"]) assert_greater_than(psbt2["fee"], psbt["fee"])
# The provided weight should override the calculated weight when solving data is provided # The provided weight should override the calculated weight when solving data is provided
psbt3 = wallet.walletcreatefundedpsbt( psbt3 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15}, outputs={self.nodes[0].getnewaddress(): 15},
options={'add_inputs': True, "solving_data":{"descriptors": [desc]}} add_inputs=True, solving_data={"descriptors": [desc]},
) )
assert_equal(psbt2["fee"], psbt3["fee"]) assert_equal(psbt2["fee"], psbt3["fee"])
@ -816,7 +816,7 @@ class PSBTTest(BitcoinTestFramework):
psbt3 = wallet.walletcreatefundedpsbt( psbt3 = wallet.walletcreatefundedpsbt(
inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}],
outputs={self.nodes[0].getnewaddress(): 15}, outputs={self.nodes[0].getnewaddress(): 15},
options={"add_inputs": True} add_inputs=True,
) )
assert_equal(psbt2["fee"], psbt3["fee"]) assert_equal(psbt2["fee"], psbt3["fee"])

View file

@ -123,36 +123,36 @@ class BumpFeeTest(BitcoinTestFramework):
assert_raises_rpc_error(-3, "Unexpected key {}".format(key), rbf_node.bumpfee, rbfid, {key: NORMAL}) assert_raises_rpc_error(-3, "Unexpected key {}".format(key), rbf_node.bumpfee, rbfid, {key: NORMAL})
# Bumping to just above minrelay should fail to increase the total fee enough. # Bumping to just above minrelay should fail to increase the total fee enough.
assert_raises_rpc_error(-8, "Insufficient total fee 0.00000141", rbf_node.bumpfee, rbfid, {"fee_rate": INSUFFICIENT}) assert_raises_rpc_error(-8, "Insufficient total fee 0.00000141", rbf_node.bumpfee, rbfid, fee_rate=INSUFFICIENT)
self.log.info("Test invalid fee rate settings") self.log.info("Test invalid fee rate settings")
assert_raises_rpc_error(-4, "Specified or calculated fee 0.141 is too high (cannot be higher than -maxtxfee 0.10", assert_raises_rpc_error(-4, "Specified or calculated fee 0.141 is too high (cannot be higher than -maxtxfee 0.10",
rbf_node.bumpfee, rbfid, {"fee_rate": TOO_HIGH}) rbf_node.bumpfee, rbfid, fee_rate=TOO_HIGH)
# Test fee_rate with zero values. # Test fee_rate with zero values.
msg = "Insufficient total fee 0.00" msg = "Insufficient total fee 0.00"
for zero_value in [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]: for zero_value in [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]:
assert_raises_rpc_error(-8, msg, rbf_node.bumpfee, rbfid, {"fee_rate": zero_value}) assert_raises_rpc_error(-8, msg, rbf_node.bumpfee, rbfid, fee_rate=zero_value)
msg = "Invalid amount" msg = "Invalid amount"
# Test fee_rate values that don't pass fixed-point parsing checks. # 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 ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]:
assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, {"fee_rate": invalid_value}) assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value)
# Test fee_rate values that cannot be represented in sat/vB. # Test fee_rate values that cannot be represented in sat/vB.
for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]: for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]:
assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, {"fee_rate": invalid_value}) assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value)
# Test fee_rate out of range (negative number). # Test fee_rate out of range (negative number).
assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, {"fee_rate": -1}) assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, fee_rate=-1)
# Test type error. # Test type error.
for value in [{"foo": "bar"}, True]: for value in [{"foo": "bar"}, True]:
assert_raises_rpc_error(-3, "Amount is not a number or string", rbf_node.bumpfee, rbfid, {"fee_rate": value}) assert_raises_rpc_error(-3, "Amount is not a number or string", rbf_node.bumpfee, rbfid, fee_rate=value)
self.log.info("Test explicit fee rate raises RPC error if both fee_rate and conf_target are passed") self.log.info("Test explicit fee rate raises RPC error if both fee_rate and conf_target are passed")
assert_raises_rpc_error(-8, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation " assert_raises_rpc_error(-8, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation "
"target in blocks for automatic fee estimation, or an explicit fee rate.", "target in blocks for automatic fee estimation, or an explicit fee rate.",
rbf_node.bumpfee, rbfid, {"conf_target": NORMAL, "fee_rate": NORMAL}) rbf_node.bumpfee, rbfid, conf_target=NORMAL, fee_rate=NORMAL)
self.log.info("Test explicit fee rate raises RPC error if both fee_rate and estimate_mode are passed") self.log.info("Test explicit fee rate raises RPC error if both fee_rate and estimate_mode are passed")
assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and fee_rate", assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and fee_rate",
rbf_node.bumpfee, rbfid, {"estimate_mode": "economical", "fee_rate": NORMAL}) rbf_node.bumpfee, rbfid, estimate_mode="economical", fee_rate=NORMAL)
self.log.info("Test invalid conf_target settings") self.log.info("Test invalid conf_target settings")
assert_raises_rpc_error(-8, "confTarget and conf_target options should not both be set", assert_raises_rpc_error(-8, "confTarget and conf_target options should not both be set",
@ -161,10 +161,10 @@ class BumpFeeTest(BitcoinTestFramework):
self.log.info("Test invalid estimate_mode settings") self.log.info("Test invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string", assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string",
rbf_node.bumpfee, rbfid, {"estimate_mode": v}) rbf_node.bumpfee, rbfid, estimate_mode=v)
for mode in ["foo", Decimal("3.1415"), "sat/B", "BTC/kB"]: for mode in ["foo", Decimal("3.1415"), "sat/B", "BTC/kB"]:
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
rbf_node.bumpfee, rbfid, {"estimate_mode": mode}) rbf_node.bumpfee, rbfid, estimate_mode=mode)
self.log.info("Test invalid outputs values") self.log.info("Test invalid outputs values")
assert_raises_rpc_error(-8, "Invalid parameter, output argument cannot be an empty array", assert_raises_rpc_error(-8, "Invalid parameter, output argument cannot be an empty array",
@ -232,12 +232,12 @@ def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address):
self.sync_mempools((rbf_node, peer_node)) self.sync_mempools((rbf_node, peer_node))
assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool() assert rbfid in rbf_node.getrawmempool() and rbfid in peer_node.getrawmempool()
if mode == "fee_rate": if mode == "fee_rate":
bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"fee_rate": str(NORMAL)}) bumped_psbt = rbf_node.psbtbumpfee(rbfid, fee_rate=str(NORMAL))
bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": NORMAL}) bumped_tx = rbf_node.bumpfee(rbfid, fee_rate=NORMAL)
elif mode == "new_outputs": elif mode == "new_outputs":
new_address = peer_node.getnewaddress() new_address = peer_node.getnewaddress()
bumped_psbt = rbf_node.psbtbumpfee(rbfid, {"outputs": {new_address: 0.0003}}) bumped_psbt = rbf_node.psbtbumpfee(rbfid, outputs={new_address: 0.0003})
bumped_tx = rbf_node.bumpfee(rbfid, {"outputs": {new_address: 0.0003}}) bumped_tx = rbf_node.bumpfee(rbfid, outputs={new_address: 0.0003})
else: else:
bumped_psbt = rbf_node.psbtbumpfee(rbfid) bumped_psbt = rbf_node.psbtbumpfee(rbfid)
bumped_tx = rbf_node.bumpfee(rbfid) bumped_tx = rbf_node.bumpfee(rbfid)
@ -305,7 +305,7 @@ def test_notmine_bumpfee(self, rbf_node, peer_node, dest_address):
# Note that this test depends upon the RPC code checking input ownership prior to change outputs # Note that this test depends upon the RPC code checking input ownership prior to change outputs
# (since it can't use fundrawtransaction, it lacks a proper change output) # (since it can't use fundrawtransaction, it lacks a proper change output)
fee = Decimal("0.001") fee = Decimal("0.001")
utxos = [node.listunspent(query_options={'minimumAmount': fee})[-1] for node in (rbf_node, peer_node)] utxos = [node.listunspent(minimumAmount=fee)[-1] for node in (rbf_node, peer_node)]
inputs = [{ inputs = [{
"txid": utxo["txid"], "txid": utxo["txid"],
"vout": utxo["vout"], "vout": utxo["vout"],
@ -335,7 +335,7 @@ def test_notmine_bumpfee(self, rbf_node, peer_node, dest_address):
psbt = rbf_node.psbtbumpfee(txid=rbfid) psbt = rbf_node.psbtbumpfee(txid=rbfid)
finish_psbtbumpfee(psbt["psbt"]) finish_psbtbumpfee(psbt["psbt"])
psbt = rbf_node.psbtbumpfee(txid=rbfid, options={"fee_rate": old_feerate + 10}) psbt = rbf_node.psbtbumpfee(txid=rbfid, fee_rate=old_feerate + 10)
finish_psbtbumpfee(psbt["psbt"]) finish_psbtbumpfee(psbt["psbt"])
self.clear_mempool() self.clear_mempool()
@ -445,7 +445,7 @@ def test_dust_to_fee(self, rbf_node, dest_address):
# Expected fee is 141 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049385 BTC. # Expected fee is 141 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049385 BTC.
# or occasionally 140 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049035 BTC. # or occasionally 140 vbytes * fee_rate 0.00350250 BTC / 1000 vbytes = 0.00049035 BTC.
# Dust should be dropped to the fee, so actual bump fee is 0.00050000 BTC. # Dust should be dropped to the fee, so actual bump fee is 0.00050000 BTC.
bumped_tx = rbf_node.bumpfee(rbfid, {"fee_rate": 350.25}) bumped_tx = rbf_node.bumpfee(rbfid, fee_rate=350.25)
full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1) full_bumped_tx = rbf_node.getrawtransaction(bumped_tx["txid"], 1)
assert_equal(bumped_tx["fee"], Decimal("0.00050000")) assert_equal(bumped_tx["fee"], Decimal("0.00050000"))
assert_equal(len(fulltx["vout"]), 2) assert_equal(len(fulltx["vout"]), 2)
@ -569,7 +569,7 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address):
assert_raises_rpc_error(-4, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.", watcher.bumpfee, original_txid) assert_raises_rpc_error(-4, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.", watcher.bumpfee, original_txid)
# Bump fee, obnoxiously high to add additional watchonly input # Bump fee, obnoxiously high to add additional watchonly input
bumped_psbt = watcher.psbtbumpfee(original_txid, {"fee_rate": HIGH}) bumped_psbt = watcher.psbtbumpfee(original_txid, fee_rate=HIGH)
assert_greater_than(len(watcher.decodepsbt(bumped_psbt['psbt'])["tx"]["vin"]), 1) assert_greater_than(len(watcher.decodepsbt(bumped_psbt['psbt'])["tx"]["vin"]), 1)
assert "txid" not in bumped_psbt assert "txid" not in bumped_psbt
assert_equal(bumped_psbt["origfee"], -watcher.gettransaction(original_txid)["fee"]) assert_equal(bumped_psbt["origfee"], -watcher.gettransaction(original_txid)["fee"])
@ -593,17 +593,17 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address):
def test_rebumping(self, rbf_node, dest_address): def test_rebumping(self, rbf_node, dest_address):
self.log.info('Test that re-bumping the original tx fails, but bumping successor works') self.log.info('Test that re-bumping the original tx fails, but bumping successor works')
rbfid = spend_one_input(rbf_node, dest_address) rbfid = spend_one_input(rbf_node, dest_address)
bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL}) bumped = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL)
assert_raises_rpc_error(-4, f"Cannot bump transaction {rbfid} which was already bumped by transaction {bumped['txid']}", assert_raises_rpc_error(-4, f"Cannot bump transaction {rbfid} which was already bumped by transaction {bumped['txid']}",
rbf_node.bumpfee, rbfid, {"fee_rate": NORMAL}) rbf_node.bumpfee, rbfid, fee_rate=NORMAL)
rbf_node.bumpfee(bumped["txid"], {"fee_rate": NORMAL}) rbf_node.bumpfee(bumped["txid"], fee_rate=NORMAL)
self.clear_mempool() self.clear_mempool()
def test_rebumping_not_replaceable(self, rbf_node, dest_address): def test_rebumping_not_replaceable(self, rbf_node, dest_address):
self.log.info('Test that re-bumping non-replaceable fails') self.log.info('Test that re-bumping non-replaceable fails')
rbfid = spend_one_input(rbf_node, dest_address) rbfid = spend_one_input(rbf_node, dest_address)
bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL, "replaceable": False}) bumped = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL, replaceable=False)
assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
{"fee_rate": NORMAL}) {"fee_rate": NORMAL})
self.clear_mempool() self.clear_mempool()
@ -615,7 +615,7 @@ def test_bumpfee_already_spent(self, rbf_node, dest_address):
self.generate(rbf_node, 1) # spend coin simply by mining block with tx self.generate(rbf_node, 1) # spend coin simply by mining block with tx
spent_input = rbf_node.gettransaction(txid=txid, verbose=True)['decoded']['vin'][0] spent_input = rbf_node.gettransaction(txid=txid, verbose=True)['decoded']['vin'][0]
assert_raises_rpc_error(-1, f"{spent_input['txid']}:{spent_input['vout']} is already spent", assert_raises_rpc_error(-1, f"{spent_input['txid']}:{spent_input['vout']} is already spent",
rbf_node.bumpfee, txid, {"fee_rate": NORMAL}) rbf_node.bumpfee, txid, fee_rate=NORMAL)
def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address): def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address):
@ -694,7 +694,7 @@ def test_change_script_match(self, rbf_node, dest_address):
assert_equal(len(change_addresses), 1) assert_equal(len(change_addresses), 1)
# Now find that address in each subsequent tx, and no other change # Now find that address in each subsequent tx, and no other change
bumped_total_tx = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL}) bumped_total_tx = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL)
assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'], rbf_node)) assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'], rbf_node))
bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"]) bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"])
assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'], rbf_node)) assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'], rbf_node))

View file

@ -154,7 +154,7 @@ class RawTransactionsTest(BitcoinTestFramework):
"""Ensure setting changePosition in fundraw with an exact match is handled properly.""" """Ensure setting changePosition in fundraw with an exact match is handled properly."""
self.log.info("Test fundrawtxn changePosition option") self.log.info("Test fundrawtxn changePosition option")
rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():50}) rawmatch = self.nodes[2].createrawtransaction([], {self.nodes[2].getnewaddress():50})
rawmatch = self.nodes[2].fundrawtransaction(rawmatch, {"changePosition":1, "subtractFeeFromOutputs":[0]}) rawmatch = self.nodes[2].fundrawtransaction(rawmatch, changePosition=1, subtractFeeFromOutputs=[0])
assert_equal(rawmatch["changepos"], -1) assert_equal(rawmatch["changepos"], -1)
self.nodes[3].createwallet(wallet_name="wwatch", disable_private_keys=True) self.nodes[3].createwallet(wallet_name="wwatch", disable_private_keys=True)
@ -268,10 +268,10 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx) dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
assert_raises_rpc_error(-3, "Unexpected key foo", self.nodes[2].fundrawtransaction, rawtx, {'foo':'bar'}) assert_raises_rpc_error(-8, "Unknown named parameter foo", self.nodes[2].fundrawtransaction, rawtx, foo='bar')
# reserveChangeKey was deprecated and is now removed # reserveChangeKey was deprecated and is now removed
assert_raises_rpc_error(-3, "Unexpected key reserveChangeKey", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, options={'reserveChangeKey': True})) assert_raises_rpc_error(-8, "Unknown named parameter reserveChangeKey", lambda: self.nodes[2].fundrawtransaction(hexstring=rawtx, reserveChangeKey=True))
def test_invalid_change_address(self): def test_invalid_change_address(self):
self.log.info("Test fundrawtxn with an invalid change address") self.log.info("Test fundrawtxn with an invalid change address")
@ -283,7 +283,7 @@ class RawTransactionsTest(BitcoinTestFramework):
dec_tx = self.nodes[2].decoderawtransaction(rawtx) dec_tx = self.nodes[2].decoderawtransaction(rawtx)
assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
assert_raises_rpc_error(-5, "Change address must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':'foobar'}) assert_raises_rpc_error(-5, "Change address must be a valid bitcoin address", self.nodes[2].fundrawtransaction, rawtx, changeAddress='foobar')
def test_valid_change_address(self): def test_valid_change_address(self):
self.log.info("Test fundrawtxn with a provided change address") self.log.info("Test fundrawtxn with a provided change address")
@ -296,8 +296,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
change = self.nodes[2].getnewaddress() change = self.nodes[2].getnewaddress()
assert_raises_rpc_error(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, {'changeAddress':change, 'changePosition':2}) assert_raises_rpc_error(-8, "changePosition out of bounds", self.nodes[2].fundrawtransaction, rawtx, changeAddress=change, changePosition=2)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {'changeAddress': change, 'changePosition': 0}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, changeAddress=change, changePosition=0)
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
out = dec_tx['vout'][0] out = dec_tx['vout'][0]
assert_equal(change, out['scriptPubKey']['address']) assert_equal(change, out['scriptPubKey']['address'])
@ -309,9 +309,9 @@ class RawTransactionsTest(BitcoinTestFramework):
inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ] inputs = [ {'txid' : utx['txid'], 'vout' : utx['vout']} ]
outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) } outputs = { self.nodes[0].getnewaddress() : Decimal(4.0) }
rawtx = self.nodes[2].createrawtransaction(inputs, outputs) rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", self.nodes[2].fundrawtransaction, rawtx, {'change_type': None}) assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", self.nodes[2].fundrawtransaction, rawtx, change_type=None)
assert_raises_rpc_error(-5, "Unknown change type ''", self.nodes[2].fundrawtransaction, rawtx, {'change_type': ''}) assert_raises_rpc_error(-5, "Unknown change type ''", self.nodes[2].fundrawtransaction, rawtx, change_type='')
rawtx = self.nodes[2].fundrawtransaction(rawtx, {'change_type': 'bech32'}) rawtx = self.nodes[2].fundrawtransaction(rawtx, change_type='bech32')
dec_tx = self.nodes[2].decoderawtransaction(rawtx['hex']) dec_tx = self.nodes[2].decoderawtransaction(rawtx['hex'])
assert_equal('witness_v0_keyhash', dec_tx['vout'][rawtx['changepos']]['scriptPubKey']['type']) assert_equal('witness_v0_keyhash', dec_tx['vout'][rawtx['changepos']]['scriptPubKey']['type'])
@ -331,7 +331,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex']) assert_equal("00", dec_tx['vin'][0]['scriptSig']['hex'])
# Should fail without add_inputs: # Should fail without add_inputs:
assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)
# add_inputs is enabled by default # add_inputs is enabled by default
rawtxfund = self.nodes[2].fundrawtransaction(rawtx) rawtxfund = self.nodes[2].fundrawtransaction(rawtx)
@ -363,8 +363,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
# Should fail without add_inputs: # Should fail without add_inputs:
assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, add_inputs=True)
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0 totalOut = 0
@ -397,8 +397,8 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_equal(utx['txid'], dec_tx['vin'][0]['txid']) assert_equal(utx['txid'], dec_tx['vin'][0]['txid'])
# Should fail without add_inputs: # Should fail without add_inputs:
assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, {"add_inputs": False}) assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, self.nodes[2].fundrawtransaction, rawtx, add_inputs=False)
rawtxfund = self.nodes[2].fundrawtransaction(rawtx, {"add_inputs": True}) rawtxfund = self.nodes[2].fundrawtransaction(rawtx, add_inputs=True)
dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex']) dec_tx = self.nodes[2].decoderawtransaction(rawtxfund['hex'])
totalOut = 0 totalOut = 0
@ -567,7 +567,7 @@ class RawTransactionsTest(BitcoinTestFramework):
oldBalance = self.nodes[1].getbalance() oldBalance = self.nodes[1].getbalance()
inputs = [] inputs = []
outputs = {self.nodes[1].getnewaddress():1.1} outputs = {self.nodes[1].getnewaddress():1.1}
funded_psbt = wmulti.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, options={'changeAddress': w2.getrawchangeaddress()})['psbt'] funded_psbt = wmulti.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, changeAddress=w2.getrawchangeaddress())['psbt']
signed_psbt = w2.walletprocesspsbt(funded_psbt) signed_psbt = w2.walletprocesspsbt(funded_psbt)
final_psbt = w2.finalizepsbt(signed_psbt['psbt']) final_psbt = w2.finalizepsbt(signed_psbt['psbt'])
@ -750,7 +750,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[3].loadwallet('wwatch') self.nodes[3].loadwallet('wwatch')
wwatch = self.nodes[3].get_wallet_rpc('wwatch') wwatch = self.nodes[3].get_wallet_rpc('wwatch')
w3 = self.nodes[3].get_wallet_rpc(self.default_wallet_name) w3 = self.nodes[3].get_wallet_rpc(self.default_wallet_name)
result = wwatch.fundrawtransaction(rawtx, {'includeWatching': True, 'changeAddress': w3.getrawchangeaddress(), 'subtractFeeFromOutputs': [0]}) result = wwatch.fundrawtransaction(rawtx, includeWatching=True, changeAddress=w3.getrawchangeaddress(), subtractFeeFromOutputs=[0])
res_dec = self.nodes[0].decoderawtransaction(result["hex"]) res_dec = self.nodes[0].decoderawtransaction(result["hex"])
assert_equal(len(res_dec["vin"]), 1) assert_equal(len(res_dec["vin"]), 1)
assert res_dec["vin"][0]["txid"] == self.watchonly_txid assert res_dec["vin"][0]["txid"] == self.watchonly_txid
@ -779,10 +779,10 @@ class RawTransactionsTest(BitcoinTestFramework):
result = node.fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee) result = node.fundrawtransaction(rawtx) # uses self.min_relay_tx_fee (set by settxfee)
btc_kvb_to_sat_vb = 100000 # (1e5) btc_kvb_to_sat_vb = 100000 # (1e5)
result1 = node.fundrawtransaction(rawtx, {"fee_rate": str(2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee)}) result1 = node.fundrawtransaction(rawtx, fee_rate=str(2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee))
result2 = node.fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee}) result2 = node.fundrawtransaction(rawtx, feeRate=2 * self.min_relay_tx_fee)
result3 = node.fundrawtransaction(rawtx, {"fee_rate": 10 * btc_kvb_to_sat_vb * self.min_relay_tx_fee}) result3 = node.fundrawtransaction(rawtx, fee_rate=10 * btc_kvb_to_sat_vb * self.min_relay_tx_fee)
result4 = node.fundrawtransaction(rawtx, {"feeRate": str(10 * self.min_relay_tx_fee)}) result4 = node.fundrawtransaction(rawtx, feeRate=str(10 * self.min_relay_tx_fee))
result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex']) result_fee_rate = result['fee'] * 1000 / count_bytes(result['hex'])
assert_fee_amount(result1['fee'], count_bytes(result1['hex']), 2 * result_fee_rate) assert_fee_amount(result1['fee'], count_bytes(result1['hex']), 2 * result_fee_rate)
@ -797,54 +797,54 @@ class RawTransactionsTest(BitcoinTestFramework):
# With no arguments passed, expect fee of 141 satoshis. # With no arguments passed, expect fee of 141 satoshis.
assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001) assert_approx(node.fundrawtransaction(rawtx)["fee"], vexp=0.00000141, vspan=0.00000001)
# Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified. # Expect fee to be 10,000x higher when an explicit fee rate 10,000x greater is specified.
result = node.fundrawtransaction(rawtx, {"fee_rate": 10000}) result = node.fundrawtransaction(rawtx, fee_rate=10000)
assert_approx(result["fee"], vexp=0.0141, vspan=0.0001) assert_approx(result["fee"], vexp=0.0141, vspan=0.0001)
self.log.info("Test fundrawtxn with invalid estimate_mode settings") self.log.info("Test fundrawtxn with invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string", assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string",
node.fundrawtransaction, rawtx, {"estimate_mode": v, "conf_target": 0.1, "add_inputs": True}) node.fundrawtransaction, rawtx, estimate_mode=v, conf_target=0.1, add_inputs=True)
for mode in ["", "foo", Decimal("3.141592")]: for mode in ["", "foo", Decimal("3.141592")]:
assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"',
node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": 0.1, "add_inputs": True}) node.fundrawtransaction, rawtx, estimate_mode=mode, conf_target=0.1, add_inputs=True)
self.log.info("Test fundrawtxn with invalid conf_target settings") self.log.info("Test fundrawtxn with invalid conf_target settings")
for mode in ["unset", "economical", "conservative"]: for mode in ["unset", "economical", "conservative"]:
self.log.debug("{}".format(mode)) self.log.debug("{}".format(mode))
for k, v in {"string": "", "object": {"foo": "bar"}}.items(): for k, v in {"string": "", "object": {"foo": "bar"}}.items():
assert_raises_rpc_error(-3, f"JSON value of type {k} for field conf_target is not of expected type number", assert_raises_rpc_error(-3, f"JSON value of type {k} for field conf_target is not of expected type number",
node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": v, "add_inputs": True}) node.fundrawtransaction, rawtx, estimate_mode=mode, conf_target=v, add_inputs=True)
for n in [-1, 0, 1009]: for n in [-1, 0, 1009]:
assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees.h
node.fundrawtransaction, rawtx, {"estimate_mode": mode, "conf_target": n, "add_inputs": True}) node.fundrawtransaction, rawtx, estimate_mode=mode, conf_target=n, add_inputs=True)
self.log.info("Test invalid fee rate settings") self.log.info("Test invalid fee rate settings")
for param, value in {("fee_rate", 100000), ("feeRate", 1.000)}: for param, value in {("fee_rate", 100000), ("feeRate", 1.000)}:
assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)", assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
node.fundrawtransaction, rawtx, {param: value, "add_inputs": True}) node.fundrawtransaction, rawtx, add_inputs=True, **{param: value})
assert_raises_rpc_error(-3, "Amount out of range", assert_raises_rpc_error(-3, "Amount out of range",
node.fundrawtransaction, rawtx, {param: -1, "add_inputs": True}) node.fundrawtransaction, rawtx, add_inputs=True, **{param: -1})
assert_raises_rpc_error(-3, "Amount is not a number or string", assert_raises_rpc_error(-3, "Amount is not a number or string",
node.fundrawtransaction, rawtx, {param: {"foo": "bar"}, "add_inputs": True}) node.fundrawtransaction, rawtx, add_inputs=True, **{param: {"foo": "bar"}})
# Test fee rate values that don't pass fixed-point parsing checks. # 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 ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]:
assert_raises_rpc_error(-3, "Invalid amount", node.fundrawtransaction, rawtx, {param: invalid_value, "add_inputs": True}) assert_raises_rpc_error(-3, "Invalid amount", node.fundrawtransaction, rawtx, add_inputs=True, **{param: invalid_value})
# Test fee_rate values that cannot be represented in sat/vB. # Test fee_rate values that cannot be represented in sat/vB.
for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]: for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999, "0.0001", "0.00000001", "0.00099999", "31.99999999"]:
assert_raises_rpc_error(-3, "Invalid amount", assert_raises_rpc_error(-3, "Invalid amount",
node.fundrawtransaction, rawtx, {"fee_rate": invalid_value, "add_inputs": True}) node.fundrawtransaction, rawtx, fee_rate=invalid_value, add_inputs=True)
self.log.info("Test min fee rate checks are bypassed with fundrawtxn, e.g. a fee_rate under 1 sat/vB is allowed") self.log.info("Test min fee rate checks are bypassed with fundrawtxn, e.g. a fee_rate under 1 sat/vB is allowed")
node.fundrawtransaction(rawtx, {"fee_rate": 0.999, "add_inputs": True}) node.fundrawtransaction(rawtx, fee_rate=0.999, add_inputs=True)
node.fundrawtransaction(rawtx, {"feeRate": 0.00000999, "add_inputs": True}) node.fundrawtransaction(rawtx, feeRate=0.00000999, add_inputs=True)
self.log.info("- raises RPC error if both feeRate and fee_rate are passed") 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)", assert_raises_rpc_error(-8, "Cannot specify both fee_rate (sat/vB) and feeRate (BTC/kvB)",
node.fundrawtransaction, rawtx, {"fee_rate": 0.1, "feeRate": 0.1, "add_inputs": True}) node.fundrawtransaction, rawtx, fee_rate=0.1, feeRate=0.1, add_inputs=True)
self.log.info("- raises RPC error if both feeRate and estimate_mode passed") 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", assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and feeRate",
node.fundrawtransaction, rawtx, {"estimate_mode": "economical", "feeRate": 0.1, "add_inputs": True}) node.fundrawtransaction, rawtx, estimate_mode="economical", feeRate=0.1, add_inputs=True)
for param in ["feeRate", "fee_rate"]: for param in ["feeRate", "fee_rate"]:
self.log.info("- raises RPC error if both {} and conf_target are passed".format(param)) self.log.info("- raises RPC error if both {} and conf_target are passed".format(param))
@ -854,7 +854,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.log.info("- raises RPC error if both fee_rate and estimate_mode are passed") self.log.info("- raises RPC error if both fee_rate and estimate_mode are passed")
assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and fee_rate", assert_raises_rpc_error(-8, "Cannot specify both estimate_mode and fee_rate",
node.fundrawtransaction, rawtx, {"fee_rate": 1, "estimate_mode": "economical", "add_inputs": True}) node.fundrawtransaction, rawtx, fee_rate=1, estimate_mode="economical", add_inputs=True)
def test_address_reuse(self): def test_address_reuse(self):
"""Test no address reuse occurs.""" """Test no address reuse occurs."""
@ -884,10 +884,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# Test subtract fee from outputs with feeRate (BTC/kvB) # Test subtract fee from outputs with feeRate (BTC/kvB)
result = [self.nodes[3].fundrawtransaction(rawtx), # uses self.min_relay_tx_fee (set by settxfee) result = [self.nodes[3].fundrawtransaction(rawtx), # uses self.min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[]), # empty subtraction list
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses self.min_relay_tx_fee (set by settxfee) self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0]), # uses self.min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee}), self.nodes[3].fundrawtransaction(rawtx, feeRate=2 * self.min_relay_tx_fee),
self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2 * self.min_relay_tx_fee, "subtractFeeFromOutputs": [0]}),] self.nodes[3].fundrawtransaction(rawtx, feeRate=2 * self.min_relay_tx_fee, subtractFeeFromOutputs=[0]),]
dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result] dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result]
output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)] output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]
change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)] change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]
@ -904,10 +904,10 @@ class RawTransactionsTest(BitcoinTestFramework):
# Test subtract fee from outputs with fee_rate (sat/vB) # Test subtract fee from outputs with fee_rate (sat/vB)
btc_kvb_to_sat_vb = 100000 # (1e5) btc_kvb_to_sat_vb = 100000 # (1e5)
result = [self.nodes[3].fundrawtransaction(rawtx), # uses self.min_relay_tx_fee (set by settxfee) result = [self.nodes[3].fundrawtransaction(rawtx), # uses self.min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": []}), # empty subtraction list self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[]), # empty subtraction list
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0]}), # uses self.min_relay_tx_fee (set by settxfee) self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0]), # uses self.min_relay_tx_fee (set by settxfee)
self.nodes[3].fundrawtransaction(rawtx, {"fee_rate": 2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee}), self.nodes[3].fundrawtransaction(rawtx, fee_rate=2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee),
self.nodes[3].fundrawtransaction(rawtx, {"fee_rate": 2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee, "subtractFeeFromOutputs": [0]}),] self.nodes[3].fundrawtransaction(rawtx, fee_rate=2 * btc_kvb_to_sat_vb * self.min_relay_tx_fee, subtractFeeFromOutputs=[0]),]
dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result] dec_tx = [self.nodes[3].decoderawtransaction(tx_['hex']) for tx_ in result]
output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)] output = [d['vout'][1 - r['changepos']]['value'] for d, r in zip(dec_tx, result)]
change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)] change = [d['vout'][r['changepos']]['value'] for d, r in zip(dec_tx, result)]
@ -927,7 +927,7 @@ class RawTransactionsTest(BitcoinTestFramework):
result = [self.nodes[3].fundrawtransaction(rawtx), result = [self.nodes[3].fundrawtransaction(rawtx),
# Split the fee between outputs 0, 2, and 3, but not output 1. # Split the fee between outputs 0, 2, and 3, but not output 1.
self.nodes[3].fundrawtransaction(rawtx, {"subtractFeeFromOutputs": [0, 2, 3]})] self.nodes[3].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0, 2, 3])]
dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']), dec_tx = [self.nodes[3].decoderawtransaction(result[0]['hex']),
self.nodes[3].decoderawtransaction(result[1]['hex'])] self.nodes[3].decoderawtransaction(result[1]['hex'])]
@ -969,7 +969,7 @@ class RawTransactionsTest(BitcoinTestFramework):
vout = find_vout_for_address(self.nodes[0], txid, addr) vout = find_vout_for_address(self.nodes[0], txid, addr)
rawtx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(): 5}]) rawtx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(): 5}])
fundedtx = self.nodes[0].fundrawtransaction(rawtx, {'subtractFeeFromOutputs': [0]}) fundedtx = self.nodes[0].fundrawtransaction(rawtx, subtractFeeFromOutputs=[0])
signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx['hex']) signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx['hex'])
self.nodes[0].sendrawtransaction(signedtx['hex']) self.nodes[0].sendrawtransaction(signedtx['hex'])
@ -1027,25 +1027,25 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"]), wallet.fundrawtransaction, raw_tx) assert_raises_rpc_error(-4, "Not solvable pre-selected input COutPoint(%s, %s)" % (ext_utxo["txid"][0:10], ext_utxo["vout"]), wallet.fundrawtransaction, raw_tx)
# Error conditions # Error conditions
assert_raises_rpc_error(-5, "'not a pubkey' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["not a pubkey"]}}) assert_raises_rpc_error(-5, "'not a pubkey' is not hex", wallet.fundrawtransaction, raw_tx, solving_data={"pubkeys":["not a pubkey"]})
assert_raises_rpc_error(-5, "'01234567890a0b0c0d0e0f' is not a valid public key", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["01234567890a0b0c0d0e0f"]}}) assert_raises_rpc_error(-5, "'01234567890a0b0c0d0e0f' is not a valid public key", wallet.fundrawtransaction, raw_tx, solving_data={"pubkeys":["01234567890a0b0c0d0e0f"]})
assert_raises_rpc_error(-5, "'not a script' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"scripts":["not a script"]}}) assert_raises_rpc_error(-5, "'not a script' is not hex", wallet.fundrawtransaction, raw_tx, solving_data={"scripts":["not a script"]})
assert_raises_rpc_error(-8, "Unable to parse descriptor 'not a descriptor'", wallet.fundrawtransaction, raw_tx, {"solving_data": {"descriptors":["not a descriptor"]}}) assert_raises_rpc_error(-8, "Unable to parse descriptor 'not a descriptor'", wallet.fundrawtransaction, raw_tx, solving_data={"descriptors":["not a descriptor"]})
assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"]}]}) assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"]}])
assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": -1}]}) assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": -1}])
assert_raises_rpc_error(-8, "Invalid parameter, missing weight key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"]}]}) assert_raises_rpc_error(-8, "Invalid parameter, missing weight key", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"]}])
assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 164}]}) assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 164}])
assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": -1}]}) assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": -1}])
assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be greater than", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 400001}]}) assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be greater than", wallet.fundrawtransaction, raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 400001}])
# But funding should work when the solving data is provided # But funding should work when the solving data is provided
funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}}) funded_tx = wallet.fundrawtransaction(raw_tx, solving_data={"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]})
signed_tx = wallet.signrawtransactionwithwallet(funded_tx['hex']) signed_tx = wallet.signrawtransactionwithwallet(funded_tx['hex'])
assert not signed_tx['complete'] assert not signed_tx['complete']
signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx['hex']) signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx['hex'])
assert signed_tx['complete'] assert signed_tx['complete']
funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}}) funded_tx = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]})
signed_tx1 = wallet.signrawtransactionwithwallet(funded_tx['hex']) signed_tx1 = wallet.signrawtransactionwithwallet(funded_tx['hex'])
assert not signed_tx1['complete'] assert not signed_tx1['complete']
signed_tx2 = self.nodes[0].signrawtransactionwithwallet(signed_tx1['hex']) signed_tx2 = self.nodes[0].signrawtransactionwithwallet(signed_tx1['hex'])
@ -1060,30 +1060,30 @@ class RawTransactionsTest(BitcoinTestFramework):
high_input_weight = input_weight * 2 high_input_weight = input_weight * 2
# Funding should also work if the input weight is provided # Funding should also work if the input weight is provided
funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}]}) funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}])
signed_tx = wallet.signrawtransactionwithwallet(funded_tx["hex"]) signed_tx = wallet.signrawtransactionwithwallet(funded_tx["hex"])
signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx["hex"]) signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx["hex"])
assert_equal(self.nodes[0].testmempoolaccept([signed_tx["hex"]])[0]["allowed"], True) assert_equal(self.nodes[0].testmempoolaccept([signed_tx["hex"]])[0]["allowed"], True)
assert_equal(signed_tx["complete"], True) assert_equal(signed_tx["complete"], True)
# Reducing the weight should have a lower fee # Reducing the weight should have a lower fee
funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}]}) funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}])
assert_greater_than(funded_tx["fee"], funded_tx2["fee"]) assert_greater_than(funded_tx["fee"], funded_tx2["fee"])
# Increasing the weight should have a higher fee # Increasing the weight should have a higher fee
funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]}) funded_tx2 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}])
assert_greater_than(funded_tx2["fee"], funded_tx["fee"]) assert_greater_than(funded_tx2["fee"], funded_tx["fee"])
# The provided weight should override the calculated weight when solving data is provided # The provided weight should override the calculated weight when solving data is provided
funded_tx3 = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}, "input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]}) funded_tx3 = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]}, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}])
assert_equal(funded_tx2["fee"], funded_tx3["fee"]) assert_equal(funded_tx2["fee"], funded_tx3["fee"])
# The feerate should be met # The feerate should be met
funded_tx4 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], "fee_rate": 10}) funded_tx4 = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], fee_rate=10)
input_add_weight = high_input_weight - (41 * 4) input_add_weight = high_input_weight - (41 * 4)
tx4_weight = wallet.decoderawtransaction(funded_tx4["hex"])["weight"] + input_add_weight tx4_weight = wallet.decoderawtransaction(funded_tx4["hex"])["weight"] + input_add_weight
tx4_vsize = int(ceil(tx4_weight / 4)) tx4_vsize = int(ceil(tx4_weight / 4))
assert_fee_amount(funded_tx4["fee"], tx4_vsize, Decimal(0.0001)) assert_fee_amount(funded_tx4["fee"], tx4_vsize, Decimal(0.0001))
# Funding with weight at csuint boundaries should not cause problems # Funding with weight at csuint boundaries should not cause problems
funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}]}) funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}])
funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}]}) funded_tx = wallet.fundrawtransaction(raw_tx, input_weights=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}])
self.nodes[2].unloadwallet("extfund") self.nodes[2].unloadwallet("extfund")
@ -1123,7 +1123,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Fund wallet with 2 outputs, 5 BTC each. # Fund wallet with 2 outputs, 5 BTC each.
addr2 = wallet.getnewaddress(address_type="bech32") addr2 = wallet.getnewaddress(address_type="bech32")
source_tx = self.nodes[0].send(outputs=[{addr1: 5}, {addr2: 5}], options={"change_position": 0}) source_tx = self.nodes[0].send(outputs=[{addr1: 5}, {addr2: 5}], change_position=0)
self.generate(self.nodes[0], 1) self.generate(self.nodes[0], 1)
# Select only one input. # Select only one input.
@ -1135,12 +1135,12 @@ class RawTransactionsTest(BitcoinTestFramework):
} }
] ]
} }
assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 8}], options=options) assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 8}], **options)
# Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount) # Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
options["add_inputs"] = True options["add_inputs"] = True
options["add_to_wallet"] = False options["add_to_wallet"] = False
tx = wallet.send(outputs=[{addr1: 8}], options=options) tx = wallet.send(outputs=[{addr1: 8}], **options)
assert tx["complete"] assert tx["complete"]
# Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount) # Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount)
@ -1148,7 +1148,7 @@ class RawTransactionsTest(BitcoinTestFramework):
"txid": source_tx["txid"], "txid": source_tx["txid"],
"vout": 2 # change position was hardcoded to index 0 "vout": 2 # change position was hardcoded to index 0
}) })
tx = wallet.send(outputs=[{addr1: 8}], options=options) tx = wallet.send(outputs=[{addr1: 8}], **options)
assert tx["complete"] assert tx["complete"]
# Check that only the preset inputs were added to the tx # Check that only the preset inputs were added to the tx
decoded_psbt_inputs = self.nodes[0].decodepsbt(tx["psbt"])['tx']['vin'] decoded_psbt_inputs = self.nodes[0].decodepsbt(tx["psbt"])['tx']['vin']
@ -1158,12 +1158,12 @@ class RawTransactionsTest(BitcoinTestFramework):
# Case (5), assert that inputs are added to the tx by explicitly setting add_inputs=true # Case (5), assert that inputs are added to the tx by explicitly setting add_inputs=true
options = {"add_inputs": True, "add_to_wallet": True} options = {"add_inputs": True, "add_to_wallet": True}
tx = wallet.send(outputs=[{addr1: 8}], options=options) tx = wallet.send(outputs=[{addr1: 8}], **options)
assert tx["complete"] assert tx["complete"]
# 6. Explicit add_inputs=false, no preset inputs: # 6. Explicit add_inputs=false, no preset inputs:
options = {"add_inputs": False} options = {"add_inputs": False}
assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 3}], options=options) assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.send, outputs=[{addr1: 3}], **options)
################################################ ################################################
@ -1184,14 +1184,14 @@ class RawTransactionsTest(BitcoinTestFramework):
# Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount) # Case (3), Explicit add_inputs=true and preset inputs (with preset inputs not-covering the target amount)
options["add_inputs"] = True options["add_inputs"] = True
assert "psbt" in wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, options=options) assert "psbt" in wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, **options)
# Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount) # Case (4), Explicit add_inputs=true and preset inputs (with preset inputs covering the target amount)
inputs.append({ inputs.append({
"txid": source_tx["txid"], "txid": source_tx["txid"],
"vout": 2 # change position was hardcoded to index 0 "vout": 2 # change position was hardcoded to index 0
}) })
psbt_tx = wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, options=options) psbt_tx = wallet.walletcreatefundedpsbt(outputs=[{addr1: 8}], inputs=inputs, **options)
# Check that only the preset inputs were added to the tx # Check that only the preset inputs were added to the tx
decoded_psbt_inputs = self.nodes[0].decodepsbt(psbt_tx["psbt"])['tx']['vin'] decoded_psbt_inputs = self.nodes[0].decodepsbt(psbt_tx["psbt"])['tx']['vin']
assert_equal(len(decoded_psbt_inputs), 2) assert_equal(len(decoded_psbt_inputs), 2)
@ -1203,11 +1203,11 @@ class RawTransactionsTest(BitcoinTestFramework):
options = { options = {
"add_inputs": True "add_inputs": True
} }
assert "psbt" in wallet.walletcreatefundedpsbt(inputs=[], outputs=outputs, options=options) assert "psbt" in wallet.walletcreatefundedpsbt(inputs=[], outputs=outputs, **options)
# Case (6). Explicit add_inputs=false, no preset inputs: # Case (6). Explicit add_inputs=false, no preset inputs:
options = {"add_inputs": False} options = {"add_inputs": False}
assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=[], outputs=outputs, options=options) assert_raises_rpc_error(-4, ERR_NOT_ENOUGH_PRESET_INPUTS, wallet.walletcreatefundedpsbt, inputs=[], outputs=outputs, **options)
self.nodes[2].unloadwallet("test_preset_inputs") self.nodes[2].unloadwallet("test_preset_inputs")
@ -1271,7 +1271,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.generate(self.nodes[0], 1) self.generate(self.nodes[0], 1)
rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(address_type="bech32"): 8}]) rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(address_type="bech32"): 8}])
fundedtx = wallet.fundrawtransaction(rawtx, {'fee_rate': 10, "change_type": "bech32"}) fundedtx = wallet.fundrawtransaction(rawtx, fee_rate=10, change_type="bech32")
# with 71-byte signatures we should expect following tx size # with 71-byte signatures we should expect following tx size
# tx overhead (10) + 2 inputs (41 each) + 2 p2wpkh (31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 byte sig witnesses (107 each)) / witness scaling factor (4) # tx overhead (10) + 2 inputs (41 each) + 2 p2wpkh (31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 byte sig witnesses (107 each)) / witness scaling factor (4)
tx_size = ceil(10 + 41*2 + 31*2 + (2 + 107*2)/4) tx_size = ceil(10 + 41*2 + 31*2 + (2 + 107*2)/4)
@ -1280,7 +1280,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Using the other output should have 72 byte sigs # Using the other output should have 72 byte sigs
rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': ext_vout}], [{self.nodes[0].getnewaddress(): 13}]) rawtx = wallet.createrawtransaction([{'txid': txid, 'vout': ext_vout}], [{self.nodes[0].getnewaddress(): 13}])
ext_desc = self.nodes[0].getaddressinfo(ext_addr)["desc"] ext_desc = self.nodes[0].getaddressinfo(ext_addr)["desc"]
fundedtx = wallet.fundrawtransaction(rawtx, {'fee_rate': 10, "change_type": "bech32", "solving_data": {"descriptors": [ext_desc]}}) fundedtx = wallet.fundrawtransaction(rawtx, fee_rate=10, change_type="bech32", solving_data={"descriptors": [ext_desc]})
# tx overhead (10) + 3 inputs (41 each) + 2 p2wpkh(31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 bytes sig witnesses (107 each) + p2wpkh 72 byte sig witness (108)) / witness scaling factor (4) # tx overhead (10) + 3 inputs (41 each) + 2 p2wpkh(31 each) + (segwit marker and flag (2) + 2 p2wpkh 71 bytes sig witnesses (107 each) + p2wpkh 72 byte sig witness (108)) / witness scaling factor (4)
tx_size = ceil(10 + 41*3 + 31*2 + (2 + 107*2 + 108)/4) tx_size = ceil(10 + 41*3 + 31*2 + (2 + 107*2 + 108)/4)
assert_equal(fundedtx['fee'] * COIN, tx_size * 10) assert_equal(fundedtx['fee'] * COIN, tx_size * 10)
@ -1307,7 +1307,7 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, rawtx) assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, rawtx)
# But we can opt-in to use them for funding. # But we can opt-in to use them for funding.
fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": True}) fundedtx = wallet.fundrawtransaction(rawtx, include_unsafe=True)
tx_dec = wallet.decoderawtransaction(fundedtx['hex']) tx_dec = wallet.decoderawtransaction(fundedtx['hex'])
assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"]) assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"])
signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex']) signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex'])
@ -1315,7 +1315,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# And we can also use them once they're confirmed. # And we can also use them once they're confirmed.
self.generate(self.nodes[0], 1) self.generate(self.nodes[0], 1)
fundedtx = wallet.fundrawtransaction(rawtx, {"include_unsafe": False}) fundedtx = wallet.fundrawtransaction(rawtx, include_unsafe=False)
tx_dec = wallet.decoderawtransaction(fundedtx['hex']) tx_dec = wallet.decoderawtransaction(fundedtx['hex'])
assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"]) assert all((txin["txid"], txin["vout"]) in inputs for txin in tx_dec["vin"])
signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex']) signedtx = wallet.signrawtransactionwithwallet(fundedtx['hex'])
@ -1350,7 +1350,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# Create transactions in order to calculate fees for the target bounds that can trigger this bug # Create transactions in order to calculate fees for the target bounds that can trigger this bug
change_tx = tester.fundrawtransaction(tester.createrawtransaction([], [{funds.getnewaddress(): 1.5}])) change_tx = tester.fundrawtransaction(tester.createrawtransaction([], [{funds.getnewaddress(): 1.5}]))
tx = tester.createrawtransaction([], [{funds.getnewaddress(): 2}]) tx = tester.createrawtransaction([], [{funds.getnewaddress(): 2}])
no_change_tx = tester.fundrawtransaction(tx, {"subtractFeeFromOutputs": [0]}) no_change_tx = tester.fundrawtransaction(tx, subtractFeeFromOutputs=[0])
overhead_fees = feerate * len(tx) / 2 / 1000 overhead_fees = feerate * len(tx) / 2 / 1000
cost_of_change = change_tx["fee"] - no_change_tx["fee"] cost_of_change = change_tx["fee"] - no_change_tx["fee"]
@ -1402,7 +1402,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# To test this does not happen, we subtract 202 sats from the input value. If working correctly, this should # To test this does not happen, we subtract 202 sats from the input value. If working correctly, this should
# fail with insufficient funds rather than bitcoind asserting. # fail with insufficient funds rather than bitcoind asserting.
rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}]) rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}])
assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, {"fee_rate": 1.85}) assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, fee_rate=1.85)
def test_input_confs_control(self): def test_input_confs_control(self):
self.nodes[0].createwallet("minconf") self.nodes[0].createwallet("minconf")

View file

@ -75,7 +75,7 @@ class Variant(collections.namedtuple("Variant", "call data address_type rescan p
request.update({"redeemscript": self.address['embedded']['scriptPubKey']}) request.update({"redeemscript": self.address['embedded']['scriptPubKey']})
response = self.node.importmulti( response = self.node.importmulti(
requests=[request], requests=[request],
options={"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)}, rescan=self.rescan in (Rescan.yes, Rescan.late_timestamp),
) )
assert_equal(response, [{"success": True}]) assert_equal(response, [{"success": True}])

View file

@ -178,30 +178,30 @@ class KeyPoolTest(BitcoinTestFramework):
# Using a fee rate (10 sat / byte) well above the minimum relay rate # Using a fee rate (10 sat / byte) well above the minimum relay rate
# creating a 5,000 sat transaction with change should not be possible # creating a 5,000 sat transaction with change should not be possible
assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", w2.walletcreatefundedpsbt, inputs=[], outputs=[{addr.pop(): 0.00005000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010}) assert_raises_rpc_error(-4, "Transaction needs a change address, but we can't generate it.", w2.walletcreatefundedpsbt, inputs=[], outputs=[{addr.pop(): 0.00005000}], subtractFeeFromOutputs=[0], feeRate=0.00010)
# creating a 10,000 sat transaction without change, with a manual input, should still be possible # creating a 10,000 sat transaction without change, with a manual input, should still be possible
res = w2.walletcreatefundedpsbt(inputs=w2.listunspent(), outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010}) res = w2.walletcreatefundedpsbt(inputs=w2.listunspent(), outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.00010)
assert_equal("psbt" in res, True) assert_equal("psbt" in res, True)
# creating a 10,000 sat transaction without change should still be possible # creating a 10,000 sat transaction without change should still be possible
res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010}) res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.00010)
assert_equal("psbt" in res, True) assert_equal("psbt" in res, True)
# should work without subtractFeeFromOutputs if the exact fee is subtracted from the amount # should work without subtractFeeFromOutputs if the exact fee is subtracted from the amount
res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008900}], options={"feeRate": 0.00010}) res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008900}], feeRate=0.00010)
assert_equal("psbt" in res, True) assert_equal("psbt" in res, True)
# dust change should be removed # dust change should be removed
res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008800}], options={"feeRate": 0.00010}) res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00008800}], feeRate=0.00010)
assert_equal("psbt" in res, True) assert_equal("psbt" in res, True)
# create a transaction without change at the maximum fee rate, such that the output is still spendable: # create a transaction without change at the maximum fee rate, such that the output is still spendable:
res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.0008823}) res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.0008823)
assert_equal("psbt" in res, True) assert_equal("psbt" in res, True)
assert_equal(res["fee"], Decimal("0.00009706")) assert_equal(res["fee"], Decimal("0.00009706"))
# creating a 10,000 sat transaction with a manual change address should be possible # creating a 10,000 sat transaction with a manual change address should be possible
res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], options={"subtractFeeFromOutputs": [0], "feeRate": 0.00010, "changeAddress": addr.pop()}) res = w2.walletcreatefundedpsbt(inputs=[], outputs=[{destination: 0.00010000}], subtractFeeFromOutputs=[0], feeRate=0.00010, changeAddress=addr.pop())
assert_equal("psbt" in res, True) assert_equal("psbt" in res, True)
if not self.options.descriptors: if not self.options.descriptors:

View file

@ -281,7 +281,7 @@ class WalletMigrationTest(BitcoinTestFramework):
imports0.importaddress(import_sent_addr) imports0.importaddress(import_sent_addr)
received_sent_watchonly_txid = default.sendtoaddress(import_sent_addr, 10) received_sent_watchonly_txid = default.sendtoaddress(import_sent_addr, 10)
received_sent_watchonly_vout = find_vout_for_address(self.nodes[0], received_sent_watchonly_txid, import_sent_addr) received_sent_watchonly_vout = find_vout_for_address(self.nodes[0], received_sent_watchonly_txid, import_sent_addr)
send = default.sendall(recipients=[default.getnewaddress()], options={"inputs": [{"txid": received_sent_watchonly_txid, "vout": received_sent_watchonly_vout}]}) send = default.sendall(recipients=[default.getnewaddress()], inputs=[{"txid": received_sent_watchonly_txid, "vout": received_sent_watchonly_vout}])
sent_watchonly_txid = send["txid"] sent_watchonly_txid = send["txid"]
self.generate(self.nodes[0], 1) self.generate(self.nodes[0], 1)

View file

@ -121,7 +121,7 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
to = participants["signers"][self.N - 1].getnewaddress() to = participants["signers"][self.N - 1].getnewaddress()
value = 1 value = 1
self.log.info("First, make a sending transaction, created using `walletcreatefundedpsbt` (anyone can initiate this)...") self.log.info("First, make a sending transaction, created using `walletcreatefundedpsbt` (anyone can initiate this)...")
psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, options={"feeRate": 0.00010}) psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, feeRate=0.00010)
psbts = [] psbts = []
self.log.info("Now at least M users check the psbt with decodepsbt and (if OK) signs it with walletprocesspsbt...") self.log.info("Now at least M users check the psbt with decodepsbt and (if OK) signs it with walletprocesspsbt...")
@ -143,7 +143,7 @@ class WalletMultisigDescriptorPSBTTest(BitcoinTestFramework):
assert_equal(participants["signers"][self.N - 1].getbalance(), value) assert_equal(participants["signers"][self.N - 1].getbalance(), value)
self.log.info("Send another transaction from the multisig, this time with a daisy chained signing flow (one after another in series)!") self.log.info("Send another transaction from the multisig, this time with a daisy chained signing flow (one after another in series)!")
psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, options={"feeRate": 0.00010}) psbt = participants["multisigs"][0].walletcreatefundedpsbt(inputs=[], outputs={to: value}, feeRate=0.00010)
for m in range(self.M): for m in range(self.M):
signers_multisig = participants["multisigs"][m] signers_multisig = participants["multisigs"][m]
self._check_psbt(psbt["psbt"], to, value, signers_multisig) self._check_psbt(psbt["psbt"], to, value, signers_multisig)

View file

@ -35,7 +35,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
self.log.info("Create a new transaction and wait until it's broadcast") self.log.info("Create a new transaction and wait until it's broadcast")
parent_utxo, indep_utxo = node.listunspent()[:2] parent_utxo, indep_utxo = node.listunspent()[:2]
addr = node.getnewaddress() addr = node.getnewaddress()
txid = node.send(outputs=[{addr: 1}], options={"inputs": [parent_utxo]})["txid"] txid = node.send(outputs=[{addr: 1}], inputs=[parent_utxo])["txid"]
# Can take a few seconds due to transaction trickling # Can take a few seconds due to transaction trickling
peer_first.wait_for_broadcast([txid]) peer_first.wait_for_broadcast([txid])
@ -86,7 +86,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
# ordering of mapWallet is, if the child is not before the parent, we will create a new # ordering of mapWallet is, if the child is not before the parent, we will create a new
# child (via bumpfee) and remove the old child (via removeprunedfunds) until we get the # child (via bumpfee) and remove the old child (via removeprunedfunds) until we get the
# ordering of child before parent. # ordering of child before parent.
child_txid = node.send(outputs=[{addr: 0.5}], options={"inputs": [{"txid":txid, "vout":0}]})["txid"] child_txid = node.send(outputs=[{addr: 0.5}], inputs=[{"txid":txid, "vout":0}])["txid"]
while True: while True:
txids = node.listreceivedbyaddress(minconf=0, address_filter=addr)[0]["txids"] txids = node.listreceivedbyaddress(minconf=0, address_filter=addr)[0]["txids"]
if txids == [child_txid, txid]: if txids == [child_txid, txid]:
@ -111,7 +111,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework):
# Evict these txs from the mempool # Evict these txs from the mempool
evict_time = block_time + 60 * 60 * DEFAULT_MEMPOOL_EXPIRY_HOURS + 5 evict_time = block_time + 60 * 60 * DEFAULT_MEMPOOL_EXPIRY_HOURS + 5
node.setmocktime(evict_time) node.setmocktime(evict_time)
indep_send = node.send(outputs=[{node.getnewaddress(): 1}], options={"inputs": [indep_utxo]}) indep_send = node.send(outputs=[{node.getnewaddress(): 1}], inputs=[indep_utxo])
node.getmempoolentry(indep_send["txid"]) node.getmempoolentry(indep_send["txid"])
assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, txid) assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, txid)
assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, child_txid) assert_raises_rpc_error(-5, "Transaction not in mempool", node.getmempoolentry, child_txid)

View file

@ -151,7 +151,7 @@ class SendallTest(BitcoinTestFramework):
self.log.info("Test sending more than balance") self.log.info("Test sending more than balance")
pre_sendall_balance = self.add_utxos([7, 14]) pre_sendall_balance = self.add_utxos([7, 14])
expected_tx = self.wallet.sendall(recipients=[{self.recipient: 5}, self.remainder_target], options={"add_to_wallet": False}) expected_tx = self.wallet.sendall(recipients=[{self.recipient: 5}, self.remainder_target], add_to_wallet=False)
tx = self.wallet.decoderawtransaction(expected_tx['hex']) tx = self.wallet.decoderawtransaction(expected_tx['hex'])
fee = 21 - sum([o["value"] for o in tx["vout"]]) fee = 21 - sum([o["value"] for o in tx["vout"]])
@ -190,7 +190,7 @@ class SendallTest(BitcoinTestFramework):
self.add_utxos([0.00000400, 0.00000300, 1]) self.add_utxos([0.00000400, 0.00000300, 1])
# sendall with send_max # sendall with send_max
sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, options={"send_max": True}) sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], fee_rate=300, send_max=True)
tx_from_wallet = self.wallet.gettransaction(txid = sendall_tx_receipt["txid"], verbose = True) tx_from_wallet = self.wallet.gettransaction(txid = sendall_tx_receipt["txid"], verbose = True)
assert_equal(len(tx_from_wallet["decoded"]["vin"]), 1) assert_equal(len(tx_from_wallet["decoded"]["vin"]), 1)
@ -206,7 +206,7 @@ class SendallTest(BitcoinTestFramework):
self.add_utxos([17, 4]) self.add_utxos([17, 4])
utxo = self.wallet.listunspent()[0] utxo = self.wallet.listunspent()[0]
sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], options={"inputs": [utxo]}) sendall_tx_receipt = self.wallet.sendall(recipients=[self.remainder_target], inputs=[utxo])
tx_from_wallet = self.wallet.gettransaction(txid = sendall_tx_receipt["txid"], verbose = True) tx_from_wallet = self.wallet.gettransaction(txid = sendall_tx_receipt["txid"], verbose = True)
assert_equal(len(tx_from_wallet["decoded"]["vin"]), 1) assert_equal(len(tx_from_wallet["decoded"]["vin"]), 1)
assert_equal(len(tx_from_wallet["decoded"]["vout"]), 1) assert_equal(len(tx_from_wallet["decoded"]["vout"]), 1)
@ -227,26 +227,26 @@ class SendallTest(BitcoinTestFramework):
# fails on out of bounds vout # fails on out of bounds vout
assert_raises_rpc_error(-8, assert_raises_rpc_error(-8,
"Input not found. UTXO ({}:{}) is not part of wallet.".format(spent_utxo["txid"], 1000), "Input not found. UTXO ({}:{}) is not part of wallet.".format(spent_utxo["txid"], 1000),
self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [{"txid": spent_utxo["txid"], "vout": 1000}]}) self.wallet.sendall, recipients=[self.remainder_target], inputs=[{"txid": spent_utxo["txid"], "vout": 1000}])
# fails on unconfirmed spent UTXO # fails on unconfirmed spent UTXO
self.wallet.sendall(recipients=[self.remainder_target]) self.wallet.sendall(recipients=[self.remainder_target])
assert_raises_rpc_error(-8, assert_raises_rpc_error(-8,
"Input not available. UTXO ({}:{}) was already spent.".format(spent_utxo["txid"], spent_utxo["vout"]), "Input not available. UTXO ({}:{}) was already spent.".format(spent_utxo["txid"], spent_utxo["vout"]),
self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [spent_utxo]}) self.wallet.sendall, recipients=[self.remainder_target], inputs=[spent_utxo])
# fails on specific previously spent UTXO, while other UTXOs exist # fails on specific previously spent UTXO, while other UTXOs exist
self.generate(self.nodes[0], 1) self.generate(self.nodes[0], 1)
self.add_utxos([19, 2]) self.add_utxos([19, 2])
assert_raises_rpc_error(-8, assert_raises_rpc_error(-8,
"Input not available. UTXO ({}:{}) was already spent.".format(spent_utxo["txid"], spent_utxo["vout"]), "Input not available. UTXO ({}:{}) was already spent.".format(spent_utxo["txid"], spent_utxo["vout"]),
self.wallet.sendall, recipients=[self.remainder_target], options={"inputs": [spent_utxo]}) self.wallet.sendall, recipients=[self.remainder_target], inputs=[spent_utxo])
# fails because UTXO is unknown, while other UTXOs exist # fails because UTXO is unknown, while other UTXOs exist
foreign_utxo = self.def_wallet.listunspent()[0] foreign_utxo = self.def_wallet.listunspent()[0]
assert_raises_rpc_error(-8, "Input not found. UTXO ({}:{}) is not part of wallet.".format(foreign_utxo["txid"], assert_raises_rpc_error(-8, "Input not found. UTXO ({}:{}) is not part of wallet.".format(foreign_utxo["txid"],
foreign_utxo["vout"]), self.wallet.sendall, recipients=[self.remainder_target], foreign_utxo["vout"]), self.wallet.sendall, recipients=[self.remainder_target],
options={"inputs": [foreign_utxo]}) inputs=[foreign_utxo])
@cleanup @cleanup
def sendall_fails_on_no_address(self): def sendall_fails_on_no_address(self):
@ -270,7 +270,7 @@ class SendallTest(BitcoinTestFramework):
"Cannot combine send_max with specific inputs.", "Cannot combine send_max with specific inputs.",
self.wallet.sendall, self.wallet.sendall,
recipients=[self.remainder_target], recipients=[self.remainder_target],
options={"inputs": [utxo], "send_max": True}) inputs=[utxo], send_max=True)
@cleanup @cleanup
def sendall_fails_on_high_fee(self): def sendall_fails_on_high_fee(self):
@ -308,7 +308,7 @@ class SendallTest(BitcoinTestFramework):
else: else:
watchonly.importmulti(import_req) watchonly.importmulti(import_req)
sendall_tx_receipt = watchonly.sendall(recipients=[self.remainder_target], options={"inputs": [utxo]}) sendall_tx_receipt = watchonly.sendall(recipients=[self.remainder_target], inputs=[utxo])
psbt = sendall_tx_receipt["psbt"] psbt = sendall_tx_receipt["psbt"]
decoded = self.nodes[0].decodepsbt(psbt) decoded = self.nodes[0].decodepsbt(psbt)
assert_equal(len(decoded["inputs"]), 1) assert_equal(len(decoded["inputs"]), 1)

View file

@ -211,13 +211,13 @@ class WalletSignerTest(BitcoinTestFramework):
self.log.info('Test send using hww1') self.log.info('Test send using hww1')
# Don't broadcast transaction yet so the RPC returns the raw hex # Don't broadcast transaction yet so the RPC returns the raw hex
res = hww.send(outputs={dest:0.5},options={"add_to_wallet": False}) res = hww.send(outputs={dest:0.5},add_to_wallet=False)
assert res["complete"] assert res["complete"]
assert_equal(res["hex"], mock_tx) assert_equal(res["hex"], mock_tx)
self.log.info('Test sendall using hww1') self.log.info('Test sendall using hww1')
res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()],options={"add_to_wallet": False}) res = hww.sendall(recipients=[{dest:0.5}, hww.getrawchangeaddress()], add_to_wallet=False)
assert res["complete"] assert res["complete"]
assert_equal(res["hex"], mock_tx) assert_equal(res["hex"], mock_tx)
# Broadcast transaction so we can bump the fee # Broadcast transaction so we can bump the fee

View file

@ -378,7 +378,7 @@ class WalletTaprootTest(BitcoinTestFramework):
assert psbt_online.gettransaction(txid)['confirmations'] > 0 assert psbt_online.gettransaction(txid)['confirmations'] > 0
# Cleanup # Cleanup
psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], options={"psbt": True})["psbt"] psbt = psbt_online.sendall(recipients=[self.boring.getnewaddress()], psbt=True)["psbt"]
res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False) res = psbt_offline.walletprocesspsbt(psbt=psbt, finalize=False)
rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex'] rawtx = self.nodes[0].finalizepsbt(res['psbt'])['hex']
txid = self.nodes[0].sendrawtransaction(rawtx) txid = self.nodes[0].sendrawtransaction(rawtx)

View file

@ -29,7 +29,7 @@ class WalletLocktimeTest(BitcoinTestFramework):
self.log.info("Send to new address with locktime") self.log.info("Send to new address with locktime")
node.send( node.send(
outputs={address: 5}, outputs={address: 5},
options={"locktime": mtp_tip - 1}, locktime=mtp_tip - 1,
) )
self.generate(node, 1) self.generate(node, 1)

View file

@ -98,13 +98,13 @@ class CreateWalletWatchonlyTest(BitcoinTestFramework):
options = {'changeAddress': wo_change} options = {'changeAddress': wo_change}
no_wo_options = {'changeAddress': wo_change, 'includeWatching': False} no_wo_options = {'changeAddress': wo_change, 'includeWatching': False}
result = wo_wallet.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, options=options) result = wo_wallet.walletcreatefundedpsbt(inputs=inputs, outputs=outputs, **options)
assert_equal("psbt" in result, True) assert_equal("psbt" in result, True)
assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.walletcreatefundedpsbt, inputs, outputs, 0, no_wo_options) assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.walletcreatefundedpsbt, inputs, outputs, 0, no_wo_options)
self.log.info('Testing fundrawtransaction watch-only defaults') self.log.info('Testing fundrawtransaction watch-only defaults')
rawtx = wo_wallet.createrawtransaction(inputs=inputs, outputs=outputs) rawtx = wo_wallet.createrawtransaction(inputs=inputs, outputs=outputs)
result = wo_wallet.fundrawtransaction(hexstring=rawtx, options=options) result = wo_wallet.fundrawtransaction(hexstring=rawtx, **options)
assert_equal("hex" in result, True) assert_equal("hex" in result, True)
assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.fundrawtransaction, rawtx, no_wo_options) assert_raises_rpc_error(-4, "Insufficient funds", wo_wallet.fundrawtransaction, rawtx, no_wo_options)