feat: wire PXE and walletDB to SQLite-OPFS (opt-in)#17
Open
feat: wire PXE and walletDB to SQLite-OPFS (opt-in)#17
Conversation
End-to-end persistence of both PXE state and the wallet's own account DB
on the OPFS-backed sqlite-opfs kv-store backend (new in aztec-packages).
The rollup address scopes DB names so switching networks doesn't
cross-contaminate; each store uses a distinct OPFS SAH-Pool directory
because the pool acquires an exclusive lock per directory.
- src/services/walletService.ts: construct two AztecSQLiteOPFSStore instances
and pass them via { pxe: { store }, walletDb: { store } }. Dev-mode
registers console-accessible inspectors.
- src/utils/sqliteInspector.ts: dev-only helper exposing window.__aztecStores
with downloadPxe()/downloadWallet() (exports a real .sqlite image) and
summary() for a quick container+row-count overview.
- package.json: add @aztec/kv-store as a direct dep — it's imported from
source now, so yarn needs to keep it in the tree.
Infra updates to support linked aztec-packages:
- scripts/toggle-local-aztec.js: @aztec/wallets added to PACKAGE_MAPPINGS
(was missing); VITE_FS_ALLOW_PATHS extended with kv-store and
@sqlite.org/sqlite-wasm paths so Vite can serve the worker + wasm.
- vite.config.ts:
* resolve.alias now dynamic — reads .local-aztec-path for the
aztec-packages root, so no user-specific paths get committed.
* wasmContentTypePlugin forces Content-Type: application/wasm on
.wasm responses (sqlite-wasm's streaming compile needs this).
* optimizeDeps.exclude adds @sqlite.org/sqlite-wasm — Vite's prebundle
breaks colocated .wasm asset resolution.
* nodePolyfillsFix returns absolute paths so Buffer imports from
files linked outside the workspace root resolve correctly.
Enables testing from devices on the same network (iPhone via mkcert-trusted HTTPS) or through a public tunnel (ngrok, cloudflared). The allowedHosts list covers rotating free-tier ngrok subdomains and ephemeral trycloudflare tunnels — tighten or replace with a specific domain if you want to restrict further. Usage: yarn dev # LAN access at https://<mac-IP>:5173 ngrok http 5173 # public HTTPS tunnel, URL printed by ngrok
Reviewer rightly asked why this one entry points at node_modules when the others point at workspace source trees. The short answer is that sqlite-wasm is a real npm package (not a workspace), and it's a transitive dep of @aztec/kv-store that yarn link: doesn't surface into the consumer. Declaring it as a direct dep of gregoswap would not help, because Vite resolves worker imports from the worker file's location (in aztec-packages), not from the consumer's root. Comment expanded inline so the next reviewer doesn't have to re-derive this.
mverzilli
commented
Apr 20, 2026
Comment on lines
+46
to
+72
| // Both PXE state and the wallet's own DB go on SQLite-OPFS. Each store needs a | ||
| // distinct OPFS pool directory because SAH Pool acquires an exclusive lock on | ||
| // its directory — one shared directory would collide in a single tab. The | ||
| // rollup address scopes the DB names so switching networks doesn't | ||
| // cross-contaminate. | ||
| const l1Contracts = await node.getL1ContractAddresses(); | ||
| const rollup = l1Contracts.rollupAddress.toString(); | ||
| const pxeStore = await AztecSQLiteOPFSStore.open( | ||
| createLogger('pxe:data:sqlite-opfs'), | ||
| `pxe_data_${rollup}`, | ||
| false, | ||
| `.aztec-kv-pxe-${rollup}`, | ||
| ); | ||
| const walletStore = await AztecSQLiteOPFSStore.open( | ||
| createLogger('wallet:data:sqlite-opfs'), | ||
| `wallet_data_${rollup}`, | ||
| false, | ||
| `.aztec-kv-wallet-${rollup}`, | ||
| ); | ||
| const wallet = await EmbeddedWallet.create(node, { | ||
| pxe: { proverEnabled: true, store: pxeStore }, | ||
| walletDb: { store: walletStore }, | ||
| }); | ||
| if (import.meta.env.DEV) { | ||
| // Expose dev-only inspectors at `window.__aztecStores`. See sqliteInspector.ts. | ||
| registerSqliteInspectors({ pxe: pxeStore, wallet: walletStore }); | ||
| } |
Contributor
Author
There was a problem hiding this comment.
TODO: this should maybe be reified in embedded-wallet, but while the grego-mono-repo is in the works, this shows what's needed
mverzilli
commented
Apr 20, 2026
| walletDb: { store: walletStore }, | ||
| }); | ||
| if (import.meta.env.DEV) { | ||
| // Expose dev-only inspectors at `window.__aztecStores`. See sqliteInspector.ts. |
Contributor
Author
There was a problem hiding this comment.
Just a devtool convenience
mverzilli
commented
Apr 20, 2026
| @@ -0,0 +1,73 @@ | |||
| /** | |||
Contributor
Author
There was a problem hiding this comment.
This file is just an ad-hoc tool which helps observe what's going on, considering unlinke IndexedDB, we don't get any out of the box storage inspection support from the browser
mverzilli
commented
Apr 20, 2026
| // Accept Host headers from tunnel providers without needing per-URL config. | ||
| // Wildcards cover rotating ngrok-free subdomains; trycloudflare.com covers | ||
| // ephemeral Cloudflare tunnels. Tighten if you want to restrict further. | ||
| allowedHosts: ['.ngrok-free.app', '.ngrok.app', '.trycloudflare.com'], |
Contributor
Author
There was a problem hiding this comment.
Used to test on iPhone via tunnels, will probably remove from final PR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Uses the new
@aztec/kv-store/sqlite-opfsbackend for both PXE state and the EmbeddedWallet's walletDB, replacing the default IndexedDB stores. The new backend persists to the browser's Origin Private File System viasqlite-wasm'sopfs-sahpoolVFS.Gregoswap is the reference consumer for exercising the sqlite-opfs backend on real testnet traffic before we upstream a broader switch.
Changes
src/services/walletService.tsConstructs two
AztecSQLiteOPFSStoreinstances — one for PXE, one for walletDB — and passes them via the newpxe.store/walletDb.storehooks onEmbeddedWallet.create. Each store uses a distinct OPFS pool directory (SAH Pool acquires an exclusive lock per directory, so two stores in one tab can't share one) and a rollup-address-scoped DB name so switching networks doesn't cross-contaminate state.In dev mode, registers
window.__aztecStoreswith ad-hoc query +exportDb()helpers (seesrc/utils/sqliteInspector.ts) for browser-console inspection.src/utils/sqliteInspector.ts(new)Small dev-only helper: exposes
downloadPxe()/downloadWallet()(grabs a real.sqliteimage you can open in DB Browser for SQLite / sqlite3 CLI) andsummary()(container → row-count overview). Tree-shaken out of production builds viaimport.meta.env.DEV.package.jsonAdds
@aztec/kv-storeas a direct dep — it was only reaching gregoswap transitively, and the yarnlink:resolutions used bylocal-aztec:enabledon't propagate workspace deps, so making it explicit keeps the dep tree stable across installs.scripts/toggle-local-aztec.js@aztec/walletstoPACKAGE_MAPPINGS(was missing — my edits to the wallets package weren't reaching gregoswap until this landed).VITE_FS_ALLOW_PATHSwith the kv-store worker path and the@sqlite.org/sqlite-wasmnode_modules path so Vite's dev server can serve them.vite.config.tsFour dev-setup additions, all gated/scoped so they're no-ops without local-aztec:
resolve.aliasfor transitive workspace deps that yarnlink:doesn't surface (@aztec/bb.js,@aztec/noir-acvm_js,@aztec/noir-noirc_abi,@sqlite.org/sqlite-wasm). The paths are read dynamically from.local-aztec-path(the file the toggle script writes), so no user-specific absolute paths get committed.wasmContentTypePlugin— forcesContent-Type: application/wasmon.wasmresponses. Without this,WebAssembly.compileStreaming()(used by sqlite-wasm's Emscripten init) rejects with an incorrect-MIME error.optimizeDeps.exclude: ['@sqlite.org/sqlite-wasm']— Vite's prebundle extracts the JS but doesn't copy the adjacentsqlite3.wasmasset, so the generated fetch URL 404s. Excluding keeps the JS at its real location where the.wasmsits beside it. (Per the sqlite-wasm docs' recommendation.)nodePolyfillsFixreturns absolute paths — needed soimport { Buffer } from 'buffer'resolves correctly from files linked outside gregoswap's workspace root.server.host: true+allowedHostsfor ngrok-free / cloudflare-tunnel domains, so you can test from an iPhone against a remote dev server.Scope and safety
.aztec-kv-pxe-<rollup>/and.aztec-kv-wallet-<rollup>/directories populate in OPFS as expected.Test plan
yarn dev+ pick testnet in the network selector → wallet creation succeeds..aztec-kv-pxe-*and.aztec-kv-wallet-*subdirectories.window.__aztecStores.summary()in DevTools console returns container/row-count summaries for both stores.Related