Skip to content

fix(wallet-toolbox): reserve stored explicit inputs whose source is already in the batch BEEF - #1138

Draft
GenericCPU wants to merge 3 commits into
bsv-blockchain:mainfrom
GenericCPU:fix/wallet-toolbox-reserve-stored-explicit-inputs
Draft

GenericCPU wants to merge 3 commits into
bsv-blockchain:mainfrom
GenericCPU:fix/wallet-toolbox-reserve-stored-explicit-inputs

Conversation

@GenericCPU

@GenericCPU GenericCPU commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Program and scope

  • Tracker or issue: fix(wallet-toolbox): findings from running the toolbox as a production IndexedDB wallet #1136 (finding 1)
  • Program gate(s) advanced: none; standalone defect fix
  • Why this change is needed: ActionBatchWorkspace.missingExplicitOutpoints skipped explicit inputs whose source transaction was already in sharedBeef (for example from inputBEEF). The planner used the BEEF copy, nothing reserved the stored output, and commitActionBatch rejected the batch with input <outpoint> was not reserved by this action batch. The workspace keeps skipping inputs whose source is in sharedBeef, except those this wallet stores, which it finds with a read-only findOutputs (scoped to the authenticated user, served by every StorageServer version) and reserves. External inputs carried in inputBEEF are never sent for reservation, so they cost no extra change reservation and cannot hit the batch capacity limit.
  • Explicitly out of scope: Funding selection, BEEF merging, the external-input path and the auto/legacy batch modes are unchanged. Cost: one read-only output lookup per BEEF-carried explicit input inside an open batch. The other findings in the issue each have their own pull request or are proposals.
  • Exact head SHA reviewed: 3e971254463fe2ae9c2504790c738b84e24ee4db

Impact

  • No public package source or manifest changed
  • Public package source or manifest changed; affected packages are listed below
  • Infrastructure source, dependency, image, or deployment configuration changed
  • Public API, exports, types, runtime targets, or browser/mobile behavior changed
  • Security-sensitive boundary changed
  • Documentation or examples changed

Affected packages/services and intended patch versions (publication occurs only
through the release workflow after approval): @bsv/wallet-toolbox patch.

Verification

  • Local commands and results (Node 24.22.0, pnpm, from the repository root at 3e971254463fe2ae9c2504790c738b84e24ee4db):
    • pnpm --filter @bsv/wallet-toolbox exec jest --watchman=false test/Wallet/action/actionBatch.test.ts: 61 passed, 61 total (whole actionBatch.test.ts suite). New test: "a stored explicit input is reserved even when inputBEEF already carries its source" and the negative "an external input carried in inputBEEF reserves nothing" (the external source is created by a second wallet with separate storage). Without the source change it fails the stored-input test with WERR_INVALID_OPERATION: input <txid>.0 was not reserved by this action batch; a version that reserves every unclaimed input fails the negative test.
    • cd packages/wallet/wallet-toolbox && pnpm exec tsc --noEmit -p tsconfig.json: exit 0
    • pnpm exec oxlint <changed files>: exit 0, no warnings
    • pnpm exec prettier --check <changed files>: clean on every changed hunk
  • Hosted CI run: pending on this head
  • Conformance evidence: not applicable
  • Coverage delta: new regression test only
  • Lint/typecheck delta: none
  • Browser/mobile/packed-consumer evidence: the same fix runs in HandCash Desktop (Electron) and HandCash Mobile (Android WebView) on IndexedDB storage; see the reference links in the issue
  • Performance or bundle-size delta: none expected
  • I self-reviewed the complete diff for correctness, security,
    compatibility, public API, artifacts, dependencies, docs, and operations
  • All applicable checks are terminal and successful on the exact head; any
    scope-based skip is expected and validated by the merge gate

Security and dependencies

  • No dependency or lockfile change
  • Changelog, runtime relevance, peer compatibility, transitive graph, and
    audit results were reviewed
  • CodeQL/negative tests cover any changed trust boundary
  • The exact-head CodeQL analysis has no new alert
  • The exact-head repository quality gate reports zero new Sonar findings
    (including accepted or false-positive issue states) and zero unreviewed hotspots;
    Sonar's aggregate Quality Gate passed verdict alone is not merge evidence
  • No new override, advisory dismissal, quality suppression, or skipped test
  • Any temporary exception is registered with owner, evidence, review date,
    and removal condition
  • Workflow permissions and lifecycle-script behavior remain least privilege

Release and operations

  • No npm publication was performed from a workstation or from this PR
  • Required npm patch bumps are included or intentionally deferred by the
    controlling program (deferred to the release workflow)
  • Image/SBOM/provenance/deployment/rollback impact is documented
  • Documentation, changelog, migration, and operational guidance are current

Completion evidence

  • The linked tracker is updated only for work fully proved by merged code,
    passing checks, resolved alerts, measurements, or an approved exception
  • Review conversations are resolved
  • Documentation, changelog, migration notes, release notes, and operator
    guidance are current or concretely not applicable
  • No pending, failed, stale, cancelled, or unexpectedly skipped check is
    being handed to another contributor as "complete"
  • One qualified maintainer approval is sufficient; no last-pusher
    restriction is assumed

…lready in the batch BEEF

ActionBatchWorkspace.missingExplicitOutpoints skipped any explicit input
whose source transaction was already in sharedBeef, for example because the
caller passed it in inputBEEF. The planner then resolved the input from the
BEEF instead of storage, and commitActionBatch rejected the batch with
"input <outpoint> was not reserved by this action batch".

Reserve every explicit input the workspace has not staged or reserved.
Outpoints with no storage row still reserve nothing, so external inputs keep
resolving from the BEEF.

Co-authored-by: Cursor <cursoragent@cursor.com>
GenericCPU and others added 2 commits October 17, 2026 00:18
…n the batch BEEF

The previous commit reserved every explicit input the batch had not staged or
reserved. An external input carried in inputBEEF then cost a storage call,
reserved an extra change output and failed outright once the batch was full.

Keep the main-branch skip for inputs whose source is already in sharedBeef,
and reserve only those this wallet stores, found with a read-only findOutputs
scoped to the authenticated user. Adds a negative test: an external input
carried in inputBEEF is never sent for reservation and the batch commits.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

Copy link
Copy Markdown

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant