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

68
util.py
View File

@@ -1,15 +1,13 @@
import bisect
from datetime import datetime, timedelta
from electrum.gui.qt.util import getSaveFileName
from electrum.i18n import _
from electrum.transaction import PartialTxOutput
from electrum.util import FileExportFailed
LOCKTIME_THRESHOLD = 500000000
class Util:
@staticmethod
def locktime_to_str(locktime):
try:
locktime = int(locktime)
@@ -21,6 +19,7 @@ class Util:
pass
return str(locktime)
@staticmethod
def str_to_locktime(locktime):
try:
if locktime[-1] in ("y", "d", "b"):
@@ -33,6 +32,7 @@ class Util:
timestamp = dt_object.timestamp()
return int(timestamp)
@staticmethod
def parse_locktime_string(locktime, w=None):
try:
return int(locktime)
@@ -60,6 +60,7 @@ class Util:
pass
return 0
@staticmethod
def int_locktime(seconds=0, minutes=0, hours=0, days=0, blocks=0):
return int(
seconds
@@ -69,6 +70,7 @@ class Util:
+ blocks * 600
)
@staticmethod
def encode_amount(amount, decimal_point):
if Util.is_perc(amount):
return amount
@@ -78,6 +80,7 @@ class Util:
except Exception:
return 0
@staticmethod
def decode_amount(amount, decimal_point):
if Util.is_perc(amount):
return amount
@@ -88,12 +91,14 @@ class Util:
except Exception:
return str(amount)
@staticmethod
def is_perc(value):
try:
return value[-1] == "%"
except Exception:
return False
@staticmethod
def cmp_array(heira, heirb):
try:
if len(heira) != len(heirb):
@@ -105,11 +110,13 @@ class Util:
except Exception:
return False
@staticmethod
def cmp_heir(heira, heirb):
if heira[0] == heirb[0] and heira[1] == heirb[1]:
return True
return False
@staticmethod
def cmp_willexecutor(willexecutora, willexecutorb):
if willexecutora == willexecutorb:
return True
@@ -124,6 +131,7 @@ class Util:
return False
return False
@staticmethod
def search_heir_by_values(heirs, heir, values):
for h, v in heirs.items():
found = False
@@ -135,12 +143,14 @@ class Util:
return h
return False
@staticmethod
def cmp_heir_by_values(heira, heirb, values):
for v in values:
if heira[v] != heirb[v]:
return False
return True
@staticmethod
def cmp_heirs_by_values(
heirsa, heirsb, values, exclude_willexecutors=False, reverse=True
):
@@ -165,6 +175,7 @@ class Util:
else:
return True
@staticmethod
def cmp_heirs(
heirsa,
heirsb,
@@ -187,6 +198,7 @@ class Util:
raise e
return False
@staticmethod
def cmp_inputs(inputsa, inputsb):
if len(inputsa) != len(inputsb):
return False
@@ -195,6 +207,7 @@ class Util:
return False
return True
@staticmethod
def cmp_outputs(outputsa, outputsb, willexecutor_output=None):
if len(outputsa) != len(outputsb):
return False
@@ -204,6 +217,7 @@ class Util:
return False
return True
@staticmethod
def cmp_txs(txa, txb):
if not Util.cmp_inputs(txa.inputs(), txb.inputs()):
return False
@@ -211,6 +225,7 @@ class Util:
return False
return True
@staticmethod
def get_value_amount(txa, txb):
outputsa = txa.outputs()
# outputsb = txb.outputs()
@@ -229,6 +244,7 @@ class Util:
return value_amount
@staticmethod
def chk_locktime(timestamp_to_check, block_height_to_check, locktime):
# TODO BUG: WHAT HAPPEN AT THRESHOLD?
locktime = int(locktime)
@@ -239,6 +255,7 @@ class Util:
else:
return False
@staticmethod
def anticipate_locktime(locktime, blocks=0, hours=0, days=0):
locktime = int(locktime)
out = 0
@@ -255,6 +272,7 @@ class Util:
out = 1
return out
@staticmethod
def cmp_locktime(locktimea, locktimeb):
if locktimea == locktimeb:
return 0
@@ -268,17 +286,20 @@ class Util:
else:
return int(locktimea) - (locktimeb)
@staticmethod
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
@staticmethod
def get_locktimes(will):
locktimes = {}
for txid, willitem in will.items():
locktimes[willitem["tx"].locktime] = True
return locktimes.keys()
@staticmethod
def get_lowest_locktimes(locktimes):
sorted_timestamp = []
sorted_block = []
@@ -291,18 +312,22 @@ class Util:
return sorted(sorted_timestamp), sorted(sorted_block)
@staticmethod
def get_lowest_locktimes_from_will(will):
return Util.get_lowest_locktimes(Util.get_locktimes(will))
@staticmethod
def search_willtx_per_io(will, tx):
for wid, w in will.items():
if Util.cmp_txs(w["tx"], tx["tx"]):
return wid, w
return None, None
@staticmethod
def invalidate_will(will):
raise Exception("not implemented")
@staticmethod
def get_will_spent_utxos(will):
utxos = []
for txid, willitem in will.items():
@@ -310,6 +335,7 @@ class Util:
return utxos
@staticmethod
def utxo_to_str(utxo):
try:
return utxo.to_str()
@@ -321,6 +347,7 @@ class Util:
pass
return str(utxo)
@staticmethod
def cmp_utxo(utxoa, utxob):
utxoa = Util.utxo_to_str(utxoa)
utxob = Util.utxo_to_str(utxob)
@@ -329,21 +356,25 @@ class Util:
else:
return False
@staticmethod
def in_utxo(utxo, utxos):
for s_u in utxos:
if Util.cmp_utxo(s_u, utxo):
return True
return False
@staticmethod
def txid_in_utxo(txid, utxos):
for s_u in utxos:
if s_u.prevout.txid == txid:
return True
return False
@staticmethod
def cmp_output(outputa, outputb):
return outputa.address == outputb.address and outputa.value == outputb.value
@staticmethod
def in_output(output, outputs):
for s_o in outputs:
if Util.cmp_output(s_o, output):
@@ -355,6 +386,7 @@ class Util:
# return true false same amount different address
# return false false different amount, different address not found
@staticmethod
def din_output(out, outputs):
same_amount = []
for s_o in outputs:
@@ -370,6 +402,7 @@ class Util:
else:
return False, False
@staticmethod
def get_change_output(wallet, in_amount, out_amount, fee):
change_amount = int(in_amount - out_amount - fee)
if change_amount > wallet.dust_threshold():
@@ -380,6 +413,7 @@ class Util:
out.is_change = True
return out
@staticmethod
def get_current_height(network):
# if no network or not up to date, just set locktime to zero
if not network:
@@ -401,6 +435,7 @@ class Util:
height = min(chain_height, server_height)
return height
@staticmethod
def print_var(var, name="", veryverbose=False):
print(f"---{name}---")
if var is not None:
@@ -435,6 +470,7 @@ class Util:
print(f"---end {name}---")
@staticmethod
def print_utxo(utxo, name=""):
print(f"---utxo-{name}---")
Util.print_var(utxo, name)
@@ -446,36 +482,20 @@ class Util:
print("_TxInput__value_sats:", utxo._TxInput__value_sats)
print(f"---utxo-end {name}---")
@staticmethod
def print_prevout(prevout, name=""):
print(f"---prevout-{name}---")
Util.print_var(prevout, f"{name}-prevout")
Util.print_var(prevout._asdict())
print(f"---prevout-end {name}---")
def export_meta_gui(electrum_window, title, exporter):
filter_ = "All files (*)"
filename = getSaveFileName(
parent=electrum_window,
title=_("Select file to save your {}".format(title)),
filename="BALplugin_{}".format(title),
filter=filter_,
config=electrum_window.config,
)
if not filename:
return
try:
exporter(filename)
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)))
)
@staticmethod
def copy(dicto, dictfrom):
for k, v in dictfrom.items():
dicto[k] = v
@staticmethod
def fix_will_settings_tx_fees(will_settings):
tx_fees = will_settings.get("tx_fees", False)
have_to_update = False
@@ -485,6 +505,7 @@ class Util:
have_to_update = True
return have_to_update
@staticmethod
def fix_will_tx_fees(will):
have_to_update = False
for txid, willitem in will.items():
@@ -495,15 +516,18 @@ class Util:
have_to_update = True
return have_to_update
@staticmethod
def text_to_hex(text: str) -> str:
"""Convert text to hexadecimal string"""
hex_string = text.encode('utf-8').hex()
return hex_string
@staticmethod
def hex_to_text(hex_string: str) -> str:
"""Convert hexadecimal string back to text (for verification)"""
try:
return bytes.fromhex(hex_string).decode('utf-8')
except Exception:
return "Error: Invalid hex string"