diff --git a/.vscode/launch.json b/.vscode/launch.json
index ccb112863..a633ef7df 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,7 +1,7 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ // For more information, visit: https://code.visualstudio.com/docs/editor/debugging#_launch-configurations
"version": "0.2.0",
"configurations": [
{
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000..e137fadb9
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,4 @@
+{
+ "python.testing.unittestEnabled": false,
+ "python.testing.pytestEnabled": true
+}
\ No newline at end of file
diff --git a/src/cryptoadvance/specter/managers/wallet_manager.py b/src/cryptoadvance/specter/managers/wallet_manager.py
index d44006a26..8c27f531d 100644
--- a/src/cryptoadvance/specter/managers/wallet_manager.py
+++ b/src/cryptoadvance/specter/managers/wallet_manager.py
@@ -249,7 +249,7 @@ class WalletManager:
)
self.wallets[wallet_name] = loaded_wallet
except Exception as e:
- handle_exception(e)
+ logger.exception(e)
self._failed_load_wallets.append(
{
**wallets_update_list[wallet],
@@ -263,14 +263,13 @@ class WalletManager:
# only ignore rpc errors
except RpcError as e:
logger.error(f"Failed updating wallet manager. RPC error: {e}")
- logger.info("Updating wallet manager done. Result:")
- logger.info(f" * loaded_wallets: {len(self.wallets)}")
- logger.info(f" * failed_load_wallets: {len(self._failed_load_wallets)}")
- for wallet in self._failed_load_wallets:
- logger.info(f" * {wallet['name']} : {wallet['loading_error']}")
-
- wallets_update_list = {}
- self.is_loading = False
+ finally:
+ self.is_loading = False
+ logger.info("Updating wallet manager done. Result:")
+ logger.info(f" * loaded_wallets: {len(self.wallets)}")
+ logger.info(f" * failed_load_wallets: {len(self._failed_load_wallets)}")
+ for wallet in self._failed_load_wallets:
+ logger.info(f" * {wallet['name']} : {wallet['loading_error']}")
def get_by_alias(self, alias):
for wallet_name in self.wallets:
diff --git a/src/cryptoadvance/specter/server_endpoints/wallets/wallets.py b/src/cryptoadvance/specter/server_endpoints/wallets/wallets.py
index 3e08f76f4..5234d7421 100644
--- a/src/cryptoadvance/specter/server_endpoints/wallets/wallets.py
+++ b/src/cryptoadvance/specter/server_endpoints/wallets/wallets.py
@@ -444,7 +444,7 @@ def history(wallet_alias):
wallet.update_balance()
wallet.check_utxo()
- renderting = render_template(
+ return render_template(
"wallet/history/wallet_history.jinja",
wallet_alias=wallet_alias,
wallet=wallet,
@@ -453,8 +453,6 @@ def history(wallet_alias):
rand=rand,
services=app.specter.service_manager.services,
)
- logger.info("-------------------end render_template()")
- return renderting
###### Wallet receive ######
diff --git a/src/cryptoadvance/specter/txlist.py b/src/cryptoadvance/specter/txlist.py
index 4d8f42b11..c6458fa29 100644
--- a/src/cryptoadvance/specter/txlist.py
+++ b/src/cryptoadvance/specter/txlist.py
@@ -16,6 +16,7 @@ from .persistence import delete_file, read_csv, write_csv
from .specter_error import SpecterError, SpecterInternalException
from embit.descriptor import Descriptor
from embit.liquid.descriptor import LDescriptor
+from .util.common import str2bool
from .util.psbt import (
AbstractTxContext,
SpecterInputScope,
@@ -84,6 +85,7 @@ class TxItem(dict, AbstractTxListContext):
"vsize",
"address",
]
+ # type_converter will be used to _read_csv to have a proper mapping
type_converter = [
str,
int,
@@ -289,13 +291,14 @@ class TxItem(dict, AbstractTxListContext):
class WalletAwareTxItem(TxItem):
PSBTCls = SpecterPSBT
+
+ # Columns for writing CSVs, type_converter for reading
columns = TxItem.columns.copy()
columns.extend(
["category", "flow_amount", "utxo_amount", "ismine"],
)
-
type_converter = TxItem.type_converter.copy()
- type_converter.extend([str, float, float, bool])
+ type_converter.extend([str, float, float, str2bool])
def __init__(self, parent, addresses, rawdir, **kwargs):
super().__init__(parent, addresses, rawdir, **kwargs)
@@ -323,6 +326,24 @@ class WalletAwareTxItem(TxItem):
self._psbt.update(updated)
return self._psbt
+ @property
+ def is_taproot(self):
+ return str(self.descriptor).startswith("tr(")
+
+ def decode_psbt(self, mode="embit") -> SpecterPSBT:
+ """Utility function which decodes this tx as psbt
+ as in the core rpc-call 'decodepsbt'.
+ However, it uses embit to calculate the details
+ use mode=core to ask core directly.
+ embit might support taproot, core might not.
+ """
+ if mode == "core":
+ return self.rpc.decodepsbt(str(self.psbt))
+ elif mode == "embit":
+ return self.psbt.to_dict()
+ else:
+ raise SpecterInternalException(f"Mode {mode} does not exist")
+
@property
def category(self):
"""One of mixed (default), generate, selftransfer, receive or send"""
@@ -385,8 +406,11 @@ class WalletAwareTxItem(TxItem):
def ismine(self) -> bool:
if self.get("ismine"):
return self["ismine"]
- inputs = self.psbt.inputs
- outputs = self.psbt.outputs
+ if self.is_taproot:
+ # This is a bug mitigation, see #2078
+ return True
+ inputs: List[SpecterInputScope] = self.psbt.inputs
+ outputs: List[SpecterOutputScope] = self.psbt.outputs
any_inputs_mine = any([inp.is_mine for inp in inputs])
any_outputs_mine = any([out.is_mine for out in outputs])
self["ismine"] = any_inputs_mine or any_outputs_mine
@@ -417,14 +441,6 @@ class WalletAwareTxItem(TxItem):
self["address"] = addresses[0]
return self["address"]
- def __dict__(self):
- super_dict = dict(self)
- super_dict["category"] = self.category
- super_dict["flow_amount"] = self.flow_amount
- super_dict["utxo_amount"] = self.utxo_amount
- super_dict["ismine"] = (self["ismine"] or self.ismine,)
- return super_dict
-
class TxList(dict, AbstractTxListContext):
"""A TxList is a dict with txids as keys and TxItems as values."""
@@ -474,6 +490,8 @@ class TxList(dict, AbstractTxListContext):
tx.clear_cache()
delete_file(self.path)
self._file_exists = False
+ self.clear()
+
logger.info(f"Cleared the Cache for {self.path} (and rawdir)")
def getfetch(self, txid):
diff --git a/src/cryptoadvance/specter/util/common.py b/src/cryptoadvance/specter/util/common.py
index d5cf55547..a071bde31 100644
--- a/src/cryptoadvance/specter/util/common.py
+++ b/src/cryptoadvance/specter/util/common.py
@@ -4,6 +4,7 @@ from datetime import datetime
import json
from flask_babel.speaklater import LazyString
from typing import Union
+from distutils.util import strtobool
logger = logging.getLogger(__name__)
@@ -12,11 +13,9 @@ def str2bool(my_str):
"""returns a reasonable boolean from a string so that "False" will result in False"""
if my_str is None:
return False
- elif isinstance(my_str, str) and my_str.lower() == "false":
- return False
- elif isinstance(my_str, str) and my_str.lower() == "off":
- return False
- return bool(my_str)
+ elif isinstance(my_str, bool):
+ return my_str
+ return bool(strtobool(my_str))
def camelcase2snake_case(name):
diff --git a/src/cryptoadvance/specter/wallet.py b/src/cryptoadvance/specter/wallet.py
index bf4066000..6920334d9 100644
--- a/src/cryptoadvance/specter/wallet.py
+++ b/src/cryptoadvance/specter/wallet.py
@@ -875,7 +875,7 @@ class Wallet:
except Exception as e:
logger.exception(e)
self._full_utxo = []
- raise SpecterError(f"Failed to load utxos, {e}")
+ raise SpecterError(f"Failed to load utxos, {type(e).__name__}: {e}")
def check_utxo_orig(self):
"""fetches the utxo-set from core and stores the result in self.__full_utxo which is
diff --git a/src/cryptoadvance/specterext/devhelp/templates/devhelp/dev-console.jinja b/src/cryptoadvance/specterext/devhelp/templates/devhelp/dev-console.jinja
index b3b5dbc64..2f9389791 100644
--- a/src/cryptoadvance/specterext/devhelp/templates/devhelp/dev-console.jinja
+++ b/src/cryptoadvance/specterext/devhelp/templates/devhelp/dev-console.jinja
@@ -27,9 +27,10 @@
- you can also do that in any javascript.console with:
+ Press F12 to open the dev-console (helpful to see objects)
+ You can also do that in any javascript.console with:
- await pythonCommand("app.specter")
+ await pythonCommand('app.specter')
Some usefull idioms:
@@ -109,6 +110,7 @@
} else {
+ console.log(result)
if (result == "") {
result = "(empty string)"
}
diff --git a/src/cryptoadvance/specterext/spectrum/spectrum_node.py b/src/cryptoadvance/specterext/spectrum/spectrum_node.py
index 8d0c969b0..fe5bc8222 100644
--- a/src/cryptoadvance/specterext/spectrum/spectrum_node.py
+++ b/src/cryptoadvance/specterext/spectrum/spectrum_node.py
@@ -224,3 +224,7 @@ class SpectrumNode(AbstractNode):
def node_connection_template(self):
return "spectrum/components/spectrum_node_connection.jinja"
+
+ @property
+ def taproot_support(self):
+ return False