Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions src/cryptoadvance/specter/devices/bitcoin_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from ..device import Device
from ..helpers import create_unique_id
from ..key import Key
from ..rpc import get_default_datadir
from ..rpc import get_default_datadir, get_walletdir
from ..specter_error import SpecterError
from ..util.base58 import decode_base58, encode_base58_checksum
from ..util.descriptor import AddChecksum
Expand Down Expand Up @@ -254,16 +254,24 @@ def delete(
wallet_manager.rpc.unloadwallet(wallet_rpc_path)
# Try deleting wallet file
if bitcoin_datadir:
if chain != "main":
bitcoin_datadir = os.path.join(bitcoin_datadir, chain)
candidates = [
os.path.join(bitcoin_datadir, wallet_rpc_path),
os.path.join(bitcoin_datadir, "wallets", wallet_rpc_path),
]
for path in candidates:
bitcoin_datadir = os.path.expanduser(bitcoin_datadir)
# Check walletdir in bitcoin.conf; network-specific section takes precedence over default
walletdir = get_walletdir(bitcoin_datadir, chain)
if walletdir:
path = os.path.join(walletdir, wallet_rpc_path)
if os.path.exists(path):
shutil.rmtree(path)
Comment thread
k9ert marked this conversation as resolved.
break
else:
if chain != "main":
bitcoin_datadir = os.path.join(bitcoin_datadir, chain)
candidates = [
os.path.join(bitcoin_datadir, wallet_rpc_path),
os.path.join(bitcoin_datadir, "wallets", wallet_rpc_path),
]
for path in candidates:
if os.path.exists(path):
shutil.rmtree(path)
break
except:
pass # We tried...

Expand Down
7 changes: 6 additions & 1 deletion src/cryptoadvance/specter/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
RpcError,
autodetect_rpc_confs,
get_default_datadir,
get_walletdir,
)
from .specter_error import SpecterError, BrokenCoreConnectionException
from .device import Device
Expand Down Expand Up @@ -668,7 +669,11 @@ def delete_wallet_file(self, wallet) -> bool:
)
except RpcError:
pass
if self.chain == "test":
# Check walletdir in bitcoin.conf; network-specific section takes precedence over default
walletdir = get_walletdir(datadir, self.chain)
if walletdir:
path = os.path.join(walletdir, wallet_rpc_path)
elif self.chain == "test":
Comment thread
k9ert marked this conversation as resolved.
path = os.path.join(datadir, "testnet3/wallets", wallet_rpc_path)
elif self.chain == "main":
path = os.path.join(datadir, wallet_rpc_path)
Expand Down
20 changes: 20 additions & 0 deletions src/cryptoadvance/specter/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,26 @@ def get_rpcconfig(datadir=get_default_datadir()) -> dict:
return config


def get_walletdir(datadir, chain):
"""Returns the walletdir for the given chain as configured in bitcoin.conf,
or None if not set.

The network-specific section (e.g. [regtest]) takes precedence over the
[default] section, matching Bitcoin Core's own config resolution order.
When set, walletdir is an absolute path and should be used directly as the
wallet base path without joining it with datadir.

datadir is expanded (~ resolved) before use so callers can pass user-entered
paths without manually calling os.path.expanduser first.
"""
datadir = os.path.expanduser(datadir)
config = get_rpcconfig(datadir)
btc_conf = config.get("bitcoin.conf", {})
return btc_conf.get(chain, {}).get("walletdir") or btc_conf.get("default", {}).get(
"walletdir"
)


def _detect_rpc_confs_via_datadir(config=None, datadir=get_default_datadir()):
"""returns the bitcoin.conf configuration for the network
specified in bitcoin.conf with testnet=1, regtest=1, etc. as
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
rpcuser=bitcoin
rpcpassword=CHANGEME
walletdir=/custom/wallets
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
rpcuser=bitcoin
rpcpassword=CHANGEME
walletdir=/default/wallets
[regtest]
walletdir=/regtest/wallets
46 changes: 45 additions & 1 deletion tests/test_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
RpcError,
_detect_rpc_confs_via_datadir,
get_rpcconfig,
get_walletdir,
)
from cryptoadvance.specter.specter_error import SpecterError

Expand Down Expand Up @@ -94,7 +95,50 @@ def test_get_rpcconfig2(empty_data_folder):
}


def test_detect_rpc_confs_via_datadir1(empty_data_folder):
def test_get_walletdir_not_configured(empty_data_folder):
"""get_walletdir returns None when walletdir is not set in bitcoin.conf."""
assert get_walletdir(empty_data_folder, "main") is None
assert get_walletdir(empty_data_folder, "regtest") is None


def test_get_walletdir_default_section():
"""get_walletdir returns the walletdir from the [default] section."""
datadir = "./tests/misc_testdata/rpc_autodetection/example_walletdir_default"
assert get_walletdir(datadir, "main") == "/custom/wallets"
assert get_walletdir(datadir, "regtest") == "/custom/wallets"
assert get_walletdir(datadir, "test") == "/custom/wallets"


def test_get_walletdir_network_section_takes_precedence():
"""Network-specific walletdir takes precedence over the [default] walletdir."""
datadir = "./tests/misc_testdata/rpc_autodetection/example_walletdir_network"
# regtest section overrides the default
assert get_walletdir(datadir, "regtest") == "/regtest/wallets"
# other chains fall back to default
assert get_walletdir(datadir, "main") == "/default/wallets"
assert get_walletdir(datadir, "test") == "/default/wallets"


def test_get_walletdir_dot_notation_network_override(tmp_path):
"""Dot-notation network walletdir overrides the default walletdir."""
bitcoin_conf = tmp_path / "bitcoin.conf"
bitcoin_conf.write_text(
"walletdir=/default/wallets\n" "regtest.walletdir=/regtest/wallets\n"
)
assert get_walletdir(str(tmp_path), "regtest") == "/regtest/wallets"
assert get_walletdir(str(tmp_path), "main") == "/default/wallets"
assert get_walletdir(str(tmp_path), "test") == "/default/wallets"


def test_get_walletdir_expands_tilde(tmp_path, monkeypatch):
"""get_walletdir expands ~ in the datadir path so user-entered paths work."""
monkeypatch.setenv("HOME", str(tmp_path))
bitcoin_conf = tmp_path / "bitcoin.conf"
bitcoin_conf.write_text("walletdir=/custom/wallets\n")
assert get_walletdir("~", "main") == "/custom/wallets"

def test_detect_rpc_confs_via_datadir1():
def test_detect_rpc_confs_via_datadir1():
c = _detect_rpc_confs_via_datadir(
datadir="./tests/misc_testdata/rpc_autodetection/example1"
)
Expand Down
Loading