fix(plugin): missed-update fixes, server re-check, and bold Building Will results (v0.3.2)
Revert the v0.3.1 double-invalidation change (it caused an inheritance-list regression: stale/invalidated wills lingered and heir/date updates became incoherent) and add several targeted missed-update fixes plus a UI refinement. Revert (v0.3.1 -> v0.3.2): - Remove Will.mark_invalidated_by_tx() and its call in loop_broadcast_invalidating. core/will.py and gui/qt/dialogs.py are restored to the working v0.3.0 behaviour. The postpone double-invalidation issue is intentionally left open, to be addressed without touching the shared broadcast path. FIX 1 - detect heir removal on Check / Electrum close: - core/will.py (check_willexecutors_and_heirs): the else-branch now raises HeirNotFoundException when a will still carries an heir that is no longer in the current heirs set (heir removed), mirroring the existing 'heir added' path. Rebuild therefore triggers on Check and on_close (same build_will_task path), as decided by the user (manual update only, no auto-rebuild). FIX 2 - Check queries servers for already-sent wills: - core/will.py: new Will.needs_server_check(w) returns True for any VALID will with a will-executor that is not yet CHECKED (no longer limited to PUSHED). - gui/qt/lists.py (PreviewList.check): use needs_server_check so wills stuck on 'New / Not sent' are re-checked instead of reporting 'nothing to do'. FIX 3 - Settings-dialog hide toggles refresh the list: - core/plugin_base.py: new sync_hide_filters() re-reads the cached _hide_invalidated / _hide_replaced flags from the persisted config. - gui/qt/window.py (update_all): call sync_hide_filters() before refreshing, so toggling 'Hide Invalidated' / 'Hide Replaced' in the Settings dialog (which writes the config directly) updates the transaction list immediately instead of requiring an Electrum restart. UI - bold results in the Building Will dialog: - gui/qt/dialogs.py (BalBuildWillDialog): render the right-side results in bold (Ok, Ko, Nothing to do, Skipped, Wait, Timeout, ...) keeping the left-side state labels in normal weight. Centralised in msg_ok/msg_error/msg_warning/ msg_set_status, plus the will-executor push/check rows now show Ok/Ko and True/False in bold + colour (green/red). Tests/tooling: - tests/test_core_will.py: add test_check_heirs_unchanged_is_coherent, test_check_heir_removed_triggers_rebuild, test_check_heir_added_triggers_rebuild, test_needs_server_check. - tests/sim_update_flows.py: real-world update-scenario simulation. - tests/preview_build_will_dialog.py, tests/preview_we_rows.py: GUI-only before/after previews of the bold formatting. - Bump version to 0.3.2 (VERSION, manifest.json, __init__.py, plugin_base.py). 186 tests pass; smoke test, external-zip test and update-flow simulation OK; ruff reports only pre-existing star-import false positives.
This commit is contained in:
@@ -91,7 +91,7 @@ class BalPlugin(BasePlugin):
|
||||
"""
|
||||
|
||||
_version = None
|
||||
__version__ = "0.3.1" # AUTOMATICALLY GENERATED DO NOT EDIT
|
||||
__version__ = "0.3.2" # AUTOMATICALLY GENERATED DO NOT EDIT
|
||||
|
||||
# Command used to open an .ics calendar file, per operating system.
|
||||
default_app = {
|
||||
@@ -237,6 +237,29 @@ class BalPlugin(BasePlugin):
|
||||
"""Absolute path to a file bundled inside the plugin directory."""
|
||||
return os.path.join(self.plugin_dir, *parts)
|
||||
|
||||
def sync_hide_filters(self):
|
||||
"""Re-read the "hide" filter flags from the persisted config.
|
||||
|
||||
The cached ``_hide_invalidated`` / ``_hide_replaced`` flags are used by
|
||||
the GUI list to decide which rows to skip. They can be changed from two
|
||||
different places:
|
||||
|
||||
* the list toolbar buttons, which call :meth:`hide_invalidated` /
|
||||
:meth:`hide_replaced` (a toggle that updates both the cache and the
|
||||
config), and
|
||||
* the Settings dialog checkboxes, which write the config directly
|
||||
(``BalConfig.set``) without touching the cached flags.
|
||||
|
||||
In the second case the cache and the config would drift apart and the
|
||||
transaction list would keep filtering with the *old* value, so the
|
||||
toggled rows never appear/disappear until Electrum is restarted.
|
||||
Re-syncing the cache from the config here (called by ``update_all``)
|
||||
keeps every code path coherent regardless of where the change came
|
||||
from.
|
||||
"""
|
||||
self._hide_invalidated = self.HIDE_INVALIDATED.get()
|
||||
self._hide_replaced = self.HIDE_REPLACED.get()
|
||||
|
||||
def hide_invalidated(self):
|
||||
"""Toggle (and persist) the "hide invalidated transactions" filter."""
|
||||
self._hide_invalidated = not self._hide_invalidated
|
||||
|
||||
@@ -83,6 +83,25 @@ class Will:
|
||||
if v.get_status("VALID"):
|
||||
yield k
|
||||
|
||||
@staticmethod
|
||||
def needs_server_check(w):
|
||||
"""Return True if ``w`` should be queried on its will-executor server
|
||||
when the user presses Check (or on Electrum close).
|
||||
|
||||
A will needs a server check when it is VALID, has a will-executor
|
||||
assigned, and is not yet CHECKED. This intentionally includes wills
|
||||
that are not (yet) marked PUSHED: a will that was actually sent in the
|
||||
past but whose saved status still reads "New" would otherwise be
|
||||
skipped, leaving the Server column stuck on "Not sent". The server
|
||||
response (see WillItem.set_check_willexecutor) then corrects the status
|
||||
to PUSHED/CHECKED if the transaction is present, or CHECK_FAIL if not.
|
||||
"""
|
||||
return bool(
|
||||
w.get_status("VALID")
|
||||
and w.we
|
||||
and not w.get_status("CHECKED")
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def search_equal_tx(will, tx, wid):
|
||||
for w in will:
|
||||
@@ -420,31 +439,6 @@ class Will:
|
||||
_logger.debug("len utxo_to_spend <=0")
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def mark_invalidated_by_tx(will, tx):
|
||||
"""Mark as INVALIDATED every valid will item that spends at least one
|
||||
of the prevouts consumed by ``tx`` (the on-chain invalidation tx that
|
||||
was just broadcast).
|
||||
|
||||
Once the invalidation tx is broadcast, the previously signed/sent will
|
||||
transactions that relied on those same UTXOs can no longer be mined, so
|
||||
their will items must stop being VALID. Setting INVALIDATED clears the
|
||||
VALID flag (see WillItem.set_status), which removes them from
|
||||
only_valid_list and therefore prevents the postpone/expire check from
|
||||
firing a *second* invalidation on the next pass.
|
||||
|
||||
Returns the list of will ids that were marked.
|
||||
"""
|
||||
spent_prevouts = {i.prevout.to_str() for i in tx.inputs()}
|
||||
invalidated = []
|
||||
for wid in Will.only_valid_list(will):
|
||||
w = will[wid]
|
||||
wi_prevouts = {i.prevout.to_str() for i in w.tx.inputs()}
|
||||
if spent_prevouts & wi_prevouts:
|
||||
Will.set_invalidate(wid, will)
|
||||
invalidated.append(wid)
|
||||
return invalidated
|
||||
|
||||
@staticmethod
|
||||
def is_new(will):
|
||||
for wid, w in will.items():
|
||||
@@ -732,9 +726,18 @@ class Will:
|
||||
# signed/sent falls through here -> a plain rebuild via
|
||||
# HeirNotFoundException (no on-chain fee needed).
|
||||
else:
|
||||
# The will still carries this heir, but the heir is no
|
||||
# longer present in the current heirs set: the user
|
||||
# removed it. This must trigger a rebuild exactly like
|
||||
# "heir added" does, otherwise the removed heir would
|
||||
# silently stay in the inheritance transaction. Raising
|
||||
# HeirNotFoundException reuses the same rebuild path used
|
||||
# by the Check button and by on_close (Electrum quit).
|
||||
_logger.debug(
|
||||
f"heir not present transaction is not valid:{wheir} {wid}, {w}"
|
||||
f"heir removed, transaction is not valid:"
|
||||
f"{wheir} {wid}, {w}"
|
||||
)
|
||||
raise HeirNotFoundException(wheir)
|
||||
|
||||
if willexecutor := w.we:
|
||||
count = willexecutors_found.get(willexecutor["url"], 0)
|
||||
|
||||
Reference in New Issue
Block a user