Hello everyone
sharing a roadblock hit and how, I address it. With how NozyWallet was built, shielded sends were not reliable when the wallet depended only on Zebrad’s JSON-RPC for everything the prover needs (e.g. witness / Merkle-path style data). That stalled proving and was worrying until we mapped it to a concrete fix. We’re aligning the send path with the usual Zcash light-client stack: Zebrad + lightwalletd (gRPC compact blocks) + the wallet’s local Orchard witness / anchor checks against the node (as documented in our tree). I’ll post updates as the code lands.
What’s Done: No reliance on Zebrad position/authpath RPCs for proving; spends use local incremental witnesses + treestate check + local prove; lightwalletd + Zeaking already back compact sync and related tooling.
April was good the goal moving head start improving zeaking witness catch-up from the same compact bytes Zeaking already persists, so shielded send matches a compact-first story end-to-end: lightwalletd as the primary chain-data pipe into SQLite, Zebrad for treestate checks, broadcast, and other RPC that compact does not replace.
Sequencing: We’ve started Zeaking-focused work so the compact layer is dependable at scale; Phase 1 of the roadmap below is done in-tree. Next is Phase 2 (ergonomics across surfaces), then performance/tests/DX as listed. Wiring Nozy’s OrchardWitnessProvider to use LwdCompactStore for witness advancement (instead of or as a fallback to getblock JSON) is explicit planned core work once we’re happy with the compact sync UX and semantics surfaced through Zeaking.
Phase 1 — Reliability & clarity (shipped)
Phase 1 focused on reliable compact sync and clearer errors at the boundaries (Rust crate → HTTP companion → desktop → FFI → extension).
zeaking (crate)
-
connect_lightwalletd: fixed a move-after-use bug by cloning the URI for the error path (lwd/client.rs). -
Streaming (
GetBlockRange): stream errors now go throughmap_grpc_statusso callers get structured gRPCStatus(code / message) instead of treating them like generic transport failures (lwd/sync.rs). -
Public API:
SyncCompactOptions,SyncCompactStats,sync_compact_range_with_options, andcompact_sync_progress_heightare re-exported fromlwd/mod.rs.
Companion HTTP (api-server)
-
POST /api/lwd/sync/compact: optional JSON body fieldresume(same semantics asSyncCompactOptions.resume_from_store). -
Response:
range_start_requested,range_start_effective,range_end,blocks_written(replacing the old singlerange_startfield). -
HTTP status mapping (via
zeaking_status): Grpc → 502, Storage → 500, InvalidOperation → 400.
Desktop (Tauri)
-
lwd_sync_compact: optionalresumeon the request struct. -
Response:
range_start_requested/range_start_effective/range_end(replacingrange_start). -
zeaking_err: distinct codesLWD_GRPC,LWD_STORAGE,LWD_INVALIDwhere applicable.
UniFFI (zeaking-ffi) — breaking for generated bindings
-
lwd_sync_compact: new argumentresume: Option<bool>(last parameter). -
LwdSyncResultFfi:range_startreplaced byrange_start_requestedandrange_start_effective. Regenerate Kotlin / Swift after upgrading the dylib.
Browser extension
-
Companion sync can pass
resume: truefromcompanion-api.js;extensionApi.tstypings updated. -
Defaults stay safe:
resumeis off unless explicitly set;sync_compact_rangeunchanged for callers that do not opt in.
How we validated
-
cargo build --workspace -
cargo buildindesktop-client/src-tauri -
cargo test -
cargo test -p zeaking --features lightwalletd -
cargo fmt --all -- --check
ZecHub have an hackathon coming up Nozywallet will be a submission. Great time to show the community Nozy before submission in a retroactive grant, I still more work to do.