From 5546b1f068dc8efb9987f66d7736ff244941f82a Mon Sep 17 00:00:00 2001 From: k9ert <117085+k9ert@users.noreply.github.com> Date: Thu, 9 Apr 2026 14:56:36 +0200 Subject: [PATCH] fix: auto-create BTC node from env vars on fresh install (#2598) Co-authored-by: Claude Opus 4.6 (1M context) --- .../specter/managers/node_manager.py | 16 +++++++ tests/test_managers_node.py | 46 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/cryptoadvance/specter/managers/node_manager.py b/src/cryptoadvance/specter/managers/node_manager.py index 9ea5c74e9..4379811af 100644 --- a/src/cryptoadvance/specter/managers/node_manager.py +++ b/src/cryptoadvance/specter/managers/node_manager.py @@ -85,6 +85,22 @@ class NodeManager: logger.error(f"Skipping node {node_alias} due to {e}") if not self.nodes: + if os.environ.get("BTC_RPC_USER"): + logger.info( + "Creating an external Bitcoin Core node from BTC_RPC_* environment variables." + ) + node = self.add_external_node( + node_type="BTC", + name="Bitcoin Core", + autodetect=False, + datadir=get_default_datadir(node_type="BTC"), + user=os.environ.get("BTC_RPC_USER"), + password=os.environ.get("BTC_RPC_PASSWORD", ""), + port=os.environ.get("BTC_RPC_PORT", "8332"), + host=os.environ.get("BTC_RPC_HOST", "localhost"), + protocol=os.environ.get("BTC_RPC_PROTOCOL", "http"), + ) + self._active_node = node.alias if os.environ.get("ELM_RPC_USER"): logger.debug( "Creating an external Elements node with the initial configuration." diff --git a/tests/test_managers_node.py b/tests/test_managers_node.py index 005bc649f..18212d2e1 100644 --- a/tests/test_managers_node.py +++ b/tests/test_managers_node.py @@ -74,6 +74,52 @@ def test_node_manager_basics( nm.switch_node("node_with_a_different_port") +def test_auto_create_btc_node_from_env(monkeypatch): + """Env vars BTC_RPC_* should auto-create a node on fresh install (empty nodes dir).""" + monkeypatch.setenv("BTC_RPC_USER", "testuser") + monkeypatch.setenv("BTC_RPC_PASSWORD", "testpass") + monkeypatch.setenv("BTC_RPC_PORT", "18443") + monkeypatch.setenv("BTC_RPC_HOST", "btcnode") + monkeypatch.setenv("BTC_RPC_PROTOCOL", "https") + + with tempfile.TemporaryDirectory( + prefix="pytest_NodeManager_env_" + ) as data_folder: + nm = NodeManager(data_folder=data_folder) + # Node created + assert "bitcoin_core" in nm.nodes + node = nm.nodes["bitcoin_core"] + assert node.name == "Bitcoin Core" + assert node.user == "testuser" + assert node.password == "testpass" + assert node.port == "18443" + assert node.host == "btcnode" + assert node.protocol == "https" + # Active node set + assert nm._active_node == "bitcoin_core" + # JSON persisted + assert os.path.isfile(os.path.join(data_folder, "bitcoin_core.json")) + + # Second load_from_disk should NOT duplicate (node already exists) + nm.load_from_disk(data_folder) + assert list(nm.nodes.keys()).count("bitcoin_core") == 1 + + +def test_no_auto_create_btc_node_without_env(): + """Without BTC_RPC_USER, no node should be auto-created.""" + # Ensure env var is not set (don't use monkeypatch.delenv in case it's absent) + old = os.environ.pop("BTC_RPC_USER", None) + try: + with tempfile.TemporaryDirectory( + prefix="pytest_NodeManager_noenv_" + ) as data_folder: + nm = NodeManager(data_folder=data_folder) + assert len(nm.nodes) == 0 + finally: + if old is not None: + os.environ["BTC_RPC_USER"] = old + + @pytest.mark.elm def test_switch_nodes_across_chains( bitcoin_regtest: BitcoindPlainController, elements_elreg: ElementsPlainController