Skip to content

chore: better encrypted sqlite ergonomics#23231

Merged
Thunkar merged 6 commits into
merge-train/fairiesfrom
martin/sqlite-encryption-error
May 13, 2026
Merged

chore: better encrypted sqlite ergonomics#23231
Thunkar merged 6 commits into
merge-train/fairiesfrom
martin/sqlite-encryption-error

Conversation

@mverzilli
Copy link
Copy Markdown
Contributor

@mverzilli mverzilli commented May 13, 2026

Adds some structure to typical decryption errors, and a couple of convenience helpers for orchestrating encrypted store management from embedded wallet, so that the most basic usage is straightforward and downstream projects don't need to rewrite the same lines over and over.

mverzilli and others added 5 commits May 13, 2026 08:31
Replaces consumer-side string matching against sqlite3mc's "file is not
a database" family of messages with a typed error class carrying a
discriminant `code`. Three codes:

  - invalid_key_length            (pre-flight: key != 32 bytes)
  - encryption_not_supported_for_ephemeral
                                  (pre-flight: ephemeral + key)
  - decrypt_failed                (runtime: sqlite3mc page-1 decode failed —
                                   covers both wrong-key and no-key-on-
                                   encrypted-DB; sqlite3mc does not
                                   distinguish them on the wire)

The worker-to-main wire protocol gains an optional `encryptionCode` field
on `err` responses. The worker tags responses on the catch path; the main
thread re-throws as `SqliteEncryptionError` when the tag is present. Non-
encryption error paths are unchanged — they continue to raise plain
`Error` as before, so this is a non-breaking extension.

Strengthens the existing wrong-key / no-key / short-key / ephemeral+key
tests in encrypted_store.test.ts to assert on the typed class + code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Builds on the typed SqliteEncryptionError landed in the previous commit
to give the embedded wallet a one-call helper that opens its two stores
(PXE state + walletDB) encrypted-at-rest, with cohesive failure handling.

Adds:

  - EmbeddedWalletEncryptionError extends Error
      readonly storeName: 'pxe' | 'wallet'
      cause: SqliteEncryptionError
    Lets callers drive recovery UX based on WHICH store failed — PXE
    state is typically safer to wipe-and-rebuild from L1 than walletDB,
    which holds the user's accounts and senders.

  - openEncryptedEmbeddedStores(config, getEncryptionKey, log)
    Opens both stores in sequence with the same key callback (invoked
    once per store — required because AztecSQLiteOPFSStore.open transfers
    the key buffer to its worker and detaches the caller's view).

    On PXE decrypt failure: throws EmbeddedWalletEncryptionError(pxe);
    nothing to clean up.

    On wallet decrypt failure: closes the already-opened PXE store
    (best-effort, swallowing close() errors so the original surfaces),
    then throws EmbeddedWalletEncryptionError(wallet).

    On any non-decrypt error during the wallet open: still closes PXE,
    but re-throws the original error unwrapped — keeps the typed-error
    contract narrow to encryption-shaped failures.

Re-exported only from the browser entrypoint (sqlite3mc requires Web
Workers + OPFS); the node entrypoint uses LMDB and does not surface this.

The `openStore` parameter on the helper is an `@internal` DI seam for
tests (defaults to AztecSQLiteOPFSStore.open). Without it, unit tests
would require a browser environment the wallets package doesn't set up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two `if (...) return` lines tripped the workspace's `curly` rule. Wrap
both bodies in braces. No behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nges

Two CI failures surfaced when this PR's commits landed on top of the
recent next merge into merge-train/fairies. Both fixed here.

(1) playground/vite.config.ts: chunk-size-validator's `closeBundle` hook
fired before vite/rollup had flushed any output to disk, so the
`scandirSync('dist')` inside the validator failed with ENOENT on a build
that had otherwise transformed all modules cleanly. Switching to the
`writeBundle` hook (documented to run AFTER bundle is on disk) restores
the original intent. The previous behavior was an artifact of the
vite/rollup version bump that came in via the merge — `closeBundle` is
no longer guaranteed to run post-write in current vite. `writeBundle`
is the correct hook for "check what was just written" semantics.

(2) Moved openEncryptedEmbeddedStores + types from being re-exported by
`wallets/embedded/entrypoints/browser.ts` to a dedicated package
sub-path `@aztec/wallets/embedded/store-encryption`. Reason: every
consumer importing from `@aztec/wallets/embedded` (e.g. the playground,
which only uses `EmbeddedWallet`) was transitively pulling in
`@aztec/kv-store/sqlite-opfs` and its
`new Worker(new URL('./worker.js', import.meta.url))` chain into
`@aztec/sqlite3mc-wasm`. Vite's worker plugin then tries to bundle the
worker entrypoint statically, and since playground's
`vite-plugin-node-polyfills` only applies to the main bundle (not the
worker context), the build fails with "Rollup failed to resolve import
'vite-plugin-node-polyfills/shims/process'". The sub-path split keeps
the encryption-at-rest helper a real first-class API but ensures only
consumers that explicitly opt into it pay the bundle cost.

After (1): playground's chunk-size-validator now reports correctly
("Validating chunk sizes... index-*.js: 1789.59 KB / 1850 KB").
After (2): playground's main entrypoint drops by ~43 KB because the
sqlite-opfs import chain is no longer reachable from
@aztec/wallets/embedded. Net main bundle: 1789.59 KB (within limit).

All 24 wallets tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mverzilli mverzilli requested a review from Thunkar as a code owner May 13, 2026 10:17
@AztecBot
Copy link
Copy Markdown
Collaborator

Flakey Tests

🤖 says: This CI run detected 1 tests that failed, but were tolerated due to a .test_patterns.yml entry.

\033FLAKED\033 (8;;http://ci.aztec-labs.com/f2ef946742e44eec�f2ef946742e44eec8;;�):  yarn-project/end-to-end/scripts/run_test.sh simple src/e2e_epochs/epochs_high_tps_block_building.test.ts (308s) (code: 0) group:e2e-p2p-epoch-flakes

Copy link
Copy Markdown
Contributor

@Thunkar Thunkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@Thunkar Thunkar merged commit 2175120 into merge-train/fairies May 13, 2026
22 checks passed
@Thunkar Thunkar deleted the martin/sqlite-encryption-error branch May 13, 2026 20:29
AztecBot pushed a commit that referenced this pull request May 13, 2026
Adds some structure to typical decryption errors, and a couple of
convenience helpers for orchestrating encrypted store management from
embedded wallet, so that the most basic usage is straightforward and
downstream projects don't need to rewrite the same lines over and over.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@AztecBot
Copy link
Copy Markdown
Collaborator

✅ Successfully backported to backport-to-v4-next-staging #23236.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants