diff --git a/bal.py b/bal.py index d18a4df..06ce197 100644 --- a/bal.py +++ b/bal.py @@ -1,6 +1,7 @@ import os -#import random -#import zipfile as zipfile_lib + +# import random +# import zipfile as zipfile_lib from electrum import json_db from electrum.logging import get_logger @@ -9,7 +10,7 @@ from electrum.transaction import tx_from_any def get_will_settings(x): - #print(x) + # print(x) pass @@ -18,7 +19,6 @@ 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"]) @@ -90,10 +90,10 @@ class BalPlugin(BasePlugin): 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( + # 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) @@ -149,4 +149,3 @@ class BalPlugin(BasePlugin): def default_will_settings(self): return {"baltx_fees": 100, "threshold": "180d", "locktime": "1y"} - diff --git a/heirs.py b/heirs.py index e2a8da6..6e93e57 100644 --- a/heirs.py +++ b/heirs.py @@ -31,6 +31,7 @@ from .util import Util from .willexecutors import Willexecutors from electrum.util import BitcoinException from electrum import constants + if TYPE_CHECKING: from .simple_config import SimpleConfig from .wallet_db import WalletDB @@ -104,7 +105,9 @@ def prepare_transactions(locktimes, available_utxos, fees, wallet): outputs = [] paid_heirs = {} for name, heir in heirs.items(): - if len(heir) > HEIR_REAL_AMOUNT and not "DUST" in str(heir[HEIR_REAL_AMOUNT]): + if len(heir) > HEIR_REAL_AMOUNT and not "DUST" in str( + heir[HEIR_REAL_AMOUNT] + ): try: real_amount = heir[HEIR_REAL_AMOUNT] outputs.append( @@ -115,11 +118,11 @@ def prepare_transactions(locktimes, available_utxos, fees, wallet): out_amount += real_amount description += f"{name}\n" except BitcoinException as e: - _logger.info("exception decoding output{} - {}".format(type(e),e)) - heir[HEIR_REAL_AMOUNT]=e - + _logger.info("exception decoding output{} - {}".format(type(e), e)) + heir[HEIR_REAL_AMOUNT] = e + except Exception as e: - heir[HEIR_REAL_AMOUNT]=e + heir[HEIR_REAL_AMOUNT] = e _logger.info(f"error preparing transactions {e}") pass paid_heirs[name] = heir @@ -135,10 +138,14 @@ def prepare_transactions(locktimes, available_utxos, fees, wallet): break except IndexError as e: - _logger.info(f"error preparing transactions index error {e} {in_amount}, {out_amount}") + _logger.info( + f"error preparing transactions index error {e} {in_amount}, {out_amount}" + ) pass if int(in_amount) < int(out_amount): - _logger.info("error preparing transactions in_amount < out_amount ({} < {}) ") + _logger.info( + "error preparing transactions in_amount < out_amount ({} < {}) " + ) break heirsvalue = out_amount change = get_change_output(wallet, in_amount, out_amount, fee) @@ -274,7 +281,7 @@ class Heirs(dict, Logger): def __init__(self, wallet): Logger.__init__(self) self.db = wallet.db - self.wallet=wallet + self.wallet = wallet d = self.db.get("heirs", {}) try: self.update(d) @@ -337,8 +344,8 @@ class Heirs(dict, Logger): heir_list[key].insert(HEIR_REAL_AMOUNT, value) amount += value else: - heir_list[key].insert(HEIR_REAL_AMOUNT,f"DUST: {value}") - heir_list[key].insert(HEIR_DUST_AMOUNT,value) + heir_list[key].insert(HEIR_REAL_AMOUNT, f"DUST: {value}") + heir_list[key].insert(HEIR_DUST_AMOUNT, value) _logger.info(f"{key}, {value} is dust will be ignored") except Exception as e: @@ -648,7 +655,7 @@ class Heirs(dict, Logger): return None def validate_address(address): - if not bitcoin.is_address(address,net=constants.net): + if not bitcoin.is_address(address, net=constants.net): raise NotAnAddress(f"not an address,{address}") return address @@ -677,10 +684,10 @@ class Heirs(dict, Logger): return (address, amount, locktime) def _validate(data, timestamp_to_check=False): - + for k, v in list(data.items()): if k == "heirs": - return Heirs._validate(v,timestamp_to_check) + return Heirs._validate(v, timestamp_to_check) try: Heirs.validate_heir(k, v, timestamp_to_check) except Exception as e: @@ -704,5 +711,6 @@ class LocktimeNotValid(ValueError): class HeirExpiredException(LocktimeNotValid): pass + class HeirAmountIsDustException(Exception): pass diff --git a/qt.py b/qt.py index acfeb03..12a1f03 100644 --- a/qt.py +++ b/qt.py @@ -145,7 +145,7 @@ from electrum.util import ( from .bal import BalPlugin from .bal_resources import DEFAULT_ICON, icon_path -from .heirs import (Heirs,HEIR_REAL_AMOUNT,HEIR_DUST_AMOUNT) +from .heirs import Heirs, HEIR_REAL_AMOUNT, HEIR_DUST_AMOUNT from .util import Util from .will import ( AmountException, @@ -295,8 +295,8 @@ class Plugin(BalPlugin, Logger): lbl_logo = QLabel() lbl_logo.setPixmap(qicon) - #heir_ping_willexecutors = bal_checkbox(self.PING_WILLEXECUTORS) - #heir_ask_ping_willexecutors = bal_checkbox(self.ASK_PING_WILLEXECUTORS) + # heir_ping_willexecutors = bal_checkbox(self.PING_WILLEXECUTORS) + # heir_ask_ping_willexecutors = bal_checkbox(self.ASK_PING_WILLEXECUTORS) heir_no_willexecutor = bal_checkbox(self.NO_WILLEXECUTOR) def on_multiverse_change(): @@ -327,27 +327,27 @@ class Plugin(BalPlugin, Logger): 2, "Hide invalidated transactions from will detail and list", ) - #add_widget( + # add_widget( # grid, # "Ping Willexecutors", # heir_ping_willexecutors, # 3, # "Ping willexecutors to get payment info before compiling will", - #) - #add_widget( + # ) + # add_widget( # grid, # " - Ask before", # heir_ask_ping_willexecutors, # 4, # "Ask before to ping willexecutor", - #) - #add_widget( + # ) + # 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( @@ -522,7 +522,6 @@ class BalWindow(Logger): tab.is_shown_cv = shown_cv(True) return tab - def new_heir_dialog(self, heir_key=None): heir = self.heirs.get(heir_key) title = "New heir" @@ -671,9 +670,7 @@ class BalWindow(Logger): if Willexecutors.is_selected(w): f = True if not f: - _logger.error( - "No Will-Executor or backup transaction selected" - ) + _logger.error("No Will-Executor or backup transaction selected") raise NoWillExecutorNotPresent( "No Will-Executor or backup transaction selected" ) @@ -1188,7 +1185,7 @@ class BalWindow(Logger): parent = self def on_success(result): - #del self.waiting_dialog + # del self.waiting_dialog try: parent.willexecutor_list.update() except Exception as e: @@ -1768,7 +1765,9 @@ class BalWizardWEDownloadWidget(BalWizardWidget): def on_success(willexecutors): self.bal_window.willexecutors.update(willexecutors) - self.bal_window.ping_willexecutors(self.bal_window.willexecutors,False) + self.bal_window.ping_willexecutors( + self.bal_window.willexecutors, False + ) if index < 1: for we in self.bal_window.willexecutors: if self.bal_window.willexecutors[we]["status"] == 200: @@ -1839,7 +1838,6 @@ class BalWizardLocktimeAndFeeWidget(BalWizardWidget): 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) @@ -1857,7 +1855,6 @@ class BalWizardLocktimeAndFeeWidget(BalWizardWidget): ) 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) @@ -2040,7 +2037,7 @@ class BalBuildWillDialog(BalDialog): if not parent: parent = bal_window.window BalDialog.__init__(self, parent, bal_window.bal_plugin, "Building Will") - self.parent=parent + self.parent = parent self.updatemessage.connect(self.update) self.bal_window = bal_window self.message_label = QLabel("Building Will:") @@ -2091,7 +2088,7 @@ class BalBuildWillDialog(BalDialog): self.bal_window.window.wallet.dust_threshold(), ) _logger.debug("variables ok") - self.msg_set_status("checking variables:", varrow,"Ok") + self.msg_set_status("checking variables:", varrow, "Ok") except AmountException: self.msg_set_status( "checking variables", @@ -2104,7 +2101,7 @@ class BalBuildWillDialog(BalDialog): ) + "", ) - + self.msg_set_checking() have_to_build = False try: @@ -2152,14 +2149,17 @@ class BalBuildWillDialog(BalDialog): self.msg_set_building(self.msg_error(e)) return False, None - - excluded_heirs=[] + excluded_heirs = [] for wid in Will.only_valid(self.bal_window.willitems): - heirs=self.bal_window.willitems[wid].heirs - for hid,heir in heirs.items(): + heirs = self.bal_window.willitems[wid].heirs + for hid, heir in heirs.items(): if "DUST" in str(heir[HEIR_REAL_AMOUNT]): - self.msg_set_status(f"{hid},{heir[HEIR_DUST_AMOUNT]} is DUST",None,f"Excluded from will {wid}") - + self.msg_set_status( + f'{hid},{heir[HEIR_DUST_AMOUNT]} is DUST', + None, + f"Excluded from will {wid}", + ) + have_to_sign = False for wid in Will.only_valid(self.bal_window.willitems): if not self.bal_window.willitems[wid].get_status("COMPLETE"): @@ -2260,7 +2260,7 @@ class BalBuildWillDialog(BalDialog): if not self._stopping: self.loop_push() - def invalidate_task(self,password,bal_window,tx): + def invalidate_task(self, password, bal_window, tx): _logger.debug(f"invalidate tx: {tx}") fee_per_byte = bal_window.will_settings.get("baltx_fees", 1) tx = self.bal_window.wallet.sign_transaction(tx, password) @@ -2289,6 +2289,7 @@ class BalBuildWillDialog(BalDialog): def on_error(self, error): _logger.error(error) pass + def on_success_phase1(self, result): self.have_to_sign, tx = list(result) _logger.debug("have to sign {}".format(self.have_to_sign)) @@ -2307,7 +2308,7 @@ class BalBuildWillDialog(BalDialog): self.close() return self.thread.add( - partial(self.invalidate_task,password,self.bal_window,tx), + partial(self.invalidate_task, password, self.bal_window, tx), on_success=self.on_success_invalidate, on_done=self.on_accept, on_error=self.on_error, @@ -2591,9 +2592,15 @@ class HeirList(MyTreeView, MessageBoxMixin): 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 + self.Columns.NAME) - items[self.Columns.ADDRESS].setData(key, self.ROLE_HEIR_KEY + self.Columns.ADDRESS) - items[self.Columns.AMOUNT].setData(key, self.ROLE_HEIR_KEY + self.Columns.AMOUNT) + items[self.Columns.NAME].setData( + key, self.ROLE_HEIR_KEY + self.Columns.NAME + ) + items[self.Columns.ADDRESS].setData( + key, self.ROLE_HEIR_KEY + self.Columns.ADDRESS + ) + items[self.Columns.AMOUNT].setData( + key, self.ROLE_HEIR_KEY + self.Columns.AMOUNT + ) row_count = self.model().rowCount() self.model().insertRow(row_count, items) @@ -2612,10 +2619,9 @@ class HeirList(MyTreeView, MessageBoxMixin): pass def get_edit_key_from_coordinate(self, row, col): - a= self.get_role_data_from_coordinate( - row, col, role=self.ROLE_HEIR_KEY + col - ) + a = self.get_role_data_from_coordinate(row, col, role=self.ROLE_HEIR_KEY + col) return a + def create_toolbar(self, config): toolbar, menu = self.create_toolbar_with_menu("") menu.addAction(_("&New Heir"), self.bal_window.new_heir_dialog) @@ -2623,6 +2629,7 @@ class HeirList(MyTreeView, MessageBoxMixin): menu.addAction(_("Export"), lambda: self.bal_window.export_heirs()) self.heir_locktime = HeirsLockTimeEdit(self, 0) + def on_heir_locktime(): if not self.heir_locktime.get_locktime(): self.heir_locktime.set_locktime("1y") @@ -2713,7 +2720,6 @@ class HeirList(MyTreeView, MessageBoxMixin): self.heir_threshold.set_locktime(self.bal_window.will_settings["threshold"]) self.heir_tx_fees.setValue(int(self.bal_window.will_settings["baltx_fees"])) - except Exception as e: _logger.debug(f"Exception update_will_settings {e}") @@ -2981,16 +2987,22 @@ class PreviewList(MyTreeView): def check(self): Will.add_willtree(self.bal_window.willitems) - all_utxos =self.bal_window.wallet.get_utxos() + all_utxos = self.bal_window.wallet.get_utxos() utxos_list = Will.utxos_strs(all_utxos) - Will.check_invalidated(self.bal_window.willitems,utxos_list,self.bal_window.wallet) - + Will.check_invalidated( + self.bal_window.willitems, utxos_list, self.bal_window.wallet + ) + close_window = BalBuildWillDialog(self.bal_window) close_window.build_will_task() will = {} for wid, w in self.bal_window.willitems.items(): - if w.get_status("VALID") and w.get_status("PUSHED") and not w.get_status("CHECKED"): + if ( + w.get_status("VALID") + and w.get_status("PUSHED") + and not w.get_status("CHECKED") + ): will[wid] = w if will: self.bal_window.check_transactions(will) @@ -3026,7 +3038,7 @@ class PreviewDialog(BalDialog, MessageBoxMixin): self.setMinimumSize(1000, 200) self.size_label = QLabel() self.transactions_list = PreviewList(self.bal_window, self.will) - + self.bal_window.init_class_variables() self.check_will() @@ -3308,7 +3320,7 @@ class WillExecutorList(MyTreeView): self.Columns.INFO, ], ) - self.parent=parent + self.parent = parent try: self.setModel(QStandardItemModel(self)) self.sortByColumn(self.Columns.SELECTED, Qt.SortOrder.AscendingOrder) @@ -3374,9 +3386,9 @@ class WillExecutorList(MyTreeView): self.update() def get_edit_key_from_coordinate(self, row, col): - role=self.ROLE_HEIR_KEY+col + role = self.ROLE_HEIR_KEY + col a = self.get_role_data_from_coordinate(row, col, role=role) - return a + return a def delete(self, selected_keys): for key in selected_keys: @@ -3434,16 +3446,33 @@ class WillExecutorList(MyTreeView): labels[self.Columns.URL] = url if Willexecutors.is_selected(value): - labels[self.Columns.SELECTED] = [read_QIcon_from_bytes(self.parent.bal_plugin.read_file("icons/confirmed.png")),""] + labels[self.Columns.SELECTED] = [ + read_QIcon_from_bytes( + self.parent.bal_plugin.read_file("icons/confirmed.png") + ), + "", + ] else: labels[self.Columns.SELECTED] = "" labels[self.Columns.BASE_FEE] = Util.decode_amount( value.get("base_fee", 0), self.get_decimal_point() ) if str(value.get("status", 0)) == "200": - labels[self.Columns.STATUS] = [read_QIcon_from_bytes(self.parent.bal_plugin.read_file("icons/status_connected.png")),""] + labels[self.Columns.STATUS] = [ + read_QIcon_from_bytes( + self.parent.bal_plugin.read_file( + "icons/status_connected.png" + ) + ), + "", + ] else: - labels[self.Columns.STATUS] = [read_QIcon_from_bytes(self.parent.bal_plugin.read_file("icons/unconfirmed.png")),""] + labels[self.Columns.STATUS] = [ + read_QIcon_from_bytes( + self.parent.bal_plugin.read_file("icons/unconfirmed.png") + ), + "", + ] labels[self.Columns.ADDRESS] = str(value.get("address", "")) labels[self.Columns.INFO] = str(value.get("info", "")) @@ -3463,10 +3492,18 @@ class WillExecutorList(MyTreeView): items[self.Columns.BASE_FEE].setEditable(True) items[self.Columns.STATUS].setEditable(False) - items[self.Columns.URL].setData(url, self.ROLE_HEIR_KEY + self.Columns.URL) - items[self.Columns.BASE_FEE].setData(url, self.ROLE_HEIR_KEY + self.Columns.BASE_FEE) - items[self.Columns.INFO].setData(url, self.ROLE_HEIR_KEY + self.Columns.INFO) - items[self.Columns.ADDRESS].setData(url, self.ROLE_HEIR_KEY + self.Columns.ADDRESS) + items[self.Columns.URL].setData( + url, self.ROLE_HEIR_KEY + self.Columns.URL + ) + items[self.Columns.BASE_FEE].setData( + url, self.ROLE_HEIR_KEY + self.Columns.BASE_FEE + ) + items[self.Columns.INFO].setData( + url, self.ROLE_HEIR_KEY + self.Columns.INFO + ) + items[self.Columns.ADDRESS].setData( + url, self.ROLE_HEIR_KEY + self.Columns.ADDRESS + ) row_count = self.model().rowCount() self.model().insertRow(row_count, items) if url == current_key: @@ -3534,7 +3571,7 @@ class WillExecutorWidget(QWidget, MessageBoxMixin): buttonbox.addWidget(b) vbox.addLayout(buttonbox) - #self.willexecutor_list.update() + # self.willexecutor_list.update() def add(self): self.willexecutors_list["http://localhost:8080"] = { @@ -3566,7 +3603,7 @@ class WillExecutorWidget(QWidget, MessageBoxMixin): def update_willexecutors(self, wes=None): if not wes: - wes=self.willexecutors_list + wes = self.willexecutors_list self.bal_window.ping_willexecutors(wes, self.parent) self.willexecutors_list.update(wes) self.willexecutor_list.update() diff --git a/will.py b/will.py index af52fdf..82af78f 100644 --- a/will.py +++ b/will.py @@ -161,6 +161,7 @@ class Will: """ + def check_anticipate(ow: "WillItem", nw: "WillItem"): anticipate = Util.anticipate_locktime(ow.tx.locktime, days=1) if int(nw.tx.locktime) >= int(anticipate): @@ -297,7 +298,6 @@ class Will: 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) all_inputs_min_locktime = Will.get_all_inputs_min_locktime(all_old_inputs) @@ -439,7 +439,11 @@ class Will: # 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 or willtree[w.father].get_status("CONFIRMED") or willtree[w.father].get_status("PENDING"): + if ( + not w.father + or willtree[w.father].get_status("CONFIRMED") + or willtree[w.father].get_status("PENDING") + ): for inp in w.tx.inputs(): inp_str = Util.utxo_to_str(inp) if not inp_str in utxos_list: @@ -671,11 +675,11 @@ class WillItem(Logger): } def set_status(self, status, value=True): - #_logger.trace( + # _logger.trace( # "set status {} - {} {} -> {}".format( # self._id, status, self.STATUS[status][1], value # ) - #) + # ) if self.STATUS[status][1] == bool(value): return None @@ -886,9 +890,5 @@ class FixedAmountException(AmountException): pass - - - - def test_check_invalidated(): Will.check_invalidated(will, utxos_list, wallet) diff --git a/willexecutors.py b/willexecutors.py index c785600..34110af 100644 --- a/willexecutors.py +++ b/willexecutors.py @@ -35,14 +35,16 @@ class Willexecutors: continue Willexecutors.initialize_willexecutor(willexecutors[w], w) for w in to_del: - _logger.error("error Willexecutor to delete type:{} ", type(willexecutor[w]),w) + _logger.error( + "error Willexecutor to delete type:{} ", type(willexecutor[w]), w + ) del willexecutors[w] 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: + # if update: # found = False # for url, we in willexecutors.items(): # if Willexecutors.is_selected(we):