diff --git a/bal.py b/bal.py
index 75b1a54..1dab674 100644
--- a/bal.py
+++ b/bal.py
@@ -1,124 +1,139 @@
-import random
import os
-import zipfile as zipfile_lib
+#import random
+#import zipfile as zipfile_lib
-from electrum.plugin import BasePlugin
from electrum import json_db
+from electrum.logging import get_logger
+from electrum.plugin import BasePlugin
from electrum.transaction import tx_from_any
-import os
+
def get_will_settings(x):
print(x)
-json_db.register_dict('heirs', tuple, None)
-json_db.register_dict('will', dict,None)
-json_db.register_dict('will_settings', lambda x:x,None)
-#{'rubiconda': ['bcrt1qgv0wu4v6kjzef5mnxfh2m9z6y7mez0ja0tt8mu', '45%', '1y'], 'veronica': ['bcrt1q6vxuvwrt8x5c9u9u29y5uq7frscr0vgc2dy60j', '15%', '1y']}
-from electrum.logging import get_logger
-def get_will_settings(x):
- print(x)
+
+json_db.register_dict("heirs", tuple, None)
+json_db.register_dict("will", dict, None)
+json_db.register_dict("will_settings", lambda x: x, None)
+
+
def get_will(x):
try:
- x['tx']=tx_from_any(x['tx'])
+ x["tx"] = tx_from_any(x["tx"])
except Exception as e:
raise e
return x
-class BalConfig():
+
+class BalConfig:
def __init__(self, config, name, default):
self.config = config
self.name = name
self.default = default
- def get(self,default=None):
+ def get(self, default=None):
v = self.config.get(self.name, default)
if v is None:
- if not default is None:
+ if default is not None:
v = default
else:
v = self.default
return v
-
- def set(self,value,save=True):
- self.config.set_key(self.name,value,save=save)
+
+ def set(self, value, save=True):
+ self.config.set_key(self.name, value, save=save)
+
class BalPlugin(BasePlugin):
- LATEST_VERSION = '1'
- KNOWN_VERSIONS = ('0', '1')
+ LATEST_VERSION = "1"
+ KNOWN_VERSIONS = ("0", "1")
assert LATEST_VERSION in KNOWN_VERSIONS
+
def version():
try:
- f=""
- with open("VERSION","r") as f:
- f = str(f.readline())
+ f = ""
+ with open("VERSION", "r") as fi:
+ f = str(fi.readline())
return f
except:
return "unknown"
+
SIZE = (159, 97)
def __init__(self, parent, config, name):
print("init bal_plugin")
self.logger = get_logger(__name__)
BasePlugin.__init__(self, parent, config, name)
- self.base_dir = os.path.join(config.electrum_path(), 'bal')
+ self.base_dir = os.path.join(config.electrum_path(), "bal")
self.plugin_dir = os.path.split(os.path.realpath(__file__))[0]
- zipfile="/".join(self.plugin_dir.split("/")[:-1])
- #print("real path",os.path.realpath(__file__))
- #self.logger.info(self.base_dir)
- #print("base_dir:", self.base_dir)
- #print("suca:",zipfile)
- #print("plugin_dir:", self.plugin_dir)
+ zipfile = "/".join(self.plugin_dir.split("/")[:-1])
+ # print("real path",os.path.realpath(__file__))
+ # self.logger.info(self.base_dir)
+ # print("base_dir:", self.base_dir)
+ # print("suca:",zipfile)
+ # print("plugin_dir:", self.plugin_dir)
import sys
+
sys.path.insert(0, zipfile)
- #print("sono state listate?")
+ # print("sono state listate?")
self.parent = parent
self.config = config
self.name = name
- self.ASK_BROADCAST = BalConfig(config, "bal_ask_broadcast", True)
- self.BROADCAST = BalConfig(config, "bal_broadcast", True)
- self.LOCKTIME_TIME = BalConfig(config, "bal_locktime_time", 90)
- self.LOCKTIME_BLOCKS = BalConfig(config, "bal_locktime_blocks", 144*90)
- self.LOCKTIMEDELTA_TIME = BalConfig(config, "bal_locktimedelta_time", 7)
- self.LOCKTIMEDELTA_BLOCKS = BalConfig(config, "bal_locktimedelta_blocks", 144*7)
- self.ENABLE_MULTIVERSE = BalConfig(config, "bal_enable_multiverse", False)
- self.TX_FEES = BalConfig(config, "bal_tx_fees", 100)
- self.INVALIDATE = BalConfig(config, "bal_invalidate", True)
- self.ASK_INVALIDATE = BalConfig(config, "bal_ask_invalidate", True)
- self.PREVIEW = BalConfig(config, "bal_preview", True)
- self.SAVE_TXS = BalConfig(config, "bal_save_txs", True)
- self.WILLEXECUTORS = BalConfig(config, "bal_willexecutors", True)
- self.PING_WILLEXECUTORS = BalConfig(config, "bal_ping_willexecutors", True)
- self.ASK_PING_WILLEXECUTORS = BalConfig(config, "bal_ask_ping_willexecutors", True)
- self.NO_WILLEXECUTOR = BalConfig(config, "bal_no_willexecutor", True)
- self.HIDE_REPLACED = BalConfig(config, "bal_hide_replaced", True)
- self.HIDE_INVALIDATED = BalConfig(config, "bal_hide_invalidated", True)
- self.ALLOW_REPUSH = BalConfig(config, "bal_allow_repush", True)
- self.FIRST_EXECUTION = BalConfig(config, "bal_first_execution", True)
- self.WILLEXECUTORS = BalConfig(config, "bal_willexecutors", {
- "mainnet": {
- 'https://we.bitcoin-after.life': {
- "base_fee": 100000,
- "status": "New",
- "info":"Bitcoin After Life Will Executor",
- "address":"bcrt1qa5cntu4hgadw8zd3n6sq2nzjy34sxdtd9u0gp7",
- "selected":True
- }
- }
- })
- self.WILL_SETTINGS = BalConfig(config, "bal_will_settings", {
- 'baltx_fees':100,
- 'threshold':'180d',
- 'locktime':'1y',
- })
+ self.ASK_BROADCAST = BalConfig(config, "bal_ask_broadcast", True)
+ self.BROADCAST = BalConfig(config, "bal_broadcast", True)
+ self.LOCKTIME_TIME = BalConfig(config, "bal_locktime_time", 90)
+ self.LOCKTIME_BLOCKS = BalConfig(config, "bal_locktime_blocks", 144 * 90)
+ self.LOCKTIMEDELTA_TIME = BalConfig(config, "bal_locktimedelta_time", 7)
+ self.LOCKTIMEDELTA_BLOCKS = BalConfig(
+ config, "bal_locktimedelta_blocks", 144 * 7
+ )
+ self.ENABLE_MULTIVERSE = BalConfig(config, "bal_enable_multiverse", False)
+ self.TX_FEES = BalConfig(config, "bal_tx_fees", 100)
+ self.INVALIDATE = BalConfig(config, "bal_invalidate", True)
+ self.ASK_INVALIDATE = BalConfig(config, "bal_ask_invalidate", True)
+ self.PREVIEW = BalConfig(config, "bal_preview", True)
+ self.SAVE_TXS = BalConfig(config, "bal_save_txs", True)
+ self.WILLEXECUTORS = BalConfig(config, "bal_willexecutors", True)
+ self.PING_WILLEXECUTORS = BalConfig(config, "bal_ping_willexecutors", True)
+ self.ASK_PING_WILLEXECUTORS = BalConfig(
+ config, "bal_ask_ping_willexecutors", True
+ )
+ self.NO_WILLEXECUTOR = BalConfig(config, "bal_no_willexecutor", True)
+ self.HIDE_REPLACED = BalConfig(config, "bal_hide_replaced", True)
+ self.HIDE_INVALIDATED = BalConfig(config, "bal_hide_invalidated", True)
+ self.ALLOW_REPUSH = BalConfig(config, "bal_allow_repush", True)
+ self.FIRST_EXECUTION = BalConfig(config, "bal_first_execution", True)
+ self.WILLEXECUTORS = BalConfig(
+ config,
+ "bal_willexecutors",
+ {
+ "mainnet": {
+ "https://we.bitcoin-after.life": {
+ "base_fee": 100000,
+ "status": "New",
+ "info": "Bitcoin After Life Will Executor",
+ "address": "bcrt1qa5cntu4hgadw8zd3n6sq2nzjy34sxdtd9u0gp7",
+ "selected": True,
+ }
+ }
+ },
+ )
+ self.WILL_SETTINGS = BalConfig(
+ config,
+ "bal_will_settings",
+ {
+ "baltx_fees": 100,
+ "threshold": "180d",
+ "locktime": "1y",
+ },
+ )
+ self._hide_invalidated = self.HIDE_INVALIDATED.get()
+ self._hide_replaced = self.HIDE_REPLACED.get()
- self._hide_invalidated= self.HIDE_INVALIDATED.get()
- self._hide_replaced= self.HIDE_REPLACED.get()
-
-
- def resource_path(self,*parts):
+ def resource_path(self, *parts):
return os.path.join(self.plugin_dir, *parts)
def hide_invalidated(self):
@@ -129,20 +144,16 @@ class BalPlugin(BasePlugin):
self._hide_replaced = not self._hide_replaced
self.HIDE_REPLACED.set(self._hide_replaced)
- def validate_will_settings(self,will_settings):
- #print(type(will_settings))
- #print(will_settings.get('baltx_fees',1),1)
- if int(will_settings.get('baltx_fees',1))<1:
- will_settings['baltx_fees']=1
- if not will_settings.get('threshold'):
- will_settings['threshold']='180d'
- if not will_settings.get('locktime')=='':
- will_settings['locktime']='1y'
+ def validate_will_settings(self, will_settings):
+ # print(type(will_settings))
+ # print(will_settings.get('baltx_fees',1),1)
+ if int(will_settings.get("baltx_fees", 1)) < 1:
+ will_settings["baltx_fees"] = 1
+ if not will_settings.get("threshold"):
+ will_settings["threshold"] = "180d"
+ if not will_settings.get("locktime") == "":
+ will_settings["locktime"] = "1y"
return will_settings
def default_will_settings(self):
- return {
- 'baltx_fees':100,
- 'threshold':'180d',
- 'locktime':'1y'
- }
+ return {"baltx_fees": 100, "threshold": "180d", "locktime": "1y"}
diff --git a/bal_resources.py b/bal_resources.py
index e6bca0d..678e192 100644
--- a/bal_resources.py
+++ b/bal_resources.py
@@ -1,15 +1,14 @@
import os
PLUGIN_DIR = os.path.split(os.path.realpath(__file__))[0]
-DEFAULT_ICON = 'bal32x32.png'
-DEFAULT_ICON_PATH = ''
+DEFAULT_ICON = "bal32x32.png"
+DEFAULT_ICON_PATH = ""
def icon_path(icon_basename: str = DEFAULT_ICON):
- path = resource_path(DEFAULT_ICON_PATH,icon_basename)
+ path = resource_path(DEFAULT_ICON_PATH, icon_basename)
return path
+
def resource_path(*parts):
return os.path.join(PLUGIN_DIR, *parts)
-
-
diff --git a/balqt/amountedit.py b/balqt/amountedit.py
deleted file mode 100644
index cc77ba6..0000000
--- a/balqt/amountedit.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from typing import Union
-from decimal import Decimal
-
-from . import qt_resources
-if qt_resources.QT_VERSION == 5:
- from PyQt5.QtWidgets import (QLineEdit, QStyle, QStyleOptionFrame, QSizePolicy)
- from PyQt5.QtGui import QPalette, QPainter
- from PyQt5.QtCore import pyqtSignal, Qt, QSize
-else:
- from PyQt6.QtWidgets import (QLineEdit, QStyle, QStyleOptionFrame, QSizePolicy)
- from PyQt6.QtGui import QPalette, QPainter
- from PyQt6.QtCore import pyqtSignal, Qt, QSize
-
-
-from electrum.util import (format_satoshis_plain, decimal_point_to_base_unit_name,
- FEERATE_PRECISION, quantize_feerate, DECIMAL_POINT, UI_UNIT_NAME_FEERATE_SAT_PER_VBYTE)
-
-from electrum.gui.qt.amountedit import BTCAmountEdit, char_width_in_lineedit, ColorScheme
-
-_NOT_GIVEN = object() # sentinel value
-
-
-class PercAmountEdit(BTCAmountEdit):
- def __init__(self, decimal_point, is_int=False, parent=None, *, max_amount=_NOT_GIVEN):
- super().__init__(decimal_point, is_int, parent, max_amount=max_amount)
-
- def numbify(self):
- text = self.text().strip()
- if text == '!':
- self.shortcut.emit()
- return
- pos = self.cursorPosition()
- chars = '0123456789%'
- chars += DECIMAL_POINT
-
- s = ''.join([i for i in text if i in chars])
-
- if '%' in s:
- self.is_perc=True
- s=s.replace('%','')
- else:
- self.is_perc=False
-
- if DECIMAL_POINT in s:
- p = s.find(DECIMAL_POINT)
- s = s.replace(DECIMAL_POINT, '')
- s = s[:p] + DECIMAL_POINT + s[p:p+8]
- if self.is_perc:
- s+='%'
-
-
- #if self.max_amount:
- # if (amt := self._get_amount_from_text(s)) and amt >= self.max_amount:
- # s = self._get_text_from_amount(self.max_amount)
- self.setText(s)
- # setText sets Modified to False. Instead we want to remember
- # if updates were because of user modification.
- self.setModified(self.hasFocus())
- self.setCursorPosition(pos)
- #if len(s>0)
- # self.drawText("")
-
- def _get_amount_from_text(self, text: str) -> Union[None, Decimal, int]:
- try:
- text = text.replace(DECIMAL_POINT, '.')
- text = text.replace('%', '')
- return (Decimal)(text)
- except Exception:
- return None
-
- def _get_text_from_amount(self, amount):
- out = super()._get_text_from_amount(amount)
- if self.is_perc: out+='%'
- return out
-
- def paintEvent(self, event):
- QLineEdit.paintEvent(self, event)
- if self.base_unit:
- panel = QStyleOptionFrame()
- self.initStyleOption(panel)
- textRect = self.style().subElementRect(QStyle.SubElement.SE_LineEditContents, panel, self)
- textRect.adjust(2, 0, -10, 0)
- painter = QPainter(self)
- painter.setPen(ColorScheme.GRAY.as_color())
- if len(self.text())==0:
- painter.drawText(textRect, int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter), self.base_unit() + " or perc value")
-
diff --git a/balqt/baldialog.py b/balqt/baldialog.py
deleted file mode 100644
index 86dacfb..0000000
--- a/balqt/baldialog.py
+++ /dev/null
@@ -1,102 +0,0 @@
-from typing import Callable,Any
-
-from . import qt_resources
-if qt_resources.QT_VERSION == 5:
- from PyQt5.QtCore import Qt,pyqtSignal
- from PyQt5.QtWidgets import QLabel, QVBoxLayout, QCheckBox
-else:
- from PyQt6.QtCore import Qt,pyqtSignal
- from PyQt6.QtWidgets import QLabel, QVBoxLayout, QCheckBox
-
-from electrum.gui.qt.util import WindowModalDialog, TaskThread
-from electrum.i18n import _
-from electrum.logging import get_logger
-
-_logger = get_logger(__name__)
-
-class BalDialog(WindowModalDialog):
-
- def __init__(self,parent,title=None, icon = 'bal32x32.png'):
- self.parent=parent
- WindowModalDialog.__init__(self,self.parent,title)
- self.setWindowIcon(qt_resources.read_QIcon(icon))
-
-class BalWaitingDialog(BalDialog):
- updatemessage=pyqtSignal([str], arguments=['message'])
- def __init__(self, bal_window: 'BalWindow', message: str, task, on_success=None, on_error=None, on_cancel=None,exe=True):
- assert bal_window
- BalDialog.__init__(self, bal_window.window, _("Please wait"))
- self.message_label = QLabel(message)
- vbox = QVBoxLayout(self)
- vbox.addWidget(self.message_label)
- self.updatemessage.connect(self.update_message)
- if on_cancel:
- self.cancel_button = CancelButton(self)
- self.cancel_button.clicked.connect(on_cancel)
- vbox.addLayout(Buttons(self.cancel_button))
- self.accepted.connect(self.on_accepted)
- self.task=task
- self.on_success = on_success
- self.on_error = on_error
- self.on_cancel = on_cancel
- if exe:
- self.exe()
-
- def exe(self):
- self.thread = TaskThread(self)
- self.thread.finished.connect(self.deleteLater) # see #3956
- self.thread.finished.connect(self.finished)
- self.thread.add(self.task, self.on_success, self.accept, self.on_error)
- self.exec()
-
- def hello(self):
- pass
- def finished(self):
- _logger.info("finished")
- def wait(self):
- self.thread.wait()
-
- def on_accepted(self):
- self.thread.stop()
- def update_message(self,msg):
- self.message_label.setText(msg)
-
- def update(self, msg):
- self.updatemessage.emit(msg)
-
- def getText(self):
- return self.message_label.text()
-
- def closeEvent(self,event):
- self.thread.stop()
-
-
-
-class BalBlockingWaitingDialog(BalDialog):
- def __init__(self, bal_window: 'BalWindow', message: str, task: Callable[[], Any]):
- BalDialog.__init__(self, bal_window, _("Please wait"))
- self.message_label = QLabel(message)
- vbox = QVBoxLayout(self)
- vbox.addWidget(self.message_label)
- self.finished.connect(self.deleteLater) # see #3956
- # show popup
- self.show()
- # refresh GUI; needed for popup to appear and for message_label to get drawn
- QCoreApplication.processEvents()
- QCoreApplication.processEvents()
- try:
- # block and run given task
- task()
- finally:
- # close popup
- self.accept()
-
-class bal_checkbox(QCheckBox):
- def __init__(self, plugin,variable,window=None):
- QCheckBox.__init__(self)
- self.setChecked(plugin.config_get(variable))
- def on_check(v):
- plugin.config.set_key(variable, v == 2)
- plugin.config_get(variable)
- self.stateChanged.connect(on_check)
-
diff --git a/balqt/closedialog.py b/balqt/closedialog.py
deleted file mode 100644
index 595129d..0000000
--- a/balqt/closedialog.py
+++ /dev/null
@@ -1,384 +0,0 @@
-from .baldialog import BalDialog
-from . import qt_resources
-
-if qt_resources.QT_VERSION == 5:
- from PyQt5.QtCore import Qt
- from PyQt5.QtWidgets import QLabel, QVBoxLayout, QCheckBox,QWidget
- from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject,QEventLoop
-else:
- from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject,QEventLoop
- from PyQt6.QtCore import Qt
- from PyQt6.QtWidgets import QLabel, QVBoxLayout, QCheckBox, QWidget
-import time
-from electrum.i18n import _
-from electrum.gui.qt.util import WindowModalDialog, TaskThread
-from electrum.network import Network,TxBroadcastError, BestEffortRequestFailed
-from electrum.logging import get_logger
-
-
-from functools import partial
-import copy
-
-from .. import util as Util
-from .. import will as Will
-
-from .. import willexecutors as Willexecutors
-_logger = get_logger(__name__)
-
-
-class BalCloseDialog(BalDialog):
- updatemessage=pyqtSignal()
- def __init__(self,bal_window):
- BalDialog.__init__(self,bal_window.window,"Closing BAL")
- self.updatemessage.connect(self.update)
- self.bal_window=bal_window
- self.message_label = QLabel("Closing BAL:")
- self.vbox = QVBoxLayout(self)
- self.vbox.addWidget(self.message_label)
- self.qwidget=QWidget()
- self.vbox.addWidget(self.qwidget)
- self.labels=[]
- #self.checking.connect(self.msg_set_checking)
- #self.invalidating.connect(self.msg_set_invalidating)
- #self.building.connect(self.msg_set_building)
- #self.signing.connect(self.msg_set_signing)
- #self.pushing.connect(self.msg_set_pushing)
-
- #self.askpassword.connect(self.ask_password)
- #self.passworddone.connect(self.password_done)
- self.check_row = None
- self.inval_row = None
- self.build_row = None
- self.sign_row = None
- self.push_row = None
- self.network = Network.get_instance()
- self._stopping = False
- self.thread = TaskThread(self)
- self.thread.finished.connect(self.task_finished) # see #3956
- def task_finished(self):
- pass
- #_logger.trace("task finished")
-
- def close_plugin_task(self):
- _logger.debug("close task to be started")
- self.thread.add(self.task_phase1,on_success=self.on_success_phase1,on_done=self.on_accept,on_error=self.on_error_phase1)
- self.show()
- self.exec()
-
- def task_phase1(self):
- _logger.debug("close plugin phase 1 started")
- try:
- self.bal_window.init_class_variables()
- except Will.NoHeirsException:
- return False, None
- self.msg_set_status("checking variables","Waiting")
- try:
- Will.check_amounts(self.bal_window.heirs,self.bal_window.willexecutors,self.bal_window.window.wallet.get_utxos(),self.bal_window.date_to_check,self.bal_window.window.wallet.dust_threshold())
- except Will.AmountException:
- self.msg_edit_row(''+_("In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts"+""))
- #self.bal_window.show_warning(_("In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts"),parent=self)
-
- self.msg_set_checking()
- have_to_build=False
- try:
- self.bal_window.check_will()
- self.msg_set_checking('Ok')
- except Will.WillExpiredException as e:
- self.msg_set_checking("Expired")
- fee_per_byte=self.bal_window.will_settings.get('tx_fees',1)
- return None, Will.invalidate_will(self.bal_window.willitems,self.bal_window.wallet,fee_per_byte)
- except Will.NoHeirsException:
- self.msg_set_checking("No Heirs")
- except Will.NotCompleteWillException as e:
- message = False
- have_to_build=True
- if isinstance(e,Will.HeirChangeException):
- message ="Heirs changed:"
- elif isinstance(e,Will.WillExecutorNotPresent):
- message = "Will-Executor not present"
- elif isinstance(e,Will.WillexecutorChangeException):
- message = "Will-Executor changed"
- elif isinstance(e,Will.TxFeesChangedException):
- message = "Txfees are changed"
- elif isinstance(e,Will.HeirNotFoundException):
- message = "Heir not found"
- if message:
- self.msg_set_checking(message)
- else:
- self.msg_set_checking("New")
-
- if have_to_build:
- self.msg_set_building()
- try:
- self.bal_window.build_will()
- self.bal_window.check_will()
- for wid in Will.only_valid(self.bal_window.willitems):
- self.bal_window.wallet.set_label(wid,"BAL Transaction")
- self.msg_set_building("Ok")
- except Exception as e:
- self.msg_set_building(self.msg_error(e))
- return False,None
- have_to_sign = False
- for wid in Will.only_valid(self.bal_window.willitems):
- if not self.bal_window.willitems[wid].get_status("COMPLETE"):
- have_to_sign = True
- break
- return have_to_sign, None
-
- def on_accept(self):
- pass
-
- def on_accept_phase2(self):
- pass
-
- def on_error_push(self):
- pass
-
- def wait(self,secs):
- wait_row=None
- for i in range(secs,0,-1):
- if self._stopping:
- return
- wait_row = self.msg_edit_row(f"Please wait {i}secs", wait_row)
- time.sleep(1)
- self.msg_del_row(wait_row)
-
- def loop_broadcast_invalidating(self,tx):
- self.msg_set_invalidating("Broadcasting")
- try:
- tx.add_info_from_wallet(self.bal_window.wallet)
- self.network.run_from_another_thread(tx.add_info_from_network(self.network))
- txid = self.network.run_from_another_thread(self.network.broadcast_transaction(tx,timeout=120),timeout=120)
- self.msg_set_invalidating("Ok")
- if not txid:
- _logger.debug(f"should not be none txid: {txid}")
-
-
- except TxBroadcastError as e:
- _logger.error(e)
- msg = e.get_message_for_gui()
- self.msg_set_invalidating(self.msg_error(msg))
- except BestEffortRequestFailed as e:
- self.msg_set_invalidating(self.msg_error(e))
- # self.loop_broadcast_invalidating(tx)
-
- def loop_push(self):
- self.msg_set_pushing("Broadcasting")
- retry = False
- try:
- willexecutors=Willexecutors.get_willexecutor_transactions(self.bal_window.willitems)
- for url,willexecutor in willexecutors.items():
- try:
- if Willexecutors.is_selected(self.bal_window.willexecutors.get(url)):
- _logger.debug(f"{url}: {willexecutor}")
- if not Willexecutors.push_transactions_to_willexecutor(willexecutor):
- for wid in willexecutor['txsids']:
- self.bal_window.willitems[wid].set_status('PUSH_FAIL',True)
- retry=True
- else:
- for wid in willexecutor['txsids']:
- self.bal_window.willitems[wid].set_status('PUSHED',True)
- except Willexecutors.AlreadyPresentException:
- for wid in willexecutor['txsids']:
- row = self.msg_edit_row("checking {} - {} : {}".format(self.bal_window.willitems[wid].we['url'],wid, "Waiting"))
- self.bal_window.willitems[wid].check_willexecutor()
- row = self.msg_edit_row("checked {} - {} : {}".format(self.bal_window.willitems[wid].we['url'],wid,self.bal_window.willitems[wid].get_status("CHECKED" )),row)
-
-
- except Exception as e:
-
- _logger.error(e)
- raise e
- if retry:
- raise Exception("retry")
-
- except Exception as e:
- self.msg_set_pushing(self.msg_error(e))
- self.wait(10)
- if not self._stopping:
- self.loop_push()
-
-
- def invalidate_task(self,tx,password):
- _logger.debug(f"invalidate tx: {tx}")
- tx = self.bal_window.wallet.sign_transaction(tx,password)
- try:
- if tx:
- if tx.is_complete():
- self.loop_broadcast_invalidating(tx)
- self.wait(5)
- else:
- raise
- else:
- raise
- except Exception as e:
- self.msg_set_invalidating("Error")
- raise Exception("Impossible to sign")
- def on_success_invalidate(self,success):
- self.thread.add(self.task_phase1,on_success=self.on_success_phase1,on_done=self.on_accept,on_error=self.on_error_phase1)
- def on_error(self,error):
- _logger.error(error)
- pass
- def on_success_phase1(self,result):
- self.have_to_sign,tx = list(result)
- #if have_to_sign is False and tx is None:
- #self._stopping=True
- #self.on_success_phase2()
- # return
- _logger.debug("have to sign {}".format(self.have_to_sign))
- password=None
- if self.have_to_sign is None:
- self.msg_set_invalidating()
- #need to sign invalidate and restart phase 1
-
- password = self.bal_window.get_wallet_password("Invalidate your old will",parent=self.bal_window.window)
- if password is False:
- self.msg_set_invalidating("Aborted")
- self.wait(3)
- self.close()
- return
- self.thread.add(partial(self.invalidate_task,tx,password),on_success=self.on_success_invalidate, on_done=self.on_accept, on_error=self.on_error)
-
- return
-
- elif self.have_to_sign:
- password = self.bal_window.get_wallet_password("Sign your will",parent=self.bal_window.window)
- if password is False:
- self.msg_set_signing('Aborted')
- else:
- self.msg_set_signing('Nothing to do')
- self.thread.add(partial(self.task_phase2,password),on_success=self.on_success_phase2,on_done=self.on_accept_phase2,on_error=self.on_error_phase2)
- return
-
- def on_success_phase2(self,arg=False):
- self.thread.stop()
- self.bal_window.save_willitems()
- self.msg_edit_row("Finished")
- self.close()
-
- def closeEvent(self,event):
- self._stopping=True
- self.thread.stop()
-
- def task_phase2(self,password):
- if self.have_to_sign:
- try:
- if txs:=self.bal_window.sign_transactions(password):
- for txid,tx in txs.items():
- self.bal_window.willitems[txid].tx = copy.deepcopy(tx)
- self.bal_window.save_willitems()
- self.msg_set_signing("Ok")
- except Exception as e:
- self.msg_set_signing(self.msg_error(e))
-
- self.msg_set_pushing()
- have_to_push = False
- for wid in Will.only_valid(self.bal_window.willitems):
- w=self.bal_window.willitems[wid]
- if w.we and w.get_status("COMPLETE") and not w.get_status("PUSHED"):
- have_to_push = True
- if not have_to_push:
- self.msg_set_pushing("Nothing to do")
- else:
- try:
- self.loop_push()
- self.msg_set_pushing("Ok")
-
- except Exception as e:
- self.msg_set_pushing(self.msg_error(e))
- self.msg_edit_row("Ok")
- self.wait(5)
-
- def on_error_phase1(self,error):
- _logger.error(f"error phase1: {error}")
-
- def on_error_phase2(self,error):
- _logger.error("error phase2: { error}")
-
-
- def msg_set_checking(self, status = None, row = None):
- row = self.check_row if row is None else row
- self.check_row = self.msg_set_status("Checking your will", row, status)
-
- def msg_set_invalidating(self, status = None, row = None):
- row = self.inval_row if row is None else row
- self.inval_row = self.msg_set_status("Invalidating old will", self.inval_row, status)
-
- def msg_set_building(self, status = None, row = None):
- row = self.build_row if row is None else row
- self.build_row = self.msg_set_status("Building your will", self.build_row, status)
-
- def msg_set_signing(self, status = None, row = None):
- row = self.sign_row if row is None else row
- self.sign_row = self.msg_set_status("Signing your will", self.sign_row, status)
-
- def msg_set_pushing(self, status = None, row = None):
- row = self.push_row if row is None else row
- self.push_row = self.msg_set_status("Broadcasting your will to executors", self.push_row, status)
-
- def msg_set_waiting(self, status = None, row = None):
- row = self.wait_row if row is None else row
- self.wait_row = self.msg_edit_row(f"Please wait {status}secs", self.wait_row)
-
- def msg_error(self,e):
- return "Error: {}".format(e)
-
- def msg_set_status(self,msg,row,status=None):
- status= "Wait" if status is None else status
- line="{}:\t{}".format(_(msg), status)
- return self.msg_edit_row(line,row)
-
- #return v$msg_edit_row("{}:\t{}".format(_(msg), status), row)
-
- def ask_password(self,msg=None):
- self.password=self.bal_window.get_wallet_password(msg,parent=self)
-
- def msg_edit_row(self,line,row=None):
- _logger.debug(f"{row},{line}")
-
- #msg=self.get_text()
- #rows=msg.split("\n")
- #try:
- # rows[row]=line
- #except Exception as e:
- # rows.append(line)
- #row=len(rows)-1
- #self.update("\n".join(rows))
-
- #return row
-
- #def msg_edit_label(self,line,row=None):
- #_logger.trace(f"{row},{line}")
-
- #msg=self.get_text()
- #rows=msg.split("\n")
- try:
- self.labels[row]=line
- except Exception as e:
- self.labels.append(line)
- row=len(self.labels)-1
-
- self.updatemessage.emit()
-
- return row
-
- def msg_del_row(self,row):
- #_logger.trace(f"del row: {row}")
- try:
- del self.labels[row]
- except Exception as e:
- pass
- self.updatemessage.emit()
-
- def update(self):
- self.vbox.removeWidget(self.qwidget)
- self.qwidget=QWidget(self)
- labelsbox = QVBoxLayout(self.qwidget)
- for label in self.labels:
- labelsbox.addWidget(QLabel(label))
- self.vbox.addWidget(self.qwidget)
-
- def get_text(self):
- return self.message_label.text()
-def ThreadStopped(Exception):
- pass
diff --git a/balqt/heir_list.py b/balqt/heir_list.py
deleted file mode 100644
index cb2fa50..0000000
--- a/balqt/heir_list.py
+++ /dev/null
@@ -1,283 +0,0 @@
-#!/usr/bin/env python
-#
-# Electrum - lightweight Bitcoin client
-# Copyright (C) 2015 Thomas Voegtlin
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import enum
-from typing import TYPE_CHECKING
-from datetime import datetime
-
-from . import qt_resources
-if qt_resources.QT_VERSION == 5:
- from PyQt5.QtGui import QStandardItemModel, QStandardItem
- from PyQt5.QtCore import Qt, QPersistentModelIndex, QModelIndex
- from PyQt5.QtWidgets import (QAbstractItemView, QMenu,QWidget,QHBoxLayout,QLabel,QSpinBox,QPushButton)
-else:
- from PyQt6.QtGui import QStandardItemModel, QStandardItem
- from PyQt6.QtCore import Qt, QPersistentModelIndex, QModelIndex
- from PyQt6.QtWidgets import (QAbstractItemView, QMenu,QWidget,QHBoxLayout,QLabel,QSpinBox,QPushButton)
-
-from electrum.i18n import _
-from electrum.bitcoin import is_address
-from electrum.util import block_explorer_URL
-from electrum.plugin import run_hook
-from electrum.gui.qt.util import webopen, MessageBoxMixin,HelpButton
-from electrum.gui.qt.my_treeview import MyTreeView, MySortModel
-
-from .. import util as Util
-from .locktimeedit import HeirsLockTimeEdit
-if TYPE_CHECKING:
- from electrum.gui.qt.main_window import ElectrumWindow
-
-
-class HeirList(MyTreeView,MessageBoxMixin):
-
- class Columns(MyTreeView.BaseColumnsEnum):
- NAME = enum.auto()
- ADDRESS = enum.auto()
- AMOUNT = enum.auto()
-
- headers = {
- Columns.NAME: _('Name'),
- Columns.ADDRESS: _('Address'),
- Columns.AMOUNT: _('Amount'),
- #Columns.LOCKTIME:_('LockTime'),
- }
- filter_columns = [Columns.NAME, Columns.ADDRESS]
-
- ROLE_SORT_ORDER = Qt.ItemDataRole.UserRole + 1000
-
- ROLE_HEIR_KEY = Qt.ItemDataRole.UserRole + 1001
- key_role = ROLE_HEIR_KEY
-
- def __init__(self, bal_window: 'BalWindow'):
- super().__init__(
- parent=bal_window.window,
- main_window=bal_window.window,
- stretch_column=self.Columns.NAME,
- editable_columns=[self.Columns.NAME,self.Columns.ADDRESS,self.Columns.AMOUNT],
- )
- self.decimal_point = bal_window.bal_plugin.config.get_decimal_point()
- self.bal_window = bal_window
-
- try:
- self.setModel(QStandardItemModel(self))
- self.sortByColumn(self.Columns.NAME, Qt.SortOrder.AscendingOrder)
- self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
- except:
- pass
- #self.sortByColumn(self.Columns.NAME, Qt.SortOrder.AscendingOrder)
- #self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
-
- self.setSortingEnabled(True)
- self.std_model = self.model()
-
- self.update()
-
-
- def on_edited(self, idx, edit_key, *, text):
- original = prior_name = self.bal_window.heirs.get(edit_key)
- if not prior_name:
- return
- col = idx.column()
- try:
- #if col == 3:
- # try:
- # text = Util.str_to_locktime(text)
- # except:
- # print("not a valid locktime")
- # pass
- if col == 2:
- text = Util.encode_amount(text,self.decimal_point)
- elif col == 0:
- self.bal_window.delete_heirs([edit_key])
- edit_key = text
- prior_name[col-1] = text
- prior_name.insert(0,edit_key)
- prior_name = tuple(prior_name)
- except Exception as e:
- #print("eccezione tupla",e)
- prior_name = (edit_key,)+prior_name[:col-1]+(text,)+prior_name[col:]
- #print("prior_name",prior_name,original)
-
- try:
- self.bal_window.set_heir(prior_name)
- #print("setheir")
- except Exception as e:
- pass
-
- #print("heir non valido ripristino l'originale",e)
- try:
- #print("setup_original",(edit_key,)+original)
- self.bal_window.set_heir((edit_key,)+original)
- except Exception as e:
- #print("errore nellimpostare original",e,original)
- self.update()
-
- def create_menu(self, position):
- menu = QMenu()
- idx = self.indexAt(position)
- column = idx.column() or self.Columns.NAME
- selected_keys = []
- for s_idx in self.selected_in_column(self.Columns.NAME):
- #print(s_idx)
- sel_key = self.model().itemFromIndex(s_idx).data(0)
- selected_keys.append(sel_key)
- if selected_keys and idx.isValid():
- column_title = self.model().horizontalHeaderItem(column).text()
- column_data = '\n'.join(self.model().itemFromIndex(s_idx).text()
- for s_idx in self.selected_in_column(column))
- menu.addAction(_("Copy {}").format(column_title), lambda: self.place_text_on_clipboard(column_data, title=column_title))
- if column in self.editable_columns:
- item = self.model().itemFromIndex(idx)
- if item.isEditable():
- # would not be editable if openalias
- persistent = QPersistentModelIndex(idx)
- menu.addAction(_("Edit {}").format(column_title), lambda p=persistent: self.edit(QModelIndex(p)))
- menu.addAction(_("Delete"), lambda: self.bal_window.delete_heirs(selected_keys))
- menu.exec(self.viewport().mapToGlobal(position))
-
- def update(self):
- if self.maybe_defer_update():
- return
- current_key = self.get_role_data_for_current_item(col=self.Columns.NAME, role=self.ROLE_HEIR_KEY)
- self.model().clear()
- self.update_headers(self.__class__.headers)
- set_current = None
- for key in sorted(self.bal_window.heirs.keys()):
- heir = self.bal_window.heirs[key]
- labels = [""] * len(self.Columns)
- labels[self.Columns.NAME] = key
- labels[self.Columns.ADDRESS] = heir[0]
- labels[self.Columns.AMOUNT] = Util.decode_amount(heir[1],self.decimal_point)
- #labels[self.Columns.LOCKTIME] = str(Util.locktime_to_str(heir[2]))
-
- items = [QStandardItem(x) for x in labels]
- items[self.Columns.NAME].setEditable(True)
- items[self.Columns.ADDRESS].setEditable(True)
- items[self.Columns.AMOUNT].setEditable(True)
- #items[self.Columns.LOCKTIME].setEditable(True)
- items[self.Columns.NAME].setData(key, self.ROLE_HEIR_KEY+1)
- items[self.Columns.ADDRESS].setData(key, self.ROLE_HEIR_KEY+2)
- items[self.Columns.AMOUNT].setData(key, self.ROLE_HEIR_KEY+3)
- #items[self.Columns.LOCKTIME].setData(key, self.ROLE_HEIR_KEY+4)
-
- self.model().insertRow(self.model().rowCount(), items)
-
- if key == current_key:
- idx = self.model().index(row_count, self.Columns.NAME)
- set_current = QPersistentModelIndex(idx)
- self.set_current_idx(set_current)
- # FIXME refresh loses sort order; so set "default" here:
- self.filter()
- run_hook('update_heirs_tab', self)
-
- def refresh_row(self, key, row):
- # nothing to update here
- pass
-
- def get_edit_key_from_coordinate(self, row, col):
- #print("role_data",self.get_role_data_from_coordinate(row, col, role=self.ROLE_HEIR_KEY))
- #print(col)
- return self.get_role_data_from_coordinate(row, col, role=self.ROLE_HEIR_KEY+col+1)
- return col
-
- def create_toolbar(self, config):
- toolbar, menu = self.create_toolbar_with_menu('')
- menu.addAction(_("&New Heir"), self.bal_window.new_heir_dialog)
- menu.addAction(_("Import"), self.bal_window.import_heirs)
- menu.addAction(_("Export"), lambda: self.bal_window.export_heirs())
- #menu.addAction(_("Build Traonsactions"), self.build_transactions)
-
- self.heir_locktime = HeirsLockTimeEdit(self.window(),0)
- def on_heir_locktime():
- if not self.heir_locktime.get_locktime():
- self.heir_locktime.set_locktime('1y')
- self.bal_window.will_settings['locktime'] = self.heir_locktime.get_locktime() if self.heir_locktime.get_locktime() else "1y"
- self.bal_window.bal_plugin.config.set_key('will_settings',self.bal_window.will_settings,save = True)
- self.heir_locktime.valueEdited.connect(on_heir_locktime)
-
- self.heir_threshold = HeirsLockTimeEdit(self,0)
- def on_heir_threshold():
- if not self.heir_threshold.get_locktime():
- self.heir_threshold.set_locktime('180d')
-
- self.bal_window.will_settings['threshold'] = self.heir_threshold.get_locktime()
- self.bal_window.bal_plugin.config.set_key('will_settings',self.bal_window.will_settings,save = True)
- self.heir_threshold.valueEdited.connect(on_heir_threshold)
-
- self.heir_tx_fees = QSpinBox()
- self.heir_tx_fees.setMinimum(1)
- self.heir_tx_fees.setMaximum(10000)
- def on_heir_tx_fees():
- if not self.heir_tx_fees.value():
- self.heir_tx_fees.set_value(1)
- self.bal_window.will_settings['tx_fees'] = self.heir_tx_fees.value()
- self.bal_window.bal_plugin.config.set_key('will_settings',self.bal_window.will_settings,save = True)
- self.heir_tx_fees.valueChanged.connect(on_heir_tx_fees)
-
-
- self.heirs_widget = QWidget()
- layout = QHBoxLayout()
- self.heirs_widget.setLayout(layout)
-
- layout.addWidget(QLabel(_("Delivery Time:")))
- layout.addWidget(self.heir_locktime)
- layout.addWidget(HelpButton(_("Locktime* to be used in the transaction\n"
- +"if you choose Raw, you can insert various options based on suffix:\n"
- #+" - b: number of blocks after current block(ex: 144b means tomorrow)\n"
- +" - d: number of days after current day(ex: 1d means tomorrow)\n"
- +" - y: number of years after currrent day(ex: 1y means one year from today)\n"
- +"* locktime can be anticipated to update will\n")))
-
- layout.addWidget(QLabel(" "))
- layout.addWidget(QLabel(_("Check Alive:")))
- layout.addWidget(self.heir_threshold)
- layout.addWidget(HelpButton(_("Check to ask for invalidation.\n"
- +"When less then this time is missing, ask to invalidate.\n"
- +"If you fail to invalidate during this time, your transactions will be delivered to your heirs.\n"
- +"if you choose Raw, you can insert various options based on suffix:\n"
- #+" - b: number of blocks after current block(ex: 144b means tomorrow)\n"
- +" - d: number of days after current day(ex: 1d means tomorrow).\n"
- +" - y: number of years after currrent day(ex: 1y means one year from today).\n\n")))
- layout.addWidget(QLabel(" "))
- layout.addWidget(QLabel(_("Fees:")))
- layout.addWidget(self.heir_tx_fees)
- layout.addWidget(HelpButton(_("Fee to be used in the transaction")))
- layout.addWidget(QLabel("sats/vbyte"))
- layout.addWidget(QLabel(" "))
- newHeirButton = QPushButton(_("New Heir"))
- newHeirButton.clicked.connect(self.bal_window.new_heir_dialog)
- layout.addWidget(newHeirButton)
-
- toolbar.insertWidget(2, self.heirs_widget)
-
- return toolbar
- def update_will_settings(self):
- self.heir_threshold.set_locktime(self.bal_window.will_settings['threshold'])
- self.heir_locktime.set_locktime(self.bal_window.will_settings['locktime'])
- self.heir_tx_fees.setValue(int(self.bal_window.will_settings['tx_fees']))
-
- def build_transactions(self):
- will = self.bal_window.prepare_will()
-
diff --git a/balqt/locktimeedit.py b/balqt/locktimeedit.py
deleted file mode 100644
index cfc1ff2..0000000
--- a/balqt/locktimeedit.py
+++ /dev/null
@@ -1,255 +0,0 @@
-# Copyright (C) 2020 The Electrum developers
-# Distributed under the MIT software license, see the accompanying
-# file LICENCE or http://www.opensource.org/licenses/mit-license.php
-
-import time
-from datetime import datetime
-from typing import Optional, Any
-
-from . import qt_resources
-if qt_resources.QT_VERSION == 5:
- from PyQt5.QtCore import Qt, QDateTime, pyqtSignal
- from PyQt5.QtGui import QPalette, QPainter
- from PyQt5.QtWidgets import (QWidget, QLineEdit, QStyle, QStyleOptionFrame, QComboBox, QHBoxLayout, QDateTimeEdit)
-else:
- from PyQt6.QtCore import Qt, QDateTime, pyqtSignal
- from PyQt6.QtGui import QPalette, QPainter
- from PyQt6.QtWidgets import (QWidget, QLineEdit, QStyle, QStyleOptionFrame, QComboBox, QHBoxLayout, QDateTimeEdit)
-
-from electrum.i18n import _
-from electrum.bitcoin import NLOCKTIME_MIN, NLOCKTIME_MAX, NLOCKTIME_BLOCKHEIGHT_MAX
-
-from electrum.gui.qt.util import char_width_in_lineedit, ColorScheme
-
-
-class HeirsLockTimeEdit(QWidget):
-
- valueEdited = pyqtSignal()
- locktime_threshold = 50000000
- def __init__(self, parent=None,default_index = 1):
- QWidget.__init__(self, parent)
-
- hbox = QHBoxLayout()
- self.setLayout(hbox)
- hbox.setContentsMargins(0, 0, 0, 0)
- hbox.setSpacing(0)
-
- self.locktime_raw_e = LockTimeRawEdit(self,time_edit = self)
- #self.locktime_height_e = LockTimeHeightEdit(self)
- self.locktime_date_e = LockTimeDateEdit(self,time_edit = self)
- #self.editors = [self.locktime_raw_e, self.locktime_height_e, self.locktime_date_e]
- self.editors = [self.locktime_raw_e, self.locktime_date_e]
-
- self.combo = QComboBox()
- #options = [_("Raw"), _("Block height"), _("Date")]
- options = [_("Raw"),_("Date")]
- self.option_index_to_editor_map = {
- 0: self.locktime_raw_e,
- #1: self.locktime_height_e,
- 1: self.locktime_date_e,
- #2: self.locktime_date_e,
- }
- self.combo.addItems(options)
-
-
- self.editor = self.option_index_to_editor_map[default_index]
- self.combo.currentIndexChanged.connect(self.on_current_index_changed)
- self.combo.setCurrentIndex(default_index)
- self.on_current_index_changed(default_index)
-
- hbox.addWidget(self.combo)
- for w in self.editors:
- hbox.addWidget(w)
- hbox.addStretch(1)
-
- #self.locktime_height_e.textEdited.connect(self.valueEdited.emit)
- self.locktime_raw_e.editingFinished.connect(self.valueEdited.emit)
- self.locktime_date_e.dateTimeChanged.connect(self.valueEdited.emit)
- self.combo.currentIndexChanged.connect(self.valueEdited.emit)
-
- def on_current_index_changed(self,i):
- for w in self.editors:
- w.setVisible(False)
- w.setEnabled(False)
- prev_locktime = self.editor.get_locktime()
- self.editor = self.option_index_to_editor_map[i]
- if self.editor.is_acceptable_locktime(prev_locktime):
- self.editor.set_locktime(prev_locktime,force=True)
- self.editor.setVisible(True)
- self.editor.setEnabled(True)
-
- def get_locktime(self) -> Optional[str]:
- return self.editor.get_locktime()
-
- def set_index(self,index):
- self.combo.setCurrentIndex(index)
- self.on_current_index_changed(index)
-
- def set_locktime(self, x: Any,force=True) -> None:
- self.editor.set_locktime(x,force)
-
-
-class _LockTimeEditor:
- min_allowed_value = NLOCKTIME_MIN
- max_allowed_value = NLOCKTIME_MAX
-
- def get_locktime(self) -> Optional[int]:
- raise NotImplementedError()
-
- def set_locktime(self, x: Any,force=True) -> None:
- raise NotImplementedError()
-
- @classmethod
- def is_acceptable_locktime(cls, x: Any) -> bool:
- if not x: # e.g. empty string
- return True
- try:
- x = int(x)
- except Exception as e:
- return False
- return cls.min_allowed_value <= x <= cls.max_allowed_value
-
-
-class LockTimeRawEdit(QLineEdit, _LockTimeEditor):
-
- def __init__(self, parent=None,time_edit=None):
- QLineEdit.__init__(self, parent)
- self.setFixedWidth(14 * char_width_in_lineedit())
- self.textChanged.connect(self.numbify)
- self.isdays = False
- self.isyears = False
- self.isblocks = False
- self.time_edit=time_edit
-
- def replace_str(self,text):
- return str(text).replace('d','').replace('y','').replace('b','')
-
- def checkbdy(self,s,pos,appendix):
- try:
- charpos = pos-1
- charpos = max(0,charpos)
- charpos = min(len(s)-1,charpos)
- if appendix == s[charpos]:
- s=self.replace_str(s)+appendix
- pos = charpos
- except Exception as e:
- pass
- return pos, s
-
- def numbify(self):
- text = self.text().strip()
- #chars = '0123456789bdy' removed the option to choose locktime by block
- chars = '0123456789dy'
- pos = posx = self.cursorPosition()
- pos = len(''.join([i for i in text[:pos] if i in chars]))
- s = ''.join([i for i in text if i in chars])
- self.isdays = False
- self.isyears = False
- self.isblocks = False
-
- pos,s = self.checkbdy(s,pos,'d')
- pos,s = self.checkbdy(s,pos,'y')
- pos,s = self.checkbdy(s,pos,'b')
-
- if 'd' in s: self.isdays = True
- if 'y' in s: self.isyears = True
- if 'b' in s: self.isblocks = True
-
-
- if self.isdays: s= self.replace_str(s) + 'd'
- if self.isyears: s = self.replace_str(s) + 'y'
- if self.isblocks: s= self.replace_str(s) + 'b'
-
- self.set_locktime(s,force=False)
- # setText sets Modified to False. Instead we want to remember
- # if updates were because of user modification.
- self.setModified(self.hasFocus())
- self.setCursorPosition(pos)
-
- def get_locktime(self) -> Optional[str]:
- try:
- return str(self.text())
- except Exception as e:
- return None
-
- def set_locktime(self, x: Any,force=True) -> None:
- out = str(x)
- if 'd' in out:
- out = self.replace_str(x)+'d'
- elif 'y' in out:
- out = self.replace_str(x)+'y'
- elif 'b' in out:
- out = self.replace_str(x)+'b'
- else:
- try:
- out = int(x)
- except Exception as e:
- self.setText('')
- return
- out = max(out, self.min_allowed_value)
- out = min(out, self.max_allowed_value)
- self.setText(str(out))
- #try:
- # if self.time_edit and int(out)>self.time_edit.locktime_threshold and not force:
- # self.time_edit.set_index(1)
- #except:
- # pass
-
-class LockTimeHeightEdit(LockTimeRawEdit):
- max_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX
-
- def __init__(self, parent=None,time_edit=None):
- LockTimeRawEdit.__init__(self, parent)
- self.setFixedWidth(20 * char_width_in_lineedit())
- self.time_edit = time_edit
-
- def paintEvent(self, event):
- super().paintEvent(event)
- panel = QStyleOptionFrame()
- self.initStyleOption(panel)
- textRect = self.style().subElementRect(QStyle.SE_LineEditContents, panel, self)
- textRect.adjust(2, 0, -10, 0)
- painter = QPainter(self)
- painter.setPen(ColorScheme.GRAY.as_color())
- painter.drawText(textRect, int(Qt.AlignRight | Qt.AlignVCenter), "height")
-
-
-def get_max_allowed_timestamp() -> int:
- ts = NLOCKTIME_MAX
- # Test if this value is within the valid timestamp limits (which is platform-dependent).
- # see #6170
- try:
- datetime.fromtimestamp(ts)
- except (OSError, OverflowError):
- ts = 2 ** 31 - 1 # INT32_MAX
- datetime.fromtimestamp(ts) # test if raises
- return ts
-
-
-class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
- min_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX + 1
- max_allowed_value = get_max_allowed_timestamp()
-
- def __init__(self, parent=None,time_edit=None):
- QDateTimeEdit.__init__(self, parent)
- self.setMinimumDateTime(datetime.fromtimestamp(self.min_allowed_value))
- self.setMaximumDateTime(datetime.fromtimestamp(self.max_allowed_value))
- self.setDateTime(QDateTime.currentDateTime())
- self.time_edit = time_edit
-
- def get_locktime(self) -> Optional[int]:
- dt = self.dateTime().toPyDateTime()
- locktime = int(time.mktime(dt.timetuple()))
- return locktime
-
- def set_locktime(self, x: Any,force = False) -> None:
- if not self.is_acceptable_locktime(x):
- self.setDateTime(QDateTime.currentDateTime())
- return
- try:
- x = int(x)
- except Exception:
- self.setDateTime(QDateTime.currentDateTime())
- return
- dt = datetime.fromtimestamp(x)
- self.setDateTime(dt)
diff --git a/balqt/preview_dialog.py b/balqt/preview_dialog.py
deleted file mode 100644
index 92a7688..0000000
--- a/balqt/preview_dialog.py
+++ /dev/null
@@ -1,331 +0,0 @@
-
-import enum
-import copy
-import json
-import urllib.request
-import urllib.parse
-from functools import partial
-
-from . import qt_resources
-if qt_resources.QT_VERSION == 5:
- from PyQt5.QtGui import QStandardItemModel, QStandardItem, QPalette, QColor
- from PyQt5.QtCore import Qt,QPersistentModelIndex, QModelIndex
- from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,QMenu,QAbstractItemView,QWidget)
-else:
- from PyQt6.QtGui import QStandardItemModel, QStandardItem, QPalette, QColor
- from PyQt6.QtCore import Qt,QPersistentModelIndex, QModelIndex
- from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,QMenu,QAbstractItemView,QWidget)
-
-from electrum.i18n import _
-from electrum.gui.qt.util import (Buttons,read_QIcon, import_meta_gui, export_meta_gui,MessageBoxMixin)
-from electrum.util import write_json_file,read_json_file,FileImportFailed
-from electrum.gui.qt.my_treeview import MyTreeView
-from electrum.transaction import tx_from_any
-from electrum.network import Network
-
-
-from ..bal import BalPlugin
-from .. import willexecutors as Willexecutors
-from .. import util as Util
-from .. import will as Will
-from .baldialog import BalDialog
-
-class PreviewList(MyTreeView):
- class Columns(MyTreeView.BaseColumnsEnum):
- LOCKTIME = enum.auto()
- TXID = enum.auto()
- WILLEXECUTOR = enum.auto()
- STATUS = enum.auto()
-
- headers = {
- Columns.LOCKTIME: _('Locktime'),
- Columns.TXID: _('Txid'),
- Columns.WILLEXECUTOR: _('Will-Executor'),
- Columns.STATUS: _('Status'),
- }
-
- ROLE_HEIR_KEY = Qt.ItemDataRole.UserRole + 2000
- key_role = ROLE_HEIR_KEY
-
- def __init__(self, parent: 'BalWindow',will):
- super().__init__(
- parent=parent.window,
- stretch_column=self.Columns.TXID,
- )
- self.decimal_point=parent.bal_plugin.config.get_decimal_point
- self.setModel(QStandardItemModel(self))
- self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
-
-
- if not will is None:
- self.will = will
- else:
- self.will = parent.willitems
-
- self.bal_window = parent
- self.wallet=parent.window.wallet
- self.setModel(QStandardItemModel(self))
- self.setSortingEnabled(True)
- self.std_model = self.model()
- self.config = parent.bal_plugin.config
- self.bal_plugin=self.bal_window.bal_plugin
-
- self.update()
-
- def create_menu(self, position):
- menu = QMenu()
- idx = self.indexAt(position)
- column = idx.column() or self.Columns.TXID
- selected_keys = []
- for s_idx in self.selected_in_column(self.Columns.TXID):
- sel_key = self.model().itemFromIndex(s_idx).data(0)
- selected_keys.append(sel_key)
- if selected_keys and idx.isValid():
- column_title = self.model().horizontalHeaderItem(column).text()
- column_data = '\n'.join(self.model().itemFromIndex(s_idx).text()
- for s_idx in self.selected_in_column(column))
-
- menu.addAction(_("details").format(column_title), lambda: self.show_transaction(selected_keys)).setEnabled(len(selected_keys)<2)
- menu.addAction(_("check ").format(column_title), lambda: self.check_transactions(selected_keys))
-
- menu.addSeparator()
- menu.addAction(_("delete").format(column_title), lambda: self.delete(selected_keys))
-
- menu.exec(self.viewport().mapToGlobal(position))
-
- def delete(self,selected_keys):
- for key in selected_keys:
- del self.will[key]
- try:
- del self.bal_window.willitems[key]
- except:
- pass
- try:
- del self.bal_window.will[key]
- except:
- pass
- self.update()
-
- def check_transactions(self,selected_keys):
- wout = {}
- for k in selected_keys:
- wout[k] = self.will[k]
- if wout:
- self.bal_window.check_transactions(wout)
- self.update()
-
- def show_transaction(self,selected_keys):
- for key in selected_keys:
- self.bal_window.show_transaction(self.will[key].tx)
-
- self.update()
-
- def select(self,selected_keys):
- self.selected += selected_keys
- self.update()
-
- def deselect(self,selected_keys):
- for key in selected_keys:
- self.selected.remove(key)
- self.update()
-
- def update_will(self,will):
- self.will.update(will)
- self.update()
-
- def update(self):
- if self.will is None:
- return
-
- current_key = self.get_role_data_for_current_item(col=self.Columns.TXID, role=self.ROLE_HEIR_KEY)
- self.model().clear()
- self.update_headers(self.__class__.headers)
-
-
-
-
- set_current = None
- for txid,bal_tx in self.will.items():
- if self.bal_window.bal_plugin._hide_replaced and bal_tx.get_status('REPLACED'):
- continue
- if self.bal_window.bal_plugin._hide_invalidated and bal_tx.get_status('INVALIDATED'):
- continue
-
-
- tx=bal_tx.tx
- labels = [""] * len(self.Columns)
- labels[self.Columns.LOCKTIME] = Util.locktime_to_str(tx.locktime)
- labels[self.Columns.TXID] = txid
- we = 'None'
- if bal_tx.we:
- we = bal_tx.we['url']
- labels[self.Columns.WILLEXECUTOR]=we
- status = bal_tx.status
- if len(bal_tx.status) > 53:
- status = "...{}".format(status[-50:])
- labels[self.Columns.STATUS] = status
-
-
-
- items=[]
- for e in labels:
- if type(e)== list:
- try:
- items.append(QStandardItem(*e))
- except Exception as e:
- pass
- else:
- items.append(QStandardItem(str(e)))
-
- #pal = QPalette()
- #pal.setColor(QPalette.ColorRole.Window, QColor(bal_tx.get_color()))
- #items[-1].setAutoFillBackground(True)
- #items[-1o].setPalette(pal)
- items[-1].setBackground(QColor(bal_tx.get_color()))
-
-
- self.model().insertRow(self.model().rowCount(), items)
- if txid == current_key:
- idx = self.model().index(row_count, self.Columns.TXID)
- set_current = QPersistentModelIndex(idx)
- self.set_current_idx(set_current)
-
- def create_toolbar(self, config):
- toolbar, menu = self.create_toolbar_with_menu('')
- menu.addAction(_("Prepare"), self.build_transactions)
- menu.addAction(_("Display"), self.bal_window.preview_modal_dialog)
- menu.addAction(_("Sign"), self.ask_password_and_sign_transactions)
- menu.addAction(_("Export"), self.export_will)
- #menu.addAction(_("Import"), self.import_will)
- menu.addAction(_("Broadcast"), self.broadcast)
- menu.addAction(_("Check"), self.check)
- menu.addAction(_("Invalidate"), self.invalidate_will)
- prepareButton = QPushButton(_("Prepare"))
- prepareButton.clicked.connect(self.build_transactions)
- signButton = QPushButton(_("Sign"))
- signButton.clicked.connect(self.ask_password_and_sign_transactions)
- pushButton = QPushButton(_("Broadcast"))
- pushButton.clicked.connect(self.broadcast)
- displayButton = QPushButton(_("Display"))
- displayButton.clicked.connect(self.bal_window.preview_modal_dialog)
- hlayout = QHBoxLayout()
- widget = QWidget()
- hlayout.addWidget(prepareButton)
- hlayout.addWidget(signButton)
- hlayout.addWidget(pushButton)
- hlayout.addWidget(displayButton)
- widget.setLayout(hlayout)
- toolbar.insertWidget(2,widget)
-
- return toolbar
-
- def hide_replaced(self):
- self.bal_window.bal_plugin.hide_replaced()
- self.update()
-
- def hide_invalidated(self):
- f.bal_window.bal_plugin.hide_invalidated()
- self.update()
-
- def build_transactions(self):
- will = self.bal_window.prepare_will()
- if will:
- self.update_will(will)
-
- def export_json_file(self,path):
- write_json_file(path, self.will)
-
- def export_will(self):
- self.bal_window.export_will()
- self.update()
-
- def import_will(self):
- self.bal_window.import_will()
-
- def ask_password_and_sign_transactions(self):
- self.bal_window.ask_password_and_sign_transactions(callback=self.update)
-
- def broadcast(self):
- self.bal_window.broadcast_transactions()
- self.update()
-
- def check(self):
- self.bal_window.check_transactions(self.bal_window.willitems)
- self.update()
-
- def invalidate_will(self):
- self.bal_window.invalidate_will()
- self.update()
-
-class PreviewDialog(BalDialog,MessageBoxMixin):
- def __init__(self, bal_window, will):
- self.parent = bal_window.window
- BalDialog.__init__(self,bal_window = bal_window)
- self.bal_plugin = bal_window.bal_plugin
- self.gui_object = self.bal_plugin.gui_object
- self.config = self.bal_plugin.config
- self.bal_window = bal_window
- self.wallet = bal_window.window.wallet
- self.format_amount = bal_window.window.format_amount
- self.base_unit = bal_window.window.base_unit
- self.format_fiat_and_units = bal_window.window.format_fiat_and_units
- self.fx = bal_window.window.fx
- self.format_fee_rate = bal_window.window.format_fee_rate
- self.show_address = bal_window.window.show_address
- if not will:
- self.will = bal_window.willitems
- else:
- self.will = will
- self.setWindowTitle(_('Transactions Preview'))
- self.setMinimumSize(1000, 200)
- self.size_label = QLabel()
- self.transactions_list = PreviewList(self.bal_window,self.will)
- vbox = QVBoxLayout(self)
- vbox.addWidget(self.size_label)
- vbox.addWidget(self.transactions_list)
- buttonbox = QHBoxLayout()
-
- b = QPushButton(_('Sign'))
- b.clicked.connect(self.transactions_list.ask_password_and_sign_transactions)
- buttonbox.addWidget(b)
-
- b = QPushButton(_('Export Will'))
- b.clicked.connect(self.transactions_list.export_will)
- buttonbox.addWidget(b)
-
- b = QPushButton(_('Broadcast'))
- b.clicked.connect(self.transactions_list.broadcast)
- buttonbox.addWidget(b)
-
- b = QPushButton(_('Invalidate will'))
- b.clicked.connect(self.transactions_list.invalidate_will)
- buttonbox.addWidget(b)
-
- vbox.addLayout(buttonbox)
-
- self.update()
-
-
- def update_will(self,will):
- self.will.update(will)
- self.transactions_list.update_will(will)
- self.update()
-
- def update(self):
- self.transactions_list.update()
-
- def is_hidden(self):
- return self.isMinimized() or self.isHidden()
-
- def show_or_hide(self):
- if self.is_hidden():
- self.bring_to_top()
- else:
- self.hide()
-
- def bring_to_top(self):
- self.show()
- self.raise_()
-
- def closeEvent(self, event):
- event.accept()
diff --git a/balqt/qt_resources.py b/balqt/qt_resources.py
deleted file mode 100644
index 5b05954..0000000
--- a/balqt/qt_resources.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from .. import bal_resources
-import sys
-try:
- QT_VERSION=sys._GUI_QT_VERSION
-except:
- QT_VERSION=6
-if QT_VERSION == 5:
- from PyQt5.QtGui import QIcon,QPixmap
-else:
- from PyQt6.QtGui import QIcon,QPixmap
-
-def read_QIcon(icon_basename: str=bal_resources.DEFAULT_ICON) -> QIcon:
- return QIcon(bal_resources.icon_path(icon_basename))
-def read_QPixmap(icon_basename: str=bal_resources.DEFAULT_ICON) -> QPixmap:
- return QPixmap(bal_resources.icon_path(icon_basename))
-
diff --git a/balqt/willdetail.py b/balqt/willdetail.py
deleted file mode 100644
index 11bc42c..0000000
--- a/balqt/willdetail.py
+++ /dev/null
@@ -1,199 +0,0 @@
-from functools import partial
-
-from . import qt_resources
-if qt_resources.QT_VERSION == 5:
- from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,QWidget,QScrollArea)
- from PyQt5.QtGui import (QPixmap, QImage, QBitmap, QPainter, QFontDatabase, QPen, QFont,
- QColor, QDesktopServices, qRgba, QPainterPath,QPalette)
-else:
- from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,QWidget,QScrollArea)
- from PyQt6.QtGui import (QPixmap, QImage, QBitmap, QPainter, QFontDatabase, QPen, QFont,
- QColor, QDesktopServices, qRgba, QPainterPath,QPalette)
-
-
-from electrum.util import decimal_point_to_base_unit_name
-from electrum.i18n import _
-
-from ..bal import BalPlugin
-from .. import will as Will
-from .. import util as Util
-from .baldialog import BalDialog
-
-
-
-
-
-
-class WillDetailDialog(BalDialog):
-
-
- def __init__(self, bal_window):
-
- self.will = bal_window.willitems
- self.threshold = Util.parse_locktime_string(bal_window.will_settings['threshold'])
- self.bal_window = bal_window
- Will.add_willtree(self.will)
- super().__init__(bal_window.window)
- self.config = bal_window.window.config
- self.wallet = bal_window.wallet
- self.format_amount = bal_window.window.format_amount
- self.base_unit = bal_window.window.base_unit
- self.format_fiat_and_units = bal_window.window.format_fiat_and_units
- self.fx = bal_window.window.fx
- self.format_fee_rate = bal_window.window.format_fee_rate
- self.decimal_point = bal_window.bal_plugin.config.get_decimal_point()
- self.base_unit_name = decimal_point_to_base_unit_name(self.decimal_point)
- self.setWindowTitle(_('Will Details'))
- self.setMinimumSize(670,700)
- self.vlayout= QVBoxLayout()
- w=QWidget()
- hlayout = QHBoxLayout(w)
-
- b = QPushButton(_('Sign'))
- b.clicked.connect(self.ask_password_and_sign_transactions)
- hlayout.addWidget(b)
-
- b = QPushButton(_('Broadcast'))
- b.clicked.connect(self.broadcast_transactions)
- hlayout.addWidget(b)
-
- b = QPushButton(_('Export'))
- b.clicked.connect(self.export_will)
- hlayout.addWidget(b)
- """
- toggle = "Hide"
- if self.bal_window.bal_plugin._hide_replaced:
- toggle = "Unhide"
- self.toggle_replace_button = QPushButton(_(f"{toggle} replaced"))
- self.toggle_replace_button.clicked.connect(self.toggle_replaced)
- hlayout.addWidget(self.toggle_replace_button)
-
- toggle = "Hide"
- if self.bal_window.bal_plugin._hide_invalidated:
- toggle = "Unhide"
-
- self.toggle_invalidate_button = QPushButton(_(f"{toggle} invalidated"))
- self.toggle_invalidate_button.clicked.connect(self.toggle_invalidated)
- hlayout.addWidget(self.toggle_invalidate_button)
- """
- b = QPushButton(_('Invalidate'))
- b.clicked.connect(bal_window.invalidate_will)
- hlayout.addWidget(b)
- self.vlayout.addWidget(w)
-
- self.paint_scroll_area()
- #vlayout.addWidget(QLabel(_("DON'T PANIC !!! everything is fine, all possible futures are covered")))
- self.vlayout.addWidget(QLabel(_("Expiration date: ")+Util.locktime_to_str(self.threshold)))
- self.vlayout.addWidget(self.scrollbox)
- w=QWidget()
- hlayout = QHBoxLayout(w)
- hlayout.addWidget(QLabel(_("Valid Txs:")+ str(len(Will.only_valid_list(self.will)))))
- hlayout.addWidget(QLabel(_("Total Txs:")+ str(len(self.will))))
- self.vlayout.addWidget(w)
- self.setLayout(self.vlayout)
-
- def paint_scroll_area(self):
- #self.scrollbox.deleteLater()
- #self.willlayout.deleteLater()
- #self.detailsWidget.deleteLater()
- self.scrollbox = QScrollArea()
- viewport = QWidget(self.scrollbox)
- self.willlayout = QVBoxLayout(viewport)
- self.detailsWidget = WillWidget(parent=self)
- self.willlayout.addWidget(self.detailsWidget)
-
- self.scrollbox.setWidget(viewport)
- viewport.setLayout(self.willlayout)
- def ask_password_and_sign_transactions(self):
- self.bal_window.ask_password_and_sign_transactions(callback=self.update)
- self.update()
- def broadcast_transactions(self):
- self.bal_window.broadcast_transactions()
- self.update()
- def export_will(self):
- self.bal_window.export_will()
- def toggle_replaced(self):
- self.bal_window.bal_plugin.hide_replaced()
- toggle = _("Hide")
- if self.bal_window.bal_plugin._hide_replaced:
- toggle = _("Unhide")
- self.toggle_replace_button.setText(f"{toggle} {_('replaced')}")
- self.update()
-
- def toggle_invalidated(self):
- self.bal_window.bal_plugin.hide_invalidated()
- toggle = _("Hide")
- if self.bal_window.bal_plugin._hide_invalidated:
- toggle = _("Unhide")
- self.toggle_invalidate_button.setText(_(f"{toggle} {_('invalidated')}"))
- self.update()
-
- def update(self):
- self.will = self.bal_window.willitems
- pos = self.vlayout.indexOf(self.scrollbox)
- self.vlayout.removeWidget(self.scrollbox)
- self.paint_scroll_area()
- self.vlayout.insertWidget(pos,self.scrollbox)
- super().update()
-
-class WillWidget(QWidget):
- def __init__(self,father=None,parent = None):
- super().__init__()
- vlayout = QVBoxLayout()
- self.setLayout(vlayout)
- self.will = parent.bal_window.willitems
- self.parent = parent
- for w in self.will:
- if self.will[w].get_status('REPLACED') and self.parent.bal_window.bal_plugin._hide_replaced:
- continue
- if self.will[w].get_status('INVALIDATED') and self.parent.bal_window.bal_plugin._hide_invalidated:
- continue
- f = self.will[w].father
- if father == f:
- qwidget = QWidget()
- childWidget = QWidget()
- hlayout=QHBoxLayout(qwidget)
- qwidget.setLayout(hlayout)
- vlayout.addWidget(qwidget)
- detailw=QWidget()
- detaillayout=QVBoxLayout()
- detailw.setLayout(detaillayout)
-
- willpushbutton = QPushButton(w)
-
- willpushbutton.clicked.connect(partial(self.parent.bal_window.show_transaction,txid=w))
- detaillayout.addWidget(willpushbutton)
- locktime = Util.locktime_to_str(self.will[w].tx.locktime)
- creation = Util.locktime_to_str(self.will[w].time)
- def qlabel(title,value):
- label = ""+_(str(title)) + f":\t{str(value)}"
- return QLabel(label)
- detaillayout.addWidget(qlabel("Locktime",locktime))
- detaillayout.addWidget(qlabel("Creation Time",creation))
- total_fees = self.will[w].tx.input_value() - self.will[w].tx.output_value()
- decoded_fees = total_fees #Util.decode_amount(total_fees,self.parent.decimal_point)
- fee_per_byte = round(total_fees/self.will[w].tx.estimated_size(),3)
- fees_str = str(decoded_fees) + " ("+ str(fee_per_byte) + " sats/vbyte)"
- detaillayout.addWidget(qlabel("Transaction fees:",fees_str))
- detaillayout.addWidget(qlabel("Status:",self.will[w].status))
- detaillayout.addWidget(QLabel(""))
- detaillayout.addWidget(QLabel("Heirs:"))
- for heir in self.will[w].heirs:
- if "w!ll3x3c\"" not in heir:
- decoded_amount = Util.decode_amount(self.will[w].heirs[heir][3],self.parent.decimal_point)
- detaillayout.addWidget(qlabel(heir,f"{decoded_amount} {self.parent.base_unit_name}"))
- if self.will[w].we:
- detaillayout.addWidget(QLabel(""))
- detaillayout.addWidget(QLabel(_("Willexecutor:HEIR_REAL_AMOUNT:
+ if len(heir) > HEIR_REAL_AMOUNT:
real_amount = heir[HEIR_REAL_AMOUNT]
out_amount += real_amount
description += f"{name}\n"
- paid_heirs[name]=heir
- outputs.append(PartialTxOutput.from_address_and_value(heir[HEIR_ADDRESS], real_amount))
+ paid_heirs[name] = heir
+ outputs.append(
+ PartialTxOutput.from_address_and_value(
+ heir[HEIR_ADDRESS], real_amount
+ )
+ )
else:
pass
except Exception as e:
@@ -109,35 +132,42 @@ def prepare_transactions(locktimes, available_utxos, fees, wallet):
pass
if int(in_amount) < int(out_amount):
break
- heirsvalue=out_amount
+ heirsvalue = out_amount
change = get_change_output(wallet, in_amount, out_amount, fee)
if change:
outputs.append(change)
- for i in range(0,100):
+ for i in range(0, 100):
random.shuffle(outputs)
print(outputs)
- tx = PartialTransaction.from_io(used_utxos, outputs, locktime=Util.parse_locktime_string(locktime,wallet), version=2)
- if len(description)>0: tx.description = description[:-1]
- else: tx.description = ""
+ tx = PartialTransaction.from_io(
+ used_utxos,
+ outputs,
+ locktime=Util.parse_locktime_string(locktime, wallet),
+ version=2,
+ )
+ if len(description) > 0:
+ tx.description = description[:-1]
+ else:
+ tx.description = ""
tx.heirsvalue = heirsvalue
- tx.set_rbf(True)
+ tx.set_rbf(True)
tx.remove_signatures()
txid = tx.txid()
if txid is None:
- raise Exception("txid is none",tx)
-
+ raise Exception("txid is none", tx)
+
tx.heirs = paid_heirs
tx.my_locktime = locktime
- txsout[txid]=tx
-
+ txsout[txid] = tx
+
if change:
- change_idx=tx.get_output_idxs_from_address(change.address)
+ change_idx = tx.get_output_idxs_from_address(change.address)
prevout = TxOutpoint(txid=bfh(tx.txid()), out_idx=change_idx.pop())
txin = PartialTxInput(prevout=prevout)
txin._trusted_value_sats = change.value
txin.script_descriptor = change.script_descriptor
- txin.is_mine=True
- txin._TxInput__address=change.address
+ txin.is_mine = True
+ txin._TxInput__address = change.address
txin._TxInput__scriptpubkey = change.scriptpubkey
txin._TxInput__value_sats = change.value
txin.utxo = tx
@@ -146,67 +176,74 @@ def prepare_transactions(locktimes, available_utxos, fees, wallet):
return txsout
-def get_utxos_from_inputs(tx_inputs,tx,utxos):
+def get_utxos_from_inputs(tx_inputs, tx, utxos):
for tx_input in tx_inputs:
- prevoutstr=tx_input.prevout.to_str()
- utxos[prevoutstr] =utxos.get(prevoutstr,{'input':tx_input,'txs':[]})
- utxos[prevoutstr]['txs'].append(tx)
+ prevoutstr = tx_input.prevout.to_str()
+ utxos[prevoutstr] = utxos.get(prevoutstr, {"input": tx_input, "txs": []})
+ utxos[prevoutstr]["txs"].append(tx)
return utxos
-#TODO calculate de minimum inputs to be invalidated
+
+# TODO calculate de minimum inputs to be invalidated
def invalidate_inheritance_transactions(wallet):
listids = []
utxos = {}
dtxs = {}
- for k,v in wallet.get_all_labels().items():
+ for k, v in wallet.get_all_labels().items():
tx = None
if TRANSACTION_LABEL == v:
- tx=wallet.adb.get_transaction(k)
+ tx = wallet.adb.get_transaction(k)
if tx:
- dtxs[tx.txid()]=tx
- get_utxos_from_inputs(tx.inputs(),tx,utxos)
+ dtxs[tx.txid()] = tx
+ get_utxos_from_inputs(tx.inputs(), tx, utxos)
- for key,utxo in utxos.items():
- txid=key.split(":")[0]
+ for key, utxo in utxos.items():
+ txid = key.split(":")[0]
if txid in dtxs:
- for tx in utxo['txs']:
- txid =tx.txid()
+ for tx in utxo["txs"]:
+ txid = tx.txid()
del dtxs[txid]
-
+
utxos = {}
- for txid,tx in dtxs.items():
- get_utxos_from_inputs(tx.inputs(),tx,utxos)
+ for txid, tx in dtxs.items():
+ get_utxos_from_inputs(tx.inputs(), tx, utxos)
- utxos = sorted(utxos.items(), key = lambda item: len(item[1]))
+ utxos = sorted(utxos.items(), key=lambda item: len(item[1]))
-
- remaining={}
+ remaining = {}
invalidated = []
- for key,value in utxos:
- for tx in value['txs']:
+ for key, value in utxos:
+ for tx in value["txs"]:
txid = tx.txid()
if not txid in invalidated:
invalidated.append(tx.txid())
remaining[key] = value
-def print_transaction(heirs,tx,locktimes,tx_fees):
- jtx=tx.to_json()
+
+def print_transaction(heirs, tx, locktimes, tx_fees):
+ jtx = tx.to_json()
print(f"TX: {tx.txid()}\t-\tLocktime: {jtx['locktime']}")
print(f"---")
for inp in jtx["inputs"]:
print(f"{inp['address']}: {inp['value_sats']}")
print(f"---")
for out in jtx["outputs"]:
- heirname=""
+ heirname = ""
for key in heirs.keys():
- heir=heirs[key]
- if heir[HEIR_ADDRESS] == out['address'] and str(heir[HEIR_LOCKTIME]) == str(jtx['locktime']):
- heirname=key
+ heir = heirs[key]
+ if heir[HEIR_ADDRESS] == out["address"] and str(heir[HEIR_LOCKTIME]) == str(
+ jtx["locktime"]
+ ):
+ heirname = key
print(f"{heirname}\t{out['address']}: {out['value_sats']}")
print()
size = tx.estimated_size()
- print("fee: {}\texpected: {}\tsize: {}".format(tx.input_value()-tx.output_value(), size*tx_fees, size))
+ print(
+ "fee: {}\texpected: {}\tsize: {}".format(
+ tx.input_value() - tx.output_value(), size * tx_fees, size
+ )
+ )
print()
try:
@@ -215,30 +252,32 @@ def print_transaction(heirs,tx,locktimes,tx_fees):
print("impossible to serialize")
print()
-def get_change_output(wallet,in_amount,out_amount,fee):
+
+def get_change_output(wallet, in_amount, out_amount, fee):
change_amount = int(in_amount - out_amount - fee)
if change_amount > wallet.dust_threshold():
change_addresses = wallet.get_change_addresses_for_new_transaction()
out = PartialTxOutput.from_address_and_value(change_addresses[0], change_amount)
out.is_change = True
return out
-
+
+
class Heirs(dict, Logger):
- def __init__(self, db: 'WalletDB'):
+ def __init__(self, db: "WalletDB"):
Logger.__init__(self)
self.db = db
- d = self.db.get('heirs', {})
+ d = self.db.get("heirs", {})
try:
self.update(d)
except e as Exception:
return
- def invalidate_transactions(self,wallet):
+ def invalidate_transactions(self, wallet):
invalidate_inheritance_transactions(wallet)
def save(self):
- self.db.put('heirs', dict(self))
+ self.db.put("heirs", dict(self))
def import_file(self, path):
data = read_json_file(path)
@@ -259,25 +298,33 @@ class Heirs(dict, Logger):
self.save()
return res
- def get_locktimes(self,from_locktime, a=False):
+ def get_locktimes(self, from_locktime, a=False):
locktimes = {}
for key in self.keys():
locktime = Util.parse_locktime_string(self[key][HEIR_LOCKTIME])
- if locktime > from_locktime and not a \
- or locktime <=from_locktime and a:
- locktimes[int(locktime)]=None
+ if locktime > from_locktime and not a or locktime <= from_locktime and a:
+ locktimes[int(locktime)] = None
return locktimes.keys()
def check_locktime(self):
return False
- def normalize_perc(self, heir_list, total_balance, relative_balance,wallet,real=False):
+ def normalize_perc(
+ self, heir_list, total_balance, relative_balance, wallet, real=False
+ ):
amount = 0
- for key,v in heir_list.items():
+ for key, v in heir_list.items():
try:
column = HEIR_AMOUNT
- if real: column = HEIR_REAL_AMOUNT
- value = int(math.floor(total_balance/relative_balance*self.amount_to_float(v[column])))
+ if real:
+ column = HEIR_REAL_AMOUNT
+ value = int(
+ math.floor(
+ total_balance
+ / relative_balance
+ * self.amount_to_float(v[column])
+ )
+ )
if value > wallet.dust_threshold():
heir_list[key].insert(HEIR_REAL_AMOUNT, value)
amount += value
@@ -286,7 +333,7 @@ class Heirs(dict, Logger):
raise e
return amount
- def amount_to_float(self,amount):
+ def amount_to_float(self, amount):
try:
return float(amount)
except:
@@ -295,92 +342,114 @@ class Heirs(dict, Logger):
except:
return 0.0
- def fixed_percent_lists_amount(self,from_locktime,dust_threshold,reverse = False):
+ def fixed_percent_lists_amount(self, from_locktime, dust_threshold, reverse=False):
fixed_heirs = {}
fixed_amount = 0.0
- percent_heirs= {}
+ percent_heirs = {}
percent_amount = 0.0
for key in self.keys():
try:
- cmp= Util.parse_locktime_string(self[key][HEIR_LOCKTIME]) - from_locktime
- if cmp<=0:
+ cmp = (
+ Util.parse_locktime_string(self[key][HEIR_LOCKTIME]) - from_locktime
+ )
+ if cmp <= 0:
continue
if Util.is_perc(self[key][HEIR_AMOUNT]):
percent_amount += float(self[key][HEIR_AMOUNT][:-1])
- percent_heirs[key] =list(self[key])
+ percent_heirs[key] = list(self[key])
else:
heir_amount = int(math.floor(float(self[key][HEIR_AMOUNT])))
- if heir_amount>dust_threshold:
+ if heir_amount > dust_threshold:
fixed_amount += heir_amount
fixed_heirs[key] = list(self[key])
- fixed_heirs[key].insert(HEIR_REAL_AMOUNT,heir_amount)
+ fixed_heirs[key].insert(HEIR_REAL_AMOUNT, heir_amount)
else:
pass
- except Exception as e:
+ except Exception as e:
_logger.error(e)
- return fixed_heirs,fixed_amount,percent_heirs,percent_amount
+ return fixed_heirs, fixed_amount, percent_heirs, percent_amount
-
- def prepare_lists(self, balance, total_fees, wallet, willexecutor = False, from_locktime = 0):
- willexecutors_amount = 0
+ def prepare_lists(
+ self, balance, total_fees, wallet, willexecutor=False, from_locktime=0
+ ):
+ willexecutors_amount = 0
willexecutors = {}
heir_list = {}
onlyfixed = False
newbalance = balance - total_fees
- locktimes = self.get_locktimes(from_locktime);
+ locktimes = self.get_locktimes(from_locktime)
if willexecutor:
for locktime in locktimes:
if int(Util.int_locktime(locktime)) > int(from_locktime):
try:
- base_fee = int(willexecutor['base_fee'])
+ base_fee = int(willexecutor["base_fee"])
willexecutors_amount += base_fee
h = [None] * 4
h[HEIR_AMOUNT] = base_fee
h[HEIR_REAL_AMOUNT] = base_fee
h[HEIR_LOCKTIME] = locktime
- h[HEIR_ADDRESS] = willexecutor['address']
- willexecutors["w!ll3x3c\""+willexecutor['url']+"\""+str(locktime)] = h
+ h[HEIR_ADDRESS] = willexecutor["address"]
+ willexecutors[
+ 'w!ll3x3c"' + willexecutor["url"] + '"' + str(locktime)
+ ] = h
except Exception as e:
- return [],False
+ return [], False
else:
- _logger.error(f"heir excluded from will locktime({locktime}){Util.int_locktime(locktime)} newbalance:
- fixed_amount = self.normalize_perc(fixed_heirs,newbalance,fixed_amount,wallet)
+ fixed_amount = self.normalize_perc(
+ fixed_heirs, newbalance, fixed_amount, wallet
+ )
onlyfixed = True
heir_list.update(fixed_heirs)
-
+
newbalance -= fixed_amount
if newbalance > 0:
- perc_amount = self.normalize_perc(percent_heirs,newbalance,percent_amount,wallet)
+ perc_amount = self.normalize_perc(
+ percent_heirs, newbalance, percent_amount, wallet
+ )
newbalance -= perc_amount
heir_list.update(percent_heirs)
if newbalance > 0:
newbalance += fixed_amount
- fixed_amount = self.normalize_perc(fixed_heirs,newbalance,fixed_amount,wallet,real=True)
+ fixed_amount = self.normalize_perc(
+ fixed_heirs, newbalance, fixed_amount, wallet, real=True
+ )
newbalance -= fixed_amount
heir_list.update(fixed_heirs)
-
- heir_list = sorted(heir_list.items(), key = lambda item: Util.parse_locktime_string(item[1][HEIR_LOCKTIME],wallet))
-
+
+ heir_list = sorted(
+ heir_list.items(),
+ key=lambda item: Util.parse_locktime_string(item[1][HEIR_LOCKTIME], wallet),
+ )
locktimes = {}
for key, value in heir_list:
- locktime=Util.parse_locktime_string(value[HEIR_LOCKTIME])
- if not locktime in locktimes: locktimes[locktime]={key:value}
- else: locktimes[locktime][key]=value
+ locktime = Util.parse_locktime_string(value[HEIR_LOCKTIME])
+ if not locktime in locktimes:
+ locktimes[locktime] = {key: value}
+ else:
+ locktimes[locktime][key] = value
return locktimes, onlyfixed
- def is_perc(self,key):
+
+ def is_perc(self, key):
return Util.is_perc(self[key][HEIR_AMOUNT])
- def buildTransactions(self,bal_plugin,wallet,tx_fees = None, utxos=None,from_locktime=0):
+ def buildTransactions(
+ self, bal_plugin, wallet, tx_fees=None, utxos=None, from_locktime=0
+ ):
Heirs._validate(self)
- if len(self)<=0:
+ if len(self) <= 0:
return
balance = 0.0
len_utxo_set = 0
@@ -388,20 +457,21 @@ class Heirs(dict, Logger):
if not utxos:
utxos = wallet.get_utxos()
willexecutors = Willexecutors.get_willexecutors(bal_plugin) or {}
- self.decimal_point=bal_plugin.get_decimal_point()
+ self.decimal_point = bal_plugin.get_decimal_point()
no_willexecutors = bal_plugin.NO_WILLEXECUTOR.get()
for utxo in utxos:
- if utxo.value_sats()> 0*tx_fees:
+ if utxo.value_sats() > 0 * tx_fees:
balance += utxo.value_sats()
len_utxo_set += 1
available_utxos.append(utxo)
- if len_utxo_set==0: return
- j=-2
+ if len_utxo_set == 0:
+ return
+ j = -2
willexecutorsitems = list(willexecutors.items())
willexecutorslen = len(willexecutorsitems)
alltxs = {}
while True:
- j+=1
+ j += 1
if j >= willexecutorslen:
break
elif 0 <= j:
@@ -409,7 +479,7 @@ class Heirs(dict, Logger):
if not Willexecutors.is_selected(willexecutor):
continue
else:
- willexecutor['url']=url
+ willexecutor["url"] = url
elif j == -1:
if not no_willexecutors:
continue
@@ -417,78 +487,84 @@ class Heirs(dict, Logger):
else:
break
fees = {}
- i=0
+ i = 0
while True:
txs = {}
redo = False
- i+=1
- total_fees=0
+ i += 1
+ total_fees = 0
for fee in fees:
total_fees += int(fees[fee])
- newbalance = balance
- locktimes, onlyfixed = self.prepare_lists(balance, total_fees, wallet, willexecutor, from_locktime)
+ newbalance = balance
+ locktimes, onlyfixed = self.prepare_lists(
+ balance, total_fees, wallet, willexecutor, from_locktime
+ )
try:
- txs = prepare_transactions(locktimes, available_utxos[:], fees, wallet)
+ txs = prepare_transactions(
+ locktimes, available_utxos[:], fees, wallet
+ )
if not txs:
return {}
except Exception as e:
try:
if "w!ll3x3c" in e.heirname:
- Willexecutors.is_selected(willexecutors[w],False)
+ Willexecutors.is_selected(willexecutors[w], False)
break
except:
raise e
total_fees = 0
total_fees_real = 0
total_in = 0
- for txid,tx in txs.items():
+ for txid, tx in txs.items():
tx.willexecutor = willexecutor
- fee = tx.estimated_size() * tx_fees
- txs[txid].tx_fees= tx_fees
+ fee = tx.estimated_size() * tx_fees
+ txs[txid].tx_fees = tx_fees
total_fees += fee
total_fees_real += tx.get_fee()
total_in += tx.input_value()
- rfee= tx.input_value()-tx.output_value()
+ rfee = tx.input_value() - tx.output_value()
if rfee < fee or rfee > fee + wallet.dust_threshold():
redo = True
- oldfees= fees.get(tx.my_locktime,0)
- fees[tx.my_locktime]=fee
+ oldfees = fees.get(tx.my_locktime, 0)
+ fees[tx.my_locktime] = fee
-
- if balance - total_in > wallet.dust_threshold():
+ if balance - total_in > wallet.dust_threshold():
redo = True
if not redo:
break
- if i>=10:
+ if i >= 10:
break
alltxs.update(txs)
-
+
return alltxs
- def get_transactions(self,bal_plugin,wallet,tx_fees,utxos=None,from_locktime=0):
- txs=self.buildTransactions(bal_plugin,wallet,tx_fees,utxos,from_locktime)
+
+ def get_transactions(
+ self, bal_plugin, wallet, tx_fees, utxos=None, from_locktime=0
+ ):
+ txs = self.buildTransactions(bal_plugin, wallet, tx_fees, utxos, from_locktime)
if txs:
temp_txs = {}
for txid in txs:
if txs[txid].available_utxos:
- temp_txs.update(self.get_transactions(bal_plugin,wallet,tx_fees,txs[txid].available_utxos,txs[txid].locktime))
+ temp_txs.update(
+ self.get_transactions(
+ bal_plugin,
+ wallet,
+ tx_fees,
+ txs[txid].available_utxos,
+ txs[txid].locktime,
+ )
+ )
txs.update(temp_txs)
return txs
-
-
def resolve(self, k):
if bitcoin.is_address(k):
- return {
- 'address': k,
- 'type': 'address'
- }
+ return {"address": k, "type": "address"}
if k in self.keys():
_type, addr = self[k]
- if _type == 'address':
- return {
- 'address': addr,
- 'type': 'heir'
- }
+ if _type == "address":
+ return {"address": addr, "type": "heir"}
if openalias := self.resolve_openalias(k):
return openalias
raise AliasNotFoundException("Invalid Bitcoin address or alias", k)
@@ -499,10 +575,10 @@ class Heirs(dict, Logger):
if out:
address, name, validated = out
return {
- 'address': address,
- 'name': name,
- 'type': 'openalias',
- 'validated': validated
+ "address": address,
+ "name": name,
+ "type": "openalias",
+ "validated": validated,
}
return {}
@@ -510,21 +586,19 @@ class Heirs(dict, Logger):
for k in self.keys():
_type, addr = self[k]
if addr.casefold() == name.casefold():
- return {
- 'name': addr,
- 'type': _type,
- 'address': k
- }
+ return {"name": addr, "type": _type, "address": k}
return None
- def fetch_openalias(self, config: 'SimpleConfig'):
+ def fetch_openalias(self, config: "SimpleConfig"):
self.alias_info = None
alias = config.OPENALIAS_ID
if alias:
alias = str(alias)
+
def f():
self.alias_info = self._resolve_openalias(alias)
- trigger_callback('alias_received')
+ trigger_callback("alias_received")
+
t = threading.Thread(target=f)
t.daemon = True
t.start()
@@ -532,18 +606,18 @@ class Heirs(dict, Logger):
@classmethod
def _resolve_openalias(cls, url: str) -> Optional[Tuple[str, str, bool]]:
# support email-style addresses, per the OA standard
- url = url.replace('@', '.')
+ url = url.replace("@", ".")
try:
records, validated = dnssec.query(url, dns.rdatatype.TXT)
except DNSException as e:
- _logger.info(f'Error resolving openalias: {repr(e)}')
+ _logger.info(f"Error resolving openalias: {repr(e)}")
return None
- prefix = 'btc'
+ prefix = "btc"
for record in records:
- string = to_string(record.strings[0], 'utf8')
- if string.startswith('oa1:' + prefix):
- address = cls.find_regex(string, r'recipient_address=([A-Za-z0-9]+)')
- name = cls.find_regex(string, r'recipient_name=([^;]+)')
+ string = to_string(record.strings[0], "utf8")
+ if string.startswith("oa1:" + prefix):
+ address = cls.find_regex(string, r"recipient_address=([A-Za-z0-9]+)")
+ name = cls.find_regex(string, r"recipient_name=([^;]+)")
if not name:
name = address
if not address:
@@ -558,7 +632,6 @@ class Heirs(dict, Logger):
except AttributeError:
return None
-
def validate_address(address):
if not bitcoin.is_address(address):
raise NotAnAddress(f"not an address,{address}")
@@ -573,36 +646,43 @@ class Heirs(dict, Logger):
raise AmountNotValid(f"amount not properly formatted, {e}")
return amount
- def validate_locktime(locktime,timestamp_to_check=False):
+ def validate_locktime(locktime, timestamp_to_check=False):
try:
if timestamp_to_check:
- if Util.parse_locktime_string(locktime,None) < timestamp_to_check:
+ if Util.parse_locktime_string(locktime, None) < timestamp_to_check:
raise HeirExpiredException()
except Exception as e:
raise LocktimeNotValid(f"locktime string not properly formatted, {e}")
return locktime
- def validate_heir(k,v,timestamp_to_check=False):
+ def validate_heir(k, v, timestamp_to_check=False):
address = Heirs.validate_address(v[HEIR_ADDRESS])
amount = Heirs.validate_amount(v[HEIR_AMOUNT])
- locktime = Heirs.validate_locktime(v[HEIR_LOCKTIME],timestamp_to_check)
- return (address,amount,locktime)
+ locktime = Heirs.validate_locktime(v[HEIR_LOCKTIME], timestamp_to_check)
+ return (address, amount, locktime)
- def _validate(data,timestamp_to_check=False):
+ def _validate(data, timestamp_to_check=False):
for k, v in list(data.items()):
- if k == 'heirs':
+ if k == "heirs":
return Heirs._validate(v)
try:
- Heirs.validate_heir(k,v)
+ Heirs.validate_heir(k, v)
except Exception as e:
data.pop(k)
return data
+
class NotAnAddress(ValueError):
pass
+
+
class AmountNotValid(ValueError):
pass
+
+
class LocktimeNotValid(ValueError):
pass
+
+
class HeirExpiredException(LocktimeNotValid):
pass
diff --git a/manifest.json b/manifest.json
index 08d4ec3..751a49d 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,9 +1,8 @@
{
- "name": "BAL",
- "fullname": "Bitcoin After Life",
- "description": "Provides free and decentralized inheritance support
Version: 0.2.2c",
- "author":"Svatantrya",
- "available_for": ["qt"],
- "icon":"icons/bal32x32.png"
- }
-
+ "name": "BAL",
+ "fullname": "Bitcoin After Life",
+ "description": "Provides free and decentralized inheritance support
Version: 0.2.2d",
+ "author": "Svatantrya",
+ "available_for": ["qt"],
+ "icon": "icons/bal32x32.png"
+}
diff --git a/qt.py b/qt.py
index 7d409bd..be97f3a 100644
--- a/qt.py
+++ b/qt.py
@@ -1,432 +1,275 @@
-'''
+"""
Bal
Bitcoin after life
-'''
-
-
-
-
+"""
import copy
+import enum
+import sys
+import time
from datetime import datetime
from decimal import Decimal
-import enum
from functools import partial
-import json
-import os
-import random
-import sys
-import traceback
-import time
-from typing import (
- TYPE_CHECKING,
- Callable,
- Optional,
- List,
- Union,
- Tuple,
- Mapping,Any)
-import urllib.parse
-import urllib.request
+from typing import TYPE_CHECKING, Any, Callable, Mapping, Optional, Union
try:
- QT_VERSION=sys._GUI_QT_VERSION
-except:
- QT_VERSION=6
+ QT_VERSION = sys._GUI_QT_VERSION
+except Exception:
+ QT_VERSION = 6
if QT_VERSION == 5:
- from PyQt5.QtGui import QStandardItemModel, QStandardItem
- from PyQt5.QtCore import Qt,QPersistentModelIndex, QModelIndex
- from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,QMenu)
from PyQt5.QtCore import (
- QPersistentModelIndex,
- QModelIndex,
- Qt,
- QRectF,
- QRect,
- QSizeF,
- QUrl,
- QPoint,
- QSize,
- QDateTime,
- pyqtProperty,
- pyqtSignal,
- pyqtSlot,
- QObject,
- QEventLoop,
- pyqtSignal)
+ QDateTime,
+ QModelIndex,
+ QPersistentModelIndex,
+ Qt,
+ pyqtSignal,
+ )
from PyQt5.QtGui import (
- QStandardItemModel,
- QStandardItem,
- QPalette,
- QColor,
- QPixmap,
- QImage,
- QBitmap,
- QPainter,
- QFontDatabase,
- QPen,
- QFont,
- QColor,
- QDesktopServices,
- qRgba,
- QPainterPath,
- QPalette,
- QPixmap,
- QImage,
- QBitmap,
- QPainter,
- QFontDatabase,
- QPen,
- QFont,
- QIcon,
- QColor,
- QDesktopServices,
- qRgba,
- QPainterPath,
- QPalette)
+ QColor,
+ QIcon,
+ QPainter,
+ QPalette,
+ QPixmap,
+ QStandardItem,
+ QStandardItemModel,
+ )
from PyQt5.QtWidgets import (
- QDialog,
- QVBoxLayout,
- QHBoxLayout,
- QPushButton,
- QLabel,
- QMenu,
- QDialog,
- QVBoxLayout,
- QHBoxLayout,
- QPushButton,
- QLabel,
- QWidget,
- QScrollArea,
- QAbstractItemView,
- QWidget,
- QDateTimeEdit,
- QLineEdit,
- QStyle,
- QStyleOptionFrame,
- QSizePolicy,
- QCheckBox,
- QGridLayout,
- QHBoxLayout,
- QLabel,
- QLineEdit,
- QMenu,
- QMenuBar,
- QPushButton,
- QScrollArea,
- QSpacerItem,
- QSizePolicy,
- QSpinBox,
- QVBoxLayout,
- QWidget,
- QStyle,
- QStyleOptionFrame,
- QComboBox,
- QHBoxLayout,
- )
-else: #QT6
+ QAbstractItemView,
+ QCheckBox,
+ QComboBox,
+ QDateTimeEdit,
+ QGridLayout,
+ QHBoxLayout,
+ QLabel,
+ QLineEdit,
+ QMenu,
+ QMenuBar,
+ QPushButton,
+ QScrollArea,
+ QSizePolicy,
+ QSpinBox,
+ QStyle,
+ QStyleOptionFrame,
+ QVBoxLayout,
+ QWidget,
+ )
+else: # QT6
from PyQt6.QtCore import (
- Qt,
- QDateTime,
- QPersistentModelIndex,
- QModelIndex,
- pyqtProperty,
- pyqtSignal,
- pyqtSlot,
- QObject,
- pyqtSignal,
- QSize,
- Qt,
- QRectF,
- QRect,
- QSizeF,
- QUrl,
- QPoint,
- QSize)
+ QDateTime,
+ QModelIndex,
+ QPersistentModelIndex,
+ Qt,
+ pyqtSignal,
+ )
from PyQt6.QtGui import (
- QStandardItemModel,
- QStandardItem,
- QPalette,
- QColor,
- QPixmap,
- QImage,
- QBitmap,
- QPainter,
- QFontDatabase,
- QPen,
- QFont,
- QColor,
- QDesktopServices,
- qRgba,
- QPainterPath,
- QPalette,
- QPainter,
- QPixmap,
- QImage,
- QBitmap,
- QPainter,
- QFontDatabase,
- QPen,
- QFont,
- QIcon,
- QColor,
- QDesktopServices,
- qRgba,
- QPainterPath,
- QPalette)
-
+ QColor,
+ QIcon,
+ QPainter,
+ QPalette,
+ QPixmap,
+ QStandardItem,
+ QStandardItemModel,
+ )
from PyQt6.QtWidgets import (
- QDialog,
- QVBoxLayout,
- QHBoxLayout,
- QPushButton,
- QLabel,
- QMenu,
- QAbstractItemView,
- QWidget,
- QDialog,
- QVBoxLayout,
- QHBoxLayout,
- QPushButton,
- QLabel,
- QWidget,
- QScrollArea,
- QDateTimeEdit,
- QLabel,
- QVBoxLayout,
- QCheckBox,
- QWidget,
- QLabel,
- QVBoxLayout,
- QCheckBox,
- QLineEdit,
- QStyle,
- QStyleOptionFrame,
- QSizePolicy,
- QGridLayout,
- QVBoxLayout,
- QHBoxLayout,
- QLabel,
- QPushButton,
- QLineEdit,
- QCheckBox,
- QSpinBox,
- QMenuBar,
- QMenu,
- QLineEdit,
- QScrollArea,
- QWidget,
- QSpacerItem,
- QComboBox,
- QSizePolicy)
+ QAbstractItemView,
+ QCheckBox,
+ QComboBox,
+ QDateTimeEdit,
+ QGridLayout,
+ QHBoxLayout,
+ QLabel,
+ QLineEdit,
+ QMenu,
+ QMenuBar,
+ QPushButton,
+ QScrollArea,
+ QSizePolicy,
+ QSpinBox,
+ QStyle,
+ QStyleOptionFrame,
+ QVBoxLayout,
+ QWidget,
+ )
-
-
-
-from electrum import json_db
-from electrum import constants
from electrum.bitcoin import (
- is_address,
- NLOCKTIME_MIN,
- NLOCKTIME_MAX,
- NLOCKTIME_BLOCKHEIGHT_MAX)
+ NLOCKTIME_BLOCKHEIGHT_MAX,
+ NLOCKTIME_MAX,
+ NLOCKTIME_MIN,
+)
from electrum.gui.qt.amountedit import (
- BTCAmountEdit,
- char_width_in_lineedit,
- ColorScheme)
+ BTCAmountEdit,
+)
if TYPE_CHECKING:
from electrum.gui.qt.main_window import ElectrumWindow
-from electrum.gui.qt.util import (
- Buttons,
- CancelButton,
- char_width_in_lineedit,
- CloseButton,
- ColorScheme,
- EnterButton,
- export_meta_gui,
- HelpButton,
- import_meta_gui,
- MessageBoxMixin,
- OkButton,
- read_QIcon,
- TaskThread,
- WindowModalDialog,
- WWLabel,
- read_QIcon_from_bytes,
- read_QPixmap_from_bytes,
- )
from electrum.gui.qt.main_window import StatusBarButton
-from electrum.gui.qt.my_treeview import (
- MyTreeView,
- MySortModel)
-from electrum.gui.qt.transaction_dialog import TxDialog
+from electrum.gui.qt.my_treeview import MyTreeView
from electrum.gui.qt.password_dialog import PasswordDialog
-from electrum.gui.qt.qrtextedit import ScanQRTextEdit
+from electrum.gui.qt.transaction_dialog import TxDialog
+from electrum.gui.qt.util import (
+ Buttons,
+ CancelButton,
+ ColorScheme,
+ EnterButton,
+ HelpButton,
+ MessageBoxMixin,
+ OkButton,
+ TaskThread,
+ WindowModalDialog,
+ char_width_in_lineedit,
+ import_meta_gui,
+ read_QIcon,
+ read_QIcon_from_bytes,
+ read_QPixmap_from_bytes,
+)
from electrum.i18n import _
-from electrum.logging import get_logger,Logger
-from electrum.json_db import StoredDict
-from electrum.network import (
- Network,
- TxBroadcastError,
- BestEffortRequestFailed
- )
-from electrum.plugin import (
- hook,
- run_hook)
-from electrum.transaction import (
- SerializationError,
- Transaction,
- tx_from_any)
+from electrum.logging import Logger, get_logger
+from electrum.network import BestEffortRequestFailed, Network, TxBroadcastError
+from electrum.plugin import hook, run_hook
+from electrum.transaction import SerializationError, Transaction, tx_from_any
from electrum.util import (
- write_json_file,
- read_json_file,
- make_dir,
- InvalidPassword,
- UserCancelled,
- resource_path,
- write_json_file,
- read_json_file,
- FileImportFailed,
- bfh,
- read_json_file,
- write_json_file,
- decimal_point_to_base_unit_name,
- FileImportFailed,
- DECIMAL_POINT,
- FEERATE_PRECISION,
- quantize_feerate,
- UI_UNIT_NAME_FEERATE_SAT_PER_VBYTE,
- FileExportFailed)
-
+ DECIMAL_POINT,
+ FileImportFailed,
+ UserCancelled,
+ decimal_point_to_base_unit_name,
+ read_json_file,
+ write_json_file,
+)
from .bal import BalPlugin
-from .bal_resources import (
- DEFAULT_ICON,
- icon_path)
+from .bal_resources import DEFAULT_ICON, icon_path
from .heirs import Heirs
from .util import Util
from .will import (
- Will,
- WillItem,
- NoHeirsException,
- NoWillExecutorNotPresent,
- NotCompleteWillException,
- AmountException,
- HeirNotFoundException,
- HeirChangeException,
- WillexecutorChangeException,
- WillExecutorNotPresent,
- TxFeesChangedException,
- WillExpiredException)
-
+ AmountException,
+ HeirChangeException,
+ HeirNotFoundException,
+ NoHeirsException,
+ NotCompleteWillException,
+ NoWillExecutorNotPresent,
+ TxFeesChangedException,
+ Will,
+ WillexecutorChangeException,
+ WillExecutorNotPresent,
+ WillExpiredException,
+ WillItem,
+)
from .willexecutors import Willexecutors
+
_logger = get_logger(__name__)
-
-
-class Plugin(BalPlugin,Logger):
+class Plugin(BalPlugin, Logger):
def __init__(self, parent, config, name):
Logger.__init__(self)
self.logger.info("INIT BALPLUGIN")
print("init bal_plugin")
BalPlugin.__init__(self, parent, config, name)
- self.bal_windows={}
-
+ self.bal_windows = {}
@hook
- def init_qt(self,gui_object):
+ def init_qt(self, gui_object):
print("hook init qt")
- self.logger.info("HOOK init qt")
+ self.logger.info("HOOK init qt")
try:
- self.gui_object=gui_object
+ self.gui_object = gui_object
for window in gui_object.windows:
wallet = window.wallet
if wallet:
- window.show_warning(_('Please restart Electrum to activate the BAL plugin'), title=_('Success'))
+ window.show_warning(
+ _("Please restart Electrum to activate the BAL plugin"),
+ title=_("Success"),
+ )
return
- w = BalWindow(self,window)
- self.bal_windows[window.winId]= w
+ w = BalWindow(self, window)
+ self.bal_windows[window.winId] = w
for child in window.children():
- if isinstance(child,QMenuBar):
+ if isinstance(child, QMenuBar):
for menu_child in child.children():
- if isinstance(menu_child,QMenu):
+ if isinstance(menu_child, QMenu):
try:
- if menu_child.title()==_("&Tools"):
+ if menu_child.title() == _("&Tools"):
w.init_menubar_tools(menu_child)
-
+
except Exception as e:
raise e
- self.logger.error(("except:",menu_child.text()))
-
+ self.logger.error(("except:", menu_child.text()))
+
except Exception as e:
self.logger.error("Error loading plugini {}".format(e))
raise e
-
-
@hook
def create_status_bar(self, sb):
self.logger.info("HOOK create status bar")
return
- b = StatusBarButton(read_QIcon_from_bytes(self.bal_plugin.read_file('bal32x32.png')), "Bal "+_("Bitcoin After Life"),
- partial(self.setup_dialog, sb), sb.height())
+ b = StatusBarButton(
+ read_QIcon_from_bytes(self.bal_plugin.read_file("bal32x32.png")),
+ "Bal " + _("Bitcoin After Life"),
+ partial(self.setup_dialog, sb),
+ sb.height(),
+ )
sb.addPermanentWidget(b)
@hook
- def init_menubar(self,window):
+ def init_menubar(self, window):
self.logger.info("HOOK init_menubar")
w = self.get_window(window)
w.init_menubar_tools(window.tools_menu)
@hook
- def load_wallet(self,wallet, main_window):
+ def load_wallet(self, wallet, main_window):
self.logger.info("HOOK load wallet")
w = self.get_window(main_window)
- #havetoupdate = Util.fix_will_settings_tx_fees(wallet.db)
+ # havetoupdate = Util.fix_will_settings_tx_fees(wallet.db)
w.wallet = wallet
w.init_will()
- w.willexecutors = Willexecutors.get_willexecutors(self, update=False, bal_window=w)
+ w.willexecutors = Willexecutors.get_willexecutors(
+ self, update=False, bal_window=w
+ )
w.disable_plugin = False
- w.ok=True
+ w.ok = True
@hook
- def close_wallet(self,wallet):
+ def close_wallet(self, wallet):
print("HOOK close wallet")
- for winid,win in self.bal_windows.items():
+ for winid, win in self.bal_windows.items():
if win.wallet == wallet:
win.on_close()
+
@hook
def init_keystore(self):
print("init keystore")
+
@hook
- def daemon_wallet_loaded(self,boh,wallet):
+ def daemon_wallet_loaded(self, boh, wallet):
print("daemon wallet loaded")
- def get_window(self,window):
- w = self.bal_windows.get(window.winId,None)
+
+ def get_window(self, window):
+ w = self.bal_windows.get(window.winId, None)
if w is None:
- w=BalWindow(self,window)
- self.bal_windows[window.winId]=w
+ w = BalWindow(self, window)
+ self.bal_windows[window.winId] = w
return w
-
+
def requires_settings(self):
return True
-
+
def settings_widget(self, window):
- w=self.get_window(window.window)
- widget=QWidget()
- enterbutton=EnterButton(_('Settings'), partial(w.settings_dialog,window))
+ w = self.get_window(window.window)
+ widget = QWidget()
+ enterbutton = EnterButton(_("Settings"), partial(w.settings_dialog, window))
- widget.setLayout(Buttons(enterbutton,widget))
+ widget.setLayout(Buttons(enterbutton, widget))
return widget
+
def password_dialog(self, msg=None, parent=None):
parent = parent or self
d = PasswordDialog(parent, msg)
@@ -445,11 +288,11 @@ class Plugin(BalPlugin,Logger):
self.extension = bool(keystore.get_passphrase(password))
return keystore.get_seed(password)
- def settings_dialog(self,window,wallet):
+ def settings_dialog(self, window, wallet):
- d = BalDialog(window,self,self.get_window_title("Settings"))
+ d = BalDialog(window, self, self.get_window_title("Settings"))
d.setMinimumSize(100, 200)
- qicon=read_QPixmap_from_bytes(self.read_file("bal32x32.png"))
+ qicon = read_QPixmap_from_bytes(self.read_file("bal32x32.png"))
lbl_logo = QLabel()
lbl_logo.setPixmap(qicon)
@@ -460,53 +303,97 @@ class Plugin(BalPlugin,Logger):
def on_multiverse_change():
self.update_all()
- #heir_enable_multiverse = bal_checkbox(self.ENABLE_MULTIVERSE,on_multiverse_change)
+ # heir_enable_multiverse = bal_checkbox(self.ENABLE_MULTIVERSE,on_multiverse_change)
- heir_hide_replaced = bal_checkbox(self.HIDE_REPLACED,on_multiverse_change)
+ heir_hide_replaced = bal_checkbox(self.HIDE_REPLACED, on_multiverse_change)
- heir_hide_invalidated = bal_checkbox(self.HIDE_INVALIDATED,on_multiverse_change)
+ heir_hide_invalidated = bal_checkbox(
+ self.HIDE_INVALIDATED, on_multiverse_change
+ )
heir_repush = QPushButton("Rebroadcast transactions")
- heir_repush.clicked.connect(partial(self.broadcast_transactions,True))
- grid=QGridLayout(d)
- add_widget(grid,"Hide Replaced",heir_hide_replaced, 1, "Hide replaced transactions from will detail and list")
- add_widget(grid,"Hide Invalidated",heir_hide_invalidated ,2,"Hide invalidated transactions from will detail and list")
- add_widget(grid,"Ping Willexecutors",heir_ping_willexecutors,3,"Ping willexecutors to get payment info before compiling will")
- add_widget(grid," - Ask before",heir_ask_ping_willexecutors,4,"Ask before to ping willexecutor")
- add_widget(grid,"Backup Transaction",heir_no_willexecutor,5,"Add transactions without willexecutor")
- #add_widget(grid,"Enable Multiverse(EXPERIMENTAL/BROKEN)",heir_enable_multiverse,6,"enable multiple locktimes, will import.... ")
- grid.addWidget(heir_repush,7,0)
- grid.addWidget(HelpButton("Broadcast all transactions to willexecutors including those already pushed"),7,2)
+ heir_repush.clicked.connect(partial(self.broadcast_transactions, True))
+ grid = QGridLayout(d)
+ add_widget(
+ grid,
+ "Hide Replaced",
+ heir_hide_replaced,
+ 1,
+ "Hide replaced transactions from will detail and list",
+ )
+ add_widget(
+ grid,
+ "Hide Invalidated",
+ heir_hide_invalidated,
+ 2,
+ "Hide invalidated transactions from will detail and list",
+ )
+ add_widget(
+ grid,
+ "Ping Willexecutors",
+ heir_ping_willexecutors,
+ 3,
+ "Ping willexecutors to get payment info before compiling will",
+ )
+ add_widget(
+ grid,
+ " - Ask before",
+ heir_ask_ping_willexecutors,
+ 4,
+ "Ask before to ping willexecutor",
+ )
+ add_widget(
+ grid,
+ "Backup Transaction",
+ heir_no_willexecutor,
+ 5,
+ "Add transactions without willexecutor",
+ )
+ # add_widget(grid,"Enable Multiverse(EXPERIMENTAL/BROKEN)",heir_enable_multiverse,6,"enable multiple locktimes, will import.... ")
+ grid.addWidget(heir_repush, 7, 0)
+ grid.addWidget(
+ HelpButton(
+ "Broadcast all transactions to willexecutors including those already pushed"
+ ),
+ 7,
+ 2,
+ )
if ret := bool(d.exec()):
try:
self.update_all()
return ret
- except:
+ except Exception:
pass
return False
- def broadcast_transactions(self,force):
- for k,w in self.bal_windows.items():
+ def broadcast_transactions(self, force):
+ for k, w in self.bal_windows.items():
w.broadcast_transactions(force)
def update_all(self):
- for k,w in self.bal_windows.items():
+ for k, w in self.bal_windows.items():
w.update_all()
- def get_window_title(self,title):
- return _('BAL - ') + _(title)
-class shown_cv():
- _type= bool
- def __init__(self,value):
- self.value=value
+ def get_window_title(self, title):
+ return _("BAL - ") + _(title)
+
+
+class shown_cv:
+ _type = bool
+
+ def __init__(self, value):
+ self.value = value
+
def get(self):
return self.value
- def set(self,value):
- self.value=value
+
+ def set(self, value):
+ self.value = value
+
class BalWindow(Logger):
- def __init__(self,bal_plugin: 'BalPlugin',window: 'ElectrumWindow'):
+ def __init__(self, bal_plugin: "BalPlugin", window: "ElectrumWindow"):
Logger.__init__(self)
self.bal_plugin = bal_plugin
self.window = window
@@ -517,18 +404,17 @@ class BalWindow(Logger):
self.will_settings = None
self.heirs_tab = self.create_heirs_tab()
self.will_tab = self.create_will_tab()
- self.ok= False
+ self.ok = False
self.disable_plugin = True
self.bal_plugin.get_decimal_point = self.window.get_decimal_point
-
+
if self.window.wallet:
self.wallet = self.window.wallet
self.heirs_tab.wallet = self.wallet
self.will_tab.wallet = self.wallet
-
- def init_menubar_tools(self,tools_menu):
- self.tools_menu=tools_menu
+ def init_menubar_tools(self, tools_menu):
+ self.tools_menu = tools_menu
def add_optional_tab(tabs, tab, icon, description):
tab.tab_icon = icon
@@ -536,28 +422,41 @@ class BalWindow(Logger):
tab.tab_pos = len(tabs)
if tab.is_shown_cv:
tabs.addTab(tab, icon, description.replace("&", ""))
+
def add_toggle_action(tab):
is_shown = tab.is_shown_cv.get()
- tab.menu_action = self.window.view_menu.addAction(tab.tab_description, lambda: self.window.toggle_tab(tab))
+ tab.menu_action = self.window.view_menu.addAction(
+ tab.tab_description, lambda: self.window.toggle_tab(tab)
+ )
tab.menu_action.setCheckable(True)
tab.menu_action.setChecked(is_shown)
-
-
- add_optional_tab(self.window.tabs, self.heirs_tab, read_QIcon_from_bytes(self.bal_plugin.read_file("heir.png")), _("&Heirs"))
- add_optional_tab(self.window.tabs, self.will_tab, read_QIcon_from_bytes(self.bal_plugin.read_file("will.png")), _("&Will"))
+ add_optional_tab(
+ self.window.tabs,
+ self.heirs_tab,
+ read_QIcon_from_bytes(self.bal_plugin.read_file("heir.png")),
+ _("&Heirs"),
+ )
+ add_optional_tab(
+ self.window.tabs,
+ self.will_tab,
+ read_QIcon_from_bytes(self.bal_plugin.read_file("will.png")),
+ _("&Will"),
+ )
tools_menu.addSeparator()
- self.tools_menu.willexecutors_action = tools_menu.addAction(_("&Will-Executors"), self.show_willexecutor_dialog)
+ self.tools_menu.willexecutors_action = tools_menu.addAction(
+ _("&Will-Executors"), self.show_willexecutor_dialog
+ )
self.window.view_menu.addSeparator()
add_toggle_action(self.heirs_tab)
add_toggle_action(self.will_tab)
def load_willitems(self):
- self.willitems={}
- for wid,w in self.will.items():
- self.willitems[wid]=WillItem(w,wallet=self.wallet)
+ self.willitems = {}
+ for wid, w in self.will.items():
+ self.willitems[wid] = WillItem(w, wallet=self.wallet)
if self.willitems:
- self.will_list.will=self.willitems
+ self.will_list.will = self.willitems
self.will_list.update_will(self.willitems)
self.will_tab.update()
@@ -565,40 +464,45 @@ class BalWindow(Logger):
keys = list(self.will.keys())
for k in keys:
del self.will[k]
- for wid,w in self.willitems.items():
- self.will[wid]=w.to_dict()
+ for wid, w in self.willitems.items():
+ self.will[wid] = w.to_dict()
def init_will(self):
self.logger.info("********************init_____will____________**********")
if not self.willexecutors:
- self.willexecutors = Willexecutors.get_willexecutors(self.bal_plugin, update=False, bal_window=self)
+ self.willexecutors = Willexecutors.get_willexecutors(
+ self.bal_plugin, update=False, bal_window=self
+ )
if not self.heirs:
self.heirs = Heirs._validate(Heirs(self.wallet.db))
if not self.will:
- self.will=self.wallet.db.get_dict("will")
+ self.will = self.wallet.db.get_dict("will")
Util.fix_will_tx_fees(self.will)
if self.will:
self.willitems = {}
try:
self.load_willitems()
except:
- self.disable_plugin=True
- self.show_warning(_('Please restart Electrum to activate the BAL plugin'), title=_('Success'))
+ self.disable_plugin = True
+ self.show_warning(
+ _("Please restart Electrum to activate the BAL plugin"),
+ title=_("Success"),
+ )
self.close_wallet()
return
if not self.will_settings:
- self.will_settings=self.wallet.db.get_dict("will_settings")
+ self.will_settings = self.wallet.db.get_dict("will_settings")
Util.fix_will_settings_tx_fees(self.will_settings)
self.logger.info("will_settings: {}".format(self.will_settings))
if not self.will_settings:
- Util.copy(self.will_settings,self.bal_plugin.default_will_settings())
+ Util.copy(self.will_settings, self.bal_plugin.default_will_settings())
self.logger.debug("not_will_settings {}".format(self.will_settings))
self.bal_plugin.validate_will_settings(self.will_settings)
self.heir_list.update_will_settings()
-
+
def init_wizard(self):
wizard_dialog = BalWizardDialog(self)
wizard_dialog.exec()
@@ -608,25 +512,27 @@ class BalWindow(Logger):
self.willexecutor_dialog.show()
def create_heirs_tab(self):
- self.heir_list = l = HeirList(self,self.window)
+ self.heir_list = l = HeirList(self, self.window)
tab = self.window.create_list_tab(l)
tab.is_shown_cv = shown_cv(True)
return tab
def create_will_tab(self):
- self.will_list = l = PreviewList(self,self.window,None)
+ self.will_list = l = PreviewList(self, self.window, None)
tab = self.window.create_list_tab(l)
tab.is_shown_cv = shown_cv(True)
return tab
- def new_heir_dialog(self,heir_key=None):
+ def new_heir_dialog(self, heir_key=None):
heir = self.heirs.get(heir_key)
title = "New heir"
if heir:
title = f"Edit: {heir_key}"
- d = BalDialog(self.window, self.bal_plugin,self.bal_plugin.get_window_title(_(title)))
+ d = BalDialog(
+ self.window, self.bal_plugin, self.bal_plugin.get_window_title(_(title))
+ )
vbox = QVBoxLayout(d)
grid = QGridLayout()
@@ -641,17 +547,20 @@ class BalWindow(Logger):
heir_address.setText(str(heir[0]))
heir_amount = PercAmountEdit(self.window.get_decimal_point)
if heir:
- heir_amount.setText(str(Util.decode_amount(heir[1],self.window.get_decimal_point())))
- heir_locktime = HeirsLockTimeEdit(self.window,0)
+ heir_amount.setText(
+ str(Util.decode_amount(heir[1], self.window.get_decimal_point()))
+ )
+ self.heir_locktime = HeirsLockTimeEdit(self.window, 0)
if heir:
- heir_locktime.set_locktime(heir[2])
+ self.heir_locktime.set_locktime(heir[2])
heir_is_xpub = QCheckBox()
- new_heir_button=QPushButton(_("Add another heir"))
- self.add_another_heir=False
+ new_heir_button = QPushButton(_("Add another heir"))
+ self.add_another_heir = False
+
def new_heir():
- self.add_another_heir=True
+ self.add_another_heir = True
d.accept()
new_heir_button.clicked.connect(new_heir)
@@ -659,36 +568,36 @@ class BalWindow(Logger):
grid.addWidget(QLabel(_("Name")), 1, 0)
grid.addWidget(heir_name, 1, 1)
- grid.addWidget(HelpButton(_("Unique name or description about heir")),1,2)
+ grid.addWidget(HelpButton(_("Unique name or description about heir")), 1, 2)
grid.addWidget(QLabel(_("Address")), 2, 0)
grid.addWidget(heir_address, 2, 1)
- grid.addWidget(HelpButton(_("heir bitcoin address")),2,2)
+ grid.addWidget(HelpButton(_("heir bitcoin address")), 2, 2)
- grid.addWidget(QLabel(_("Amount")),3,0)
- grid.addWidget(heir_amount,3,1)
- grid.addWidget(HelpButton(_("Fixed or Percentage amount if end with %")),3,2)
+ grid.addWidget(QLabel(_("Amount")), 3, 0)
+ grid.addWidget(heir_amount, 3, 1)
+ grid.addWidget(HelpButton(_("Fixed or Percentage amount if end with %")), 3, 2)
- locktime_label=QLabel(_("Locktime"))
- enable_multiverse=self.bal_plugin.ENABLE_MULTIVERSE.get()
+ locktime_label = QLabel(_("Locktime"))
+ enable_multiverse = self.bal_plugin.ENABLE_MULTIVERSE.get()
if enable_multiverse:
- grid.addWidget(locktime_label,4,0)
- grid.addWidget(heir_locktime,4,1)
- grid.addWidget(HelpButton(_("locktime")),4,2)
+ grid.addWidget(locktime_label, 4, 0)
+ grid.addWidget(self.heir_locktime, 4, 1)
+ grid.addWidget(HelpButton(_("locktime")), 4, 2)
vbox.addLayout(grid)
- buttons=[CancelButton(d), OkButton(d)]
+ buttons = [CancelButton(d), OkButton(d)]
if not heir:
buttons.append(new_heir_button)
vbox.addLayout(Buttons(*buttons))
while d.exec():
- #TODO SAVE HEIR
+ # TODO SAVE HEIR
heir = [
- heir_name.text(),
- heir_address.text(),
- Util.encode_amount(heir_amount.text(),self.window.get_decimal_point()),
- str(heir_locktime.get_locktime()),
- ]
+ heir_name.text(),
+ heir_address.text(),
+ Util.encode_amount(heir_amount.text(), self.window.get_decimal_point()),
+ str(self.heir_locktime.get_locktime()),
+ ]
try:
self.set_heir(heir)
if self.add_another_heir:
@@ -697,127 +606,162 @@ class BalWindow(Logger):
except Exception as e:
self.show_error(str(e))
- #def export_inheritance_handler(self,path):
+ # def export_inheritance_handler(self,path):
# txs = self.build_inheritance_transaction(ignore_duplicate=True, keep_original=False)
# with open(path,"w") as f:
# for tx in txs:
# tx['status']+="."+BalPlugin.STATUS_EXPORTED
# f.write(str(tx['tx']))
# f.write('\n')
-
- def set_heir(self,heir):
- heir=list(heir)
- if not self.bal_plugin.ENABLE_MULTIVERSE.get():
- heir[3]=self.will_settings['locktime']
- h=Heirs.validate_heir(heir[0],heir[1:])
- self.heirs[heir[0]]=h
+ def set_heir(self, heir):
+ heir = list(heir)
+ if not self.bal_plugin.ENABLE_MULTIVERSE.get():
+ heir[3] = self.will_settings["locktime"]
+
+ h = Heirs.validate_heir(heir[0], heir[1:])
+ self.heirs[heir[0]] = h
self.heir_list.update()
return True
- def delete_heirs(self,heirs):
+ def delete_heirs(self, heirs):
for heir in heirs:
del self.heirs[heir]
self.heirs.save()
self.heir_list.update()
return True
-
- def import_heirs(self,):
- import_meta_gui(self.window, _('heirs'), self.heirs.import_file, self.heir_list.update)
+
+ def import_heirs(
+ self,
+ ):
+ import_meta_gui(
+ self.window, _("heirs"), self.heirs.import_file, self.heir_list.update
+ )
def export_heirs(self):
- Util.export_meta_gui(self.window, _('heirs'), self.heirs.export_file)
+ Util.export_meta_gui(self.window, _("heirs"), self.heirs.export_file)
- def prepare_will(self, ignore_duplicate = False, keep_original = False):
- will = self.build_inheritance_transaction(ignore_duplicate = ignore_duplicate, keep_original=keep_original)
+ def prepare_will(self, ignore_duplicate=False, keep_original=False):
+ will = self.build_inheritance_transaction(
+ ignore_duplicate=ignore_duplicate, keep_original=keep_original
+ )
return will
-
- def delete_not_valid(self,txid,s_utxo):
+
+ def delete_not_valid(self, txid, s_utxo):
raise NotImplementedError()
- def update_will(self,will):
- Will.update_will(self.willitems,will)
+ def update_will(self, will):
+ Will.update_will(self.willitems, will)
self.willitems.update(will)
- Will.normalize_will(self.willitems,self.wallet)
+ Will.normalize_will(self.willitems, self.wallet)
- def build_will(self, ignore_duplicate = True, keep_original = True ):
+ def build_will(self, ignore_duplicate=True, keep_original=True):
will = {}
- willtodelete=[]
- willtoappend={}
+ willtodelete = []
+ willtoappend = {}
try:
self.init_class_variables()
- self.willexecutors = Willexecutors.get_willexecutors(self.bal_plugin, update=False, bal_window=self)
-
+ self.willexecutors = Willexecutors.get_willexecutors(
+ self.bal_plugin, update=False, bal_window=self
+ )
+
if not self.no_willexecutor:
- f=False
- for u,w in self.willexecutors.items():
+ f = False
+ for u, w in self.willexecutors.items():
if Willexecutors.is_selected(w):
- f=True
+ f = True
if not f:
- raise NoWillExecutorNotPresent("No Will-Executor or backup transaction selected")
- txs = self.heirs.get_transactions(self.bal_plugin,self.window.wallet,self.will_settings['baltx_fees'],None,self.date_to_check)
+ raise NoWillExecutorNotPresent(
+ "No Will-Executor or backup transaction selected"
+ )
+ txs = self.heirs.get_transactions(
+ self.bal_plugin,
+ self.window.wallet,
+ self.will_settings["baltx_fees"],
+ None,
+ self.date_to_check,
+ )
self.logger.info(txs)
creation_time = time.time()
if txs:
for txid in txs:
- txtodelete=[]
+ txtodelete = []
_break = False
tx = {}
- tx['tx'] = txs[txid]
- tx['my_locktime'] = txs[txid].my_locktime
- tx['heirsvalue'] = txs[txid].heirsvalue
- tx['description'] = txs[txid].description
- tx['willexecutor'] = copy.deepcopy(txs[txid].willexecutor)
- tx['status'] = _("New")
- tx['baltx_fees'] = txs[txid].tx_fees
- tx['time'] = creation_time
- tx['heirs'] = copy.deepcopy(txs[txid].heirs)
- tx['txchildren'] = []
- will[txid]=WillItem(tx,_id=txid,wallet=self.wallet)
+ tx["tx"] = txs[txid]
+ tx["my_locktime"] = txs[txid].my_locktime
+ tx["heirsvalue"] = txs[txid].heirsvalue
+ tx["description"] = txs[txid].description
+ tx["willexecutor"] = copy.deepcopy(txs[txid].willexecutor)
+ tx["status"] = _("New")
+ tx["baltx_fees"] = txs[txid].tx_fees
+ tx["time"] = creation_time
+ tx["heirs"] = copy.deepcopy(txs[txid].heirs)
+ tx["txchildren"] = []
+ will[txid] = WillItem(tx, _id=txid, wallet=self.wallet)
self.update_will(will)
except Exception as e:
raise e
pass
- return self.willitems
+ return self.willitems
def check_will(self):
- return Will.is_will_valid(self.willitems, self.block_to_check, self.date_to_check, self.will_settings['baltx_fees'],self.window.wallet.get_utxos(),heirs=self.heirs,willexecutors=self.willexecutors ,self_willexecutor=self.no_willexecutor, wallet = self.wallet, callback_not_valid_tx=self.delete_not_valid)
- def show_message(self,text):
+ return Will.is_will_valid(
+ self.willitems,
+ self.block_to_check,
+ self.date_to_check,
+ self.will_settings["baltx_fees"],
+ self.window.wallet.get_utxos(),
+ heirs=self.heirs,
+ willexecutors=self.willexecutors,
+ self_willexecutor=self.no_willexecutor,
+ wallet=self.wallet,
+ callback_not_valid_tx=self.delete_not_valid,
+ )
+
+ def show_message(self, text):
self.window.show_message(text)
- def show_warning(self,text,parent =None):
- self.window.show_warning(text, parent= None)
- def show_error(self,text):
+
+ def show_warning(self, text, parent=None):
+ self.window.show_warning(text, parent=None)
+
+ def show_error(self, text):
self.window.show_error(text)
- def show_critical(self,text):
+
+ def show_critical(self, text):
self.window.show_critical(text)
- def init_heirs_to_locktime(self,multiverse=False):
+ def init_heirs_to_locktime(self, multiverse=False):
for heir in self.heirs:
- h=self.heirs[heir]
+ h = self.heirs[heir]
if not multiverse:
- self.heirs[heir]=[h[0],h[1],self.will_settings['locktime']]
+ self.heirs[heir] = [h[0], h[1], self.will_settings["locktime"]]
def init_class_variables(self):
- if not self.heirs:
- raise NoHeirsException()
- return
- try:
- self.date_to_check = Util.parse_locktime_string(self.will_settings['threshold'])
- found = False
- self.locktime_blocks=self.bal_plugin.LOCKTIME_BLOCKS.get()
- self.current_block = Util.get_current_height(self.wallet.network)
- self.block_to_check = self.current_block + self.locktime_blocks
- self.no_willexecutor = self.bal_plugin.NO_WILLEXECUTOR.get()
- self.willexecutors = Willexecutors.get_willexecutors(self.bal_plugin,update=True,bal_window=self,task=False)
- self.init_heirs_to_locktime(self.bal_plugin.ENABLE_MULTIVERSE.get())
+ if not self.heirs:
+ raise NoHeirsException()
+ return
+ try:
+ self.date_to_check = Util.parse_locktime_string(
+ self.will_settings["threshold"]
+ )
+ found = False
+ self.locktime_blocks = self.bal_plugin.LOCKTIME_BLOCKS.get()
+ self.current_block = Util.get_current_height(self.wallet.network)
+ self.block_to_check = self.current_block + self.locktime_blocks
+ self.no_willexecutor = self.bal_plugin.NO_WILLEXECUTOR.get()
+ self.willexecutors = Willexecutors.get_willexecutors(
+ self.bal_plugin, update=True, bal_window=self, task=False
+ )
+ self.init_heirs_to_locktime(self.bal_plugin.ENABLE_MULTIVERSE.get())
- except Exception as e:
- self.logger.error(e)
- raise e
+ except Exception as e:
+ self.logger.error(e)
+ raise e
- def build_inheritance_transaction(self,ignore_duplicate = True, keep_original = True):
+ def build_inheritance_transaction(self, ignore_duplicate=True, keep_original=True):
try:
if self.disable_plugin:
self.logger.info("plugin is disabled")
@@ -827,57 +771,76 @@ class BalWindow(Logger):
return
self.init_class_variables()
try:
- Will.check_amounts(self.heirs,self.willexecutors,self.window.wallet.get_utxos(),self.date_to_check,self.window.wallet.dust_threshold())
+ Will.check_amounts(
+ self.heirs,
+ self.willexecutors,
+ self.window.wallet.get_utxos(),
+ self.date_to_check,
+ self.window.wallet.dust_threshold(),
+ )
except AmountException as e:
- self.show_warning(_(f"In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.\n{e}"))
- locktime = Util.parse_locktime_string(self.will_settings['locktime'])
+ self.show_warning(
+ _(
+ f"In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.\n{e}"
+ )
+ )
+ locktime = Util.parse_locktime_string(self.will_settings["locktime"])
if locktime < self.date_to_check:
self.show_error(_("locktime is lower than threshold"))
return
if not self.no_willexecutor:
- f=False
- for k,we in self.willexecutors.items():
+ f = False
+ for k, we in self.willexecutors.items():
if Willexecutors.is_selected(we):
- f=True
+ f = True
if not f:
- self.show_error(_(" no backup transaction or willexecutor selected"))
+ self.show_error(
+ _(" no backup transaction or willexecutor selected")
+ )
return
try:
self.check_will()
- except WillExpiredException as e:
+ except WillExpiredException:
self.invalidate_will()
return
except NoHeirsException:
return
except NotCompleteWillException as e:
- self.logger.info("{}:{}".format(type(e),e))
- message = False
- if isinstance(e,HeirChangeException):
- message ="Heirs changed:"
- elif isinstance(e,WillExecutorNotPresent):
+ self.logger.info("{}:{}".format(type(e), e))
+ message = False
+ if isinstance(e, HeirChangeException):
+ message = "Heirs changed:"
+ elif isinstance(e, WillExecutorNotPresent):
message = "Will-Executor not present:"
- elif isinstance(e,WillexecutorChangeException):
+ elif isinstance(e, WillexecutorChangeException):
message = "Will-Executor changed"
- elif isinstance(e,TxFeesChangedException):
+ elif isinstance(e, TxFeesChangedException):
message = "Txfees are changed"
- elif isinstance(e,HeirNotFoundException):
+ elif isinstance(e, HeirNotFoundException):
message = "Heir not found"
if message:
- self.show_message(f"{_(message)}:\n {e}\n{_('will have to be built')}")
-
+ self.show_message(
+ f"{_(message)}:\n {e}\n{_('will have to be built')}"
+ )
+
self.logger.info("build will")
- self.build_will(ignore_duplicate,keep_original)
+ self.build_will(ignore_duplicate, keep_original)
try:
self.check_will()
- for wid,w in self.willitems.items():
- self.wallet.set_label(wid,"BAL Transaction")
+ for wid, w in self.willitems.items():
+ self.wallet.set_label(wid, "BAL Transaction")
except WillExpiredException as e:
self.invalidate_will()
except NotCompleteWillException as e:
- self.show_error("Error:{}\n {}".format(str(e),_("Please, check your heirs, locktime and threshold!")))
+ self.show_error(
+ "Error:{}\n {}".format(
+ str(e),
+ _("Please, check your heirs, locktime and threshold!"),
+ )
+ )
self.window.history_list.update()
self.window.utxo_list.update()
@@ -890,10 +853,10 @@ class BalWindow(Logger):
self,
tx: Transaction,
*,
- parent: 'ElectrumWindow',
+ parent: "ElectrumWindow",
prompt_if_unsaved: bool = False,
external_keypairs: Mapping[bytes, bytes] = None,
- payment_identifier: 'PaymentIdentifier' = None,
+ payment_identifier: "PaymentIdentifier" = None,
):
try:
d = TxDialog(
@@ -901,62 +864,76 @@ class BalWindow(Logger):
parent=parent,
prompt_if_unsaved=prompt_if_unsaved,
external_keypairs=external_keypairs,
- #payment_identifier=payment_identifier,
+ # payment_identifier=payment_identifier,
+ )
+ d.setWindowIcon(
+ read_QIcon_from_bytes(self.bal_plugin.read_file("bal32x32.png"))
)
- d.setWindowIcon(read_QIcon_from_bytes(self.bal_plugin.read_file("bal32x32.png")))
except SerializationError as e:
- self.logger.error('unable to deserialize the transaction')
- parent.show_critical(_("Electrum was unable to deserialize the transaction:") + "\n" + str(e))
+ self.logger.error("unable to deserialize the transaction")
+ parent.show_critical(
+ _("Electrum was unable to deserialize the transaction:") + "\n" + str(e)
+ )
else:
d.show()
return d
- def show_transaction(self,tx=None,txid=None,parent = None):
+ def show_transaction(self, tx=None, txid=None, parent=None):
if not parent:
parent = self.window
- if txid !=None and txid in self.willitems:
- tx=self.willitems[txid].tx
+ if txid != None and txid in self.willitems:
+ tx = self.willitems[txid].tx
if not tx:
raise Exception(_("no tx"))
- return self.show_transaction_real(tx,parent=parent)
+ return self.show_transaction_real(tx, parent=parent)
def invalidate_will(self):
def on_success(result):
if result:
- self.show_message(_("Please sign and broadcast this transaction to invalidate current will"))
- self.wallet.set_label(result.txid(),"BAL Invalidate")
- a=self.show_transaction(result)
+ self.show_message(
+ _(
+ "Please sign and broadcast this transaction to invalidate current will"
+ )
+ )
+ self.wallet.set_label(result.txid(), "BAL Invalidate")
+ a = self.show_transaction(result)
else:
self.show_message(_("No transactions to invalidate"))
+
def on_failure(exec_info):
self.show_error(f"ERROR:{exec_info}")
- fee_per_byte=self.will_settings.get('baltx_fees',1)
- task = partial(Will.invalidate_will,self.willitems,self.wallet,fee_per_byte)
+ fee_per_byte = self.will_settings.get("baltx_fees", 1)
+ task = partial(Will.invalidate_will, self.willitems, self.wallet, fee_per_byte)
msg = _("Calculating Transactions")
- self.waiting_dialog = BalWaitingDialog(self, msg, task, on_success, on_failure,exe=False)
+ self.waiting_dialog = BalWaitingDialog(
+ self, msg, task, on_success, on_failure, exe=False
+ )
self.waiting_dialog.exe()
- def sign_transactions(self,password):
+ def sign_transactions(self, password):
try:
- txs={}
+ txs = {}
signed = None
tosign = None
+
def get_message():
msg = ""
if signed:
- msg=_(f"signed: {signed}\n")
+ msg = _(f"signed: {signed}\n")
return msg + _(f"signing: {tosign}")
+
for txid in Will.only_valid(self.willitems):
wi = self.willitems[txid]
tx = copy.deepcopy(wi.tx)
- if wi.get_status('COMPLETE'):
- txs[txid]=tx
+ if wi.get_status("COMPLETE"):
+ txs[txid] = tx
continue
- tosign=txid
+ tosign = txid
try:
self.waiting_dialog.update(get_message())
- except:pass
+ except:
+ pass
for txin in tx.inputs():
prevout = txin.prevout.to_json()
if prevout[0] in self.willitems:
@@ -966,27 +943,27 @@ class BalWindow(Logger):
txin.script_descriptor = change.script_descriptor
except:
pass
- txin.is_mine=True
- txin._TxInput__address=change.address
+ txin.is_mine = True
+ txin._TxInput__address = change.address
txin._TxInput__scriptpubkey = change.scriptpubkey
txin._TxInput__value_sats = change.value
-
- self.wallet.sign_transaction(tx, password,ignore_warnings=True)
- signed=tosign
- is_complete=False
+
+ self.wallet.sign_transaction(tx, password, ignore_warnings=True)
+ signed = tosign
+ is_complete = False
if tx.is_complete():
- is_complete=True
- wi.set_status('COMPLETE',True)
- txs[txid]=tx
- except Exception as e:
+ is_complete = True
+ wi.set_status("COMPLETE", True)
+ txs[txid] = tx
+ except Exception:
return None
return txs
- def get_wallet_password(self,message=None,parent=None):
- parent =self.window if not parent else parent
+ def get_wallet_password(self, message=None, parent=None):
+ parent = self.window if not parent else parent
password = None
if self.wallet.has_keystore_encryption():
- password = self.bal_plugin.password_dialog(parent=parent,msg=message)
+ password = self.bal_plugin.password_dialog(parent=parent, msg=message)
if password is None:
return False
try:
@@ -999,7 +976,7 @@ class BalWindow(Logger):
def on_close(self):
try:
if not self.disable_plugin:
- close_window=BalBuildWillDialog(self)
+ close_window = BalBuildWillDialog(self)
close_window.build_will_task()
self.save_willitems()
self.heirs_tab.close()
@@ -1008,18 +985,18 @@ class BalWindow(Logger):
self.window.toggle_tab(self.heirs_tab)
self.window.toggle_tab(self.will_tab)
self.window.tabs.update()
- except Exception as e:
+ except Exception:
pass
- def ask_password_and_sign_transactions(self,callback=None):
+ def ask_password_and_sign_transactions(self, callback=None):
def on_success(txs):
if txs:
- for txid,tx in txs.items():
- self.willitems[txid].tx=copy.deepcopy(tx)
- self.will[txid]=self.willitems[txid].to_dict()
+ for txid, tx in txs.items():
+ self.willitems[txid].tx = copy.deepcopy(tx)
+ self.will[txid] = self.willitems[txid].to_dict()
try:
self.will_list.update()
- except:
+ except Exception:
pass
if callback:
try:
@@ -1030,149 +1007,178 @@ class BalWindow(Logger):
def on_failure(exc_info):
self.logger.info("sign fail: {}".format(exc_info))
self.show_error(exc_info)
- password= self.get_wallet_password()
- task = partial(self.sign_transactions,password)
- msg = _('Signing transactions...')
- self.waiting_dialog = BalWaitingDialog(self, msg, task, on_success, on_failure,exe=False)
+
+ password = self.get_wallet_password()
+ task = partial(self.sign_transactions, password)
+ msg = _("Signing transactions...")
+ self.waiting_dialog = BalWaitingDialog(
+ self, msg, task, on_success, on_failure, exe=False
+ )
self.waiting_dialog.exe()
- def broadcast_transactions(self,force=False):
+ def broadcast_transactions(self, force=False):
def on_success(sulcess):
self.will_list.update()
if sulcess:
- self.logger.info("error, some transaction was not sent");
+ self.logger.info("error, some transaction was not sent")
self.show_warning(_("Some transaction was not broadcasted"))
return
self.logger.debug("OK, sulcess transaction was sent")
- self.show_message(_("All transactions are broadcasted to respective Will-Executors"))
+ self.show_message(
+ _("All transactions are broadcasted to respective Will-Executors")
+ )
def on_failure(err):
self.logger.error(err)
- task = partial(self.push_transactions_to_willexecutors,force)
- msg = _('Selecting Will-Executors')
- self.waiting_dialog = BalWaitingDialog(self,msg,task,on_success,on_failure,exe=False)
+ task = partial(self.push_transactions_to_willexecutors, force)
+ msg = _("Selecting Will-Executors")
+ self.waiting_dialog = BalWaitingDialog(
+ self, msg, task, on_success, on_failure, exe=False
+ )
self.waiting_dialog.exe()
- def push_transactions_to_willexecutors(self,force=False):
+ def push_transactions_to_willexecutors(self, force=False):
willexecutors = Willexecutors.get_willexecutor_transactions(self.willitems)
+
def getMsg(willexecutors):
msg = "Broadcasting Transactions to Will-Executors:\n"
for url in willexecutors:
msg += f"{url}:\t{willexecutors[url]['broadcast_status']}\n"
return msg
- error=False
+
+ error = False
for url in willexecutors:
willexecutor = willexecutors[url]
self.waiting_dialog.update(getMsg(willexecutors))
- if 'txs' in willexecutor:
+ if "txs" in willexecutor:
try:
- if Willexecutors.push_transactions_to_willexecutor(willexecutors[url]):
- for wid in willexecutors[url]['txsids']:
- self.willitems[wid].set_status('PUSHED', True)
- willexecutors[url]['broadcast_status'] = _("Success")
+ if Willexecutors.push_transactions_to_willexecutor(
+ willexecutors[url]
+ ):
+ for wid in willexecutors[url]["txsids"]:
+ self.willitems[wid].set_status("PUSHED", True)
+ willexecutors[url]["broadcast_status"] = _("Success")
else:
- for wid in willexecutors[url]['txsids']:
- self.willitems[wid].set_status('PUSH_FAIL', True)
- error=True
- willexecutors[url]['broadcast_status'] = _("Failed")
- del willexecutor['txs']
+ for wid in willexecutors[url]["txsids"]:
+ self.willitems[wid].set_status("PUSH_FAIL", True)
+ error = True
+ willexecutors[url]["broadcast_status"] = _("Failed")
+ del willexecutor["txs"]
except Willexecutors.AlreadyPresentException:
- for wid in willexecutor['txsids']:
- row = self.waiting_dialog.update("checking {} - {} : {}".format(self.willitems[wid].we['url'],wid, "Waiting"))
+ for wid in willexecutor["txsids"]:
+ self.waiting_dialog.update(
+ "checking {} - {} : {}".format(
+ self.willitems[wid].we["url"], wid, "Waiting"
+ )
+ )
self.willitems[wid].check_willexecutor()
- row = self.waiting_dialog.update("checked {} - {} : {}".format(self.willitems[wid].we['url'],wid,self.willitems[wid].get_status("CHECKED" )))
+ self.waiting_dialog.update(
+ "checked {} - {} : {}".format(
+ self.willitems[wid].we["url"],
+ wid,
+ self.willitems[wid].get_status("CHECKED"),
+ )
+ )
if error:
return True
-
- def export_json_file(self,path):
+ def export_json_file(self, path):
for wid in self.willitems:
- self.willitems[wid].set_status('EXPORTED', True)
- self.will[wid]=self.willitems[wid].to_dict()
+ self.willitems[wid].set_status("EXPORTED", True)
+ self.will[wid] = self.willitems[wid].to_dict()
write_json_file(path, self.will)
def export_will(self):
try:
- Util.export_meta_gui(self.window, _('will.json'), self.export_json_file)
+ Util.export_meta_gui(self.window, _("will.json"), self.export_json_file)
except Exception as e:
self.show_error(str(e))
raise e
-
+
def import_will(self):
def sulcess():
self.will_list.update_will(self.willitems)
- import_meta_gui(self.window, _('will'), self.import_json_file,sulcess)
- def import_json_file(self,path):
+ import_meta_gui(self.window, _("will"), self.import_json_file, sulcess)
+
+ def import_json_file(self, path):
try:
data = read_json_file(path)
willitems = {}
- for k,v in data.items():
- data[k]['tx']=tx_from_any(v['tx'])
- willitems[k]=WillItem(data[k],_id=k)
+ for k, v in data.items():
+ data[k]["tx"] = tx_from_any(v["tx"])
+ willitems[k] = WillItem(data[k], _id=k)
self.update_will(willitems)
except Exception as e:
raise e
raise FileImportFailed(_("Invalid will file"))
- def check_transactions_task(self,will):
+ def check_transactions_task(self, will):
start = time.time()
- for wid,w in will.items():
- self.waiting_dialog.update("checking transaction: {}\n willexecutor: {}".format(wid,w.we['url']))
- w.check_willexecutor()
+ for wid, w in will.items():
+ self.waiting_dialog.update(
+ "checking transaction: {}\n willexecutor: {}".format(wid, w.we["url"])
+ )
+ w.check_willexecutor()
- if time.time()-start < 3:
- time.sleep(3-(time.time()-start))
+ if time.time() - start < 3:
+ time.sleep(3 - (time.time() - start))
- def check_transactions(self,will):
+ def check_transactions(self, will):
def on_success(result):
del self.waiting_dialog
self.update_all()
pass
+
def on_failure(e):
self.logger.error(f"error checking transactions {e}")
pass
- task = partial(self.check_transactions_task,will)
- msg = _('Check Transaction')
- self.waiting_dialog = BalWaitingDialog(self,msg,task,on_success,on_failure,exe=False)
+ task = partial(self.check_transactions_task, will)
+ msg = _("Check Transaction")
+ self.waiting_dialog = BalWaitingDialog(
+ self, msg, task, on_success, on_failure, exe=False
+ )
self.waiting_dialog.exe()
- def ping_willexecutors_task(self,wes):
+ def ping_willexecutors_task(self, wes):
self.logger.info("ping willexecutots task")
pinged = []
failed = []
+
def get_title():
- msg = _('Ping Will-Executors:')
+ msg = _("Ping Will-Executors:")
msg += "\n\n"
for url in wes:
urlstr = "{:<50}: ".format(url[:50])
if url in pinged:
urlstr += "Ok"
elif url in failed:
- urlstr +="Ko"
+ urlstr += "Ko"
else:
urlstr += "--"
- urlstr+="\n"
- msg+=urlstr
+ urlstr += "\n"
+ msg += urlstr
- return msg
- for url,we in wes.items():
+ return msg
+
+ for url, we in wes.items():
try:
self.waiting_dialog.update(get_title())
- except:
+ except Exception:
pass
- wes[url]=Willexecutors.get_info_task(url,we)
- if wes[url]['status']=='KO':
+ wes[url] = Willexecutors.get_info_task(url, we)
+ if wes[url]["status"] == "KO":
failed.append(url)
else:
pinged.append(url)
-
- def ping_willexecutors(self,wes,parent=None):
+
+ def ping_willexecutors(self, wes, parent=None):
if not parent:
- parent=self
+ parent = self
+
def on_success(result):
del self.waiting_dialog
try:
@@ -1180,19 +1186,22 @@ class BalWindow(Logger):
except Exception as e:
_logger.error(f"error updating willexecutors {e}")
pass
+
def on_failure(e):
self.logger.error(e)
pass
+
self.logger.info("ping willexecutors")
- task = partial(self.ping_willexecutors_task,wes)
- msg = _('Ping Will-Executors')
- self.waiting_dialog = BalWaitingDialog(self,msg,task,on_success,on_failure,exe=False)
+ task = partial(self.ping_willexecutors_task, wes)
+ msg = _("Ping Will-Executors")
+ self.waiting_dialog = BalWaitingDialog(
+ self, msg, task, on_success, on_failure, exe=False
+ )
self.waiting_dialog.exe()
def preview_modal_dialog(self):
- self.dw=WillDetailDialog(self)
+ self.dw = WillDetailDialog(self)
self.dw.show()
-
def update_all(self):
self.will_list.update_will(self.willitems)
@@ -1200,15 +1209,38 @@ class BalWindow(Logger):
self.will_tab.update()
self.will_list.update()
-def add_widget(grid,label,widget,row,help_):
- grid.addWidget(QLabel(_(label)),row,0)
- grid.addWidget(widget,row,1)
- grid.addWidget(HelpButton(help_),row,2)
-class HeirsLockTimeEdit(QWidget):
+def add_widget(grid, label, widget, row, help_):
+ grid.addWidget(QLabel(_(label)), row, 0)
+ grid.addWidget(widget, row, 1)
+ grid.addWidget(HelpButton(help_), row, 2)
+
+
+class _LockTimeEditor:
+ min_allowed_value = NLOCKTIME_MIN
+ max_allowed_value = NLOCKTIME_MAX
+
+ def get_locktime(self) -> Optional[int]:
+ raise NotImplementedError()
+
+ def set_locktime(self, x: Any, force=True) -> None:
+ raise NotImplementedError()
+
+ def is_acceptable_locktime(cls, x: Any) -> bool:
+ if not x: # e.g. empty string
+ return True
+ try:
+ x = int(x)
+ except Exception:
+ return False
+ return cls.min_allowed_value <= x <= cls.max_allowed_value
+
+
+class HeirsLockTimeEdit(QWidget, _LockTimeEditor):
valueEdited = pyqtSignal()
locktime_threshold = 50000000
- def __init__(self, parent=None,default_index = 1):
+
+ def __init__(self, parent=None, default_index=1):
QWidget.__init__(self, parent)
hbox = QHBoxLayout()
@@ -1216,19 +1248,18 @@ class HeirsLockTimeEdit(QWidget):
hbox.setContentsMargins(0, 0, 0, 0)
hbox.setSpacing(0)
- self.locktime_raw_e = LockTimeRawEdit(self,time_edit = self)
- self.locktime_date_e = LockTimeDateEdit(self,time_edit = self)
+ self.locktime_raw_e = LockTimeRawEdit(self, time_edit=self)
+ self.locktime_date_e = LockTimeDateEdit(self, time_edit=self)
self.editors = [self.locktime_raw_e, self.locktime_date_e]
self.combo = QComboBox()
- options = [_("Raw"),_("Date")]
+ options = [_("Raw"), _("Date")]
self.option_index_to_editor_map = {
0: self.locktime_raw_e,
1: self.locktime_date_e,
}
self.combo.addItems(options)
-
self.editor = self.option_index_to_editor_map[default_index]
self.combo.currentIndexChanged.connect(self.on_current_index_changed)
self.combo.setCurrentIndex(default_index)
@@ -1238,106 +1269,91 @@ class HeirsLockTimeEdit(QWidget):
for w in self.editors:
hbox.addWidget(w)
hbox.addStretch(1)
- #spacer_widget = QWidget()
- #spacer_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
- #hbox.addWidget(spacer_widget)
-
-
+ # spacer_widget = QWidget()
+ # spacer_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
+ # hbox.addWidget(spacer_widget)
self.locktime_raw_e.editingFinished.connect(self.valueEdited.emit)
self.locktime_date_e.dateTimeChanged.connect(self.valueEdited.emit)
self.combo.currentIndexChanged.connect(self.valueEdited.emit)
- def on_current_index_changed(self,i):
+ def on_current_index_changed(self, i):
for w in self.editors:
w.setVisible(False)
w.setEnabled(False)
prev_locktime = self.editor.get_locktime()
self.editor = self.option_index_to_editor_map[i]
if self.editor.is_acceptable_locktime(prev_locktime):
- self.editor.set_locktime(prev_locktime,force=True)
+ self.editor.set_locktime(prev_locktime, force=True)
self.editor.setVisible(True)
self.editor.setEnabled(True)
def get_locktime(self) -> Optional[str]:
return self.editor.get_locktime()
- def set_index(self,index):
+ def set_index(self, index):
self.combo.setCurrentIndex(index)
self.on_current_index_changed(index)
- def set_locktime(self, x: Any,force=True) -> None:
- self.editor.set_locktime(x,force)
+ def set_locktime(self, x: Any, force=True) -> None:
+ self.editor.set_locktime(x, force)
-class _LockTimeEditor:
- min_allowed_value = NLOCKTIME_MIN
- max_allowed_value = NLOCKTIME_MAX
-
- def get_locktime(self) -> Optional[int]:
- raise NotImplementedError()
-
- def set_locktime(self, x: Any,force=True) -> None:
- raise NotImplementedError()
-
- def is_acceptable_locktime(cls, x: Any) -> bool:
- if not x: # e.g. empty string
- return True
- try:
- x = int(x)
- except Exception as e:
- return False
- return cls.min_allowed_value <= x <= cls.max_allowed_value
class LockTimeRawEdit(QLineEdit, _LockTimeEditor):
- def __init__(self, parent=None,time_edit=None):
+ def __init__(self, parent=None, time_edit=None):
QLineEdit.__init__(self, parent)
self.setFixedWidth(14 * char_width_in_lineedit())
self.textChanged.connect(self.numbify)
self.isdays = False
self.isyears = False
self.isblocks = False
- self.time_edit=time_edit
+ self.time_edit = time_edit
- def replace_str(self,text):
- return str(text).replace('d','').replace('y','').replace('b','')
+ def replace_str(self, text):
+ return str(text).replace("d", "").replace("y", "").replace("b", "")
- def checkbdy(self,s,pos,appendix):
+ def checkbdy(self, s, pos, appendix):
try:
- charpos = pos-1
- charpos = max(0,charpos)
- charpos = min(len(s)-1,charpos)
- if appendix == s[charpos]:
- s=self.replace_str(s)+appendix
+ charpos = pos - 1
+ charpos = max(0, charpos)
+ charpos = min(len(s) - 1, charpos)
+ if appendix == s[charpos]:
+ s = self.replace_str(s) + appendix
pos = charpos
- except Exception as e:
+ except Exception:
pass
return pos, s
def numbify(self):
text = self.text().strip()
- #chars = '0123456789bdy' removed the option to choose locktime by block
- chars = '0123456789dy'
- pos = posx = self.cursorPosition()
- pos = len(''.join([i for i in text[:pos] if i in chars]))
- s = ''.join([i for i in text if i in chars])
+ # chars = '0123456789bdy' removed the option to choose locktime by block
+ chars = "0123456789dy"
+ pos = self.cursorPosition()
+ pos = len("".join([i for i in text[:pos] if i in chars]))
+ s = "".join([i for i in text if i in chars])
self.isdays = False
self.isyears = False
self.isblocks = False
- pos,s = self.checkbdy(s,pos,'d')
- pos,s = self.checkbdy(s,pos,'y')
- pos,s = self.checkbdy(s,pos,'b')
+ pos, s = self.checkbdy(s, pos, "d")
+ pos, s = self.checkbdy(s, pos, "y")
+ pos, s = self.checkbdy(s, pos, "b")
- if 'd' in s: self.isdays = True
- if 'y' in s: self.isyears = True
- if 'b' in s: self.isblocks = True
+ if "d" in s:
+ self.isdays = True
+ if "y" in s:
+ self.isyears = True
+ if "b" in s:
+ self.isblocks = True
+ if self.isdays:
+ s = self.replace_str(s) + "d"
+ if self.isyears:
+ s = self.replace_str(s) + "y"
+ if self.isblocks:
+ s = self.replace_str(s) + "b"
- if self.isdays: s= self.replace_str(s) + 'd'
- if self.isyears: s = self.replace_str(s) + 'y'
- if self.isblocks: s= self.replace_str(s) + 'b'
-
- self.set_locktime(s,force=False)
+ self.set_locktime(s, force=False)
# setText sets Modified to False. Instead we want to remember
# if updates were because of user modification.
self.setModified(self.hasFocus())
@@ -1346,31 +1362,32 @@ class LockTimeRawEdit(QLineEdit, _LockTimeEditor):
def get_locktime(self) -> Optional[str]:
try:
return str(self.text())
- except Exception as e:
+ except Exception:
return None
- def set_locktime(self, x: Any,force=True) -> None:
+ def set_locktime(self, x: Any, force=True) -> None:
out = str(x)
- if 'd' in out:
- out = self.replace_str(x)+'d'
- elif 'y' in out:
- out = self.replace_str(x)+'y'
- elif 'b' in out:
- out = self.replace_str(x)+'b'
+ if "d" in out:
+ out = self.replace_str(x) + "d"
+ elif "y" in out:
+ out = self.replace_str(x) + "y"
+ elif "b" in out:
+ out = self.replace_str(x) + "b"
else:
try:
out = int(x)
- except Exception as e:
- self.setText('')
+ except Exception:
+ self.setText("")
return
out = max(out, self.min_allowed_value)
out = min(out, self.max_allowed_value)
self.setText(str(out))
+
class LockTimeHeightEdit(LockTimeRawEdit):
max_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX
- def __init__(self, parent=None,time_edit=None):
+ def __init__(self, parent=None, time_edit=None):
LockTimeRawEdit.__init__(self, parent)
self.setFixedWidth(20 * char_width_in_lineedit())
self.time_edit = time_edit
@@ -1385,6 +1402,7 @@ class LockTimeHeightEdit(LockTimeRawEdit):
painter.setPen(ColorScheme.GRAY.as_color())
painter.drawText(textRect, int(Qt.AlignRight | Qt.AlignVCenter), "height")
+
def get_max_allowed_timestamp() -> int:
ts = NLOCKTIME_MAX
# Test if this value is within the valid timestamp limits (which is platform-dependent).
@@ -1392,15 +1410,16 @@ def get_max_allowed_timestamp() -> int:
try:
datetime.fromtimestamp(ts)
except (OSError, OverflowError):
- ts = 2 ** 31 - 1 # INT32_MAX
+ ts = 2**31 - 1 # INT32_MAX
datetime.fromtimestamp(ts) # test if raises
return ts
+
class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
min_allowed_value = NLOCKTIME_BLOCKHEIGHT_MAX + 1
max_allowed_value = get_max_allowed_timestamp()
- def __init__(self, parent=None,time_edit=None):
+ def __init__(self, parent=None, time_edit=None):
QDateTimeEdit.__init__(self, parent)
self.setMinimumDateTime(datetime.fromtimestamp(self.min_allowed_value))
self.setMaximumDateTime(datetime.fromtimestamp(self.max_allowed_value))
@@ -1412,7 +1431,7 @@ class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
locktime = int(time.mktime(dt.timetuple()))
return locktime
- def set_locktime(self, x: Any,force = False) -> None:
+ def set_locktime(self, x: Any, force=False) -> None:
if not self.is_acceptable_locktime(x):
self.setDateTime(QDateTime.currentDateTime())
return
@@ -1424,36 +1443,39 @@ class LockTimeDateEdit(QDateTimeEdit, _LockTimeEditor):
dt = datetime.fromtimestamp(x)
self.setDateTime(dt)
+
_NOT_GIVEN = object() # sentinel value
+
class PercAmountEdit(BTCAmountEdit):
- def __init__(self, decimal_point, is_int=False, parent=None, *, max_amount=_NOT_GIVEN):
+ def __init__(
+ self, decimal_point, is_int=False, parent=None, *, max_amount=_NOT_GIVEN
+ ):
super().__init__(decimal_point, is_int, parent, max_amount=max_amount)
def numbify(self):
text = self.text().strip()
- if text == '!':
+ if text == "!":
self.shortcut.emit()
return
pos = self.cursorPosition()
- chars = '0123456789%'
+ chars = "0123456789%"
chars += DECIMAL_POINT
-
- s = ''.join([i for i in text if i in chars])
- if '%' in s:
- self.is_perc=True
- s=s.replace('%','')
+ s = "".join([i for i in text if i in chars])
+
+ if "%" in s:
+ self.is_perc = True
+ s = s.replace("%", "")
else:
- self.is_perc=False
+ self.is_perc = False
if DECIMAL_POINT in s:
p = s.find(DECIMAL_POINT)
- s = s.replace(DECIMAL_POINT, '')
- s = s[:p] + DECIMAL_POINT + s[p:p+8]
+ s = s.replace(DECIMAL_POINT, "")
+ s = s[:p] + DECIMAL_POINT + s[p : p + 8]
if self.is_perc:
- s+='%'
-
+ s += "%"
self.setText(s)
self.setModified(self.hasFocus())
@@ -1461,15 +1483,16 @@ class PercAmountEdit(BTCAmountEdit):
def _get_amount_from_text(self, text: str) -> Union[None, Decimal, int]:
try:
- text = text.replace(DECIMAL_POINT, '.')
- text = text.replace('%', '')
+ text = text.replace(DECIMAL_POINT, ".")
+ text = text.replace("%", "")
return (Decimal)(text)
except Exception:
return None
def _get_text_from_amount(self, amount):
out = super()._get_text_from_amount(amount)
- if self.is_perc: out+='%'
+ if self.is_perc:
+ out += "%"
return out
def paintEvent(self, event):
@@ -1477,97 +1500,149 @@ class PercAmountEdit(BTCAmountEdit):
if self.base_unit:
panel = QStyleOptionFrame()
self.initStyleOption(panel)
- textRect = self.style().subElementRect(QStyle.SubElement.SE_LineEditContents, panel, self)
+ textRect = self.style().subElementRect(
+ QStyle.SubElement.SE_LineEditContents, panel, self
+ )
textRect.adjust(2, 0, -10, 0)
painter = QPainter(self)
painter.setPen(ColorScheme.GRAY.as_color())
- if len(self.text())==0:
- painter.drawText(textRect, int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter), self.base_unit() + " or perc value")
+ if len(self.text()) == 0:
+ painter.drawText(
+ textRect,
+ int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter),
+ self.base_unit() + " or perc value",
+ )
+
class BalDialog(WindowModalDialog):
- def __init__(self,parent,bal_plugin,title=None, icon = 'bal32x32.png'):
- self.parent=parent
- WindowModalDialog.__init__(self,parent,title)
- #WindowModalDialog.__init__(self,parent)
+ def __init__(self, parent, bal_plugin, title=None, icon="bal32x32.png"):
+ self.parent = parent
+ WindowModalDialog.__init__(self, parent, title)
+ # WindowModalDialog.__init__(self,parent)
self.setWindowIcon(read_QIcon_from_bytes(bal_plugin.read_file(icon)))
+
class BalWizardDialog(BalDialog):
- def __init__(self,bal_window: 'BalWindow' ):
+ def __init__(self, bal_window: "BalWindow"):
assert bal_window
- BalDialog.__init__(self, bal_window.window, bal_window.bal_plugin, _("Bal Wizard Setup"))
+ BalDialog.__init__(
+ self, bal_window.window, bal_window.bal_plugin, _("Bal Wizard Setup")
+ )
self.setMinimumSize(800, 400)
self.bal_window = bal_window
self.parent = bal_window.window
- self.layout=QVBoxLayout(self)
- self.widget = BalWizardHeirsWidget(bal_window,self,self.on_next_heir,None,self.on_cancel_heir)
+ self.layout = QVBoxLayout(self)
+ self.widget = BalWizardHeirsWidget(
+ bal_window, self, self.on_next_heir, None, self.on_cancel_heir
+ )
self.layout.addWidget(self.widget)
- def next_widget(self,widget):
+ def next_widget(self, widget):
self.layout.removeWidget(self.widget)
self.widget.close()
- self.widget=widget
+ self.widget = widget
self.layout.addWidget(self.widget)
- #self.update()
- #self.repaint()
+ # self.update()
+ # self.repaint()
def on_next_heir(self):
- self.next_widget(BalWizardLocktimeAndFeeWidget(self.bal_window,self,self.on_next_locktimeandfee,self.on_previous_heir,self.on_cancel_heir))
+ self.next_widget(
+ BalWizardLocktimeAndFeeWidget(
+ self.bal_window,
+ self,
+ self.on_next_locktimeandfee,
+ self.on_previous_heir,
+ self.on_cancel_heir,
+ )
+ )
def on_previous_heir(self):
- self.next_widget(BalWizardHeirsWidget(self.bal_window,self,self.on_next_heir,None,self.on_cancel_heir))
+ self.next_widget(
+ BalWizardHeirsWidget(
+ self.bal_window, self, self.on_next_heir, None, self.on_cancel_heir
+ )
+ )
def on_cancel_heir(self):
pass
+
def on_next_wedonwload(self):
- self.next_widget(BalWizardWEWidget(self.bal_window,self,self.on_next_we,self.on_next_locktimeandfee,self.on_cancel_heir))
+ self.next_widget(
+ BalWizardWEWidget(
+ self.bal_window,
+ self,
+ self.on_next_we,
+ self.on_next_locktimeandfee,
+ self.on_cancel_heir,
+ )
+ )
+
def on_next_we(self):
- close_window=BalBuildWillDialog(self.bal_window,self)
+ close_window = BalBuildWillDialog(self.bal_window, self)
close_window.build_will_task()
self.close()
- #self.next_widget(BalWizardLocktimeAndFeeWidget(self.bal_window,self,self.on_next_locktimeandfee,self.on_next_wedonwload,self.on_next_wedonwload.on_cancel_heir))
+ # self.next_widget(BalWizardLocktimeAndFeeWidget(self.bal_window,self,self.on_next_locktimeandfee,self.on_next_wedonwload,self.on_next_wedonwload.on_cancel_heir))
def on_next_locktimeandfee(self):
- self.next_widget(BalWizardWEDownloadWidget(self.bal_window,self,self.on_next_wedonwload,self.on_next_heir,self.on_cancel_heir))
+ self.next_widget(
+ BalWizardWEDownloadWidget(
+ self.bal_window,
+ self,
+ self.on_next_wedonwload,
+ self.on_next_heir,
+ self.on_cancel_heir,
+ )
+ )
+
def on_accept(self):
pass
+
def on_reject(self):
pass
+
def on_close(self):
pass
- def closeEvent(self,event):
+
+ def closeEvent(self, event):
self.bal_window.update_all()
self.bal_window.heir_list.update_will_settings()
pass
+
class BalWizardWidget(QWidget):
title = None
message = None
- def __init__(self,bal_window: 'BalWindow',parent,on_next,on_previous,on_cancel):
- QWidget.__init__(self,parent)
- self.vbox=QVBoxLayout(self)
- self.bal_window=bal_window
- self.parent=parent
- self.on_next=on_next
- self.on_cancel=on_cancel
+
+ def __init__(
+ self, bal_window: "BalWindow", parent, on_next, on_previous, on_cancel
+ ):
+ QWidget.__init__(self, parent)
+ self.vbox = QVBoxLayout(self)
+ self.bal_window = bal_window
+ self.parent = parent
+ self.on_next = on_next
+ self.on_cancel = on_cancel
self.titleLabel = QLabel(self.title)
self.vbox.addWidget(self.titleLabel)
self.messageLabel = QLabel(_(self.message))
self.vbox.addWidget(self.messageLabel)
self.content = self.get_content()
- self.content_container= QWidget()
- self.containrelayout=QVBoxLayout(self.content_container)
+ self.content_container = QWidget()
+ self.containrelayout = QVBoxLayout(self.content_container)
self.containrelayout.addWidget(self.content)
self.vbox.addWidget(self.content_container)
spacer_widget = QWidget()
- spacer_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
+ spacer_widget.setSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
+ )
self.vbox.addWidget(spacer_widget)
- self.buttons=[]
+ self.buttons = []
if on_previous:
- self.on_previous=on_previous
+ self.on_previous = on_previous
self.previous_button = QPushButton(_("Previous"))
self.previous_button.clicked.connect(self._on_previous)
self.buttons.append(self.previous_button)
@@ -1575,7 +1650,7 @@ class BalWizardWidget(QWidget):
self.next_button = QPushButton(_("Next"))
self.next_button.clicked.connect(self._on_next)
self.buttons.append(self.next_button)
-
+
self.abort_button = QPushButton(_("Cancel"))
self.abort_button.clicked.connect(self._on_cancel)
self.buttons.append(self.abort_button)
@@ -1589,98 +1664,124 @@ class BalWizardWidget(QWidget):
def _on_next(self):
if self.validate():
self.on_next()
-
+
def _on_previous(self):
self.on_previous()
-
+
def get_content(self):
pass
-
+
def validate(self):
return True
-class BalWizardHeirsWidget(BalWizardWidget):
- title="Bitcoin After Life Heirs"
- message="Please add your heirs\n remember that 100% of wallet balance will be spent"
+class BalWizardHeirsWidget(BalWizardWidget):
+ title = "Bitcoin After Life Heirs"
+ message = (
+ "Please add your heirs\n remember that 100% of wallet balance will be spent"
+ )
def get_content(self):
- self.heirs_list=HeirList(self.bal_window,self.parent)
- button_add=QPushButton(_("Add"))
+ self.heirs_list = HeirList(self.bal_window, self.parent)
+ button_add = QPushButton(_("Add"))
button_add.clicked.connect(self.add_heir)
- button_import=QPushButton(_("Import"))
+ button_import = QPushButton(_("Import"))
button_import.clicked.connect(self.import_from_file)
- button_export=QPushButton(_("Export"))
+ button_export = QPushButton(_("Export"))
button_import.clicked.connect(self.export_to_file)
- widget=QWidget()
- vbox=QVBoxLayout(widget)
+ widget = QWidget()
+ vbox = QVBoxLayout(widget)
vbox.addWidget(self.heirs_list)
- vbox.addLayout(Buttons(button_add,button_import,button_export))
+ vbox.addLayout(Buttons(button_add, button_import, button_export))
return widget
-
def import_from_file(self):
self.bal_window.import_heirs()
self.heirs_list.update()
+
def export_to_file(self):
self.bal_window.export_heirs()
+
def add_heir(self):
self.bal_window.new_heir_dialog()
self.heirs_list.update()
+
def validate(self):
return True
+
class BalWizardWEDownloadWidget(BalWizardWidget):
- title=_("Bitcoin After Life Will-Executors")
- message=_("Choose willexecutors download method")
+ title = _("Bitcoin After Life Will-Executors")
+ message = _("Choose willexecutors download method")
def get_content(self):
- question=QLabel()
- self.combo=QComboBox()
- self.combo.addItems([
- "Automatically download and select willexecutors",
- "Only download willexecutors list",
- "Import willexecutor list from file",
- "Manual"])
- #heir_name.setFixedWidth(32 * char_width_in_lineedit())
+ # question = QLabel()
+ self.combo = QComboBox()
+ self.combo.addItems(
+ [
+ "Automatically download and select willexecutors",
+ "Only download willexecutors list",
+ "Import willexecutor list from file",
+ "Manual",
+ ]
+ )
+ # heir_name.setFixedWidth(32 * char_width_in_lineedit())
return self.combo
def validate(self):
return True
+
def _on_next(self):
index = self.combo.currentIndex()
_logger.debug(f"selected index:{index}")
if index < 3:
- self.bal_window.willexecutors=Willexecutors.get_willexecutors(self.bal_window.bal_plugin)
-
+ self.bal_window.willexecutors = Willexecutors.get_willexecutors(
+ self.bal_window.bal_plugin
+ )
+
if index == 2:
+
def doNothing():
self.bal_window.willexecutors.update(self.willexecutors)
- Willexecutors.save(self.bal_window.bal_plugin,self.bal_window.willexecutors)
+ Willexecutors.save(
+ self.bal_window.bal_plugin, self.bal_window.willexecutors
+ )
pass
- import_meta_gui(self.bal_window.window, _('willexecutors.json'), self.import_json_file, doNothing)
+
+ import_meta_gui(
+ self.bal_window.window,
+ _("willexecutors.json"),
+ self.import_json_file,
+ doNothing,
+ )
if index < 2:
+
def on_success(willexecutors):
self.bal_window.willexecutors.update(willexecutors)
self.bal_window.ping_willexecutors(self.bal_window.willexecutors)
if index < 1:
for we in self.bal_window.willexecutors:
- if self.bal_window.willexecutors[we]['status']==200:
- self.bal_window.willexecutors[we]['selected']=True
- Willexecutors.save(self.bal_window.bal_plugin,self.bal_window.willexecutors)
+ if self.bal_window.willexecutors[we]["status"] == 200:
+ self.bal_window.willexecutors[we]["selected"] = True
+ Willexecutors.save(
+ self.bal_window.bal_plugin, self.bal_window.willexecutors
+ )
+
def on_failure(fail):
_logger.debug(f"Failed to download willexecutors list {fail}")
pass
- task = partial(Willexecutors.download_list,self.bal_window.bal_plugin)
+ task = partial(Willexecutors.download_list, self.bal_window.bal_plugin)
msg = _("Downloading Will-Executors list")
- self.waiting_dialog = BalWaitingDialog(self.bal_window, msg, task, on_success, on_failure,exe=False)
+ self.waiting_dialog = BalWaitingDialog(
+ self.bal_window, msg, task, on_success, on_failure, exe=False
+ )
self.waiting_dialog.exe()
-
+
elif index == 3:
- #TODO DO NOTHING
+ # TODO DO NOTHING
pass
if self.validate():
@@ -1689,97 +1790,155 @@ class BalWizardWEDownloadWidget(BalWizardWidget):
def import_json_file(self, path):
data = read_json_file(path)
data = self._validate(data)
- self.willexecutors=data
+ self.willexecutors = data
- def _validate(self,data):
+ def _validate(self, data):
return data
+
class BalWizardWEWidget(BalWizardWidget):
- title=("Bitcoin After Life Will-Executors")
- message=_("Configure and select your willexecutors")
+ title = "Bitcoin After Life Will-Executors"
+ message = _("Configure and select your willexecutors")
def get_content(self):
- widget=QWidget()
- vbox=QVBoxLayout(widget)
- vbox.addWidget(WillExecutorWidget(self,self.bal_window,Willexecutors.get_willexecutors(self.bal_window.bal_plugin)))
+ widget = QWidget()
+ vbox = QVBoxLayout(widget)
+ vbox.addWidget(
+ WillExecutorWidget(
+ self,
+ self.bal_window,
+ Willexecutors.get_willexecutors(self.bal_window.bal_plugin),
+ )
+ )
return widget
+
class BalWizardLocktimeAndFeeWidget(BalWizardWidget):
- title=("Bitcoin After Life Will Settings")
- message=_("")
+ title = "Bitcoin After Life Will Settings"
+ message = _("")
def get_content(self):
- widget=QWidget()
- self.heir_locktime = HeirsLockTimeEdit(widget,0)
- will_settings=self.bal_window.bal_plugin.WILL_SETTINGS.get()
- self.heir_locktime.set_locktime(will_settings['locktime'])
+ widget = QWidget()
+ self.heir_locktime = HeirsLockTimeEdit(widget, 0)
+ will_settings = self.bal_window.bal_plugin.WILL_SETTINGS.get()
+ self.heir_locktime.set_locktime(will_settings["locktime"])
+
def on_heir_locktime():
if not self.heir_locktime.get_locktime():
- self.heir_locktime.set_locktime('1y')
- self.bal_window.will_settings['locktime'] = self.heir_locktime.get_locktime() if self.heir_locktime.get_locktime() else "1y"
+ self.heir_locktime.set_locktime("1y")
+ self.bal_window.will_settings["locktime"] = (
+ self.heir_locktime.get_locktime()
+ if self.heir_locktime.get_locktime()
+ else "1y"
+ )
self.bal_window.bal_plugin.WILL_SETTINGS.set(self.bal_window.will_settings)
+
self.heir_locktime.valueEdited.connect(on_heir_locktime)
- self.heir_threshold = HeirsLockTimeEdit(widget,0)
- self.heir_threshold.set_locktime(will_settings['threshold'])
+ self.heir_threshold = HeirsLockTimeEdit(widget, 0)
+ self.heir_threshold.set_locktime(will_settings["threshold"])
+
def on_heir_threshold():
if not self.heir_threshold.get_locktime():
- self.heir_threshold.set_locktime('180d')
+ self.heir_threshold.set_locktime("180d")
- self.bal_window.will_settings['threshold'] = self.heir_threshold.get_locktime()
+ self.bal_window.will_settings["threshold"] = (
+ self.heir_threshold.get_locktime()
+ )
self.bal_window.bal_plugin.WILL_SETTINGS.set(self.bal_window.will_settings)
+
self.heir_threshold.valueEdited.connect(on_heir_threshold)
self.heir_tx_fees = QSpinBox(widget)
self.heir_tx_fees.setMinimum(1)
self.heir_tx_fees.setMaximum(10000)
- self.heir_tx_fees.setValue(will_settings['baltx_fees'])
+ self.heir_tx_fees.setValue(will_settings["baltx_fees"])
+
def on_heir_tx_fees():
if not self.heir_tx_fees.value():
self.heir_tx_fees.set_value(1)
- self.bal_window.will_settings['baltx_fees'] = self.heir_tx_fees.value()
+ self.bal_window.will_settings["baltx_fees"] = self.heir_tx_fees.value()
self.bal_window.bal_plugin.WILL_SETTINGS.set(self.bal_window.will_settings)
+
self.heir_tx_fees.valueChanged.connect(on_heir_tx_fees)
-
- def make_hlayout(label,twidget,help_text):
- tw=QWidget()
- hlayout=QHBoxLayout(tw)
+
+ def make_hlayout(label, twidget, help_text):
+ tw = QWidget()
+ hlayout = QHBoxLayout(tw)
hlayout.addWidget(QLabel(label))
hlayout.addWidget(twidget)
hlayout.addWidget(HelpButton(help_text))
hlayout.addStretch(1)
spacer_widget = QWidget()
- spacer_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
+ spacer_widget.setSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
+ )
hlayout.addWidget(spacer_widget)
return tw
-
layout = QVBoxLayout(widget)
-
- layout.addWidget(make_hlayout(_("Delivery Time:"),self.heir_locktime,_("Locktime* to be used in the transaction\n"
- +"if you choose Raw, you can insert various options based on suffix:\n"
- +" - d: number of days after current day(ex: 1d means tomorrow)\n"
- +" - y: number of years after currrent day(ex: 1y means one year from today)\n"
- +"* locktime can be anticipated to update will\n")))
- layout.addWidget(make_hlayout(_("Check Alive:"),self.heir_threshold,_("Check to ask for invalidation.\n"
- +"When less then this time is missing, ask to invalidate.\n"
- +"If you fail to invalidate during this time, your transactions will be delivered to your heirs.\n"
- +"if you choose Raw, you can insert various options based on suffix:\n"
- +" - d: number of days after current day(ex: 1d means tomorrow).\n"
- +" - y: number of years after currrent day(ex: 1y means one year from today).\n\n")))
- layout.addWidget(make_hlayout(_("Fees(sats/vbyte):"),self.heir_tx_fees,("Fee to be used in the transaction")))
+
+ layout.addWidget(
+ make_hlayout(
+ _("Delivery Time:"),
+ self.heir_locktime,
+ _(
+ "Locktime* to be used in the transaction\n"
+ + "if you choose Raw, you can insert various options based on suffix:\n"
+ + " - d: number of days after current day(ex: 1d means tomorrow)\n"
+ + " - y: number of years after currrent day(ex: 1y means one year from today)\n"
+ + "* locktime can be anticipated to update will\n"
+ ),
+ )
+ )
+ layout.addWidget(
+ make_hlayout(
+ _("Check Alive:"),
+ self.heir_threshold,
+ _(
+ "Check to ask for invalidation.\n"
+ + "When less then this time is missing, ask to invalidate.\n"
+ + "If you fail to invalidate during this time, your transactions will be delivered to your heirs.\n"
+ + "if you choose Raw, you can insert various options based on suffix:\n"
+ + " - d: number of days after current day(ex: 1d means tomorrow).\n"
+ + " - y: number of years after currrent day(ex: 1y means one year from today).\n\n"
+ ),
+ )
+ )
+ layout.addWidget(
+ make_hlayout(
+ _("Fees(sats/vbyte):"),
+ self.heir_tx_fees,
+ ("Fee to be used in the transaction"),
+ )
+ )
spacer_widget = QWidget()
- spacer_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
+ spacer_widget.setSizePolicy(
+ QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
+ )
layout.addWidget(spacer_widget)
return widget
+
class BalWaitingDialog(BalDialog):
- updatemessage=pyqtSignal([str], arguments=['message'])
- def __init__(self, bal_window: 'BalWindow', message: str, task, on_success=None, on_error=None, on_cancel=None,exe=True):
+ updatemessage = pyqtSignal([str], arguments=["message"])
+
+ def __init__(
+ self,
+ bal_window: "BalWindow",
+ message: str,
+ task,
+ on_success=None,
+ on_error=None,
+ on_cancel=None,
+ exe=True,
+ ):
assert bal_window
- BalDialog.__init__(self, bal_window.window,bal_window.bal_plugin, _("Please wait"))
+ BalDialog.__init__(
+ self, bal_window.window, bal_window.bal_plugin, _("Please wait")
+ )
self.message_label = QLabel(message)
vbox = QVBoxLayout(self)
vbox.addWidget(self.message_label)
@@ -1789,7 +1948,7 @@ class BalWaitingDialog(BalDialog):
self.cancel_button.clicked.connect(on_cancel)
vbox.addLayout(Buttons(self.cancel_button))
self.accepted.connect(self.on_accepted)
- self.task=task
+ self.task = task
self.on_success = on_success
self.on_error = on_error
self.on_cancel = on_cancel
@@ -1805,28 +1964,32 @@ class BalWaitingDialog(BalDialog):
def hello(self):
pass
+
def finished(self):
_logger.info("finished")
+
def wait(self):
self.thread.wait()
def on_accepted(self):
self.thread.stop()
- def update_message(self,msg):
+
+ def update_message(self, msg):
self.message_label.setText(msg)
def update(self, msg):
self.updatemessage.emit(msg)
def getText(self):
- return self.message_label.text()
+ return self.message_label.text()
- def closeEvent(self,event):
+ def closeEvent(self, event):
self.thread.stop()
+
class BalBlockingWaitingDialog(BalDialog):
- def __init__(self, bal_window: 'BalWindow', message: str, task: Callable[[], Any]):
- BalDialog.__init__(self, bal_window, bal_window.bal_plugin,_("Please wait"))
+ def __init__(self, bal_window: "BalWindow", message: str, task: Callable[[], Any]):
+ BalDialog.__init__(self, bal_window, bal_window.bal_plugin, _("Please wait"))
self.message_label = QLabel(message)
vbox = QVBoxLayout(self)
vbox.addWidget(self.message_label)
@@ -1834,8 +1997,8 @@ class BalBlockingWaitingDialog(BalDialog):
# show popup
self.show()
# refresh GUI; needed for popup to appear and for message_label to get drawn
- QCoreApplication.processEvents()
- QCoreApplication.processEvents()
+ # QCoreApplication.processEvents()
+ # QCoreApplication.processEvents()
try:
# block and run given task
task()
@@ -1843,32 +2006,37 @@ class BalBlockingWaitingDialog(BalDialog):
# close popup
self.accept()
+
class bal_checkbox(QCheckBox):
- def __init__(self, variable,on_click=None):
+ def __init__(self, variable, on_click=None):
QCheckBox.__init__(self)
self.setChecked(variable.get())
- self.on_click=on_click
+ self.on_click = on_click
+
def on_check(v):
variable.set(v == 2)
variable.get()
if self.on_click:
self.on_click()
+
self.stateChanged.connect(on_check)
+
class BalBuildWillDialog(BalDialog):
- updatemessage=pyqtSignal()
- def __init__(self,bal_window,parent=None):
+ updatemessage = pyqtSignal()
+
+ def __init__(self, bal_window, parent=None):
if not parent:
parent = bal_window.window
- BalDialog.__init__(self,parent,bal_window.bal_plugin, "Building Will")
+ BalDialog.__init__(self, parent, bal_window.bal_plugin, "Building Will")
self.updatemessage.connect(self.update)
- self.bal_window=bal_window
+ self.bal_window = bal_window
self.message_label = QLabel("Building Will:")
self.vbox = QVBoxLayout(self)
self.vbox.addWidget(self.message_label)
- self.qwidget=QWidget()
+ self.qwidget = QWidget()
self.vbox.addWidget(self.qwidget)
- self.labels=[]
+ self.labels = []
self.check_row = None
self.inval_row = None
self.build_row = None
@@ -1878,12 +2046,18 @@ class BalBuildWillDialog(BalDialog):
self._stopping = False
self.thread = TaskThread(self)
self.thread.finished.connect(self.task_finished) # see #3956
+
def task_finished(self):
pass
-
+
def build_will_task(self):
_logger.debug("build will task to be started")
- self.thread.add(self.task_phase1,on_success=self.on_success_phase1,on_done=self.on_accept,on_error=self.on_error_phase1)
+ self.thread.add(
+ self.task_phase1,
+ on_success=self.on_success_phase1,
+ on_done=self.on_accept,
+ on_error=self.on_error_phase1,
+ )
self.show()
self.exec()
@@ -1892,38 +2066,63 @@ class BalBuildWillDialog(BalDialog):
try:
self.bal_window.init_class_variables()
except NoHeirsException:
+ _logger.error("no heirs exception")
return False, None
- self.msg_set_status("checking variables","Waiting")
+ varrow = self.msg_set_status("checking variables")
try:
- Will.check_amounts(self.bal_window.heirs,self.bal_window.willexecutors,self.bal_window.window.wallet.get_utxos(),self.bal_window.date_to_check,self.bal_window.window.wallet.dust_threshold())
+ _logger.debug("checking variables")
+ Will.check_amounts(
+ self.bal_window.heirs,
+ self.bal_window.willexecutors,
+ self.bal_window.window.wallet.get_utxos(),
+ self.bal_window.date_to_check,
+ self.bal_window.window.wallet.dust_threshold(),
+ )
+ _logger.debug("variables ok")
except AmountException:
- self.msg_edit_row(''+_("In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts"+""))
+ self.msg_set_status(
+ "checking variables",
+ varrow,
+ ''
+ + _(
+ "In the inheritance process, "
+ + "the entire wallet will always be fully emptied. \n"
+ + "Your settings require an adjustment of the amounts"
+ )
+ + "",
+ )
self.msg_set_checking()
- have_to_build=False
+ have_to_build = False
try:
self.bal_window.check_will()
- self.msg_set_checking('Ok')
- except WillExpiredException as e:
+ self.msg_set_checking("Ok")
+ except WillExpiredException:
+ _logger.debug("expired")
self.msg_set_checking("Expired")
- fee_per_byte=self.bal_window.will_settings.get('baltx_fees',1)
- return None, Will.invalidate_will(self.bal_window.willitems,self.bal_window.wallet,fee_per_byte)
+ fee_per_byte = self.bal_window.will_settings.get("baltx_fees", 1)
+ return None, Will.invalidate_will(
+ self.bal_window.willitems, self.bal_window.wallet, fee_per_byte
+ )
except NoHeirsException:
+ _logger.debug("no heirs")
self.msg_set_checking("No Heirs")
except NotCompleteWillException as e:
+ _logger.debug("not complete", e)
message = False
- have_to_build=True
- if isinstance(e,HeirChangeException):
- message ="Heirs changed:"
- elif isinstance(e,WillExecutorNotPresent):
+ have_to_build = True
+ if isinstance(e, HeirChangeException):
+ message = "Heirs changed:"
+ elif isinstance(e, WillExecutorNotPresent):
message = "Will-Executor not present"
- elif isinstance(e,WillexecutorChangeException):
+ elif isinstance(e, WillexecutorChangeException):
message = "Will-Executor changed"
- elif isinstance(e,TxFeesChangedException):
+ elif isinstance(e, TxFeesChangedException):
message = "Txfees are changed"
- elif isinstance(e,HeirNotFoundException):
+ elif isinstance(e, HeirNotFoundException):
message = "Heir not found"
if message:
+ _logger.debug("message")
self.msg_set_checking(message)
else:
self.msg_set_checking("New")
@@ -1934,18 +2133,18 @@ class BalBuildWillDialog(BalDialog):
self.bal_window.build_will()
self.bal_window.check_will()
for wid in Will.only_valid(self.bal_window.willitems):
- self.bal_window.wallet.set_label(wid,"BAL Transaction")
+ self.bal_window.wallet.set_label(wid, "BAL Transaction")
self.msg_set_building("Ok")
except Exception as e:
self.msg_set_building(self.msg_error(e))
- return False,None
+ return False, None
have_to_sign = False
for wid in Will.only_valid(self.bal_window.willitems):
if not self.bal_window.willitems[wid].get_status("COMPLETE"):
have_to_sign = True
break
return have_to_sign, None
-
+
def on_accept(self):
pass
@@ -1955,25 +2154,26 @@ class BalBuildWillDialog(BalDialog):
def on_error_push(self):
pass
- def wait(self,secs):
- wait_row=None
- for i in range(secs,0,-1):
+ def wait(self, secs):
+ wait_row = None
+ for i in range(secs, 0, -1):
if self._stopping:
return
- wait_row = self.msg_edit_row(f"Please wait {i}secs", wait_row)
+ wait_row = self.msg_edit_row(f"Please wait {i}secs", wait_row)
time.sleep(1)
self.msg_del_row(wait_row)
- def loop_broadcast_invalidating(self,tx):
+ def loop_broadcast_invalidating(self, tx):
self.msg_set_invalidating("Broadcasting")
try:
tx.add_info_from_wallet(self.bal_window.wallet)
self.network.run_from_another_thread(tx.add_info_from_network(self.network))
- txid = self.network.run_from_another_thread(self.network.broadcast_transaction(tx,timeout=120),timeout=120)
+ txid = self.network.run_from_another_thread(
+ self.network.broadcast_transaction(tx, timeout=120), timeout=120
+ )
self.msg_set_invalidating("Ok")
if not txid:
_logger.debug(f"should not be none txid: {txid}")
-
except TxBroadcastError as e:
_logger.error(e)
@@ -1986,25 +2186,45 @@ class BalBuildWillDialog(BalDialog):
self.msg_set_pushing("Broadcasting")
retry = False
try:
- willexecutors=Willexecutors.get_willexecutor_transactions(self.bal_window.willitems)
- for url,willexecutor in willexecutors.items():
+ willexecutors = Willexecutors.get_willexecutor_transactions(
+ self.bal_window.willitems
+ )
+ for url, willexecutor in willexecutors.items():
try:
- if Willexecutors.is_selected(self.bal_window.willexecutors.get(url)):
+ if Willexecutors.is_selected(
+ self.bal_window.willexecutors.get(url)
+ ):
_logger.debug(f"{url}: {willexecutor}")
- if not Willexecutors.push_transactions_to_willexecutor(willexecutor):
- for wid in willexecutor['txsids']:
- self.bal_window.willitems[wid].set_status('PUSH_FAIL',True)
- retry=True
+ if not Willexecutors.push_transactions_to_willexecutor(
+ willexecutor
+ ):
+ for wid in willexecutor["txsids"]:
+ self.bal_window.willitems[wid].set_status(
+ "PUSH_FAIL", True
+ )
+ retry = True
else:
- for wid in willexecutor['txsids']:
- self.bal_window.willitems[wid].set_status('PUSHED',True)
+ for wid in willexecutor["txsids"]:
+ self.bal_window.willitems[wid].set_status(
+ "PUSHED", True
+ )
except Willexecutors.AlreadyPresentException:
- for wid in willexecutor['txsids']:
- row = self.msg_edit_row("checking {} - {} : {}".format(self.bal_window.willitems[wid].we['url'],wid, "Waiting"))
+ for wid in willexecutor["txsids"]:
+ row = self.msg_edit_row(
+ "checking {} - {} : {}".format(
+ self.bal_window.willitems[wid].we["url"], wid, "Waiting"
+ )
+ )
self.bal_window.willitems[wid].check_willexecutor()
- row = self.msg_edit_row("checked {} - {} : {}".format(self.bal_window.willitems[wid].we['url'],wid,self.bal_window.willitems[wid].get_status("CHECKED" )),row)
-
-
+ row = self.msg_edit_row(
+ "checked {} - {} : {}".format(
+ self.bal_window.willitems[wid].we["url"],
+ wid,
+ self.bal_window.willitems[wid].get_status("CHECKED"),
+ ),
+ row,
+ )
+
except Exception as e:
_logger.error(e)
@@ -2018,10 +2238,9 @@ class BalBuildWillDialog(BalDialog):
if not self._stopping:
self.loop_push()
-
- def invalidate_task(self,tx,password):
+ def invalidate_task(self, tx, password):
_logger.debug(f"invalidate tx: {tx}")
- tx = self.bal_window.wallet.sign_transaction(tx,password)
+ tx = self.bal_window.wallet.sign_transaction(tx, password)
try:
if tx:
if tx.is_complete():
@@ -2031,57 +2250,79 @@ class BalBuildWillDialog(BalDialog):
raise
else:
raise
- except Exception as e:
+ except Exception:
self.msg_set_invalidating("Error")
raise Exception("Impossible to sign")
- def on_success_invalidate(self,success):
- self.thread.add(self.task_phase1,on_success=self.on_success_phase1,on_done=self.on_accept,on_error=self.on_error_phase1)
- def on_error(self,error):
+
+ def on_success_invalidate(self, success):
+ self.thread.add(
+ self.task_phase1,
+ on_success=self.on_success_phase1,
+ on_done=self.on_accept,
+ on_error=self.on_error_phase1,
+ )
+
+ def on_error(self, error):
_logger.error(error)
pass
- def on_success_phase1(self,result):
- self.have_to_sign,tx = list(result)
+
+ def on_success_phase1(self, result):
+ self.have_to_sign, tx = list(result)
_logger.debug("have to sign {}".format(self.have_to_sign))
- password=None
+ password = None
if self.have_to_sign is None:
self.msg_set_invalidating()
- #need to sign invalidate and restart phase 1
+ # need to sign invalidate and restart phase 1
- password = self.bal_window.get_wallet_password("Invalidate your old will",parent=self)
+ password = self.bal_window.get_wallet_password(
+ "Invalidate your old will", parent=self
+ )
if password is False:
self.msg_set_invalidating("Aborted")
self.wait(3)
self.close()
return
- self.thread.add(partial(self.invalidate_task,tx,password),on_success=self.on_success_invalidate, on_done=self.on_accept, on_error=self.on_error)
-
+ self.thread.add(
+ partial(self.invalidate_task, tx, password),
+ on_success=self.on_success_invalidate,
+ on_done=self.on_accept,
+ on_error=self.on_error,
+ )
+
return
-
+
elif self.have_to_sign:
- password = self.bal_window.get_wallet_password("Sign your will",parent=self)
+ password = self.bal_window.get_wallet_password(
+ "Sign your will", parent=self
+ )
if password is False:
- self.msg_set_signing('Aborted')
+ self.msg_set_signing("Aborted")
else:
- self.msg_set_signing('Nothing to do')
- self.thread.add(partial(self.task_phase2,password),on_success=self.on_success_phase2,on_done=self.on_accept_phase2,on_error=self.on_error_phase2)
+ self.msg_set_signing("Nothing to do")
+ self.thread.add(
+ partial(self.task_phase2, password),
+ on_success=self.on_success_phase2,
+ on_done=self.on_accept_phase2,
+ on_error=self.on_error_phase2,
+ )
return
-
- def on_success_phase2(self,arg=False):
+
+ def on_success_phase2(self, arg=False):
self.thread.stop()
self.bal_window.save_willitems()
self.msg_edit_row("Finished")
self.close()
- def closeEvent(self,event):
+ def closeEvent(self, event):
self.bal_window.update_all()
- self._stopping=True
+ self._stopping = True
self.thread.stop()
- def task_phase2(self,password):
+ def task_phase2(self, password):
if self.have_to_sign:
try:
- if txs:=self.bal_window.sign_transactions(password):
- for txid,tx in txs.items():
+ if txs := self.bal_window.sign_transactions(password):
+ for txid, tx in txs.items():
self.bal_window.willitems[txid].tx = copy.deepcopy(tx)
self.bal_window.save_willitems()
self.msg_set_signing("Ok")
@@ -2091,7 +2332,7 @@ class BalBuildWillDialog(BalDialog):
self.msg_set_pushing()
have_to_push = False
for wid in Will.only_valid(self.bal_window.willitems):
- w=self.bal_window.willitems[wid]
+ w = self.bal_window.willitems[wid]
if w.we and w.get_status("COMPLETE") and not w.get_status("PUSHED"):
have_to_push = True
if not have_to_push:
@@ -2106,72 +2347,76 @@ class BalBuildWillDialog(BalDialog):
self.msg_edit_row("Ok")
self.wait(5)
- def on_error_phase1(self,error):
+ def on_error_phase1(self, error):
_logger.error(f"error phase1: {error}")
- def on_error_phase2(self,error):
+ def on_error_phase2(self, error):
_logger.error("error phase2: { error}")
-
- def msg_set_checking(self, status = None, row = None):
+ def msg_set_checking(self, status="Waiting", row=None):
row = self.check_row if row is None else row
- self.check_row = self.msg_set_status("Checking your will", row, status)
+ self.check_row = self.msg_set_status("Checking your will", row, status)
- def msg_set_invalidating(self, status = None, row = None):
+ def msg_set_invalidating(self, status=None, row=None):
row = self.inval_row if row is None else row
- self.inval_row = self.msg_set_status("Invalidating old will", self.inval_row, status)
+ self.inval_row = self.msg_set_status(
+ "Invalidating old will", self.inval_row, status
+ )
- def msg_set_building(self, status = None, row = None):
+ def msg_set_building(self, status=None, row=None):
row = self.build_row if row is None else row
- self.build_row = self.msg_set_status("Building your will", self.build_row, status)
+ self.build_row = self.msg_set_status(
+ "Building your will", self.build_row, status
+ )
- def msg_set_signing(self, status = None, row = None):
+ def msg_set_signing(self, status=None, row=None):
row = self.sign_row if row is None else row
- self.sign_row = self.msg_set_status("Signing your will", self.sign_row, status)
+ self.sign_row = self.msg_set_status("Signing your will", self.sign_row, status)
- def msg_set_pushing(self, status = None, row = None):
+ def msg_set_pushing(self, status=None, row=None):
row = self.push_row if row is None else row
- self.push_row = self.msg_set_status("Broadcasting your will to executors", self.push_row, status)
+ self.push_row = self.msg_set_status(
+ "Broadcasting your will to executors", self.push_row, status
+ )
- def msg_set_waiting(self, status = None, row = None):
+ def msg_set_waiting(self, status=None, row=None):
row = self.wait_row if row is None else row
- self.wait_row = self.msg_edit_row(f"Please wait {status}secs", self.wait_row)
+ self.wait_row = self.msg_edit_row(f"Please wait {status}secs", self.wait_row)
- def msg_error(self,e):
+ def msg_error(self, e):
return "Error: {}".format(e)
- def msg_set_status(self,msg,row,status=None):
- status= "Wait" if status is None else status
- line="{}:\t{}".format(_(msg), status)
- return self.msg_edit_row(line,row)
-
-
- def ask_password(self,msg=None):
- self.password=self.bal_window.get_wallet_password(msg,parent=self)
+ def msg_set_status(self, msg, row=None, status=None):
+ status = "Wait" if status is None else status
+ line = "{}:\t{}".format(_(msg), status)
+ return self.msg_edit_row(line, row)
- def msg_edit_row(self,line,row=None):
+ def ask_password(self, msg=None):
+ self.password = self.bal_window.get_wallet_password(msg, parent=self)
+
+ def msg_edit_row(self, line, row=None):
_logger.debug(f"{row},{line}")
-
+
try:
- self.labels[row]=line
- except Exception as e:
+ self.labels[row] = line
+ except Exception:
self.labels.append(line)
- row=len(self.labels)-1
-
+ row = len(self.labels) - 1
+
self.updatemessage.emit()
-
+
return row
- def msg_del_row(self,row):
+ def msg_del_row(self, row):
try:
del self.labels[row]
- except Exception as e:
+ except Exception:
pass
self.updatemessage.emit()
def update(self):
self.vbox.removeWidget(self.qwidget)
- self.qwidget=QWidget(self)
+ self.qwidget = QWidget(self)
labelsbox = QVBoxLayout(self.qwidget)
for label in self.labels:
labelsbox.addWidget(QLabel(label))
@@ -2179,18 +2424,20 @@ class BalBuildWillDialog(BalDialog):
def get_text(self):
return self.message_label.text()
+
pass
-class HeirList(MyTreeView,MessageBoxMixin):
+
+class HeirList(MyTreeView, MessageBoxMixin):
class Columns(MyTreeView.BaseColumnsEnum):
NAME = enum.auto()
ADDRESS = enum.auto()
AMOUNT = enum.auto()
headers = {
- Columns.NAME: _('Name'),
- Columns.ADDRESS: _('Address'),
- Columns.AMOUNT: _('Amount'),
+ Columns.NAME: _("Name"),
+ Columns.ADDRESS: _("Address"),
+ Columns.AMOUNT: _("Amount"),
}
filter_columns = [Columns.NAME, Columns.ADDRESS]
@@ -2199,34 +2446,38 @@ class HeirList(MyTreeView,MessageBoxMixin):
ROLE_HEIR_KEY = Qt.ItemDataRole.UserRole + 1001
key_role = ROLE_HEIR_KEY
- def __init__(self, bal_window: 'BalWindow',parent):
+ def __init__(self, bal_window: "BalWindow", parent):
super().__init__(
parent=parent,
main_window=bal_window.window,
stretch_column=self.Columns.NAME,
- editable_columns=[self.Columns.NAME,self.Columns.ADDRESS,self.Columns.AMOUNT],
+ editable_columns=[
+ self.Columns.NAME,
+ self.Columns.ADDRESS,
+ self.Columns.AMOUNT,
+ ],
)
self.decimal_point = bal_window.window.get_decimal_point()
self.bal_window = bal_window
-
+
try:
self.setModel(QStandardItemModel(self))
self.sortByColumn(self.Columns.NAME, Qt.SortOrder.AscendingOrder)
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
- except:
+ except Exception:
pass
self.setSortingEnabled(True)
self.std_model = self.model()
self.update()
-
- def on_activated(self,idx):
+
+ def on_activated(self, idx):
self.on_double_click(idx)
- def on_double_click(self,idx):
- edit_key = self.get_edit_key_from_coordinate(idx.row(),idx.column())
- heir= self.bal_window.heirs.get(edit_key)
+ def on_double_click(self, idx):
+ edit_key = self.get_edit_key_from_coordinate(idx.row(), idx.column())
+ self.bal_window.heirs.get(edit_key)
self.bal_window.new_heir_dialog(edit_key)
def on_edited(self, idx, edit_key, *, text):
@@ -2236,24 +2487,26 @@ class HeirList(MyTreeView,MessageBoxMixin):
col = idx.column()
try:
if col == 2:
- text = Util.encode_amount(text,self.decimal_point)
+ text = Util.encode_amount(text, self.decimal_point)
elif col == 0:
self.bal_window.delete_heirs([edit_key])
edit_key = text
- prior_name[col-1] = text
- prior_name.insert(0,edit_key)
+ prior_name[col - 1] = text
+ prior_name.insert(0, edit_key)
prior_name = tuple(prior_name)
- except Exception as e:
- prior_name = (edit_key,)+prior_name[:col-1]+(text,)+prior_name[col:]
-
+ except Exception:
+ prior_name = (
+ (edit_key,) + prior_name[: col - 1] + (text,) + prior_name[col:]
+ )
+
try:
self.bal_window.set_heir(prior_name)
- except Exception as e:
+ except Exception:
pass
try:
- self.bal_window.set_heir((edit_key,)+original)
- except Exception as e:
+ self.bal_window.set_heir((edit_key,) + original)
+ except Exception:
self.update()
def create_menu(self, position):
@@ -2266,18 +2519,29 @@ class HeirList(MyTreeView,MessageBoxMixin):
selected_keys.append(sel_key)
if selected_keys and idx.isValid():
column_title = self.model().horizontalHeaderItem(column).text()
- column_data = '\n'.join(self.model().itemFromIndex(s_idx).text()
- for s_idx in self.selected_in_column(column))
- menu.addAction(_("Copy {}").format(column_title), lambda: self.place_text_on_clipboard(column_data, title=column_title))
+ # ok
+ column_data = "\n".join(
+ self.model().itemFromIndex(s_idx).text()
+ for s_idx in self.selected_in_column(column)
+ )
+ menu.addAction(
+ _("Copy {}").format(column_title),
+ lambda: self.place_text_on_clipboard(column_data, title=column_title),
+ )
if column in self.editable_columns:
item = self.model().itemFromIndex(idx)
if item.isEditable():
persistent = QPersistentModelIndex(idx)
- menu.addAction(_("Edit {}").format(column_title), lambda p=persistent: self.edit(QModelIndex(p)))
- menu.addAction(_("Delete"), lambda: self.bal_window.delete_heirs(selected_keys))
+ menu.addAction(
+ _("Edit {}").format(column_title),
+ lambda p=persistent: self.edit(QModelIndex(p)),
+ )
+ menu.addAction(
+ _("Delete"), lambda: self.bal_window.delete_heirs(selected_keys)
+ )
menu.exec(self.viewport().mapToGlobal(position))
- #def get_selected_keys(self):
+ # def get_selected_keys(self):
# selected_keys = []
# for s_idx in self.selected_in_column(self.Columns.NAME):
# sel_key = self.model().itemFromIndex(s_idx).data(0)
@@ -2286,7 +2550,9 @@ class HeirList(MyTreeView,MessageBoxMixin):
def update(self):
if self.maybe_defer_update():
return
- current_key = self.get_role_data_for_current_item(col=self.Columns.NAME, role=self.ROLE_HEIR_KEY)
+ current_key = self.get_role_data_for_current_item(
+ col=self.Columns.NAME, role=self.ROLE_HEIR_KEY
+ )
self.model().clear()
self.update_headers(self.__class__.headers)
set_current = None
@@ -2295,17 +2561,20 @@ class HeirList(MyTreeView,MessageBoxMixin):
labels = [""] * len(self.Columns)
labels[self.Columns.NAME] = key
labels[self.Columns.ADDRESS] = heir[0]
- labels[self.Columns.AMOUNT] = Util.decode_amount(heir[1],self.decimal_point)
+ labels[self.Columns.AMOUNT] = Util.decode_amount(
+ heir[1], self.decimal_point
+ )
items = [QStandardItem(x) for x in labels]
items[self.Columns.NAME].setEditable(True)
items[self.Columns.ADDRESS].setEditable(True)
items[self.Columns.AMOUNT].setEditable(True)
- items[self.Columns.NAME].setData(key, self.ROLE_HEIR_KEY+1)
- items[self.Columns.ADDRESS].setData(key, self.ROLE_HEIR_KEY+2)
- items[self.Columns.AMOUNT].setData(key, self.ROLE_HEIR_KEY+3)
+ items[self.Columns.NAME].setData(key, self.ROLE_HEIR_KEY + 1)
+ items[self.Columns.ADDRESS].setData(key, self.ROLE_HEIR_KEY + 2)
+ items[self.Columns.AMOUNT].setData(key, self.ROLE_HEIR_KEY + 3)
- self.model().insertRow(self.model().rowCount(), items)
+ row_count = self.model().rowCount()
+ self.model().insertRow(row_count, items)
if key == current_key:
idx = self.model().index(row_count, self.Columns.NAME)
@@ -2313,7 +2582,7 @@ class HeirList(MyTreeView,MessageBoxMixin):
self.set_current_idx(set_current)
# FIXME refresh loses sort order; so set "default" here:
self.filter()
- run_hook('update_heirs_tab', self)
+ run_hook("update_heirs_tab", self)
self.update_will_settings()
def refresh_row(self, key, row):
@@ -2321,63 +2590,88 @@ class HeirList(MyTreeView,MessageBoxMixin):
pass
def get_edit_key_from_coordinate(self, row, col):
- return self.get_role_data_from_coordinate(row, col, role=self.ROLE_HEIR_KEY+col+1)
+ return self.get_role_data_from_coordinate(
+ row, col, role=self.ROLE_HEIR_KEY + col + 1
+ )
def create_toolbar(self, config):
- toolbar, menu = self.create_toolbar_with_menu('')
+ toolbar, menu = self.create_toolbar_with_menu("")
menu.addAction(_("&New Heir"), self.bal_window.new_heir_dialog)
menu.addAction(_("Import"), self.bal_window.import_heirs)
menu.addAction(_("Export"), lambda: self.bal_window.export_heirs())
- self.heir_locktime = HeirsLockTimeEdit(self,0)
+ self.heir_locktime = HeirsLockTimeEdit(self, 0)
+
def on_heir_locktime():
if not self.heir_locktime.get_locktime():
- self.heir_locktime.set_locktime('1y')
- self.bal_window.will_settings['locktime'] = self.heir_locktime.get_locktime() if self.heir_locktime.get_locktime() else "1y"
+ self.heir_locktime.set_locktime("1y")
+ self.bal_window.will_settings["locktime"] = (
+ self.heir_locktime.get_locktime()
+ if self.heir_locktime.get_locktime()
+ else "1y"
+ )
self.bal_window.bal_plugin.WILL_SETTINGS.set(self.bal_window.will_settings)
+
self.heir_locktime.valueEdited.connect(on_heir_locktime)
- self.heir_threshold = HeirsLockTimeEdit(self,0)
+ self.heir_threshold = HeirsLockTimeEdit(self, 0)
+
def on_heir_threshold():
if not self.heir_threshold.get_locktime():
- self.heir_threshold.set_locktime('180d')
+ self.heir_threshold.set_locktime("180d")
- self.bal_window.will_settings['threshold'] = self.heir_threshold.get_locktime()
+ self.bal_window.will_settings["threshold"] = (
+ self.heir_threshold.get_locktime()
+ )
self.bal_window.bal_plugin.WILL_SETTINGS.set(self.bal_window.will_settings)
+
self.heir_threshold.valueEdited.connect(on_heir_threshold)
self.heir_tx_fees = QSpinBox()
self.heir_tx_fees.setMinimum(1)
self.heir_tx_fees.setMaximum(10000)
+
def on_heir_tx_fees():
if not self.heir_tx_fees.value():
self.heir_tx_fees.set_value(1)
- self.bal_window.will_settings['baltx_fees'] = self.heir_tx_fees.value()
+ self.bal_window.will_settings["baltx_fees"] = self.heir_tx_fees.value()
self.bal_window.bal_plugin.WILL_SETTINGS.set(self.bal_window.will_settings)
- self.heir_tx_fees.valueChanged.connect(on_heir_tx_fees)
+ self.heir_tx_fees.valueChanged.connect(on_heir_tx_fees)
self.heirs_widget = QWidget()
layout = QHBoxLayout()
self.heirs_widget.setLayout(layout)
-
+
layout.addWidget(QLabel(_("Delivery Time:")))
layout.addWidget(self.heir_locktime)
- layout.addWidget(HelpButton(_("Locktime* to be used in the transaction\n"
- +"if you choose Raw, you can insert various options based on suffix:\n"
- +" - d: number of days after current day(ex: 1d means tomorrow)\n"
- +" - y: number of years after currrent day(ex: 1y means one year from today)\n"
- +"* locktime can be anticipated to update will\n")))
+ layout.addWidget(
+ HelpButton(
+ _(
+ "Locktime* to be used in the transaction\n"
+ + "if you choose Raw, you can insert various options based on suffix:\n"
+ + " - d: number of days after current day(ex: 1d means tomorrow)\n"
+ + " - y: number of years after currrent day(ex: 1y means one year from today)\n"
+ + "* locktime can be anticipated to update will\n"
+ )
+ )
+ )
layout.addWidget(QLabel(" "))
layout.addWidget(QLabel(_("Check Alive:")))
layout.addWidget(self.heir_threshold)
- layout.addWidget(HelpButton(_("Check to ask for invalidation.\n"
- +"When less then this time is missing, ask to invalidate.\n"
- +"If you fail to invalidate during this time, your transactions will be delivered to your heirs.\n"
- +"if you choose Raw, you can insert various options based on suffix:\n"
- +" - d: number of days after current day(ex: 1d means tomorrow).\n"
- +" - y: number of years after currrent day(ex: 1y means one year from today).\n\n")))
+ layout.addWidget(
+ HelpButton(
+ _(
+ "Check to ask for invalidation.\n"
+ + "When less then this time is missing, ask to invalidate.\n"
+ + "If you fail to invalidate during this time, your transactions will be delivered to your heirs.\n"
+ + "if you choose Raw, you can insert various options based on suffix:\n"
+ + " - d: number of days after current day(ex: 1d means tomorrow).\n"
+ + " - y: number of years after currrent day(ex: 1y means one year from today).\n\n"
+ )
+ )
+ )
layout.addWidget(QLabel(" "))
layout.addWidget(QLabel(_("Fees:")))
layout.addWidget(self.heir_tx_fees)
@@ -2391,17 +2685,19 @@ class HeirList(MyTreeView,MessageBoxMixin):
toolbar.insertWidget(2, self.heirs_widget)
return toolbar
+
def update_will_settings(self):
try:
- self.heir_locktime.set_locktime(self.bal_window.will_settings['locktime'])
- self.heir_tx_fees.setValue(int(self.bal_window.will_settings['baltx_fees']))
- self.heir_threshold.set_locktime(self.bal_window.will_settings['threshold'])
+ self.heir_locktime.set_locktime(self.bal_window.will_settings["locktime"])
+ self.heir_tx_fees.setValue(int(self.bal_window.will_settings["baltx_fees"]))
+ self.heir_threshold.set_locktime(self.bal_window.will_settings["threshold"])
except Exception as e:
- _logger.error(f"Exception update_will_settings {e}")
+ _logger.debug(f"Exception update_will_settings {e}")
def build_transactions(self):
- will = self.bal_window.prepare_will()
+ # will = self.bal_window.prepare_will()
+ self.bal_window.prepare_will()
class PreviewList(MyTreeView):
@@ -2412,44 +2708,44 @@ class PreviewList(MyTreeView):
STATUS = enum.auto()
headers = {
- Columns.LOCKTIME: _('Locktime'),
- Columns.TXID: _('Txid'),
- Columns.WILLEXECUTOR: _('Will-Executor'),
- Columns.STATUS: _('Status'),
+ Columns.LOCKTIME: _("Locktime"),
+ Columns.TXID: _("Txid"),
+ Columns.WILLEXECUTOR: _("Will-Executor"),
+ Columns.STATUS: _("Status"),
}
ROLE_HEIR_KEY = Qt.ItemDataRole.UserRole + 2000
key_role = ROLE_HEIR_KEY
- def __init__(self, bal_window: 'BalWindow',parent,will):
+ def __init__(self, bal_window: "BalWindow", parent, will):
super().__init__(
parent=parent,
stretch_column=self.Columns.TXID,
)
- self.parent=parent
- self.bal_window=bal_window
- self.decimal_point=bal_window.window.get_decimal_point
+ self.parent = parent
+ self.bal_window = bal_window
+ self.decimal_point = bal_window.window.get_decimal_point
self.setModel(QStandardItemModel(self))
self.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
-
- if not will is None:
+ if will is not None:
self.will = will
else:
self.will = bal_window.willitems
- self.wallet=bal_window.window.wallet
+ self.wallet = bal_window.window.wallet
self.setModel(QStandardItemModel(self))
self.setSortingEnabled(True)
self.std_model = self.model()
self.config = bal_window.bal_plugin.config
- self.bal_plugin=self.bal_window.bal_plugin
+ self.bal_plugin = self.bal_window.bal_plugin
self.update()
- def on_activated(self,idx):
+
+ def on_activated(self, idx):
self.on_double_click(idx)
- def on_double_click(self,idx):
+ def on_double_click(self, idx):
idx = self.model().index(idx.row(), self.Columns.TXID)
sel_key = self.model().itemFromIndex(idx).data(0)
self.show_transaction([sel_key])
@@ -2464,32 +2760,48 @@ class PreviewList(MyTreeView):
selected_keys.append(sel_key)
if selected_keys and idx.isValid():
column_title = self.model().horizontalHeaderItem(column).text()
- column_data = '\n'.join(self.model().itemFromIndex(s_idx).text()
- for s_idx in self.selected_in_column(column))
+ # column_data = "\n".join(
+ # self.model().itemFromIndex(s_idx).text()
+ # for s_idx in self.selected_in_column(column)
+ # )
- menu.addAction(_("details").format(column_title), lambda: self.show_transaction(selected_keys)).setEnabled(len(selected_keys)<2)
- menu.addAction(_("check ").format(column_title), lambda: self.check_transactions(selected_keys))
+ menu.addAction(
+ _("details").format(column_title),
+ lambda: self.show_transaction(selected_keys),
+ ).setEnabled(len(selected_keys) < 2)
+ menu.addAction(
+ _("check ").format(column_title),
+ lambda: self.check_transactions(selected_keys),
+ )
+ if self.bal_plugin.ENABLE_MULTIVERSE.get():
+ try:
+ self.importaction = self.menu.addAction(
+ _("Import"), self.import_will
+ )
+ except Exception:
+ pass
menu.addSeparator()
- menu.addAction(_("delete").format(column_title), lambda: self.delete(selected_keys))
+ menu.addAction(
+ _("delete").format(column_title), lambda: self.delete(selected_keys)
+ )
menu.exec(self.viewport().mapToGlobal(position))
-
- def delete(self,selected_keys):
+ def delete(self, selected_keys):
for key in selected_keys:
del self.will[key]
try:
del self.bal_window.willitems[key]
- except:
+ except Exception:
pass
try:
del self.bal_window.will[key]
- except:
+ except Exception:
pass
self.update()
- def check_transactions(self,selected_keys):
+ def check_transactions(self, selected_keys):
wout = {}
for k in selected_keys:
wout[k] = self.will[k]
@@ -2497,105 +2809,104 @@ class PreviewList(MyTreeView):
self.bal_window.check_transactions(wout)
self.update()
- def show_transaction(self,selected_keys):
+ def show_transaction(self, selected_keys):
for key in selected_keys:
self.bal_window.show_transaction(self.will[key].tx)
self.update()
- def select(self,selected_keys):
+ def select(self, selected_keys):
self.selected += selected_keys
self.update()
- def deselect(self,selected_keys):
+ def deselect(self, selected_keys):
for key in selected_keys:
self.selected.remove(key)
self.update()
- def update_will(self,will):
+ def update_will(self, will):
self.will.update(will)
self.update()
+ def replace(self, set_current, current_key, txid, bal_tx):
+ if self.bal_window.bal_plugin._hide_replaced and bal_tx.get_status("REPLACED"):
+ return False
+ if self.bal_window.bal_plugin._hide_invalidated and bal_tx.get_status(
+ "INVALIDATED"
+ ):
+ return False
+
+ if not isinstance(bal_tx, WillItem):
+ bal_tx = WillItem(bal_tx)
+
+ tx = bal_tx.tx
+
+ labels = [""] * len(self.Columns)
+ labels[self.Columns.LOCKTIME] = Util.locktime_to_str(tx.locktime)
+ labels[self.Columns.TXID] = txid
+ we = "None"
+ if bal_tx.we:
+ we = bal_tx.we["url"]
+ labels[self.Columns.WILLEXECUTOR] = we
+ status = bal_tx.status
+ if len(bal_tx.status) > 53:
+ status = "...{}".format(status[-50:])
+ labels[self.Columns.STATUS] = status
+
+ items = []
+ for e in labels:
+ if isinstance(e, list):
+ try:
+ items.append(QStandardItem(*e))
+ except Exception as e:
+ pass
+ else:
+ items.append(QStandardItem(str(e)))
+
+ items[-1].setBackground(QColor(bal_tx.get_color()))
+
+ row_count = self.model().rowCount()
+ self.model().insertRow(row_count, items)
+ if txid == current_key:
+ idx = self.model().index(row_count, self.Columns.TXID)
+ set_current = QPersistentModelIndex(idx)
+ self.set_current_idx(set_current)
+ return set_current
+
def update(self):
try:
self.menu.removeAction(self.importaction)
- except Exception as e:
+ except Exception:
pass
- finally:
- if self.bal_plugin.ENABLE_MULTIVERSE.get():
- try:
- self.importaction=self.menu.addAction(_("Import"), self.import_will)
- except Exception as ex:
- pass
if self.will is None:
return
- current_key = self.get_role_data_for_current_item(col=self.Columns.TXID, role=self.ROLE_HEIR_KEY)
+ current_key = self.get_role_data_for_current_item(
+ col=self.Columns.TXID, role=self.ROLE_HEIR_KEY
+ )
self.model().clear()
self.update_headers(self.__class__.headers)
-
-
-
set_current = None
- for txid,bal_tx in self.will.items():
- if self.bal_window.bal_plugin._hide_replaced and bal_tx.get_status('REPLACED'):
- continue
- if self.bal_window.bal_plugin._hide_invalidated and bal_tx.get_status('INVALIDATED'):
- continue
+ for txid, bal_tx in self.will.items():
+ tmp = self.replace(set_current, current_key, txid, bal_tx)
+ if tmp:
+ set_current = tmp
- if not isinstance(bal_tx,WillItem):
- bal_tx=WillItem(bal_tx)
-
- tx=bal_tx.tx
-
- labels = [""] * len(self.Columns)
- labels[self.Columns.LOCKTIME] = Util.locktime_to_str(tx.locktime)
- labels[self.Columns.TXID] = txid
- we = 'None'
- if bal_tx.we:
- we = bal_tx.we['url']
- labels[self.Columns.WILLEXECUTOR]=we
- status = bal_tx.status
- if len(bal_tx.status) > 53:
- status = "...{}".format(status[-50:])
- labels[self.Columns.STATUS] = status
-
-
-
- items=[]
- for e in labels:
- if type(e)== list:
- try:
- items.append(QStandardItem(*e))
- except Exception as e:
- pass
- else:
- items.append(QStandardItem(str(e)))
-
- items[-1].setBackground(QColor(bal_tx.get_color()))
-
-
- self.model().insertRow(self.model().rowCount(), items)
- if txid == current_key:
- idx = self.model().index(row_count, self.Columns.TXID)
- set_current = QPersistentModelIndex(idx)
- self.set_current_idx(set_current)
-
- def create_toolbar(self, config):
- toolbar, menu = self.create_toolbar_with_menu('')
- menu.addAction(_("Prepare"), self.build_transactions)
- menu.addAction(_("Display"), self.bal_window.preview_modal_dialog)
+ def create_toolbar(self, config):
+ toolbar, menu = self.create_toolbar_with_menu("")
+ menu.addAction(_("Prepare"), self.build_transactions)
+ menu.addAction(_("Display"), self.bal_window.preview_modal_dialog)
menu.addAction(_("Sign"), self.ask_password_and_sign_transactions)
menu.addAction(_("Export"), self.export_will)
if self.bal_plugin.ENABLE_MULTIVERSE.get():
- self.importaction=menu.addAction(_("Import"), self.import_will)
+ self.importaction = menu.addAction(_("Import"), self.import_will)
menu.addAction(_("Broadcast"), self.broadcast)
menu.addAction(_("Check"), self.check)
menu.addAction(_("Invalidate"), self.invalidate_will)
- wizard=QPushButton(_("Setup Wizard"))
+ wizard = QPushButton(_("Setup Wizard"))
wizard.clicked.connect(self.bal_window.init_wizard)
display = QPushButton(_("Display"))
display.clicked.connect(self.bal_window.preview_modal_dialog)
@@ -2604,20 +2915,18 @@ class PreviewList(MyTreeView):
hlayout = QHBoxLayout(widget)
hlayout.addWidget(wizard)
hlayout.addWidget(display)
- toolbar.insertWidget(2,widget)
+ toolbar.insertWidget(2, widget)
-
- self.menu=menu
- self.toolbar=toolbar
+ self.menu = menu
+ self.toolbar = toolbar
return toolbar
-
def hide_replaced(self):
self.bal_window.bal_plugin.hide_replaced()
self.update()
def hide_invalidated(self):
- f.bal_window.bal_plugin.hide_invalidated()
+ self.bal_window.bal_plugin.hide_invalidated()
self.update()
def build_transactions(self):
@@ -2625,7 +2934,7 @@ class PreviewList(MyTreeView):
if will:
self.update_will(will)
- def export_json_file(self,path):
+ def export_json_file(self, path):
write_json_file(path, self.will)
def export_will(self):
@@ -2636,17 +2945,17 @@ class PreviewList(MyTreeView):
self.bal_window.import_will()
def ask_password_and_sign_transactions(self):
- self.bal_window.ask_password_and_sign_transactions(callback=self.update)
-
+ self.bal_window.ask_password_and_sign_transactions(callback=self.update)
+
def broadcast(self):
self.bal_window.broadcast_transactions()
self.update()
def check(self):
will = {}
- for wid, w in self.bal_window.willitems:
+ for wid, w in self.bal_window.willitems.items():
if w.get_status("VALID"):
- will[wid]=w
+ will[wid] = w
self.bal_window.check_transactions(will)
self.update()
@@ -2654,10 +2963,13 @@ class PreviewList(MyTreeView):
self.bal_window.invalidate_will()
self.update()
-class PreviewDialog(BalDialog,MessageBoxMixin):
+
+class PreviewDialog(BalDialog, MessageBoxMixin):
def __init__(self, bal_window, will):
self.parent = bal_window.window
- BalDialog.__init__(self,bal_window = bal_window,bal_plugin=bal_window.bal_plugin)
+ BalDialog.__init__(
+ self, bal_window=bal_window, bal_plugin=bal_window.bal_plugin
+ )
self.bal_plugin = bal_window.bal_plugin
self.gui_object = self.bal_plugin.gui_object
self.config = self.bal_plugin.config
@@ -2665,49 +2977,48 @@ class PreviewDialog(BalDialog,MessageBoxMixin):
self.wallet = bal_window.window.wallet
self.format_amount = bal_window.window.format_amount
self.base_unit = bal_window.window.base_unit
- self.format_fiat_and_units = bal_window.window.format_fiat_and_units
- self.fx = bal_window.window.fx
+ self.format_fiat_and_units = bal_window.window.format_fiat_and_units
+ self.fx = bal_window.window.fx
self.format_fee_rate = bal_window.window.format_fee_rate
self.show_address = bal_window.window.show_address
if not will:
self.will = bal_window.willitems
else:
self.will = will
- self.setWindowTitle(_('Transactions Preview'))
+ self.setWindowTitle(_("Transactions Preview"))
self.setMinimumSize(1000, 200)
self.size_label = QLabel()
- self.transactions_list = PreviewList(self.bal_window,self.will)
+ self.transactions_list = PreviewList(self.bal_window, self.will)
vbox = QVBoxLayout(self)
vbox.addWidget(self.size_label)
vbox.addWidget(self.transactions_list)
buttonbox = QHBoxLayout()
- b = QPushButton(_('Sign'))
+ b = QPushButton(_("Sign"))
b.clicked.connect(self.transactions_list.ask_password_and_sign_transactions)
buttonbox.addWidget(b)
- b = QPushButton(_('Export Will'))
+ b = QPushButton(_("Export Will"))
b.clicked.connect(self.transactions_list.export_will)
buttonbox.addWidget(b)
- b = QPushButton(_('Broadcast'))
+ b = QPushButton(_("Broadcast"))
b.clicked.connect(self.transactions_list.broadcast)
buttonbox.addWidget(b)
- b = QPushButton(_('Invalidate will'))
+ b = QPushButton(_("Invalidate will"))
b.clicked.connect(self.transactions_list.invalidate_will)
buttonbox.addWidget(b)
vbox.addLayout(buttonbox)
self.update()
-
- def update_will(self,will):
+ def update_will(self, will):
self.will.update(will)
self.transactions_list.update_will(will)
self.update()
-
+
def update(self):
self.transactions_list.update()
@@ -2726,11 +3037,13 @@ class PreviewDialog(BalDialog,MessageBoxMixin):
def closeEvent(self, event):
event.accept()
-
-def read_bal_QIcon(icon_basename: str=DEFAULT_ICON) -> QIcon:
+
+
+def read_bal_QIcon(icon_basename: str = DEFAULT_ICON) -> QIcon:
return QIcon(icon_path(icon_basename))
-def read_bal_QPixmap(icon_basename: str=DEFAULT_ICON) -> QPixmap:
+
+def read_bal_QPixmap(icon_basename: str = DEFAULT_ICON) -> QPixmap:
return QPixmap(icon_path(icon_basename))
@@ -2738,10 +3051,12 @@ class WillDetailDialog(BalDialog):
def __init__(self, bal_window):
self.will = bal_window.willitems
- self.threshold = Util.parse_locktime_string(bal_window.will_settings['threshold'])
- self.bal_window = bal_window
+ self.threshold = Util.parse_locktime_string(
+ bal_window.will_settings["threshold"]
+ )
+ self.bal_window = bal_window
Will.add_willtree(self.will)
- super().__init__(bal_window.window,bal_window.bal_plugin)
+ super().__init__(bal_window.window, bal_window.bal_plugin)
self.config = bal_window.window.config
self.wallet = bal_window.wallet
self.format_amount = bal_window.window.format_amount
@@ -2751,35 +3066,39 @@ class WillDetailDialog(BalDialog):
self.format_fee_rate = bal_window.window.format_fee_rate
self.decimal_point = bal_window.window.get_decimal_point()
self.base_unit_name = decimal_point_to_base_unit_name(self.decimal_point)
- self.setWindowTitle(_('Will Details'))
- self.setMinimumSize(670,700)
- self.vlayout= QVBoxLayout()
- w=QWidget()
+ self.setWindowTitle(_("Will Details"))
+ self.setMinimumSize(670, 700)
+ self.vlayout = QVBoxLayout()
+ w = QWidget()
hlayout = QHBoxLayout(w)
- b = QPushButton(_('Sign'))
+ b = QPushButton(_("Sign"))
b.clicked.connect(self.ask_password_and_sign_transactions)
hlayout.addWidget(b)
-
- b = QPushButton(_('Broadcast'))
- b.clicked.connect(self.broadcast_transactions)
- hlayout.addWidget(b)
- b = QPushButton(_('Export'))
+ b = QPushButton(_("Broadcast"))
+ b.clicked.connect(self.broadcast_transactions)
+ hlayout.addWidget(b)
+
+ b = QPushButton(_("Export"))
b.clicked.connect(self.export_will)
hlayout.addWidget(b)
- b = QPushButton(_('Invalidate'))
+ b = QPushButton(_("Invalidate"))
b.clicked.connect(bal_window.invalidate_will)
hlayout.addWidget(b)
self.vlayout.addWidget(w)
self.paint_scroll_area()
- self.vlayout.addWidget(QLabel(_("Expiration date: ")+Util.locktime_to_str(self.threshold)))
+ self.vlayout.addWidget(
+ QLabel(_("Expiration date: ") + Util.locktime_to_str(self.threshold))
+ )
self.vlayout.addWidget(self.scrollbox)
- w=QWidget()
+ w = QWidget()
hlayout = QHBoxLayout(w)
- hlayout.addWidget(QLabel(_("Valid Txs:")+ str(len(Will.only_valid_list(self.will)))))
- hlayout.addWidget(QLabel(_("Total Txs:")+ str(len(self.will))))
+ hlayout.addWidget(
+ QLabel(_("Valid Txs:") + str(len(Will.only_valid_list(self.will))))
+ )
+ hlayout.addWidget(QLabel(_("Total Txs:") + str(len(self.will))))
self.vlayout.addWidget(w)
self.setLayout(self.vlayout)
@@ -2792,14 +3111,18 @@ class WillDetailDialog(BalDialog):
self.scrollbox.setWidget(viewport)
viewport.setLayout(self.willlayout)
+
def ask_password_and_sign_transactions(self):
self.bal_window.ask_password_and_sign_transactions(callback=self.update)
self.update()
+
def broadcast_transactions(self):
self.bal_window.broadcast_transactions()
self.update()
+
def export_will(self):
self.bal_window.export_will()
+
def toggle_replaced(self):
self.bal_window.bal_plugin.hide_replaced()
toggle = _("Hide")
@@ -2821,72 +3144,101 @@ class WillDetailDialog(BalDialog):
pos = self.vlayout.indexOf(self.scrollbox)
self.vlayout.removeWidget(self.scrollbox)
self.paint_scroll_area()
- self.vlayout.insertWidget(pos,self.scrollbox)
+ self.vlayout.insertWidget(pos, self.scrollbox)
super().update()
+
class WillWidget(QWidget):
- def __init__(self,father=None,parent = None):
+ def __init__(self, father=None, parent=None):
super().__init__()
vlayout = QVBoxLayout()
self.setLayout(vlayout)
self.will = parent.bal_window.willitems
self.parent = parent
for w in self.will:
- if self.will[w].get_status('REPLACED') and self.parent.bal_window.bal_plugin._hide_replaced:
+ if (
+ self.will[w].get_status("REPLACED")
+ and self.parent.bal_window.bal_plugin._hide_replaced
+ ):
continue
- if self.will[w].get_status('INVALIDATED') and self.parent.bal_window.bal_plugin._hide_invalidated:
+ if (
+ self.will[w].get_status("INVALIDATED")
+ and self.parent.bal_window.bal_plugin._hide_invalidated
+ ):
continue
f = self.will[w].father
if father == f:
qwidget = QWidget()
- childWidget = QWidget()
- hlayout=QHBoxLayout(qwidget)
+ # childWidget = QWidget()
+ hlayout = QHBoxLayout(qwidget)
qwidget.setLayout(hlayout)
vlayout.addWidget(qwidget)
- detailw=QWidget()
- detaillayout=QVBoxLayout()
+ detailw = QWidget()
+ detaillayout = QVBoxLayout()
detailw.setLayout(detaillayout)
willpushbutton = QPushButton(w)
- willpushbutton.clicked.connect(partial(self.parent.bal_window.show_transaction,txid=w))
+ willpushbutton.clicked.connect(
+ partial(self.parent.bal_window.show_transaction, txid=w)
+ )
detaillayout.addWidget(willpushbutton)
locktime = Util.locktime_to_str(self.will[w].tx.locktime)
creation = Util.locktime_to_str(self.will[w].time)
- def qlabel(title,value):
- label = ""+_(str(title)) + f":\t{str(value)}"
+
+ def qlabel(title, value):
+ label = "" + _(str(title)) + f":\t{str(value)}"
return QLabel(label)
- detaillayout.addWidget(qlabel("Locktime",locktime))
- detaillayout.addWidget(qlabel("Creation Time",creation))
+
+ detaillayout.addWidget(qlabel("Locktime", locktime))
+ detaillayout.addWidget(qlabel("Creation Time", creation))
try:
- total_fees = self.will[w].tx.input_value() - self.will[w].tx.output_value()
- except:
+ total_fees = (
+ self.will[w].tx.input_value() - self.will[w].tx.output_value()
+ )
+ except Exception:
total_fees = -1
- decoded_fees = total_fees
- fee_per_byte = round(total_fees/self.will[w].tx.estimated_size(),3)
- fees_str = str(decoded_fees) + " ("+ str(fee_per_byte) + " sats/vbyte)"
- detaillayout.addWidget(qlabel("Transaction fees:",fees_str))
- detaillayout.addWidget(qlabel("Status:",self.will[w].status))
+ decoded_fees = total_fees
+ fee_per_byte = round(total_fees / self.will[w].tx.estimated_size(), 3)
+ fees_str = str(decoded_fees) + " (" + str(fee_per_byte) + " sats/vbyte)"
+ detaillayout.addWidget(qlabel("Transaction fees:", fees_str))
+ detaillayout.addWidget(qlabel("Status:", self.will[w].status))
detaillayout.addWidget(QLabel(""))
detaillayout.addWidget(QLabel("Heirs:"))
for heir in self.will[w].heirs:
- if "w!ll3x3c\"" not in heir:
- decoded_amount = Util.decode_amount(self.will[w].heirs[heir][3],self.parent.decimal_point)
- detaillayout.addWidget(qlabel(heir,f"{decoded_amount} {self.parent.base_unit_name}"))
+ if 'w!ll3x3c"' not in heir:
+ decoded_amount = Util.decode_amount(
+ self.will[w].heirs[heir][3], self.parent.decimal_point
+ )
+ detaillayout.addWidget(
+ qlabel(
+ heir, f"{decoded_amount} {self.parent.base_unit_name}"
+ )
+ )
if self.will[w].we:
detaillayout.addWidget(QLabel(""))
detaillayout.addWidget(QLabel(_("Willexecutor: LOCKTIME_THRESHOLD:
dt = datetime.fromtimestamp(locktime).isoformat()
return dt
@@ -22,93 +25,107 @@ class Util:
def str_to_locktime(locktime):
try:
- if locktime[-1] in ('y','d','b'):
- return locktime
- else: return int(locktime)
+ if locktime[-1] in ("y", "d", "b"):
+ return locktime
+ else:
+ return int(locktime)
except Exception as e:
pass
dt_object = datetime.fromisoformat(locktime)
timestamp = dt_object.timestamp()
return int(timestamp)
- def parse_locktime_string(locktime,w=None):
- try:
- return int(locktime)
-
- except Exception as e:
+ def parse_locktime_string(locktime, w=None):
+ try:
+ return int(locktime)
+
+ except Exception as e:
pass
- try:
- now = datetime.now()
- if locktime[-1] == 'y':
- locktime = str(int(locktime[:-1])*365) + "d"
- if locktime[-1] == 'd':
- return int((now + timedelta(days = int(locktime[:-1]))).replace(hour=0,minute=0,second=0,microsecond=0).timestamp())
- if locktime[-1] == 'b':
- locktime = int(locktime[:-1])
- height = 0
- if w:
- height = Util.get_current_height(w.network)
- locktime+=int(height)
- return int(locktime)
- except Exception as e:
+ try:
+ now = datetime.now()
+ if locktime[-1] == "y":
+ locktime = str(int(locktime[:-1]) * 365) + "d"
+ if locktime[-1] == "d":
+ return int(
+ (now + timedelta(days=int(locktime[:-1])))
+ .replace(hour=0, minute=0, second=0, microsecond=0)
+ .timestamp()
+ )
+ if locktime[-1] == "b":
+ locktime = int(locktime[:-1])
+ height = 0
+ if w:
+ height = Util.get_current_height(w.network)
+ locktime += int(height)
+ return int(locktime)
+ except Exception as e:
pass
return 0
-
- def int_locktime(seconds=0,minutes=0,hours=0, days=0, blocks = 0):
- return int(seconds + minutes*60 + hours*60*60 + days*60*60*24 + blocks * 600)
+ def int_locktime(seconds=0, minutes=0, hours=0, days=0, blocks=0):
+ return int(
+ seconds
+ + minutes * 60
+ + hours * 60 * 60
+ + days * 60 * 60 * 24
+ + blocks * 600
+ )
def encode_amount(amount, decimal_point):
if Util.is_perc(amount):
return amount
else:
try:
- return int(float(amount)*pow(10,decimal_point))
+ return int(float(amount) * pow(10, decimal_point))
except:
return 0
- def decode_amount(amount,decimal_point):
+ def decode_amount(amount, decimal_point):
if Util.is_perc(amount):
return amount
else:
- num=8-decimal_point
- basestr="{{:0{}.{}f}}".format(num,num)
- return "{:08.8f}".format(float(amount)/pow(10,decimal_point))
+ num = 8 - decimal_point
+ basestr = "{{:0{}.{}f}}".format(num, num)
+ return "{:08.8f}".format(float(amount) / pow(10, decimal_point))
- def is_perc(value):
+ def is_perc(value):
try:
- return value[-1] == '%'
+ return value[-1] == "%"
except:
return False
- def cmp_array(heira,heirb):
+ def cmp_array(heira, heirb):
try:
if not len(heira) == len(heirb):
return False
- for h in range(0,len(heira)):
+ for h in range(0, len(heira)):
if not heira[h] == heirb[h]:
return False
return True
except:
return False
- def cmp_heir(heira,heirb):
- if heira[0] == heirb[0] and heira[1] == heirb[1]:
+ def cmp_heir(heira, heirb):
+ if heira[0] == heirb[0] and heira[1] == heirb[1]:
return True
return False
- def cmp_willexecutor(willexecutora,willexecutorb):
+ def cmp_willexecutor(willexecutora, willexecutorb):
if willexecutora == willexecutorb:
return True
try:
- if willexecutora['url']==willexecutorb['url'] and willexecutora['address'] == willexecutorb['address'] and willexecutora['base_fee']==willexecutorb['base_fee']:
+ if (
+ willexecutora["url"] == willexecutorb["url"]
+ and willexecutora["address"] == willexecutorb["address"]
+ and willexecutora["base_fee"] == willexecutorb["base_fee"]
+ ):
return True
except:
return False
return False
- def search_heir_by_values(heirs,heir,values):
- for h,v in heirs.items():
+ def search_heir_by_values(heirs, heir, values):
+ for h, v in heirs.items():
found = False
for val in values:
if val in v and v[val] != heir[val]:
@@ -118,76 +135,93 @@ class Util:
return h
return False
- def cmp_heir_by_values(heira,heirb,values):
+ def cmp_heir_by_values(heira, heirb, values):
for v in values:
if heira[v] != heirb[v]:
return False
return True
- def cmp_heirs_by_values(heirsa,heirsb,values,exclude_willexecutors=False,reverse = True):
+ def cmp_heirs_by_values(
+ heirsa, heirsb, values, exclude_willexecutors=False, reverse=True
+ ):
for heira in heirsa:
- if (exclude_willexecutors and not "w!ll3x3c\"" in heira) or not exclude_willexecutors:
+ if (
+ exclude_willexecutors and not 'w!ll3x3c"' in heira
+ ) or not exclude_willexecutors:
found = False
for heirb in heirsb:
- if Util.cmp_heir_by_values(heirsa[heira],heirsb[heirb],values):
- found=True
+ if Util.cmp_heir_by_values(heirsa[heira], heirsb[heirb], values):
+ found = True
if not found:
return False
if reverse:
- return Util.cmp_heirs_by_values(heirsb,heirsa,values,exclude_willexecutors=exclude_willexecutors,reverse=False)
+ return Util.cmp_heirs_by_values(
+ heirsb,
+ heirsa,
+ values,
+ exclude_willexecutors=exclude_willexecutors,
+ reverse=False,
+ )
else:
return True
-
- def cmp_heirs(heirsa,heirsb,cmp_function = lambda x,y: x[0]==y[0] and x[3]==y[3],reverse=True):
+
+ def cmp_heirs(
+ heirsa,
+ heirsb,
+ cmp_function=lambda x, y: x[0] == y[0] and x[3] == y[3],
+ reverse=True,
+ ):
try:
for heir in heirsa:
- if not "w!ll3x3c\"" in heir:
- if not heir in heirsb or not cmp_function(heirsa[heir],heirsb[heir]):
- if not Util.search_heir_by_values(heirsb,heirsa[heir],[0,3]):
+ if not 'w!ll3x3c"' in heir:
+ if not heir in heirsb or not cmp_function(
+ heirsa[heir], heirsb[heir]
+ ):
+ if not Util.search_heir_by_values(heirsb, heirsa[heir], [0, 3]):
return False
if reverse:
- return Util.cmp_heirs(heirsb,heirsa,cmp_function,False)
+ return Util.cmp_heirs(heirsb, heirsa, cmp_function, False)
else:
return True
except Exception as e:
raise e
return False
- def cmp_inputs(inputsa,inputsb):
- if len(inputsa) != len(inputsb):
- return False
+ def cmp_inputs(inputsa, inputsb):
+ if len(inputsa) != len(inputsb):
+ return False
for inputa in inputsa:
- if not Util.in_utxo(inputa,inputsb):
+ if not Util.in_utxo(inputa, inputsb):
return False
return True
- def cmp_outputs(outputsa,outputsb,willexecutor_output = None):
- if len(outputsa) != len(outputsb):
- return False
- for outputa in outputsa:
- if not Util.cmp_output(outputa,willexecutor_output):
- if not Util.in_output(outputa,outputsb):
+ def cmp_outputs(outputsa, outputsb, willexecutor_output=None):
+ if len(outputsa) != len(outputsb):
+ return False
+ for outputa in outputsa:
+ if not Util.cmp_output(outputa, willexecutor_output):
+ if not Util.in_output(outputa, outputsb):
return False
return True
- def cmp_txs(txa,txb):
- if not Util.cmp_inputs(txa.inputs(),txb.inputs()):
+ def cmp_txs(txa, txb):
+ if not Util.cmp_inputs(txa.inputs(), txb.inputs()):
return False
- if not Util.cmp_outputs(txa.outputs(),txb.outputs()):
+ if not Util.cmp_outputs(txa.outputs(), txb.outputs()):
return False
return True
- def get_value_amount(txa,txb):
- outputsa=txa.outputs()
- outputsb=txb.outputs()
+ def get_value_amount(txa, txb):
+ outputsa = txa.outputs()
+ outputsb = txb.outputs()
value_amount = 0
for outa in outputsa:
- same_amount,same_address = Util.in_output(outa,txb.outputs())
+ same_amount, same_address = Util.in_output(outa, txb.outputs())
if not (same_amount or same_address):
return False
if same_amount and same_address:
- value_amount+=outa.value
+ value_amount += outa.value
if same_amount:
pass
if same_address:
@@ -195,11 +229,9 @@ class Util:
return value_amount
-
-
- def chk_locktime(timestamp_to_check,block_height_to_check,locktime):
- #TODO BUG: WHAT HAPPEN AT THRESHOLD?
- locktime=int(locktime)
+ def chk_locktime(timestamp_to_check, block_height_to_check, locktime):
+ # TODO BUG: WHAT HAPPEN AT THRESHOLD?
+ locktime = int(locktime)
if locktime > LOCKTIME_THRESHOLD and locktime > timestamp_to_check:
return True
elif locktime < LOCKTIME_THRESHOLD and locktime > block_height_to_check:
@@ -207,24 +239,24 @@ class Util:
else:
return False
- def anticipate_locktime(locktime,blocks=0,hours=0,days=0):
+ def anticipate_locktime(locktime, blocks=0, hours=0, days=0):
locktime = int(locktime)
- out=0
- if locktime> LOCKTIME_THRESHOLD:
- seconds = blocks*600 + hours*3600 + days*86400
+ out = 0
+ if locktime > LOCKTIME_THRESHOLD:
+ seconds = blocks * 600 + hours * 3600 + days * 86400
dt = datetime.fromtimestamp(locktime)
dt -= timedelta(seconds=seconds)
out = dt.timestamp()
else:
- blocks -= hours*6 + days*144
+ blocks -= hours * 6 + days * 144
out = locktime + blocks
if out < 1:
- out = 1
+ out = 1
return out
- def cmp_locktime(locktimea,locktimeb):
- if locktimea==locktimeb:
+ def cmp_locktime(locktimea, locktimeb):
+ if locktimea == locktimeb:
return 0
strlocktime = str(locktimea)
strlocktimeb = str(locktimeb)
@@ -232,63 +264,66 @@ class Util:
intlocktimeb = Util.str_to_locktime(strlocktimeb)
if locktimea[-1] in "ydb":
if locktimeb[-1] == locktimea[-1]:
- return int(strlocktimea[-1])-int(strlocktimeb[-1])
+ return int(strlocktimea[-1]) - int(strlocktimeb[-1])
else:
- return int(locktimea)-(locktimeb)
-
+ return int(locktimea) - (locktimeb)
- def get_lowest_valid_tx(available_utxos,will):
- will = sorted(will.items(),key = lambda x: x[1]['tx'].locktime)
- for txid,willitem in will.items():
+ def get_lowest_valid_tx(available_utxos, will):
+ will = sorted(will.items(), key=lambda x: x[1]["tx"].locktime)
+ for txid, willitem in will.items():
pass
def get_locktimes(will):
locktimes = {}
- for txid,willitem in will.items():
- locktimes[willitem['tx'].locktime]=True
+ for txid, willitem in will.items():
+ locktimes[willitem["tx"].locktime] = True
return locktimes.keys()
def get_lowest_locktimes(locktimes):
- sorted_timestamp=[]
- sorted_block=[]
+ sorted_timestamp = []
+ sorted_block = []
for l in locktimes:
- l=Util.parse_locktime_string(l)
+ l = Util.parse_locktime_string(l)
if l < LOCKTIME_THRESHOLD:
- bisect.insort(sorted_block,l)
+ bisect.insort(sorted_block, l)
else:
- bisect.insort(sorted_timestamp,l)
+ bisect.insort(sorted_timestamp, l)
return sorted(sorted_timestamp), sorted(sorted_block)
def get_lowest_locktimes_from_will(will):
return Util.get_lowest_locktimes(Util.get_locktimes(will))
- def search_willtx_per_io(will,tx):
+ def search_willtx_per_io(will, tx):
for wid, w in will.items():
- if Util.cmp_txs(w['tx'],tx['tx']):
- return wid,w
+ if Util.cmp_txs(w["tx"], tx["tx"]):
+ return wid, w
return None, None
def invalidate_will(will):
raise Exception("not implemented")
def get_will_spent_utxos(will):
- utxos=[]
- for txid,willitem in will.items():
- utxos+=willitem['tx'].inputs()
-
+ utxos = []
+ for txid, willitem in will.items():
+ utxos += willitem["tx"].inputs()
+
return utxos
def utxo_to_str(utxo):
- try: return utxo.to_str()
- except Exception as e: pass
- try: return utxo.prevout.to_str()
- except Exception as e: pass
+ try:
+ return utxo.to_str()
+ except Exception as e:
+ pass
+ try:
+ return utxo.prevout.to_str()
+ except Exception as e:
+ pass
return str(utxo)
- def cmp_utxo(utxoa,utxob):
- utxoa=Util.utxo_to_str(utxoa)
- utxob=Util.utxo_to_str(utxob)
+ def cmp_utxo(utxoa, utxob):
+ utxoa = Util.utxo_to_str(utxoa)
+ utxob = Util.utxo_to_str(utxob)
if utxoa == utxob:
return True
else:
@@ -296,57 +331,57 @@ class Util:
def in_utxo(utxo, utxos):
for s_u in utxos:
- if Util.cmp_utxo(s_u,utxo):
+ if Util.cmp_utxo(s_u, utxo):
return True
return False
- def txid_in_utxo(txid,utxos):
+ def txid_in_utxo(txid, utxos):
for s_u in utxos:
if s_u.prevout.txid == txid:
return True
return False
- def cmp_output(outputa,outputb):
+ def cmp_output(outputa, outputb):
return outputa.address == outputb.address and outputa.value == outputb.value
- def in_output(output,outputs):
+ def in_output(output, outputs):
for s_o in outputs:
- if Util.cmp_output(s_o,output):
+ if Util.cmp_output(s_o, output):
return True
return False
- #check all output with the same amount if none have the same address it can be a change
- #return true true same address same amount
- #return true false same amount different address
- #return false false different amount, different address not found
+ # check all output with the same amount if none have the same address it can be a change
+ # return true true same address same amount
+ # return true false same amount different address
+ # return false false different amount, different address not found
-
- def din_output(out,outputs):
- same_amount=[]
+ def din_output(out, outputs):
+ same_amount = []
for s_o in outputs:
if int(out.value) == int(s_o.value):
same_amount.append(s_o)
- if out.address==s_o.address:
+ if out.address == s_o.address:
return True, True
else:
pass
- if len(same_amount)>0:
+ if len(same_amount) > 0:
return True, False
- else:return False, False
+ else:
+ return False, False
-
- def get_change_output(wallet,in_amount,out_amount,fee):
- change_amount = int(in_amount - out_amount - fee)
- if change_amount > wallet.dust_threshold():
- change_addresses = wallet.get_change_addresses_for_new_transaction()
- out = PartialTxOutput.from_address_and_value(change_addresses[0], change_amount)
- out.is_change = True
+ def get_change_output(wallet, in_amount, out_amount, fee):
+ change_amount = int(in_amount - out_amount - fee)
+ if change_amount > wallet.dust_threshold():
+ change_addresses = wallet.get_change_addresses_for_new_transaction()
+ out = PartialTxOutput.from_address_and_value(
+ change_addresses[0], change_amount
+ )
+ out.is_change = True
return out
-
- def get_current_height(network:'Network'):
- #if no network or not up to date, just set locktime to zero
+ def get_current_height(network: "Network"):
+ # if no network or not up to date, just set locktime to zero
if not network:
return 0
chain = network.blockchain()
@@ -354,7 +389,9 @@ class Util:
return 0
# figure out current block height
chain_height = chain.height() # learnt from all connected servers, SPV-checked
- server_height = network.get_server_height() # height claimed by main server, unverified
+ server_height = (
+ network.get_server_height()
+ ) # height claimed by main server, unverified
# note: main server might be lagging (either is slow, is malicious, or there is an SPV-invisible-hard-fork)
# - if it's lagging too much, it is the network's job to switch away
if server_height < chain_height - 10:
@@ -364,60 +401,67 @@ class Util:
height = min(chain_height, server_height)
return height
-
- def print_var(var,name = "",veryverbose=False):
+ def print_var(var, name="", veryverbose=False):
print(f"---{name}---")
if not var is None:
try:
- print("doc:",doc(var))
- except: pass
+ print("doc:", doc(var))
+ except:
+ pass
try:
- print("str:",str(var))
- except: pass
+ print("str:", str(var))
+ except:
+ pass
try:
- print("repr",repr(var))
- except:pass
+ print("repr", repr(var))
+ except:
+ pass
try:
- print("dict",dict(var))
- except:pass
+ print("dict", dict(var))
+ except:
+ pass
try:
- print("dir",dir(var))
- except:pass
+ print("dir", dir(var))
+ except:
+ pass
try:
- print("type",type(var))
- except:pass
+ print("type", type(var))
+ except:
+ pass
try:
- print("to_json",var.to_json())
- except: pass
+ print("to_json", var.to_json())
+ except:
+ pass
try:
- print("__slotnames__",var.__slotnames__)
- except:pass
+ print("__slotnames__", var.__slotnames__)
+ except:
+ pass
print(f"---end {name}---")
- def print_utxo(utxo, name = ""):
+ def print_utxo(utxo, name=""):
print(f"---utxo-{name}---")
- Util.print_var(utxo,name)
- Util.print_prevout(utxo.prevout,name)
- Util.print_var(utxo.script_sig,f"{name}-script-sig")
- Util.print_var(utxo.witness,f"{name}-witness")
- print("_TxInput__address:",utxo._TxInput__address)
- print("_TxInput__scriptpubkey:",utxo._TxInput__scriptpubkey)
- print("_TxInput__value_sats:",utxo._TxInput__value_sats)
+ Util.print_var(utxo, name)
+ Util.print_prevout(utxo.prevout, name)
+ Util.print_var(utxo.script_sig, f"{name}-script-sig")
+ Util.print_var(utxo.witness, f"{name}-witness")
+ print("_TxInput__address:", utxo._TxInput__address)
+ print("_TxInput__scriptpubkey:", utxo._TxInput__scriptpubkey)
+ print("_TxInput__value_sats:", utxo._TxInput__value_sats)
print(f"---utxo-end {name}---")
- def print_prevout(prevout, name = ""):
+ def print_prevout(prevout, name=""):
print(f"---prevout-{name}---")
- Util.print_var(prevout,f"{name}-prevout")
+ Util.print_var(prevout, f"{name}-prevout")
Util.print_var(prevout._asdict())
print(f"---prevout-end {name}---")
- def export_meta_gui(electrum_window: 'ElectrumWindow', title, exporter):
+ def export_meta_gui(electrum_window: "ElectrumWindow", title, exporter):
filter_ = "All files (*)"
filename = getSaveFileName(
parent=electrum_window,
title=_("Select file to save your {}").format(title),
- filename='BALplugin_{}'.format(title),
+ filename="BALplugin_{}".format(title),
filter=filter_,
config=electrum_window.config,
)
@@ -428,29 +472,29 @@ class Util:
except FileExportFailed as e:
electrum_window.show_critical(str(e))
else:
- electrum_window.show_message(_("Your {0} were exported to '{1}'")
- .format(title, str(filename)))
+ electrum_window.show_message(
+ _("Your {0} were exported to '{1}'").format(title, str(filename))
+ )
-
- def copy(dicto,dictfrom):
- for k,v in dictfrom.items():
- dicto[k]=v
+ def copy(dicto, dictfrom):
+ for k, v in dictfrom.items():
+ dicto[k] = v
def fix_will_settings_tx_fees(will_settings):
- tx_fees = will_settings.get('tx_fees',False)
- have_to_update=False
+ tx_fees = will_settings.get("tx_fees", False)
+ have_to_update = False
if tx_fees:
- will_settings['baltx_fees']=tx_fees
- del will_settings['tx_fees']
- have_to_update=True
+ will_settings["baltx_fees"] = tx_fees
+ del will_settings["tx_fees"]
+ have_to_update = True
return have_to_update
def fix_will_tx_fees(will):
have_to_update = False
- for txid,willitem in will.items():
- tx_fees=willitem.get('tx_fees',False)
+ for txid, willitem in will.items():
+ tx_fees = willitem.get("tx_fees", False)
if tx_fees:
- will[txid]['baltx_fees']=tx_fees
- del will[txid]['tx_fees']
- have_to_update=True
+ will[txid]["baltx_fees"] = tx_fees
+ del will[txid]["tx_fees"]
+ have_to_update = True
return have_to_update
diff --git a/wallet_util/bal_wallet_utils.py b/wallet_util/bal_wallet_utils.py
index 88962ee..2c4e0a9 100755
--- a/wallet_util/bal_wallet_utils.py
+++ b/wallet_util/bal_wallet_utils.py
@@ -1,4 +1,4 @@
-#!env/bin/python3
+#!env/bin/python3
from electrum.storage import WalletStorage
from electrum.util import MyEncoder
import json
@@ -6,49 +6,57 @@ import sys
import getpass
import os
-default_fees= 100
+default_fees = 100
+
def fix_will_settings_tx_fees(json_wallet):
- tx_fees = json_wallet.get('will_settings',{}).get('tx_fees',False)
- have_to_update=False
+ tx_fees = json_wallet.get("will_settings", {}).get("tx_fees", False)
+ have_to_update = False
if tx_fees:
- json_wallet['will_settings']['baltx_fees']=tx_fees
- del json_wallet['will_settings']['tx_fees']
- have_to_update=True
- for txid,willitem in json_wallet['will'].items():
- tx_fees=willitem.get('tx_fees',False)
+ json_wallet["will_settings"]["baltx_fees"] = tx_fees
+ del json_wallet["will_settings"]["tx_fees"]
+ have_to_update = True
+ for txid, willitem in json_wallet["will"].items():
+ tx_fees = willitem.get("tx_fees", False)
if tx_fees:
- json_wallet['will'][txid]['baltx_fees']=tx_fees
- del json_wallet['will'][txid]['tx_fees']
- have_to_update=True
+ json_wallet["will"][txid]["baltx_fees"] = tx_fees
+ del json_wallet["will"][txid]["tx_fees"]
+ have_to_update = True
return have_to_update
+
def uninstall_bal(json_wallet):
- del json_wallet['will_settings']
- del json_wallet['will']
- del json_wallet['heirs']
+ del json_wallet["will_settings"]
+ del json_wallet["will"]
+ del json_wallet["heirs"]
return True
-def save(json_wallet,storage):
- human_readable=not storage.is_encrypted()
- storage.write(json.dumps(
+
+def save(json_wallet, storage):
+ human_readable = not storage.is_encrypted()
+ storage.write(
+ json.dumps(
json_wallet,
indent=4 if human_readable else None,
sort_keys=bool(human_readable),
cls=MyEncoder,
- ))
-def read_wallet(path,password=False):
- storage=WalletStorage(path)
+ )
+ )
+
+
+def read_wallet(path, password=False):
+ storage = WalletStorage(path)
if storage.is_encrypted():
- if password==False:
- password = getpass.getpass("Enter wallet password: ", stream = None)
+ if password == False:
+ password = getpass.getpass("Enter wallet password: ", stream=None)
storage.decrypt(password)
- data=storage.read()
- json_wallet=json.loads('['+data+']')[0]
+ data = storage.read()
+ json_wallet = json.loads("[" + data + "]")[0]
return json_wallet
-if __name__ == '__main__':
- if len(sys.argv) <3:
+
+if __name__ == "__main__":
+ if len(sys.argv) < 3:
print("usage: ./bal_wallet_utils ")
print("available commands: uninstall, fix")
exit(1)
@@ -58,12 +66,12 @@ if __name__ == '__main__':
command = sys.argv[1]
path = sys.argv[2]
json_wallet = read_wallet(path)
- have_to_save=False
- if command == 'fix':
+ have_to_save = False
+ if command == "fix":
have_to_save = fix_will_settings_tx_fees(json_wallet)
- if command == 'uninstall':
+ if command == "uninstall":
have_to_save = uninstall_bal(json_wallet)
if have_to_save:
- save(json_wallet,storage)
+ save(json_wallet, storage)
else:
print("nothing to do")
diff --git a/wallet_util/bal_wallet_utils_qt.py b/wallet_util/bal_wallet_utils_qt.py
index 0f72da3..8d8d565 100755
--- a/wallet_util/bal_wallet_utils_qt.py
+++ b/wallet_util/bal_wallet_utils_qt.py
@@ -2,47 +2,58 @@
import sys
import os
import json
-from PyQt6.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout,
- QLabel, QLineEdit, QPushButton, QWidget, QFileDialog,
- QGroupBox, QTextEdit)
+from PyQt6.QtWidgets import (
+ QApplication,
+ QMainWindow,
+ QVBoxLayout,
+ QHBoxLayout,
+ QLabel,
+ QLineEdit,
+ QPushButton,
+ QWidget,
+ QFileDialog,
+ QGroupBox,
+ QTextEdit,
+)
from PyQt6.QtCore import Qt
from electrum.storage import WalletStorage
from electrum.util import MyEncoder
-from bal_wallet_utils import fix_will_settings_tx_fees,uninstall_bal,read_wallet
+from bal_wallet_utils import fix_will_settings_tx_fees, uninstall_bal, read_wallet
+
class WalletUtilityGUI(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
-
+
def initUI(self):
- self.setWindowTitle('BAL Wallet Utility')
+ self.setWindowTitle("BAL Wallet Utility")
self.setFixedSize(500, 400)
-
+
# Central widget
central_widget = QWidget()
self.setCentralWidget(central_widget)
-
+
# Main layout
layout = QVBoxLayout(central_widget)
-
+
# Wallet input group
wallet_group = QGroupBox("Wallet Settings")
wallet_layout = QVBoxLayout(wallet_group)
-
+
# Wallet path
wallet_path_layout = QHBoxLayout()
wallet_path_layout.addWidget(QLabel("Wallet Path:"))
self.wallet_path_edit = QLineEdit()
self.wallet_path_edit.setPlaceholderText("Select wallet path...")
wallet_path_layout.addWidget(self.wallet_path_edit)
-
+
self.browse_btn = QPushButton("Browse...")
self.browse_btn.clicked.connect(self.browse_wallet)
wallet_path_layout.addWidget(self.browse_btn)
-
+
wallet_layout.addLayout(wallet_path_layout)
-
+
# Password
password_layout = QHBoxLayout()
password_layout.addWidget(QLabel("Password:"))
@@ -50,111 +61,118 @@ class WalletUtilityGUI(QMainWindow):
self.password_edit.setEchoMode(QLineEdit.EchoMode.Password)
self.password_edit.setPlaceholderText("Enter password (if encrypted)")
password_layout.addWidget(self.password_edit)
-
+
wallet_layout.addLayout(password_layout)
-
+
layout.addWidget(wallet_group)
-
+
# Output area
output_group = QGroupBox("Output")
output_layout = QVBoxLayout(output_group)
-
+
self.output_text = QTextEdit()
self.output_text.setReadOnly(True)
output_layout.addWidget(self.output_text)
-
+
layout.addWidget(output_group)
-
+
# Action buttons
buttons_layout = QHBoxLayout()
-
+
self.fix_btn = QPushButton("Fix")
self.fix_btn.clicked.connect(self.fix_wallet)
self.fix_btn.setEnabled(False)
buttons_layout.addWidget(self.fix_btn)
-
+
self.uninstall_btn = QPushButton("Uninstall")
self.uninstall_btn.clicked.connect(self.uninstall_wallet)
self.uninstall_btn.setEnabled(False)
buttons_layout.addWidget(self.uninstall_btn)
-
+
layout.addLayout(buttons_layout)
-
+
# Connections to enable buttons when path is entered
self.wallet_path_edit.textChanged.connect(self.check_inputs)
-
+
def browse_wallet(self):
file_path, _ = QFileDialog.getOpenFileName(
- self,
- "Select Wallet",
- "*",
- "Electrum Wallet (*)"
+ self, "Select Wallet", "*", "Electrum Wallet (*)"
)
if file_path:
self.wallet_path_edit.setText(file_path)
-
+
def check_inputs(self):
wallet_path = self.wallet_path_edit.text().strip()
has_path = bool(wallet_path) and os.path.exists(wallet_path)
-
+
self.fix_btn.setEnabled(has_path)
self.uninstall_btn.setEnabled(has_path)
-
+
def log_message(self, message):
self.output_text.append(message)
-
+
def fix_wallet(self):
- self.process_wallet('fix')
-
+ self.process_wallet("fix")
+
def uninstall_wallet(self):
- self.log_message("WARNING: This will remove all BAL settings. This operation cannot be undone.")
- self.process_wallet('uninstall')
-
+ self.log_message(
+ "WARNING: This will remove all BAL settings. This operation cannot be undone."
+ )
+ self.process_wallet("uninstall")
+
def process_wallet(self, command):
wallet_path = self.wallet_path_edit.text().strip()
password = self.password_edit.text()
-
+
if not wallet_path:
self.log_message("ERROR: Please enter wallet path")
return
-
+
if not os.path.exists(wallet_path):
self.log_message("ERROR: Wallet not found")
return
-
+
try:
self.log_message(f"Processing wallet: {wallet_path}")
-
+
storage = WalletStorage(wallet_path)
-
+
# Decrypt if necessary
if storage.is_encrypted():
if not password:
- self.log_message("ERROR: Wallet is encrypted, please enter password")
+ self.log_message(
+ "ERROR: Wallet is encrypted, please enter password"
+ )
return
-
+
try:
storage.decrypt(password)
self.log_message("Wallet decrypted successfully")
except Exception as e:
self.log_message(f"ERROR: Wrong password: {str(e)}")
return
-
+
# Read wallet
data = storage.read()
- json_wallet = json.loads('[' + data + ']')[0]
-
+ json_wallet = json.loads("[" + data + "]")[0]
+
have_to_save = False
message = ""
-
- if command == 'fix':
+
+ if command == "fix":
have_to_save = fix_will_settings_tx_fees(json_wallet)
- message = "Fix applied successfully" if have_to_save else "No fix needed"
-
- elif command == 'uninstall':
+ message = (
+ "Fix applied successfully" if have_to_save else "No fix needed"
+ )
+
+ elif command == "uninstall":
have_to_save = uninstall_bal(json_wallet)
- message = "BAL uninstalled successfully" if have_to_save else "No BAL settings found to uninstall"
-
+ message = (
+ "BAL uninstalled successfully"
+ if have_to_save
+ else "No BAL settings found to uninstall"
+ )
+
if have_to_save:
try:
save_wallet(json_wallet, storage)
@@ -163,14 +181,15 @@ class WalletUtilityGUI(QMainWindow):
self.log_message(f"Save error: {str(e)}")
else:
self.log_message(f"INFO: {message}")
-
+
except Exception as e:
error_msg = f"ERROR: Processing failed: {str(e)}"
self.log_message(error_msg)
+
def main():
app = QApplication(sys.argv)
-
+
# Check if dependencies are available
try:
from electrum.storage import WalletStorage
@@ -178,11 +197,12 @@ def main():
except ImportError as e:
print(f"ERROR: Cannot import Electrum dependencies: {str(e)}")
return 1
-
+
window = WalletUtilityGUI()
window.show()
-
+
return app.exec()
-if __name__ == '__main__':
+
+if __name__ == "__main__":
sys.exit(main())
diff --git a/will.py b/will.py
index b3cd89d..e2cc8c9 100644
--- a/will.py
+++ b/will.py
@@ -1,101 +1,111 @@
import copy
-from .willexecutors import Willexecutors
-from .util import Util
-
-from electrum.i18n import _
-
-from electrum.transaction import TxOutpoint,PartialTxInput,tx_from_any,PartialTransaction,PartialTxOutput,Transaction
-from electrum.util import bfh, decimal_point_to_base_unit_name
-from electrum.util import write_json_file,read_json_file,FileImportFailed
-from electrum.logging import get_logger,Logger
from electrum.bitcoin import NLOCKTIME_BLOCKHEIGHT_MAX
+from electrum.i18n import _
+from electrum.logging import Logger, get_logger
+from electrum.transaction import (
+ PartialTransaction,
+ PartialTxInput,
+ PartialTxOutput,
+ Transaction,
+ TxOutpoint,
+ tx_from_any,
+)
+from electrum.util import (
+ FileImportFailed,
+ bfh,
+ decimal_point_to_base_unit_name,
+ read_json_file,
+ write_json_file,
+)
+
+from .util import Util
+from .willexecutors import Willexecutors
MIN_LOCKTIME = 1
MIN_BLOCK = 1
_logger = get_logger(__name__)
+
class Will:
- #return an array with the list of children
- def get_children(will,willid):
+ # return an array with the list of children
+ def get_children(will, willid):
out = []
for _id in will:
inputs = will[_id].tx.inputs()
- for idi in range(0,len(inputs)):
+ for idi in range(0, len(inputs)):
_input = inputs[idi]
if _input.prevout.txid.hex() == willid:
- out.append([_id,idi,_input.prevout.out_idx])
+ out.append([_id, idi, _input.prevout.out_idx])
return out
- #build a tree with parent transactions
+ # build a tree with parent transactions
def add_willtree(will):
for willid in will:
- will[willid].children = Will.get_children(will,willid)
+ will[willid].children = Will.get_children(will, willid)
for child in will[willid].children:
- if not will[child[0]].father:
+ if not will[child[0]].father:
will[child[0]].father = willid
-
- #return a list of will sorted by locktime
+ # return a list of will sorted by locktime
def get_sorted_will(will):
- return sorted(will.items(),key = lambda x: x[1]['tx'].locktime)
-
+ return sorted(will.items(), key=lambda x: x[1]["tx"].locktime)
def only_valid(will):
- for k,v in will.items():
- if v.get_status('VALID'):
+ for k, v in will.items():
+ if v.get_status("VALID"):
yield k
- def search_equal_tx(will,tx,wid):
+ def search_equal_tx(will, tx, wid):
for w in will:
- if w != wid and not tx.to_json() != will[w]['tx'].to_json():
- if will[w]['tx'].txid() != tx.txid():
- if Util.cmp_txs(will[w]['tx'],tx):
- return will[w]['tx']
+ if w != wid and not tx.to_json() != will[w]["tx"].to_json():
+ if will[w]["tx"].txid() != tx.txid():
+ if Util.cmp_txs(will[w]["tx"], tx):
+ return will[w]["tx"]
return False
def get_tx_from_any(x):
try:
- a=str(x)
+ a = str(x)
return tx_from_any(a)
-
+
except Exception as e:
raise e
return x
- def add_info_from_will(will,wid,wallet):
- if isinstance(will[wid].tx,str):
+ def add_info_from_will(will, wid, wallet):
+ if isinstance(will[wid].tx, str):
will[wid].tx = Will.get_tx_from_any(will[wid].tx)
if wallet:
will[wid].tx.add_info_from_wallet(wallet)
for txin in will[wid].tx.inputs():
txid = txin.prevout.txid.hex()
if txid in will:
- #print(will[txid].tx.outputs())
- #print(txin.prevout.out_idx)
+ # print(will[txid].tx.outputs())
+ # print(txin.prevout.out_idx)
change = will[txid].tx.outputs()[txin.prevout.out_idx]
txin._trusted_value_sats = change.value
try:
txin.script_descriptor = change.script_descriptor
except:
pass
- txin.is_mine=True
- txin._TxInput__address=change.address
+ txin.is_mine = True
+ txin._TxInput__address = change.address
txin._TxInput__scriptpubkey = change.scriptpubkey
txin._TxInput__value_sats = change.value
txin._trusted_value_sats = change.value
- def normalize_will(will,wallet = None,others_inputs = {}):
+ def normalize_will(will, wallet=None, others_inputs={}):
to_delete = []
to_add = {}
- #add info from wallet
- willitems={}
+ # add info from wallet
+ willitems = {}
for wid in will:
- Will.add_info_from_will(will,wid,wallet)
- willitems[wid]=WillItem(will[wid])
- will=willitems
- errors ={}
+ Will.add_info_from_will(will, wid, wallet)
+ willitems[wid] = WillItem(will[wid])
+ will = willitems
+ errors = {}
for wid in will:
txid = will[wid].tx.txid()
@@ -105,51 +115,55 @@ class Will:
_logger.error(wid)
_logger.error(will[wid])
_logger.error(will[wid].tx.to_json())
-
+
_logger.error("txid is none")
- will[wid].set_status('ERROR',True)
- errors[wid]=will[wid]
+ will[wid].set_status("ERROR", True)
+ errors[wid] = will[wid]
continue
if txid != wid:
outputs = will[wid].tx.outputs()
- ow=will[wid]
+ ow = will[wid]
ow.normalize_locktime(others_inputs)
- will[wid]=WillItem(ow.to_dict())
+ will[wid] = WillItem(ow.to_dict())
- for i in range(0,len(outputs)):
- Will.change_input(will,wid,i,outputs[i],others_inputs,to_delete,to_add)
+ for i in range(0, len(outputs)):
+ Will.change_input(
+ will, wid, i, outputs[i], others_inputs, to_delete, to_add
+ )
to_delete.append(wid)
- to_add[ow.tx.txid()]=ow.to_dict()
+ to_add[ow.tx.txid()] = ow.to_dict()
- for eid,err in errors.items():
+ for eid, err in errors.items():
new_txid = err.tx.txid()
- for k,w in to_add.items():
+ for k, w in to_add.items():
will[k] = w
for wid in to_delete:
if wid in will:
del will[wid]
- def new_input(txid,idx,change):
+ def new_input(txid, idx, change):
prevout = TxOutpoint(txid=bfh(txid), out_idx=idx)
inp = PartialTxInput(prevout=prevout)
inp._trusted_value_sats = change.value
- inp.is_mine=True
- inp._TxInput__address=change.address
+ inp.is_mine = True
+ inp._TxInput__address = change.address
inp._TxInput__scriptpubkey = change.scriptpubkey
inp._TxInput__value_sats = change.value
return inp
- def check_anticipate(ow:'WillItem',nw:'WillItem'):
- anticipate = Util.anticipate_locktime(ow.tx.locktime,days=1)
+ def check_anticipate(ow: "WillItem", nw: "WillItem"):
+ anticipate = Util.anticipate_locktime(ow.tx.locktime, days=1)
if int(nw.tx.locktime) >= int(anticipate):
- if Util.cmp_heirs_by_values(ow.heirs,nw.heirs,[0,1],exclude_willexecutors = True):
+ if Util.cmp_heirs_by_values(
+ ow.heirs, nw.heirs, [0, 1], exclude_willexecutors=True
+ ):
if nw.we and ow.we:
- if ow.we['url'] == nw.we['url']:
- if int(ow.we['base_fee'])>int(nw.we['base_fee']):
+ if ow.we["url"] == nw.we["url"]:
+ if int(ow.we["base_fee"]) > int(nw.we["base_fee"]):
return anticipate
else:
if int(ow.tx_fees) != int(nw.tx_fees):
@@ -160,7 +174,7 @@ class Will:
ow.tx.locktime
else:
if nw.we == ow.we:
- if not Util.cmp_heirs_by_values(ow.heirs,nw.heirs,[0,3]):
+ if not Util.cmp_heirs_by_values(ow.heirs, nw.heirs, [0, 3]):
return anticipate
else:
return ow.tx.locktime
@@ -168,10 +182,9 @@ class Will:
return ow.tx.locktime
else:
return anticipate
- return 4294967295+1
+ return 4294967295 + 1
-
- def change_input(will, otxid, idx, change,others_inputs,to_delete,to_append):
+ def change_input(will, otxid, idx, change, others_inputs, to_delete, to_append):
ow = will[otxid]
ntxid = ow.tx.txid()
if otxid != ntxid:
@@ -182,12 +195,15 @@ class Will:
found = False
old_txid = w.tx.txid()
ntx = None
- for i in range(0,len(inputs)):
- if inputs[i].prevout.txid.hex() == otxid and inputs[i].prevout.out_idx == idx:
- if isinstance(w.tx,Transaction):
+ for i in range(0, len(inputs)):
+ if (
+ inputs[i].prevout.txid.hex() == otxid
+ and inputs[i].prevout.out_idx == idx
+ ):
+ if isinstance(w.tx, Transaction):
will[wid].tx = PartialTransaction.from_tx(w.tx)
will[wid].tx.set_rbf(True)
- will[wid].tx._inputs[i]=Will.new_input(wid,idx,change)
+ will[wid].tx._inputs[i] = Will.new_input(wid, idx, change)
found = True
if found == True:
pass
@@ -195,19 +211,27 @@ class Will:
new_txid = will[wid].tx.txid()
if old_txid != new_txid:
to_delete.append(old_txid)
- to_append[new_txid]=will[wid]
+ to_append[new_txid] = will[wid]
outputs = will[wid].tx.outputs()
- for i in range(0,len(outputs)):
- Will.change_input(will, wid, i, outputs[i],others_inputs,to_delete,to_append)
-
- def get_all_inputs(will,only_valid = False):
+ for i in range(0, len(outputs)):
+ Will.change_input(
+ will,
+ wid,
+ i,
+ outputs[i],
+ others_inputs,
+ to_delete,
+ to_append,
+ )
+
+ def get_all_inputs(will, only_valid=False):
all_inputs = {}
- for w,wi in will.items():
- if not only_valid or wi.get_status('VALID'):
+ for w, wi in will.items():
+ if not only_valid or wi.get_status("VALID"):
inputs = wi.tx.inputs()
for i in inputs:
prevout_str = i.prevout.to_str()
- inp=[w,will[w],i]
+ inp = [w, will[w], i]
if not prevout_str in all_inputs:
all_inputs[prevout_str] = [inp]
else:
@@ -216,67 +240,65 @@ class Will:
def get_all_inputs_min_locktime(all_inputs):
all_inputs_min_locktime = {}
-
- for i,values in all_inputs.items():
- min_locktime = min(values,key = lambda x:x[1].tx.locktime)[1].tx.locktime
+
+ for i, values in all_inputs.items():
+ min_locktime = min(values, key=lambda x: x[1].tx.locktime)[1].tx.locktime
for w in values:
if w[1].tx.locktime == min_locktime:
if not i in all_inputs_min_locktime:
- all_inputs_min_locktime[i]=[w]
+ all_inputs_min_locktime[i] = [w]
else:
- all_inputs_min_locktime[i].append(w)
+ all_inputs_min_locktime[i].append(w)
return all_inputs_min_locktime
-
- def search_anticipate_rec(will,old_inputs):
+ def search_anticipate_rec(will, old_inputs):
redo = False
to_delete = []
to_append = {}
- new_inputs = Will.get_all_inputs(will,only_valid = True)
- for nid,nwi in will.items():
+ new_inputs = Will.get_all_inputs(will, only_valid=True)
+ for nid, nwi in will.items():
if nwi.search_anticipate(new_inputs) or nwi.search_anticipate(old_inputs):
if nid != nwi.tx.txid():
redo = True
to_delete.append(nid)
to_append[nwi.tx.txid()] = nwi
outputs = nwi.tx.outputs()
- for i in range(0,len(outputs)):
- Will.change_input(will,nid,i,outputs[i],new_inputs,to_delete,to_append)
-
+ for i in range(0, len(outputs)):
+ Will.change_input(
+ will, nid, i, outputs[i], new_inputs, to_delete, to_append
+ )
for w in to_delete:
try:
del will[w]
except:
pass
- for k,w in to_append.items():
- will[k]=w
+ for k, w in to_append.items():
+ will[k] = w
if redo:
- Will.search_anticipate_rec(will,old_inputs)
+ Will.search_anticipate_rec(will, old_inputs)
-
- def update_will(old_will,new_will):
- all_old_inputs = Will.get_all_inputs(old_will,only_valid=True)
+ def update_will(old_will, new_will):
+ all_old_inputs = Will.get_all_inputs(old_will, only_valid=True)
all_inputs_min_locktime = Will.get_all_inputs_min_locktime(all_old_inputs)
all_new_inputs = Will.get_all_inputs(new_will)
- #check if the new input is already spent by other transaction
- #if it is use the same locktime, or anticipate.
- Will.search_anticipate_rec(new_will,all_old_inputs)
+ # check if the new input is already spent by other transaction
+ # if it is use the same locktime, or anticipate.
+ Will.search_anticipate_rec(new_will, all_old_inputs)
- other_inputs = Will.get_all_inputs(old_will,{})
+ other_inputs = Will.get_all_inputs(old_will, {})
try:
- Will.normalize_will(new_will,others_inputs=other_inputs)
+ Will.normalize_will(new_will, others_inputs=other_inputs)
except Exception as e:
raise e
-
for oid in Will.only_valid(old_will):
if oid in new_will:
new_heirs = new_will[oid].heirs
new_we = new_will[oid].we
- new_will[oid]=old_will[oid]
+ new_will[oid] = old_will[oid]
new_will[oid].heirs = new_heirs
new_will[oid].we = new_we
@@ -297,39 +319,45 @@ class Will:
out[inp.prevout.to_str()] = inp
return out
- def invalidate_will(will,wallet,fees_per_byte):
+ def invalidate_will(will, wallet, fees_per_byte):
will_only_valid = Will.only_valid_list(will)
inputs = Will.get_all_inputs(will_only_valid)
utxos = wallet.get_utxos()
filtered_inputs = []
prevout_to_spend = []
- for prevout_str,ws in inputs.items():
+ for prevout_str, ws in inputs.items():
for w in ws:
- if not w[0] in filtered_inputs:
+ if not w[0] in filtered_inputs:
filtered_inputs.append(w[0])
if not prevout_str in prevout_to_spend:
prevout_to_spend.append(prevout_str)
balance = 0
utxo_to_spend = []
for utxo in utxos:
- utxo_str=utxo.prevout.to_str()
+ utxo_str = utxo.prevout.to_str()
if utxo_str in prevout_to_spend:
balance += inputs[utxo_str][0][2].value_sats()
utxo_to_spend.append(utxo)
- if len(utxo_to_spend) > 0:
+ if len(utxo_to_spend) > 0:
change_addresses = wallet.get_change_addresses_for_new_transaction()
out = PartialTxOutput.from_address_and_value(change_addresses[0], balance)
out.is_change = True
locktime = Util.get_current_height(wallet.network)
- tx = PartialTransaction.from_io(utxo_to_spend, [out], locktime=locktime, version=2)
+ tx = PartialTransaction.from_io(
+ utxo_to_spend, [out], locktime=locktime, version=2
+ )
tx.set_rbf(True)
- fee=tx.estimated_size()*fees_per_byte
- if balance -fee >0:
- out = PartialTxOutput.from_address_and_value(change_addresses[0],balance - fee)
- tx = PartialTransaction.from_io(utxo_to_spend,[out], locktime=locktime, version=2)
+ fee = tx.estimated_size() * fees_per_byte
+ if balance - fee > 0:
+ out = PartialTxOutput.from_address_and_value(
+ change_addresses[0], balance - fee
+ )
+ tx = PartialTransaction.from_io(
+ utxo_to_spend, [out], locktime=locktime, version=2
+ )
tx.set_rbf(True)
-
+
_logger.debug(f"invalidation tx: {tx}")
return tx
@@ -340,71 +368,73 @@ class Will:
_logger.debug("len utxo_to_spend <=0")
pass
-
def is_new(will):
- for wid,w in will.items():
- if w.get_status('VALID') and not w.get_status('COMPLETE'):
+ for wid, w in will.items():
+ if w.get_status("VALID") and not w.get_status("COMPLETE"):
return True
- def search_rai (all_inputs,all_utxos,will,wallet):
+ def search_rai(all_inputs, all_utxos, will, wallet):
will_only_valid = Will.only_valid_or_replaced_list(will)
- for inp,ws in all_inputs.items():
- inutxo = Util.in_utxo(inp,all_utxos)
+ for inp, ws in all_inputs.items():
+ inutxo = Util.in_utxo(inp, all_utxos)
for w in ws:
- wi=w[1]
- if wi.get_status('VALID') or wi.get_status('CONFIRMED') or wi.get_status('PENDING'):
- prevout_id=w[2].prevout.txid.hex()
+ wi = w[1]
+ if (
+ wi.get_status("VALID")
+ or wi.get_status("CONFIRMED")
+ or wi.get_status("PENDING")
+ ):
+ prevout_id = w[2].prevout.txid.hex()
if not inutxo:
if prevout_id in will:
- wo=will[prevout_id]
- if wo.get_status('REPLACED'):
- wi.set_status('REPLACED',True)
+ wo = will[prevout_id]
+ if wo.get_status("REPLACED"):
+ wi.set_status("REPLACED", True)
if wo.get_status("INVALIDATED"):
- wi.set_status('INVALIDATED',True)
-
+ wi.set_status("INVALIDATED", True)
+
else:
if wallet.db.get_transaction(wi._id):
- wi.set_status('CONFIRMED',True)
+ wi.set_status("CONFIRMED", True)
else:
- wi.set_status('INVALIDATED',True)
-
+ wi.set_status("INVALIDATED", True)
+
for child in wi.search(all_inputs):
if child.tx.locktime < wi.tx.locktime:
_logger.debug("a child was found")
- wi.set_status('REPLACED',True)
+ wi.set_status("REPLACED", True)
else:
pass
def utxos_strs(utxos):
return [Util.utxo_to_str(u) for u in utxos]
-
- def set_invalidate(wid,will=[]):
- will[wid].set_status("INVALIDATED",True)
+ def set_invalidate(wid, will=[]):
+ will[wid].set_status("INVALIDATED", True)
if will[wid].children:
for c in self.children.items():
- Will.set_invalidate(c[0],will)
+ Will.set_invalidate(c[0], will)
def check_tx_height(tx, wallet):
- info=wallet.get_tx_info(tx)
- return info.tx_mined_status.height
+ info = wallet.get_tx_info(tx)
+ return info.tx_mined_status.height()
- #check if transactions are stil valid tecnically valid
- def check_invalidated(willtree,utxos_list,wallet):
- for wid,w in willtree.items():
+ # check if transactions are stil valid tecnically valid
+ def check_invalidated(willtree, utxos_list, wallet):
+ for wid, w in willtree.items():
if not w.father:
for inp in w.tx.inputs():
inp_str = Util.utxo_to_str(inp)
if not inp_str in utxos_list:
if wallet:
- height= Will.check_tx_height(w.tx,wallet)
-
+ height = Will.check_tx_height(w.tx, wallet)
+ print(type(height))
if height < 0:
- Will.set_invalidate(wid,willtree)
+ Will.set_invalidate(wid, willtree)
elif height == 0:
- w.set_status("PENDING",True)
+ w.set_status("PENDING", True)
else:
- w.set_status('CONFIRMED',True)
+ w.set_status("CONFIRMED", True)
def reflect_to_children(treeitem):
if not treeitem.get_status("VALID"):
@@ -413,153 +443,197 @@ class Will:
wc = willtree[child]
if wc.get_status("VALID"):
if treeitem.get_status("INVALIDATED"):
- wc.set_status("INVALIDATED",True)
+ wc.set_status("INVALIDATED", True)
if treeitem.get_status("REPLACED"):
- wc.set_status("REPLACED",True)
+ wc.set_status("REPLACED", True)
if wc.children:
Will.reflect_to_children(wc)
- def check_amounts(heirs,willexecutors,all_utxos,timestamp_to_check,dust):
- fixed_heirs,fixed_amount,perc_heirs,perc_amount = heirs.fixed_percent_lists_amount(timestamp_to_check,dust,reverse=True)
+ def check_amounts(heirs, willexecutors, all_utxos, timestamp_to_check, dust):
+ fixed_heirs, fixed_amount, perc_heirs, perc_amount = (
+ heirs.fixed_percent_lists_amount(timestamp_to_check, dust, reverse=True)
+ )
wallet_balance = 0
for utxo in all_utxos:
wallet_balance += utxo.value_sats()
if fixed_amount >= wallet_balance:
- raise FixedAmountException(f"Fixed amount({fixed_amount}) >= {wallet_balance}")
+ raise FixedAmountException(
+ f"Fixed amount({fixed_amount}) >= {wallet_balance}"
+ )
if perc_amount != 100:
raise PercAmountException(f"Perc amount({perc_amount}) =! 100%")
- for url,wex in willexecutors.items():
+ for url, wex in willexecutors.items():
if Willexecutors.is_selected(wex):
- temp_balance = wallet_balance - int(wex['base_fee'])
+ temp_balance = wallet_balance - int(wex["base_fee"])
if fixed_amount >= temp_balance:
- raise FixedAmountException(f"Willexecutor{url} excess base fee({wex['base_fee']}), {fixed_amount} >={temp_balance}")
+ raise FixedAmountException(
+ f"Willexecutor{url} excess base fee({wex['base_fee']}), {fixed_amount} >={temp_balance}"
+ )
-
- def check_will(will,all_utxos,wallet,block_to_check,timestamp_to_check):
+ def check_will(will, all_utxos, wallet, block_to_check, timestamp_to_check):
+ print("check will2")
Will.add_willtree(will)
- utxos_list= Will.utxos_strs(all_utxos)
+ print("willtree")
+ utxos_list = Will.utxos_strs(all_utxos)
+ print("utxo_list")
- Will.check_invalidated(will,utxos_list,wallet)
-
- all_inputs=Will.get_all_inputs(will,only_valid = True)
+ Will.check_invalidated(will, utxos_list, wallet)
+ print("check invalidate")
+ all_inputs = Will.get_all_inputs(will, only_valid=True)
+ print("get all inputs")
all_inputs_min_locktime = Will.get_all_inputs_min_locktime(all_inputs)
+ print("min_locktime")
+ Will.check_will_expired(
+ all_inputs_min_locktime, block_to_check, timestamp_to_check
+ )
+ print("check expired")
- Will.check_will_expired(all_inputs_min_locktime,block_to_check,timestamp_to_check)
-
- all_inputs=Will.get_all_inputs(will,only_valid = True)
-
- Will.search_rai(all_inputs,all_utxos,will,wallet)
-
- def is_will_valid(will, block_to_check, timestamp_to_check, tx_fees, all_utxos,heirs={},willexecutors={},self_willexecutor=False, wallet=False, callback_not_valid_tx=None):
-
- Will.check_will(will,all_utxos,wallet,block_to_check,timestamp_to_check)
+ all_inputs = Will.get_all_inputs(will, only_valid=True)
+ Will.search_rai(all_inputs, all_utxos, will, wallet)
+ def is_will_valid(
+ will,
+ block_to_check,
+ timestamp_to_check,
+ tx_fees,
+ all_utxos,
+ heirs={},
+ willexecutors={},
+ self_willexecutor=False,
+ wallet=False,
+ callback_not_valid_tx=None,
+ ):
+ print("is_will_valid")
+ Will.check_will(will, all_utxos, wallet, block_to_check, timestamp_to_check)
+ print("check will")
if heirs:
- if not Will.check_willexecutors_and_heirs(will,heirs,willexecutors,self_willexecutor,timestamp_to_check,tx_fees):
+ if not Will.check_willexecutors_and_heirs(
+ will,
+ heirs,
+ willexecutors,
+ self_willexecutor,
+ timestamp_to_check,
+ tx_fees,
+ ):
raise NotCompleteWillException()
+ all_inputs = Will.get_all_inputs(will, only_valid=True)
- all_inputs=Will.get_all_inputs(will,only_valid = True)
-
- _logger.info('check all utxo in wallet are spent')
+ _logger.info("check all utxo in wallet are spent")
if all_inputs:
for utxo in all_utxos:
- if utxo.value_sats() > 68 * tx_fees:
- if not Util.in_utxo(utxo,all_inputs.keys()):
- _logger.info("utxo is not spent",utxo.to_json())
- _logger.debug(all_inputs.keys())
- raise NotCompleteWillException("Some utxo in the wallet is not included")
+ if utxo.value_sats() > 68 * tx_fees:
+ if not Util.in_utxo(utxo, all_inputs.keys()):
+ _logger.info("utxo is not spent", utxo.to_json())
+ _logger.debug(all_inputs.keys())
+ raise NotCompleteWillException(
+ "Some utxo in the wallet is not included"
+ )
- _logger.info('will ok')
+ _logger.info("will ok")
return True
- def check_will_expired(all_inputs_min_locktime,block_to_check,timestamp_to_check):
+ def check_will_expired(all_inputs_min_locktime, block_to_check, timestamp_to_check):
_logger.info("check if some transaction is expired")
for prevout_str, wid in all_inputs_min_locktime.items():
- for w in wid:
- if w[1].get_status('VALID'):
+ for w in wid:
+ if w[1].get_status("VALID"):
locktime = int(wid[0][1].tx.locktime)
if locktime <= NLOCKTIME_BLOCKHEIGHT_MAX:
if locktime < int(block_to_check):
- raise WillExpiredException(f"Will Expired {wid[0][0]}: {locktime}<{block_to_check}")
+ raise WillExpiredException(
+ f"Will Expired {wid[0][0]}: {locktime}<{block_to_check}"
+ )
else:
if locktime < int(timestamp_to_check):
- raise WillExpiredException(f"Will Expired {wid[0][0]}: {locktime}<{timestamp_to_check}")
-
+ raise WillExpiredException(
+ f"Will Expired {wid[0][0]}: {locktime}<{timestamp_to_check}"
+ )
+
def check_all_input_spent_are_in_wallet():
_logger.info("check all input spent are in wallet or valid txs")
- for inp,ws in all_inputs.items():
- if not Util.in_utxo(inp,all_utxos):
+ for inp, ws in all_inputs.items():
+ if not Util.in_utxo(inp, all_utxos):
for w in ws:
- if w[1].get_status('VALID'):
+ if w[1].get_status("VALID"):
prevout_id = w[2].prevout.txid.hex()
- parentwill = will.get(prevout_id,False)
- if not parentwill or not parentwill.get_status('VALID'):
- w[1].set_status('INVALIDATED',True)
-
+ parentwill = will.get(prevout_id, False)
+ if not parentwill or not parentwill.get_status("VALID"):
+ w[1].set_status("INVALIDATED", True)
def only_valid_list(will):
- out={}
- for wid,w in will.items():
- if w.get_status('VALID'):
- out[wid]=w
+ out = {}
+ for wid, w in will.items():
+ if w.get_status("VALID"):
+ out[wid] = w
return out
def only_valid_or_replaced_list(will):
- out=[]
- for wid,w in will.items():
+ out = []
+ for wid, w in will.items():
wi = w
- if wi.get_status('VALID') or wi.get_status('REPLACED'):
+ if wi.get_status("VALID") or wi.get_status("REPLACED"):
out.append(wid)
return out
- def check_willexecutors_and_heirs(will,heirs,willexecutors,self_willexecutor,check_date,tx_fees):
+ def check_willexecutors_and_heirs(
+ will, heirs, willexecutors, self_willexecutor, check_date, tx_fees
+ ):
_logger.debug("check willexecutors heirs")
no_willexecutor = 0
willexecutors_found = {}
heirs_found = {}
will_only_valid = Will.only_valid_list(will)
- if len(will_only_valid)<1:
+ if len(will_only_valid) < 1:
return False
for wid in Will.only_valid_list(will):
w = will[wid]
if w.tx_fees != tx_fees:
- raise TxFeesChangedException(f"{tx_fees}:",w.tx_fees)
+ raise TxFeesChangedException(f"{tx_fees}:", w.tx_fees)
for wheir in w.heirs:
if not 'w!ll3x3c"' == wheir[:9]:
their = will[wid].heirs[wheir]
- if heir := heirs.get(wheir,None):
-
- if heir[0] == their[0] and heir[1] == their[1] and Util.parse_locktime_string(heir[2]) >= Util.parse_locktime_string(their[2]):
- count = heirs_found.get(wheir,0)
- heirs_found[wheir]=count + 1
+ if heir := heirs.get(wheir, None):
+
+ if (
+ heir[0] == their[0]
+ and heir[1] == their[1]
+ and Util.parse_locktime_string(heir[2])
+ >= Util.parse_locktime_string(their[2])
+ ):
+ count = heirs_found.get(wheir, 0)
+ heirs_found[wheir] = count + 1
else:
- _logger.debug("heir not present transaction is not valid:",wid,w)
+ _logger.debug(
+ "heir not present transaction is not valid:", wid, w
+ )
continue
if willexecutor := w.we:
- count = willexecutors_found.get(willexecutor['url'],0)
- if Util.cmp_willexecutor(willexecutor,willexecutors.get(willexecutor['url'],None)):
- willexecutors_found[willexecutor['url']]=count+1
+ count = willexecutors_found.get(willexecutor["url"], 0)
+ if Util.cmp_willexecutor(
+ willexecutor, willexecutors.get(willexecutor["url"], None)
+ ):
+ willexecutors_found[willexecutor["url"]] = count + 1
else:
no_willexecutor += 1
count_heirs = 0
for h in heirs:
- if Util.parse_locktime_string(heirs[h][2])>=check_date:
- count_heirs +=1
+ if Util.parse_locktime_string(heirs[h][2]) >= check_date:
+ count_heirs += 1
if not h in heirs_found:
_logger.debug(f"heir: {h} not found")
raise HeirNotFoundException(h)
if not count_heirs:
raise NoHeirsException("there are not valid heirs")
- if self_willexecutor and no_willexecutor ==0:
+ if self_willexecutor and no_willexecutor == 0:
raise NoWillExecutorNotPresent("Backup tx")
- for url,we in willexecutors.items():
+ for url, we in willexecutors.items():
if Willexecutors.is_selected(we):
if not url in willexecutors_found:
_logger.debug(f"will-executor: {url} not fount")
@@ -568,101 +642,106 @@ class Will:
return True
-class WillItem(Logger):
+class WillItem(Logger):
STATUS_DEFAULT = {
- 'ANTICIPATED': ['Anticipated', False],
- 'BROADCASTED': ['Broadcasted', False],
- 'CHECKED': ['Checked', False],
- 'CHECK_FAIL': ['Check Failed',False],
- 'COMPLETE': ['Signed', False],
- 'CONFIRMED': ['Confirmed', False],
- 'ERROR': ['Error', False],
- 'EXPIRED': ['Expired', False],
- 'EXPORTED': ['Exported', False],
- 'IMPORTED': ['Imported', False],
- 'INVALIDATED': ['Invalidated', False],
- 'PENDING': ['Pending', False],
- 'PUSH_FAIL': ['Push failed', False],
- 'PUSHED': ['Pushed', False],
- 'REPLACED': ['Replaced', False],
- 'RESTORED': ['Restored', False],
- 'VALID': ['Valid', True],
+ "ANTICIPATED": ["Anticipated", False],
+ "BROADCASTED": ["Broadcasted", False],
+ "CHECKED": ["Checked", False],
+ "CHECK_FAIL": ["Check Failed", False],
+ "COMPLETE": ["Signed", False],
+ "CONFIRMED": ["Confirmed", False],
+ "ERROR": ["Error", False],
+ "EXPIRED": ["Expired", False],
+ "EXPORTED": ["Exported", False],
+ "IMPORTED": ["Imported", False],
+ "INVALIDATED": ["Invalidated", False],
+ "PENDING": ["Pending", False],
+ "PUSH_FAIL": ["Push failed", False],
+ "PUSHED": ["Pushed", False],
+ "REPLACED": ["Replaced", False],
+ "RESTORED": ["Restored", False],
+ "VALID": ["Valid", True],
}
- def set_status(self,status,value=True):
- _logger.debug("set status {} - {} {} -> {}".format(self._id,status,self.STATUS[status][1],value))
+
+ def set_status(self, status, value=True):
+ _logger.debug(
+ "set status {} - {} {} -> {}".format(
+ self._id, status, self.STATUS[status][1], value
+ )
+ )
if self.STATUS[status][1] == bool(value):
return None
- self.status += "." +("NOT " if not value else "" + _(self.STATUS[status][0]))
+ self.status += "." + ("NOT " if not value else "" + _(self.STATUS[status][0]))
self.STATUS[status][1] = bool(value)
if value:
- if status in ['INVALIDATED','REPLACED','CONFIRMED','PENDING']:
- self.STATUS['VALID'][1] = False
+ if status in ["INVALIDATED", "REPLACED", "CONFIRMED", "PENDING"]:
+ self.STATUS["VALID"][1] = False
- if status in ['CONFIRMED','PENDING']:
- self.STATUS['INVALIDATED'][1] = False
+ if status in ["CONFIRMED", "PENDING"]:
+ self.STATUS["INVALIDATED"][1] = False
- if status in ['PUSHED']:
- self.STATUS['PUSH_FAIL'][1] = False
- self.STATUS['CHECK_FAIL'][1] = False
+ if status in ["PUSHED"]:
+ self.STATUS["PUSH_FAIL"][1] = False
+ self.STATUS["CHECK_FAIL"][1] = False
-
- if status in ['CHECKED']:
- self.STATUS['PUSHED'][1] = True
- self.STATUS['PUSH_FAIL'][1] = False
+ if status in ["CHECKED"]:
+ self.STATUS["PUSHED"][1] = True
+ self.STATUS["PUSH_FAIL"][1] = False
return value
- def get_status(self,status):
+ def get_status(self, status):
return self.STATUS[status][1]
- def __init__(self,w,_id=None,wallet=None):
- if isinstance(w,WillItem,):
+ def __init__(self, w, _id=None, wallet=None):
+ if isinstance(
+ w,
+ WillItem,
+ ):
self.__dict__ = w.__dict__.copy()
else:
- self.tx = Will.get_tx_from_any(w['tx'])
- self.heirs = w.get('heirs',None)
- self.we = w.get('willexecutor',None)
- self.status = w.get('status',None)
- self.description = w.get('description',None)
- self.time = w.get('time',None)
- self.change = w.get('change',None)
- self.tx_fees = w.get('baltx_fees',0)
- self.father = w.get('Father',None)
- self.children = w.get('Children',None)
+ self.tx = Will.get_tx_from_any(w["tx"])
+ self.heirs = w.get("heirs", None)
+ self.we = w.get("willexecutor", None)
+ self.status = w.get("status", None)
+ self.description = w.get("description", None)
+ self.time = w.get("time", None)
+ self.change = w.get("change", None)
+ self.tx_fees = w.get("baltx_fees", 0)
+ self.father = w.get("Father", None)
+ self.children = w.get("Children", None)
self.STATUS = copy.deepcopy(WillItem.STATUS_DEFAULT)
for s in self.STATUS:
- self.STATUS[s][1]=w.get(s,WillItem.STATUS_DEFAULT[s][1])
+ self.STATUS[s][1] = w.get(s, WillItem.STATUS_DEFAULT[s][1])
if not _id:
self._id = self.tx.txid()
else:
self._id = _id
if not self._id:
- self.status+="ERROR!!!"
+ self.status += "ERROR!!!"
self.valid = False
if wallet:
self.tx.add_info_from_wallet(wallet)
-
-
def to_dict(self):
out = {
- '_id':self._id,
- 'tx':self.tx,
- 'heirs':self.heirs,
- 'willexecutor':self.we,
- 'status':self.status,
- 'description':self.description,
- 'time':self.time,
- 'change':self.change,
- 'baltx_fees':self.tx_fees
+ "_id": self._id,
+ "tx": self.tx,
+ "heirs": self.heirs,
+ "willexecutor": self.we,
+ "status": self.status,
+ "description": self.description,
+ "time": self.time,
+ "change": self.change,
+ "baltx_fees": self.tx_fees,
}
for key in self.STATUS:
try:
- out[key]=self.STATUS[key][1]
+ out[key] = self.STATUS[key][1]
except Exception as e:
_logger.error(f"{key},{self.STATUS[key]} {e}")
@@ -674,58 +753,58 @@ class WillItem(Logger):
def __str__(self):
return str(self.to_dict())
- def set_anticipate(self, ow:'WillItem'):
- nl = min(ow.tx.locktime,Will.check_anticipate(ow,self))
+ def set_anticipate(self, ow: "WillItem"):
+ nl = min(ow.tx.locktime, Will.check_anticipate(ow, self))
if int(nl) < self.tx.locktime:
self.tx.locktime = int(nl)
return True
else:
return False
-
- def search_anticipate(self,all_inputs):
+ def search_anticipate(self, all_inputs):
anticipated = False
for ow in self.search(all_inputs):
if self.set_anticipate(ow):
anticipated = True
return anticipated
- def search(self,all_inputs):
+ def search(self, all_inputs):
for inp in self.tx.inputs():
prevout_str = inp.prevout.to_str()
- oinps = all_inputs.get(prevout_str,[])
+ oinps = all_inputs.get(prevout_str, [])
for oinp in oinps:
- ow=oinp[1]
- if ow._id!=self._id:
+ ow = oinp[1]
+ if ow._id != self._id:
yield ow
- def normalize_locktime(self,all_inputs):
+ def normalize_locktime(self, all_inputs):
outputs = self.tx.outputs()
- for idx in range(0,len(outputs)):
- inps = all_inputs.get(f"{self._id}:{idx}",[])
+ for idx in range(0, len(outputs)):
+ inps = all_inputs.get(f"{self._id}:{idx}", [])
_logger.debug("****check locktime***")
for inp in inps:
- if inp[0]!= self._id:
+ if inp[0] != self._id:
iw = inp[1]
self.set_anticipate(iw)
def check_willexecutor(self):
try:
- if resp:=Willexecutors.check_transaction(self._id,self.we['url']):
- if 'tx' in resp and resp['tx']==str(self.tx):
- self.set_status('PUSHED')
- self.set_status('CHECKED')
- else:
- self.set_status('CHECK_FAIL')
- self.set_status('PUSHED',False)
+ if resp := Willexecutors.check_transaction(self._id, self.we["url"]):
+ if "tx" in resp and resp["tx"] == str(self.tx):
+ self.set_status("PUSHED")
+ self.set_status("CHECKED")
+ else:
+ self.set_status("CHECK_FAIL")
+ self.set_status("PUSHED", False)
return True
else:
- self.set_status('CHECK_FAIL')
- self.set_status('PUSHED',False)
+ self.set_status("CHECK_FAIL")
+ self.set_status("PUSHED", False)
return False
except Exception as e:
_logger.error(f"exception checking transaction: {e}")
- self.set_status('CHECK_FAIL')
+ self.set_status("CHECK_FAIL")
+
def get_color(self):
if self.get_status("INVALIDATED"):
return "#f87838"
@@ -748,29 +827,54 @@ class WillItem(Logger):
else:
return "#ffffff"
+
class WillException(Exception):
pass
+
+
class WillExpiredException(WillException):
pass
+
+
class NotCompleteWillException(WillException):
pass
+
+
class HeirChangeException(NotCompleteWillException):
pass
+
+
class TxFeesChangedException(NotCompleteWillException):
pass
+
+
class HeirNotFoundException(NotCompleteWillException):
pass
+
+
class WillexecutorChangeException(NotCompleteWillException):
pass
+
+
class NoWillExecutorNotPresent(NotCompleteWillException):
pass
+
+
class WillExecutorNotPresent(NotCompleteWillException):
pass
+
+
class NoHeirsException(WillException):
pass
+
+
class AmountException(WillException):
pass
+
+
class PercAmountException(AmountException):
pass
+
+
class FixedAmountException(AmountException):
pass
diff --git a/willexecutors.py b/willexecutors.py
index 899b483..a86e6f9 100644
--- a/willexecutors.py
+++ b/willexecutors.py
@@ -1,45 +1,50 @@
import json
from datetime import datetime
from functools import partial
-from aiohttp import ClientResponse
-from electrum.network import Network
+from aiohttp import ClientResponse
from electrum import constants
-from electrum.logging import get_logger
from electrum.gui.qt.util import WaitingDialog
from electrum.i18n import _
+from electrum.logging import get_logger
+from electrum.network import Network
+
from .bal import BalPlugin
from .util import Util
DEFAULT_TIMEOUT = 5
_logger = get_logger(__name__)
+
+
class Willexecutors:
def save(bal_plugin, willexecutors):
- aw=bal_plugin.WILLEXECUTORS.get()
- aw[constants.net.NET_NAME]=willexecutors
+ aw = bal_plugin.WILLEXECUTORS.get()
+ aw[constants.net.NET_NAME] = willexecutors
bal_plugin.WILLEXECUTORS.set(aw)
- def get_willexecutors(bal_plugin, update = False,bal_window=False,force=False,task=True):
+ def get_willexecutors(
+ bal_plugin, update=False, bal_window=False, force=False, task=True
+ ):
willexecutors = bal_plugin.WILLEXECUTORS.get()
- willexecutors=willexecutors.get(constants.net.NET_NAME,{})
- to_del=[]
+ willexecutors = willexecutors.get(constants.net.NET_NAME, {})
+ to_del = []
for w in willexecutors:
- if not isinstance(willexecutors[w],dict):
+ if not isinstance(willexecutors[w], dict):
to_del.append(w)
continue
- Willexecutors.initialize_willexecutor(willexecutors[w],w)
+ Willexecutors.initialize_willexecutor(willexecutors[w], w)
for w in to_del:
print("ERROR: WILLEXECUTOR TO DELETE:", w)
del willexecutors[w]
- bal = bal_plugin.WILLEXECUTORS.default.get(constants.net.NET_NAME,{})
- for bal_url,bal_executor in bal.items():
+ bal = bal_plugin.WILLEXECUTORS.default.get(constants.net.NET_NAME, {})
+ for bal_url, bal_executor in bal.items():
if not bal_url in willexecutors:
_logger.debug(f"force add {bal_url} willexecutor")
willexecutors[bal_url] = bal_executor
if update:
found = False
- for url,we in willexecutors.items():
+ for url, we in willexecutors.items():
if Willexecutors.is_selected(we):
found = True
if found or force:
@@ -47,110 +52,134 @@ class Willexecutors:
ping_willexecutors = True
if bal_plugin.ASK_PING_WILLEXECUTORS.get() and not force:
if bal_window:
- ping_willexecutors = bal_window.window.question(_("Contact willexecutors servers to update payment informations?"))
+ ping_willexecutors = bal_window.window.question(
+ _(
+ "Contact willexecutors servers to update payment informations?"
+ )
+ )
if ping_willexecutors:
if task:
- bal_window.ping_willexecutors(willexecutors,task)
+ bal_window.ping_willexecutors(willexecutors, task)
else:
bal_window.ping_willexecutors_task(willexecutors)
- w_sorted = dict(sorted(willexecutors.items(), key=lambda w:w[1].get('sort',0),reverse=True))
+ w_sorted = dict(
+ sorted(
+ willexecutors.items(), key=lambda w: w[1].get("sort", 0), reverse=True
+ )
+ )
return w_sorted
- def is_selected(willexecutor,value=None):
+
+ def is_selected(willexecutor, value=None):
if not willexecutor:
return False
if not value is None:
- willexecutor['selected']=value
+ willexecutor["selected"] = value
try:
- return willexecutor['selected']
+ return willexecutor["selected"]
except:
- willexecutor['selected']=False
+ willexecutor["selected"] = False
return False
def get_willexecutor_transactions(will, force=False):
- willexecutors ={}
- for wid,willitem in will.items():
- if willitem.get_status('VALID'):
- if willitem.get_status('COMPLETE'):
- if not willitem.get_status('PUSHED') or force:
+ willexecutors = {}
+ for wid, willitem in will.items():
+ if willitem.get_status("VALID"):
+ if willitem.get_status("COMPLETE"):
+ if not willitem.get_status("PUSHED") or force:
if willexecutor := willitem.we:
- url=willexecutor['url']
- if willexecutor and Willexecutors.is_selected(willexecutor):
+ url = willexecutor["url"]
+ if willexecutor and Willexecutors.is_selected(willexecutor):
if not url in willexecutors:
- willexecutor['txs']=""
- willexecutor['txsids']=[]
- willexecutor['broadcast_status']= _("Waiting...")
- willexecutors[url]=willexecutor
- willexecutors[url]['txs']+=str(willitem.tx)+"\n"
- willexecutors[url]['txsids'].append(wid)
+ willexecutor["txs"] = ""
+ willexecutor["txsids"] = []
+ willexecutor["broadcast_status"] = _("Waiting...")
+ willexecutors[url] = willexecutor
+ willexecutors[url]["txs"] += str(willitem.tx) + "\n"
+ willexecutors[url]["txsids"].append(wid)
return willexecutors
def only_selected_list(willexecutors):
out = {}
- for url,v in willexecutors.items():
+ for url, v in willexecutors.items():
if Willexecutors.is_selected(willexecutor):
- out[url]=v
+ out[url] = v
+
def push_transactions_to_willexecutors(will):
willexecutors = get_transactions_to_be_pushed()
for url in willexecutors:
willexecutor = willexecutors[url]
if Willexecutors.is_selected(willexecutor):
- if 'txs' in willexecutor:
- Willexecutors.push_transactions_to_willexecutor(willexecutors[url]['txs'],url)
+ if "txs" in willexecutor:
+ Willexecutors.push_transactions_to_willexecutor(
+ willexecutors[url]["txs"], url
+ )
def send_request(method, url, data=None, *, timeout=10):
network = Network.get_instance()
if not network:
- raise ErrorConnectingServer('You are offline.')
- _logger.debug(f'<-- {method} {url} {data}')
+ raise ErrorConnectingServer("You are offline.")
+ _logger.debug(f"<-- {method} {url} {data}")
headers = {}
- headers['user-agent'] = f"BalPlugin v:{BalPlugin.version()}"
- headers['Content-Type']='text/plain'
+ headers["user-agent"] = f"BalPlugin v:{BalPlugin.version()}"
+ headers["Content-Type"] = "text/plain"
try:
- if method == 'get':
- response = Network.send_http_on_proxy(method, url,
- params=data,
- headers=headers,
- on_finish=Willexecutors.handle_response,
- timeout=timeout)
- elif method == 'post':
- response = Network.send_http_on_proxy(method, url,
- body=data,
- headers=headers,
- on_finish=Willexecutors.handle_response,
- timeout=timeout)
+ if method == "get":
+ response = Network.send_http_on_proxy(
+ method,
+ url,
+ params=data,
+ headers=headers,
+ on_finish=Willexecutors.handle_response,
+ timeout=timeout,
+ )
+ elif method == "post":
+ response = Network.send_http_on_proxy(
+ method,
+ url,
+ body=data,
+ headers=headers,
+ on_finish=Willexecutors.handle_response,
+ timeout=timeout,
+ )
else:
raise Exception(f"unexpected {method=!r}")
except Exception as e:
_logger.error(f"exception sending request {e}")
raise e
else:
- _logger.debug(f'--> {response}')
+ _logger.debug(f"--> {response}")
return response
- async def handle_response(resp:ClientResponse):
- r=await resp.text()
+
+ async def handle_response(resp: ClientResponse):
+ r = await resp.text()
try:
- r=json.loads(r)
- r['status'] = resp.status
- r['selected']=Willexecutors.is_selected(willexecutor)
- r['url']=url
+ r = json.loads(r)
+ r["status"] = resp.status
+ r["selected"] = Willexecutors.is_selected(willexecutor)
+ r["url"] = url
except:
- pass
+ pass
return r
class AlreadyPresentException(Exception):
pass
+
def push_transactions_to_willexecutor(willexecutor):
- out=True
+ out = True
try:
_logger.debug(f"willexecutor['txs']")
- if w:=Willexecutors.send_request('post', willexecutor['url']+"/"+constants.net.NET_NAME+"/pushtxs", data=willexecutor['txs'].encode('ascii')):
- willexecutor['broadcast_status'] = _("Success")
+ if w := Willexecutors.send_request(
+ "post",
+ willexecutor["url"] + "/" + constants.net.NET_NAME + "/pushtxs",
+ data=willexecutor["txs"].encode("ascii"),
+ ):
+ willexecutor["broadcast_status"] = _("Success")
_logger.debug(f"pushed: {w}")
- if w !='thx':
+ if w != "thx":
_logger.debug(f"error: {w}")
raise Exception(w)
else:
@@ -159,98 +188,95 @@ class Willexecutors:
_logger.debug(f"error:{e}")
if str(e) == "already present":
raise Willexecutors.AlreadyPresentException()
- out=False
- willexecutor['broadcast_status'] = _("Failed")
+ out = False
+ willexecutor["broadcast_status"] = _("Failed")
return out
def ping_servers(willexecutors):
- for url,we in willexecutors.items():
- Willexecutors.get_info_task(url,we)
+ for url, we in willexecutors.items():
+ Willexecutors.get_info_task(url, we)
-
- def get_info_task(url,willexecutor):
- w=None
+ def get_info_task(url, willexecutor):
+ w = None
try:
_logger.info("GETINFO_WILLEXECUTOR")
_logger.debug(url)
- netname="bitcoin"
- if constants.net.NET_NAME!="mainnet":
- netname=constants.net.NET_NAME
- w = Willexecutors.send_request('get',url+"/"+netname+"/info")
+ netname = "bitcoin"
+ if constants.net.NET_NAME != "mainnet":
+ netname = constants.net.NET_NAME
+ w = Willexecutors.send_request("get", url + "/" + netname + "/info")
- willexecutor['url']=url
- willexecutor['status'] = w['status']
- willexecutor['base_fee'] = w['base_fee']
- willexecutor['address'] = w['address']
- if not willexecutor['info']:
- willexecutor['info'] = w['info']
+ willexecutor["url"] = url
+ willexecutor["status"] = w["status"]
+ willexecutor["base_fee"] = w["base_fee"]
+ willexecutor["address"] = w["address"]
+ if not willexecutor["info"]:
+ willexecutor["info"] = w["info"]
_logger.debug(f"response_data {w['address']}")
except Exception as e:
_logger.error(f"error {e} contacting {url}: {w}")
- willexecutor['status']="KO"
+ willexecutor["status"] = "KO"
- willexecutor['last_update'] = datetime.now().timestamp()
+ willexecutor["last_update"] = datetime.now().timestamp()
return willexecutor
- def initialize_willexecutor(willexecutor,url,status=None,selected=None):
- willexecutor['url']=url
+ def initialize_willexecutor(willexecutor, url, status=None, selected=None):
+ willexecutor["url"] = url
if not status is None:
- willexecutor['status'] = status
- willexecutor['selected'] = Willexecutors.is_selected(willexecutor,selected)
+ willexecutor["status"] = status
+ willexecutor["selected"] = Willexecutors.is_selected(willexecutor, selected)
def download_list(bal_plugin):
try:
- l = Willexecutors.send_request('get',"https://welist.bitcoin-after.life/data/bitcoin?page=0&limit=100")
- del l['status']
+ l = Willexecutors.send_request(
+ "get", "https://welist.bitcoin-after.life/data/bitcoin?page=0&limit=100"
+ )
+ del l["status"]
for w in l:
- willexecutor=l[w]
- Willexecutors.initialize_willexecutor(willexecutor,w,'New',False)
- #bal_plugin.WILLEXECUTORS.set(l)
- #bal_plugin.config.set_key(bal_plugin.WILLEXECUTORS,l,save=True)
+ willexecutor = l[w]
+ Willexecutors.initialize_willexecutor(willexecutor, w, "New", False)
+ # bal_plugin.WILLEXECUTORS.set(l)
+ # bal_plugin.config.set_key(bal_plugin.WILLEXECUTORS,l,save=True)
return l
except Exception as e:
_logger.error(f"Failed to download willexecutors list: {e}")
return {}
+
def get_willexecutors_list_from_json(bal_plugin):
try:
with open("willexecutors.json") as f:
willexecutors = json.load(f)
for w in willexecutors:
- willexecutor=willexecutors[w]
- Willexecutors.initialize_willexecutor(willexecutor,w,'New',False)
- #bal_plugin.WILLEXECUTORS.set(willexecutors)
+ willexecutor = willexecutors[w]
+ Willexecutors.initialize_willexecutor(willexecutor, w, "New", False)
+ # bal_plugin.WILLEXECUTORS.set(willexecutors)
return h
except Exception as e:
_logger.error(f"error opening willexecutors json: {e}")
return {}
- def check_transaction(txid,url):
+ def check_transaction(txid, url):
_logger.debug(f"{url}:{txid}")
try:
- w = Willexecutors.send_request('post',url+"/searchtx",data=txid.encode('ascii'))
+ w = Willexecutors.send_request(
+ "post", url + "/searchtx", data=txid.encode("ascii")
+ )
return w
except Exception as e:
_logger.error(f"error contacting {url} for checking txs {e}")
raise e
+
class WillExecutor:
- def __init__(self,url,base_fee,chain,info,version):
- self.url = url
- self.base_fee = base_fee
- self.chain = chain
- self.info = info
- self.version = version
+ def __init__(self, url, base_fee, chain, info, version):
+ self.url = url
+ self.base_fee = base_fee
+ self.chain = chain
+ self.info = info
+ self.version = version
def from_dict(d):
- we = WillExecutor(
- d['url'],
- d['base_fee'],
- d['chain'],
- d['info'],
- d['version']
- )
-
-
+ we = WillExecutor(d["url"], d["base_fee"], d["chain"], d["info"], d["version"])