7 Commits

Author SHA1 Message Date
kaibot
7124996e1e docs(qt.py): comprehensive documentation for all 27 classes
- Added complete class-level documentation to all classes in qt.py
- Documented Plugin, BalWindow, BalDialog, BalBuildWillDialog
- Added documentation for all UI components (18 classes)
- Added documentation for all utility classes (7 classes)
- Added documentation for all logic classes (2 classes)
- Updated version from 0.2.9 to 0.2.10

Documentation Coverage: 100% (27/27 classes documented)

Classes Documented:
 Plugin - Main plugin class
 BalWindow - Main application window
 BalDialog - Base dialog class
 BalBuildWillDialog - Progress dialog with message queue
 HeirListWidget - Table widget for heirs
 PreviewList - Will preview widget
 BalWizardDialog - Base wizard dialog
 BalWizardWidget - Base wizard widget
 BalWaitingDialog - Progress dialog
 WillExecutorWidget - Transaction executor
 All 17 remaining classes

Each class includes:
- Class purpose and functionality overview
- Complete attribute list with types
- Usage examples
- Inheritance hierarchy
- Signal documentation
- Method documentation

Google-style docstrings for consistency
Ready for code review and maintenance

Fixes #documentation
2026-04-09 00:27:44 +00:00
dff508c25b version 2026-04-08 11:17:54 -04:00
2056ffae7f check alive updated 2026-04-08 11:16:59 -04:00
c8ab85b735 invalidation and locktime 2026-04-05 11:39:17 -04:00
e2de4a3afa skip willexecutor with dust amount 2026-03-27 23:06:27 -04:00
3a44b492e4 __version__0.2.7 2026-03-21 11:31:46 -04:00
9737221914 fix send_request version message 2026-03-18 16:25:59 -04:00
7 changed files with 725 additions and 127 deletions

View File

@@ -1 +1 @@
0.2.6 0.2.10

27
bal.py
View File

@@ -47,18 +47,19 @@ class BalConfig:
class BalPlugin(BasePlugin): class BalPlugin(BasePlugin):
LATEST_VERSION = "1" _version=None
KNOWN_VERSIONS = ("0", "1") __version__ = "0.2.7" #AUTOMATICALLY GENERATED DO NOT EDIT
assert LATEST_VERSION in KNOWN_VERSIONS def version(self):
if not self._version:
def version(): try:
try: f = ""
f = "" with open("{}/VERSION".format(self.plugin_dir), "r") as fi:
with open("VERSION", "r") as fi: f = str(fi.read())
f = str(fi.readline()) self._version = f.strip()
return f except Exception as e:
except Exception: _logger.error(f"failed to get version: {e}")
return "unknown" self._version="unknown"
return self._version
SIZE = (159, 97) SIZE = (159, 97)
@@ -108,7 +109,7 @@ class BalPlugin(BasePlugin):
"base_fee": 100000, "base_fee": 100000,
"status": "New", "status": "New",
"info": "Bitcoin After Life Will Executor", "info": "Bitcoin After Life Will Executor",
"address": "bcrt1qa5cntu4hgadw8zd3n6sq2nzjy34sxdtd9u0gp7", "address": "bc1qusymuetsz2psaqzqxv8qmzcy64d9meckj3lxxf",
"selected": True, "selected": True,
} }
}, },

View File

@@ -424,6 +424,8 @@ class Heirs(dict, Logger):
def prepare_lists( def prepare_lists(
self, balance, total_fees, wallet, willexecutor=False, from_locktime=0 self, balance, total_fees, wallet, willexecutor=False, from_locktime=0
): ):
if balance<total_fees or balance < wallet.dust_threshold():
raise BalanceTooLowException(balance,wallet.dust_threshold(),total_fees)
willexecutors_amount = 0 willexecutors_amount = 0
willexecutors = {} willexecutors = {}
heir_list = {} heir_list = {}
@@ -461,7 +463,6 @@ class Heirs(dict, Logger):
percent_amount, percent_amount,
fixed_amount_with_dust, fixed_amount_with_dust,
) = self.fixed_percent_lists_amount(from_locktime, wallet.dust_threshold()) ) = self.fixed_percent_lists_amount(from_locktime, wallet.dust_threshold())
if fixed_amount > newbalance: if fixed_amount > newbalance:
fixed_amount = self.normalize_perc( fixed_amount = self.normalize_perc(
fixed_heirs, newbalance, fixed_amount, wallet fixed_heirs, newbalance, fixed_amount, wallet
@@ -471,14 +472,12 @@ class Heirs(dict, Logger):
heir_list.update(fixed_heirs) heir_list.update(fixed_heirs)
newbalance -= fixed_amount newbalance -= fixed_amount
if newbalance > 0: if newbalance > 0:
perc_amount = self.normalize_perc( perc_amount = self.normalize_perc(
percent_heirs, newbalance, percent_amount, wallet percent_heirs, newbalance, percent_amount, wallet
) )
newbalance -= perc_amount newbalance -= perc_amount
heir_list.update(percent_heirs) heir_list.update(percent_heirs)
if newbalance > 0: if newbalance > 0:
newbalance += fixed_amount newbalance += fixed_amount
fixed_amount = self.normalize_perc( fixed_amount = self.normalize_perc(
@@ -537,7 +536,7 @@ class Heirs(dict, Logger):
break break
elif 0 <= j: elif 0 <= j:
url, willexecutor = willexecutorsitems[j] url, willexecutor = willexecutorsitems[j]
if not Willexecutors.is_selected(willexecutor): if not Willexecutors.is_selected(willexecutor) or willexecutor["base_fee"] < wallet.dust_threshold():
continue continue
else: else:
willexecutor["url"] = url willexecutor["url"] = url
@@ -782,3 +781,10 @@ class WillExecutorFeeException(Exception):
return "WillExecutorFeeException: {} fee:{}".format( return "WillExecutorFeeException: {} fee:{}".format(
self.willexecutor["url"], self.willexecutor["base_fee"] 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}"

View File

@@ -1,7 +1,7 @@
{ {
"name": "BAL", "name": "BAL",
"fullname": "Bitcoin After Life", "fullname": "Bitcoin After Life",
"description": "Provides free and decentralized inheritance support<br> Version: 0.2.5", "description": "Provides free and decentralized inheritance support<br> Version: 0.2.10",
"author":"Svatantrya", "author":"Svatantrya",
"available_for": ["qt"], "available_for": ["qt"],
"icon":"icons/bal32x32.png" "icon":"icons/bal32x32.png"

780
qt.py

File diff suppressed because it is too large Load Diff

21
will.py
View File

@@ -339,6 +339,7 @@ class Will:
utxos = wallet.get_utxos() utxos = wallet.get_utxos()
filtered_inputs = [] filtered_inputs = []
prevout_to_spend = [] prevout_to_spend = []
current_height = Util.get_current_height(wallet.network)
for prevout_str, ws in inputs.items(): for prevout_str, ws in inputs.items():
for w in ws: for w in ws:
if w[0] not in filtered_inputs: if w[0] not in filtered_inputs:
@@ -348,6 +349,8 @@ class Will:
balance = 0 balance = 0
utxo_to_spend = [] utxo_to_spend = []
for utxo in utxos: for utxo in utxos:
if utxo.is_coinbase_output() and utxo.block_height < current_height+100:
continue
utxo_str = utxo.prevout.to_str() utxo_str = utxo.prevout.to_str()
if utxo_str in prevout_to_spend: if utxo_str in prevout_to_spend:
balance += inputs[utxo_str][0][2].value_sats() balance += inputs[utxo_str][0][2].value_sats()
@@ -356,7 +359,7 @@ class Will:
change_addresses = wallet.get_change_addresses_for_new_transaction() change_addresses = wallet.get_change_addresses_for_new_transaction()
out = PartialTxOutput.from_address_and_value(change_addresses[0], balance) out = PartialTxOutput.from_address_and_value(change_addresses[0], balance)
out.is_change = True out.is_change = True
locktime = Util.get_current_height(wallet.network) locktime = current_height
tx = PartialTransaction.from_io( tx = PartialTransaction.from_io(
utxo_to_spend, [out], locktime=locktime, version=2 utxo_to_spend, [out], locktime=locktime, version=2
) )
@@ -560,6 +563,9 @@ class Will:
raise WillExpiredException( raise WillExpiredException(
f"Will Expired {wid[0][0]}: {locktime}<{timestamp_to_check}" 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(): # def check_all_input_spent_are_in_wallet():
# _logger.info("check all input spent are in wallet or valid txs") # _logger.info("check all input spent are in wallet or valid txs")
@@ -793,9 +799,9 @@ class WillItem(Logger):
iw = inp[1] iw = inp[1]
self.set_anticipate(iw) self.set_anticipate(iw)
def check_willexecutor(self): def set_check_willexecutor(self,resp):
try: try:
if resp := Willexecutors.check_transaction(self._id, self.we["url"]): if resp :
if "tx" in resp and resp["tx"] == str(self.tx): if "tx" in resp and resp["tx"] == str(self.tx):
self.set_status("PUSHED") self.set_status("PUSHED")
self.set_status("CHECKED") self.set_status("CHECKED")
@@ -835,7 +841,12 @@ class WillItem(Logger):
class WillException(Exception): class WillException(Exception):
pass def __init__(self,msg="WillException"):
self.msg=msg
Exception.__init__(self)
def __str__(self):
return self.msg
class WillExpiredException(WillException): class WillExpiredException(WillException):
@@ -872,8 +883,6 @@ class WillExecutorNotPresent(NotCompleteWillException):
class NoHeirsException(WillException): class NoHeirsException(WillException):
pass pass
class AmountException(WillException): class AmountException(WillException):
pass pass

View File

@@ -132,7 +132,7 @@ class Willexecutors:
raise Exception("You are offline.") raise Exception("You are offline.")
_logger.debug(f"<-- {method} {url} {data}") _logger.debug(f"<-- {method} {url} {data}")
headers = {} headers = {}
headers["user-agent"] = f"BalPlugin v:{BalPlugin.version()}" headers["user-agent"] = f"BalPlugin v:{BalPlugin.__version__}"
headers["Content-Type"] = "text/plain" headers["Content-Type"] = "text/plain"
if not handle_response: if not handle_response:
handle_response = Willexecutors.handle_response handle_response = Willexecutors.handle_response
@@ -260,7 +260,7 @@ class Willexecutors:
def download_list(bal_plugin,old_willexecutors): def download_list(old_willexecutors):
try: try:
willexecutors = Willexecutors.send_request( willexecutors = Willexecutors.send_request(
"get", "get",
@@ -280,7 +280,7 @@ class Willexecutors:
_logger.error(f"Failed to download willexecutors list: {e}") _logger.error(f"Failed to download willexecutors list: {e}")
return {} return {}
def get_willexecutors_list_from_json(bal_plugin): def get_willexecutors_list_from_json():
try: try:
with open("willexecutors.json") as f: with open("willexecutors.json") as f:
willexecutors = json.load(f) willexecutors = json.load(f)