Skip to content

Commit

Permalink
Chore: Remove default node (#2072)
Browse files Browse the repository at this point in the history
* change passwordaspin auth implementation

* env-var for RASPIBLITZ_SPECTER_RPC_LOGIN_BITCOIN_CONF_LOCATION

* remove default

* fix tests

* fix the tests part2

* fix cypress tests

* docstrings and other default removals

* improve error_handling

* do not raise exception
  • Loading branch information
k9ert authored Jan 30, 2023
1 parent 55d157b commit 40a6a2e
Show file tree
Hide file tree
Showing 32 changed files with 846 additions and 415 deletions.
4 changes: 3 additions & 1 deletion cypress/integration/spec_configures_nodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ describe('Configuring nodes', () => {
cy.viewport(1200,660)
cy.visit('/')
cy.get('#node-switch-icon').click()
cy.get('[href="/nodes/node/default/"]').first().click()
cy.get('[data-cy="connect-new-node-btn"]').click()
cy.get(':nth-child(6) > [href="/nodes/new_node/"]').click()
cy.get('#datadir-container').then(($datadir) => {
cy.log($datadir)
if (!Cypress.dom.isVisible($datadir)) {
cy.get('.slider').click()
}
})
cy.get('#name').type('Bitcoin Core')
cy.get('.slider').click()
cy.get('#username').clear()
cy.get('#username').type("bitcoin")
Expand Down
3 changes: 0 additions & 3 deletions cypress/integration/spec_empty_specter_home.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ describe('Completely empty specter-home', () => {
cy.viewport(1200,660)
cy.visit('/welcome/about')
cy.contains('Welcome to Specter Desktop')
cy.get('#node-switch-icon').click()
cy.get('[href="/nodes/node/default/"]').first().click()
cy.contains('Bitcoin Core')
cy.get('[href="/settings/"] > img').click()
cy.contains('Backup and Restore')
cy.get('[href="/settings/auth"]').click()
Expand Down
7 changes: 7 additions & 0 deletions src/cryptoadvance/specter/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ class BaseConfig(object):
# CERT and KEY is for running self-signed-ssl-certs. Check cli_server for details
CERT = os.getenv("CERT", None)
KEY = os.getenv("KEY", None)

# This will be used to search for a bitcoin.conf in order to enable the
# auth method "RPC password as pin"
RASPIBLITZ_SPECTER_RPC_LOGIN_BITCOIN_CONF_LOCATION = os.getenv(
"RASPIBLITZ_SPECTER_RPC_LOGIN_BITCOIN_CONF_LOCATION", "/mnt/hdd/bitcoin"
)

# This will get passed to initialize the specter-object
DEFAULT_SPECTER_CONFIG = {}

Expand Down
3 changes: 2 additions & 1 deletion src/cryptoadvance/specter/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from cryptoadvance.specter.util.reflection import get_subclasses_for_clazz
from .key import Key
from typing import List
from .persistence import read_json_file, write_json_file
import logging
from .helpers import is_testnet, is_liquid
Expand Down Expand Up @@ -44,7 +45,7 @@ def __init__(self, name, alias, keys, blinding_key, fullpath, manager):
"""
self.name = name
self.alias = alias
self.keys = keys
self.keys: List[Key] = keys
self.fullpath = fullpath
self.blinding_key = blinding_key
self.manager = manager
Expand Down
2 changes: 1 addition & 1 deletion src/cryptoadvance/specter/managers/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(self, data_folder, config={}):
"asset_labels": {
"liquidv1": {},
},
"active_node_alias": "default",
"active_node_alias": None,
"proxy_url": "socks5h://localhost:9050", # Tor proxy URL
"only_tor": False,
"tor_control_port": "",
Expand Down
119 changes: 46 additions & 73 deletions src/cryptoadvance/specter/managers/node_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from ..specter_error import SpecterError, SpecterInternalException
from ..persistence import PersistentObject, write_node, delete_file
from ..helpers import alias, calc_fullpath, load_jsons
from ..node import Node
from ..node import Node, NonExistingNode
from ..internal_node import InternalNode
from ..services import callbacks
from ..managers.service_manager import ServiceManager
Expand All @@ -18,14 +18,11 @@


class NodeManager:
# chain is required to manage wallets when bitcoind is not running
DEFAULT_ALIAS = "default"

def __init__(
self,
proxy_url="socks5h://localhost:9050",
only_tor=False,
active_node="default",
active_node=None,
bitcoind_path="",
internal_bitcoind_version="",
data_folder="",
Expand Down Expand Up @@ -56,6 +53,7 @@ def load_from_disk(self, data_folder=None):
if not os.path.isdir(data_folder):
os.mkdir(data_folder)
nodes_files = load_jsons(self.data_folder, key="alias")
logger.debug(nodes_files)
for node_alias in nodes_files:
try:
valid_node = True
Expand Down Expand Up @@ -101,49 +99,15 @@ def load_from_disk(self, data_folder=None):
port=7041,
host="localhost",
protocol="http",
default_alias=self.DEFAULT_ALIAS,
)
logger.debug(
"Creating an external BTC node with the initial configuration."
)
self.add_external_node(
node_type="BTC",
name="Bitcoin Core",
autodetect=True,
datadir=get_default_datadir(),
user="",
password="",
port=8332,
host="localhost",
protocol="http",
default_alias=self.DEFAULT_ALIAS,
)

# Make sure we always have the default node
# (needed for the rpc-as-pin-authentication used on Raspiblitz)
has_default_node = False
for node in self.nodes.values():
if node.alias == self.DEFAULT_ALIAS:
has_default_node = True
# Recreate the default node if it doesn't exist anymore
if not has_default_node:
logger.debug("Recreating the default node.")
self.add_external_node(
node_type="BTC",
name="Bitcoin Core",
autodetect=True,
datadir=get_default_datadir(),
user="",
password="",
port=8332,
host="localhost",
protocol="http",
default_alias=self.DEFAULT_ALIAS,
)

@property
def active_node(self) -> Node:
return self.get_by_alias(self._active_node)
"""returns the current active node or a NonExistingNode
if no node is active, currently.
"""
active_node = self.get_by_alias(self._active_node)
return active_node if active_node else NonExistingNode()

@property
def nodes_names(self) -> list:
Expand All @@ -155,26 +119,37 @@ def nodes_by_chain(self, chain: str) -> list:
return [node for node in self.nodes.values() if node.chain == chain]

def switch_node(self, node_alias: str):
# This will throw an error if the node doesn't exist
"""This will throw an SpecterError if the node doesn't exist.
It won't persist anything! Use specter.update_active_node to persist!
"""
new_node = self.get_by_alias(node_alias)
if not new_node:
raise SpecterError(f"Node alias {node_alias} does not exist!")
logger.debug(f"Switching from {self._active_node} to {node_alias}.")
self._active_node = self.get_by_alias(node_alias).alias

def default_node(self) -> Node:
return self.get_by_alias(self.DEFAULT_ALIAS)
self._active_node = node_alias

def get_by_alias(self, alias: str) -> Node:
"""Returns a Node instance for the given alias.
None if a node with that alias doesn't exist
"""
for node in self.nodes.values():
if node.alias == alias:
return node
raise SpecterError("Node alias %s does not exist!" % alias)
return None

def get_by_name(self, name: str) -> Node:
"""Returns a Node instance for the given alias.
raises an SpecterError if it doesn't exist
"""
for node in self.nodes.values():
if node.name == name:
return node
raise SpecterError("Node name %s does not exist!" % name)

def get_name_from_alias(self, alias: str) -> str:
"""Returns the name for a specific node alias
raises an SpecterError if it doesn't exist
"""
for node in self.nodes.values():
if node.alias == alias:
return node.name
Expand All @@ -200,26 +175,25 @@ def update_bitcoind_version(self, specter, version):

def add_external_node(
self,
node_type,
name,
autodetect,
node_type: str,
name: str,
autodetect: bool,
datadir,
user,
password,
port,
host,
protocol,
default_alias=None,
user: str,
password: str,
port: str,
host: str,
protocol: str,
):
"""Adding a node. Params:
:param node_type: only valid for autodetect. Either BTC or ELM
"""Adding a node and saves it to disk as well. Params:
* node_type: only valid for autodetect. Either BTC or ELM
* name: A nice name for this node. The alias will get calculated out of that
* autodetect (boolean): whether this node should get autodetected
* datadir: questionable! Why is that here needed?!
This should only be used for an external node. Use add_internal_node for internal node
and if you have defined your own node type, use save_node directly to save the node (and create it yourself)
"""
if not default_alias:
node_alias = alias(name)
else:
node_alias = default_alias
node_alias = alias(name)
fullpath = os.path.join(self.data_folder, "%s.json" % node_alias)
i = 2
while os.path.isfile(fullpath):
Expand Down Expand Up @@ -247,27 +221,25 @@ def add_external_node(
return node

def save_node(self, node):
"""writes the node to disk. Will also apply a fullpath based on the datadir of the
NodeManager if the node doesn't have one."""
if not hasattr(node, "fullpath"):
node.fullpath = calc_fullpath(self.data_folder, node.alias)
write_node(node, node.fullpath)
logger.info(f"Saved new node {node.alias} at {node.fullpath}")

def add_internal_node(
self,
name,
name: str,
network="main",
port=None,
default_alias=None,
port: str = None,
datadir=None,
):
"""Adding an internal node. Params:
This should only be used for internal nodes. Use add__External_node for external nodes
and if you have defined your own node-type, use save_node directly. to save the node (and create it yourself)
"""
if not default_alias:
node_alias = alias(name)
else:
node_alias = default_alias
node_alias = alias(name)
fullpath = os.path.join(self.data_folder, "%s.json" % node_alias)
i = 2
while os.path.isfile(fullpath):
Expand Down Expand Up @@ -298,6 +270,7 @@ def add_internal_node(
return node

def delete_node(self, node, specter):
"""Deletes the node. Also from the disk."""
logger.info("Deleting {}".format(node.alias))
try:
# Delete from wallet manager
Expand All @@ -306,7 +279,7 @@ def delete_node(self, node, specter):
delete_file(node.fullpath)
delete_file(node.fullpath + ".bkp")
# Update the active node
if self._active_node == node.alias:
if self._active_node == node.alias and len(self.nodes) > 0:
specter.update_active_node(
next(iter(self.nodes.values())).alias
) # This switches to the first node in the node list, which is usually the default node
Expand Down
15 changes: 11 additions & 4 deletions src/cryptoadvance/specter/managers/wallet_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from ..helpers import add_dicts, alias, is_liquid, load_jsons
from ..liquid.wallet import LWallet
from ..persistence import delete_folder
from ..rpc import RpcError, get_default_datadir
from ..rpc import RpcError, get_default_datadir, BrokenCoreConnectionException
from ..specter_error import SpecterError, SpecterInternalException, handle_exception
from ..util.flask import FlaskThread
from ..wallet import ( # TODO: `purposes` unused here, but other files rely on this import
Expand All @@ -31,7 +31,6 @@ class WalletManager:
# chain is required to manage wallets when bitcoind is not running
def __init__(
self,
bitcoin_core_version_raw,
data_folder,
rpc,
chain,
Expand All @@ -50,8 +49,6 @@ def __init__(
# key is the name of the wallet, value is the actual instance

self.wallets = {}
# A way to communicate failed wallets to the outside
self.bitcoin_core_version_raw = bitcoin_core_version_raw
self.allow_threading_for_testing = allow_threading_for_testing
# define different wallet classes for liquid and bitcoin
self.WalletClass = LWallet if is_liquid(chain) else Wallet
Expand Down Expand Up @@ -333,6 +330,16 @@ def wallets(self, value):
self._wallets[self.chain] = {}
self._wallets[self.chain] = value

@property
def bitcoin_core_version_raw(self):
try:
bitcoin_core_version_raw = self.rpc.getnetworkinfo()["version"]
return bitcoin_core_version_raw or 200000
except BrokenCoreConnectionException:
# In good faith and in order to keep the tests running, we assume
# a reasonable core version
return 200000

def create_wallet(self, name, sigs_required, key_type, keys, devices, **kwargs):
try:
walletsindir = [
Expand Down
Loading

0 comments on commit 40a6a2e

Please sign in to comment.