From e1b6fcbc090cb2d46df5533cd076c3ecc0bb1286 Mon Sep 17 00:00:00 2001 From: Kristaps Kaupe Date: Sat, 2 Dec 2023 22:37:51 +0200 Subject: [PATCH] RPC API: Add optional txfee property for single joins --- docs/api/wallet-rpc.yaml | 4 ++++ src/jmclient/wallet_rpc.py | 44 +++++++++++++++++++++++++++++++------- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/docs/api/wallet-rpc.yaml b/docs/api/wallet-rpc.yaml index eeffeaba0..1402cbc4b 100644 --- a/docs/api/wallet-rpc.yaml +++ b/docs/api/wallet-rpc.yaml @@ -655,6 +655,10 @@ components: destination: type: string example: "bcrt1qujp2x2fv437493sm25gfjycns7d39exjnpptzw" + txfee: + type: integer + example: 6 + description: Bitcoin miner fee to use for transaction. A number higher than 1000 is used as satoshi per kvB tx fee. The number lower than that uses the dynamic fee estimation of blockchain provider as confirmation target. TokenRequest: type: object required: diff --git a/src/jmclient/wallet_rpc.py b/src/jmclient/wallet_rpc.py index e9a9e6658..9dab87ea3 100644 --- a/src/jmclient/wallet_rpc.py +++ b/src/jmclient/wallet_rpc.py @@ -187,6 +187,9 @@ def __init__(self, port, wss_port, tls=True): # a tumble schedule. self.tumbler_options = None self.tumble_log = None + # save settings we might temporary change runtime + self.default_policy_tx_fees = jm_single().config.get("POLICY", + "tx_fees") def get_client_factory(self): return JMClientProtocolFactory(self.taker) @@ -511,6 +514,8 @@ def taker_finished(self, res, fromtx=False, waittime=0.0, txdetails=None): if not self.tumbler_options: # We were doing a single coinjoin -- stop taker. self.stop_taker(res) + jm_single().config.set("POLICY", "tx_fees", + self.default_policy_tx_fees) else: # We're running the tumbler. assert self.tumble_log is not None @@ -782,10 +787,12 @@ def directsend(self, request, walletname): if not self.coinjoin_state == CJ_NOT_RUNNING: raise ActionNotAllowed() - old_txfee = jm_single().config.get("POLICY", "tx_fees") if "txfee" in payment_info_json: - jm_single().config.set("POLICY", "tx_fees", - str(payment_info_json["txfee"])) + if int(payment_info_json["txfee"]) > 0: + jm_single().config.set("POLICY", "tx_fees", + str(payment_info_json["txfee"])) + else: + raise InvalidRequestFormat() try: tx = direct_send(self.services["wallet"], @@ -793,13 +800,20 @@ def directsend(self, request, walletname): int(payment_info_json["mixdepth"]), destination=payment_info_json["destination"], return_transaction=True, answeryes=True) - jm_single().config.set("POLICY", "tx_fees", old_txfee) + jm_single().config.set("POLICY", "tx_fees", + self.default_policy_tx_fees) except AssertionError: - jm_single().config.set("POLICY", "tx_fees", old_txfee) + jm_single().config.set("POLICY", "tx_fees", + self.default_policy_tx_fees) raise InvalidRequestFormat() except NotEnoughFundsException as e: - jm_single().config.set("POLICY", "tx_fees", old_txfee) + jm_single().config.set("POLICY", "tx_fees", + self.default_policy_tx_fees) raise TransactionFailed(repr(e)) + except Exception: + jm_single().config.set("POLICY", "tx_fees", + self.default_policy_tx_fees) + raise if not tx: # this should not really happen; not a coinjoin # so tx should go through. @@ -1183,6 +1197,9 @@ def configset(self, request, walletname): try: jm_single().config.set(config_json["section"], config_json["field"], config_json["value"]) + if config_json["section"] == "POLICY": + if config_json["field"] == "tx_fees": + self.default_policy_tx_fees = config_json["value"] except: raise ConfigNotPresent() # null return indicates success in updating: @@ -1265,8 +1282,11 @@ def docoinjoin(self, request, walletname): raise NoWalletFound() if not self.wallet_name == walletname: raise InvalidRequestFormat() - request_data = self.get_POST_body(request,["mixdepth", "amount_sats", - "counterparties", "destination"]) + request_data = self.get_POST_body(request, + ["mixdepth", "amount_sats", + "counterparties", + "destination"], + ["txfee"]) if not request_data: raise InvalidRequestFormat() #see file scripts/sample-schedule-for-testnet for schedule format @@ -1297,6 +1317,14 @@ def dummy_user_callback(rel, abs): # Before actual start, update our coinjoin state: if not self.activate_coinjoin_state(CJ_TAKER_RUNNING): raise ServiceAlreadyStarted() + + if "txfee" in request_data: + if int(request_data["txfee"]) > 0: + jm_single().config.set("POLICY", "tx_fees", + str(request_data["txfee"])) + else: + raise InvalidRequestFormat() + self.taker = Taker(self.services["wallet"], schedule, max_cj_fee = max_cj_fee, callbacks=(self.filter_orders_callback,