2021-06-16 15:33:35 +02:00
|
|
|
from enum import auto
|
|
|
|
|
import tempfile
|
2021-10-13 09:05:26 +02:00
|
|
|
import time
|
|
|
|
|
import tarfile
|
|
|
|
|
import os
|
2022-10-29 15:54:34 +02:00
|
|
|
from unittest.mock import MagicMock
|
2021-08-17 17:27:21 +02:00
|
|
|
|
|
|
|
|
import pytest
|
2021-06-16 15:33:35 +02:00
|
|
|
from cryptoadvance.specter.managers.node_manager import NodeManager
|
2022-11-23 17:50:25 +01:00
|
|
|
from cryptoadvance.specter.specter_error import SpecterError
|
2021-06-16 15:33:35 +02:00
|
|
|
from cryptoadvance.specter.process_controller.bitcoind_controller import (
|
|
|
|
|
BitcoindPlainController,
|
|
|
|
|
)
|
|
|
|
|
from cryptoadvance.specter.process_controller.elementsd_controller import (
|
|
|
|
|
ElementsPlainController,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2022-11-23 17:50:25 +01:00
|
|
|
def test_node_manager_basics(
|
|
|
|
|
empty_data_folder, node, node_with_different_port, specter_regtest_configured
|
|
|
|
|
):
|
|
|
|
|
nodes_folder = empty_data_folder + "/nodes"
|
|
|
|
|
nm = specter_regtest_configured.node_manager
|
|
|
|
|
# # Load from disk to get the other two nodes
|
|
|
|
|
assert sorted(list(nm.nodes.keys())) == [
|
2023-01-31 11:06:29 +01:00
|
|
|
"bitcoin_core",
|
|
|
|
|
"node_with_a_different_port",
|
2022-11-23 17:50:25 +01:00
|
|
|
"standard_node",
|
|
|
|
|
]
|
|
|
|
|
assert nm.nodes_names == [
|
|
|
|
|
"Standard node",
|
|
|
|
|
"Node with a different port",
|
|
|
|
|
"Bitcoin Core",
|
|
|
|
|
]
|
|
|
|
|
nm.load_from_disk(nodes_folder)
|
|
|
|
|
assert nm.nodes_names == [
|
|
|
|
|
"Standard node",
|
|
|
|
|
"Node with a different port",
|
|
|
|
|
"Bitcoin Core",
|
|
|
|
|
]
|
|
|
|
|
# Checking some standard methods and properties
|
2023-01-31 11:06:29 +01:00
|
|
|
assert nm.get_by_alias("node_with_a_different_port") == nm.get_by_name(
|
2022-11-23 17:50:25 +01:00
|
|
|
"Node with a different port"
|
|
|
|
|
)
|
2023-01-31 11:06:29 +01:00
|
|
|
default_node = nm.get_by_alias("bitcoin_core")
|
|
|
|
|
node_with_a_different_port = nm.get_by_alias("node_with_a_different_port")
|
2022-11-23 17:50:25 +01:00
|
|
|
assert nm.active_node == default_node
|
2023-01-31 11:06:29 +01:00
|
|
|
assert specter_regtest_configured.config["active_node_alias"] == "bitcoin_core"
|
2022-11-23 17:50:25 +01:00
|
|
|
# Switching the node via the node manager does not change the active_node_alias in the config, only specter.update_active_node() does
|
2023-01-31 11:06:29 +01:00
|
|
|
nm.switch_node("node_with_a_different_port")
|
|
|
|
|
assert nm.active_node == node_with_a_different_port
|
|
|
|
|
assert specter_regtest_configured.config["active_node_alias"] == "bitcoin_core"
|
|
|
|
|
specter_regtest_configured.update_active_node("node_with_a_different_port")
|
|
|
|
|
assert (
|
|
|
|
|
specter_regtest_configured.config["active_node_alias"]
|
|
|
|
|
== "node_with_a_different_port"
|
|
|
|
|
)
|
|
|
|
|
assert nm.active_node == node_with_a_different_port
|
2022-11-23 17:50:25 +01:00
|
|
|
# Deleting a node
|
2023-01-31 11:06:29 +01:00
|
|
|
nm.delete_node(node_with_a_different_port, specter_regtest_configured)
|
2022-11-23 17:50:25 +01:00
|
|
|
assert nm.nodes_names == ["Standard node", "Bitcoin Core"]
|
|
|
|
|
# Check that with the deletion of the active node the switch to the next node work, the first node in the list, here the Standard node, is switched to
|
|
|
|
|
assert specter_regtest_configured.config["active_node_alias"] == "standard_node"
|
|
|
|
|
assert nm._active_node == "standard_node"
|
|
|
|
|
# Check the error handling
|
|
|
|
|
with pytest.raises(
|
|
|
|
|
SpecterError,
|
|
|
|
|
match="Node with a different port not found, node could not be deleted.",
|
|
|
|
|
):
|
2023-01-31 11:06:29 +01:00
|
|
|
nm.delete_node(node_with_a_different_port, specter_regtest_configured)
|
|
|
|
|
with pytest.raises(
|
|
|
|
|
SpecterError, match="Node alias node_with_a_different_port does not exist!"
|
|
|
|
|
):
|
|
|
|
|
nm.switch_node("node_with_a_different_port")
|
2022-11-23 17:50:25 +01:00
|
|
|
|
|
|
|
|
|
2026-04-09 14:56:36 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
2021-08-17 17:27:21 +02:00
|
|
|
@pytest.mark.elm
|
2022-11-23 17:50:25 +01:00
|
|
|
def test_switch_nodes_across_chains(
|
2021-06-16 15:33:35 +02:00
|
|
|
bitcoin_regtest: BitcoindPlainController, elements_elreg: ElementsPlainController
|
|
|
|
|
):
|
2022-10-29 15:54:34 +02:00
|
|
|
with tempfile.TemporaryDirectory(
|
|
|
|
|
prefix="pytest_NodeManager_datafolder"
|
|
|
|
|
) as data_folder:
|
2021-06-16 15:33:35 +02:00
|
|
|
print(f"data_folder={data_folder}")
|
|
|
|
|
nm = NodeManager(data_folder=data_folder)
|
2022-10-29 15:54:34 +02:00
|
|
|
nm.add_external_node(
|
2022-01-05 17:05:00 +01:00
|
|
|
"BTC",
|
2021-06-16 15:33:35 +02:00
|
|
|
"bitcoin_regtest",
|
|
|
|
|
False,
|
|
|
|
|
"",
|
|
|
|
|
bitcoin_regtest.rpcconn.rpcuser,
|
|
|
|
|
bitcoin_regtest.rpcconn.rpcpassword,
|
|
|
|
|
bitcoin_regtest.rpcconn.rpcport,
|
|
|
|
|
bitcoin_regtest.rpcconn._ipaddress,
|
|
|
|
|
"http",
|
|
|
|
|
)
|
2023-01-31 11:06:29 +01:00
|
|
|
assert nm.nodes_names == ["bitcoin_regtest"]
|
|
|
|
|
nm.switch_node("bitcoin_regtest")
|
2022-10-20 09:44:36 +02:00
|
|
|
assert nm.active_node.rpc.getblockchaininfo()["chain"] == "regtest"
|
2022-10-29 15:54:34 +02:00
|
|
|
nm.add_external_node(
|
2022-01-05 17:05:00 +01:00
|
|
|
"ELM",
|
2021-06-16 15:33:35 +02:00
|
|
|
"elements_elreg",
|
|
|
|
|
False,
|
|
|
|
|
"",
|
|
|
|
|
elements_elreg.rpcconn.rpcuser,
|
|
|
|
|
elements_elreg.rpcconn.rpcpassword,
|
|
|
|
|
elements_elreg.rpcconn.rpcport,
|
|
|
|
|
elements_elreg.rpcconn._ipaddress,
|
|
|
|
|
"http",
|
|
|
|
|
)
|
2023-01-31 11:06:29 +01:00
|
|
|
assert nm.nodes_names == ["bitcoin_regtest", "elements_elreg"]
|
2021-06-16 15:33:35 +02:00
|
|
|
nm.switch_node("elements_elreg")
|
2022-10-20 09:44:36 +02:00
|
|
|
assert nm.active_node.rpc.getblockchaininfo()["chain"] == "elreg"
|