Add Willexecutors.is_valid + grey italic styling for invalid executors

This commit is contained in:
2026-07-30 17:49:28 -04:00
parent 4a9299d85b
commit 9bf088b7ff
20 changed files with 3826 additions and 66 deletions

View File

@@ -230,6 +230,7 @@ def get_utxos_from_inputs(tx_inputs, tx, utxos):
# TODO calculate de minimum inputs to be invalidated
def invalidate_inheritance_transactions(wallet):
print("invalidate tx in heir method")
# listids = []
utxos = {}
dtxs = {}
@@ -478,7 +479,8 @@ class Heirs(dict, Logger):
)
def prepare_lists(
self, balance, total_fees, wallet, willexecutor=False, from_locktime=0
self, balance, total_fees, wallet, willexecutor=False, from_locktime=0,
max_fee=None,
):
if balance<total_fees or balance < wallet.dust_threshold():
raise BalanceTooLowException(balance,wallet.dust_threshold(),total_fees)
@@ -493,6 +495,10 @@ class Heirs(dict, Logger):
if int(Util.int_locktime(locktime)) > int(from_locktime):
try:
base_fee = int(willexecutor["base_fee"])
if max_fee is not None and base_fee > max_fee:
raise WillExecutorFeeTooHighException(
willexecutor, max_fee
)
willexecutors_amount += base_fee
h = [None] * 4
h[HEIR_AMOUNT] = base_fee
@@ -629,7 +635,7 @@ class Heirs(dict, Logger):
break
elif 0 <= j:
url, willexecutor = willexecutorsitems[j]
if not Willexecutors.is_selected(willexecutor) or willexecutor["base_fee"] < wallet.dust_threshold():
if not (Willexecutors.is_selected(willexecutor) and Willexecutors.is_valid(willexecutor, max_fee=bal_plugin.MAX_WILLEXECUTOR_FEE.get(), dust=wallet.dust_threshold())):
continue
else:
willexecutor["url"] = url
@@ -651,11 +657,15 @@ class Heirs(dict, Logger):
# newbalance = balance
try:
locktimes, onlyfixed = self.prepare_lists(
balance, total_fees, wallet, willexecutor, from_locktime
balance, total_fees, wallet, willexecutor, from_locktime,
max_fee=bal_plugin.MAX_WILLEXECUTOR_FEE.get(),
)
except WillExecutorFeeException:
i = 10
continue
except WillExecutorFeeTooHighException:
i = 10
continue
if locktimes:
try:
txs = prepare_transactions(
@@ -874,6 +884,19 @@ class WillExecutorFeeException(Exception):
return "WillExecutorFeeException: {} fee:{}".format(
self.willexecutor["url"], self.willexecutor["base_fee"]
)
class WillExecutorFeeTooHighException(Exception):
def __init__(self, willexecutor, max_fee):
self.willexecutor = willexecutor
self.max_fee = max_fee
def __str__(self):
return "WillExecutorFeeTooHighException: {} fee:{} > max:{}".format(
self.willexecutor["url"],
self.willexecutor["base_fee"],
self.max_fee,
)
class BalanceTooLowException(Exception):
def __init__(self,balance, dust_threshold, fees):
self.balance=balance

View File

@@ -258,6 +258,9 @@ class BalPlugin(BasePlugin):
# follows what is saved in that wallet (the default only applies when no
# value has been stored yet, i.e. new wallets).
self.NO_WILLEXECUTOR = BalConfig(config, "bal_no_willexecutor", False)
self.MAX_WILLEXECUTOR_FEE = BalConfig(
config, "bal_max_willexecutor_fee", 500000
)
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)

View File

@@ -45,6 +45,7 @@ from electrum.util import (
from .util import Util
from .willexecutors import Willexecutors
from .heirs import WillExecutorFeeTooHighException
MIN_LOCKTIME = 1
MIN_BLOCK = 1
@@ -456,6 +457,7 @@ class Will:
@staticmethod
def invalidate_will(will, wallet, fees_per_byte):
print("invalidate tx in will module")
will_only_valid = Will.only_valid_list(will)
inputs = Will.get_all_inputs(will_only_valid)
utxos = wallet.get_utxos()
@@ -472,11 +474,13 @@ class Will:
utxo_to_spend = []
for utxo in utxos:
if utxo.is_coinbase_output() and utxo.block_height < current_height+100:
print("is not mature coinbase output")
continue
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)
print("utxo to spend",utxo_to_spend)
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)
@@ -598,7 +602,8 @@ class Will:
# Will.reflect_to_children(wc)
@staticmethod
def check_amounts(heirs, willexecutors, all_utxos, timestamp_to_check, dust):
def check_amounts(heirs, willexecutors, all_utxos, timestamp_to_check, dust,
max_fee=None):
fixed_heirs, fixed_amount, perc_heirs, perc_amount, fixed_amount_with_dust = (
heirs.fixed_percent_lists_amount(timestamp_to_check, dust, reverse=True)
)
@@ -614,7 +619,9 @@ class Will:
raise PercAmountException(f"Perc amount({perc_amount}) =! 100%")
for url, wex in willexecutors.items():
if Willexecutors.is_selected(wex):
if Willexecutors.is_selected(wex) and Willexecutors.is_valid(wex, max_fee=max_fee, dust=dust):
if max_fee is not None and int(wex["base_fee"]) > max_fee:
raise WillExecutorFeeTooHighException(wex, max_fee)
temp_balance = wallet_balance - int(wex["base_fee"])
if fixed_amount >= temp_balance:
raise FixedAmountException(
@@ -937,7 +944,7 @@ class Will:
if self_willexecutor and no_willexecutor == 0:
raise NoWillExecutorNotPresent("Backup tx")
for url, we in willexecutors.items():
if Willexecutors.is_selected(we):
if Willexecutors.is_selected(we) and Willexecutors.is_valid(we):
if url not in willexecutors_found:
_logger.debug(f"will-executor: {url} not fount")
raise WillExecutorNotPresent(url)

View File

@@ -205,17 +205,35 @@ class Willexecutors:
return w_sorted
@staticmethod
def is_selected(willexecutor, value=None):
def is_selected(willexecutor, value=None, max_fee=None):
if not willexecutor:
return False
if value is not None:
willexecutor["selected"] = value
if max_fee is not None:
base_fee = willexecutor.get("base_fee", 0)
if int(base_fee) >= max_fee:
return False
try:
return willexecutor["selected"]
except Exception:
willexecutor["selected"] = False
return False
@staticmethod
def is_valid(willexecutor, max_fee=None, dust=None):
if not willexecutor:
return False
address = willexecutor.get("address", "")
if not address or not bitcoin.is_address(address, net=constants.net):
return False
base_fee = int(willexecutor.get("base_fee", 0))
if dust is not None and base_fee <= dust:
return False
if max_fee is not None and base_fee >= max_fee:
return False
return True
@staticmethod
def get_willexecutor_transactions(will, force=False):
willexecutors = {}