diff --git a/.vscode/launch.json b/.vscode/launch.json
index ccb112863e..a633ef7dfd 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 0000000000..e137fadb9e
--- /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 d44006a265..8c27f531d1 100644
--- a/src/cryptoadvance/specter/managers/wallet_manager.py
+++ b/src/cryptoadvance/specter/managers/wallet_manager.py
@@ -249,7 +249,7 @@ def _update(self, wallets_update_list: Dict):
)
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 @@ def _update(self, wallets_update_list: Dict):
# 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 3e08f76f43..5234d74213 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 4d8f42b11f..6b8ebe9d47 100644
--- a/src/cryptoadvance/specter/txlist.py
+++ b/src/cryptoadvance/specter/txlist.py
@@ -16,6 +16,7 @@
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 @@ def __dict__(self):
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 @@ def psbt(self) -> SpecterPSBT:
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("Mode not existing")
+
@property
def category(self):
"""One of mixed (default), generate, selftransfer, receive or send"""
@@ -385,8 +406,11 @@ def flow_amount(self) -> float:
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,13 +441,13 @@ def address(self):
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
+ # 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):
@@ -474,6 +498,8 @@ def clear_cache(self):
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 d5cf555472..a071bde31e 100644
--- a/src/cryptoadvance/specter/util/common.py
+++ b/src/cryptoadvance/specter/util/common.py
@@ -4,6 +4,7 @@
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 bf4066000d..6920334d9e 100644
--- a/src/cryptoadvance/specter/wallet.py
+++ b/src/cryptoadvance/specter/wallet.py
@@ -875,7 +875,7 @@ def check_utxo(self):
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 b3b5dbc64b..2f9389791d 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 8d0c969b0c..fe5bc82224 100644 --- a/src/cryptoadvance/specterext/spectrum/spectrum_node.py +++ b/src/cryptoadvance/specterext/spectrum/spectrum_node.py @@ -224,3 +224,7 @@ def node_logo_template(self): def node_connection_template(self): return "spectrum/components/spectrum_node_connection.jinja" + + @property + def taproot_support(self): + return False