Trim the signer_account_ids/PublicDiff explanation down to one canonical
location per concept instead of restating it at every call site, drop
dangling "See X" pointers in favor of letting readers look up the code
directly, and shorten the two malicious-victim test docstrings that
re-derived the same mechanism already covered elsewhere.
Separately, fix pre-existing clippy debt that was hidden behind compile
errors in the two guest binaries clippy could originally reach:
- update_from_diff implementations across most lez/programs/* guests,
test_methods_guests, test_programs/guest, and the program_deployment
examples returned Result<Data, Infallible> for no reason; now return
Data directly.
- unchanged(...) helpers made const fn.
- Program::execute_update_from_diff/prove_update_from_diff took Account/Data
by value without consuming them; now take references, dropping the
now-unnecessary clones at every call site.
- One redundant clone, one redundant closure, one large enum variant
(TxEvaluation::Accept now boxes its LeeTransaction), and four
if-let/else patterns simplified to map_or_else/bool::then in the
indexer FFI's AccountDiff/Claim conversions.
Rebuild every affected guest artifact and the prebuilt test fixture.
The privacy-preserving circuit's output no longer commits materialized
public-account post-states; it commits the raw AccountDiffs it produced
instead, plus a signer_account_ids set the sequencer cross-checks
against real signatures. Proof verification now checks the proof
against exactly what the circuit witnessed, with no dependency on live
sequencer state, fixing the race condition where an unrelated public
transaction landing between proving and validation would invalidate an
otherwise-valid proof. Materialization moves to a separate step that
replays public_diffs against whatever the live account state actually
is at apply time, mirroring how the public-transaction path already
applies diffs.
Also updates lez/indexer and lez/explorer_service for the new Message
shape, and fixes the pre-existing clippy debt this surfaced across
lez/programs (needless_pass_by_value/missing_const_for_fn/etc.) now
that the workspace builds and lints clean end to end.
Resolves needless_pass_by_value (take AccountWithMetadata/Account by
reference where only borrowed), unnecessary_wraps (drop Result<Data,
Infallible> from passthrough update_from_diff implementations),
missing_const_for_fn, useless_let_if_seq, arbitrary_source_item_ordering,
too_many_arguments, redundant_clone, and useless_conversion across the
guest programs and lee core touched by the incremental-updates rebase.
Programs now report AccountDiff/AccountDiffOutput instead of full
post-states; balance changes are applied via apply_balance_diff's
checked arithmetic at the protocol level rather than checked in-guest,
and data changes are materialized through a new update_from_diff
guest entrypoint (trusted execution for public transactions, proven
via a recursive receipt for the privacy-preserving circuit). All 15
production programs and test/example guest programs are converted;
attack-surface guest programs that are now structurally impossible
(nonce/program_owner mutation) or redundant (manual balance-sufficiency
bypass) are moved to a dormant/ directory rather than deleted outright.
UpdateFromDiffOutput's docstring didn't make clear that this journal is
never the privacy-preserving circuit's own output — it's a separate
program's inner receipt, reconstructed and checked via env::verify, then
discarded. Clarify that, and trim the rest of the comment down.
write_update_from_diff_output took its inputs by reference and cloned
them to build the owned UpdateFromDiffOutput it commits. It has no
callers yet on this branch and nothing else needs the values afterward,
so take them by value and move them in instead.
Rebuild every guest artifact and the prebuilt sequencer fixture: they
were stale relative to this branch's own committed source (confirmed via
mtimes — most of lee_core and every touched program's source postdated
the checked-in .bin files), causing spurious DeserializeBadBool failures
for anyone running tests against a fresh checkout without first running
`just build-artifacts`.
h2 0.4.14 had an unbounded empty DATA frames flaw (low severity); bumped to
0.4.18 via cargo update -p h2. cargo deny check now passes clean
(advisories/bans/licenses/sources all ok).
Rebuild every guest artifact and the prebuilt test fixture to match the
dependency bump.
* feat(key_protocol): version-independent domain separators for normal keys
Introduce a /LEE-Keys/v1/... namespace for account key derivation
(private and public), distinct from LEE protocol versioning
(/LEE/v0.3/...). This lets the key derivation protocol evolve
independently of the transaction/message format version, so a LEE
version bump doesn't silently rotate or orphan user keys.
Covers master/child private and public key derivation, authorization
and viewing secret keys, and nullifier secret/public key derivation
(the latter also used by the privacy-preserving guest circuit).
Pinned regression tests updated to match the new derivation outputs.
* chore(artifacts): rebuild guest ELFs and test fixture for key protocol change
Regenerated via just build-artifacts after the /LEE-Keys/v1/... domain
separator migration touched lee_core::nullifier, which every guest
program links against, and changed derived account IDs embedded in
the prebuilt sequencer fixture.
* test(testnet_initial_state): update pinned private-account values for new key domain separators
initial_priv_accounts_private_keys() derives from fixed SSK roots
through the key_protocol chain the /LEE-Keys/v1/... migration changed,
so the derived viewing secret keys and account addresses shifted even
though the SSK roots themselves didn't. Public account addresses are
unaffected since they sign with a raw PrivateKey outside this chain.
* chore(artifacts): rebuild guest ELFs and test fixture after dev rebase
The rebase onto dev conflicted on these binaries (dev had independently
rebuilt them since this branch diverged). Conflicts were resolved
provisionally during the rebase and are now replaced with a fresh
build-artifacts run against the fully merged tree.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Every guest moved, not only the ones whose source changed: adding real
dependencies (borsh to two cores, cross_zone_inbox_core to two targets) changes
the build graph, and with it the metadata hash of every crate in the guest build.
Piece A moved only three because it added a dev-dependency, which the guest build
never sees.
* refactor: rename PrivateUnauthorized to PrivateForeignInit
The account_identity's is_authorized flag no longer determines
authorization for this variant, so keep the name tied to what
actually distinguishes it: no nsk, only npk (a foreign account init).
* chore: rebuild guest artifacts and bump spin to clear yanked advisory
Regenerate ELF artifacts after the PrivateForeignInit rename in lee_core
(compiled into every guest program), and update spin 0.9.8 -> 0.9.9 since
0.9.8 was yanked from crates.io, per cargo deny check advisories.
* test: align is_authorized with PrivateForeignInit's flipped semantics
Recipient pre-states built for PrivateForeignInit now need is_authorized:
true to match the assertion in output.rs. Also rewrites the boundary test
that checked the old invalid case to check the new one, and updates
stale "unauthorized" wording left over from the PrivateUnauthorized name.
* chore: rebuild guest artifacts
Reproducible across repeated local builds; likely toolchain drift since
the prior artifact commit rather than a source change, since no
guest-relevant source or Cargo.lock changed in between.
* fix(tests): align integration tests with PrivateForeignInit and regenerate fixture
prove_init_with_commitment_root (private.rs) and build_privacy_transaction
(tps.rs) still built PrivateForeignInit recipients with is_authorized: false,
same stale-semantics bug fixed earlier in the lee crate's own tests.
The prebuilt sequencer DB dump embeds program IDs derived from guest ELF
bytes, which shifted once the PrivateForeignInit rename changed lee_core
(compiled into every guest program). The stale dump caused widespread
"Unknown program" failures across integration test suites that exercise
deployed programs (wallet_ffi, auth_transfer, bridge, amm, token, pinata,
ata, indexer state-consistency checks). Regenerated via
`just regenerate-test-fixture`.
* fix(tests): rename leftover PrivateUnauthorized to PrivateForeignInit and regenerate fixture
* test: align is_authorized with PrivateForeignInit's flipped semantics
* chore: regenerate test fixture after rebase onto dev
* chore: regenerate test fixture after rebase onto dev
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Integrates origin/main (per-program-crate refactor) and re-homes the cross-zone messaging feature onto it.
BREAKING CHANGE: Genesis state root changes. This registers six builtin programs
(cross_zone_outbox, cross_zone_inbox, ping_sender, ping_receiver, bridge_lock,
wrapped_token) and seeds their genesis accounts (the wrapped_token authorized
minter config, the per-zone inbox config, and optional bridge-lock holdings).
Building the new cores alongside the existing builtins also enables serde/alloc
for the shared programs build, regenerating every builtin program image id. All
nodes must upgrade together.
* refactor(lee): split large modules into directories and extract tests
Split state.rs, program.rs, circuit.rs, validated_state_diff.rs,
merkle_tree, and core/program.rs into module directories with separate
test files. State tests are further split into themed files (genesis,
authenticated_transfer, circuit, claiming, etc.). Extract
authenticate_public_transaction_signers helper in validated_state_diff
to remove duplicated authentication logic.
* chore: rebuild artifacts
* refactor(privacy_preserving_circuit): extract functions for readability
* refactor(privacy_preserving_circuit): address PR review comments
Bundle shared handle_* arguments into PrivateOutputHandler struct in
output.rs and fix misplaced docstring on resolve_external_seed in
execution_state.rs.
* feat: update commitment mechanism for new private account (#546)
* refactor(privacy_preserving_circuit): extract functions for readability
* feat: update commitment mechanism for new private accounts
Allow init accounts to optionally use a real membership proof for
DUMMY_COMMITMENT instead of hardcoding DUMMY_COMMITMENT_HASH as the
CommitmentSetDigest. The wallet fetches the proof from the sequencer
and passes it through the circuit.
* fix: address clippy lints and fix integration test visibility
* add tests
* refactor: removed duplicated code
* refactor: simplify init nullifier mechanism
Replace Option<MembershipProof> with Option<CommitmentSetDigest> on init
variants (PrivateAuthorizedInit, PrivateUnauthorized, PrivatePdaInit).
The circuit now receives the commitment tree root directly instead of
recomputing it from a Merkle proof.
* refactor: use CommitmentSetDigest directly instead of Option for init commitment root
Address PR #546 review feedback: the circuit now accepts CommitmentSetDigest
directly on init variants (PrivateAuthorizedInit, PrivateUnauthorized,
PrivatePdaInit), with callers providing DUMMY_COMMITMENT_HASH as the default.
Also fixes duplicate resolve_external_seed from rebase and rebuilds artifacts.
* style: run cargo +nightly fmt