diff --git a/heirs.py b/heirs.py index c316ff6..e8a749a 100644 --- a/heirs.py +++ b/heirs.py @@ -341,6 +341,7 @@ class Heirs(dict, Logger): def normalize_perc( self, heir_list, total_balance, relative_balance, wallet, real=False ): + print("relative balance", relative_balance) amount = 0 for key, v in heir_list.items(): try: @@ -424,6 +425,16 @@ class Heirs(dict, Logger): def prepare_lists( self, balance, total_fees, wallet, willexecutor=False, from_locktime=0 ): + if balance int(from_locktime): try: base_fee = int(willexecutor["base_fee"]) - if base_fee > dust_threshold: - 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 + 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 except Exception: return [], False else: @@ -452,6 +462,8 @@ class Heirs(dict, Logger): f"heir excluded from will locktime({locktime}){Util.int_locktime(locktime)} newbalance: + print(fixed_heirs,newbalance,fixed_amount) fixed_amount = self.normalize_perc( fixed_heirs, newbalance, fixed_amount, wallet ) @@ -472,14 +485,15 @@ class Heirs(dict, Logger): heir_list.update(fixed_heirs) newbalance -= fixed_amount - + print("new balance", newbalance) if newbalance > 0: perc_amount = self.normalize_perc( percent_heirs, newbalance, percent_amount, wallet ) + print("normalize perc", perc_amount) newbalance -= perc_amount heir_list.update(percent_heirs) - + print("newbalance2",newbalance) if newbalance > 0: newbalance += fixed_amount fixed_amount = self.normalize_perc( @@ -500,6 +514,7 @@ class Heirs(dict, Logger): locktimes[locktime] = {key: value} else: locktimes[locktime][key] = value + print(2) return locktimes, onlyfixed def is_perc(self, key): @@ -567,9 +582,11 @@ class Heirs(dict, Logger): continue if locktimes: try: + print(3) txs = prepare_transactions( locktimes, available_utxos[:], fees, wallet ) + print(4) if not txs: return {} except Exception as e: @@ -783,3 +800,10 @@ class WillExecutorFeeException(Exception): return "WillExecutorFeeException: {} fee:{}".format( self.willexecutor["url"], self.willexecutor["base_fee"] ) +class BalanceTooLowException(Exception): + def __init__(self,balance, dust_threshold, fees): + self.balance=balance + self.dust_threshold = dust_threshold + self.fees = fees + def __str__(self): + return f"Balance too low, balance: {self.balance}, dust threshold: {self.dust_threshold}, fees: {self.fees}" diff --git a/qt.py b/qt.py index b0e8cd5..1f3d0fb 100644 --- a/qt.py +++ b/qt.py @@ -15,7 +15,7 @@ from datetime import datetime from decimal import Decimal from functools import partial from typing import TYPE_CHECKING, Any, Callable, Mapping, Optional, Union - +import traceback try: QT_VERSION = sys._GUI_QT_VERSION except Exception: @@ -601,14 +601,6 @@ class BalWindow(Logger): except Exception as e: self.show_error(str(e)) - # 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(): @@ -630,9 +622,7 @@ class BalWindow(Logger): self.heir_list_widget.update() return True - def import_heirs( - self, - ): + def import_heirs(self): import_meta_gui( self.window, _("heirs"), self.heirs.import_file, self.heir_list_widget.update ) @@ -748,8 +738,7 @@ class BalWindow(Logger): def init_class_variables(self): if not self.heirs: - raise NoHeirsException() - return + raise NoHeirsException(_("Heirs are not defined")) try: self.date_to_check = Util.parse_locktime_string( self.will_settings["threshold"] @@ -757,11 +746,13 @@ class BalWindow(Logger): # 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.block_to_check=0 self.no_willexecutor = self.bal_plugin.NO_WILLEXECUTOR.get() self.willexecutors = Willexecutors.get_willexecutors( self.bal_plugin, update=True, bal_window=self, task=False ) + if self.date_to_check < datetime.now().timestamp(): + raise CheckAliveException(self.date_to_check) self.init_heirs_to_locktime(self.bal_plugin.ENABLE_MULTIVERSE.get()) except Exception as e: @@ -776,8 +767,8 @@ class BalWindow(Logger): if not self.heirs: self.logger.warning("not heirs {}".format(self.heirs)) return - self.init_class_variables() try: + self.init_class_variables() Will.check_amounts( self.heirs, self.willexecutors, @@ -791,6 +782,9 @@ class BalWindow(Logger): f"In the inheritance process, the entire wallet will always be fully emptied. Your settings require an adjustment of the amounts.\n{e}" ) ) + except CheckAliveException: + self.show_error(_("CheckAlive is in the past please update it to a date in the future but less than locktime")) + return locktime = Util.parse_locktime_string(self.will_settings["locktime"]) if locktime < self.date_to_check: self.show_error(_("locktime is lower than threshold")) @@ -1082,7 +1076,7 @@ class BalWindow(Logger): w = self.willitems[wid] w.set_check_willexecutor( Willexecutors.check_transaction( - w._id, + wid, w.we["url"] ) ) @@ -1134,7 +1128,8 @@ class BalWindow(Logger): self.waiting_dialog.update( "checking transaction: {}\n willexecutor: {}".format(wid, w.we["url"]) ) - w.set_check_willexecutor(Willexecutors.check_transaction(self.bal_plugin,w._id, w.we["url"])) + + w.set_check_willexecutor(Willexecutors.check_transaction(wid, w.we["url"])) if time.time() - start < 3: @@ -1221,10 +1216,20 @@ class BalWindow(Logger): self.dw.show() def update_all(self): - self.will_list.update_will(self.willitems) - self.heirs_tab.update() - self.will_tab.update() - self.will_list.update() + try: + Will.add_willtree(self.willitems) + all_utxos = self.wallet.get_utxos() + utxos_list = Will.utxos_strs(all_utxos) + Will.check_invalidated( + self.willitems, utxos_list, self.wallet + ) + + self.will_list.update_will(self.willitems) + self.heirs_tab.update() + self.will_tab.update() + self.will_list.update() + except Exception as e: + _logger.error(f"error while updating window: {e}") def add_widget(grid, label, widget, row, help_): @@ -1612,16 +1617,18 @@ class BalWizardDialog(BalDialog): ) def on_accept(self): + self.bal_window.update_all() pass def on_reject(self): pass def on_close(self): + self.bal_window.update_all() pass def closeEvent(self, event): - self.bal_window.update_all() + self.bal_window.heir_list_widget.update_will_settings() pass @@ -2087,13 +2094,26 @@ class BalBuildWillDialog(BalDialog): self.exec() def task_phase1(self): + txs=None _logger.debug("close plugin phase 1 started") + varrow = self.msg_set_status("checking variables") try: self.bal_window.init_class_variables() - except NoHeirsException: - _logger.error("no heirs exception") - return False, None - varrow = self.msg_set_status("checking variables") + except CheckAliveException as cae: + fee_per_byte = self.bal_window.will_settings.get("baltx_fees", 1) + tx = Will.invalidate_will( + self.bal_window.willitems, self.bal_window.wallet, fee_per_byte + ) + if tx: + _logger.debug("during phase1 CAE: {}, Continue to invalidate".format(cae)) + self.msg_set_checking(self.msg_warning("Check Alive Threshold Passed: you have to Invalidate your old Will")) + else: + raise cae + return None, tx + + + except Exception as e: + raise e try: _logger.debug("checking variables") Will.check_amounts( @@ -2129,9 +2149,10 @@ class BalBuildWillDialog(BalDialog): return None, Will.invalidate_will( self.bal_window.willitems, self.bal_window.wallet, fee_per_byte ) - except NoHeirsException: + except NoHeirsException as e: _logger.debug("no heirs") self.msg_set_checking("No Heirs") + raise e except NotCompleteWillException as e: _logger.debug(f"not complete {e} true") message = False @@ -2155,13 +2176,15 @@ class BalBuildWillDialog(BalDialog): if have_to_build: self.msg_set_building() try: - if not self.bal_window.build_will(): + txs = self.bal_window.build_will() + if not txs: self.msg_set_status( _("Balance is too low. No transaction was built"), None, _("Skipped"), self.COLOR_ERROR, ) + return False,None self.bal_window.check_will() for wid in Will.only_valid(self.bal_window.willitems): @@ -2193,12 +2216,14 @@ class BalBuildWillDialog(BalDialog): if not self.bal_window.willitems[wid].get_status("COMPLETE"): have_to_sign = True break - return have_to_sign, None + return have_to_sign, txs def on_accept(self): + self.bal_window.update_all() pass def on_accept_phase2(self): + self.bal_window.update_all() pass def on_error_push(self): @@ -2236,6 +2261,7 @@ class BalBuildWillDialog(BalDialog): self.msg_set_pushing(_("Broadcasting")) retry = False try: + willexecutors = Willexecutors.get_willexecutor_transactions( self.bal_window.willitems ) @@ -2265,9 +2291,10 @@ class BalBuildWillDialog(BalDialog): self.bal_window.willitems[wid].we["url"], wid, "Waiting" ) ) - self.bal_plugin = bal_window.bal_plugin + self.bal_plugin = self.bal_window.bal_plugin w = self.bal_window.willitems[wid] - w.set_check_willexecutor(Willexecutors.check_transaction(w._id, w.we["url"])) + + w.set_check_willexecutor(Willexecutors.check_transaction(wid, w.we["url"])) row = self.msg_edit_row( "checked {} - {} : {}".format( self.bal_window.willitems[wid].we["url"], @@ -2278,7 +2305,6 @@ class BalBuildWillDialog(BalDialog): ) except Exception as e: - _logger.error(f"loop push error:{e}") raise e if retry: @@ -2316,12 +2342,11 @@ class BalBuildWillDialog(BalDialog): 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 not tx: + self.msg_edit_row(self.msg_error("Error, no tx was built")) + return _logger.debug("have to sign {}".format(self.have_to_sign)) password = None if self.have_to_sign is None: @@ -2369,7 +2394,6 @@ class BalBuildWillDialog(BalDialog): self.close() def closeEvent(self, event): - self.bal_window.update_all() self._stopping = True self.thread.stop() @@ -2398,12 +2422,20 @@ class BalBuildWillDialog(BalDialog): self.msg_set_pushing(self.msg_ok()) except Exception as e: + td = traceback.format_exc() self.msg_set_pushing(self.msg_error(e)) self.msg_edit_row(self.msg_ok()) self.wait(5) + def on_error(self, error): + _logger.error(error) + pass + def on_error_phase1(self, error): - _logger.error(f"error phase1: {error}") + self.bal_window.update_all() + a,b,c = error + self.msg_edit_row(self.msg_error(f"Error: {b}")) + _logger.error(f"error phase1: {b}") def on_error_phase2(self, error): _logger.error(f"error phase2: { error}") @@ -2978,16 +3010,16 @@ class PreviewList(MyTreeView): wizard = QPushButton(_("Setup Wizard")) wizard.clicked.connect(self.bal_window.init_wizard) - display = QPushButton(_("Display")) - display.clicked.connect(self.bal_window.preview_modal_dialog) + #display = QPushButton(_("Display")) + #display.clicked.connect(self.bal_window.preview_modal_dialog) - display = QPushButton(_("Refresh")) - display.clicked.connect(self.check) + refresh = QPushButton(_("Refresh")) + refresh.clicked.connect(self.check) widget = QWidget() hlayout = QHBoxLayout(widget) hlayout.addWidget(wizard) - hlayout.addWidget(display) + hlayout.addWidget(refresh) toolbar.insertWidget(2, widget) self.menu = menu @@ -3025,13 +3057,6 @@ class PreviewList(MyTreeView): self.update() def check(self): - Will.add_willtree(self.bal_window.willitems) - 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 - ) - close_window = BalBuildWillDialog(self.bal_window) close_window.build_will_task() @@ -3078,7 +3103,10 @@ class PreviewDialog(BalDialog, MessageBoxMixin): self.size_label = QLabel() self.transactions_list = PreviewList(self.bal_window, self.will) - self.bal_window.init_class_variables() + try: + self.bal_window.init_class_variables() + except Exception as e: + _logger.error(f"PreviewDialog Exception: {e}") self.check_will() vbox = QVBoxLayout(self) @@ -3695,3 +3723,10 @@ class WillExecutorDialog(BalDialog, MessageBoxMixin): def closeEvent(self, event): event.accept() + + +class CheckAliveException(Exception): + def __init__(self,timestamp_to_check): + self.timestamp_to_check = timestamp_to_check + def __str__(self): + return "Check alive expired please update it: {}".format(datetime.fromtimestamp(self.timestamp_to_check).isoformat()) diff --git a/will.py b/will.py index 4d255de..160e11d 100644 --- a/will.py +++ b/will.py @@ -339,6 +339,7 @@ class Will: utxos = wallet.get_utxos() filtered_inputs = [] prevout_to_spend = [] + current_height = Util.get_current_height(wallet.network) for prevout_str, ws in inputs.items(): for w in ws: if w[0] not in filtered_inputs: @@ -348,6 +349,8 @@ class Will: balance = 0 utxo_to_spend = [] for utxo in utxos: + if utxo.is_coinbase_output() and utxo.block_height < current_height+100: + continue utxo_str = utxo.prevout.to_str() if utxo_str in prevout_to_spend: balance += inputs[utxo_str][0][2].value_sats() @@ -356,7 +359,7 @@ class Will: 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) + locktime = current_height tx = PartialTransaction.from_io( utxo_to_spend, [out], locktime=locktime, version=2 ) @@ -560,6 +563,9 @@ class Will: raise WillExpiredException( f"Will Expired {wid[0][0]}: {locktime}<{timestamp_to_check}" ) + else: + from datetime import datetime + _logger.debug(f"Will Not Expired {wid[0][0]}: {datetime.fromtimestamp(locktime).isoformat()} > {datetime.fromtimestamp(timestamp_to_check).isoformat()}") # def check_all_input_spent_are_in_wallet(): # _logger.info("check all input spent are in wallet or valid txs") @@ -835,7 +841,12 @@ class WillItem(Logger): class WillException(Exception): - pass + def __init__(self,msg="WillException"): + self.msg=msg + Exception.__init__(self) + def __str__(self): + return self.msg + class WillExpiredException(WillException): @@ -872,8 +883,6 @@ class WillExecutorNotPresent(NotCompleteWillException): class NoHeirsException(WillException): pass - - class AmountException(WillException): pass diff --git a/willexecutors.py b/willexecutors.py index b86655d..24bd715 100644 --- a/willexecutors.py +++ b/willexecutors.py @@ -295,6 +295,7 @@ class Willexecutors: return {} def check_transaction(txid, url): + print("check transaction", txid,url) _logger.debug(f"{url}:{txid}") try: w = Willexecutors.send_request(