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