From f3630dc10b25baf6238d655be7e395bee0cc4fe8 Mon Sep 17 00:00:00 2001 From: Kristaps Kaupe Date: Wed, 16 Apr 2025 19:16:12 +0300 Subject: [PATCH] Support Bitcoin Core descriptor wallets (quick and dirty way) Co-authored-by: laanwj <126646+laanwj@users.noreply.github.com> --- docs/USAGE.md | 12 ++------- src/jmclient/blockchaininterface.py | 40 +++++++++++++++++------------ 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/docs/USAGE.md b/docs/USAGE.md index d718d98..abfcf01 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -121,19 +121,11 @@ Make sure to follow the following step. With `bitcoind` running, do: ``` -bitcoin-cli -named createwallet wallet_name=jm_wallet descriptors=false +bitcoin-cli -named createwallet wallet_name=jm_wallet disable_private_keys=true ``` -If this command fails with error `Unknown named parameter descriptors`, it means you run Bitcoin Core version older than v0.21. In that case do the following instead (but it's recommended to upgrade Bitcoin Core to more recent version): -``` -bitcoin-cli createwallet "jm_wallet" -``` - -If this command fails with error `BDB wallet creation is deprecated and will be removed in a future release. In this release it can be re-enabled temporarily with the -deprecatedrpc=create_bdb setting.`, it means you run Bitcoin Core version v26 or newer. In that case you must add `deprecatedrpc=create_bdb` setting to your `bitcoin.conf`, restart Bitcoin Core and try again. - The "jm_wallet" name is just an example. You can set any name. Alternative to this `bitcoin-cli` command: you can set a line with `wallet=..` in your -`bitcoin.conf` before starting Core (see the Bitcoin Core documentation for details). At the moment, only legacy wallets (`descriptors=false`) -work with Joinmarket. This means that Bitcoin Core needs to have been built with legacy wallet (Berkeley DB) support. +`bitcoin.conf` before starting Core (see the Bitcoin Core documentation for details). After you create the wallet in the Bitcoin Core, you should set it in the `joinmarket.cfg`: diff --git a/src/jmclient/blockchaininterface.py b/src/jmclient/blockchaininterface.py index 7382e2d..81c7194 100644 --- a/src/jmclient/blockchaininterface.py +++ b/src/jmclient/blockchaininterface.py @@ -356,14 +356,11 @@ class BitcoinCoreInterface(BlockchainInterface): log.info("Loading Bitcoin RPC wallet " + wallet_name + "...") self._rpc("loadwallet", [wallet_name]) log.info("Done.") - # We only support legacy wallets currently + # We need to know is this legacy or descriptors wallet because there + # will be different RPC calls needed for address import. wallet_info = self._getwalletinfo() - if "descriptors" in wallet_info and wallet_info["descriptors"]: - raise Exception( - "JoinMarket currently does not support Bitcoin Core " - "descriptor wallets, use legacy wallet (rpc_wallet_file " - "setting in joinmarket.cfg) instead. See docs/USAGE.md " - "for details.") + self.descriptors = ("descriptors" in wallet_info and + wallet_info["descriptors"]) def is_address_imported(self, addr: str) -> bool: return len(self._rpc('getaddressinfo', [addr])['labels']) > 0 @@ -429,7 +426,8 @@ class BitcoinCoreInterface(BlockchainInterface): if method not in ['importaddress', 'walletpassphrase', 'getaccount', 'gettransaction', 'getrawtransaction', 'gettxout', 'importmulti', 'listtransactions', 'getblockcount', - 'scantxoutset', 'getblock', 'getblockhash']: + 'scantxoutset', 'getblock', 'getblockhash', + 'importdescriptors']: log.debug('rpc: ' + method + " " + str(args)) try: res = self.jsonRpc.call(method, args) @@ -457,15 +455,23 @@ class BitcoinCoreInterface(BlockchainInterface): def import_addresses(self, addr_list: Iterable[str], wallet_name: str, restart_cb: Callable[[str], None] = None) -> None: requests = [] - for addr in addr_list: - requests.append({ - "scriptPubKey": {"address": addr}, - "timestamp": 0, - "label": wallet_name, - "watchonly": True - }) - - result = self._rpc('importmulti', [requests, {"rescan": False}]) + if self.descriptors: + for addr in addr_list: + requests.append({ + "desc": btc.get_address_descriptor(addr), + "timestamp": "now", + "label": wallet_name + }) + result = self._rpc('importdescriptors', [requests]) + else: + for addr in addr_list: + requests.append({ + "scriptPubKey": {"address": addr}, + "timestamp": 0, + "label": wallet_name, + "watchonly": True + }) + result = self._rpc('importmulti', [requests, {"rescan": False}]) num_failed = 0 for row in result: