38 Commits
Author SHA1 Message Date
Artem Gureev 68d00d5ed0 chore(lee): clear post-migration residue and pin the remaining failure reasons 2026-08-23 15:49:18 +04:00
Artem Gureev c09b1ed778 test(lee): assert failure reasons in should-fail proving tests 2026-08-23 09:35:41 +00:00
Artem Gureev 5a3edc3c10 test(lee): pass exact-typed instructions to strict-decode failure tests 2026-08-23 09:35:41 +00:00
Artem Gureev 96661b4a78 refactor(lee): finish borsh instruction-data cutover in tests and tools 2026-08-23 09:35:23 +00:00
Artem Gureev 5a393d2bff refactor!: carry zkVM instruction_data as borsh bytes end-to-end 2026-08-23 09:35:23 +00:00
jonesmarvin8 96c8577db8 refactor(lee): fold program storage into public_state (#723)
V03State.programs is gone; deployed programs now live directly in public_state, keyed by AccountId::from(program_id) same as any other account. insert_program sets program_owner to a new reserved sentinel, PROGRAM_STORAGE_OWNER, instead of leaving it at the default.

That ownership choice is load-bearing now in a way it wasn't before: once program accounts share the same map as everything else, they're reachable through ordinary dispatch, so program_owner determines whether they're claimable/writable. Left unclaimed, a program invocation could legitimately claim a program's storage account via the normal claim path and then rewrite its elf; self-ownership has the same flaw, since it authorizes exactly the program whose own invocation would touch its own storage account. The reserved sentinel makes every program account unwritable by construction, since no real chained_call.program_id will ever derive to it.

Also centralizes the program-ownership check behind V03State::get_program and applies the program_owner AccountId migration to code added after the earlier rebase.
2026-08-18 12:44:06 -04:00
jonesmarvin8andClaude Sonnet 5 2ba1ecd609 refactor!(lee): Change program_owner: ProgramId to AccountId (#722)
* feat(lee): store deployed programs as Account-shaped state, keyed by AccountId

Program-as-Account migration, first slice: V03State.programs becomes
HashMap<AccountId, Account> instead of HashMap<ProgramId, Program>,
with the elf held directly in Account.data. The map key is derived
from ProgramId via a new 1:1 From<ProgramId> for AccountId conversion
(both types are exactly 32 bytes) rather than a hash, since ProgramId
is already content-derived from the elf.

Account.program_owner stays ProgramId-typed everywhere - this only
changes how deployed programs are stored and looked up host-side, not
the dispatch/authorization model any guest program logic depends on.
Dispatch resolves a ChainedCall's program_id by converting to
AccountId, fetching the Account, and reconstructing a Program via
new_unchecked for execution.

DATA_MAX_LENGTH is raised from 100 KiB to 700 KiB to fit real program
elfs (observed 375 KB-631 KB) directly in Account.data; noted in its
docstring as a rough placeholder pending real transaction/block-size
budget analysis.

* fix(lee): store deployed programs as Account-shaped state, correct SeenShard cap

Corrects lee/state_machine internals for the Program-as-Account migration
and fixes SeenShard::MAX_DELIVERIES, which was still calibrated for the
old 100 KiB DATA_MAX_LENGTH instead of the current 700 KiB cap. Rebuilds
program artifacts and the sequencer test fixture to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* address PR #720 review nits

- Use FIXME instead of TODO for the temporary ProgramId->AccountId
  conversion, per review convention for patches guaranteed to be
  fixed later.
- Derive cross_zone_inbox's MAX_DELIVERIES from DATA_MAX_LENGTH
  instead of a hand-recomputed literal, so it stays in sync
  automatically the next time the cap changes.

* feat(lee): migrate Account.program_owner from ProgramId to AccountId

Account.program_owner is now AccountId-typed instead of ProgramId,
via a new bijective From<ProgramId> for AccountId / From<AccountId>
for ProgramId conversion pair (pure byte reinterpretation, not a
hash - both types are exactly 32 bytes). Adds DEFAULT_PROGRAM_OWNER
as the AccountId-typed counterpart to DEFAULT_PROGRAM_ID, used at
every program_owner comparison/claim site instead of an inline
AccountId::default().

Touches every call site across lee_core, lee (including the
guest-side privacy-preserving circuit), all 16 deployed guest
programs, wallet/wallet-ffi, indexer_ffi/indexer_service/
indexer_service_protocol, sequencer_core, testnet_initial_state,
system_accounts, cross_zone, storage, cycle_bench, and
integration_tests - mostly mechanical .into() conversions, plus two
simplifications: wallet's manual base58 encode/decode of
program_owner was dead code once it's AccountId (which already has
Display/FromStr), and the FFI crates' program_owner field now reuses
the existing generic FfiBytes32 wrapper instead of the now-unused
FfiProgramId one.

Rebuilds every guest ELF artifact and the prebuilt sequencer test
fixture via just build-artifacts, since execute_and_prove runs
against the checked-in precompiled privacy_preserving_circuit.bin,
which isn't rebuilt automatically by cargo test/check.

* chore(lee): rebuild artifacts after rebase, drop unused base58 dep

Rebases marvin/program-as-account-2 onto the updated
marvin/program-as-account (SeenShard cap fix), regenerating program
and circuit artifacts plus the sequencer test fixture to match.
Also removes lez/wallet's now-unused base58 dependency, dead since
AccountId gained its own Display/FromStr base58 encoding.

* docs(lee): trim DEFAULT_PROGRAM_OWNER and From<AccountId> for ProgramId docs

* test(lee): add known-answer tests for ProgramId/AccountId conversion, rebuild artifacts

* fix(lee): apply program_owner AccountId migration to code added after rebase

dev grew new program_owner call sites (sequencer_stake genesis/config
handling, committee_discovery, a new selective_pda_delegator test
program, and related tests) after this branch's ProgramId->AccountId
migration commit was originally written, so they predated the .into()
sweep and didn't conflict during the rebase - they just still assumed
the old ProgramId-typed field. Converts all of them, fixes a stray
unseparated hex literal clippy caught along the way, and rebuilds
artifacts against the fixed source.

* chore(lee): regenerate test fixture after rebasing onto dev

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 11:26:57 -04:00
jonesmarvin8andClaude Sonnet 5 d52c76e2b5 refactor(lee): change programs shape (#720)
* feat(lee): store deployed programs as Account-shaped state, keyed by AccountId

Program-as-Account migration, first slice: V03State.programs becomes
HashMap<AccountId, Account> instead of HashMap<ProgramId, Program>,
with the elf held directly in Account.data. The map key is derived
from ProgramId via a new 1:1 From<ProgramId> for AccountId conversion
(both types are exactly 32 bytes) rather than a hash, since ProgramId
is already content-derived from the elf.

Account.program_owner stays ProgramId-typed everywhere - this only
changes how deployed programs are stored and looked up host-side, not
the dispatch/authorization model any guest program logic depends on.
Dispatch resolves a ChainedCall's program_id by converting to
AccountId, fetching the Account, and reconstructing a Program via
new_unchecked for execution.

DATA_MAX_LENGTH is raised from 100 KiB to 700 KiB to fit real program
elfs (observed 375 KB-631 KB) directly in Account.data; noted in its
docstring as a rough placeholder pending real transaction/block-size
budget analysis.

* fix(lee): store deployed programs as Account-shaped state, correct SeenShard cap

Corrects lee/state_machine internals for the Program-as-Account migration
and fixes SeenShard::MAX_DELIVERIES, which was still calibrated for the
old 100 KiB DATA_MAX_LENGTH instead of the current 700 KiB cap. Rebuilds
program artifacts and the sequencer test fixture to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* address PR #720 review nits

- Use FIXME instead of TODO for the temporary ProgramId->AccountId
  conversion, per review convention for patches guaranteed to be
  fixed later.
- Derive cross_zone_inbox's MAX_DELIVERIES from DATA_MAX_LENGTH
  instead of a hand-recomputed literal, so it stays in sync
  automatically the next time the cap changes.

* chore: regenerate artifacts after rebasing onto dev

Binary program artifacts and the prebuilt sequencer DB dump were left
as rebase-conflict placeholders; regenerated via `just build-artifacts`
against the fully rebased source.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 10:06:42 -04:00
Artem Gureev f707d5e8fb refactor(lee): dedup test, function naming 2026-08-17 17:23:39 +00:00
Artem Gureev f828026df9 fix(lee): authorize caller-seeded public PDAs at first sight 2026-08-17 17:23:39 +00:00
agureev c77313b5ca fix(lee): check private PDA authorization on first sight 2026-08-17 17:23:39 +00:00
agureev 79c43dc5a0 fix!(lee): scope private PDA authorization to the callee subtree
BREAKING!

Before: authorized private PDAs remain authorized for the rest of the
calls after.

After: the authorized preivate PDAs remain authorized for the rest of
the callee subtree.
2026-08-17 17:23:39 +00:00
Artem Gureev 279a9b8313 feat!(lee): derive private authorization from an authorization secret key
BREAKING!

Before: Providing `nsk` was the same as authorizing a regular private
account.

After: A separate `ask` is required, making unauthorized private
updates possible.
2026-08-07 10:41:56 +00:00
Artem Gureev fc8f7f2d42 refactor(lee): verbose key domains and the ask key chain 2026-08-07 10:40:04 +00:00
agureev d05035eb9e refactor(lee): refactor private kinds 2026-08-04 15:55:09 +04:00
agureev dbcdbb29f3 Merge remote-tracking branch 'origin/dev' into artem/bundle-actions 2026-07-31 00:16:31 +04:00
erhant 0659774e43 chore(state_machine); rename get_public_account to get_account_by_id_ref [skip ci] 2026-07-30 14:23:49 +03:00
erhant 57759d8953 fix(bridge): enforce deposit exactly-once via a per-op-id receipt PDA 2026-07-30 14:21:10 +03:00
Artem Gureev f16c3bd1e2 refactor: bundle private/public i/o into action struccts 2026-07-29 18:16:13 +00:00
moudyellaz 150cd17ff5 Merge origin/dev 2026-07-24 00:56:00 +02:00
moudyellaz 124bbee6c6 Merge origin/dev 2026-07-23 23:59:36 +02:00
jonesmarvin8andClaude Sonnet 5 6c0bd71523 refactor: PrivateUnauthorized authorization changed to true (#621)
* 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>
2026-07-23 17:32:01 -04:00
moudyellaz dc977db7ab refactor: destructure genesis fingerprint and return an iterator from bridge_lock_holdings 2026-07-23 21:55:55 +02:00
jonesmarvin8 7bc4c460a2 fix!(state_machine): reject public transactions that silently drop a d… (#625)
* fix(state_machine): reject public transactions that silently drop a declared account

ValidatedStateDiff::from_public_transaction never checked that the accounts
touched in a program's output matched the caller-declared message.account_ids
— it just folded whatever pairs the program returned into the diff. A program
(or a macro-generated dispatcher wrapping one) that silently drops an account
from both sides of its own output together stays internally consistent
(pre_states.len() == post_states.len()) and passes validate_execution's
existing checks, so the dropped account simply vanishes with no error.

Add a check after the chained-call loop: every account_id in
message.account_ids must appear in the final state_diff, or the transaction is
rejected with the new DeclaredAccountMissingFromOutput error.

Add a dropped_account test-guest program that reproduces the exact shape of
the bug (two pre_states in, one consistent (pre, post) pair out) and a
regression test proving the transaction is now rejected. Verified the test
fails with Ok(()) when the check is removed, and passes once it's restored.

* style: tighten comments and apply nightly rustfmt

Condense the explanatory comments on the new account-accounting check and the
dropped_account test guest, and fix imprecise wording (the account is dropped
from both pre_state and post_states together, not just pre_state). Also
applies cargo +nightly fmt's wrapping of the new error message.

* chore: regenerate test fixture after rebase onto dev
2026-07-23 12:09:16 -04:00
erhantandClaude Fable 5 8d09ffd733 feat(sequencer): two-tier chain state and multi-sequencer support
Decentralized-sequencing foundation: a shared chain_state crate (two-tier
head/final ChainState, apply_block, AcceptOutcome, StallReason, and the
absorbed channel-consistency machinery), turn-gated block production, the
publisher follow path for adopted/orphaned/finalized peer blocks, and
persistence that keeps disk order equal to apply order under the chain lock.

Rebased onto dev after #600/#606: chain_consistency is absorbed into
chain_state, the sequencer bootstrap's verify_and_reconstruct is re-wired
onto the two-tier ChainState (reconstruction applies channel history
through the final tier and persists via the follow-path primitives), and
test fixtures adopt the SequencerSetup builder extended with
with_bedrock_signing_key.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 11:43:57 +03:00
moudyellaz 72195ce09e Merge origin/dev 2026-07-23 02:43:53 +02:00
agureev 61cad70f9b feat(circuit): supply a view_tag on private-account updates 2026-07-22 22:31:31 +04:00
moudyellaz a806ebb94a refactor(cross-zone)!: register cross-zone programs as base builtins
BREAKING CHANGE: GenesisAction::DeployProgram and IndexerConfig.deploy_programs are removed. The cross-zone programs (inbox, outbox, ping_sender, ping_receiver, bridge_lock, wrapped_token) are now base builtins in testnet_initial_state, because program bytecode exceeds the genesis block inscription limit, so they cannot be shipped through genesis transactions.
2026-07-21 10:50:41 +02:00
moudyellaz 0f88fda054 Merge origin/dev 2026-07-16 12:44:07 +02:00
Pravdyvy ba741da37b Merge branch 'dev' into Pravdyvy/multi-sequencer-client 2026-07-15 13:45:44 +03:00
Pravdyvy ac2bf7f996 Merge branch 'dev' into Pravdyvy/multi-sequencer-client 2026-07-14 13:19:04 +03:00
Pravdyvy bf237daf71 fix(tintegration_tests): tests work 2026-07-14 13:10:32 +03:00
moudyellaz a16e22c46c refactor!(cross-zone): deploy programs at genesis instead of builtins
Cross-zone builtin programs are no longer registered in the production
genesis. A zone that participates declares the ones it uses via a new
GenesisAction::DeployProgram (sequencer) and a matching deploy_programs
list (indexer), both resolved through CrossZoneProgram and registered
with with_programs. Cross-zone genesis accounts (inbox config,
wrapped-token config) are seeded through the state constructor for a
receiving zone, and bridge-lock holdings are seeded from their actions
regardless of receiving config, dropping V03State::insert_genesis_account.
GenesisAction amounts now use the Balance alias. Documents cross_zone as
the reference LEZ adapter and the bridge demo as not production-safe.

The sequencer's DeployProgram set and the indexer's deploy_programs are
configured separately, so both nodes now log a deterministic genesis
fingerprint (V03State::genesis_fingerprint) at startup: equal values
confirm the two genesis states agree, a mismatch flags a divergent
deploy set.

BREAKING CHANGE: the genesis state root changes (cross-zone builtins are
out of production genesis) and the sequencer/indexer configs gain the
DeployProgram / deploy_programs list that cross-zone-participating zones
must set.
2026-07-13 19:12:24 +02:00
Artem Gureev 8545ff1466 feat!(sequencer): serve proofs and root in one getProofsAndRoot RPC
BREAKING:

Before: An endpoint exposing getting a single proof for a commitment
existed.

After: There is one endpoint where you give a vector of commitments
and a vector of Maybe proofs back alongside the shared root.

Mitigation: Use the new rpc endpoint with the appopriate vector.
2026-07-13 13:34:03 +00:00
moudyellaz eff31df9ce Merge origin/dev 2026-07-11 01:12:00 +02:00
moudyellaz 9f7db3fa38 Merge origin/dev 2026-07-04 00:48:40 +02:00
agureev 8e084e22d1 Merge remote-tracking branch 'origin/dev' into artem/viewing-key-binding 2026-07-02 20:04:30 +04:00
jonesmarvin8 072ea3b066 refactor(lee::state_machine): clean up long functions and files (#535)
* 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
2026-07-01 11:11:08 -04:00