Skip to content

fix(deps): bump @bsv/wallet-toolbox to 2.10.1 for both proof-task deadlock fixes - #78

Open
imranterranode wants to merge 1 commit into
bsv-blockchain:masterfrom
imranterranode:feature/bump-wallet-toolbox-2.10.1
Open

fix(deps): bump @bsv/wallet-toolbox to 2.10.1 for both proof-task deadlock fixes#78
imranterranode wants to merge 1 commit into
bsv-blockchain:masterfrom
imranterranode:feature/bump-wallet-toolbox-2.10.1

Conversation

@imranterranode

Copy link
Copy Markdown

Every released build of BSV Desktop cannot fetch merkle proofs. v2.8.1 pins @bsv/wallet-toolbox 2.4.4, which contains two self-deadlocks in StorageKnex. Both are the same mistake — a method drops the caller's transaction token, so its query asks the pool for a second connection while the caller's transaction holds the first. knex forces {min:1, max:1} on sqlite, so it can never be granted and the task dies after acquireConnectionTimeout:

KnexTimeoutError: Timeout acquiring a connection. The pool is probably full.
Are you missing a .transacting(trx) call?

TaskCheckForProofs therefore fails before processing any request, which is why an affected wallet's proven_tx_reqs backlog sits at zero attempts — the rows are never reached rather than tried and failed.

Downstream, BEEF payment ancestry never terminates at a proven parent, so x-bsv-payment headers grow without bound until a Cloudflare-fronted origin refuses the request at its 32KB header cap — after the wallet has already broadcast and paid.

Why 2.10.1 and not 2.6.x

The two fixes shipped in different releases, and the second one is the reason this PR isn't a smaller bump. Verified by unpacking the published tarballs rather than trusting release notes — the signature of readSettings is the tell:

toolbox getProvenOrRawTx readSettings
2.4.4 (shipped in v2.8.1) drops trx readSettings() — no param
2.6.2 – 2.6.5 trx forwarded readSettings() — no param
2.7.0 → 2.10.1 trx forwarded readSettings(trx)

Fixed upstream by ts-stack#426 (published 2.6.0) and ts-stack#444 (published 2.7.0). Landing any 2.6.x would ship only half the fix.

The @bsv/sdk bump is forced, not incidental

wallet-toolbox declares peerDependencies: { "@bsv/sdk": "^2.4.0" } from 2.7.0 onwards — the same release that carries the readSettings fix. The two cannot be separated. Checked that every other @bsv/* dependency accepts it: amountinator, btms, btms-permission-module and message-box-client all ask for ^2.1.6, and btms-permission-module wants wallet-toolbox-client ^2.3.3 (satisfied by 2.4.4).

2.10.1 also carries 96e888612, which raises minimumDesiredUTXOValue off the historic 32 satoshis. That mismatch against the 96-satoshi dust floor is the other half of the header-growth problem, so it lands here for free.

wallet-toolbox-client deliberately stays at 2.4.4

Its newer releases are bundled packages whose exports map blocks the deep /out/src/... paths this app imports across six files (config.ts, WalletContext.tsx, StorageElectronIPC.ts, WalletService.ts, AddEntityModal.tsx, TrustedEntity.tsx). That is a separate, mechanical migration and unrelated to this defect, which lives in StorageKnex — Electron main only.

Upgrading is one-way — please read before merging

This bump takes the toolbox migration ledger from 17 to 21. They are forward-only, applied on first launch by electron/storage.ts:156:

+ 2026-07-26-001  retain prepared action batch manifests
+ 2026-08-02-001  add createAction funding selection index
+ 2026-08-04-001  add payment replay claims
+ 2026-08-10-001  upgrade managed change liquidity defaults   ← mutates data, not just schema

The last one rewrites change-management settings rather than adding a table, so a user who launches this build and then reinstalls v2.8.1 will not get those settings back. That is inherent to taking the upstream fix, but it should be a deliberate decision rather than a surprise.

No test in this repo opens a populated wallet database, so I exercised the migration path locally against two populated databases — one testnet, one mainnet — reproducing exactly what electron/storage.ts:150-158 does on startup:

database size rows before migrating result
testnet 12.1 MB 37 transactions, 260 outputs, 11,799 monitor events +4 migrations in 21 ms, no rows lost, integrity_check ok
mainnet 36.7 MB 508 transactions, 1,178 outputs, 246 proven_txs, 474 proven_tx_reqs, 25,476 monitor events +4 migrations in 10 ms, no rows lost, integrity_check ok

Row counts in every tracked table (users, transactions, outputs, proven_txs, proven_tx_reqs, monitor_events) were identical before and after, and PRAGMA integrity_check returned ok on both.

Developers now need Node ≥ 22

@bsv/sdk 2.4.0, @bsv/wallet-toolbox 2.10.1 and better-sqlite3 all declare engines.node >= 22, and on Node 20 npm install now dies in postinstall at electron-builder install-app-deps@electron/rebuild (which already required >=22.12.0 on master). Verified on 24.13.0. I have deliberately not added an engines field or .nvmrc here so this stays a pure dependency bump — happy to follow up with one if you'd like it enforced.

Testing

  • npm run build passes — this covers both sides, since build:renderer is tsc && vite build and build:electron is tsc -p tsconfig.electron.json.
  • npm test 15/15 · npm run test:tokens 58/58 · npm run test:stas:db 32/32, including the four migration.test.ts cases that drive StorageKnex over knex+sqlite.
  • Ran the app against an isolated profile on 2.10.1: wallet created, all 21 migrations applied, storage served listOutputs/listActions continuously, monitor tasks (ReviewProvenTxs, ReconcilePendingTransactions, NewHeader) all recorded events, and zero KnexTimeoutError occurrences.
  • The lockfile's net reduction is deduplication, not dropped dependencies: of 43 removed entries, 42 are nested copies collapsed under @bsv/wallet-toolbox, plus one orphaned transitive (encoding). 1202 → 1161 entries.

Unrelated foot-gun found while verifying

electron/main.ts:144 hardcodes mainWindow.loadURL('http://localhost:5173'). If anything already holds that port, vite prints "Port 5173 is in use, trying another one…", moves to 5174, and Electron silently loads whatever is on 5173 — in my case a stale dev server, which nearly invalidated this verification. Not touching it here, but it's worth a separate fix to read the actual port.

…dlock fixes

2.4.4 contains TWO self-deadlocks that stop proof fetching entirely. Both are the
same mistake: a StorageKnex method drops the caller's transaction token, so its
query asks the pool for a second connection while the caller's transaction holds
the first. knex forces {min:1,max:1} on sqlite, so it can never be granted and the
task dies after acquireConnectionTimeout with

  KnexTimeoutError: Timeout acquiring a connection. The pool is probably full.
  Are you missing a .transacting(trx) call?

  1. getProvenOrRawTx(txid, trx) dropped trx on its findProvenTxs call.
     Fixed upstream by ef710c3 (bsv-blockchain/ts-stack#426), published in 2.6.0.
  2. readSettings() took no trx at all, so verifyReadyForDatabaseAccess deadlocked
     on the same pool. Fixed by 4958767a5 (#444), published in 2.7.0.

TaskCheckForProofs therefore fails before processing any request, which is why an
affected wallet's proven_tx_reqs backlog sits at zero attempts -- the rows are
never reached rather than tried and failed.

Downstream this makes BEEF payment ancestry never terminate at a proven parent, so
x-bsv-payment headers grow without bound until a Cloudflare-fronted origin refuses
the request at its 32KB header cap -- after the wallet has already broadcast and
paid.

Observed on a real wallet running the released build: 2,532 monitor error events,
340 proof requests outstanding at 0 attempts, 433 unproven transactions. Applying
the equivalent fix moved proven_tx_reqs completed 18 -> 119, outstanding 139 -> 38,
and the payment header 33,058 -> 13,666 bytes, with a wallet Cloudflare had been
refusing paying again.

Verified by unpacking the published tarballs rather than trusting release notes:

  version   getProvenOrRawTx   readSettings
  2.4.4     drops trx          no trx param
  2.6.2     trx forwarded      no trx param
  2.10.1    trx forwarded      trx forwarded

Landing 2.6.x would therefore have shipped only half the fix.

@bsv/sdk moves ^2.2.0 -> ^2.4.0 because it has to: wallet-toolbox declares
peerDependencies @bsv/sdk ^2.4.0 from 2.7.0 onwards, which is the same version that
carries the readSettings fix, so the two cannot be separated. Checked that every
other @bsv/* dependency accepts it -- amountinator, btms, btms-permission-module and
message-box-client all ask for ^2.1.6.

2.10.1 also carries 96e888612, which raises minimumDesiredUTXOValue off the historic
32 satoshis. That mismatch against the 96-satoshi dust floor is the other half of the
header-growth problem, so it lands here for free.

@bsv/wallet-toolbox-client is deliberately left at 2.4.4. Its newer releases are
bundled packages whose exports map blocks the deep '/out/src/...' paths this app
imports across six files. That is a separate migration and unrelated to this defect,
which lives in StorageKnex -- Electron main only.

NOTE FOR DEVELOPERS: this raises the effective minimum Node for a local install to
22. @bsv/sdk 2.4.0, @bsv/wallet-toolbox 2.10.1 and better-sqlite3 all declare
engines node >=22, and on Node 20 npm install now dies in the postinstall step
(electron-builder install-app-deps -> @electron/rebuild, itself already requiring
>=22.12.0 on master). Verified on Node 24.13.0.

npm run build passes (renderer tsc + vite, electron tsc). Tests: 15/15 default,
58/58 test:tokens, 32/32 test:stas:db including the four migration tests that
exercise StorageKnex over knex+sqlite.
@imranterranode

Copy link
Copy Markdown
Author

@sirdeggen would you have time to take a look at this one when you get a chance? It is a dependency bump only — package.json moves @bsv/sdk to ^2.4.0 and @bsv/wallet-toolbox to ^2.10.1, and everything else in the diff is the regenerated lockfile.

Also, whenever someone with write access has a spare minute: Install and Test is sitting at action_required on 469d41e, since fork PRs need the runs approved. No rush.

@ty-everett — thanks for validating the combination in #79, and for flagging the lockfile. I dug into the missing encoding@0.1.13 and it is a slightly odd one:

  • Confirmed it is absent here relative to master (169 vs 170 "optional": true entries), so your observation is right.
  • It arrives as an optional peer of the node-fetch@2 nested under stas-js (peerDependenciesMeta: { encoding: { optional: true } }), rather than as a direct dependency.
  • npm 10.2.3 on Node 20 will not put it back: both npm install and npm install --package-lock-only leave it out, because npm skips optional peers when building the tree. So a plain lockfile refresh does not fix it from my side.
  • npm ci against this branch did not reject the lockfile for me either — no Missing ... from lock file, the tree reified fine, and it only failed later in electron-builder install-app-deps (a native rebuild issue local to my Mac).

Which npm version did you hit the npm ci failure on? If yours does include the optional peer, I am happy to copy master's node_modules/encoding block into this lockfile verbatim so the two trees agree — I just did not want to hand-edit a lockfile to fix something I could not reproduce. Worth noting too that CI here runs npm install rather than npm ci, so the gate should be unaffected either way.

@mo-jaber
mo-jaber requested a review from sirdeggen August 20, 2026 13:02
@mo-jaber

Copy link
Copy Markdown

friendly nudge to look at this when you get the chance @sirdeggen

@rohenaz

rohenaz commented Sep 1, 2026

Copy link
Copy Markdown

A current-master refresh aligned to the exact Sigma official-matrix versions is available in #86. It pins Wallet Toolbox 2.10.4 and SDK 2.4.2, refreshes the lockfile, and passes the default, token, STAS/SQLite, and full build gates without force-pushing this upstream branch.

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.

3 participants