Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mitigating taproot hotwallet issue 2078 #2083

Merged
merged 6 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -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": [
{
Expand Down
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
17 changes: 8 additions & 9 deletions src/cryptoadvance/specter/managers/wallet_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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
k9ert marked this conversation as resolved.
Show resolved Hide resolved
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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 ######
Expand Down
48 changes: 37 additions & 11 deletions src/cryptoadvance/specter/txlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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):
Expand Down
9 changes: 4 additions & 5 deletions src/cryptoadvance/specter/util/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand All @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion src/cryptoadvance/specter/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
<br><br>
<input name="Submit" class="btn" type="submit" value="Submit" />
</form>
you can also do that in any javascript.console with:
Press <b>F12</b> to open the dev-console (helpful to see objects)<br>
You can also do that in any javascript.console with:
<pre>
await pythonCommand("app.specter")
await pythonCommand('app.specter')
</pre>
Some usefull idioms:
<pre>
Expand Down Expand Up @@ -109,6 +110,7 @@


} else {
console.log(result)
if (result == "") {
result = "(empty string)"
}
Expand Down
4 changes: 4 additions & 0 deletions src/cryptoadvance/specterext/spectrum/spectrum_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -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