partial commit to fix wallet utils

this commit provide a lot of changes in will-settings including export to ics calendar file.
This commit is contained in:
2026-04-27 10:03:05 -04:00
parent 9204c90e4c
commit b5eda4f05a
9 changed files with 839 additions and 635 deletions

50
will.py
View File

@@ -24,6 +24,7 @@ _logger = get_logger(__name__)
class Will:
@staticmethod
def get_children(will, willid):
out = []
for _id in will:
@@ -35,6 +36,7 @@ class Will:
return out
# build a tree with parent transactions
@staticmethod
def add_willtree(will):
for willid in will:
will[willid].children = Will.get_children(will, willid)
@@ -43,14 +45,17 @@ class Will:
will[child[0]].father = willid
# return a list of will sorted by locktime
@staticmethod
def get_sorted_will(will):
return sorted(will.items(), key=lambda x: x[1]["tx"].locktime)
@staticmethod
def only_valid(will):
for k, v in will.items():
if v.get_status("VALID"):
yield k
@staticmethod
def search_equal_tx(will, tx, wid):
for w in will:
if w != wid and not tx.to_json() != will[w]["tx"].to_json():
@@ -59,6 +64,7 @@ class Will:
return will[w]["tx"]
return False
@staticmethod
def get_tx_from_any(x):
try:
a = str(x)
@@ -69,6 +75,7 @@ class Will:
return x
@staticmethod
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)
@@ -89,7 +96,9 @@ class Will:
txin._TxInput__value_sats = change.value
txin._trusted_value_sats = change.value
def normalize_will(will, wallet=None, others_inputs={}):
@staticmethod
def normalize_will(will, wallet=None, others_inputs=None):
others_input = others_inputs if others_inputs is not None else {}
to_delete = []
to_add = {}
# add info from wallet
@@ -138,6 +147,7 @@ class Will:
if wid in will:
del will[wid]
@staticmethod
def new_input(txid, idx, change):
prevout = TxOutpoint(txid=bfh(txid), out_idx=idx)
inp = PartialTxInput(prevout=prevout)
@@ -148,6 +158,7 @@ class Will:
inp._TxInput__value_sats = change.value
return inp
@staticmethod
def check_anticipate(ow: "WillItem", nw: "WillItem"):
anticipate = Util.anticipate_locktime(ow.tx.locktime, days=1)
if int(nw.tx.locktime) >= int(anticipate):
@@ -177,6 +188,7 @@ class Will:
return anticipate
return 4294967295 + 1
@staticmethod
def change_input(will, otxid, idx, change, others_inputs, to_delete, to_append):
ow = will[otxid]
ntxid = ow.tx.txid()
@@ -217,6 +229,7 @@ class Will:
to_append,
)
@staticmethod
def get_all_inputs(will, only_valid=False):
all_inputs = {}
for w, wi in will.items():
@@ -231,6 +244,7 @@ class Will:
all_inputs[prevout_str].append(inp)
return all_inputs
@staticmethod
def get_all_inputs_min_locktime(all_inputs):
all_inputs_min_locktime = {}
@@ -245,6 +259,7 @@ class Will:
return all_inputs_min_locktime
@staticmethod
def search_anticipate_rec(will, old_inputs):
redo = False
to_delete = []
@@ -284,6 +299,7 @@ class Will:
Will.search_anticipate_rec(will, old_inputs)
@staticmethod
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)
@@ -310,6 +326,7 @@ class Will:
else:
continue
@staticmethod
def get_higher_input_for_tx(will):
out = {}
for wid in will:
@@ -323,6 +340,7 @@ class Will:
out[inp.prevout.to_str()] = inp
return out
@staticmethod
def invalidate_will(will, wallet, fees_per_byte):
will_only_valid = Will.only_valid_list(will)
inputs = Will.get_all_inputs(will_only_valid)
@@ -374,11 +392,13 @@ class Will:
_logger.debug("len utxo_to_spend <=0")
pass
@staticmethod
def is_new(will):
for wid, w in will.items():
if w.get_status("VALID") and not w.get_status("COMPLETE"):
return True
@staticmethod
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():
@@ -412,20 +432,25 @@ class Will:
else:
pass
@staticmethod
def utxos_strs(utxos):
return [Util.utxo_to_str(u) for u in utxos]
def set_invalidate(wid, will=[]):
@staticmethod
def set_invalidate(wid, will=None):
will = will if will is not None else {}
will[wid].set_status("INVALIDATED", True)
if will[wid].children:
for c in will[wid].children.items():
Will.set_invalidate(c[0], will)
@staticmethod
def check_tx_height(tx, wallet):
info = wallet.get_tx_info(tx)
return info.tx_mined_status.height()
# check if transactions are stil valid tecnically valid
@staticmethod
def check_invalidated(willtree, utxos_list, wallet):
for wid, w in willtree.items():
if (
@@ -458,6 +483,7 @@ class Will:
# if wc.children:
# Will.reflect_to_children(wc)
@staticmethod
def check_amounts(heirs, willexecutors, all_utxos, timestamp_to_check, dust):
fixed_heirs, fixed_amount, perc_heirs, perc_amount, fixed_amount_with_dust = (
heirs.fixed_percent_lists_amount(timestamp_to_check, dust, reverse=True)
@@ -481,6 +507,7 @@ class Will:
f"Willexecutor{url} excess base fee({wex['base_fee']}), {fixed_amount} >={temp_balance}"
)
@staticmethod
def check_will(will, all_utxos, wallet, block_to_check, timestamp_to_check):
Will.add_willtree(will)
utxos_list = Will.utxos_strs(all_utxos)
@@ -497,18 +524,28 @@ class Will:
Will.search_rai(all_inputs, all_utxos, will, wallet)
@staticmethod
def get_min_locktime(will,default_value=None):
return min((v.tx.locktime for v in will.values() if v.get_status('VALID')), default=default_value)
@staticmethod
def is_will_valid(
will,
block_to_check,
timestamp_to_check,
tx_fees,
all_utxos,
heirs={},
willexecutors={},
heirs=None,
willexecutors=None,
self_willexecutor=False,
wallet=False,
callback_not_valid_tx=None,
):
heirs = heirs if heirs is not None else {}
willexecutors= willexecutors if willexecutors is not None else {}
Will.check_will(will, all_utxos, wallet, block_to_check, timestamp_to_check)
if heirs:
if not Will.check_willexecutors_and_heirs(
@@ -537,6 +574,7 @@ class Will:
_logger.info("will ok")
return True
@staticmethod
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():
@@ -568,6 +606,7 @@ class Will:
# if not parentwill or not parentwill.get_status("VALID"):
# w[1].set_status("INVALIDATED", True)
@staticmethod
def only_valid_list(will):
out = {}
for wid, w in will.items():
@@ -575,6 +614,7 @@ class Will:
out[wid] = w
return out
@staticmethod
def only_valid_or_replaced_list(will):
out = []
for wid, w in will.items():
@@ -583,6 +623,7 @@ class Will:
out.append(wid)
return out
@staticmethod
def check_willexecutors_and_heirs(
will, heirs, willexecutors, self_willexecutor, check_date, tx_fees
):
@@ -645,6 +686,7 @@ class Will:
return True
class WillItem(Logger):
STATUS_DEFAULT = {
"ANTICIPATED": ["Anticipated", False],