feat(wallet-toolbox): plan noSend batches locally and commit atomically - #289
Conversation
|
So much good stuff here :-) |
29ae61e to
9f00a94
Compare
Resolve the stacked PR conflicts against current main and preserve the shared auth/session migrations. Serialize wallet-local batch operations, scope capability negotiation per active provider, lock expired inputs before releasing reservations, avoid extension reservation leaks, and include staged noSend actions in special listings.
Reject excessive physical chunk lists and cap assembled logical blobs before allocation, preventing authenticated clients from amplifying a small uploaded chunk into unbounded database work and memory use.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…t at realistic fees Un-chained noSend batch staging fails WERR_INSUFFICIENT_FUNDS on a dust- fragmented wallet at feeModel sat/kb 100 while legacy mode succeeds on the identical wallet shape. The wallet is fragmented organically by the change generator itself; no rows are hand-crafted. Batch test is expected to fail until planFunding converges (target stays pinned at changeFirstSatoshis while requestedOutputs doubles and selectCanonicalChange keeps choosing dust).
Live E2E + unit test results: perf win confirmed, but batch funding fails deterministically on fragmented wallets at realistic fee ratesTested PR head Perf — realA/B on the same wallet/server, un-chained noSend sequences committed via
2.4× overall; staging alone is 942 ms vs 6,454 ms. Round-trips go 2N+1 → constant, so the advantage widens with N. 14 txids confirmed on mainnet across N=1/5/8 runs. Bug — batch staging dies with bogus
|
|
Addressed these review items in the latest commit, it should be good for another round of review now! |
…o codex/action-batch-atomic-commit # Conflicts: # pnpm-lock.yaml
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
|
All of the issues raised by @BraydenLangley have been addressed, so I am going to merge this and then focus on dependency management, versioning, security issues, and new releases stack-wide. |



Summary
Add an automatically negotiated Wallet Toolbox fast path for high-volume
noSendtransaction sequences:sendWith;The BRC-100 wallet interface,
CreateActionArgs,SignActionArgs,noSend,noSendChange,sendWith, and result shapes are unchanged. Providers that do not advertiseactionBatch: 1retain the legacy path before a workspace begins.Why
The existing behavior is correct but latency-bound for long transaction sequences. Every signed
noSendaction performs a storagecreateActioncall followed byprocessAction; the finalsendWithadds another call. A 250-action sequence therefore serializes 501 storage control calls.That cost is modest against a local database but dominates against remote storage. At 100 ms RTT, the storage-control component alone is approximately 50.1 seconds before transaction planning, signing, validation, payload transfer, persistence, or broadcast.
This change moves the middle of the workflow to the wallet process, where the keys and staged transactions already live, while preserving storage authority and an atomic remote durability boundary.
Stack status
This PR now targets current
maindirectly. Commit021951635mergesmainatf63482576(including #285) and resolves the integration conflicts while preserving the independent shared-session/auth migrations from #283.The post-merge review also hardens workspace concurrency, provider-scoped capability negotiation, expired-reservation reacquisition, failed-extension cleanup, staged
noSendlisting behavior, and logical blob assembly limits.Design
Capability negotiation and compatibility
actionBatch: 1.WalletArgs.actionBatchMode?: 'auto' | 'legacy', defaulting toauto.In-memory planning
returnTXIDOnly,knownTxids, commissions, custom inputs, two-step signing, deterministic output order, andnoSendChange.Reservations and lifecycle
Atomic commit and validation
Before persistence, validate:
noSendChange, and storage-controlled outputs.Persist transactions, outputs, labels, tags, mappings, and proof requests in one storage transaction. Consume reserved inputs and release unused reservations in that same transaction.
Broadcast remains outside the database transaction. Persistence is idempotent by user, batch ID, and semantic manifest digest; retries reconcile the committed result without duplicating wallet state.
Large payload transport
Main changes
Benchmarks
Command:
Environment: local SQLite provider, Node v25.9.0, pnpm 10.33.2. The measured representative workload is a 250-action dependent chain with 1 KiB scripts and deterministic randomness.
Peak heap is GC-sensitive; the structural assertions are the stronger memory regression gate. They verify that staged records do not retain duplicate source transactions or locking scripts.
The modeled storage-control component for the same 250-action sequence is:
The benchmark retains 192 modeled cases across dependent, independent, mixed explicit-input, and two-step workloads; 1, 10, 50, and 250 actions; 1 KiB, 64 KiB, 1 MiB, and 4 MiB scripts; and 25/100/250 ms RTT.
It also physically executes 64 KiB, 1 MiB, and 4 MiB scripts. The 4 MiB one-action batch exercises the prepare/upload/commit path successfully. It is intentionally not presented as a local one-action speedup: on the measured machine, batch stage plus commit was about 2.53 seconds versus 1.47 seconds for legacy because validation and blob staging outweigh avoided local latency. The target benefit is long and/or remote sequences.
Validation
Completed locally after merging current
main:pnpm install --frozen-lockfilegit diff --checkThe prior hosted build/test failure was traced to two new suites reaching live chain-root validation and broadcast services. Their providers now use pinned hermetic service fixtures for both boundaries. The final hosted build/test job passed in 10m51s; CodeQL, Socket, SonarCloud, Codecov, docs, and both conformance checks also passed.
Not yet completed:
Reviewer notes
Suggested review order:
Wallet.ts,WalletStorageManager.ts, and the storage interfaces leave public BRC-100 behavior unchanged.returnTXIDOnly,knownTxids, two-step signing, andnoSendChangebehavior.[userId, batchId]key.Rollout considerations
A server-first rollout is safe:
automode;actionBatchMode: 'legacy'for controlled comparison or rollback.Intermediate workspaces are intentionally session-scoped. The final commit is the remote durability boundary.