Skip to content
Bitcoin Roots

v31.1-roots.1 · Commit 6: [PATCH 06/17] feat(wallet): preserve Roots signing and spend controls on v31

doc/roots-v31-port-review.md

Before: doc/roots-v31-port-review.md · After: doc/roots-v31-port-review.md

File metadata
index 0948ff33ab106892045cf13b8157c1d4fadd214d..0a0a6ca759a62ab091751e6a6246df35262dbef1 100644

Download original patch · Release notes

Diff rows 1–108 of 108. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

doc/roots-v31-port-review.md CHANGED
@@ -619,3 +619,108 @@ matrix. No static mockup or history collector is introduced.
619
  These adaptations preserve the catalogued Roots contracts and attribution to
620
  Jaromil and devjoinedthechat alongside the Bitcoin Core and Bitcoin Knots
621
  provenance already recorded above.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
619
  These adaptations preserve the catalogued Roots contracts and attribution to
620
  Jaromil and devjoinedthechat alongside the Bitcoin Core and Bitcoin Knots
621
  provenance already recorded above.
622
+
623
+ ## L11.1 wallet foundations and per-send RBF
624
+
625
+ The descriptor/SQLite and external-signer boundaries retain the native v31
626
+ wallet API. Roots database enumeration excludes node database directories and
627
+ avoids descending through symlinks/reparse points. SQLite opening probes directory
628
+ write access before opening an existing database, retaining v31 locking/error
629
+ handling; all 19 source SQLite warning/error modernization lines already exist
630
+ upstream. No legacy database build support or new backup/flush promise is added.
631
+
632
+ External signer invocation keeps v31's explicit argument vector and closes
633
+ unrelated inherited Unix descriptors after redirecting standard streams, retaining
634
+ the exec-error pipe at FD 3 with close-on-exec set. `close_range` closes all higher
635
+ descriptors when available. Its Linux fallback reads `/proc/self/fd` using raw
636
+ `getdents64` into a fixed stack buffer: it enumerates actual descriptors, including
637
+ those above a subsequently lowered soft limit, without post-fork heap allocation
638
+ or scanning a numeric descriptor limit. Other Unix builds use a detected native
639
+ `closefrom` fallback. If no safe closure mechanism succeeds, the child reports an
640
+ error through the retained pipe and exits before executing the signer. Non-Linux
641
+ fallback runtime behavior is an untested platform gap; unsupported fallback
642
+ platforms fail closed. The unsafe source RLIMIT-based fallback is replaced;
643
+ source process poll/kill APIs remain unported. The current Windows
644
+ CreateProcess implementation does not provide equivalent inherited-handle
645
+ isolation; Windows handle, permission and reparse behavior remain explicit gaps.
646
+
647
+ The Send dialog takes its initial RBF choice from the selected wallet's
648
+ `walletrbf`, retains native explicit coin-control overrides and reports signaling
649
+ from the prepared transaction even when no fee is charged. Saved PSBT tests decode
650
+ both signaling choices. Replacement acceptance remains dependent on network policy.
651
+ Automatic anti-fee-sniping locktimes avoid the source CAT21 policy marker; explicit
652
+ caller locktimes and consensus validity are unchanged. This ports the spending
653
+ safeguard associated with the accepted local-policy rule.
654
+
655
+ Focused candidate coverage exercises database-directory write rejection, skipped
656
+ node databases and symlink traversal; descriptor wallet/send and external signer
657
+ behavior; child descriptor closure plus preserved standard streams and process
658
+ errors; both wallet RBF defaults, explicit overrides, confirmation text and PSBT
659
+ sequences. Sweep authorization, coin-control facts and the rendered interaction
660
+ matrix remain L11.2. Attribution remains Jaromil and devjoinedthechat alongside
661
+ Bitcoin Core/Knots provenance.
662
+
663
+ L11.1 focused evidence: 34 GCC unit cases in system/filesystem/wallet/spend and
664
+ wallet database/load/PSBT suites; four functional profiles (wallet signer,
665
+ multiwallet RPC and CLI, wallet send); 21 Qt6 test results, including the RBF
666
+ confirmation and decoded PSBT assertions; and the same 34 focused unit cases in
667
+ Clang ASan/UBSan under a 60-second runtime bound. Leak detection was disabled
668
+ (`ASAN_OPTIONS=detect_leaks=0`); undefined behavior halts on error. This is bounded
669
+ sanitizer coverage, not a leak or exhaustive race proof. A Qt-only fixture reset
670
+ was corrected after its first run and the Qt suite rerun; production and headless
671
+ results stayed hash-matched. Qt5 and the visual matrix remain L11.2. The full
672
+ applicable candidate gate remains the L11 acceptance gate.
673
+
674
+ L11.1 signer review corrected the source fallback's soft-limit assumption. A new
675
+ regression opens a descriptor at 123 or higher before lowering the child's soft
676
+ limit to 32, forces fallback and checks descriptor closure, standard streams,
677
+ retained exec-error pipe and its close-on-exec flag. All three current signer
678
+ system cases pass under GCC and bounded Clang ASan/UBSan; `wallet_signer.py`
679
+ passes again against the corrected daemon. Unaffected wallet/database/RBF and
680
+ Qt6 evidence retains its original source/fixture and binary-hash provenance.
681
+ The combined focused gate now covers 35 distinct unit cases, with the three
682
+ signer cases replacing the original two; it is not a claim that every retained
683
+ case was rerun against the new binary. The full acceptance gate is still L11.
684
+
685
+ ### L11.2 — sweep and coin-control authorization
686
+
687
+ The v31 port carries transient-key WIF sweep through shared native UTXO scanning,
688
+ RPC and Qt, without importing supplied keys. Preview remains the default. The
689
+ GUI requires a current preview, default-Cancel confirmation and an exact rebuilt
690
+ transaction-ID match. Atomic cancellation/final submission transitions prevent
691
+ accepted cancellation from later broadcasting. Worker disposal clears secure
692
+ storage and catches interruption errors; complete Qt/host memory erasure is not
693
+ promised. Fee convergence uses one locked native estimate/fallback snapshot.
694
+
695
+ Source review found an inherited destination defect: cached-script ownership
696
+ accepted an incomplete local-key multisig descriptor. A disposable source-build
697
+ probe confirmed accepted preview but incomplete wallet-only spending. Both v31
698
+ entry points now share a native signing-satisfaction check. Cached public
699
+ descriptor expansion maps available roots, including encrypted keys, to derived
700
+ public keys without private-key retrieval/export or unlock. An availability-gated
701
+ dummy creator uses native script satisfaction for multisig, Taproot alternatives
702
+ and MuSig participants. Missing 2-of-2 keys are rejected; a sufficient 2-of-3
703
+ subset remains eligible. Timelock maturity and future network acceptance remain
704
+ separate from local signing capability.
705
+
706
+ Coin-control preserves native availability/selection and PSBT behavior while
707
+ reporting effective value, input size, lock, watch-only, reuse/group, fee/change
708
+ and actual transaction RBF facts. Same-balance wallet notifications invalidate
709
+ selection. Horizontal scrolling retains readable columns at large fonts; summary
710
+ and controls fit the bounded visual profiles. These are facts, not privacy scores.
711
+
712
+ Focused final verification covers 91 cases across all affected wallet, shared
713
+ script/descriptor, key, RPC and process suites; six functional profiles (sweep,
714
+ send, multiwallet RPC/CLI, signer and scantxoutset); the complete Qt5 and Qt6
715
+ test suites (21 result rows each, including initialization/cleanup); and 48
716
+ bounded Clang ASan/UBSan cases with leak detection disabled. After a recursive
717
+ lock annotation correction, all 91 unit cases and all six affected functional
718
+ profiles were rerun against the frozen final binaries.
719
+ Eight actual Qt5/Qt6 profiles at 1280x800 and 1920x1080 with 100%/150% font scale
720
+ produced 80 captures. These unchanged-UI captures retain their original binary
721
+ hashes; both Qt suites passed again with the final destination correction.
722
+ Native confirmation captures preserve a prior test's background shutdown window
723
+ and synthetic regtest fee-estimator limitations. Linux/Xvfb evidence does not
724
+ establish Windows/macOS rendering, physical-DPI scaling, complete secret erasure
725
+ or exhaustive races. The full applicable L11 acceptance sweep remains the next
726
+ root-directed gate. Credits remain Jaromil, devjoinedthechat, Core and Knots.