zallet-core: add zcash_ironwood_migration_backend dependency scaffold#623
Draft
dannywillems wants to merge 22 commits into
Draft
zallet-core: add zcash_ironwood_migration_backend dependency scaffold#623dannywillems wants to merge 22 commits into
dannywillems wants to merge 22 commits into
Conversation
Wire the backend-agnostic Orchard-to-Ironwood value-pool migration engine into the workspace as a first, minimal integration point. The zcash_ironwood_migration_backend crate is not yet published to crates.io; it currently lives only on the feat/ironwood-denominations branch of librustzcash while its API is still evolving. It is therefore pinned to that git branch rather than to a released crates.io version like the other librustzcash crates. Repoint it at a released version once one is published. The crate is added as a dependency of zallet-core, which both backend binaries statically link, so the engine and its git-sourced transitive librustzcash crates resolve identically across all three workspace lockfiles and utils/check-lockstep.sh stays green. The three lockfiles were regenerated together with utils/sync-lockfiles.sh. The new zallet_core::migrate module is only a scaffold: it re-exports the engine so the rest of Zallet has a single stable path to it, and does not depend on the shape of the engine's final API. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a pool-to-pool value-pool migration RPC surface to the wallet build,
following the existing json_rpc method conventions (one module per method,
each with a Response/ResultType alias, PARAM_*_DESC constants consumed by the
OpenRPC build script, and a call function invoked from WalletRpcImpl):
z_startpoolmigration schedule a migration between two pools
z_getpoolmigrationstatus report a migration's status
z_advancepoolmigration advance a migration by one step
z_cancelpoolmigration cancel a migration
z_listpoolmigrations list known migrations
The surface is generic, not hardcoded Orchard to Ironwood. It is parameterised
by a Pool pair ("sapling", "orchard", "ironwood"), and a single shared table,
SUPPORTED_MIGRATIONS, is the one extension point: it maps each supported pool
pair to the network upgrade that enables it (Orchard to Ironwood requires
NU6.3). Adding a pool pair there makes it selectable across the whole surface.
Pool names and the not-implemented message are named constants, not literals.
This is a scaffold. Each method validates its inputs (pool parsing, the
supported-pair table, and that the enabling network upgrade is active at the
wallet's chain height), but the call into the migration engine returns a clear
"not implemented yet" error. The engine (zcash_ironwood_migration_backend) is
still evolving upstream, so nothing here depends on the shape of its final API.
The response types are defined so the rpc.discover schema documents the intended
shapes; MigrationPhase is marked with expect(dead_code) until the engine
constructs it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the read-only planning slice of the pool-migration surface: a new `z_previewpoolmigration` RPC that reads an account's spendable source-pool balance and runs the note-split planner (`zcash_ironwood_migration_backend::note_splitting`) to return the proposed decomposition into self-funding notes: the crossing denominations, the residual left behind, and the reserved prep fee. It plans only; nothing is scheduled, built, proved, or broadcast, so unlike the rest of the migration surface it does not depend on the unreleased Ironwood PCZT builder. Inputs are validated (the supported pool pair and its enabling network upgrade, the strategy name, and the account); the response is a documented, schema-typed plan. The strategy object is not `Send`, so the name is validated before any wallet I/O and the strategy is built after the last await. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename the migration engine dependency from zcash_ironwood_migration_backend to zcash_pool_migration_backend (renamed upstream to a pool-agnostic name) and repoint it, for local development, at a relative path to the checked-out worktree of the feat/pool-migration-engine branch. This is not portable and must not be pushed as-is; the Cargo.toml comment records the git-rev form to switch to first, and its prerequisite (the engine commit that introduces the current MigrationBackend trait is not yet on any remote). Rewrite z_previewpoolmigration against the engine's planning slice. It now enumerates the account's individual spendable Orchard notes (mirroring z_listunspent's selection and confirmation filter) and calls engine::plan_migration over SpendableSnapshot, Zallet's MigrationBackend implementation. The response reports the reconciled funding notes with each note's crossing denomination, its transfer broadcast height and expiry, the raw note-split summary, and the note-preparation summary. The old strategy parameter is dropped: the engine no longer exposes a strategy choice, so the method takes only account, from_pool, to_pool, and minconf. SpendableSnapshot is planning-only: the engine's persistence methods (store/load/update) are not supported, so committing a migration stays behind the not-implemented start/status/advance/cancel/list scaffold until the engine adds its build, sign, and persist slices. The prep fee reserved for the note split and preparation planner is derived from the crate's own constants (PREP_TX_ACTIONS times the ZIP-317 marginal fee), not a hardcoded literal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update the migrate integration entry for the renamed engine crate and its MigrationBackend impl, and record z_previewpoolmigration as the fully-wired planning preview of the pool-migration surface. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the local-development path dependency on the migration engine crate with a git dependency pinned to the commit that carries the engine API this integration uses (the MigrationBackend trait plus engine::plan_migration), now that it is pushed to librustzcash. Regenerate the workspace and backend lockfiles for the git source. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point the git dependency at the engine commit that adds commit_preparation and commit_transfers (the two-phase build/sign path). The MigrationBackend trait the preview integration uses is unchanged, so this is a rev bump plus lockfile regeneration. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI resolves the git dependency via the canonical https://...librustzcash.git URL (GitHub Actions rewrites git URLs), so a lock recorded against the no-.git form is seen as out of date under --locked (the vet and Docker build jobs failed with "the lock file needs to be updated"). Use the .git form, matching the repository convention (the age patch), and regenerate the workspace and backend lockfiles. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dannywillems
force-pushed
the
feat/ironwood-migration-backend-dep
branch
from
July 18, 2026 08:44
3fff95d to
526b6de
Compare
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bump the librustzcash pin to the rev that carries the S1/S2/S3 slices: the PoolMigrationRead/PoolMigrationWrite store traits, the zcash_pool_migration_sqlite store crate, and the WalletMigration wallet-backed adapter (the `wallet` feature). This is the foundation for wiring z_startpoolmigration and the companion RPCs onto the real engine commit path. S1 split persistence out of MigrationBackend into the store traits, so the planning-only SpendableSnapshot no longer implements store_migration / load_migration / update_transaction; it now implements just the two query methods and is infallible. The preview RPC's error mapping and its test backend follow suit. zallet-core builds against the new pin. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the not_implemented scaffolds for z_startpoolmigration, z_getpoolmigrationstatus, z_listpoolmigrations, and z_cancelpoolmigration with real bodies over the migration engine and the SQLite store. start plans and pre-signs the preparation transactions over the account's wallet (WalletMigration adapter) and persists the committed migration (its pre-signed PCZTs plus metadata) to the store; it derives the spending key before the blocking build section, runs the engine against an in-memory store, then persists the returned state to SQLite over one connection sequentially, and refuses to overwrite a migration that is still in progress. status and list read the persisted state; cancel marks it cancelled. Nothing is proved or broadcast here, so no transaction reaches the chain. The store holds one migration at a time, named by a fixed identifier. Proving and broadcasting the pre-signed transactions (z_advancepoolmigration) is the remaining step; until it is wired a committed migration cannot make on-chain progress. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The zebra and zaino backend workspaces patch the librustzcash stack independently of the main workspace; bump their pins to match so they build against zallet-core's re-pinned dependencies. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Advance drives a committed migration forward one step per call: it detects newly mined transactions (get_tx_height, which reports only a tx mined at or below the tip), proves and extracts the next due pre-signed transaction, and broadcasts it; once every preparation is mined it builds and pre-signs the phase-2 transfers. Proving runs in the blocking database section and broadcast runs async, so no await occurs under the write lock. Migration transactions are Orchard-shaped, so both the Orchard and Ironwood bundles prove with one orchard::circuit::ProvingKey and verify with one VerifyingKey; the circuit version is the Orchard bundle version for the tip's consensus branch (NU6.3 = revision 3). Adds the pczt dependency (prover, tx-extractor, orchard). Known: the lifecycle is compile-checked here and must still be driven end to end on a funded regtest migration; expiry/reorg recovery is not yet handled. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The zebra and zaino backend workspaces have their own lockfiles; regenerate them so the bumped patch pins resolve under --locked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The engine now commits a multi-layer preparation phase by phase: start builds and pre-signs only the first layer, and each later layer is built once its predecessor is mined. Re-pin onto that engine revision and teach the advance state machine the intermediate step: after nothing is left to broadcast but before the transfers, build the next preparation layer whose dependencies are mined (commit_pending_preparation_over_wallet), so its transactions become broadcastable. The transfers still build only once every preparation layer is mined. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dannywillems
commented
Jul 18, 2026
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { |
Contributor
Author
There was a problem hiding this comment.
Useless. Can be removed.
Multi-layer preparation is supported now (committed layer by layer), so the CommitFailure::UnsupportedMultiLayer variant and its "not yet supported" RPC message are dead and misleading; remove them (the residual engine variant maps to a generic build failure). Refresh the module docs that still described the surface as a scaffold with an unwired advance and a not_implemented start, drop the now-broken intra-doc link to the removed not_implemented helper, and remove the "stubbed" notes on MigrationPlan/MigrationProgress (both are real). Remove the pool_migration unit tests, which only restated the table. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align zcash_note_encryption across the three workspaces: root and zebra resolve 0.4.1 while zaino had floated to 0.4.2, tripping the wallet-critical lockstep check. Pin zaino back to 0.4.1 (already audited safe-to-deploy in every workspace), the minimal change that restores lockstep without a new vet gap. Exempt darling and serde_with (pulled in transitively by pczt, which the migration advance uses to prove and extract) in the root and zaino supply-chain configs; zebra already exempted them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The engine dropped CommitError::UnsupportedMultiLayer (multi-layer preparation is fully supported), so remove the corresponding map_commit_error arm and re-pin to that revision. The revision changes no dependencies, so the lockfiles move only the git rev and the wallet-critical lockstep is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tatus A multi-layer migration cannot be pre-signed up front (later layers become witnessable only as earlier layers mine) and a mobile wallet may be restarted between layers, so it needs to decide the next transaction to sign or broadcast from persisted state alone. z_getpoolmigrationstatus now returns, per transaction, its kind, layer (anchor bucket), lifecycle state, dependencies, schedule, whether it is ready to act on now and with which action (build-and-sign or prove-and-broadcast), or otherwise what it is waiting on (its dependencies mining, or its scheduled height). The status RPC reads the chain tip to decide which scheduled transactions are due. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The migration state logic now lives in the engine as methods on MigrationState (the mobile wallet drives it the same way). Reduce zallet to a thin consumer: advance_blocking detects mining and does the wallet I/O around the engine's decision (state.next_step -> prove+broadcast / build the next preparation layer / build the transfers / wait), using state.mark_mined and state.mark_broadcast for the transitions; the per-transaction status RPC maps state.transaction_ statuses into the JSON-RPC shape. Remove the state helpers now owned by the engine (deps_mined, all_preparations_mined, has_ready_prep_layer, next_broadcastable, recompute_status, is_terminal) and re-pin to that engine revision. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The backend lockfile regeneration in an earlier re-pin floated many of zaino's transitive dependencies (aws-lc-rs, tokio, and others) ahead of the versions its supply-chain config vets, so cargo-vet reported 81 unvetted crates. Rebase the zaino lockfile on main's vetted versions and add only the migration engine dependencies on top, and restore the root and zebra lockfiles to their minimal pre-churn state, all still pinned to the engine revision. Wallet-critical lockstep and zcash_note_encryption 0.4.1 are preserved; cargo-vet passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-pin to the engine that preserves a terminal status, and guard advance so a terminal migration (complete, or cancelled/failed) is not driven: it reports its status and does nothing, so a cancelled migration cannot be resurrected. The revision changes no dependencies, so lockstep is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Wires the new backend-agnostic
zcash_ironwood_migration_backendcrate (the Orchard -> Ironwood migration engine) into zallet as a dependency scaffold, independent of the crate's still-evolving API.zcash_ironwood_migration_backendpinned to thefeat/ironwood-denominationsgit branch ofzcash/librustzcash(the crate is unpublished; to be repointed at a release later).zallet-corevia a thinzallet_core::migratescaffold module (a whole-crate re-export, no coupling to the evolving API), so all three workspaces (root, backends/zebra, backends/zaino) resolve its git-sourced transitive librustzcash crates identically andcheck-lockstep.shstays green.utils/sync-lockfiles.sh; CHANGELOG entry included.Note: the separate "sync existing librustzcash deps" commit was a verified no-op (all pins already at their latest published versions), so this is a single commit. Verified:
cargo test194 passed, both backendscargo checkclean, fmt/clippy clean, lockstep OK.Draft; part of the Ironwood migration effort. Do not merge yet.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com