mirror of
https://github.com/cryptoadvance/specter-desktop.git
synced 2026-08-13 12:33:29 +02:00
* Bugfix: mitigating taproot hotwallet issue 2078 (#2083) * Some smaller improvements and fixes * mitigating 2078 * removed Microsoft link tracking * wrap up a failed update properly * better decode and better error_handling * kick * removed commented code
This commit is contained in:
parent
373e96eac0
commit
f2d0857bbb
9 changed files with 57 additions and 33 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
|
@ -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": [
|
||||
{
|
||||
|
|
|
|||
4
.vscode/settings.json
vendored
Normal file
4
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestEnabled": true
|
||||
}
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 ######
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -109,6 +110,7 @@
|
|||
|
||||
|
||||
} else {
|
||||
console.log(result)
|
||||
if (result == "") {
|
||||
result = "(empty string)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue