Skip to content

Commit

Permalink
Feature: Deactivate hot wallets for extensions (Spectrum) for now (#1999
Browse files Browse the repository at this point in the history
)

* device based approach + prop in specter

* Revert "device based approach + prop in specter"

This reverts commit af5d6f9.

* add filter ability for nodes to reject Devices

* avoid double negation and adapt front end

* also check in new_device_type for unwanted devices

* fixes

* enable both device and device_types

* better naming

* renaming

* release test asserts

* more explicit tool-tip text for not supported device by node

Co-authored-by: Kim Neunert <k9ert@gmx.de>
  • Loading branch information
moneymanolis and k9ert authored Dec 6, 2022
1 parent f5e52fb commit 29c28db
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 16 deletions.
33 changes: 20 additions & 13 deletions src/cryptoadvance/specter/managers/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import pathlib
from flask_babel import lazy_gettext as _

from cryptoadvance.specter.devices.bitcoin_core import BitcoinCoreWatchOnly
from cryptoadvance.specter.devices.bitcoin_core import BitcoinCore, BitcoinCoreWatchOnly

from ..helpers import alias, load_jsons
from ..rpc import get_default_datadir

from ..devices import __all__ as device_classes
from ..devices import __all__ as all_device_classes
from ..devices.generic import GenericDevice # default device type
from ..persistence import write_device, delete_file, delete_folder

Expand All @@ -18,7 +18,7 @@

def get_device_class(device_type):
"""Look up device class by its type"""
for cls in device_classes:
for cls in all_device_classes:
if device_type == cls.device_type:
return cls
return GenericDevice
Expand Down Expand Up @@ -100,33 +100,40 @@ def remove_device(

@property
def supported_devices(self):
return device_classes
return all_device_classes

def supported_devices_for_chain(self, specter):
"""Devices which you can create via the UI. BitcoinCoreWatchonly is not among them
and if we have no node, hot-wallets neither. Liquid support is limited as well.
"""
if not specter.chain:
devices = [
device_classes = [
device_class
for device_class in device_classes
for device_class in all_device_classes
if device_class.device_type not in ["bitcoincore", "elementscore"]
]
elif specter.is_liquid:
devices = [
device_classes = [
device_class
for device_class in device_classes
for device_class in all_device_classes
if device_class.liquid_support
]
else:
devices = [
device_classes = [
device_class
for device_class in device_classes
for device_class in all_device_classes
if device_class.bitcoin_core_support
]
if BitcoinCoreWatchOnly in devices:
devices.remove(BitcoinCoreWatchOnly)
return devices
if BitcoinCoreWatchOnly in device_classes:
device_classes.remove(BitcoinCoreWatchOnly)

# The node might not like to have certain devices
new_device_classes = []
for device_class in device_classes:
if specter.node.is_device_supported(device_class):
new_device_classes.append(device_class)
device_classes = new_device_classes
return device_classes

def delete(self, specter):
"""Deletes all the devices"""
Expand Down
2 changes: 0 additions & 2 deletions src/cryptoadvance/specter/managers/node_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ def load_from_disk(self, data_folder=None):
default_alias=nodes_files[node_alias]["alias"],
default_fullpath=calc_fullpath(self.data_folder, node_alias),
)
print("---------------------------------------")
print(node.__class__.__module__.split("."))
if (
node.__class__.__module__.split(".")[1] == "specterext"
): # e.g. cryptoadvance.specterext.spectrum
Expand Down
20 changes: 20 additions & 0 deletions src/cryptoadvance/specter/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
import os
from os import path
import shutil
from typing import Type

from embit.liquid.networks import get_network
from flask import render_template
from flask_babel import lazy_gettext as _
from requests.exceptions import ConnectionError

from cryptoadvance.specter.devices.bitcoin_core import BitcoinCore, BitcoinCoreWatchOnly
from cryptoadvance.specter.devices.elements_core import ElementsCore

from .helpers import deep_update, is_liquid, is_testnet
from .liquid.rpc import LiquidRPC
from .persistence import PersistentObject, write_node
Expand All @@ -19,6 +23,7 @@
get_default_datadir,
)
from .specter_error import SpecterError, BrokenCoreConnectionException
from .device import Device

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -132,6 +137,21 @@ def check_blockheight(self):
"A Node Implementation need to implement the check_blockheight method"
)

def is_device_supported(self, device_class_or_device_instance):
"""Lets the node deactivate specific devices. The parameter could be a device or a device_type
You have to check yourself if overriding this method.
e.g.
if device_instance_or_device_class.__class__ == type:
device_class = device_instance_or_device_class
else:
device_class = device_instance_or_device_class.__class__
# example:
# if BitcoinCore == device_class:
# return False
return True
"""
return True

def node_info_template(self):
"""This should return the path to a Info template as string"""
return "node/components/bitcoin_core_info.jinja"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{% for device_name in specter.device_manager.devices_names %}
{% set device = specter.device_manager.devices[device_name] %}
<label style="position: relative;">
<input type="{{ 'checkbox' if wallet_type == 'multisig' else 'radio' }}" {% if wallet_type == 'simple' %} onchange="document.getElementById('submit-device').click()" {% endif %} name="devices" value="{{ device.alias }}" class="hidden" chain="{{specter.chain}}" {% if not device.has_key_types(wallet_type, specter.chain) %}disabled{% endif %}>
<input type="{{ 'checkbox' if wallet_type == 'multisig' else 'radio' }}" {% if wallet_type == 'simple' %} onchange="document.getElementById('submit-device').click()" {% endif %} name="devices" value="{{ device.alias }}" class="hidden" chain="{{specter.chain}}" {% if not device.has_key_types(wallet_type, specter.chain) or (not specter.node.is_device_supported(device)) %}disabled{% endif %}>
<div class="small-card radio" id="{{device.alias}}">
<img src="{{ url_for('static', filename=device.icon) }}" width="18px">
{{ device_name }}
Expand All @@ -24,6 +24,13 @@
</span>
</tool-tip>
{% endif %}
{% if not specter.node.is_device_supported(device) %}
<tool-tip width="150px" image="note" style="position: absolute; top: 30px; left: 25px;">
<span slot="paragraph">
{{ _("The node you are using does not support this device.") }} <br>
</span>
</tool-tip>
{% endif %}
</label>
{% endfor %}
<a href="{{ url_for('devices_endpoint.new_device_type') }}" style="text-decoration: none; color: #fff;">
Expand Down
20 changes: 20 additions & 0 deletions tests/test_managers_device.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import logging
from unittest.mock import MagicMock
from cryptoadvance.specter.devices.generic import GenericDevice
from cryptoadvance.specter.key import Key
from cryptoadvance.specter.managers.device_manager import DeviceManager
Expand Down Expand Up @@ -101,6 +102,25 @@ def test_DeviceManager(empty_data_folder, a_key, a_tpub_only_key):
assert some_device.keys[1] == a_tpub_only_key


def test_DeviceManager_supported_devices_for_chain(empty_data_folder):
# A DeviceManager manages devices, specifically the persistence
# of them via json-files in an empty data folder
dm = DeviceManager(data_folder=empty_data_folder)
specter_mock = MagicMock()
specter_mock.chain = False
device_classes = dm.supported_devices_for_chain(specter=specter_mock)
for device_class in device_classes:
assert device_class.__class__ == type
specter_mock.chain = True
device_classes = dm.supported_devices_for_chain(specter=specter_mock)
for device_class in device_classes:
assert device_class.__class__ == type
specter_mock.is_liquid = True
device_classes = dm.supported_devices_for_chain(specter=specter_mock)
for device_class in device_classes:
assert device_class.__class__ == type


def test_device_wallets(
bitcoin_regtest, devices_filled_data_folder, device_manager, caplog
):
Expand Down

0 comments on commit 29c28db

Please sign in to comment.