aboutsummaryrefslogtreecommitdiff
path: root/test/functional/rpc_psbt.py
diff options
context:
space:
mode:
authorJon Atack <jon@atack.com>2020-11-04 13:13:17 +0100
committerJon Atack <jon@atack.com>2020-11-11 15:55:59 +0100
commita0d495747320c79b27a83c216dcc526ac8df8f24 (patch)
tree1d662469632dc37850ff4b5bd9a9e04566f8e78a /test/functional/rpc_psbt.py
parente21212f01b7c41eba13b0479b252053cf482bc1f (diff)
downloadbitcoin-a0d495747320c79b27a83c216dcc526ac8df8f24.tar.xz
wallet: introduce fee_rate (sat/vB) param/option
Create a fee_rate (sat/vB) RPC param and replace overloading the conf_target and estimate_mode params in the following 6 RPCs with it: - sendtoaddress - sendmany - send - fundrawtransaction - walletcreatefundedpsbt - bumpfee In RPC bumpfee, the previously existing fee_rate remains but the unit is changed from BTC/kvB to sat/vB. This is a breaking change, but it should not be an overly risky one, as the units change by a factor of 1e5 and any fees specified in BTC/kvB after this commit will either be too low and raise an error or be 1 sat/vB and can be RBFed. Update the test coverage for each RPC. Co-authored-by: Murch <murch@murch.one>
Diffstat (limited to 'test/functional/rpc_psbt.py')
-rwxr-xr-xtest/functional/rpc_psbt.py98
1 files changed, 56 insertions, 42 deletions
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index ca75bcb9bb..9adbce1436 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -187,60 +187,74 @@ class PSBTTest(BitcoinTestFramework):
assert_equal(walletprocesspsbt_out['complete'], True)
self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])
- self.log.info("Test walletcreatefundedpsbt feeRate of 0.1 BTC/kB produces a total fee at or slightly below -maxtxfee (~0.05290000)")
- res = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.1, "add_inputs": True})
- assert_approx(res["fee"], 0.055, 0.005)
-
- self.log.info("Test walletcreatefundedpsbt explicit fee rate with conf_target and estimate_mode")
- for unit, fee_rate in {"btc/kb": 0.1, "sat/b": 10000}.items():
- fee = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"conf_target": fee_rate, "estimate_mode": unit, "add_inputs": True})["fee"]
- self.log.info("- conf_target {}, estimate_mode {} produces fee {} at or slightly below -maxtxfee (~0.05290000)".format(fee_rate, unit, fee))
- assert_approx(fee, vexp=0.055, vspan=0.005)
-
- for field, fee_rate in {"conf_target": 0.1, "estimate_mode": "sat/b"}.items():
- self.log.info("- raises RPC error if both feeRate and {} are passed".format(field))
- assert_raises_rpc_error(-8, "Cannot specify both {} and feeRate".format(field),
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.1, field: fee_rate, "add_inputs": True}))
+ 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})
+ assert_approx(res1["fee"], 0.055, 0.005)
+ res2 = self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"feeRate": 0.1, "add_inputs": True})
+ assert_approx(res2["fee"], 0.055, 0.005)
+
+ self.log.info("Test invalid fee rate settings")
+ assert_raises_rpc_error(-4, "Fee rate (0.00000000 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)",
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": 0, "add_inputs": True})
+ assert_raises_rpc_error(-8, "Invalid feeRate 0.00000000 BTC/kB (must be greater than 0)",
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"feeRate": 0, "add_inputs": True})
+ for param, value in {("fee_rate", 100000), ("feeRate", 1)}:
+ assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {param: value, "add_inputs": True})
+ assert_raises_rpc_error(-3, "Amount out of range",
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": -1, "add_inputs": True})
+ assert_raises_rpc_error(-3, "Amount is not a number or string",
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": {"foo": "bar"}, "add_inputs": True})
+ assert_raises_rpc_error(-3, "Invalid amount",
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": "", "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.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})
+
+ for param in ["feeRate", "fee_rate"]:
+ self.log.info("- raises RPC error if both {} and conf_target are passed".format(param))
+ assert_raises_rpc_error(-8, "Cannot specify both conf_target and {}. Please provide either a confirmation "
+ "target in blocks for automatic fee estimation, or an explicit fee rate.".format(param),
+ self.nodes[1].walletcreatefundedpsbt ,inputs, outputs, 0, {param: 1, "conf_target": 1, "add_inputs": True})
+
+ 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",
+ self.nodes[1].walletcreatefundedpsbt ,inputs, outputs, 0, {"fee_rate": 1, "estimate_mode": "economical", "add_inputs": True})
self.log.info("- raises RPC error with invalid estimate_mode settings")
for k, v in {"number": 42, "object": {"foo": "bar"}}.items():
assert_raises_rpc_error(-3, "Expected type string for estimate_mode, got {}".format(k),
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": v, "conf_target": 0.1, "add_inputs": True}))
- for mode in ["foo", Decimal("3.141592")]:
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": v, "conf_target": 0.1, "add_inputs": True})
+ for mode in ["", "foo", Decimal("3.141592")]:
assert_raises_rpc_error(-8, "Invalid estimate_mode parameter",
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": mode, "conf_target": 0.1, "add_inputs": True}))
-
- self.log.info("- raises RPC error if estimate_mode is passed without a conf_target")
- for unit in ["SAT/B", "BTC/KB"]:
- assert_raises_rpc_error(-8, "Selected estimate_mode {} requires a fee rate to be specified in conf_target".format(unit),
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": unit}))
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": mode, "conf_target": 0.1, "add_inputs": True})
self.log.info("- raises RPC error with invalid conf_target settings")
- for mode in ["unset", "economical", "conservative", "btc/kb", "sat/b"]:
+ for mode in ["unset", "economical", "conservative"]:
self.log.debug("{}".format(mode))
for k, v in {"string": "", "object": {"foo": "bar"}}.items():
assert_raises_rpc_error(-3, "Expected type number for conf_target, got {}".format(k),
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": mode, "conf_target": v, "add_inputs": True}))
- if mode in ["btc/kb", "sat/b"]:
- assert_raises_rpc_error(-3, "Amount out of range",
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": mode, "conf_target": -1, "add_inputs": True}))
- assert_raises_rpc_error(-4, "Fee rate (0.00000000 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)",
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": mode, "conf_target": 0, "add_inputs": True}))
- else:
- for n in [-1, 0, 1009]:
- assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008",
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": mode, "conf_target": n, "add_inputs": True}))
-
- for unit, fee_rate in {"SAT/B": 0.99999999, "BTC/KB": 0.00000999}.items():
- self.log.info("- raises RPC error 'fee rate too low' if conf_target {} and estimate_mode {} are passed".format(fee_rate, unit))
- assert_raises_rpc_error(-4, "Fee rate (0.00000999 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)",
- lambda: self.nodes[1].walletcreatefundedpsbt(inputs, outputs, 0, {"estimate_mode": unit, "conf_target": fee_rate, "add_inputs": True}))
-
- self.log.info("Test walletcreatefundedpsbt feeRate of 10 BTC/kB produces total fee well above -maxtxfee and raises RPC error")
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": mode, "conf_target": v, "add_inputs": True})
+ 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
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"estimate_mode": mode, "conf_target": n, "add_inputs": True})
+
+ # Test setting explicit fee rate just below the minimum.
+ self.log.info("- raises RPC error 'fee rate too low' if feerate_sat_vb of 0.99999999 is passed")
+ assert_raises_rpc_error(-4, "Fee rate (0.00000999 BTC/kB) is lower than the minimum fee rate setting (0.00001000 BTC/kB)",
+ self.nodes[1].walletcreatefundedpsbt, inputs, outputs, 0, {"fee_rate": 0.99999999, "add_inputs": True})
+
+ self.log.info("Test walletcreatefundedpsbt with too-high fee rate produces total fee well above -maxtxfee and raises RPC error")
# previously this was silently capped at -maxtxfee
for bool_add, outputs_array in {True: outputs, False: [{self.nodes[1].getnewaddress(): 1}]}.items():
- assert_raises_rpc_error(-4, "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)",
- self.nodes[1].walletcreatefundedpsbt, inputs, outputs_array, 0, {"feeRate": 10, "add_inputs": bool_add})
+ msg = "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"
+ assert_raises_rpc_error(-4, msg, self.nodes[1].walletcreatefundedpsbt, inputs, outputs_array, 0, {"fee_rate": 1000000, "add_inputs": bool_add})
+ assert_raises_rpc_error(-4, msg, self.nodes[1].walletcreatefundedpsbt, inputs, outputs_array, 0, {"feeRate": 1, "add_inputs": bool_add})
self.log.info("Test various PSBT operations")
# partially sign multisig things with node 1