diff --git a/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin b/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin index 97567415d..97e556711 100644 Binary files a/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin and b/artifacts/lee/privacy_preserving_circuit/privacy_preserving_circuit.bin differ diff --git a/artifacts/lez/programs/amm.bin b/artifacts/lez/programs/amm.bin index fd192e693..d612a3d00 100644 Binary files a/artifacts/lez/programs/amm.bin and b/artifacts/lez/programs/amm.bin differ diff --git a/artifacts/lez/programs/associated_token_account.bin b/artifacts/lez/programs/associated_token_account.bin index 96ca998d2..cb6b77766 100644 Binary files a/artifacts/lez/programs/associated_token_account.bin and b/artifacts/lez/programs/associated_token_account.bin differ diff --git a/artifacts/lez/programs/authenticated_transfer.bin b/artifacts/lez/programs/authenticated_transfer.bin index 9ac927132..dd5846305 100644 Binary files a/artifacts/lez/programs/authenticated_transfer.bin and b/artifacts/lez/programs/authenticated_transfer.bin differ diff --git a/artifacts/lez/programs/bridge.bin b/artifacts/lez/programs/bridge.bin index 98a113fe7..8690c3b73 100644 Binary files a/artifacts/lez/programs/bridge.bin and b/artifacts/lez/programs/bridge.bin differ diff --git a/artifacts/lez/programs/bridge_lock.bin b/artifacts/lez/programs/bridge_lock.bin index 72ee2e941..20f660046 100644 Binary files a/artifacts/lez/programs/bridge_lock.bin and b/artifacts/lez/programs/bridge_lock.bin differ diff --git a/artifacts/lez/programs/clock.bin b/artifacts/lez/programs/clock.bin index 10c5bdcae..42a34da93 100644 Binary files a/artifacts/lez/programs/clock.bin and b/artifacts/lez/programs/clock.bin differ diff --git a/artifacts/lez/programs/cross_zone_inbox.bin b/artifacts/lez/programs/cross_zone_inbox.bin index eab9bf344..a6d0d20df 100644 Binary files a/artifacts/lez/programs/cross_zone_inbox.bin and b/artifacts/lez/programs/cross_zone_inbox.bin differ diff --git a/artifacts/lez/programs/cross_zone_outbox.bin b/artifacts/lez/programs/cross_zone_outbox.bin index 3da07afbe..a3e83654a 100644 Binary files a/artifacts/lez/programs/cross_zone_outbox.bin and b/artifacts/lez/programs/cross_zone_outbox.bin differ diff --git a/artifacts/lez/programs/faucet.bin b/artifacts/lez/programs/faucet.bin index dd9d2a282..706886e1b 100644 Binary files a/artifacts/lez/programs/faucet.bin and b/artifacts/lez/programs/faucet.bin differ diff --git a/artifacts/lez/programs/pinata.bin b/artifacts/lez/programs/pinata.bin index d123d24dc..a35958637 100644 Binary files a/artifacts/lez/programs/pinata.bin and b/artifacts/lez/programs/pinata.bin differ diff --git a/artifacts/lez/programs/pinata_token.bin b/artifacts/lez/programs/pinata_token.bin index 8aeca35d3..5a7f1625a 100644 Binary files a/artifacts/lez/programs/pinata_token.bin and b/artifacts/lez/programs/pinata_token.bin differ diff --git a/artifacts/lez/programs/ping_receiver.bin b/artifacts/lez/programs/ping_receiver.bin index 564bce29b..5f04d811a 100644 Binary files a/artifacts/lez/programs/ping_receiver.bin and b/artifacts/lez/programs/ping_receiver.bin differ diff --git a/artifacts/lez/programs/ping_sender.bin b/artifacts/lez/programs/ping_sender.bin index 29b067403..a1cd57fc9 100644 Binary files a/artifacts/lez/programs/ping_sender.bin and b/artifacts/lez/programs/ping_sender.bin differ diff --git a/artifacts/lez/programs/sequencer_stake.bin b/artifacts/lez/programs/sequencer_stake.bin index a3d271f7b..10f766663 100644 Binary files a/artifacts/lez/programs/sequencer_stake.bin and b/artifacts/lez/programs/sequencer_stake.bin differ diff --git a/artifacts/lez/programs/token.bin b/artifacts/lez/programs/token.bin index 1e6ac3005..6943754b4 100644 Binary files a/artifacts/lez/programs/token.bin and b/artifacts/lez/programs/token.bin differ diff --git a/artifacts/lez/programs/vault.bin b/artifacts/lez/programs/vault.bin index 3c419e5a3..93435014f 100644 Binary files a/artifacts/lez/programs/vault.bin and b/artifacts/lez/programs/vault.bin differ diff --git a/artifacts/lez/programs/wrapped_token.bin b/artifacts/lez/programs/wrapped_token.bin index 3294a44ba..a778cdaa3 100644 Binary files a/artifacts/lez/programs/wrapped_token.bin and b/artifacts/lez/programs/wrapped_token.bin differ diff --git a/lee/state_machine/core/src/account/data.rs b/lee/state_machine/core/src/account/data.rs index 272f01915..d24ccb1d0 100644 --- a/lee/state_machine/core/src/account/data.rs +++ b/lee/state_machine/core/src/account/data.rs @@ -4,7 +4,9 @@ use borsh::{BorshDeserialize, BorshSerialize}; use bytesize::ByteSize; use serde::{Deserialize, Serialize}; -pub const DATA_MAX_LENGTH: ByteSize = ByteSize::kib(100); +/// TODO: Temporarily raised cap to 700 KiB from 100 KiB. This is a placeholder +/// until multiple accounts are used to store the entire elf. +pub const DATA_MAX_LENGTH: ByteSize = ByteSize::kib(700); #[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, BorshSerialize)] pub struct Data(Vec); diff --git a/lee/state_machine/core/src/program/mod.rs b/lee/state_machine/core/src/program/mod.rs index d8d0acd40..2d7d4e6f7 100644 --- a/lee/state_machine/core/src/program/mod.rs +++ b/lee/state_machine/core/src/program/mod.rs @@ -14,6 +14,19 @@ pub const DEFAULT_PROGRAM_ID: ProgramId = [0; 8]; pub const MAX_NUMBER_CHAINED_CALLS: usize = 10; pub type ProgramId = [u32; 8]; + +/// FIXME: This is a temporary conversion; will be removed once `Program` to `Account` +/// migration is complete. +impl From for AccountId { + fn from(program_id: ProgramId) -> Self { + let bytes: Vec = program_id + .iter() + .flat_map(|word| word.to_le_bytes()) + .collect(); + Self::new(bytes.try_into().expect("8 u32 words are exactly 32 bytes")) + } +} + pub type InstructionData = Vec; pub struct ProgramInput { pub self_program_id: ProgramId, diff --git a/lee/state_machine/src/state/mod.rs b/lee/state_machine/src/state/mod.rs index 8b91b6983..cb04e0e93 100644 --- a/lee/state_machine/src/state/mod.rs +++ b/lee/state_machine/src/state/mod.rs @@ -4,8 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use lee_core::{ BlockId, Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, Timestamp, - account::{Account, AccountId}, - program::ProgramId, + account::{Account, AccountId, Data}, }; use crate::{ @@ -114,7 +113,7 @@ impl BorshDeserialize for NullifierSet { pub struct V03State { public_state: HashMap, private_state: (CommitmentSet, NullifierSet), - programs: HashMap, + programs: HashMap, } impl Default for V03State { @@ -190,13 +189,19 @@ impl V03State { #[must_use] pub fn with_programs(mut self, programs: impl IntoIterator) -> Self { for program in programs { - self.insert_program(program); + self.insert_program(&program); } self } - pub(crate) fn insert_program(&mut self, program: Program) { - self.programs.insert(program.id(), program); + pub(crate) fn insert_program(&mut self, program: &Program) { + let account_id = AccountId::from(program.id()); + let account = Account { + data: Data::try_from(program.elf().to_vec()) + .expect("elf must fit under DATA_MAX_LENGTH"), + ..Account::default() + }; + self.programs.insert(account_id, account); } pub fn apply_state_diff(&mut self, diff: ValidatedStateDiff) { @@ -222,7 +227,7 @@ impl V03State { self.private_state.0.extend(&new_commitments); self.private_state.1.extend(&new_nullifiers); if let Some(program) = program { - self.insert_program(program); + self.insert_program(&program); } } @@ -281,7 +286,7 @@ impl V03State { self.private_state.0.get_proof_for(commitment) } - pub(crate) const fn programs(&self) -> &HashMap { + pub(crate) const fn programs(&self) -> &HashMap { &self.programs } @@ -314,11 +319,12 @@ impl V03State { let mut accounts: Vec<(&AccountId, &Account)> = public_state.iter().collect(); accounts.sort_by(|a, b| a.0.as_ref().cmp(b.0.as_ref())); - let mut program_ids: Vec = programs.keys().copied().collect(); - program_ids.sort_unstable(); + let mut program_accounts: Vec<(&AccountId, &Account)> = programs.iter().collect(); + program_accounts.sort_by(|a, b| a.0.as_ref().cmp(b.0.as_ref())); let account_count = u64::try_from(accounts.len()).expect("account count fits in u64"); - let program_count = u64::try_from(program_ids.len()).expect("program count fits in u64"); + let program_count = + u64::try_from(program_accounts.len()).expect("program count fits in u64"); let mut hasher = Sha256::new(); hasher.update(account_count.to_le_bytes()); @@ -330,10 +336,12 @@ impl V03State { hasher.update(&bytes); } hasher.update(program_count.to_le_bytes()); - for id in program_ids { - for word in id { - hasher.update(word.to_le_bytes()); - } + for (id, account) in program_accounts { + hasher.update(id.as_ref()); + let bytes = borsh::to_vec(account).expect("Account is BorshSerialize"); + let len = u64::try_from(bytes.len()).expect("program account encoding fits in u64"); + hasher.update(len.to_le_bytes()); + hasher.update(&bytes); } hasher.update(private_state.0.digest()); diff --git a/lee/state_machine/src/state/tests/genesis.rs b/lee/state_machine/src/state/tests/genesis.rs index f67628eee..4a07b5086 100644 --- a/lee/state_machine/src/state/tests/genesis.rs +++ b/lee/state_machine/src/state/tests/genesis.rs @@ -67,11 +67,12 @@ fn insert_program() { let mut state = V03State::new(); let program_to_insert = crate::test_methods::simple_balance_transfer(); let program_id = program_to_insert.id(); - assert!(!state.programs.contains_key(&program_id)); + let account_id = lee_core::account::AccountId::from(program_id); + assert!(!state.programs.contains_key(&account_id)); - state.insert_program(program_to_insert); + state.insert_program(&program_to_insert); - assert!(state.programs.contains_key(&program_id)); + assert!(state.programs.contains_key(&account_id)); } #[test] diff --git a/lee/state_machine/src/state/tests/mod.rs b/lee/state_machine/src/state/tests/mod.rs index c3a9e2285..8ec2bae27 100644 --- a/lee/state_machine/src/state/tests/mod.rs +++ b/lee/state_machine/src/state/tests/mod.rs @@ -45,36 +45,36 @@ impl V03State { /// Include test programs in the builtin programs map. #[must_use] pub fn with_test_programs(mut self) -> Self { - self.insert_program(crate::test_methods::simple_balance_transfer()); - self.insert_program(crate::test_methods::nonce_changer()); - self.insert_program(crate::test_methods::extra_output()); - self.insert_program(crate::test_methods::missing_output()); - self.insert_program(crate::test_methods::dropped_account()); - self.insert_program(crate::test_methods::program_owner_changer()); - self.insert_program(crate::test_methods::data_changer()); - self.insert_program(crate::test_methods::minter()); - self.insert_program(crate::test_methods::burner()); - self.insert_program(crate::test_methods::auth_asserting_noop()); - self.insert_program(crate::test_methods::private_pda_delegator()); - self.insert_program(crate::test_methods::pda_claimer()); - self.insert_program(crate::test_methods::two_pda_claimer()); - self.insert_program(crate::test_methods::noop()); - self.insert_program(crate::test_methods::chain_caller()); - self.insert_program(crate::test_methods::modified_transfer_program()); - self.insert_program(crate::test_methods::malicious_authorization_changer()); - self.insert_program(crate::test_methods::validity_window()); - self.insert_program(crate::test_methods::flash_swap_initiator()); - self.insert_program(crate::test_methods::flash_swap_callback()); - self.insert_program(crate::test_methods::malicious_self_program_id()); - self.insert_program(crate::test_methods::malicious_caller_program_id()); - self.insert_program(crate::test_methods::pda_spend_proxy()); - self.insert_program(crate::test_methods::claimer()); - self.insert_program(crate::test_methods::changer_claimer()); - self.insert_program(crate::test_methods::validity_window_chain_caller()); - self.insert_program(crate::test_methods::simple_transfer_proxy()); - self.insert_program(crate::test_methods::malicious_injector()); - self.insert_program(crate::test_methods::malicious_launderer()); - self.insert_program(crate::test_methods::modified_transfer_program()); + self.insert_program(&crate::test_methods::simple_balance_transfer()); + self.insert_program(&crate::test_methods::nonce_changer()); + self.insert_program(&crate::test_methods::extra_output()); + self.insert_program(&crate::test_methods::missing_output()); + self.insert_program(&crate::test_methods::dropped_account()); + self.insert_program(&crate::test_methods::program_owner_changer()); + self.insert_program(&crate::test_methods::data_changer()); + self.insert_program(&crate::test_methods::minter()); + self.insert_program(&crate::test_methods::burner()); + self.insert_program(&crate::test_methods::auth_asserting_noop()); + self.insert_program(&crate::test_methods::private_pda_delegator()); + self.insert_program(&crate::test_methods::pda_claimer()); + self.insert_program(&crate::test_methods::two_pda_claimer()); + self.insert_program(&crate::test_methods::noop()); + self.insert_program(&crate::test_methods::chain_caller()); + self.insert_program(&crate::test_methods::modified_transfer_program()); + self.insert_program(&crate::test_methods::malicious_authorization_changer()); + self.insert_program(&crate::test_methods::validity_window()); + self.insert_program(&crate::test_methods::flash_swap_initiator()); + self.insert_program(&crate::test_methods::flash_swap_callback()); + self.insert_program(&crate::test_methods::malicious_self_program_id()); + self.insert_program(&crate::test_methods::malicious_caller_program_id()); + self.insert_program(&crate::test_methods::pda_spend_proxy()); + self.insert_program(&crate::test_methods::claimer()); + self.insert_program(&crate::test_methods::changer_claimer()); + self.insert_program(&crate::test_methods::validity_window_chain_caller()); + self.insert_program(&crate::test_methods::simple_transfer_proxy()); + self.insert_program(&crate::test_methods::malicious_injector()); + self.insert_program(&crate::test_methods::malicious_launderer()); + self.insert_program(&crate::test_methods::modified_transfer_program()); self } diff --git a/lee/state_machine/src/validated_state_diff/mod.rs b/lee/state_machine/src/validated_state_diff/mod.rs index 7afb99b1f..f1773f806 100644 --- a/lee/state_machine/src/validated_state_diff/mod.rs +++ b/lee/state_machine/src/validated_state_diff/mod.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Cow, collections::{HashMap, HashSet, VecDeque}, hash::Hash, }; @@ -111,10 +112,16 @@ impl ValidatedStateDiff { LeeError::MaxChainedCallsDepthExceeded ); - // Check that the `program_id` corresponds to a deployed program - let Some(program) = state.programs().get(&chained_call.program_id) else { + let Some(program_account) = state + .programs() + .get(&AccountId::from(chained_call.program_id)) + else { return Err(LeeError::InvalidInput("Unknown program".into())); }; + let program = Program::new_unchecked( + chained_call.program_id, + Cow::Owned(program_account.data.to_vec()), + ); debug!( "Program {:?} pre_states: {:?}, instruction_data: {:?}", @@ -441,7 +448,10 @@ impl ValidatedStateDiff { ) -> Result { // TODO: remove clone let program = Program::new(tx.message.bytecode.clone().into())?; - if state.programs().contains_key(&program.id()) { + if state + .programs() + .contains_key(&AccountId::from(program.id())) + { return Err(LeeError::ProgramAlreadyExists); } Ok(Self(StateDiff { diff --git a/lez/programs/cross_zone_inbox/core/src/lib.rs b/lez/programs/cross_zone_inbox/core/src/lib.rs index 9184e0342..03c3c615e 100644 --- a/lez/programs/cross_zone_inbox/core/src/lib.rs +++ b/lez/programs/cross_zone_inbox/core/src/lib.rs @@ -2,7 +2,7 @@ use std::collections::BTreeSet; use borsh::{BorshDeserialize, BorshSerialize}; use lee_core::{ - account::AccountId, + account::{AccountId, data::DATA_MAX_LENGTH}, program::{PdaSeed, ProgramId}, }; use serde::{Deserialize, Serialize}; @@ -133,13 +133,25 @@ impl SeenShard { /// Deliveries one shard can hold before it exceeds `DATA_MAX_LENGTH`. /// /// Borsh is 32 bytes of hash, a 4-byte count, then 4 bytes per index, so - /// this is exactly the 100 KiB an account may carry. + /// this is exactly the `DATA_MAX_LENGTH` an account may carry. /// /// Out of reach only because of the L1 inscription cap: a block inscribes as /// one op near 1.75 MiB and a minimal emitting transaction is about 257 /// bytes, capping a peer block near 7,100 deliveries. Raising that L1 cap /// past roughly 6.3 MiB puts this back in reach. - pub const MAX_DELIVERIES: usize = 25_591; + pub const MAX_DELIVERIES: usize = { + let remaining_bytes = DATA_MAX_LENGTH.as_u64() - 36; + let count = remaining_bytes + .checked_div(4) + .expect("division is well-defined"); + #[expect( + clippy::as_conversions, + clippy::cast_possible_truncation, + reason = "usize::try_from is not yet const-stable; the value is tiny and always fits" + )] + let count = count as usize; + count + }; /// Decodes a shard from account data; empty data is an unclaimed shard. pub fn from_bytes(bytes: &[u8]) -> borsh::io::Result { @@ -300,8 +312,6 @@ pub fn inbox_source_marker_seed(src_zone: &ZoneId, src_program_id: ProgramId) -> } #[cfg(test)] mod tests { - use lee_core::account::data::DATA_MAX_LENGTH; - use super::*; fn zone(b: u8) -> ZoneId { @@ -379,6 +389,7 @@ mod tests { #[test] fn a_full_shard_fits_in_account_data() { + // Exact only because `DATA_MAX_LENGTH` is whole KiB, hence a multiple of 4. let mut shard = SeenShard::default(); for index in 0..SeenShard::MAX_DELIVERIES { shard.insert([5; 32], u32::try_from(index).expect("index fits")); diff --git a/test_fixtures/fixtures/prebuilt_sequencer_db.dump b/test_fixtures/fixtures/prebuilt_sequencer_db.dump index 1a14baddf..2e3ab54ee 100644 Binary files a/test_fixtures/fixtures/prebuilt_sequencer_db.dump and b/test_fixtures/fixtures/prebuilt_sequencer_db.dump differ