feat(bal): Group A (timestamps + statuses + anticipate docs) and Group B (auto-sign) v0.3.4
Bump plugin version to 0.3.4 (manifest, __init__, plugin_base, VERSION). GROUP A - A1: remove block-height locktimes; the plugin now uses UNIX timestamps only. The NLOCKTIME_BLOCKHEIGHT_MAX guard is kept on purpose (it forces every locktime to be a timestamp). chk_locktime is now 2-arg; int_locktime and anticipate_locktime no longer accept blocks; RAW input only accepts d/y. Two now-dormant configs (LOCKTIME_BLOCKS, LOCKTIMEDELTA_BLOCKS) are kept with comments to avoid touching persisted keys. - A2: rename PENDING -> MEMPOOL everywhere (label 'Mempool', yellow #ffce30); add new UPDATED status; ANTICIPATED & UPDATED keep VALID; documented set_status rules; backward-compat migration (old PENDING -> MEMPOOL). - A3: clarify that anticipating to a future date only rebuilds (never invalidates), while only a past locktime invalidates (WillExpired). Code was already correct; only the comment and docs were fixed. Colour follow-up: UPDATED lightened from #800080 to #b266b2 (more readable), updated in theme.py, docs and the theme test. GROUP B - B1: verified the 'Create your will' button already opens the guided wizard (no code change needed). - B2: new persisted AUTO_SIGN setting (default ON) with an 'Auto-sign on Check' checkbox in the settings dialog. When enabled, Check signs and broadcasts automatically; the wallet password is requested only for encrypted wallets. B2 follow-up (fixes reported after testing): - Remove the duplicate sign/broadcast cycle in lists.check(); build_will_task() already signs and broadcasts. - Suppress the manual 'press Sign/Broadcast' hint and its popup when AUTO_SIGN is ON (kept when OFF). - Make broadcast one-shot: removed the retry flag and the Exception('retry'); failed will-executors stay PUSH_FAIL and are skipped (no endless retry). PUSHED transactions are already excluded from re-collection. Docs: inheritance-options.md/.html and inheritance-flow.svg updated to v0.3.4. Tests: 206 passing (new test_anticipate_manual_locktime, test_anticipate_past_locktime, test_group_b_auto_sign; updated core/util, core/will_extra, gui/theme, gui/widgets). CHANGELOG.md added with one numbered entry per task.
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
|
||||
<!-- Title -->
|
||||
<text x="24" y="34" font-size="20" font-weight="700">BAL — Inheritance change decision flow</text>
|
||||
<text x="24" y="56" class="sub">What happens to your pre-signed transactions when you change the will (v0.3.3)</text>
|
||||
<text x="24" y="56" class="sub">What happens to your pre-signed transactions when you change the will (v0.3.4)</text>
|
||||
|
||||
<!-- Legend -->
|
||||
<g transform="translate(760,76)">
|
||||
@@ -63,32 +63,32 @@
|
||||
<path class="edge" d="M420,256 L300,256"/>
|
||||
<text x="330" y="250" class="lbl">No</text>
|
||||
|
||||
<!-- D earlier? -->
|
||||
<!-- D new date in the past? -->
|
||||
<polygon class="dec" points="590,312 800,350 590,388 380,350"/>
|
||||
<text x="590" y="346" text-anchor="middle">VALID tx with locktime</text>
|
||||
<text x="590" y="362" text-anchor="middle" class="sub">earlier than the new date? (anticipate)</text>
|
||||
<text x="590" y="346" text-anchor="middle">New delivery date</text>
|
||||
<text x="590" y="362" text-anchor="middle" class="sub">already in the PAST?</text>
|
||||
<path class="edge" d="M590,290 L590,312"/>
|
||||
|
||||
<!-- D Yes -> E -->
|
||||
<!-- D No -> AN anticipate? -->
|
||||
<polygon class="dec" points="930,312 1110,350 930,388 750,350"/>
|
||||
<text x="930" y="346" text-anchor="middle">Already signed</text>
|
||||
<text x="930" y="362" text-anchor="middle" class="sub">or sent?</text>
|
||||
<text x="930" y="346" text-anchor="middle">Moved the date</text>
|
||||
<text x="930" y="362" text-anchor="middle" class="sub">EARLIER? (anticipate)</text>
|
||||
<path class="edge" d="M800,350 L750,350"/>
|
||||
<text x="772" y="344" class="lbl">Yes (earlier)</text>
|
||||
<text x="772" y="344" class="lbl">No (still future)</text>
|
||||
|
||||
<!-- E No -> R1 rebuild -->
|
||||
<!-- AN Yes -> R1 rebuild (never invalidates) -->
|
||||
<rect class="rebuild" x="820" y="410" width="220" height="48" rx="8"/>
|
||||
<text x="930" y="430" text-anchor="middle" class="ttl">Rebuild only</text>
|
||||
<text x="930" y="446" text-anchor="middle" class="sub">no on-chain cost</text>
|
||||
<text x="930" y="428" text-anchor="middle" class="ttl">Rebuild only</text>
|
||||
<text x="930" y="444" text-anchor="middle" class="sub">no on-chain cost - NEVER invalidates</text>
|
||||
<path class="edge" d="M930,388 L930,410"/>
|
||||
<text x="940" y="402" class="lbl">Not signed</text>
|
||||
<text x="940" y="402" class="lbl">Yes (signed or not)</text>
|
||||
|
||||
<!-- E Yes -> INV2 -->
|
||||
<!-- D Yes (past) -> INV2 -->
|
||||
<rect class="inval" x="820" y="476" width="240" height="48" rx="8"/>
|
||||
<text x="940" y="496" text-anchor="middle" class="ttl">Invalidate on-chain FIRST</text>
|
||||
<text x="940" y="512" text-anchor="middle" class="sub">WillExpired</text>
|
||||
<path class="edge" d="M1010,386 C1090,430 1080,460 1010,476"/>
|
||||
<text x="1058" y="430" class="lbl">Signed</text>
|
||||
<text x="940" y="512" text-anchor="middle" class="sub">WillExpired (date in the past)</text>
|
||||
<path class="edge" d="M800,350 C1010,355 980,440 980,476"/>
|
||||
<text x="806" y="372" class="lbl">Yes (past)</text>
|
||||
|
||||
<!-- D No -> F -->
|
||||
<polygon class="dec" points="430,420 620,458 430,496 240,458"/>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.4 KiB |
@@ -38,6 +38,12 @@
|
||||
.pill.blue{background:var(--blue)}
|
||||
.pill.green{background:var(--green);color:#fff}
|
||||
.pill.grey{background:var(--grey);color:#fff}
|
||||
/* Status colours matching gui/qt/theme.py exactly. */
|
||||
.pill.orange{background:#f87838;color:#0d1117}
|
||||
.pill.pink{background:#ff97e9;color:#0d1117}
|
||||
.pill.violet{background:#b266b2;color:#fff}
|
||||
.pill.yellow{background:#ffce30;color:#0d1117}
|
||||
.pill.teal{background:#73f3c8;color:#0d1117}
|
||||
.mermaid{background:var(--panel);border:1px solid var(--border);border-radius:10px;padding:18px;margin:1.2em 0;overflow-x:auto}
|
||||
.lead{color:var(--muted);font-size:1.05rem}
|
||||
footer{margin-top:3em;color:var(--muted);font-size:.85rem;border-top:1px solid var(--border);padding-top:1em}
|
||||
@@ -78,37 +84,47 @@ transaction that would execute your inheritance too early.</strong></blockquote>
|
||||
<table>
|
||||
<thead><tr><th>Status</th><th>Meaning</th><th>Set when</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>VALID</code></td><td>The current, usable plan</td><td>default; cleared by INVALIDATED/REPLACED/CONFIRMED/PENDING</td></tr>
|
||||
<tr><td><code>VALID</code></td><td>The current, usable plan</td><td>default; cleared by INVALIDATED/REPLACED/CONFIRMED/MEMPOOL</td></tr>
|
||||
<tr><td><code>COMPLETE</code> (<em>Signed</em>)</td><td>The transaction has been <strong>signed</strong></td><td>after <strong>Sign</strong></td></tr>
|
||||
<tr><td><code>PUSHED</code></td><td>Signed tx <strong>sent to executor(s)</strong></td><td>after <strong>Broadcast</strong> to executors</td></tr>
|
||||
<tr><td><code>CHECKED</code></td><td>Executor <strong>confirmed</strong> it holds the tx</td><td>after a successful server <strong>Check</strong> (implies PUSHED)</td></tr>
|
||||
<tr><td><code>CHECK_FAIL</code></td><td>Server <strong>check failed</strong></td><td>a queried executor did not return the tx</td></tr>
|
||||
<tr><td><code>PUSH_FAIL</code></td><td>Sending to the executor failed</td><td>cleared when PUSHED becomes true</td></tr>
|
||||
<tr><td><code>CONFIRMED</code></td><td>Tx <strong>mined on‑chain</strong></td><td>seen on‑chain, height > 0</td></tr>
|
||||
<tr><td><code>PENDING</code></td><td>Tx <strong>in the mempool</strong></td><td>seen on‑chain, height 0</td></tr>
|
||||
<tr><td><code>MEMPOOL</code></td><td>Tx <strong>in the Electrum mempool</strong></td><td>seen on‑chain, height 0 (named <code>PENDING</code> before v0.3.4)</td></tr>
|
||||
<tr><td><code>INVALIDATED</code></td><td>Inputs spent → can never confirm</td><td>invalidation tx / inputs gone</td></tr>
|
||||
<tr><td><code>REPLACED</code></td><td>Superseded by an earlier‑locktime child</td><td>a replacing child found</td></tr>
|
||||
<tr><td><code>REPLACED</code></td><td>Superseded by an <strong>earlier</strong>‑locktime child</td><td>a replacing child found</td></tr>
|
||||
<tr><td><code>ANTICIPATED</code></td><td>Locktime anticipated by 1 day vs a pre‑existing tx with the same heirs</td><td><code>set_anticipate</code> (tx <strong>stays</strong> VALID)</td></tr>
|
||||
<tr><td><code>UPDATED</code></td><td>Replaced by a new tx keeping the <strong>same</strong> locktime + same heirs</td><td>same‑locktime replacement (tx <strong>stays</strong> VALID)</td></tr>
|
||||
<tr><td><code>EXPIRED</code></td><td>Locktime already in the past vs the check date</td><td><code>check_will_expired</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Safety rules baked into <code>set_status</code></h3>
|
||||
<ul>
|
||||
<li>Setting <code>INVALIDATED</code> / <code>REPLACED</code> / <code>CONFIRMED</code> / <code>PENDING</code> → clears <code>VALID</code>.</li>
|
||||
<li>Setting <code>CONFIRMED</code> / <code>PENDING</code> → clears <code>INVALIDATED</code>.</li>
|
||||
<li>Setting <code>INVALIDATED</code> / <code>REPLACED</code> / <code>CONFIRMED</code> / <code>MEMPOOL</code> → clears <code>VALID</code>.</li>
|
||||
<li>Setting <code>ANTICIPATED</code> → <strong>keeps</strong> <code>VALID</code> (only moves the locktime 1 day earlier).</li>
|
||||
<li>Setting <code>UPDATED</code> → <strong>keeps</strong> <code>VALID</code> (same locktime + same heirs).</li>
|
||||
<li>Setting <code>CONFIRMED</code> / <code>MEMPOOL</code> → clears <code>INVALIDATED</code>.</li>
|
||||
<li>Setting <code>PUSHED</code> → clears <code>PUSH_FAIL</code> <strong>and</strong> <code>CHECK_FAIL</code>.</li>
|
||||
<li>Setting <code>CHECKED</code> → implies <code>PUSHED</code>.</li>
|
||||
</ul>
|
||||
|
||||
<h3>How states map to row colour</h3>
|
||||
<table>
|
||||
<thead><tr><th>State (first match wins)</th><th>Colour</th><th>Hex</th></tr></thead>
|
||||
<thead><tr><th>Priority</th><th>State</th><th>Colour</th><th>Hex</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td><code>CHECK_FAIL</code></td><td><span class="pill red">red</span></td><td><code>#e83845</code></td></tr>
|
||||
<tr><td><code>INVALIDATED</code> / <code>REPLACED</code></td><td><span class="pill grey">grey</span></td><td>muted</td></tr>
|
||||
<tr><td><code>CONFIRMED</code></td><td><span class="pill green">green</span></td><td>confirmed</td></tr>
|
||||
<tr><td><code>COMPLETE</code> (signed, not pushed)</td><td><span class="pill blue">blue</span></td><td><code>#2bc8ed</code></td></tr>
|
||||
<tr><td><code>VALID</code> (prepared, not signed)</td><td>default</td><td>—</td></tr>
|
||||
<tr><td>1</td><td><code>INVALIDATED</code></td><td><span class="pill orange">orange</span></td><td><code>#f87838</code></td></tr>
|
||||
<tr><td>2</td><td><code>REPLACED</code></td><td><span class="pill pink">pink</span></td><td><code>#ff97e9</code></td></tr>
|
||||
<tr><td>3</td><td><code>UPDATED</code></td><td><span class="pill violet">light violet</span></td><td><code>#b266b2</code></td></tr>
|
||||
<tr><td>4</td><td><code>CONFIRMED</code></td><td><span class="pill grey">grey</span></td><td><code>#bfbfbf</code></td></tr>
|
||||
<tr><td>5</td><td><code>MEMPOOL</code></td><td><span class="pill yellow">yellow</span></td><td><code>#ffce30</code></td></tr>
|
||||
<tr><td>6</td><td><code>CHECK_FAIL</code> (and not <code>CHECKED</code>)</td><td><span class="pill red">red</span></td><td><code>#e83845</code></td></tr>
|
||||
<tr><td>7</td><td><code>CHECKED</code></td><td><span class="pill green">green</span></td><td><code>#8afa6c</code></td></tr>
|
||||
<tr><td>8</td><td><code>PUSH_FAIL</code></td><td><span class="pill red">red</span></td><td><code>#e83845</code></td></tr>
|
||||
<tr><td>9</td><td><code>PUSHED</code></td><td><span class="pill teal">teal</span></td><td><code>#73f3c8</code></td></tr>
|
||||
<tr><td>10</td><td><code>COMPLETE</code> (signed, not pushed)</td><td><span class="pill blue">blue</span></td><td><code>#2bc8ed</code></td></tr>
|
||||
<tr><td>—</td><td>none of the above (plain <code>VALID</code>)</td><td>default white</td><td><code>#ffffff</code></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<blockquote><strong>v0.3.3 fix:</strong> a will that is <em>signed but not yet broadcast</em>
|
||||
@@ -125,13 +141,13 @@ flowchart TD
|
||||
B -- No --> Z1[/Show: Heirs are not defined — stop/]
|
||||
B -- Yes --> C{Check-Alive threshold in the future?}
|
||||
C -- "No, it's in the past" --> INV1[[Invalidate on-chain<br/>CheckAliveError]]
|
||||
C -- Yes --> D{Any VALID tx with locktime earlier than the new date?}
|
||||
C -- Yes --> D{New delivery date already in the PAST?}
|
||||
|
||||
D -- "Yes you moved the date EARLIER / anticipate" --> E{Was that tx already signed or sent?}
|
||||
E -- "Not signed yet" --> R1[[Rebuild only<br/>no on-chain cost]]
|
||||
E -- "Signed / sent" --> INV2[[Invalidate on-chain FIRST<br/>WillExpired]]
|
||||
D -- "Yes date is now expired" --> INV2[[Invalidate on-chain FIRST<br/>WillExpired]]
|
||||
D -- "No date still in the future" --> AN{Did you move the date EARLIER anticipate?}
|
||||
|
||||
D -- No --> F{Will-executor / fee / heirs unchanged?}
|
||||
AN -- "Yes anticipate — signed or not" --> R1[[Rebuild only<br/>no on-chain cost<br/>NEVER invalidates]]
|
||||
AN -- No --> F{Will-executor / fee / heirs unchanged?}
|
||||
F -- "Fee changed" --> R2[[Rebuild<br/>TxFeesChanged]]
|
||||
F -- "Will-executor changed/absent" --> R3[[Rebuild<br/>WillExecutorNotPresent / Change]]
|
||||
F -- "Heir added/removed, % or address changed" --> G{POSTPONE of an already signed/sent tx?}
|
||||
@@ -165,13 +181,20 @@ already‑signed transaction</strong> (<code>w.tx.locktime</code>) — exactly w
|
||||
<tbody>
|
||||
<tr><td>Move date <strong>LATER</strong> (postpone)</td><td>No (never signed)</td><td>Plain <strong>rebuild</strong></td><td class="no">No</td></tr>
|
||||
<tr><td>Move date <strong>LATER</strong> (postpone)</td><td>Yes</td><td><strong>Invalidate first</strong>, then rebuild (WillPostponed)</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Move date <strong>EARLIER</strong> (anticipate)</td><td>any</td><td>Old tx <strong>expired</strong> → invalidate (WillExpired)</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Move date <strong>EARLIER, still in the future</strong> (anticipate)</td><td><strong>any</strong> (signed or not)</td><td>Plain <strong>rebuild</strong> with the new earlier locktime — <strong>never</strong> invalidates</td><td class="no">No</td></tr>
|
||||
<tr><td>Move date <strong>EARLIER into the past</strong> (new date already passed)</td><td>—</td><td>Will is genuinely <strong>expired</strong> → invalidate (WillExpired)</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Check‑Alive threshold already passed</td><td>—</td><td><strong>Invalidate</strong> (CheckAliveError)</td><td class="fee">Yes</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<blockquote><strong>Why postpone needs on‑chain invalidation:</strong> the executor still holds the <em>old</em>
|
||||
transaction with the <em>earlier</em> locktime. Spending its inputs on‑chain makes it un‑minable, so it can
|
||||
never execute the inheritance early. The plugin tells you this and offers to build the invalidation tx.</blockquote>
|
||||
<blockquote><strong>Why anticipate (move earlier, still future) is NOT on‑chain:</strong> moving the delivery
|
||||
date <em>earlier</em> only makes the inheritance available <em>sooner</em>; there is no early‑execution risk,
|
||||
so the plugin simply <strong>rebuilds</strong> the transactions with the new earlier locktime — <strong>no
|
||||
on‑chain invalidation and no Bitcoin fee</strong>. This holds <strong>even if the will was already
|
||||
signed/sent</strong>: anticipating never invalidates. Only a date that lands in the <em>past</em> is treated
|
||||
as expired and invalidated (<code>WillExpired</code>).</blockquote>
|
||||
|
||||
<h3>4.2 Adding an heir</h3>
|
||||
<p>An heir present in your set but not yet in the will raises <code>HeirNotFoundException</code>.</p>
|
||||
@@ -237,11 +260,12 @@ executor that <em>should</em> hold your tx did not return it — re‑Broadcast
|
||||
<tr><td>Change % / address (only prepared)</td><td class="yes">Yes</td><td class="no">No</td></tr>
|
||||
<tr><td>Change fee rate</td><td class="yes">Yes</td><td class="no">No</td></tr>
|
||||
<tr><td>Change / remove will‑executor</td><td class="yes">Yes</td><td class="no">No</td></tr>
|
||||
<tr><td>Move date <strong>earlier</strong> (anticipate)</td><td class="yes">Yes after</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Move date <strong>earlier, still in the future</strong> (anticipate) — signed <strong>or</strong> not</td><td class="yes">Yes</td><td class="no">No</td></tr>
|
||||
<tr><td>Move date <strong>earlier into the past</strong> (new date already passed)</td><td class="yes">Yes after</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Move date <strong>later</strong> — will <strong>signed/sent</strong></td><td class="yes">Yes after</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Move date <strong>later</strong> — will <strong>only prepared</strong></td><td class="yes">Yes</td><td class="no">No</td></tr>
|
||||
<tr><td>Check‑Alive threshold already passed</td><td class="yes">Yes after</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Any change to an <strong>already signed/sent</strong> will</td><td class="yes">Yes after</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Any change to an <strong>already signed/sent</strong> will <strong>that postpones it or expires it</strong></td><td class="yes">Yes after</td><td class="fee">Yes</td></tr>
|
||||
<tr><td>Nothing changed</td><td class="no">No</td><td class="no">No</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -249,13 +273,16 @@ executor that <em>should</em> hold your tx did not return it — re‑Broadcast
|
||||
<h2>7. Golden rules</h2>
|
||||
<ol>
|
||||
<li><strong>Before it's signed</strong>, changing anything is free — just <strong>Prepare</strong> again.</li>
|
||||
<li><strong>After it's signed/sent</strong>, moving the date or replacing it requires an <strong>on‑chain
|
||||
invalidation first</strong> (a small Bitcoin fee) so an old transaction can never execute early.</li>
|
||||
<li><strong>After it's signed/sent</strong>, only <strong>postponing</strong> the date (moving it <em>later</em>),
|
||||
or letting it <strong>expire</strong> (a date now in the past), requires an <strong>on‑chain invalidation
|
||||
first</strong> (a small Bitcoin fee) so an old transaction can never execute early.
|
||||
<strong>Anticipating</strong> (moving the date <em>earlier</em>, still in the future) never invalidates —
|
||||
it is just a free <strong>rebuild</strong>.</li>
|
||||
<li>Always finish with <strong>Sign → Broadcast → Check</strong> so executors hold the current plan (green).</li>
|
||||
<li>The wallet is always <strong>fully emptied</strong> by the inheritance, so heir amounts must add up.</li>
|
||||
</ol>
|
||||
|
||||
<footer>This document reflects BAL plugin v0.3.3. Behaviour is derived directly from
|
||||
<footer>This document reflects BAL plugin v0.3.4. Behaviour is derived directly from
|
||||
<code>core/will.py</code> and <code>gui/qt/window.py</code>.</footer>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -41,34 +41,50 @@ important ones:
|
||||
|
||||
| Status | Meaning | Set when |
|
||||
|---|---|---|
|
||||
| `VALID` | The item is the current, usable plan | default `True`; cleared by INVALIDATED/REPLACED/CONFIRMED/PENDING |
|
||||
| `VALID` | The item is the current, usable plan | default `True`; cleared by INVALIDATED/REPLACED/CONFIRMED/MEMPOOL |
|
||||
| `COMPLETE` (*Signed*) | The transaction has been **signed** | after you press **Sign** |
|
||||
| `PUSHED` | The signed tx was **sent to the will‑executor(s)** | after **Broadcast** to executors |
|
||||
| `CHECKED` | The will‑executor **confirmed** it holds the tx | after a successful server **Check** (implies `PUSHED`) |
|
||||
| `CHECK_FAIL` | The server **check failed** | a queried executor did not return the tx |
|
||||
| `PUSH_FAIL` | Sending to the executor failed | cleared when PUSHED becomes true |
|
||||
| `CONFIRMED` | The tx is **mined on‑chain** | seen on‑chain with height > 0 |
|
||||
| `PENDING` | The tx is **in the mempool** (height 0) | seen on‑chain, not yet mined |
|
||||
| `MEMPOOL` | The tx is **in the Electrum mempool** (height 0) | seen on‑chain, not yet mined (was named `PENDING` before v0.3.4) |
|
||||
| `INVALIDATED` | Its inputs were spent → it can never confirm | invalidation tx created / inputs gone |
|
||||
| `REPLACED` | Superseded by a child tx with earlier locktime | a replacing child was found |
|
||||
| `REPLACED` | Superseded by a child tx with **earlier** locktime | a replacing child was found |
|
||||
| `ANTICIPATED` | Its locktime was anticipated by 1 day vs a pre‑existing tx with the same heirs | `set_anticipate` (the tx **stays** `VALID`) |
|
||||
| `UPDATED` | Replaced by a new tx that keeps the **same** locktime **and** same heirs | a same‑locktime replacement was applied (the tx **stays** `VALID`) |
|
||||
| `EXPIRED` | Its locktime is already in the past relative to the check date | `check_will_expired` |
|
||||
|
||||
Flag transitions enforced by `set_status` (the safety rules baked in the code):
|
||||
|
||||
- Setting `INVALIDATED` / `REPLACED` / `CONFIRMED` / `PENDING` → clears `VALID`.
|
||||
- Setting `CONFIRMED` / `PENDING` → clears `INVALIDATED`.
|
||||
- Setting `INVALIDATED` / `REPLACED` / `CONFIRMED` / `MEMPOOL` → clears `VALID`.
|
||||
- Setting `ANTICIPATED` → **keeps** `VALID` (anticipating only moves the locktime
|
||||
1 day earlier; the tx stays valid).
|
||||
- Setting `UPDATED` → **keeps** `VALID` (same locktime + same heirs; the tx stays
|
||||
valid).
|
||||
- Setting `CONFIRMED` / `MEMPOOL` → clears `INVALIDATED`.
|
||||
- Setting `PUSHED` → clears `PUSH_FAIL` **and** `CHECK_FAIL`.
|
||||
- Setting `CHECKED` → implies `PUSHED` (and clears `PUSH_FAIL`).
|
||||
|
||||
### How states map to row colour in the list
|
||||
|
||||
| State (first match wins) | Colour | Hex |
|
||||
|---|---|---|
|
||||
| `CHECK_FAIL` | red | `#e83845` |
|
||||
| `INVALIDATED` / `REPLACED` | grey | (muted) |
|
||||
| `CONFIRMED` | green | (confirmed on server / chain) |
|
||||
| `COMPLETE` (signed, **not** yet pushed) | blue | `#2bc8ed` |
|
||||
| `VALID` (prepared, not signed) | default | — |
|
||||
The colour is decided by `status_color` (in `gui/qt/theme.py`). The list below is
|
||||
in the exact priority order used by the code — the **first** matching status
|
||||
wins:
|
||||
|
||||
| Priority | State | Colour | Hex |
|
||||
|---|---|---|---|
|
||||
| 1 | `INVALIDATED` | orange | `#f87838` |
|
||||
| 2 | `REPLACED` | pink | `#ff97e9` |
|
||||
| 3 | `UPDATED` | light violet | `#b266b2` |
|
||||
| 4 | `CONFIRMED` | grey | `#bfbfbf` |
|
||||
| 5 | `MEMPOOL` | yellow | `#ffce30` |
|
||||
| 6 | `CHECK_FAIL` (and **not** `CHECKED`) | red | `#e83845` |
|
||||
| 7 | `CHECKED` | green | `#8afa6c` |
|
||||
| 8 | `PUSH_FAIL` | red | `#e83845` |
|
||||
| 9 | `PUSHED` | teal | `#73f3c8` |
|
||||
| 10 | `COMPLETE` (signed, **not** yet pushed) | blue | `#2bc8ed` |
|
||||
| — | none of the above (e.g. plain `VALID`, prepared) | default white | `#ffffff` |
|
||||
|
||||
> **Note (v0.3.3 fix):** a will that is *signed but not yet broadcast*
|
||||
> (`COMPLETE` and **not** `PUSHED`) is **not** queried on the server, so it stays
|
||||
@@ -97,13 +113,13 @@ flowchart TD
|
||||
B -- No --> Z1[/Show: "Heirs are not defined" — stop/]
|
||||
B -- Yes --> C{Check-Alive threshold<br/>in the future?}
|
||||
C -- No, it's in the past --> INV1[[Invalidate on-chain<br/>CheckAliveError]]
|
||||
C -- Yes --> D{Any VALID tx with<br/>locktime earlier than<br/>the new date?}
|
||||
C -- Yes --> D{New delivery date<br/>already in the PAST?}
|
||||
|
||||
D -- "Yes (you moved the date EARLIER / anticipate)" --> E{Was that tx already<br/>signed or sent?}
|
||||
E -- "Not signed yet" --> R1[[Rebuild only<br/>no on-chain cost]]
|
||||
E -- "Signed / sent" --> INV2[[Invalidate on-chain FIRST<br/>WillExpired]]
|
||||
D -- "Yes (date is now expired)" --> INV2[[Invalidate on-chain FIRST<br/>WillExpired]]
|
||||
D -- "No (date still in the future)" --> AN{Did you move the date<br/>EARLIER (anticipate)?}
|
||||
|
||||
D -- "No" --> F{Will-executor / fee /<br/>heirs unchanged?}
|
||||
AN -- "Yes (anticipate) — signed or not" --> R1[[Rebuild only<br/>no on-chain cost<br/>NEVER invalidates]]
|
||||
AN -- "No" --> F{Will-executor / fee /<br/>heirs unchanged?}
|
||||
F -- "Fee changed" --> R2[[Rebuild<br/>TxFeesChanged]]
|
||||
F -- "Will-executor changed/absent" --> R3[[Rebuild<br/>WillExecutorNotPresent / Change]]
|
||||
F -- "Heir added or removed,<br/>% or address changed" --> G{Is it a POSTPONE of an<br/>already signed/sent tx?}
|
||||
@@ -142,7 +158,8 @@ exactly what the will‑executors hold — not the in‑memory copy.
|
||||
|---|---|---|---|
|
||||
| **Move date LATER** (postpone) | **No** (never signed) | Plain **rebuild** (`HeirNotFound` fall‑through) | **No** |
|
||||
| **Move date LATER** (postpone) | **Yes** | **Invalidate first**, then rebuild (`WillPostponed`) | **Yes** |
|
||||
| **Move date EARLIER** (anticipate) | any | Old tx becomes **expired** → **invalidate** (`WillExpired`) | **Yes** |
|
||||
| **Move date EARLIER, still in the future** (anticipate) | **any** (signed or not) | Plain **rebuild** with the new earlier locktime (`HeirNotFound` fall‑through) — **never** an on‑chain invalidation | **No** |
|
||||
| **Move date EARLIER into the past** (new date already passed) | — | Will is genuinely **expired** → **invalidate** (`WillExpired`) | **Yes** |
|
||||
| Check‑Alive threshold already passed | — | **Invalidate** (`CheckAliveError`) | **Yes** |
|
||||
|
||||
> **Why postpone needs an on‑chain invalidation:** the will‑executor still holds
|
||||
@@ -152,9 +169,24 @@ exactly what the will‑executors hold — not the in‑memory copy.
|
||||
> Spending the old transaction's inputs on‑chain makes the old tx **un‑minable**.
|
||||
> The plugin tells you this explicitly and offers to build the invalidation tx.
|
||||
|
||||
> **Why anticipate is also on‑chain:** moving the date earlier makes the current
|
||||
> committed tx *expired* relative to the new check date; the safe path is the
|
||||
> same — invalidate, then rebuild.
|
||||
> **Why anticipate (move earlier, still future) is NOT on‑chain:** moving the
|
||||
> delivery date *earlier* only makes the inheritance available *sooner*. There is
|
||||
> no early‑execution risk to protect against — on the contrary, the new plan is
|
||||
> *more* restrictive than the old one. So the plugin simply **rebuilds** the
|
||||
> transactions with the new, earlier locktime; **no on‑chain invalidation and no
|
||||
> Bitcoin fee** are needed. This holds **even if the will was already
|
||||
> signed/sent**: anticipating never invalidates.
|
||||
>
|
||||
> This is the opposite of postpone: postpone (later date) is dangerous because
|
||||
> the will‑executor could still broadcast the *earlier* old tx; anticipate
|
||||
> (earlier date) is safe because the old, *later* tx can only ever execute *after*
|
||||
> the new one.
|
||||
|
||||
> **Note — only a date that lands in the *past* invalidates.** "Move date earlier"
|
||||
> only triggers an on‑chain invalidation in the separate case where the new date
|
||||
> is already **in the past** relative to the Check‑Alive date: then the will is
|
||||
> truly *expired* (`WillExpired`) and must be invalidated, exactly like a
|
||||
> Check‑Alive threshold that has already passed.
|
||||
|
||||
### 4.2 Adding an heir
|
||||
|
||||
@@ -252,11 +284,12 @@ stays exactly as broadcast to the executors.
|
||||
| Change % / address (only prepared) | ✅ | ❌ |
|
||||
| Change fee rate | ✅ | ❌ |
|
||||
| Change / remove will‑executor | ✅ | ❌ |
|
||||
| Move date **earlier** (anticipate) | ✅ after | ✅ **yes** |
|
||||
| Move date **earlier, still in the future** (anticipate) — signed **or** not | ✅ | ❌ |
|
||||
| Move date **earlier into the past** (new date already passed) | ✅ after | ✅ **yes** |
|
||||
| Move date **later** (postpone) — will **signed/sent** | ✅ after | ✅ **yes** |
|
||||
| Move date **later** (postpone) — will **only prepared** | ✅ | ❌ |
|
||||
| Check‑Alive threshold already in the past | ✅ after | ✅ **yes** |
|
||||
| Any change to an **already signed/sent** will | ✅ after | ✅ **yes** (invalidate first) |
|
||||
| Any change to an **already signed/sent** will **that postpones it or expires it** | ✅ after | ✅ **yes** (invalidate first) |
|
||||
| Nothing changed | ❌ | ❌ |
|
||||
|
||||
---
|
||||
@@ -264,9 +297,11 @@ stays exactly as broadcast to the executors.
|
||||
## 7. Golden rules
|
||||
|
||||
1. **Before it's signed**, changing anything is free — just **Prepare** again.
|
||||
2. **After it's signed/sent**, moving the date or otherwise replacing it requires
|
||||
an **on‑chain invalidation first** (a small Bitcoin fee) so an old transaction
|
||||
can never be executed early.
|
||||
2. **After it's signed/sent**, only **postponing** the date (moving it *later*),
|
||||
or letting it **expire** (a date now in the past), requires an **on‑chain
|
||||
invalidation first** (a small Bitcoin fee) so an old transaction can never be
|
||||
executed early. **Anticipating** (moving the date *earlier*, still in the
|
||||
future) never invalidates — it is just a free **rebuild**.
|
||||
3. Always finish with **Sign → Broadcast → Check** so the will‑executors hold the
|
||||
*current* plan (green), not an obsolete one.
|
||||
4. The wallet is always **fully emptied** by the inheritance, so heir amounts must
|
||||
@@ -274,5 +309,5 @@ stays exactly as broadcast to the executors.
|
||||
|
||||
---
|
||||
|
||||
*This document reflects BAL plugin v0.3.3. Behaviour is derived directly from
|
||||
*This document reflects BAL plugin v0.3.4. Behaviour is derived directly from
|
||||
`core/will.py` and `gui/qt/window.py`.*
|
||||
|
||||
Reference in New Issue
Block a user