Skip to content

Release v1.0.1: test results, remaining fixes, and release gates #174

Open

Description

@kiwidream

Recommend v1.0.1-rc1, followed by v1.0.1, as a maintenance release from the reviewed 1.x.x work plus the fixes below. The current published release is v1.0.0. This version recommendation assumes the scope stays focused on reliability, performance, and release tooling; it is not a proposal for a new network activation or wallet-format change.

The manual wallet inspection completed successfully apart from an encryption responsiveness problem. Final release readiness also requires resolving the release items and validating the final source and packaged artifacts below.

Tested source and environment

  • Date: September 23, 2026.
  • Tested 1.x.x: c4b254e2d39f3a430b8b4a85798dd03ed47c3d98.
  • Comparison main: 70fea84f5becfb57463247af09790df5ddd424f8 — 18 commits ahead. Both remote branch heads were rechecked when preparing this issue.
  • Native Apple Silicon macOS 26.4, RelWithDebInfo build with GUI, wallet, unit/GUI tests, and benchmarks enabled. The tested binary still identifies as v1.0.0; the source SHA identifies this inspection build.
  • Manual testing used an existing testnet4 wallet, initially unencrypted and then encrypted in place. Fresh backups were made before encryption and after the completed inspection; the final encrypted backup passed a database integrity check. No restored backup was loaded as a second signing wallet.

Manual inspection completed

The maintainer reports completing all eight checks in the original guide and steps 1–5 of the follow-up guide:

  • Open the existing wallet, sync, inspect balances/history, and create a receiving address.
  • Send a small self-payment with the recommended fee settings and Replace-By-Fee enabled. Fee estimation was unavailable; the send exercised the fallback-fee path.
  • Cancel and retry a fee increase; complete the replacement and inspect signing-usage feedback.
  • Sign a prepared PSBT, save it, close/reopen it, and broadcast the completed transaction.
  • Inspect a change-only self-transfer: one fee-only Payment to self row, no output-index field, and inclusion in the Other filter.
  • Sign text and verify the proof against the expected signer and original text.
  • Quit normally and reopen: wallet history, receive address, and sampled signing counters persisted.
  • Encrypt the existing wallet and save an encrypted backup. Encryption succeeded, with the responsiveness finding below.
  • Exercise canceled unlock, incorrect passphrase, successful unlock, canceled send confirmation, retry, and automatic relocking.
  • Increase a fee from the locked wallet, including canceled unlock and successful retry/relock.
  • Explicitly unlock for ten minutes, send twice without another passphrase prompt or unexpected relocking, then explicitly lock and confirm that sending prompts again.
  • With the wallet encrypted and locked, sign a PSBT containing both receive and change inputs; inspect usage for both keys, save/reopen, and broadcast. RPC also confirmed the transaction was in the wallet and both sampled counters increased.

Limits: The follow-up history check was not separately repeated; that behavior was inspected in the original guide. Quitting during active transaction preparation was not tested manually. Completion of the guides does not establish that every brief background-cancellation window was caught. Controlled cancellation, teardown, and failure cases rely on automated tests.

New-wallet deferred refill was covered by automated tests, not a newly created wallet in this walkthrough. Forced proof-verification failures, counter persistence on failed signing, and conflict/reorg cases also rely on their controlled tests.

The missing receiving address in the Verify Proof picker was a runbook mistake: that picker lists sending contacts. Pasting the signing address into Expected signer completed the intended flow; no product defect was established by that observation.

Automated and CI evidence

Evidence Result
Local targeted unit/GUI suites 26/26 passed: wallet/database, deferred keypool, P2MR signing, PSBT, fee bump, PQC/signature cache, header synchronization, AuxPoW, and Qt coverage.
Local functional suites 7/7 passed: wallet_listsinceblock, wallet_p2mr_psbt, wallet_pqc_usage, wallet_bumpfee, wallet_signer, interface_bitcoin_cli, interface_rest.
Fallback fee Existing functional suite passed; a separate disposable-node check passed compiled-default sending and explicit -fallbackfee=0 rejection.
Tooling contracts Classifier, scheduled-source selection, merge poller, release publisher, versioned RPC docs, and fuzz runner contracts passed. RPC docs generated successfully. GNU command adaptations were needed for two native macOS test-environment differences; optional real IBD lanes were skipped.
Core Checks Passed at the tested SHA, including P2MR v1 conformance. The mainnet-publication-posture job was skipped in this run.
Full Validation Passed at the tested SHA, including Windows, Linux/GUI, sanitizer, cross-build, docs, and lint jobs. A cross-build labeled “no tests” is build evidence only.
Required Merge Gate Passed at the tested SHA.

One local tooling check failed: python3 test/fuzz/test_qbit_fuzz_coverage.py --anchors-only. Actual instrumented fuzz coverage/replay/mutation was not established by this inspection. Public mainnet wallet operation, physical hardware signers, full IBD/performance campaigns, and final release-package installation/publication were not exercised here.

Recommended fixes before the final release

These are proposed release requirements, not claims that every item affects funds or consensus correctness.

  • #172: keep Encrypt Wallet responsive. The maintainer observed roughly 20 seconds of apparent freezing before encryption completed. Source inspection shows the GUI calls encryption and replacement-keypool generation synchronously. Keep the interface responsive and show progress while preserving atomic encryption, wallet lifetime, and locking behavior. Acceptance: encrypt an existing populated wallet; the interface repaints, completion/errors are visible, the wallet ends locked, backup/reopen works, and interrupted/failed operations do not compromise wallet state. The observed run completed; no persistent deadlock or data loss was observed.
    • Status (2026-09-25): Done. #178 merged as a32081e. Encryption runs on a worker thread behind a busy dialog. GUI reads and transaction-table updates are cached or deferred while encryption runs. An exception after the commit stops the app instead of being misreported. The wallet ends encrypted and locked and works after reopening. qt: Encrypt Wallet blocks the GUI during existing-wallet encryption #172 is closed. The manual timing run on a populated testnet wallet moves to the packaged-RC smoke checks below. Follow-ups: #179 and #180.
  • #173: repair the fuzz coverage source anchor. pqc_sign_refused expects a return false; line changed by #163 to return finish(false);. Update the anchor without weakening the intended refusal-path coverage, pass the anchor check, then obtain actual instrumented replay/mutation and coverage evidence. This is a test-tool failure, not evidence that PQC verification is failing.
  • #168: reliably display fee-bump signing usage without a notification backend. Provide an in-app success surface and test the no-backend path. Durable accounting and warning dialogs already remain intact; this Mac inspection does not cover the affected desktop configuration.
  • #156: correct the v1.0.0 trust record. Accurately enumerate the original failed jobs, accepted deviation, and retained-file references. Distinguish that historical release from the passing maintenance-branch validation; do not imply that later fixes changed the original tag.

Added to scope (2026-09-25): follow-ups from the #172 work

  • #179: close pre-existing races around CWallet::EncryptWallet. Make the already-encrypted check and the encryption atomic, so an encryptwallet RPC overlapping the GUI worker fails cleanly instead of double-encrypting and asserting. Leave no in-memory master key when TxnBegin fails. Lock or annotate the SPKM readers (IsHDEnabled, GetActiveScriptPubKeyMans). These races predate qt: keep Encrypt Wallet responsive during existing-wallet encryption #178, but the asynchronous GUI encryption makes the overlap easier to reach. Acceptance: a deterministic test for each item that fails without its fix, and a build that is clean under clang -Wthread-safety.
    • Status (2026-09-25): #183 is open.
      • It makes the checks and the encryption atomic under LOCK2 after key derivation. An overlapping or repeated encryptwallet now returns -15 (already encrypted) instead of -16.
      • No master key is left in memory when the transaction fails.
      • The SPKM readers now require the wallet lock.
      • The GUI dialog reports correctly when another request won the race.
      • Deterministic unit and functional tests fail without the fix.
      • It builds clean under clang thread-safety with DEBUG_LOCKORDER, and an adversarial review found no blocker.
      • Waiting on CI, Codex review and merge. The -15 change should be added to the v1.0.1 release notes (release: prepare v1.0.1 #181).
  • #180: keep transaction-list repaints responsive during encryption. Label lookups during a repaint still take cs_wallet through AddressTableModel::labelForAddress, so they stall the GUI until encryption finishes. Answer them from GUI-side data while encrypting, and audit the other repaint paths. Acceptance: a Qt test that requests label data while encryption is held open and shows the event loop keeps running; it must fail without the fix.
    • Status (2026-09-25): #182 is open. While encrypting, label lookups are answered from AddressTableModel's cached rows. A Qt test covering PKHash and P2MR rows with RECEIVE, SEND and REFUND purposes fails without the fix. It builds clean under clang with thread-safety -Werror, and an adversarial review found no blocker. Waiting on CI, Codex review and merge.

If either issue can't land in time for the final release, record the deferral in the v1.0.1 release notes' "Known limitations" section rather than dropping it silently.

Added to scope (2026-10-29): release-gate review findings

These are the findings from the 2026-10-29 review, listed in the comment below. Each was checked against the v1.0.1 candidate fb45d18d7b. Dispositions are still pending: fix before tagging, or defer and record the item under "Known limitations". Fix PRs target 1.x.x. Merging them requires lifting the v1.0.1 freeze (#181) and adding entries to the release notes. Update (2026-10-30): An Orca daemon restart at 18:37 on 2026-10-29 interrupted the workers before any PR opened. Their in-progress work was preserved, and replacement workers resumed it on 2026-10-30. Consolidation (2026-10-30): Each finding now has one PR: #263 (djh58) for #257, #266 (djh58) for #258, and #265 for #259. The duplicates #267 and #269 are closed. The extra #258 unit tests and release notes are going to #266 as a PR into djh58's branch.

  • #257: P2MR runtime stack counts items, not bytes. Confirmed. A 16 KiB initial item duplicated to 1,000 items is valid and standard. One 18,391-byte input raised peak RSS by 15.5 MiB. 108 such inputs fit in a block.
    • Status (2026-10-30): Tracked in #263 (djh58). It adds a policy-only 1 MiB cap on P2MR stack plus altstack bytes, enforced under SCRIPT_VERIFY_P2MR_STACK_BYTES, and changes no consensus rule. #271 was fast-forwarded into policy: bound P2MR runtime stack bytes #263's branch (head ba62cfcd71). It adds its own error, SCRIPT_ERR_P2MR_STACK_BYTES, the §10/§11 spec rows, and oracle cases. Because the spec text changed, the consensus review must cite a commit that includes them. The duplicate policy: cap P2MR runtime stack bytes at 1 MiB (v1.0.1) #269 is closed. Review input on #263: the enforcement is correct, but the PR reuses SCRIPT_ERR_STACK_SIZE for the new limit, and its uniform-size tests missed accounting regressions we planted deliberately. It also edits doc/consensus/p2mr-v1.md, which the release conformance check binds, so the consensus-review evidence would need refreshing. It has no release-notes fragment and no note on the known limitation. The consensus cap stays open for a later release with activation. Update (2026-10-30, late): policy: bound P2MR runtime stack bytes #263's Core Checks failed because doc/integration/p2mr-v1-support-matrix.{json,md} still carried the previous src/test/data/p2mr_v1_manifest.json digest. The coordinator pushed a signed fix (head 04c03ef296) that updates all 13 occurrences and regenerates the Markdown; the conformance unit tests pass. All required checks now pass on 04c03ef296 (28 passing, 8 skipped), including Full Validation and the Required Merge Gate. It is ready to merge once approved.
  • #258: AuxPoW header payload size. Confirmed, with a wider effect than reported.
    • A block with a 1,900,290-byte auxpow header has a weight of 1,900,436, so it is accepted to the active chain.
    • The payload stays resident in the in-memory block index.
    • Three such headers in one headers reply total 5.7 MB. That exceeds the 4 MB receive limit, so the requesting peer disconnects.
    • Status (2026-10-30): Tracked in #266 (djh58), which Codex approved. It byte-caps getheaders replies and serializes them outside cs_main, falls back to inv for oversized announcements, and adds a rule that treats a byte-limited reply as not final. #272, stacked on djh58's branch, adds 8 unit tests and doc/release-notes-266.md, and Codex approved it. Because it is stacked, CI runs only after it is merged into net: bound the size of headers messages we send #266's branch or retargeted. Review input on #266: the block index keeps the first copy of a header it receives, so a stored header with oversized AuxPoW can make a byte-limited reply look final. That disconnects outbound peers during IBD and repeatedly aborts low-work presync. The suggested fix is to reject header copies larger than the block-size bound, or to replace the stored payload when the block arrives. Still deferred: a consensus cap on auxpow size, and keeping payloads out of the in-memory block index. Update (2026-10-30, late): test: unit coverage and release notes for #266 #272 is merged into net: bound the size of headers messages we send #266's branch (head 1c03c4f132). Full Validation then failed in all seven Clang jobs, because Clang's thread-safety analysis rejects a lambda in one of the new tests (src/test/peerman_tests.cpp:578). A one-line fix annotates the lambda with the lock its caller already holds. It is verified locally with clang 21 and GCC: thread-safety errors, CI's warning set and clang-tidy with the repo config on all four C++ files net: bound the size of headers messages we send #266 changes, and the peerman_tests and headers_sync_chainwork_tests suites (23 cases) pass. It will be pushed to net: bound the size of headers messages we send #266 once it is signed.
  • #259: OP_CHECKDATASIGPQC bypasses the PQC cache. Confirmed. The bypass is the scope script: cache successful P2MR PQC signature checks #162 chose, and pqc_sigcache_tests/data_signatures_bypass_the_cache pins it. A valid data signature in a leaf that then fails is verified in full on every replay: 50 replays cost 50 backend verifications of about 1.9 ms each.
    • Status (2026-10-30): #265 is open against 1.x.x, and Codex approved head 98502488a2. OP_CHECKDATASIG(ADD)PQC now verifies through a new BaseSignatureChecker::VerifyPQCDataSignature hook. The caching checker stores verified successes only, in a separate salted 'D' domain, with the same store/consume rules and shared budget as script: cache successful P2MR PQC signature checks #162. Validation weight and error codes are unchanged. A failure cache was deliberately left out. The leftover denial-of-service risk (free full-cost invalid signatures, about 0.5 µs of handler time per witness byte) is recorded in the PR and release notes, with per-peer accounting as follow-up options. The coordinator reviewed the code. An independent adversarial review found no correctness, soundness, forwarding or concurrency defects; it ran 8 unit suites and feature_p2mr.py. Two optional low-severity test gaps remain: forwarding through DeferringSignatureChecker is untested, and no end-to-end test covers block connection consuming a 'D' entry stored by the mempool. The PR references Review finding: OP_CHECKDATASIGPQC failures bypass the PQC signature cache #259 without closing it. Update: script: cache verified P2MR data-signature checks (v1.0.1) #265 merged into 1.x.x (2026-10-30 17:33Z, 02a465d09c). Its fragment, doc/release-notes-265.md, still needs folding into the release: prepare v1.0.1 #181 v1.0.1 notes.
  • #260: signer leaves SLH-DSA secrets on the stack. Confirmed for v1.0.1. This corrects the comment below: 1.x.x does not have the scrub. It still vendors libbitcoinpqc v0.3.0, unchanged since v1.0.0. The scrub exists only on the unreleased Qbit-Org/qbit-libbitcoinpqc main branch (Zero SLH-DSA secret-key scratch before keygen/sign return qbit-libbitcoinpqc#5 and Burn released stack once per secret-key call instead of per SHA-2 block qbit-libbitcoinpqc#6).
    • Status (2026-10-30): Draft #268 is open against 1.x.x and blocked until an upstream tag exists. It imports Qbit-Org/qbit-libbitcoinpqc main edcea6cb89; the signed import's tree matches upstream exactly. It pins v0.4.0 in all 7 places that name the version, removes the crossbeam Cargo.lock exception that no longer applies, and adds a qbit-side stack-residue test. That test fails 6 checks on v0.3.0 and catches a 4 KiB-burn mutant. Keys and signatures are byte-identical to v0.3.0, so consensus is unchanged. Signing is about 9% slower, verification 1-9% slower, and each secret-key call needs about 17 KiB of stack. Alternative for v1.0.1: #270 (djh58) clears the released stack on the qbit side instead. It burns 32 KiB after each secret-key operation in src/crypto/pqc.cpp, which covers all four qbit call sites including DerivePQCKey. The library stays at v0.3.0, so no upstream tag is needed. The 32 KiB burn covers optimized builds, which use about 12 KiB; unoptimized Debug builds use more and are not fully covered. Decision (2026-10-30): upstream will be a semver patch release, Qbit-Org/qbit-libbitcoinpqc v0.3.1, built on a new release/0.3.x branch. It is v0.3.0 plus Require aggregate checks in public rulesets #5 and Fix PR 4 Windows and lint failures #6 (the stack scrub), the code fix from Avoid full synchronous P2MR keypool top-up from MarkUnusedAddresses #14 (UBSan), and the crossbeam RUSTSEC Cargo.lock bump. Upstream Pin libbitcoinpqc subtree to v0.3.0 #10 is held back for 0.4.0 because it adds a variant to the exhaustive public PqcError enum. A worker is preparing the release branch, the upstream PR, the release-checklist evidence and draft release notes, and is moving subtree: import libbitcoinpqc v0.3.1 signer stack scrub #268 onto that content. The maintainer then fast-forwards release/0.3.x, signs and pushes the v0.3.1 tag, and publishes the release; after that, subtree: import libbitcoinpqc v0.3.1 signer stack scrub #268 can leave draft. Update (2026-10-30, late): v0.3.1 is released. Release qbit-libbitcoinpqc 0.3.1 (signer stack scrub) qbit-libbitcoinpqc#15 merged, and the signed tag v0.3.1 is on ebd9092b2a (release). Upstream CI is green, and an independent review returned "ready to tag with notes". subtree: import libbitcoinpqc v0.3.1 signer stack scrub #268 now imports v0.3.1 (head 18943b770b) and is out of draft. test/lint/libbitcoinpqc-subtree-check.sh reports GOOD against the real tag, and Codex found no issues. Full Validation then failed in two jobs, no IPC, i686, DEBUG and TSan, depends, no gui. Both fail on the new stack-residue test's window check, and both are false positives of the test. No SK_SEED or SK_PRF copy is left on the stack in either job. On i686, the 32-bit position-independent burn function loads its GOT pointer with call/pop after reserving its array, which leaves a return address just below the zeroed bytes. Under TSan, every store in the burn loop calls into the TSan runtime below the array. Both were reproduced locally against the vendored v0.3.1. v0.3.2's burn is the same, so a newer library would not change this. A test fix is verified locally: it measures the longest zeroed run, allows up to 64 bytes written below it, and skips the inspection under TSan as under ASan and MSan. A 4 KiB-burn mutant still fails it on x86_64 and i686, and pqc_tests passes. The fix will be pushed once it is signed. The PR needs a maintainer approval. Upstream main also has the 0.3.1 metadata now (Forward-port 0.3.1 release metadata and provenance doc to main qbit-libbitcoinpqc#16, merged). v0.3.2 is ready as Release qbit-libbitcoinpqc 0.3.2 qbit-libbitcoinpqc#17. It contains all of upstream main with two changes. First, Pin libbitcoinpqc subtree to v0.3.0 #10's new Rust PqcError::OutOfMemory variant is removed, so -6 reaches Rust as Other(-6) and 0.3.x stays semver-compatible. Second, the unoptimized stack burn is larger. Its CI is green and Codex found no issues. cargo-semver-checks passes, and keys, signatures and verify codes are byte-identical to v0.3.1. An independent review returned "ready to tag with notes". It awaits merge, the signed tag and the release.
  • #261: bounded30 FORS+C margin and the wallet-local cap. Partly confirmed.
    • The 112-bit figure is wrong, because the verifier enforces the forced-zero index.
    • The standard FORS bound is about 118 bits at the full 2^30 cap, and at least 128 bits only up to about 2^26.6 signatures.
    • signrawtransactionwithkey starts each raw key's counter at 0 on every call.
    • Status (2026-10-30): #264 merged into 1.x.x (2026-10-30 16:52Z). Codex had approved head b0bc0e2d72. It adds a non-normative note, doc/reference/p2mr-signature-security.md. The note gives the model, a script, and a table: 128 bits up to about 2^26.6 signatures per key, and about 118.2 bits at the 2^30 limit. The PR also updates the help for signrawtransactionwithkey, descriptorprocesspsbt and importdescriptors: keys supplied by the caller are not usage-tracked across calls. It rewords the counter-enforcement sentence in doc/consensus/p2mr-v1.md §9 and changes no MUST text. Because that file changes, the P2MR v1 consensus review must cite a commit that includes this change. The PR references Review finding: bounded30 FORS+C index is 112 bits and the signature cap is wallet-local #261 without closing it. The release: prepare v1.0.1 #181 v1.0.1 release notes still need an entry for it.
  • #262: header-sync commitment bound wrap. Valid for v1.0.0. It was already fixed on 1.x.x by fix: resolve finalized mainnet CI failures #137, which has a regression test and a release-notes entry. The issue is closed.

Other open issues: disposition

Issue Release recommendation
#166 — consistent PQC limit-state labels Optional polish for this release. Shared translated labels are desirable; capitalization/translation inconsistency does not invalidate signing or accounting.
#70 — platform signing/notarization Complete platform signing if credentials are ready. Otherwise explicitly record a waiver for this release under the existing release policy; do not treat an older release's waiver as blanket approval. Signed tags, checksums, and attestation requirements still apply.
#152 — scheduled validation source Implemented on 1.x.x by #165. Verify deployment to the default-branch scheduled workflows and evidence naming the maintained source SHA, then close. No duplicate implementation needed.
#158 — IBD timeout forwarding Implemented on 1.x.x by #159. Confirm the effective workflow/harness configuration and close after integration. Full performance results remain a separate claim requiring measurements.

No open PRs or release milestone were present when this release plan was prepared. The new findings are tracked in the linked issues above.

Release completion checklist

Exit condition: Required fixes and release evidence are complete, all applicable gates pass for the final source/artifacts, and any consciously deferred item is explicitly documented in the release notes/trust record.

Activity

  1. kiwidream commented on Oct 22, 2026

    @kiwidream
    MemberAuthor

    1.x.x is frozen for v1.0.1-rc1 at 45e9e72c2d (#182). #181 is rebased onto it, and its release notes cover every merge since v1.0.0. Please don't merge anything else into 1.x.x until v1.0.1-rc1 is tagged. Open PRs against 1.x.x (currently #233) have been notified.

  2. kiwidream commented on Oct 27, 2026

    @kiwidream
    MemberAuthor

    Plan change (2026-10-27): v1.0.1 ships directly, without v1.0.1-rc1. No release candidate has ever been tagged in this repository, and release-process.md doesn't require one. #181 now sets the version to 1.0.1, at fb45d18.

    The RC's job in this plan was the packaged-binary smoke checks. v* tags can't be moved or deleted, so those checks now run before tagging:

    1.x.x stays frozen until v1.0.1 is tagged. #252 merged on 10-26, during the freeze. It is documentation only and is now covered by the v1.0.1 notes. The release trust doc becomes doc/release-trust-1.0.1.md. Publish with --no-prerelease --make-latest true; new drafts otherwise default to make-latest=false.

  3. djh58 commented on Oct 29, 2026

    @djh58
    Member

    New review findings for the release gate: #257 P2MR runtime stack bytes; #258 AuxPoW getheaders size; #259 data-signature cache gap; #260 v1.0.0 stack residue (1.x.x has the scrub); #261 bounded30 FORS/counter; #262 headerssync bound wrap.

  4. kiwidream commented on Oct 29, 2026

    @kiwidream
    MemberAuthor

    I triaged the 2026-10-29 findings against the v1.0.1 candidate fb45d18d7b. The results are in the new "Added to scope (2026-10-29)" section of the issue body. #262 is closed because #137 had already fixed it. One correction to the list above: 1.x.x does not have the libbitcoinpqc stack scrub. It still vendors v0.3.0, so #260 still applies to v1.0.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions