diff --git a/Cargo.lock b/Cargo.lock index e29d74a13..d134e0801 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,6 +154,7 @@ dependencies = [ "amm_core", "lee", "lee_core", + "program_loader_core", "programs", "token_core", ] @@ -1806,6 +1807,7 @@ dependencies = [ "lee_core", "log", "logos-blockchain-common-http-client", + "program_loader_core", "programs", "serde", "serde_with", @@ -2108,6 +2110,7 @@ dependencies = [ "lee", "lee_core", "ping_core", + "program_loader_core", "programs", "risc0-zkvm", "serde", @@ -2127,6 +2130,7 @@ dependencies = [ "lee", "log", "ping_core", + "program_loader_core", "programs", "rand 0.8.6", "risc0-zkvm", @@ -4608,6 +4612,7 @@ dependencies = [ "logos-blockchain-core", "logos-blockchain-zone-sdk", "ping_core", + "program_loader_core", "programs", "risc0-zkvm", "serde", @@ -12013,6 +12018,7 @@ dependencies = [ "clock_core", "faucet_core", "lee_core", + "program_loader_core", "programs", "sequencer_stake_core", ] @@ -12419,6 +12425,7 @@ dependencies = [ "key_protocol", "lee", "lee_core", + "program_loader_core", "programs", "serde", "system_accounts", @@ -13536,6 +13543,7 @@ dependencies = [ "lee_core", "log", "optfield", + "program_loader_core", "programs", "rand 0.8.6", "rpassword", @@ -13564,6 +13572,7 @@ dependencies = [ "key_protocol", "lee", "lee_core", + "program_loader_core", "programs", "risc0-zkvm", "serde_json", diff --git a/integration_tests/tests/account.rs b/integration_tests/tests/account.rs index 298e5029a..ed4af6ea2 100644 --- a/integration_tests/tests/account.rs +++ b/integration_tests/tests/account.rs @@ -29,7 +29,7 @@ async fn get_existing_account() -> Result<()> { assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); @@ -149,7 +149,9 @@ async fn import_private_account() -> Result<()> { 0, )); let account = lee::Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id( + programs::authenticated_transfer().id(), + ), balance: 777, data: Data::default(), nonce: Nonce::default(), @@ -213,7 +215,9 @@ async fn import_private_account_second_time_overrides_account_data() -> Result<( serde_json::to_string(&key_chain).context("Failed to serialize key chain")?; let initial_account = lee::Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id( + programs::authenticated_transfer().id(), + ), balance: 100, data: Data::default(), nonce: Nonce::default(), @@ -232,7 +236,9 @@ async fn import_private_account_second_time_overrides_account_data() -> Result<( .await?; let updated_account = lee::Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id( + programs::authenticated_transfer().id(), + ), balance: 999, data: Data::default(), nonce: Nonce::default(), diff --git a/integration_tests/tests/auth_transfer/private.rs b/integration_tests/tests/auth_transfer/private.rs index 31223ab66..8fa281f69 100644 --- a/integration_tests/tests/auth_transfer/private.rs +++ b/integration_tests/tests/auth_transfer/private.rs @@ -391,7 +391,7 @@ async fn initialize_private_account() -> Result<()> { assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); assert_eq!(account.balance, 0); assert!(account.data.is_empty()); @@ -470,7 +470,7 @@ async fn initialize_private_account_using_label() -> Result<()> { assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); log::info!("Successfully initialized private account using label"); @@ -641,10 +641,16 @@ async fn ppt_cant_chain_call_faucet() -> Result<()> { let program_with_deps = ProgramWithDependencies::new( faucet_chain_caller, [ - (faucet_program_id.into(), programs::faucet()), - (vault_program_id.into(), programs::vault()), ( - auth_transfer_program_id.into(), + program_loader_core::immutable_deploy_account_id(faucet_program_id), + programs::faucet(), + ), + ( + program_loader_core::immutable_deploy_account_id(vault_program_id), + programs::vault(), + ), + ( + program_loader_core::immutable_deploy_account_id(auth_transfer_program_id), programs::authenticated_transfer(), ), ] @@ -652,8 +658,13 @@ async fn ppt_cant_chain_call_faucet() -> Result<()> { ) .with_program_account_id(faucet_chain_caller_header); - let instruction = - Program::serialize_instruction((faucet_program_id, vault_program_id, attacker_id, amount))?; + let instruction = Program::serialize_instruction(( + faucet_program_id, + program_loader_core::immutable_deploy_account_id(faucet_program_id), + program_loader_core::immutable_deploy_account_id(vault_program_id), + attacker_id, + amount, + ))?; let res = execute_and_prove( vec![faucet_pre, vault_pda_pre], @@ -698,6 +709,7 @@ async fn prove_init_with_commitment_root( let recipient_account_id = AccountId::for_regular_private_account(&npk, &vpk, 0); let recipient = AccountWithMetadata::new(Account::default(), true, recipient_account_id); + let program_id = program.id(); let (output, _) = execute_and_prove( vec![sender_pre, recipient], Program::serialize_instruction(authenticated_transfer_core::Instruction::Transfer { @@ -716,7 +728,8 @@ async fn prove_init_with_commitment_root( }, }), ], - &program.into(), + &ProgramWithDependencies::new(program, [].into()) + .with_program_account_id(program_loader_core::immutable_deploy_account_id(program_id)), )?; Ok(output) diff --git a/integration_tests/tests/auth_transfer/public.rs b/integration_tests/tests/auth_transfer/public.rs index 2077bc031..8d5822662 100644 --- a/integration_tests/tests/auth_transfer/public.rs +++ b/integration_tests/tests/auth_transfer/public.rs @@ -221,7 +221,7 @@ async fn initialize_public_account() -> Result<()> { assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); assert_eq!(account.balance, 0); assert_eq!(account.nonce.0, 1); @@ -319,7 +319,7 @@ async fn cannot_transfer_funds_from_system_faucet_account() -> Result<()> { let amount = 1_u128; let message = public_transaction::Message::try_new( - programs::authenticated_transfer().id().into(), + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()), vec![faucet_account_id, recipient], vec![], authenticated_transfer_core::Instruction::Transfer { amount }, @@ -361,11 +361,12 @@ async fn cannot_execute_faucet_program() -> Result<()> { let amount = 1_u128; let message = public_transaction::Message::try_new( - programs::faucet().id().into(), + program_loader_core::immutable_deploy_account_id(programs::faucet().id()), vec![faucet_account_id, recipient_vault_id], vec![], faucet_core::Instruction::GenesisTransferVault { - vault_program_id, + self_program_id: programs::faucet().id(), + vault_account_id: program_loader_core::immutable_deploy_account_id(vault_program_id), recipient_id: recipient, amount, }, @@ -434,7 +435,13 @@ async fn user_tx_that_chain_calls_faucet_is_dropped() -> Result<()> { faucet_chain_caller_header, vec![faucet_account_id, attacker_vault_id], vec![], - (faucet_program_id, vault_program_id, attacker, amount), + ( + faucet_program_id, + program_loader_core::immutable_deploy_account_id(faucet_program_id), + program_loader_core::immutable_deploy_account_id(vault_program_id), + attacker, + amount, + ), )?; let attack_tx = LeeTransaction::Public(lee::PublicTransaction::new( message, diff --git a/integration_tests/tests/block_size_limit.rs b/integration_tests/tests/block_size_limit.rs index dbcbb1312..67e1d75aa 100644 --- a/integration_tests/tests/block_size_limit.rs +++ b/integration_tests/tests/block_size_limit.rs @@ -167,8 +167,8 @@ async fn transaction_deferred_to_next_block_when_current_full() -> Result<()> { if public_tx.message.program_account_id != RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID { return None; } - let loader_core::Instruction::Deploy { bytecode } = - risc0_zkvm::serde::from_slice::( + let program_loader_core::Instruction::Deploy { bytecode } = + risc0_zkvm::serde::from_slice::( &public_tx.message.instruction_data, ) .ok()?; diff --git a/integration_tests/tests/bridge.rs b/integration_tests/tests/bridge.rs index a359739ce..3b8a6343c 100644 --- a/integration_tests/tests/bridge.rs +++ b/integration_tests/tests/bridge.rs @@ -30,12 +30,14 @@ async fn public_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> { let receipt_id = bridge_core::deposit_receipt_account_id(programs::bridge().id(), [0_u8; 32]); let message = public_transaction::Message::try_new( - programs::bridge().id().into(), + program_loader_core::immutable_deploy_account_id(programs::bridge().id()), vec![bridge_account_id, recipient_vault_id, receipt_id], vec![], bridge_core::Instruction::Deposit { l1_deposit_op_id: [0_u8; 32], + self_program_id: programs::bridge().id(), vault_program_id, + vault_account_id: program_loader_core::immutable_deploy_account_id(vault_program_id), recipient_id, amount: 1, }, @@ -79,12 +81,14 @@ async fn public_bridge_deposit_with_zero_amount_is_rejected() -> anyhow::Result< let receipt_id = bridge_core::deposit_receipt_account_id(programs::bridge().id(), [0_u8; 32]); let message = public_transaction::Message::try_new( - programs::bridge().id().into(), + program_loader_core::immutable_deploy_account_id(programs::bridge().id()), vec![bridge_account_id, recipient_vault_id, receipt_id], vec![], bridge_core::Instruction::Deposit { l1_deposit_op_id: [0_u8; 32], + self_program_id: programs::bridge().id(), vault_program_id, + vault_account_id: program_loader_core::immutable_deploy_account_id(vault_program_id), recipient_id, amount: 0, }, @@ -159,19 +163,29 @@ async fn private_bridge_deposit_invocation_is_dropped() -> anyhow::Result<()> { lee::privacy_preserving_transaction::circuit::ProgramWithDependencies::new( programs::bridge(), [ - (vault_program_id.into(), programs::vault()), ( - programs::authenticated_transfer().id().into(), + program_loader_core::immutable_deploy_account_id(vault_program_id), + programs::vault(), + ), + ( + program_loader_core::immutable_deploy_account_id( + programs::authenticated_transfer().id(), + ), programs::authenticated_transfer(), ), ] .into(), - ); + ) + .with_program_account_id(program_loader_core::immutable_deploy_account_id( + programs::bridge().id(), + )); // Serialize the bridge deposit instruction let instruction = Program::serialize_instruction(bridge_core::Instruction::Deposit { l1_deposit_op_id: [0_u8; 32], + self_program_id: programs::bridge().id(), vault_program_id, + vault_account_id: program_loader_core::immutable_deploy_account_id(vault_program_id), recipient_id, amount: 1, }) diff --git a/integration_tests/tests/cross_zone_bridge.rs b/integration_tests/tests/cross_zone_bridge.rs index 1767c67c0..4a45e85f0 100644 --- a/integration_tests/tests/cross_zone_bridge.rs +++ b/integration_tests/tests/cross_zone_bridge.rs @@ -54,7 +54,9 @@ async fn lock_on_zone_a_mints_wrapped_token_on_zone_b() -> Result<()> { peers: vec![CrossZonePeer { channel_id: *channel_a.as_ref(), allowed_routes: vec![CrossZoneRoute { - src_program_id: programs::bridge_lock().id(), + src_account_id: program_loader_core::immutable_deploy_account_id( + programs::bridge_lock().id(), + ), target_program_id: wrapped_token_id, }], expected_block_signing_pubkeys: Vec::new(), @@ -147,6 +149,7 @@ fn build_lock_tx( let ordinal = 0; let mint = wrapped_token_core::Instruction::Mint { + self_program_id: wrapped_token_id, recipient: RECIPIENT, amount: LOCK_AMOUNT, }; @@ -158,6 +161,7 @@ fn build_lock_tx( wrapped_token_core::holding_account_id(wrapped_token_id, &RECIPIENT).into_value(), ]; let lock = bridge_lock_core::Instruction::Lock { + self_program_id: bridge_lock_id, amount: LOCK_AMOUNT, target_zone, target_program_id: wrapped_token_id, @@ -170,11 +174,21 @@ fn build_lock_tx( bridge_lock_core::config_account_id(bridge_lock_id), holder_id, bridge_lock_core::escrow_account_id(bridge_lock_id), - outbox_pda(outbox_id, bridge_lock_id, &target_zone, ordinal), + outbox_pda( + outbox_id, + program_loader_core::immutable_deploy_account_id(bridge_lock_id), + &target_zone, + ordinal, + ), ]; // One nonce per signature: the holder signs, at its genesis nonce 0. - let message = Message::try_new(bridge_lock_id.into(), accounts, vec![0_u128.into()], lock) - .expect("build lock message"); + let message = Message::try_new( + program_loader_core::immutable_deploy_account_id(bridge_lock_id), + accounts, + vec![0_u128.into()], + lock, + ) + .expect("build lock message"); let witness = WitnessSet::for_message(&message, &[holder_key]); LeeTransaction::Public(PublicTransaction::new(message, witness)) } diff --git a/integration_tests/tests/cross_zone_ingress_guard.rs b/integration_tests/tests/cross_zone_ingress_guard.rs index 0af05ff9b..b16d7a4b4 100644 --- a/integration_tests/tests/cross_zone_ingress_guard.rs +++ b/integration_tests/tests/cross_zone_ingress_guard.rs @@ -45,22 +45,27 @@ async fn user_origin_inbox_call_rejected() -> Result<()> { // A user hand-builds a top-level inbox Dispatch and submits it via RPC. let inbox_id = programs::cross_zone_inbox().id(); + let ping_receiver_id = programs::ping_receiver().id(); let msg = CrossZoneMessage { src_zone: [2; 32], src_block_id: 1, src_block_hash: [7; 32], src_tx_index: 0, - src_program_id: [9; 8], - target_program_id: programs::ping_receiver().id(), + src_account_id: lee::AccountId::new([9; 32]), + target_program_id: ping_receiver_id, + target_account_id: program_loader_core::immutable_deploy_account_id(ping_receiver_id), payload: vec![], l1_inclusion_witness: None, }; let seen_id = inbox_seen_shard_account_id(inbox_id, &msg.src_zone, msg.src_block_id); let message = Message::try_new( - inbox_id.into(), + program_loader_core::immutable_deploy_account_id(inbox_id), vec![inbox_config_account_id(inbox_id), seen_id], vec![], - Instruction::Dispatch(msg), + Instruction::Dispatch { + message: msg, + self_program_id: inbox_id, + }, ) .expect("build dispatch message"); let tx = LeeTransaction::Public(PublicTransaction::new( diff --git a/integration_tests/tests/cross_zone_ping.rs b/integration_tests/tests/cross_zone_ping.rs index 0287b40b5..d9bb632d4 100644 --- a/integration_tests/tests/cross_zone_ping.rs +++ b/integration_tests/tests/cross_zone_ping.rs @@ -48,7 +48,9 @@ async fn ping_crosses_from_zone_a_to_zone_b() -> Result<()> { peers: vec![CrossZonePeer { channel_id: zone_a, allowed_routes: vec![CrossZoneRoute { - src_program_id: programs::ping_sender().id(), + src_account_id: program_loader_core::immutable_deploy_account_id( + programs::ping_sender().id(), + ), target_program_id: receiver_id, }], expected_block_signing_pubkeys: Vec::new(), @@ -118,12 +120,15 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio // The payload is the ping_receiver instruction, serialized as risc0 words in // little-endian bytes (the contract the inbox reverses when forwarding). let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + self_program_id: receiver_id, payload: PING_PAYLOAD.to_vec(), }) .expect("serialize ping instruction"); let payload: Vec = words.iter().flat_map(|word| word.to_le_bytes()).collect(); + let sender_id = programs::ping_sender().id(); let send = SenderInstruction::Send { + self_program_id: sender_id, target_zone, target_program_id: receiver_id, target_accounts: vec![ @@ -134,10 +139,14 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio ordinal, }; - let sender_id = programs::ping_sender().id(); - let outbox_account = outbox_pda(outbox_id, sender_id, &target_zone, ordinal); + let outbox_account = outbox_pda( + outbox_id, + program_loader_core::immutable_deploy_account_id(sender_id), + &target_zone, + ordinal, + ); let message = Message::try_new( - sender_id.into(), + program_loader_core::immutable_deploy_account_id(sender_id), vec![sender_config_account_id(sender_id), outbox_account], vec![], send, diff --git a/integration_tests/tests/cross_zone_state_machine.rs b/integration_tests/tests/cross_zone_state_machine.rs index d48ae3c6c..1704f3246 100644 --- a/integration_tests/tests/cross_zone_state_machine.rs +++ b/integration_tests/tests/cross_zone_state_machine.rs @@ -60,7 +60,7 @@ fn seed_inbox_config(state: &mut V03State, self_zone: [u8; 32]) { *state = std::mem::replace(state, V03State::new()).with_public_accounts([( inbox_config_account_id(inbox_id), Account { - program_owner: inbox_id.into(), + program_owner: program_loader_core::immutable_deploy_account_id(inbox_id), balance: 0, data: config .to_bytes() @@ -76,7 +76,7 @@ fn seed_inbox_config(state: &mut V03State, self_zone: [u8; 32]) { fn seed_wrapped_config( state: &mut V03State, authority: Option, - sources: Vec<([u8; 32], lee_core::program::ProgramId)>, + sources: Vec<([u8; 32], AccountId)>, ) { seed_wrapped_config_with_governance(state, None, authority, sources); } @@ -86,11 +86,11 @@ fn seed_wrapped_config_with_governance( state: &mut V03State, governance: Option, authority: Option, - sources: Vec<([u8; 32], lee_core::program::ProgramId)>, + sources: Vec<([u8; 32], AccountId)>, ) { let wrapped_token_id = programs::wrapped_token().id(); let config = wrapped_token_core::WrappedTokenConfig { - minter: programs::cross_zone_inbox().id(), + minter: program_loader_core::immutable_deploy_account_id(programs::cross_zone_inbox().id()), governance, authority, sources, @@ -98,7 +98,7 @@ fn seed_wrapped_config_with_governance( *state = std::mem::replace(state, V03State::new()).with_public_accounts([( wrapped_token_core::config_account_id(wrapped_token_id), Account { - program_owner: wrapped_token_id.into(), + program_owner: program_loader_core::immutable_deploy_account_id(wrapped_token_id), data: config .to_bytes() .try_into() @@ -113,7 +113,7 @@ fn seed_wrapped_config_with_governance( fn seed_receiver_config( state: &mut V03State, authority: Option, - sources: Vec<([u8; 32], lee_core::program::ProgramId)>, + sources: Vec<([u8; 32], AccountId)>, ) { seed_receiver_config_with_governance(state, None, authority, sources); } @@ -123,11 +123,11 @@ fn seed_receiver_config_with_governance( state: &mut V03State, governance: Option, authority: Option, - sources: Vec<([u8; 32], lee_core::program::ProgramId)>, + sources: Vec<([u8; 32], AccountId)>, ) { let receiver_id = programs::ping_receiver().id(); let config = ping_core::ReceiverConfig { - deliverer: programs::cross_zone_inbox().id(), + deliverer: program_loader_core::immutable_deploy_account_id(programs::cross_zone_inbox().id()), governance, authority, sources, @@ -135,7 +135,7 @@ fn seed_receiver_config_with_governance( *state = std::mem::replace(state, V03State::new()).with_public_accounts([( receiver_config_account_id(receiver_id), Account { - program_owner: receiver_id.into(), + program_owner: program_loader_core::immutable_deploy_account_id(receiver_id), data: config .to_bytes() .try_into() @@ -149,14 +149,18 @@ fn seed_receiver_config_with_governance( /// genesis seeds for a real zone. fn seed_ping_sender_config(state: &mut V03State) { let sender_id = programs::ping_sender().id(); + let outbox_id = programs::cross_zone_outbox().id(); *state = std::mem::replace(state, V03State::new()).with_public_accounts([( sender_config_account_id(sender_id), Account { - program_owner: sender_id.into(), - data: outbox_bytes(programs::cross_zone_outbox().id()) - .to_vec() - .try_into() - .expect("outbox id fits in account data"), + program_owner: program_loader_core::immutable_deploy_account_id(sender_id), + data: outbox_bytes( + program_loader_core::immutable_deploy_account_id(outbox_id), + outbox_id, + ) + .to_vec() + .try_into() + .expect("outbox id fits in account data"), ..Default::default() }, )]); @@ -169,8 +173,9 @@ fn seed_bridge_lock_config(state: &mut V03State) { *state = std::mem::replace(state, V03State::new()).with_public_accounts([( bridge_lock_core::config_account_id(bridge_lock_id), Account { - program_owner: bridge_lock_id.into(), + program_owner: program_loader_core::immutable_deploy_account_id(bridge_lock_id), data: bridge_lock_core::config_bytes( + program_loader_core::immutable_deploy_account_id(programs::cross_zone_outbox().id()), programs::cross_zone_outbox().id(), programs::wrapped_token().id(), ) @@ -192,7 +197,11 @@ fn dispatch_accounts( let mut ids = vec![ inbox_config_account_id(inbox_id), inbox_seen_shard_account_id(inbox_id, &msg.src_zone, msg.src_block_id), - inbox_source_marker_account_id(inbox_id, &msg.src_zone, msg.src_program_id), + inbox_source_marker_account_id( + program_loader_core::immutable_deploy_account_id(inbox_id), + &msg.src_zone, + msg.src_account_id, + ), ]; ids.extend(targets); ids @@ -278,10 +287,13 @@ fn chained_via_inbox( fn send_tx(accounts: Vec, target_zone: [u8; 32], ordinal: u32) -> PublicTransaction { let receiver_id = programs::ping_receiver().id(); let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + self_program_id: receiver_id, payload: b"ping".to_vec(), }) .expect("serialize ping instruction"); + let sender_id = programs::ping_sender().id(); let send = ping_core::SenderInstruction::Send { + self_program_id: sender_id, target_zone, target_program_id: receiver_id, target_accounts: vec![ @@ -291,8 +303,13 @@ fn send_tx(accounts: Vec, target_zone: [u8; 32], ordinal: u32) -> Pub payload: words.iter().flat_map(|word| word.to_le_bytes()).collect(), ordinal, }; - let message = Message::try_new(programs::ping_sender().id().into(), accounts, vec![], send) - .expect("build ping_sender message"); + let message = Message::try_new( + program_loader_core::immutable_deploy_account_id(sender_id), + accounts, + vec![], + send, + ) + .expect("build ping_sender message"); PublicTransaction::new(message, WitnessSet::from_raw_parts(vec![])) } @@ -304,6 +321,7 @@ fn mint_payload() -> Vec { fn mint_payload_of(amount: u128) -> Vec { let mint = wrapped_token_core::Instruction::Mint { + self_program_id: programs::wrapped_token().id(), recipient: RECIPIENT, amount, }; @@ -321,21 +339,22 @@ fn dispatch_mint(amount: u128) -> Result Result Result<()> { peers: vec![CrossZonePeer { channel_id: zone_a, allowed_routes: vec![CrossZoneRoute { - src_program_id: programs::ping_sender().id(), + src_account_id: program_loader_core::immutable_deploy_account_id( + programs::ping_sender().id(), + ), target_program_id: receiver_id, }], expected_block_signing_pubkeys: Vec::new(), @@ -111,12 +113,15 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio let ordinal = 0; let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + self_program_id: receiver_id, payload: PING_PAYLOAD.to_vec(), }) .expect("serialize ping instruction"); let payload: Vec = words.iter().flat_map(|word| word.to_le_bytes()).collect(); + let sender_id = programs::ping_sender().id(); let send = SenderInstruction::Send { + self_program_id: sender_id, target_zone, target_program_id: receiver_id, target_accounts: vec![ @@ -127,10 +132,14 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio ordinal, }; - let sender_id = programs::ping_sender().id(); - let outbox_account = outbox_pda(outbox_id, sender_id, &target_zone, ordinal); + let outbox_account = outbox_pda( + outbox_id, + program_loader_core::immutable_deploy_account_id(sender_id), + &target_zone, + ordinal, + ); let message = Message::try_new( - sender_id.into(), + program_loader_core::immutable_deploy_account_id(sender_id), vec![sender_config_account_id(sender_id), outbox_account], vec![], send, diff --git a/integration_tests/tests/cross_zone_watcher_restart.rs b/integration_tests/tests/cross_zone_watcher_restart.rs index 53f438e22..b499ad706 100644 --- a/integration_tests/tests/cross_zone_watcher_restart.rs +++ b/integration_tests/tests/cross_zone_watcher_restart.rs @@ -59,7 +59,9 @@ async fn restarted_watcher_resumes_instead_of_replaying_the_peer_channel() -> Re peers: vec![CrossZonePeer { channel_id: zone_a, allowed_routes: vec![CrossZoneRoute { - src_program_id: programs::ping_sender().id(), + src_account_id: program_loader_core::immutable_deploy_account_id( + programs::ping_sender().id(), + ), target_program_id: receiver_id, }], expected_block_signing_pubkeys: Vec::new(), @@ -153,7 +155,8 @@ async fn count_inbox_transactions(client: &SequencerClient, from: u64, to: u64) }; for tx in &block.body.transactions { if let LeeTransaction::Public(public_tx) = tx - && public_tx.message().program_account_id == inbox_id.into() + && public_tx.message().program_account_id + == program_loader_core::immutable_deploy_account_id(inbox_id) { count = count.saturating_add(1); } @@ -189,12 +192,15 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio let ordinal = 0; let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + self_program_id: receiver_id, payload: PING_PAYLOAD.to_vec(), }) .expect("serialize ping instruction"); let payload: Vec = words.iter().flat_map(|word| word.to_le_bytes()).collect(); + let sender_id = programs::ping_sender().id(); let send = SenderInstruction::Send { + self_program_id: sender_id, target_zone, target_program_id: receiver_id, target_accounts: vec![ @@ -205,10 +211,14 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio ordinal, }; - let sender_id = programs::ping_sender().id(); - let outbox_account = outbox_pda(outbox_id, sender_id, &target_zone, ordinal); + let outbox_account = outbox_pda( + outbox_id, + program_loader_core::immutable_deploy_account_id(sender_id), + &target_zone, + ordinal, + ); let message = Message::try_new( - sender_id.into(), + program_loader_core::immutable_deploy_account_id(sender_id), vec![sender_config_account_id(sender_id), outbox_account], vec![], send, diff --git a/integration_tests/tests/keys.rs b/integration_tests/tests/keys.rs index 4a3a63518..bd8ddf214 100644 --- a/integration_tests/tests/keys.rs +++ b/integration_tests/tests/keys.rs @@ -143,11 +143,11 @@ async fn restore_keys_from_seed() -> Result<()> { assert_eq!( acc1.account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); assert_eq!( acc2.account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); assert_eq!(acc1.account.balance, 100); diff --git a/integration_tests/tests/private_pda.rs b/integration_tests/tests/private_pda.rs index 9abe8f2a5..27c49b87c 100644 --- a/integration_tests/tests/private_pda.rs +++ b/integration_tests/tests/private_pda.rs @@ -116,7 +116,7 @@ async fn spend_private_pda( seed: PdaSeed, amount: u128, spend_program: &ProgramWithDependencies, - auth_transfer_id: ProgramId, + auth_transfer_account_id: AccountId, ) -> Result<()> { wallet .send_privacy_preserving_tx( @@ -128,7 +128,7 @@ async fn spend_private_pda( identifier: 0, }, ], - Program::serialize_instruction((seed, amount, auth_transfer_id)) + Program::serialize_instruction((seed, amount, auth_transfer_account_id)) .context("failed to serialize pda_spend_proxy instruction")?, spend_program, ) @@ -166,9 +166,11 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { let seed = PdaSeed::new([42; 32]); let amount: u128 = 100; - let auth_transfer_program = ProgramWithDependencies::new(auth_transfer.clone(), [].into()); + let auth_transfer_account_id = program_loader_core::immutable_deploy_account_id(auth_transfer_id); + let auth_transfer_program = ProgramWithDependencies::new(auth_transfer.clone(), [].into()) + .with_program_account_id(auth_transfer_account_id); let spend_program = - ProgramWithDependencies::new(proxy, [(auth_transfer_id.into(), auth_transfer)].into()); + ProgramWithDependencies::new(proxy, [(auth_transfer_account_id, auth_transfer)].into()); let alice_pda_0_id = AccountId::for_private_pda(&proxy_id, &seed, &alice_npk, &alice_vpk, 0); let alice_pda_1_id = AccountId::for_private_pda(&proxy_id, &seed, &alice_npk, &alice_vpk, 1); @@ -271,7 +273,7 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { seed, amount_spend_0, &spend_program, - auth_transfer_id, + auth_transfer_account_id, ) .await?; @@ -284,7 +286,7 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { seed, amount_spend_1, &spend_program, - auth_transfer_id, + auth_transfer_account_id, ) .await?; diff --git a/integration_tests/tests/program_deployment.rs b/integration_tests/tests/program_deployment.rs index 1e52d2841..14a00ffe1 100644 --- a/integration_tests/tests/program_deployment.rs +++ b/integration_tests/tests/program_deployment.rs @@ -39,7 +39,7 @@ async fn deploy_and_execute_program() -> Result<()> { .get_account_public_signing_key(account_id) .unwrap(); let message = lee::public_transaction::Message::try_new( - claimer.id().into(), + program_loader_core::immutable_deploy_account_id(claimer.id()), vec![account_id], nonces, (), @@ -59,7 +59,10 @@ async fn deploy_and_execute_program() -> Result<()> { let post_state_account = get_account(&ctx, account_id).await?; let expected_data: &[u8] = &[]; - assert_eq!(post_state_account.program_owner, claimer.id().into()); + assert_eq!( + post_state_account.program_owner, + program_loader_core::immutable_deploy_account_id(claimer.id()) + ); assert_eq!(post_state_account.balance, 0); assert_eq!(post_state_account.data.as_ref(), expected_data); assert_eq!(post_state_account.nonce.0, 1); diff --git a/integration_tests/tests/tps.rs b/integration_tests/tests/tps.rs index a7a6cba00..b94c33485 100644 --- a/integration_tests/tests/tps.rs +++ b/integration_tests/tests/tps.rs @@ -85,7 +85,7 @@ impl TpsTestManager { let owner_vault_id = vault_core::compute_vault_account_id(vault_program_id, *account_id); let message = putx::Message::try_new( - vault_program_id.into(), + program_loader_core::immutable_deploy_account_id(vault_program_id), vec![*account_id, owner_vault_id], vec![Nonce(0_u128)], vault_core::Instruction::Claim { amount: 10 }, @@ -135,7 +135,7 @@ impl TpsTestManager { .map(|pair| { let amount: u128 = 1; let message = putx::Message::try_new( - program.id().into(), + program_loader_core::immutable_deploy_account_id(program.id()), [pair[0].1, pair[1].1].to_vec(), [Nonce(1_u128)].to_vec(), authenticated_transfer_core::Instruction::Transfer { amount }, @@ -270,7 +270,7 @@ fn build_privacy_transaction() -> PrivacyPreservingTransaction { Account { balance: 100, nonce: Nonce(0xdead_beef), - program_owner: program.id().into(), + program_owner: program_loader_core::immutable_deploy_account_id(program.id()), data: Data::default(), }, true, diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index f2bb19f47..8707ef83d 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -634,7 +634,7 @@ fn test_wallet_ffi_get_account_public() -> Result<()> { assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); @@ -674,7 +674,7 @@ fn test_wallet_ffi_get_account_private() -> Result<()> { assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); assert_eq!(account.balance, 10000); assert!(account.data.is_empty()); @@ -872,7 +872,7 @@ fn wallet_ffi_init_public_account_auth_transfer() -> Result<()> { }; assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); unsafe { @@ -932,7 +932,7 @@ fn wallet_ffi_init_private_account_auth_transfer() -> Result<()> { }; assert_eq!( account.program_owner, - programs::authenticated_transfer().id().into() + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()) ); unsafe { diff --git a/lee/privacy_preserving_circuit/src/execution_state.rs b/lee/privacy_preserving_circuit/src/execution_state.rs index 1c8048c85..ec6ecbf54 100644 --- a/lee/privacy_preserving_circuit/src/execution_state.rs +++ b/lee/privacy_preserving_circuit/src/execution_state.rs @@ -121,8 +121,18 @@ impl ExecutionState { panic!("No program outputs provided"); }; + // The initial program's real dispatch address. Like every other address in this + // circuit, it doesn't have to equal the legacy bijection `AccountId::from(program_id)` + // for a `Deploy`-created program — the host supplies the real one via a claim (see + // `ProgramImageClaim`'s doc comment) whenever it differs, exactly as it does for every + // dependency below. + let initial_program_account_id = program_image_claims + .iter() + .find(|claim| claim.image_id == program_id) + .map_or_else(|| AccountId::from(program_id), |claim| claim.account_id); + let initial_call = ChainedCall { - program_account_id: AccountId::from(program_id), + program_account_id: initial_program_account_id, instruction_data: first_output.instruction_data.clone(), pre_states: first_output.pre_states.clone(), pda_seeds: Vec::new(), @@ -208,6 +218,7 @@ impl ExecutionState { execution_state.validate_and_sync_states( account_identities, + chained_call.program_account_id, current_program_id, caller_image_id, &chained_call.pda_seeds, @@ -264,9 +275,14 @@ impl ExecutionState { } /// Validate program pre and post states and populate the execution state. + #[expect( + clippy::too_many_arguments, + reason = "breaking out a context struct does not buy us anything here" + )] fn validate_and_sync_states( &mut self, account_identities: &[InputAccountIdentity], + account_id: AccountId, program_id: ProgramId, caller_image_id: Option, caller_pda_seeds: &[PdaSeed], @@ -455,7 +471,7 @@ impl ExecutionState { } } - post.account_mut().program_owner = AccountId::from(program_id); + post.account_mut().program_owner = account_id; } post_states_entry.insert_entry(post.into_account()); diff --git a/lee/state_machine/src/privacy_preserving_transaction/circuit/tests.rs b/lee/state_machine/src/privacy_preserving_transaction/circuit/tests.rs index 386adbddb..59888323a 100644 --- a/lee/state_machine/src/privacy_preserving_transaction/circuit/tests.rs +++ b/lee/state_machine/src/privacy_preserving_transaction/circuit/tests.rs @@ -370,10 +370,11 @@ fn circuit_fails_when_chained_validity_windows_have_empty_intersection() { let validity_window_chain_caller = crate::test_methods::validity_window_chain_caller(); let validity_window = crate::test_methods::validity_window(); + let validity_window_account_id = validity_window.deployed_account_id(); let instruction = Program::serialize_instruction(( Some(1_u64), Some(4_u64), - validity_window.id(), + validity_window_account_id, Some(4_u64), Some(7_u64), )) @@ -381,7 +382,7 @@ fn circuit_fails_when_chained_validity_windows_have_empty_intersection() { let program_with_deps = ProgramWithDependencies::new( validity_window_chain_caller, - [(validity_window.id().into(), validity_window)].into(), + [(validity_window_account_id, validity_window)].into(), ); let result = execute_and_prove( @@ -463,9 +464,9 @@ fn private_pda_init() { let pda_id = AccountId::for_private_pda(&program.id(), &seed, &npk, &keys.vpk(), 0); let pda_pre = AccountWithMetadata::new(Account::default(), false, pda_id); - let auth_id = simple_transfer.id(); + let auth_id = simple_transfer.deployed_account_id(); let program_with_deps = - ProgramWithDependencies::new(program, [(auth_id.into(), simple_transfer)].into()); + ProgramWithDependencies::new(program, [(auth_id, simple_transfer)].into()); // is_withdraw=false triggers init path (1 pre-state) let instruction = Program::serialize_instruction((seed, auth_id, 0_u128, false)).unwrap(); @@ -497,9 +498,10 @@ fn private_pda_withdraw() { // Recipient (public) let recipient_id = AccountId::new([88; 32]); + let auth_id = simple_transfer.deployed_account_id(); let recipient_pre = AccountWithMetadata::new( Account { - program_owner: simple_transfer.id().into(), + program_owner: auth_id, balance: 10000, ..Account::default() }, @@ -507,9 +509,8 @@ fn private_pda_withdraw() { recipient_id, ); - let auth_id = simple_transfer.id(); let program_with_deps = - ProgramWithDependencies::new(program, [(auth_id.into(), simple_transfer)].into()); + ProgramWithDependencies::new(program, [(auth_id, simple_transfer)].into()); // is_withdraw=true, amount=0 (PDA has no balance yet) let instruction = Program::serialize_instruction((seed, auth_id, 0_u128, true)).unwrap(); @@ -940,7 +941,7 @@ fn pda_update_attempt( let simple_transfer = crate::test_methods::simple_balance_transfer(); let keys = test_private_account_keys_1(); let seed = PdaSeed::new([42; 32]); - let simple_transfer_id = simple_transfer.id(); + let simple_transfer_account_id = simple_transfer.deployed_account_id(); let pda_id = AccountId::for_private_pda( &program.id(), &seed, @@ -949,7 +950,7 @@ fn pda_update_attempt( derivation_identifier, ); let pda_account = Account { - program_owner: simple_transfer_id.into(), + program_owner: simple_transfer_account_id, balance: 1, ..Account::default() }; @@ -962,12 +963,12 @@ fn pda_update_attempt( let program_with_deps = ProgramWithDependencies::new( program, - [(simple_transfer_id.into(), simple_transfer)].into(), + [(simple_transfer_account_id, simple_transfer)].into(), ); execute_and_prove( vec![pda_pre, recipient_pre], - Program::serialize_instruction((seed, 1_u128, simple_transfer_id)).unwrap(), + Program::serialize_instruction((seed, 1_u128, simple_transfer_account_id, false)).unwrap(), vec![ InputAccountIdentity::Private(PrivateWitness { vpk: keys.vpk(), diff --git a/lee/state_machine/src/program/mod.rs b/lee/state_machine/src/program/mod.rs index 617721d93..5eee97061 100644 --- a/lee/state_machine/src/program/mod.rs +++ b/lee/state_machine/src/program/mod.rs @@ -46,6 +46,16 @@ impl Program { &self.elf } + /// The address this program dispatches at once seeded via [`crate::V03State::with_programs`] + /// (or any live `Deploy` submitted with a default `update_auth`) — see + /// `program_loader_core::immutable_deploy_account_id`. Not the program's own bijection + /// `AccountId::from(self.id())`, which is only meaningful for the legacy + /// `ProgramDeploymentTransaction` storage shape. + #[must_use] + pub fn deployed_account_id(&self) -> AccountId { + program_loader_core::immutable_deploy_account_id(self.id) + } + pub fn serialize_instruction( instruction: T, ) -> Result { diff --git a/lee/state_machine/src/state/mod.rs b/lee/state_machine/src/state/mod.rs index d4063acdb..86dfa4178 100644 --- a/lee/state_machine/src/state/mod.rs +++ b/lee/state_machine/src/state/mod.rs @@ -203,19 +203,18 @@ impl V03State { self } - /// Seeds a program directly into state in the same two-account shape a `Deploy` dispatch - /// produces (see [`Self::get_program`]), skipping the dispatch/proving machinery genesis has - /// no signer to drive. The header account is placed at `AccountId::from(image_id)` rather - /// than the loader-PDA address a live `Deploy` would use for it — deliberately, so a - /// genesis-seeded program keeps its well-known dispatch address — while the segment account - /// still lives at the exact PDA [`Self::get_program`] derives from the header's content, - /// since that address is never a caller-facing well-known address to begin with. + /// Seeds a program directly into state in the exact two-account shape a live `Deploy` + /// dispatch (with a default `update_auth`, i.e. no upgrade authority) would produce for the + /// same `image_id` (see [`Self::get_program`] and [`program_loader_core::immutable_deploy_account_id`]), + /// skipping only the dispatch/proving machinery genesis has no signer to drive. pub(crate) fn insert_program(&mut self, program: &Program) { let image_id = program.id(); let segment_number = 0; let update_auth = AccountId::default(); + let loader_id = ProgramId::from(RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID); - let header_account_id = AccountId::from(image_id); + let header_account_id = + program_loader_core::deploy_header_account_id(loader_id, image_id, segment_number, update_auth); let header_account = Account { program_owner: RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID, data: Data::from(&ProgramData { @@ -226,8 +225,7 @@ impl V03State { ..Account::default() }; - let loader_id = ProgramId::from(RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID); - let segment_account_id = loader_core::deploy_segment_account_id( + let segment_account_id = program_loader_core::deploy_segment_account_id( loader_id, image_id, segment_number, @@ -331,7 +329,7 @@ impl V03State { /// - Owned by [`RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID`]: deployed via the native `Deploy` /// dispatch shortcut. `account.data` decodes as a [`ProgramData`] header holding the real /// `image_id`; the bytecode itself lives in a second, separately-addressed segment account - /// derived from that header (see `loader_core::deploy_segment_account_id`). + /// derived from that header (see `program_loader_core::deploy_segment_account_id`). /// /// Returning the real `image_id` — rather than callers deriving one from the address, which /// is only valid for the legacy path — is what makes upgrading a `Deploy`-created program @@ -350,7 +348,7 @@ impl V03State { if account.program_owner == RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID { let header = ProgramData::try_from(&account.data).ok()?; let loader_id = ProgramId::from(RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID); - let segment_account_id = loader_core::deploy_segment_account_id( + let segment_account_id = program_loader_core::deploy_segment_account_id( loader_id, header.image_id, header.segment_number, diff --git a/lee/state_machine/src/state/tests/authenticated_transfer.rs b/lee/state_machine/src/state/tests/authenticated_transfer.rs index 28e048e7c..27252e26b 100644 --- a/lee/state_machine/src/state/tests/authenticated_transfer.rs +++ b/lee/state_machine/src/state/tests/authenticated_transfer.rs @@ -7,7 +7,7 @@ fn transition_from_authenticated_transfer_program_invocation_default_account_des let initial_data = [( account_id, Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), balance: 100, ..Account::default() }, @@ -64,7 +64,7 @@ fn transition_from_authenticated_transfer_program_invocation_non_default_account ( account_id1, Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), balance: 100, ..Account::default() }, @@ -72,7 +72,7 @@ fn transition_from_authenticated_transfer_program_invocation_non_default_account ( account_id2, Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), balance: 200, ..Account::default() }, @@ -106,7 +106,7 @@ fn transition_from_sequence_of_authenticated_transfer_program_invocations() { let initial_data = [( account_id1, Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), balance: 100, ..Account::default() }, diff --git a/lee/state_machine/src/state/tests/changer_claimer.rs b/lee/state_machine/src/state/tests/changer_claimer.rs index fc46fd785..8b52b12e7 100644 --- a/lee/state_machine/src/state/tests/changer_claimer.rs +++ b/lee/state_machine/src/state/tests/changer_claimer.rs @@ -7,7 +7,7 @@ fn public_changer_claimer_no_data_change_no_claim_succeeds() { .with_public_accounts(public_state_from_balances(&initial_data)) .with_test_programs(); let account_id = AccountId::new([1; 32]); - let account_id_for_message: AccountId = crate::test_methods::changer_claimer().id().into(); + let account_id_for_message = crate::test_methods::changer_claimer().deployed_account_id(); // Don't change data (None) and don't claim (false) let instruction: (Option>, bool) = (None, false); @@ -36,7 +36,7 @@ fn public_changer_claimer_data_change_no_claim_fails() { .with_public_accounts(public_state_from_balances(&initial_data)) .with_test_programs(); let account_id = AccountId::new([1; 32]); - let account_id_for_message: AccountId = crate::test_methods::changer_claimer().id().into(); + let account_id_for_message = crate::test_methods::changer_claimer().deployed_account_id(); // Change data but don't claim (false) - should fail let new_data = vec![1, 2, 3, 4, 5]; let instruction: (Option>, bool) = (Some(new_data), false); diff --git a/lee/state_machine/src/state/tests/circuit.rs b/lee/state_machine/src/state/tests/circuit.rs index 8f4d13e06..c39617f7d 100644 --- a/lee/state_machine/src/state/tests/circuit.rs +++ b/lee/state_machine/src/state/tests/circuit.rs @@ -1,3 +1,5 @@ +use lee_core::program::ProgramId; + use super::*; #[test] @@ -497,13 +499,13 @@ fn caller_pda_seeds_authorize_private_pda_for_callee() { AccountId::for_private_pda(&delegator.id(), &seed, &npk, &keys.vpk(), u128::MAX); let pre_state = AccountWithMetadata::new(Account::default(), false, account_id); - let callee_id = callee.id(); + let callee_account_id = callee.deployed_account_id(); let program_with_deps = - ProgramWithDependencies::new(delegator, [(callee_id.into(), callee)].into()); + ProgramWithDependencies::new(delegator, [(callee_account_id, callee)].into()); let result = execute_and_prove( vec![pre_state], - Program::serialize_instruction((seed, seed, callee_id)).unwrap(), + Program::serialize_instruction((seed, seed, callee_account_id)).unwrap(), vec![init_pda_witness(&keys, u128::MAX, None)], &program_with_deps, ); @@ -530,13 +532,14 @@ fn caller_pda_seeds_with_wrong_seed_rejects_private_pda_for_callee() { AccountId::for_private_pda(&delegator.id(), &claim_seed, &npk, &keys.vpk(), u128::MAX); let pre_state = AccountWithMetadata::new(Account::default(), false, account_id); - let callee_id = callee.id(); + let callee_account_id = callee.deployed_account_id(); let program_with_deps = - ProgramWithDependencies::new(delegator, [(callee_id.into(), callee)].into()); + ProgramWithDependencies::new(delegator, [(callee_account_id, callee)].into()); let result = execute_and_prove( vec![pre_state], - Program::serialize_instruction((claim_seed, wrong_delegated_seed, callee_id)).unwrap(), + Program::serialize_instruction((claim_seed, wrong_delegated_seed, callee_account_id)) + .unwrap(), vec![init_pda_witness(&keys, u128::MAX, None)], &program_with_deps, ); @@ -1330,13 +1333,13 @@ fn two_private_pda_family_members_receive_and_spend() { let proxy = crate::test_methods::pda_spend_proxy(); let simple_transfer = crate::test_methods::simple_balance_transfer(); let proxy_id = proxy.id(); - let simple_transfer_id = simple_transfer.id(); + let simple_transfer_account_id = simple_transfer.deployed_account_id(); let seed = PdaSeed::new([42; 32]); let amount: u128 = 100; let spend_with_deps = ProgramWithDependencies::new( proxy, - [(simple_transfer_id.into(), simple_transfer.clone())].into(), + [(simple_transfer_account_id, simple_transfer.clone())].into(), ); let funder_id = funder_keys.account_id(); @@ -1347,17 +1350,18 @@ fn two_private_pda_family_members_receive_and_spend() { let recipient_id = test_public_account_keys_2().account_id(); let recipient_signing_key = test_public_account_keys_2().signing_key; - let mut state = - V03State::new().with_public_accounts(public_state_from_balances(&[(funder_id, 500)])); + let mut state = V03State::new() + .with_public_accounts(public_state_from_balances(&[(funder_id, 500)])) + .with_test_programs(); let alice_pda_0_account = Account { - program_owner: simple_transfer_id.into(), + program_owner: simple_transfer_account_id, balance: amount, nonce: Nonce::private_account_nonce_init(&alice_pda_0_id), ..Account::default() }; let alice_pda_1_account = Account { - program_owner: simple_transfer_id.into(), + program_owner: simple_transfer_account_id, balance: amount, nonce: Nonce::private_account_nonce_init(&alice_pda_1_id), ..Account::default() @@ -1377,7 +1381,8 @@ fn two_private_pda_family_members_receive_and_spend() { InputAccountIdentity::Public, init_pda_witness(&alice_keys, 0, Some((proxy_id, seed))), ], - &simple_transfer.clone().into(), + &ProgramWithDependencies::from(simple_transfer.clone()) + .with_program_account_id(simple_transfer_account_id), ) .unwrap(); let message = Message::from_circuit_output(vec![funder_nonce], output); @@ -1405,7 +1410,8 @@ fn two_private_pda_family_members_receive_and_spend() { InputAccountIdentity::Public, init_pda_witness(&alice_keys, 1, Some((proxy_id, seed))), ], - &simple_transfer.into(), + &ProgramWithDependencies::from(simple_transfer) + .with_program_account_id(simple_transfer_account_id), ) .unwrap(); let message = Message::from_circuit_output(vec![funder_nonce], output); @@ -1433,7 +1439,7 @@ fn two_private_pda_family_members_receive_and_spend() { AccountWithMetadata::new(alice_pda_0_account, false, alice_pda_0_id), AccountWithMetadata::new(recipient_account, true, recipient_id), ], - Program::serialize_instruction((seed, amount, simple_transfer_id)).unwrap(), + Program::serialize_instruction((seed, amount, simple_transfer_account_id)).unwrap(), vec![ InputAccountIdentity::Private(PrivateWitness { vpk: alice_keys.vpk(), @@ -1472,7 +1478,7 @@ fn two_private_pda_family_members_receive_and_spend() { AccountWithMetadata::new(alice_pda_1_account.clone(), false, alice_pda_1_id), AccountWithMetadata::new(recipient_account, false, recipient_id), ], - Program::serialize_instruction((seed, amount, simple_transfer_id)).unwrap(), + Program::serialize_instruction((seed, amount, simple_transfer_account_id)).unwrap(), vec![ InputAccountIdentity::Private(PrivateWitness { vpk: alice_keys.vpk(), @@ -1508,7 +1514,7 @@ fn two_private_pda_family_members_receive_and_spend() { // Re-fund alice_pda_1 top-level via simple_transfer using a private-PDA update with an // external seed. let alice_pda_1_account_after_spend = Account { - program_owner: simple_transfer_id.into(), + program_owner: simple_transfer_account_id, balance: 0, nonce: alice_pda_1_account .nonce @@ -1544,7 +1550,8 @@ fn two_private_pda_family_members_receive_and_spend() { }, }), ], - &crate::test_methods::simple_balance_transfer().into(), + &ProgramWithDependencies::from(crate::test_methods::simple_balance_transfer()) + .with_program_account_id(simple_transfer_account_id), ) .unwrap(); let message = Message::from_circuit_output(vec![recipient_nonce], output); diff --git a/lee/state_machine/src/state/tests/claiming.rs b/lee/state_machine/src/state/tests/claiming.rs index 88334e66e..218ffcfc1 100644 --- a/lee/state_machine/src/state/tests/claiming.rs +++ b/lee/state_machine/src/state/tests/claiming.rs @@ -18,14 +18,14 @@ fn claiming_mechanism() { assert_eq!(state.get_account_by_id(to), Account::default()); let expected_recipient_post = Account { - program_owner: program.id().into(), + program_owner: program.deployed_account_id(), balance: amount, nonce: Nonce(1), ..Account::default() }; let message = public_transaction::Message::try_new( - program.id().into(), + program.deployed_account_id(), vec![from, to], vec![Nonce(0), Nonce(0)], amount, @@ -50,9 +50,13 @@ fn unauthorized_public_account_claiming_fails() { assert_eq!(state.get_account_by_id(account_id), Account::default()); - let message = - public_transaction::Message::try_new(program.id().into(), vec![account_id], vec![], 0_u128) - .unwrap(); + let message = public_transaction::Message::try_new( + program.deployed_account_id(), + vec![account_id], + vec![], + 0_u128, + ) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -72,7 +76,7 @@ fn authorized_public_account_claiming_succeeds() { assert_eq!(state.get_account_by_id(account_id), Account::default()); let message = public_transaction::Message::try_new( - program.id().into(), + program.deployed_account_id(), vec![account_id], vec![Nonce(0)], 0_u128, @@ -86,7 +90,7 @@ fn authorized_public_account_claiming_succeeds() { assert_eq!( state.get_account_by_id(account_id), Account { - program_owner: program.id().into(), + program_owner: program.deployed_account_id(), nonce: Nonce(1), ..Account::default() } @@ -106,21 +110,21 @@ fn public_chained_call() { .with_test_programs(); let from_key = key; let amount: u128 = 37; - let instruction: (u128, ProgramId, u32, Option) = ( + let instruction: (u128, AccountId, u32, Option) = ( amount, - crate::test_methods::simple_balance_transfer().id(), + crate::test_methods::simple_balance_transfer().deployed_account_id(), 2, None, ); let expected_to_post = Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), balance: amount * 2, // The `chain_caller` chains the program twice ..Account::default() }; let message = public_transaction::Message::try_new( - program.id().into(), + program.deployed_account_id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call vec![Nonce(0)], @@ -152,15 +156,15 @@ fn execution_fails_if_chained_calls_exceeds_depth() { .with_test_programs(); let from_key = key; let amount: u128 = 0; - let instruction: (u128, ProgramId, u32, Option) = ( + let instruction: (u128, AccountId, u32, Option) = ( amount, - crate::test_methods::simple_balance_transfer().id(), + crate::test_methods::simple_balance_transfer().deployed_account_id(), u32::try_from(MAX_NUMBER_CHAINED_CALLS).expect("MAX_NUMBER_CHAINED_CALLS fits in u32") + 1, None, ); let message = public_transaction::Message::try_new( - program.id().into(), + program.deployed_account_id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call vec![Nonce(0)], @@ -189,20 +193,20 @@ fn execution_that_requires_authentication_of_a_program_derived_account_id_succee .with_public_accounts(public_state_from_balances(&initial_data)) .with_test_programs(); let amount: u128 = 58; - let instruction: (u128, ProgramId, u32, Option) = ( + let instruction: (u128, AccountId, u32, Option) = ( amount, - crate::test_methods::simple_balance_transfer().id(), + crate::test_methods::simple_balance_transfer().deployed_account_id(), 1, Some(pda_seed), ); let expected_to_post = Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), balance: amount, // The `chain_caller` chains the program twice ..Account::default() }; let message = public_transaction::Message::try_new( - chain_caller.id().into(), + chain_caller.deployed_account_id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call vec![], @@ -244,7 +248,7 @@ fn claiming_mechanism_within_chain_call() { let expected_to_post = Account { // The expected program owner is the authenticated transfer program - program_owner: simple_transfer.id().into(), + program_owner: simple_transfer.deployed_account_id(), balance: amount, nonce: Nonce(1), ..Account::default() @@ -252,14 +256,14 @@ fn claiming_mechanism_within_chain_call() { // The transaction executes the chain_caller program, which internally calls the // authenticated_transfer program - let instruction: (u128, ProgramId, u32, Option) = ( + let instruction: (u128, AccountId, u32, Option) = ( amount, - crate::test_methods::simple_balance_transfer().id(), + crate::test_methods::simple_balance_transfer().deployed_account_id(), 1, None, ); let message = public_transaction::Message::try_new( - chain_caller.id().into(), + chain_caller.deployed_account_id(), vec![to, from], // The chain_caller program permutes the account order in the chain // call vec![Nonce(0), Nonce(0)], @@ -378,9 +382,10 @@ fn private_chained_call(number_of_calls: u32) { let from_keys = test_private_account_keys_1(); let to_keys = test_private_account_keys_2(); let initial_balance = 100; + let simple_transfers_account_id = simple_transfers.deployed_account_id(); let from_account = AccountWithMetadata::new( Account { - program_owner: simple_transfers.id().into(), + program_owner: simple_transfers_account_id, balance: initial_balance, ..Account::default() }, @@ -389,7 +394,7 @@ fn private_chained_call(number_of_calls: u32) { ); let to_account = AccountWithMetadata::new( Account { - program_owner: simple_transfers.id().into(), + program_owner: simple_transfers_account_id, ..Account::default() }, true, @@ -410,16 +415,12 @@ fn private_chained_call(number_of_calls: u32) { ]) .with_test_programs(); let amount: u128 = 37; - let instruction: (u128, ProgramId, u32, Option) = ( - amount, - crate::test_methods::simple_balance_transfer().id(), - number_of_calls, - None, - ); + let instruction: (u128, AccountId, u32, Option) = + (amount, simple_transfers_account_id, number_of_calls, None); let mut dependencies = HashMap::new(); - dependencies.insert(simple_transfers.id().into(), simple_transfers); + dependencies.insert(simple_transfers_account_id, simple_transfers); let program_with_deps = ProgramWithDependencies::new(chain_caller, dependencies); let from_new_nonce = Nonce::default().private_account_nonce_increment(&from_keys.nsk()); @@ -515,9 +516,13 @@ fn claiming_mechanism_cannot_claim_initialied_accounts() { }, ); - let message = - public_transaction::Message::try_new(claimer.id().into(), vec![account_id], vec![], ()) - .unwrap(); + let message = public_transaction::Message::try_new( + claimer.deployed_account_id(), + vec![account_id], + vec![], + (), + ) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -543,14 +548,15 @@ fn malicious_program_cannot_break_balance_validation_if_not_in_genesis() { let recipient_id = AccountId::from(&PublicKey::new_from_private_key(&recipient_key)); let recipient_init_balance: u128 = 10; - let modified_transfer_id = crate::test_methods::modified_transfer_program().id(); + let modified_transfer_account_id = + crate::test_methods::modified_transfer_program().deployed_account_id(); let mut state = V03State::new() .with_public_accounts([ ( sender_id, Account { - program_owner: modified_transfer_id.into(), + program_owner: modified_transfer_account_id, balance: sender_init_balance, ..Account::default() }, @@ -558,7 +564,7 @@ fn malicious_program_cannot_break_balance_validation_if_not_in_genesis() { ( recipient_id, Account { - program_owner: modified_transfer_id.into(), + program_owner: modified_transfer_account_id, balance: recipient_init_balance, ..Account::default() }, @@ -576,7 +582,7 @@ fn malicious_program_cannot_break_balance_validation_if_not_in_genesis() { AccountWithMetadata::new(state.get_account_by_id(recipient_id), false, sender_id); let message = public_transaction::Message::try_new( - modified_transfer_id.into(), + modified_transfer_account_id, vec![sender_id, recipient_id], vec![sender_nonce], balance_to_move, diff --git a/lee/state_machine/src/state/tests/flash_swap.rs b/lee/state_machine/src/state/tests/flash_swap.rs index e1b79cae3..c3efdda56 100644 --- a/lee/state_machine/src/state/tests/flash_swap.rs +++ b/lee/state_machine/src/state/tests/flash_swap.rs @@ -13,12 +13,12 @@ fn flash_swap_successful() { let amount_out: u128 = 100; let vault_account = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), balance: initial_balance, ..Account::default() }; let receiver_account = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), balance: 0, ..Account::default() }; @@ -30,14 +30,14 @@ fn flash_swap_successful() { // Callback instruction: return funds let cb_instruction = CallbackInstruction { return_funds: true, - token_program_id: token.id(), + token_program_id: token.deployed_account_id(), amount: amount_out, }; let cb_data = Program::serialize_instruction(cb_instruction).unwrap(); let instruction = FlashSwapInstruction::Initiate { - token_program_id: token.id(), - callback_program_id: callback.id(), + token_program_id: token.deployed_account_id(), + callback_program_id: callback.deployed_account_id(), amount_out, callback_instruction_data: cb_data, }; @@ -64,12 +64,12 @@ fn flash_swap_callback_keeps_funds_rollback() { let amount_out: u128 = 100; let vault_account = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), balance: initial_balance, ..Account::default() }; let receiver_account = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), balance: 0, ..Account::default() }; @@ -81,14 +81,14 @@ fn flash_swap_callback_keeps_funds_rollback() { // Callback instruction: do NOT return funds let cb_instruction = CallbackInstruction { return_funds: false, - token_program_id: token.id(), + token_program_id: token.deployed_account_id(), amount: amount_out, }; let cb_data = Program::serialize_instruction(cb_instruction).unwrap(); let instruction = FlashSwapInstruction::Initiate { - token_program_id: token.id(), - callback_program_id: callback.id(), + token_program_id: token.deployed_account_id(), + callback_program_id: callback.deployed_account_id(), amount_out, callback_instruction_data: cb_data, }; @@ -121,12 +121,12 @@ fn flash_swap_self_call_targets_correct_program() { let initial_balance: u128 = 1000; let vault_account = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), balance: initial_balance, ..Account::default() }; let receiver_account = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), balance: 0, ..Account::default() }; @@ -137,14 +137,14 @@ fn flash_swap_self_call_targets_correct_program() { let cb_instruction = CallbackInstruction { return_funds: true, - token_program_id: token.id(), + token_program_id: token.deployed_account_id(), amount: 0, }; let cb_data = Program::serialize_instruction(cb_instruction).unwrap(); let instruction = FlashSwapInstruction::Initiate { - token_program_id: token.id(), - callback_program_id: callback.id(), + token_program_id: token.deployed_account_id(), + callback_program_id: callback.deployed_account_id(), amount_out: 0, callback_instruction_data: cb_data, }; @@ -167,7 +167,7 @@ fn flash_swap_standalone_invariant_check_rejected() { let vault_id = AccountId::for_public_pda(&initiator.id(), &PdaSeed::new([0_u8; 32])); let vault_account = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), balance: 1000, ..Account::default() }; @@ -180,7 +180,7 @@ fn flash_swap_standalone_invariant_check_rejected() { }; let message = public_transaction::Message::try_new( - initiator.id().into(), + initiator.deployed_account_id(), vec![vault_id], vec![], instruction, @@ -205,9 +205,13 @@ fn malicious_self_program_id_rejected_in_public_execution() { let mut state = V03State::new().with_test_programs(); state.force_insert_account(acc_id, account); - let message = - public_transaction::Message::try_new(program.id().into(), vec![acc_id], vec![], ()) - .unwrap(); + let message = public_transaction::Message::try_new( + program.deployed_account_id(), + vec![acc_id], + vec![], + (), + ) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -227,9 +231,13 @@ fn malicious_caller_program_id_rejected_in_public_execution() { let mut state = V03State::new().with_test_programs(); state.force_insert_account(acc_id, account); - let message = - public_transaction::Message::try_new(program.id().into(), vec![acc_id], vec![], ()) - .unwrap(); + let message = public_transaction::Message::try_new( + program.deployed_account_id(), + vec![acc_id], + vec![], + (), + ) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); diff --git a/lee/state_machine/src/state/tests/genesis.rs b/lee/state_machine/src/state/tests/genesis.rs index 07b2e22c4..34152d019 100644 --- a/lee/state_machine/src/state/tests/genesis.rs +++ b/lee/state_machine/src/state/tests/genesis.rs @@ -63,8 +63,7 @@ fn new_includes_nullifiers_for_private_accounts() { 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(); - let account_id = lee_core::account::AccountId::from(program_id); + let account_id = program_to_insert.deployed_account_id(); assert!(!state.public_state.contains_key(&account_id)); state.insert_program(&program_to_insert); @@ -79,7 +78,7 @@ fn get_account_by_account_id_non_default_account() { let initial_data = [( account_id, Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), balance: 100, ..Account::default() }, diff --git a/lee/state_machine/src/state/tests/mod.rs b/lee/state_machine/src/state/tests/mod.rs index 3c33d4961..0ee32d0ab 100644 --- a/lee/state_machine/src/state/tests/mod.rs +++ b/lee/state_machine/src/state/tests/mod.rs @@ -110,7 +110,7 @@ impl V03State { #[must_use] pub fn with_account_owned_by_burner_program(mut self) -> Self { let account = Account { - program_owner: crate::test_methods::burner().id().into(), + program_owner: crate::test_methods::burner().deployed_account_id(), balance: 100, ..Default::default() }; @@ -162,15 +162,15 @@ impl TestPrivateKeys { #[derive(serde::Serialize, serde::Deserialize)] struct CallbackInstruction { return_funds: bool, - token_program_id: ProgramId, + token_program_id: AccountId, amount: u128, } #[derive(serde::Serialize, serde::Deserialize)] enum FlashSwapInstruction { Initiate { - token_program_id: ProgramId, - callback_program_id: ProgramId, + token_program_id: AccountId, + callback_program_id: AccountId, amount_out: u128, callback_instruction_data: Vec, }, @@ -187,7 +187,8 @@ fn public_state_from_balances(initial_data: &[(AccountId, u128)]) -> HashMap PublicTransaction { let account_ids = vec![from, to]; let nonces = vec![Nonce(from_nonce), Nonce(to_nonce)]; - let program_id = crate::test_methods::simple_balance_transfer().id(); + let program_id = crate::test_methods::simple_balance_transfer().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), account_ids, nonces, balance) - .unwrap(); + public_transaction::Message::try_new(program_id, account_ids, nonces, balance).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[from_key, to_key]); PublicTransaction::new(message, witness_set) } @@ -222,7 +222,7 @@ fn build_flash_swap_tx( instruction: FlashSwapInstruction, ) -> PublicTransaction { let message = public_transaction::Message::try_new( - initiator.id().into(), + initiator.deployed_account_id(), vec![vault_id, receiver_id], vec![], // no signers — vault is PDA-authorised instruction, diff --git a/lee/state_machine/src/state/tests/privacy_preserving.rs b/lee/state_machine/src/state/tests/privacy_preserving.rs index d1a18d77d..cfeb78738 100644 --- a/lee/state_machine/src/state/tests/privacy_preserving.rs +++ b/lee/state_machine/src/state/tests/privacy_preserving.rs @@ -477,7 +477,7 @@ fn malicious_authorization_changer_should_fail_in_privacy_preserving_circuit() { let sender_account = AccountWithMetadata::new( Account { - program_owner: simple_transfers.id().into(), + program_owner: simple_transfers.deployed_account_id(), balance: 100, ..Default::default() }, @@ -503,10 +503,11 @@ fn malicious_authorization_changer_should_fail_in_privacy_preserving_circuit() { .with_test_programs(); let balance_to_transfer = 10_u128; - let instruction = (balance_to_transfer, simple_transfers.id()); + let simple_transfers_account_id = simple_transfers.deployed_account_id(); + let instruction = (balance_to_transfer, simple_transfers_account_id); let mut dependencies = HashMap::new(); - dependencies.insert(simple_transfers.id().into(), simple_transfers); + dependencies.insert(simple_transfers_account_id, simple_transfers); let program_with_deps = ProgramWithDependencies::new(malicious_program, dependencies); // Act - execute the malicious program - this should fail during proving diff --git a/lee/state_machine/src/state/tests/public_program_rules.rs b/lee/state_machine/src/state/tests/public_program_rules.rs index 40844c264..51de67a59 100644 --- a/lee/state_machine/src/state/tests/public_program_rules.rs +++ b/lee/state_machine/src/state/tests/public_program_rules.rs @@ -7,9 +7,9 @@ fn program_should_fail_if_modifies_nonces() { .with_public_account_balances([(account_id, 100)]) .with_test_programs(); let account_ids = vec![account_id]; - let program_id = crate::test_methods::nonce_changer().id(); + let program_id = crate::test_methods::nonce_changer().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), account_ids, vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -31,9 +31,9 @@ fn program_should_fail_if_output_accounts_exceed_inputs() { .with_public_account_balances([(AccountId::new([1; 32]), 0)]) .with_test_programs(); let account_ids = vec![AccountId::new([1; 32])]; - let program_id = crate::test_methods::extra_output().id(); + let program_id = crate::test_methods::extra_output().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), account_ids, vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -58,9 +58,9 @@ fn program_should_fail_with_missing_output_accounts() { .with_public_account_balances([(AccountId::new([1; 32]), 100)]) .with_test_programs(); let account_ids = vec![AccountId::new([1; 32]), AccountId::new([2; 32])]; - let program_id = crate::test_methods::missing_output().id(); + let program_id = crate::test_methods::missing_output().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), account_ids, vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -96,7 +96,7 @@ fn program_should_fail_if_it_drops_a_declared_account() { ( AccountId::new([1; 32]), Account { - program_owner: crate::test_methods::dropped_account().id().into(), + program_owner: crate::test_methods::dropped_account().deployed_account_id(), balance: 100, ..Account::default() }, @@ -104,7 +104,7 @@ fn program_should_fail_if_it_drops_a_declared_account() { ( AccountId::new([2; 32]), Account { - program_owner: crate::test_methods::dropped_account().id().into(), + program_owner: crate::test_methods::dropped_account().deployed_account_id(), balance: 0, ..Account::default() }, @@ -112,9 +112,9 @@ fn program_should_fail_if_it_drops_a_declared_account() { ]) .with_test_programs(); let account_ids = vec![AccountId::new([1; 32]), AccountId::new([2; 32])]; - let program_id = crate::test_methods::dropped_account().id(); + let program_id = crate::test_methods::dropped_account().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), account_ids, vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -136,7 +136,7 @@ fn program_should_fail_if_modifies_program_owner_with_only_non_default_program_o let initial_data = [( AccountId::new([1; 32]), Account { - program_owner: crate::test_methods::simple_balance_transfer().id().into(), + program_owner: crate::test_methods::simple_balance_transfer().deployed_account_id(), ..Account::default() }, )]; @@ -151,10 +151,9 @@ fn program_should_fail_if_modifies_program_owner_with_only_non_default_program_o assert_eq!(account.balance, Account::default().balance); assert_eq!(account.nonce, Account::default().nonce); assert_eq!(account.data, Account::default().data); - let program_id = crate::test_methods::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), vec![account_id], vec![], ()) - .unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -182,10 +181,9 @@ fn program_should_fail_if_modifies_program_owner_with_only_non_default_balance() assert_ne!(account.balance, Account::default().balance); assert_eq!(account.nonce, Account::default().nonce); assert_eq!(account.data, Account::default().data); - let program_id = crate::test_methods::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), vec![account_id], vec![], ()) - .unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -213,10 +211,9 @@ fn program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() { assert_eq!(account.balance, Account::default().balance); assert_ne!(account.nonce, Account::default().nonce); assert_eq!(account.data, Account::default().data); - let program_id = crate::test_methods::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), vec![account_id], vec![], ()) - .unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -244,10 +241,9 @@ fn program_should_fail_if_modifies_program_owner_with_only_non_default_data() { assert_eq!(account.balance, Account::default().balance); assert_eq!(account.nonce, Account::default().nonce); assert_ne!(account.data, Account::default().data); - let program_id = crate::test_methods::program_owner_changer().id(); + let program_id = crate::test_methods::program_owner_changer().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), vec![account_id], vec![], ()) - .unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -269,13 +265,13 @@ fn program_should_fail_if_transfers_balance_from_non_owned_account() { .with_public_account_balances([(sender_account_id, 100)]) .with_test_programs(); let balance_to_move: u128 = 1; - let program_id = crate::test_methods::simple_balance_transfer().id(); + let program_id = crate::test_methods::simple_balance_transfer().deployed_account_id(); assert_ne!( state.get_account_by_id(sender_account_id).program_owner, - program_id.into() + program_id ); let message = public_transaction::Message::try_new( - program_id.into(), + program_id, vec![sender_account_id, receiver_account_id], vec![], balance_to_move, @@ -290,7 +286,7 @@ fn program_should_fail_if_transfers_balance_from_non_owned_account() { result, Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::UnauthorizedBalanceDecrease { account_id: err_account_id, owner_account_id, executing_account_id } - ))) if err_account_id == sender_account_id && owner_account_id != program_id.into() && executing_account_id == program_id.into() + ))) if err_account_id == sender_account_id && owner_account_id != program_id && executing_account_id == program_id )); } @@ -302,15 +298,15 @@ fn program_should_fail_if_modifies_data_of_non_owned_account() { .with_test_programs() .with_non_default_accounts_but_default_program_owners(); let account_id = AccountId::new([255; 32]); - let program_id = crate::test_methods::data_changer().id(); + let program_id = crate::test_methods::data_changer().deployed_account_id(); assert_ne!(state.get_account_by_id(account_id), Account::default()); assert_ne!( state.get_account_by_id(account_id).program_owner, - program_id.into() + program_id ); let message = - public_transaction::Message::try_new(program_id.into(), vec![account_id], vec![], vec![0]) + public_transaction::Message::try_new(program_id, vec![account_id], vec![], vec![0]) .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -321,7 +317,7 @@ fn program_should_fail_if_modifies_data_of_non_owned_account() { result, Err(LeeError::InvalidProgramBehavior(InvalidProgramBehaviorError::ExecutionValidationFailed( ExecutionValidationError::UnauthorizedDataModification { account_id: err_account_id, executing_account_id } - ))) if err_account_id == account_id && executing_account_id == program_id.into() + ))) if err_account_id == account_id && executing_account_id == program_id )); } @@ -332,11 +328,10 @@ fn program_should_fail_if_does_not_preserve_total_balance_by_minting() { .with_public_accounts(initial_data) .with_test_programs(); let account_id = AccountId::new([1; 32]); - let program_id = crate::test_methods::minter().id(); + let program_id = crate::test_methods::minter().deployed_account_id(); let message = - public_transaction::Message::try_new(program_id.into(), vec![account_id], vec![], ()) - .unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -357,22 +352,18 @@ fn program_should_fail_if_does_not_preserve_total_balance_by_burning() { .with_public_accounts(initial_data) .with_test_programs() .with_account_owned_by_burner_program(); - let program_id = crate::test_methods::burner().id(); + let program_id = crate::test_methods::burner().deployed_account_id(); let account_id = AccountId::new([252; 32]); assert_eq!( state.get_account_by_id(account_id).program_owner, - program_id.into() + program_id ); let balance_to_burn: u128 = 1; assert!(state.get_account_by_id(account_id).balance > balance_to_burn); - let message = public_transaction::Message::try_new( - program_id.into(), - vec![account_id], - vec![], - balance_to_burn, - ) - .unwrap(); + let message = + public_transaction::Message::try_new(program_id, vec![account_id], vec![], balance_to_burn) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); let result = state.transition_from_public_transaction(&tx, 2, 0); diff --git a/lee/state_machine/src/state/tests/validity_window.rs b/lee/state_machine/src/state/tests/validity_window.rs index 359b89e97..dec075440 100644 --- a/lee/state_machine/src/state/tests/validity_window.rs +++ b/lee/state_machine/src/state/tests/validity_window.rs @@ -25,18 +25,14 @@ fn validity_window_works_in_public_transactions( let tx = { let account_ids = vec![pre.account_id]; let nonces = vec![]; - let program_id = validity_window_program.id(); + let program_id = validity_window_program.deployed_account_id(); let instruction = ( block_validity_window, TimestampValidityWindow::new_unbounded(), ); - let message = public_transaction::Message::try_new( - program_id.into(), - account_ids, - nonces, - instruction, - ) - .unwrap(); + let message = + public_transaction::Message::try_new(program_id, account_ids, nonces, instruction) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); PublicTransaction::new(message, witness_set) }; @@ -80,18 +76,14 @@ fn timestamp_validity_window_works_in_public_transactions( let tx = { let account_ids = vec![pre.account_id]; let nonces = vec![]; - let program_id = validity_window_program.id(); + let program_id = validity_window_program.deployed_account_id(); let instruction = ( BlockValidityWindow::new_unbounded(), timestamp_validity_window, ); - let message = public_transaction::Message::try_new( - program_id.into(), - account_ids, - nonces, - instruction, - ) - .unwrap(); + let message = + public_transaction::Message::try_new(program_id, account_ids, nonces, instruction) + .unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); PublicTransaction::new(message, witness_set) }; diff --git a/lee/state_machine/src/validated_state_diff/tests.rs b/lee/state_machine/src/validated_state_diff/tests.rs index 107808b64..31fc05d3b 100644 --- a/lee/state_machine/src/validated_state_diff/tests.rs +++ b/lee/state_machine/src/validated_state_diff/tests.rs @@ -18,7 +18,8 @@ fn public_state_from_balances(initial_data: &[(AccountId, u128)]) -> HashMap); +type Instruction = (u128, AccountId, u32, Option); /// A program that calls another program `num_chain_calls` times. /// It permutes the order of the input accounts on the subsequent call -/// The `ProgramId` in the instruction must be the `program_id` of the transfers -/// program. +/// The `AccountId` in the instruction must be the dispatch address of the transfers program. fn main() { let ( ProgramInput { self_account_id, caller_account_id, pre_states, - instruction: (balance, simple_transfer_id, num_chain_calls, pda_seed), + instruction: (balance, simple_transfer_account_id, num_chain_calls, pda_seed), }, instruction_words, ) = read_lee_inputs::(); @@ -36,7 +38,7 @@ fn main() { let mut chained_calls = Vec::new(); for _i in 0..num_chain_calls { let new_chained_call = ChainedCall { - program_account_id: simple_transfer_id.into(), + program_account_id: simple_transfer_account_id, instruction_data: instruction_data.clone(), pre_states: vec![running_sender_pre.clone(), running_recipient_pre.clone()], /* <- Account order permutation here */ pda_seeds: pda_seed.iter().copied().collect(), diff --git a/lee/state_machine/test_methods/guest/src/bin/flash_swap_callback.rs b/lee/state_machine/test_methods/guest/src/bin/flash_swap_callback.rs index 52c81ee3f..cd69bcdf3 100644 --- a/lee/state_machine/test_methods/guest/src/bin/flash_swap_callback.rs +++ b/lee/state_machine/test_methods/guest/src/bin/flash_swap_callback.rs @@ -24,8 +24,11 @@ //! called by any program. In production, a callback would typically verify the caller //! if it needs to trust the context it is called from. -use lee_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, + }, }; use serde::{Deserialize, Serialize}; @@ -34,7 +37,8 @@ pub struct CallbackInstruction { /// If true, return the borrowed funds to the vault (happy path). /// If false, keep the funds (simulates a malicious callback, triggers rollback). pub return_funds: bool, - pub token_program_id: ProgramId, + /// The dispatch address of the token program. + pub token_program_id: AccountId, pub amount: u128, } @@ -66,7 +70,7 @@ fn main() { .expect("transfer instruction serialization"); chained_calls.push(ChainedCall { - program_account_id: instruction.token_program_id.into(), + program_account_id: instruction.token_program_id, pre_states: vec![receiver_authorized, vault_pre.clone()], instruction_data: transfer_instruction, pda_seeds: vec![PdaSeed::new([1_u8; 32])], diff --git a/lee/state_machine/test_methods/guest/src/bin/flash_swap_initiator.rs b/lee/state_machine/test_methods/guest/src/bin/flash_swap_initiator.rs index 76c2b6cbf..3f43fcce5 100644 --- a/lee/state_machine/test_methods/guest/src/bin/flash_swap_initiator.rs +++ b/lee/state_machine/test_methods/guest/src/bin/flash_swap_initiator.rs @@ -37,8 +37,11 @@ //! - `flash_swap_self_call_targets_correct_program`: zero-amount self-call isolation test //! - `flash_swap_standalone_invariant_check_rejected`: `caller_account_id` access control -use lee_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, + }, }; use serde::{Deserialize, Serialize}; @@ -54,8 +57,10 @@ pub enum FlashSwapInstruction { /// Intermediate account states are computed inside the program from `pre_states` and /// `amount_out`. Initiate { - token_program_id: ProgramId, - callback_program_id: ProgramId, + /// The dispatch address of the token program. + token_program_id: AccountId, + /// The dispatch address of the callback program. + callback_program_id: AccountId, amount_out: u128, callback_instruction_data: Vec, }, @@ -124,7 +129,7 @@ fn main() { let transfer_instruction = risc0_zkvm::serde::to_vec(&amount_out).expect("transfer instruction serialization"); let call_1 = ChainedCall { - program_account_id: token_program_id.into(), + program_account_id: token_program_id, pre_states: vec![vault_authorized, receiver_pre.clone()], instruction_data: transfer_instruction, pda_seeds: vec![PdaSeed::new([0_u8; 32])], @@ -134,7 +139,7 @@ fn main() { // Receives the post-transfer states as its pre_states. The callback may run // arbitrary logic (arbitrage, etc.) and is expected to return funds to the vault. let call_2 = ChainedCall { - program_account_id: callback_program_id.into(), + program_account_id: callback_program_id, pre_states: vec![vault_after_transfer, receiver_after_transfer], instruction_data: callback_instruction_data, pda_seeds: vec![], diff --git a/lee/state_machine/test_methods/guest/src/bin/malicious_authorization_changer.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_authorization_changer.rs index 33b98f534..07ae0d465 100644 --- a/lee/state_machine/test_methods/guest/src/bin/malicious_authorization_changer.rs +++ b/lee/state_machine/test_methods/guest/src/bin/malicious_authorization_changer.rs @@ -1,12 +1,10 @@ use lee_core::{ - account::AccountWithMetadata, - program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, - }, + account::{AccountId, AccountWithMetadata}, + program::{AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs}, }; use risc0_zkvm::serde::to_vec; -type Instruction = (u128, ProgramId); +type Instruction = (u128, AccountId); /// A malicious test program that attempts to change authorization status. /// It accepts two accounts and executes a native token transfer program via chain call, @@ -35,7 +33,7 @@ fn main() { let instruction_data = to_vec(&balance).unwrap(); let chained_call = ChainedCall { - program_account_id: transfer_program_id.into(), + program_account_id: transfer_program_id, instruction_data, pre_states: vec![authorised_sender, receiver.clone()], pda_seeds: vec![], diff --git a/lee/state_machine/test_methods/guest/src/bin/malicious_injector.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_injector.rs index d5c54d439..d878da7df 100644 --- a/lee/state_machine/test_methods/guest/src/bin/malicious_injector.rs +++ b/lee/state_machine/test_methods/guest/src/bin/malicious_injector.rs @@ -1,17 +1,15 @@ use lee_core::{ account::{Account, AccountId, AccountWithMetadata, Data, Nonce}, - program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, - }, + program::{AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs}, }; /// Instruction uses only risc0-serde-compatible primitives — no `AccountId`/`Account` structs, /// which use `SerializeDisplay`/`DeserializeFromStr` and cannot round-trip through -/// `instruction_data`. +/// `instruction_data`. `AccountId`s here are dispatch addresses, not `ProgramId`s. /// /// Fields: -/// `p2_id`: program ID of the launderer (P2) -/// `auth_transfer_id`: program ID of `authenticated_transfer`, forwarded to P2 +/// `p2_id`: dispatch address of the launderer (P2) +/// `auth_transfer_id`: dispatch address of `authenticated_transfer`, forwarded to P2 /// `victim_id_raw`: raw `[u8; 32]` of the victim `AccountId` /// `victim_balance`: victim's current balance /// `victim_nonce`: victim's current nonce (inner `u128`) @@ -19,12 +17,12 @@ use lee_core::{ /// `recipient_id_raw`: raw `[u8; 32]` of the recipient `AccountId` /// `amount`: balance to transfer out of the victim. type Instruction = ( - ProgramId, - ProgramId, + AccountId, + AccountId, [u8; 32], u128, u128, - ProgramId, + AccountId, [u8; 32], u128, ); @@ -60,7 +58,7 @@ fn main() { // Victim has not signed anything — this flag is forged entirely by P1's logic. let victim = AccountWithMetadata { account: Account { - program_owner: victim_program_owner.into(), + program_owner: victim_program_owner, balance: victim_balance, data: Data::default(), nonce: Nonce(victim_nonce), @@ -75,7 +73,7 @@ fn main() { // on the recipient — a check that would block the transfer. let recipient = AccountWithMetadata { account: Account { - program_owner: auth_transfer_id.into(), + program_owner: auth_transfer_id, balance: 0, data: Data::default(), nonce: Nonce(0), @@ -96,7 +94,7 @@ fn main() { post_states, ) .with_chained_calls(vec![ChainedCall { - program_account_id: p2_id.into(), + program_account_id: p2_id, pre_states: vec![victim, recipient], instruction_data: p2_instruction, pda_seeds: vec![], diff --git a/lee/state_machine/test_methods/guest/src/bin/malicious_launderer.rs b/lee/state_machine/test_methods/guest/src/bin/malicious_launderer.rs index 3c7a043ca..629b3a789 100644 --- a/lee/state_machine/test_methods/guest/src/bin/malicious_launderer.rs +++ b/lee/state_machine/test_methods/guest/src/bin/malicious_launderer.rs @@ -1,7 +1,10 @@ -use lee_core::program::{ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs}; +use lee_core::{ + account::AccountId, + program::{ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs}, +}; -/// Instruction: (`auth_transfer_id`, `amount`) — both primitive, safe for `risc0_zkvm::serde`. -type Instruction = (ProgramId, u128); +/// Instruction: (`auth_transfer_id`, `amount`) — `auth_transfer_id` is a dispatch address. +type Instruction = (AccountId, u128); fn main() { let ( @@ -33,7 +36,7 @@ fn main() { vec![], ) .with_chained_calls(vec![ChainedCall { - program_account_id: simple_transfer_id.into(), + program_account_id: simple_transfer_id, pre_states, instruction_data: auth_transfer_instruction, pda_seeds: vec![], diff --git a/lee/state_machine/test_methods/guest/src/bin/pda_spend_proxy.rs b/lee/state_machine/test_methods/guest/src/bin/pda_spend_proxy.rs index 525027e0c..1acfb1908 100644 --- a/lee/state_machine/test_methods/guest/src/bin/pda_spend_proxy.rs +++ b/lee/state_machine/test_methods/guest/src/bin/pda_spend_proxy.rs @@ -1,5 +1,8 @@ -use lee_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, + }, }; use risc0_zkvm::serde::to_vec; @@ -7,7 +10,8 @@ use risc0_zkvm::serde::to_vec; /// /// `pre_states = [pda, recipient]`. Debits the PDA and credits the recipient. /// The PDA-to-npk binding is established via `pda_seeds` in the chained call to `simple_transfer`. -type Instruction = (PdaSeed, u128, ProgramId); +/// The `AccountId` in the instruction must be the dispatch address of the transfer program. +type Instruction = (PdaSeed, u128, AccountId); fn main() { let ( @@ -31,7 +35,7 @@ fn main() { first_for_callee.is_authorized = true; let chained_call = ChainedCall { - program_account_id: simple_transfer_id.into(), + program_account_id: simple_transfer_id, instruction_data: to_vec(&amount).unwrap(), pre_states: vec![first_for_callee, second.clone()], pda_seeds: vec![seed], diff --git a/lee/state_machine/test_methods/guest/src/bin/private_pda_delegator.rs b/lee/state_machine/test_methods/guest/src/bin/private_pda_delegator.rs index af5a0f19c..0731f71cf 100644 --- a/lee/state_machine/test_methods/guest/src/bin/private_pda_delegator.rs +++ b/lee/state_machine/test_methods/guest/src/bin/private_pda_delegator.rs @@ -1,6 +1,8 @@ -use lee_core::program::{ - AccountPostState, ChainedCall, Claim, PdaSeed, ProgramId, ProgramInput, ProgramOutput, - read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, ChainedCall, Claim, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, + }, }; use risc0_zkvm::serde::to_vec; @@ -9,7 +11,8 @@ use risc0_zkvm::serde::to_vec; /// delegated_seed` this exercises the happy caller-seeds authorization path for mask-3 private /// PDAs in `validate_and_sync_states`; when they differ, the callee's mask-3 `pre_state` has /// no matching authorization source and the circuit must reject. -type Instruction = (PdaSeed, PdaSeed, ProgramId); +/// `callee_program_id` must be the callee's dispatch address. +type Instruction = (PdaSeed, PdaSeed, AccountId); fn main() { let ( @@ -33,7 +36,7 @@ fn main() { pre_for_callee.account.program_owner = self_account_id; let chained_call = ChainedCall { - program_account_id: callee_program_id.into(), + program_account_id: callee_program_id, instruction_data: to_vec(&()).unwrap(), pre_states: vec![pre_for_callee], pda_seeds: vec![delegated_seed], diff --git a/lee/state_machine/test_methods/guest/src/bin/simple_transfer_proxy.rs b/lee/state_machine/test_methods/guest/src/bin/simple_transfer_proxy.rs index 84d960b8d..86c4273ac 100644 --- a/lee/state_machine/test_methods/guest/src/bin/simple_transfer_proxy.rs +++ b/lee/state_machine/test_methods/guest/src/bin/simple_transfer_proxy.rs @@ -1,5 +1,8 @@ -use lee_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, + }, }; /// PDA authorization program that delegates balance operations to `simple_transfer`. @@ -7,7 +10,8 @@ use lee_core::program::{ /// The PDA is owned by `simple_transfer`, not by this program. This program's role /// is solely to provide PDA authorization via `pda_seeds` in chained calls. /// -/// Instruction: `(pda_seed, simple_transfer_id, amount, is_withdraw)`. +/// Instruction: `(pda_seed, simple_transfer_id, amount, is_withdraw)`, where +/// `simple_transfer_id` is `simple_transfer`'s dispatch address. /// /// **Init** (`is_withdraw = false`, 1 pre-state `[pda]`): /// Chains to `simple_transfer` with `instruction=0` (init path) and `pda_seeds=[seed]` @@ -19,7 +23,7 @@ use lee_core::program::{ /// `simple_transfer`, not here. /// /// **Deposit**: done directly via `simple_transfer` (no need for this program). -type Instruction = (PdaSeed, ProgramId, u128, bool); +type Instruction = (PdaSeed, AccountId, u128, bool); #[expect( clippy::allow_attributes, @@ -56,7 +60,7 @@ fn main() { let mut auth_pda_pre = pda_pre; auth_pda_pre.is_authorized = true; let auth_call = ChainedCall::new( - simple_transfer_id.into(), + simple_transfer_id, vec![auth_pda_pre, recipient_pre], &amount, ) @@ -83,7 +87,7 @@ fn main() { // to authorize the PDA. simple_transfer will claim it with Claim::Authorized. let mut auth_pda_pre = pda_pre; auth_pda_pre.is_authorized = true; - let auth_call = ChainedCall::new(simple_transfer_id.into(), vec![auth_pda_pre], &amount) + let auth_call = ChainedCall::new(simple_transfer_id, vec![auth_pda_pre], &amount) .with_pda_seeds(vec![pda_seed]); ProgramOutput::new( diff --git a/lee/state_machine/test_methods/guest/src/bin/validity_window_chain_caller.rs b/lee/state_machine/test_methods/guest/src/bin/validity_window_chain_caller.rs index 59052132a..70e8d7883 100644 --- a/lee/state_machine/test_methods/guest/src/bin/validity_window_chain_caller.rs +++ b/lee/state_machine/test_methods/guest/src/bin/validity_window_chain_caller.rs @@ -1,6 +1,9 @@ -use lee_core::program::{ - AccountPostState, BlockValidityWindow, ChainedCall, ProgramId, ProgramInput, ProgramOutput, - TimestampValidityWindow, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, BlockValidityWindow, ChainedCall, ProgramInput, ProgramOutput, + TimestampValidityWindow, read_lee_inputs, + }, }; use risc0_zkvm::serde::to_vec; @@ -8,10 +11,11 @@ use risc0_zkvm::serde::to_vec; /// potentially different block validity window. /// /// Instruction: (`window`, `chained_program_id`, `chained_window`) -/// The initial output uses `window` and chains to `chained_program_id` with `chained_window`. -/// The chained program (`validity_window`) expects `(BlockValidityWindow, TimestampValidityWindow)` -/// so an unbounded timestamp window is appended automatically. -type Instruction = (BlockValidityWindow, ProgramId, BlockValidityWindow); +/// The initial output uses `window` and chains to `chained_program_id`'s dispatch address with +/// `chained_window`. The chained program (`validity_window`) expects +/// `(BlockValidityWindow, TimestampValidityWindow)` so an unbounded timestamp window is appended +/// automatically. +type Instruction = (BlockValidityWindow, AccountId, BlockValidityWindow); fn main() { let ( @@ -33,7 +37,7 @@ fn main() { )) .unwrap(); let chained_call = ChainedCall { - program_account_id: chained_program_id.into(), + program_account_id: chained_program_id, instruction_data: chained_instruction, pre_states, pda_seeds: vec![], diff --git a/lez/common/Cargo.toml b/lez/common/Cargo.toml index 7582e8858..99464af3d 100644 --- a/lez/common/Cargo.toml +++ b/lez/common/Cargo.toml @@ -14,6 +14,7 @@ authenticated_transfer_core.workspace = true clock_core.workspace = true programs.workspace = true system_accounts.workspace = true +program_loader_core.workspace = true anyhow.workspace = true thiserror.workspace = true diff --git a/lez/common/src/test_utils.rs b/lez/common/src/test_utils.rs index f29e62fcd..15e30a507 100644 --- a/lez/common/src/test_utils.rs +++ b/lez/common/src/test_utils.rs @@ -79,11 +79,12 @@ pub fn produce_dummy_block( #[must_use] pub fn produce_dummy_empty_transaction() -> LeeTransaction { - let program_id = programs::authenticated_transfer().id(); + let program_id = + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()); let account_ids = vec![]; let nonces = vec![]; let message = lee::public_transaction::Message::try_new( - program_id.into(), + program_id, account_ids, nonces, authenticated_transfer_core::Instruction::Initialize, @@ -107,9 +108,10 @@ pub fn create_transaction_native_token_transfer( ) -> LeeTransaction { let account_ids = vec![from, to]; let nonces = vec![nonce.into()]; - let program_id = programs::authenticated_transfer().id(); + let program_id = + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()); let message = lee::public_transaction::Message::try_new( - program_id.into(), + program_id, account_ids, nonces, authenticated_transfer_core::Instruction::Transfer { diff --git a/lez/common/src/transaction.rs b/lez/common/src/transaction.rs index 536f63742..64782cdc2 100644 --- a/lez/common/src/transaction.rs +++ b/lez/common/src/transaction.rs @@ -232,7 +232,7 @@ pub enum TransactionMalformationError { #[must_use] pub fn clock_invocation(timestamp: clock_core::Instruction) -> lee::PublicTransaction { let message = lee::public_transaction::Message::try_new( - programs::clock().id().into(), + program_loader_core::immutable_deploy_account_id(programs::clock().id()), clock_core::CLOCK_PROGRAM_ACCOUNT_IDS.to_vec(), vec![], timestamp, diff --git a/lez/cross_zone/Cargo.toml b/lez/cross_zone/Cargo.toml index be80ce13e..72f87d713 100644 --- a/lez/cross_zone/Cargo.toml +++ b/lez/cross_zone/Cargo.toml @@ -14,6 +14,7 @@ test-utils = [] [dependencies] lee.workspace = true lee_core.workspace = true +program_loader_core.workspace = true programs.workspace = true common.workspace = true cross_zone_inbox_core.workspace = true diff --git a/lez/cross_zone/src/lib.rs b/lez/cross_zone/src/lib.rs index d765cc165..bdeef2b55 100644 --- a/lez/cross_zone/src/lib.rs +++ b/lez/cross_zone/src/lib.rs @@ -16,9 +16,8 @@ pub use acceptance::{ pub use cross_zone_inbox_core::{CrossZoneConfig, CrossZonePeer}; use cross_zone_inbox_core::{ CrossZoneMessage, InboxConfig, Instruction, ZoneId, inbox_config_account_id, - inbox_seen_shard_account_id, + inbox_seen_shard_account_id, inbox_source_marker_account_id, }; -use cross_zone_marker_core::inbox_source_marker_account_id; use lee_core::{ account::{Account, AccountId, Balance}, program::ProgramId, @@ -50,27 +49,31 @@ pub struct EmissionSource { pub src_block_id: u64, pub src_block_hash: [u8; 32], pub src_tx_index: u32, - pub src_program_id: ProgramId, + /// The emitting program's dispatch address on the peer zone, read verbatim off its + /// `OutboxRecord.emitter` (state-machine-verified on the peer, not derivable from any + /// `ProgramId`). + pub src_account_id: AccountId, } /// Whether a program may only be invoked by sequencer-origin transactions. /// /// The cross-zone inbox is injected solely by the watcher; a user-submitted call /// must be rejected at ingress, since `TransactionOrigin` is not carried in the -/// block. +/// block. Compares the dispatch address directly: a `ProgramId` round-trip +/// through `AccountId::from` is only exact under the legacy bijection scheme. #[must_use] -pub fn is_sequencer_only_program(program_id: ProgramId) -> bool { - program_id == programs::cross_zone_inbox().id() +pub fn is_sequencer_only_program(account_id: AccountId) -> bool { + account_id == program_loader_core::immutable_deploy_account_id(programs::cross_zone_inbox().id()) } /// Extracts the cross-zone emission from a source transaction. /// -/// Recognizes the known emitter programs (`ping_sender`, `bridge_lock`). The -/// watcher and verifier both use this so they agree on what a given source tx -/// emits. +/// Recognizes the known emitter programs (`ping_sender`, `bridge_lock`), matched +/// by their real dispatch address. The watcher and verifier both use this so +/// they agree on what a given source tx emits. #[must_use] -pub fn extract_emission(program_id: ProgramId, instruction_data: &[u32]) -> Option { - if program_id == programs::ping_sender().id() { +pub fn extract_emission(account_id: AccountId, instruction_data: &[u32]) -> Option { + if account_id == program_loader_core::immutable_deploy_account_id(programs::ping_sender().id()) { // Not every transaction to an emitter emits: `InitConfig` is one of its // instructions, so a non-`Send` decode is an ordinary non-emitting tx. let Ok(ping_core::SenderInstruction::Send { @@ -89,7 +92,7 @@ pub fn extract_emission(program_id: ProgramId, instruction_data: &[u32]) -> Opti target_accounts, payload, }) - } else if program_id == programs::bridge_lock().id() { + } else if account_id == program_loader_core::immutable_deploy_account_id(programs::bridge_lock().id()) { let Ok(bridge_lock_core::Instruction::Lock { target_zone, target_program_id, @@ -118,6 +121,7 @@ fn build_inbox_dispatch_tx( msg: &CrossZoneMessage, target_account_ids: Vec, ) -> lee::PublicTransaction { + let inbox_account_id = program_loader_core::immutable_deploy_account_id(inbox_id); let mut account_ids = Vec::with_capacity(target_account_ids.len().saturating_add(3)); account_ids.push(inbox_config_account_id(inbox_id)); account_ids.push(inbox_seen_shard_account_id( @@ -129,17 +133,20 @@ fn build_inbox_dispatch_tx( // conjure an account. Both the watcher and the verifier build it through this // one function, so they cannot disagree about the source a target will see. account_ids.push(inbox_source_marker_account_id( - inbox_id, + inbox_account_id, &msg.src_zone, - msg.src_program_id, + msg.src_account_id, )); account_ids.extend(target_account_ids); let message = lee::public_transaction::Message::try_new( - inbox_id.into(), + inbox_account_id, account_ids, vec![], - Instruction::Dispatch(msg.clone()), + Instruction::Dispatch { + message: msg.clone(), + self_program_id: inbox_id, + }, ) .expect("inbox dispatch instruction must serialize"); @@ -166,8 +173,9 @@ pub fn build_dispatch_from_emission( src_block_id: source.src_block_id, src_block_hash: source.src_block_hash, src_tx_index: source.src_tx_index, - src_program_id: source.src_program_id, + src_account_id: source.src_account_id, target_program_id, + target_account_id: program_loader_core::immutable_deploy_account_id(target_program_id), payload, l1_inclusion_witness: None, }; @@ -190,7 +198,10 @@ pub fn build_inbox_init_config_tx(self_zone: ZoneId) -> lee::PublicTransaction { genesis_public_tx( inbox_id, vec![inbox_config_account_id(inbox_id)], - Instruction::InitConfig(InboxConfig { self_zone }), + Instruction::InitConfig { + config: InboxConfig { self_zone }, + self_program_id: inbox_id, + }, ) } @@ -202,7 +213,7 @@ pub fn build_inbox_init_config_tx(self_zone: ZoneId) -> lee::PublicTransaction { #[must_use] pub fn build_holding_account(holder: AccountId, amount: Balance) -> (AccountId, Account) { let account = Account { - program_owner: programs::bridge_lock().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id(programs::bridge_lock().id()), balance: amount, ..Default::default() }; @@ -223,7 +234,7 @@ pub fn build_holding_account(holder: AccountId, amount: Balance) -> (AccountId, fn sources_for_target( cross_zone: Option<&CrossZoneConfig>, target_program_id: ProgramId, -) -> Vec<(ZoneId, ProgramId)> { +) -> Vec<(ZoneId, AccountId)> { let Some(cross_zone) = cross_zone else { return Vec::new(); }; @@ -236,7 +247,7 @@ fn sources_for_target( route.target_program_id ); if route.target_program_id == target_program_id { - sources.push((peer.channel_id, route.src_program_id)); + sources.push((peer.channel_id, route.src_account_id)); } } } @@ -269,12 +280,17 @@ pub fn build_wrapped_token_init_config_tx( genesis_public_tx( wrapped_token_id, vec![wrapped_token_core::config_account_id(wrapped_token_id)], - wrapped_token_core::Instruction::InitConfig(wrapped_token_core::WrappedTokenConfig { - minter: programs::cross_zone_inbox().id(), - governance: cross_zone.and_then(|cross_zone| cross_zone.source_governance), - authority: cross_zone.and_then(|cross_zone| cross_zone.source_authority), - sources, - }), + wrapped_token_core::Instruction::InitConfig { + self_program_id: wrapped_token_id, + config: wrapped_token_core::WrappedTokenConfig { + minter: program_loader_core::immutable_deploy_account_id( + programs::cross_zone_inbox().id(), + ), + governance: cross_zone.and_then(|cross_zone| cross_zone.source_governance), + authority: cross_zone.and_then(|cross_zone| cross_zone.source_authority), + sources, + }, + }, ) } @@ -283,11 +299,14 @@ pub fn build_wrapped_token_init_config_tx( #[must_use] pub fn build_ping_sender_init_config_tx() -> lee::PublicTransaction { let ping_sender_id = programs::ping_sender().id(); + let outbox_id = programs::cross_zone_outbox().id(); genesis_public_tx( ping_sender_id, vec![ping_core::sender_config_account_id(ping_sender_id)], ping_core::SenderInstruction::InitConfig { - outbox_program_id: programs::cross_zone_outbox().id(), + self_program_id: ping_sender_id, + outbox_account_id: program_loader_core::immutable_deploy_account_id(outbox_id), + outbox_program_id: outbox_id, }, ) } @@ -297,11 +316,14 @@ pub fn build_ping_sender_init_config_tx() -> lee::PublicTransaction { #[must_use] pub fn build_bridge_lock_init_config_tx() -> lee::PublicTransaction { let bridge_lock_id = programs::bridge_lock().id(); + let outbox_id = programs::cross_zone_outbox().id(); genesis_public_tx( bridge_lock_id, vec![bridge_lock_core::config_account_id(bridge_lock_id)], bridge_lock_core::Instruction::InitConfig { - outbox_program_id: programs::cross_zone_outbox().id(), + self_program_id: bridge_lock_id, + outbox_account_id: program_loader_core::immutable_deploy_account_id(outbox_id), + outbox_program_id: outbox_id, target_program_id: programs::wrapped_token().id(), }, ) @@ -319,12 +341,17 @@ pub fn build_ping_receiver_init_config_tx( genesis_public_tx( receiver_id, vec![ping_core::receiver_config_account_id(receiver_id)], - ping_core::ReceiverInstruction::InitConfig(ping_core::ReceiverConfig { - deliverer: programs::cross_zone_inbox().id(), - governance: cross_zone.and_then(|cross_zone| cross_zone.source_governance), - authority: cross_zone.and_then(|cross_zone| cross_zone.source_authority), - sources, - }), + ping_core::ReceiverInstruction::InitConfig { + self_program_id: receiver_id, + config: ping_core::ReceiverConfig { + deliverer: program_loader_core::immutable_deploy_account_id( + programs::cross_zone_inbox().id(), + ), + governance: cross_zone.and_then(|cross_zone| cross_zone.source_governance), + authority: cross_zone.and_then(|cross_zone| cross_zone.source_authority), + sources, + }, + }, ) } @@ -336,7 +363,7 @@ fn genesis_public_tx( instruction: I, ) -> lee::PublicTransaction { let message = lee::public_transaction::Message::try_new( - program_id.into(), + program_loader_core::immutable_deploy_account_id(program_id), account_ids, vec![], instruction, diff --git a/lez/cross_zone/src/test_utils.rs b/lez/cross_zone/src/test_utils.rs index c59fb78b2..cdb637999 100644 --- a/lez/cross_zone/src/test_utils.rs +++ b/lez/cross_zone/src/test_utils.rs @@ -33,6 +33,7 @@ pub fn ping_emission( ) -> LeeTransaction { let receiver_id = programs::ping_receiver().id(); let send = SenderInstruction::Send { + self_program_id: programs::ping_sender().id(), target_zone, target_program_id, target_accounts: vec![ @@ -42,8 +43,13 @@ pub fn ping_emission( payload: payload.to_vec(), ordinal: 0, }; - let message = Message::try_new(programs::ping_sender().id().into(), vec![], vec![], send) - .expect("emission serializes"); + let message = Message::try_new( + program_loader_core::immutable_deploy_account_id(programs::ping_sender().id()), + vec![], + vec![], + send, + ) + .expect("emission serializes"); LeeTransaction::Public(PublicTransaction::new( message, WitnessSet::from_raw_parts(vec![]), diff --git a/lez/indexer/core/Cargo.toml b/lez/indexer/core/Cargo.toml index a52e128b8..9877f34d0 100644 --- a/lez/indexer/core/Cargo.toml +++ b/lez/indexer/core/Cargo.toml @@ -22,6 +22,7 @@ cross_zone_inbox_core.workspace = true programs.workspace = true storage.workspace = true testnet_initial_state.workspace = true +program_loader_core.workspace = true anyhow.workspace = true arc-swap.workspace = true diff --git a/lez/indexer/core/src/cross_zone_verifier.rs b/lez/indexer/core/src/cross_zone_verifier.rs index 0e2a39f43..6237b5df6 100644 --- a/lez/indexer/core/src/cross_zone_verifier.rs +++ b/lez/indexer/core/src/cross_zone_verifier.rs @@ -24,7 +24,7 @@ use cross_zone_inbox_core::{ CrossZoneMessage, Instruction as InboxInstruction, MessageKey, ZoneId, message_key, }; use futures::{Stream, StreamExt as _}; -use lee::{GENESIS_BLOCK_ID, ProgramId, PublicKey}; +use lee::{GENESIS_BLOCK_ID, PublicKey}; use log::{debug, error, warn}; use logos_blockchain_core::mantle::ops::channel::ChannelId; use logos_blockchain_zone_sdk::{ @@ -799,16 +799,18 @@ impl CrossZoneVerifier { let LeeTransaction::Public(public_tx) = tx else { return None; }; - if public_tx.message().program_account_id != programs::cross_zone_inbox().id().into() { + if public_tx.message().program_account_id + != program_loader_core::immutable_deploy_account_id(programs::cross_zone_inbox().id()) + { return None; } match risc0_zkvm::serde::from_slice::( &public_tx.message().instruction_data, ) { - Ok(InboxInstruction::Dispatch(msg)) => Some(msg), + Ok(InboxInstruction::Dispatch { message, .. }) => Some(message), // Only a dispatch carries a cross-zone message to re-derive; a genesis // `InitConfig` is not verifier-relevant. - Ok(InboxInstruction::InitConfig(_)) | Err(_) => None, + Ok(InboxInstruction::InitConfig { .. }) | Err(_) => None, } } @@ -855,9 +857,8 @@ impl CrossZoneVerifier { )); }; let message = emission_tx.message(); - let message_program_id = ProgramId::from(message.program_account_id); - let emission = - extract_emission(message_program_id, &message.instruction_data).ok_or_else(|| { + let emission = extract_emission(message.program_account_id, &message.instruction_data) + .ok_or_else(|| { forged( msg, "peer transaction at src_tx_index is not a recognized emitter".to_owned(), @@ -883,7 +884,7 @@ impl CrossZoneVerifier { src_block_id: msg.src_block_id, src_block_hash: peer_block.recompute_hash().0, src_tx_index: msg.src_tx_index, - src_program_id: message_program_id, + src_account_id: message.program_account_id, }, emission.target_program_id, &emission.target_accounts, @@ -1453,7 +1454,9 @@ mod tests { src_block_id: PEER_BLOCK_ID, src_block_hash, src_tx_index: 0, - src_program_id: programs::ping_sender().id(), + src_account_id: program_loader_core::immutable_deploy_account_id( + programs::ping_sender().id(), + ), }, receiver_id, &[ diff --git a/lez/programs/amm/Cargo.toml b/lez/programs/amm/Cargo.toml index 171efbd9b..3b2160a1f 100644 --- a/lez/programs/amm/Cargo.toml +++ b/lez/programs/amm/Cargo.toml @@ -15,3 +15,4 @@ amm_core.workspace = true [dev-dependencies] lee = { workspace = true, features = ["test-utils"] } programs = { workspace = true } +program_loader_core.workspace = true diff --git a/lez/programs/amm/src/add.rs b/lez/programs/amm/src/add.rs index 4d4d3f740..807f04d09 100644 --- a/lez/programs/amm/src/add.rs +++ b/lez/programs/amm/src/add.rs @@ -133,12 +133,11 @@ pub fn add_liquidity( }; pool_post.data = Data::from(&pool_post_definition); - let token_program_id: lee_core::program::ProgramId = - user_holding_a.account.program_owner.into(); + let token_program_id = user_holding_a.account.program_owner; // Chain call for Token A (UserHoldingA -> Vault_A) let call_token_a = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![user_holding_a.clone(), vault_a.clone()], &token_core::Instruction::Transfer { amount_to_transfer: actual_amount_a, @@ -146,7 +145,7 @@ pub fn add_liquidity( ); // Chain call for Token B (UserHoldingB -> Vault_B) let call_token_b = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![user_holding_b.clone(), vault_b.clone()], &token_core::Instruction::Transfer { amount_to_transfer: actual_amount_b, @@ -156,7 +155,7 @@ pub fn add_liquidity( let mut pool_definition_lp_auth = pool_definition_lp.clone(); pool_definition_lp_auth.is_authorized = true; let call_token_lp = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![pool_definition_lp_auth, user_holding_lp.clone()], &token_core::Instruction::Mint { amount_to_mint: delta_lp, diff --git a/lez/programs/amm/src/new_definition.rs b/lez/programs/amm/src/new_definition.rs index ab9210575..a6111967e 100644 --- a/lez/programs/amm/src/new_definition.rs +++ b/lez/programs/amm/src/new_definition.rs @@ -111,8 +111,7 @@ pub fn new_definition( let pool_pda_seed = compute_pool_pda_seed(definition_token_a_id, definition_token_b_id); let pool_post = AccountPostState::new_claimed_if_default(pool_post, Claim::Pda(pool_pda_seed)); - let token_program_id: lee_core::program::ProgramId = - user_holding_a.account.program_owner.into(); + let token_program_id = user_holding_a.account.program_owner; // Chain call for Token A (user_holding_a -> Vault_A) let vault_a_seed = compute_vault_pda_seed(pool.account_id, definition_token_a_id); @@ -121,7 +120,7 @@ pub fn new_definition( ..vault_a.clone() }; let call_token_a = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![user_holding_a.clone(), vault_a_authorized], &token_core::Instruction::Transfer { amount_to_transfer: token_a_amount.into(), @@ -136,7 +135,7 @@ pub fn new_definition( ..vault_b.clone() }; let call_token_b = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![user_holding_b.clone(), vault_b_authorized], &token_core::Instruction::Transfer { amount_to_transfer: token_b_amount.into(), @@ -150,7 +149,7 @@ pub fn new_definition( ..pool_definition_lp.clone() }; let call_token_lp = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![pool_lp_authorized, user_holding_lp.clone()], &instruction, ) diff --git a/lez/programs/amm/src/remove.rs b/lez/programs/amm/src/remove.rs index fbf1733f8..5c492509a 100644 --- a/lez/programs/amm/src/remove.rs +++ b/lez/programs/amm/src/remove.rs @@ -113,12 +113,11 @@ pub fn remove_liquidity( pool_post.data = Data::from(&pool_post_definition); - let token_program_id: lee_core::program::ProgramId = - user_holding_a.account.program_owner.into(); + let token_program_id = user_holding_a.account.program_owner; // Chaincall for Token A withdraw let call_token_a = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![running_vault_a, user_holding_a.clone()], &token_core::Instruction::Transfer { amount_to_transfer: withdraw_amount_a, @@ -130,7 +129,7 @@ pub fn remove_liquidity( )]); // Chaincall for Token B withdraw let call_token_b = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![running_vault_b, user_holding_b.clone()], &token_core::Instruction::Transfer { amount_to_transfer: withdraw_amount_b, @@ -144,7 +143,7 @@ pub fn remove_liquidity( let mut pool_definition_lp_auth = pool_definition_lp.clone(); pool_definition_lp_auth.is_authorized = true; let call_token_lp = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![pool_definition_lp_auth, user_holding_lp.clone()], &token_core::Instruction::Burn { amount_to_burn: delta_lp, diff --git a/lez/programs/amm/src/swap.rs b/lez/programs/amm/src/swap.rs index c232f1a74..a76d5bcfe 100644 --- a/lez/programs/amm/src/swap.rs +++ b/lez/programs/amm/src/swap.rs @@ -182,11 +182,11 @@ fn swap_logic( ); assert!(withdraw_amount != 0, "Withdraw amount should be nonzero"); - let token_program_id: lee_core::program::ProgramId = user_deposit.account.program_owner.into(); + let token_program_id = user_deposit.account.program_owner; let mut chained_calls = Vec::new(); chained_calls.push(ChainedCall::new( - token_program_id.into(), + token_program_id, vec![user_deposit, vault_deposit], &token_core::Instruction::Transfer { amount_to_transfer: swap_amount_in, @@ -205,7 +205,7 @@ fn swap_logic( chained_calls.push( ChainedCall::new( - token_program_id.into(), + token_program_id, vec![vault_withdraw, user_withdraw], &token_core::Instruction::Transfer { amount_to_transfer: withdraw_amount, @@ -314,11 +314,11 @@ fn exact_output_swap_logic( "Required input exceeds maximum amount in" ); - let token_program_id: lee_core::program::ProgramId = user_deposit.account.program_owner.into(); + let token_program_id = user_deposit.account.program_owner; let mut chained_calls = Vec::new(); chained_calls.push(ChainedCall::new( - token_program_id.into(), + token_program_id, vec![user_deposit, vault_deposit], &token_core::Instruction::Transfer { amount_to_transfer: deposit_amount, @@ -337,7 +337,7 @@ fn exact_output_swap_logic( chained_calls.push( ChainedCall::new( - token_program_id.into(), + token_program_id, vec![vault_withdraw, user_withdraw], &token_core::Instruction::Transfer { amount_to_transfer: exact_amount_out, diff --git a/lez/programs/amm/src/tests.rs b/lez/programs/amm/src/tests.rs index a6c658628..c86a6526d 100644 --- a/lez/programs/amm/src/tests.rs +++ b/lez/programs/amm/src/tests.rs @@ -1349,7 +1349,7 @@ impl IdForExeTests { impl AccountsForExeTests { fn user_token_a_holding() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1361,7 +1361,7 @@ impl AccountsForExeTests { fn user_token_b_holding() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1373,7 +1373,7 @@ impl AccountsForExeTests { fn pool_definition_init() -> Account { Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1393,7 +1393,7 @@ impl AccountsForExeTests { fn token_a_definition_account() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -1406,7 +1406,7 @@ impl AccountsForExeTests { fn token_b_definition_acc() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -1419,7 +1419,7 @@ impl AccountsForExeTests { fn token_lp_definition_acc() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1432,7 +1432,7 @@ impl AccountsForExeTests { fn vault_a_init() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1444,7 +1444,7 @@ impl AccountsForExeTests { fn vault_b_init() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1456,7 +1456,7 @@ impl AccountsForExeTests { fn user_token_lp_holding() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1468,7 +1468,7 @@ impl AccountsForExeTests { fn vault_a_swap_1() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1480,7 +1480,7 @@ impl AccountsForExeTests { fn vault_b_swap_1() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1492,7 +1492,7 @@ impl AccountsForExeTests { fn pool_definition_swap_1() -> Account { Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1512,7 +1512,7 @@ impl AccountsForExeTests { fn user_token_a_holding_swap_1() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1524,7 +1524,7 @@ impl AccountsForExeTests { fn user_token_b_holding_swap_1() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1536,7 +1536,7 @@ impl AccountsForExeTests { fn vault_a_swap_2() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1548,7 +1548,7 @@ impl AccountsForExeTests { fn vault_b_swap_2() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1560,7 +1560,7 @@ impl AccountsForExeTests { fn pool_definition_swap_2() -> Account { Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1580,7 +1580,7 @@ impl AccountsForExeTests { fn user_token_a_holding_swap_2() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1592,7 +1592,7 @@ impl AccountsForExeTests { fn user_token_b_holding_swap_2() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1604,7 +1604,7 @@ impl AccountsForExeTests { fn vault_a_add() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1616,7 +1616,7 @@ impl AccountsForExeTests { fn vault_b_add() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1628,7 +1628,7 @@ impl AccountsForExeTests { fn pool_definition_add() -> Account { Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1648,7 +1648,7 @@ impl AccountsForExeTests { fn user_token_a_holding_add() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1660,7 +1660,7 @@ impl AccountsForExeTests { fn user_token_b_holding_add() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1672,7 +1672,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_add() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1684,7 +1684,7 @@ impl AccountsForExeTests { fn token_lp_definition_add() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1697,7 +1697,7 @@ impl AccountsForExeTests { fn vault_a_remove() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1709,7 +1709,7 @@ impl AccountsForExeTests { fn vault_b_remove() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1721,7 +1721,7 @@ impl AccountsForExeTests { fn pool_definition_remove() -> Account { Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1741,7 +1741,7 @@ impl AccountsForExeTests { fn user_token_a_holding_remove() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1753,7 +1753,7 @@ impl AccountsForExeTests { fn user_token_b_holding_remove() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1765,7 +1765,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_remove() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1777,7 +1777,7 @@ impl AccountsForExeTests { fn token_lp_definition_remove() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1790,7 +1790,7 @@ impl AccountsForExeTests { fn token_lp_definition_init_inactive() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1803,7 +1803,7 @@ impl AccountsForExeTests { fn vault_a_init_inactive() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1815,7 +1815,7 @@ impl AccountsForExeTests { fn vault_b_init_inactive() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1827,7 +1827,7 @@ impl AccountsForExeTests { fn pool_definition_inactive() -> Account { Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1847,7 +1847,7 @@ impl AccountsForExeTests { fn user_token_a_holding_new_init() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_a_definition_id(), @@ -1859,7 +1859,7 @@ impl AccountsForExeTests { fn user_token_b_holding_new_init() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_b_definition_id(), @@ -1871,7 +1871,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_new_init() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -1883,7 +1883,7 @@ impl AccountsForExeTests { fn token_lp_definition_new_init() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenDefinition::Fungible { name: String::from("LP Token"), @@ -1896,7 +1896,7 @@ impl AccountsForExeTests { fn pool_definition_new_init() -> Account { Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0_u128, data: Data::from(&PoolDefinition { definition_token_a_id: IdForExeTests::token_a_definition_id(), @@ -1916,7 +1916,7 @@ impl AccountsForExeTests { fn user_token_lp_holding_init_zero() -> Account { Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0_u128, data: Data::from(&TokenHolding::Fungible { definition_id: IdForExeTests::token_lp_definition_id(), @@ -3113,7 +3113,7 @@ fn simple_amm_remove() { }; let message = public_transaction::Message::try_new( - programs::amm().id().into(), + program_loader_core::immutable_deploy_account_id(programs::amm().id()), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3190,7 +3190,7 @@ fn simple_amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() { }; let message = public_transaction::Message::try_new( - programs::amm().id().into(), + program_loader_core::immutable_deploy_account_id(programs::amm().id()), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3275,7 +3275,7 @@ fn simple_amm_new_definition_inactive_initialized_pool_init_user_lp() { }; let message = public_transaction::Message::try_new( - programs::amm().id().into(), + program_loader_core::immutable_deploy_account_id(programs::amm().id()), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3347,7 +3347,7 @@ fn simple_amm_new_definition_uninitialized_pool() { }; let message = public_transaction::Message::try_new( - programs::amm().id().into(), + program_loader_core::immutable_deploy_account_id(programs::amm().id()), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3410,7 +3410,7 @@ fn simple_amm_add() { }; let message = public_transaction::Message::try_new( - programs::amm().id().into(), + program_loader_core::immutable_deploy_account_id(programs::amm().id()), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3472,7 +3472,7 @@ fn simple_amm_swap_1() { }; let message = public_transaction::Message::try_new( - programs::amm().id().into(), + program_loader_core::immutable_deploy_account_id(programs::amm().id()), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), @@ -3522,7 +3522,7 @@ fn simple_amm_swap_2() { token_definition_id_in: IdForExeTests::token_a_definition_id(), }; let message = public_transaction::Message::try_new( - programs::amm().id().into(), + program_loader_core::immutable_deploy_account_id(programs::amm().id()), vec![ IdForExeTests::pool_definition_id(), IdForExeTests::vault_a_id(), diff --git a/lez/programs/associated_token_account/src/burn.rs b/lez/programs/associated_token_account/src/burn.rs index 27cb572ff..09d1645a1 100644 --- a/lez/programs/associated_token_account/src/burn.rs +++ b/lez/programs/associated_token_account/src/burn.rs @@ -11,7 +11,7 @@ pub fn burn_from_associated_token_account( ata_program_id: ProgramId, amount: u128, ) -> (Vec, Vec) { - let token_program_id: lee_core::program::ProgramId = holder_ata.account.program_owner.into(); + let token_program_id = holder_ata.account.program_owner; assert!(owner.is_authorized, "Owner authorization is missing"); let definition_id = TokenHolding::try_from(&holder_ata.account.data) .expect("Holder ATA must hold a valid token") @@ -32,7 +32,7 @@ pub fn burn_from_associated_token_account( holder_ata_auth.is_authorized = true; let chained_call = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![token_definition.clone(), holder_ata_auth], &token_core::Instruction::Burn { amount_to_burn: amount, diff --git a/lez/programs/associated_token_account/src/create.rs b/lez/programs/associated_token_account/src/create.rs index 5077c720b..4e1b2074d 100644 --- a/lez/programs/associated_token_account/src/create.rs +++ b/lez/programs/associated_token_account/src/create.rs @@ -10,8 +10,7 @@ pub fn create_associated_token_account( ata_program_id: ProgramId, ) -> (Vec, Vec) { // No authorization check needed: create is idempotent, so anyone can call it safely. - let token_program_id: lee_core::program::ProgramId = - token_definition.account.program_owner.into(); + let token_program_id = token_definition.account.program_owner; let ata_seed = associated_token_account_core::verify_ata_and_get_seed( &ata_account, &owner, @@ -41,7 +40,7 @@ pub fn create_associated_token_account( ..ata_account.clone() }; let chained_call = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![token_definition.clone(), ata_account_auth], &token_core::Instruction::InitializeAccount, ) diff --git a/lez/programs/associated_token_account/src/transfer.rs b/lez/programs/associated_token_account/src/transfer.rs index dc87d3329..dbe388038 100644 --- a/lez/programs/associated_token_account/src/transfer.rs +++ b/lez/programs/associated_token_account/src/transfer.rs @@ -11,7 +11,7 @@ pub fn transfer_from_associated_token_account( ata_program_id: ProgramId, amount: u128, ) -> (Vec, Vec) { - let token_program_id: lee_core::program::ProgramId = sender_ata.account.program_owner.into(); + let token_program_id = sender_ata.account.program_owner; assert!(owner.is_authorized, "Owner authorization is missing"); let definition_id = TokenHolding::try_from(&sender_ata.account.data) .expect("Sender ATA must hold a valid token") @@ -32,7 +32,7 @@ pub fn transfer_from_associated_token_account( sender_ata_auth.is_authorized = true; let chained_call = ChainedCall::new( - token_program_id.into(), + token_program_id, vec![sender_ata_auth, recipient.clone()], &token_core::Instruction::Transfer { amount_to_transfer: amount, diff --git a/lez/programs/bridge/core/src/lib.rs b/lez/programs/bridge/core/src/lib.rs index 129276dc7..828a623c0 100644 --- a/lez/programs/bridge/core/src/lib.rs +++ b/lez/programs/bridge/core/src/lib.rs @@ -20,7 +20,15 @@ pub enum Instruction { /// Deposit OP ID from L1, stored here to pin each [`Deposit`](Instruction::Deposit) to a /// Deposit Event on L1. l1_deposit_op_id: [u8; 32], + /// This program's own image id. The guest cannot learn this at runtime, so the trusted + /// caller supplies it to recompute the bridge and receipt PDAs; a wrong value only fails + /// the guest's own self-consistency assertions, since real authorization is + /// independently enforced by the state layer against the account's `program_owner`. + self_program_id: ProgramId, + /// The vault program's own image id, used to derive the expected recipient vault PDA. vault_program_id: ProgramId, + /// The vault program's real dispatch address, used as the chained-call target. + vault_account_id: AccountId, recipient_id: AccountId, amount: u64, }, diff --git a/lez/programs/bridge/src/main.rs b/lez/programs/bridge/src/main.rs index ffc7652dd..7cfe530c4 100644 --- a/lez/programs/bridge/src/main.rs +++ b/lez/programs/bridge/src/main.rs @@ -34,7 +34,9 @@ fn main() { let (post_states, chained_calls) = match instruction { Instruction::Deposit { l1_deposit_op_id, + self_program_id, vault_program_id, + vault_account_id, recipient_id, amount, } => { @@ -44,7 +46,7 @@ fn main() { assert_eq!( bridge.account_id, - bridge_core::compute_bridge_account_id(self_account_id.into()), + bridge_core::compute_bridge_account_id(self_program_id), "First account must be bridge PDA" ); @@ -56,7 +58,7 @@ fn main() { assert_eq!( receipt.account_id, - bridge_core::deposit_receipt_account_id(self_account_id.into(), l1_deposit_op_id), + bridge_core::deposit_receipt_account_id(self_program_id, l1_deposit_op_id), "Third account must be the deposit-receipt PDA" ); @@ -91,7 +93,7 @@ fn main() { bridge_for_vault.is_authorized = true; let chained_calls = vec![ ChainedCall::new( - vault_program_id.into(), + vault_account_id, vec![bridge_for_vault, recipient_vault], &vault_core::Instruction::Transfer { recipient_id, diff --git a/lez/programs/bridge_lock/core/src/lib.rs b/lez/programs/bridge_lock/core/src/lib.rs index 77836140b..edb06f4dc 100644 --- a/lez/programs/bridge_lock/core/src/lib.rs +++ b/lez/programs/bridge_lock/core/src/lib.rs @@ -28,6 +28,11 @@ pub enum Instruction { /// Required accounts (4): config PDA, holder holding (authorized), escrow /// PDA, outbox PDA. Lock { + /// This program's own image id. The guest cannot learn this at runtime, so the trusted + /// caller supplies it to recompute the config and escrow PDAs; a wrong value only fails + /// the guest's own self-consistency assertions, since real authorization is + /// independently enforced by the state layer against the account's `program_owner`. + self_program_id: ProgramId, amount: u128, target_zone: [u8; 32], target_program_id: ProgramId, @@ -41,6 +46,12 @@ pub enum Instruction { /// /// Required accounts (1): the config PDA. InitConfig { + /// See [`Lock::self_program_id`](Instruction::Lock). + self_program_id: ProgramId, + /// The outbox program's real dispatch address. + outbox_account_id: AccountId, + /// The outbox program's own image id, supplied back to it as its `self_program_id` when + /// dispatching `cross_zone_outbox_core::Instruction::Emit`. outbox_program_id: ProgramId, target_program_id: ProgramId, }, @@ -57,8 +68,8 @@ pub const fn escrow_seed() -> PdaSeed { PdaSeed::new(ESCROW_SEED_DOMAIN) } -/// PDA holding the outbox program id and the mint target, seeded at genesis so -/// the guest can pin both without importing their image ids. +/// PDA holding the outbox's dispatch address and the mint target, seeded at +/// genesis so the guest can pin both without importing their image ids. #[must_use] pub fn config_account_id(bridge_lock_id: ProgramId) -> AccountId { AccountId::for_public_pda(&bridge_lock_id, &config_seed()) @@ -69,34 +80,49 @@ pub const fn config_seed() -> PdaSeed { PdaSeed::new(CONFIG_SEED_DOMAIN) } -/// Encodes the pinned outbox and mint target for the config account's data. +/// Encodes the pinned outbox dispatch address, outbox image id, and mint target +/// for the config account's data. #[must_use] -pub fn config_bytes(outbox_program_id: ProgramId, target_program_id: ProgramId) -> [u8; 64] { - let mut bytes = [0_u8; 64]; +pub fn config_bytes( + outbox_account_id: AccountId, + outbox_program_id: ProgramId, + target_program_id: ProgramId, +) -> [u8; 96] { + let mut bytes = [0_u8; 96]; + bytes[..32].copy_from_slice(outbox_account_id.value()); for (word, chunk) in outbox_program_id .iter() .chain(target_program_id.iter()) - .zip(bytes.chunks_exact_mut(4)) + .zip(bytes[32..].chunks_exact_mut(4)) { chunk.copy_from_slice(&word.to_le_bytes()); } bytes } -/// Decodes the pinned outbox and mint target from the config account's data. +/// Decodes the pinned outbox dispatch address, outbox image id, and mint target +/// from the config account's data. #[must_use] -pub fn read_config(data: &[u8]) -> Option<(ProgramId, ProgramId)> { - if data.len() < 64 { +pub fn read_config(data: &[u8]) -> Option<(AccountId, ProgramId, ProgramId)> { + if data.len() < 96 { return None; } + assert!(data.len() >= 96); + let outbox_account_id = + AccountId::new(data[..32].try_into().unwrap_or_else(|_| unreachable!())); let mut ids = [0_u32; 16]; - for (word, chunk) in ids.iter_mut().zip(data[..64].chunks_exact(4)) { + for (word, chunk) in ids.iter_mut().zip(data[32..96].chunks_exact(4)) { *word = u32::from_le_bytes(chunk.try_into().unwrap_or_else(|_| unreachable!())); } - let (outbox, target) = ids.split_at(8); + let (outbox_program_id, target_program_id) = ids.split_at(8); Some(( - outbox.try_into().unwrap_or_else(|_| unreachable!()), - target.try_into().unwrap_or_else(|_| unreachable!()), + outbox_account_id, + outbox_program_id + .try_into() + .unwrap_or_else(|_| unreachable!()), + target_program_id + .try_into() + .unwrap_or_else(|_| unreachable!()), )) } @@ -112,11 +138,12 @@ mod tests { #[test] fn config_ids_round_trip() { - let outbox: ProgramId = [3; 8]; + let outbox_account_id = AccountId::new([3; 32]); + let outbox_program_id: ProgramId = [4; 8]; let target: ProgramId = [5; 8]; assert_eq!( - read_config(&config_bytes(outbox, target)), - Some((outbox, target)) + read_config(&config_bytes(outbox_account_id, outbox_program_id, target)), + Some((outbox_account_id, outbox_program_id, target)) ); } @@ -126,6 +153,7 @@ mod tests { #[test] fn lock_is_the_first_variant() { let lock = Instruction::Lock { + self_program_id: [2; 8], amount: 1, target_zone: [7; 32], target_program_id: [1; 8], diff --git a/lez/programs/bridge_lock/src/main.rs b/lez/programs/bridge_lock/src/main.rs index 852cac6f6..1777f1593 100644 --- a/lez/programs/bridge_lock/src/main.rs +++ b/lez/programs/bridge_lock/src/main.rs @@ -30,6 +30,7 @@ fn main() { match instruction { Instruction::Lock { + self_program_id, amount, target_zone, target_program_id, @@ -41,6 +42,7 @@ fn main() { caller_account_id, pre_states, instruction_words, + self_program_id, amount, target_zone, target_program_id, @@ -49,6 +51,8 @@ fn main() { ordinal, ), Instruction::InitConfig { + self_program_id, + outbox_account_id, outbox_program_id, target_program_id, } => init_config( @@ -56,6 +60,8 @@ fn main() { caller_account_id, pre_states, instruction_words, + self_program_id, + outbox_account_id, outbox_program_id, target_program_id, ), @@ -71,6 +77,7 @@ fn lock( caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: ProgramId, amount: u128, target_zone: [u8; 32], target_program_id: ProgramId, @@ -78,11 +85,6 @@ fn lock( payload: Vec, ordinal: u32, ) { - // Recover the real `ProgramId` (RISC0 image id): on this branch every program account lives - // at the direct `AccountId::from(program_id)` bijection, so this round-trip is exact. Needed - // for the PDA-derivation helpers below, which are pinned to the actual image id. - let self_program_id = ProgramId::from(self_account_id); - // pre_states: [config PDA, holder holding (authorized), escrow PDA, outbox PDA]. let [config, holder, escrow, outbox] = <[AccountWithMetadata; 4]>::try_from(pre_states) .expect("Lock requires config, holder, escrow, and outbox accounts"); @@ -94,13 +96,14 @@ fn lock( config_account_id(self_program_id), "first account must be the bridge-lock config PDA" ); - let (outbox_program_id, pinned_target) = read_config(&config.account.data) + let (outbox_account_id, outbox_program_id, pinned_target) = read_config(&config.account.data) .expect("config account holds an outbox and a mint target"); // Value conservation: the forwarded payload must mint exactly what is locked. let WrappedInstruction::Mint { recipient, amount: mint_amount, + .. } = decode_mint(&payload) else { panic!("bridge_lock payload must be a wrapped-token mint"); @@ -169,9 +172,10 @@ fn lock( AccountPostState::new_claimed_if_default(escrow_account, Claim::Pda(escrow_seed())); let call = ChainedCall::new( - outbox_program_id.into(), + outbox_account_id, vec![outbox.clone()], &OutboxInstruction::Emit { + self_program_id: outbox_program_id, target_zone, target_program_id, target_accounts, @@ -200,11 +204,17 @@ fn lock( /// Writes the outbox program and the mint target into the config PDA exactly once /// at genesis. +#[expect( + clippy::too_many_arguments, + reason = "the pinned fields are passed through verbatim" +)] fn init_config( self_account_id: AccountId, caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: ProgramId, + outbox_account_id: AccountId, outbox_program_id: ProgramId, target_program_id: ProgramId, ) { @@ -213,7 +223,7 @@ fn init_config( .expect("InitConfig requires the config account"); assert_eq!( config.account_id, - config_account_id(self_account_id.into()), + config_account_id(self_program_id), "account must be the bridge-lock config PDA" ); // Init-once, idempotent under genesis replay: a `default` config is a first @@ -226,14 +236,14 @@ fn init_config( "bridge-lock config PDA is owned by another program" ); assert_eq!( - *config.account.data, - config_bytes(outbox_program_id, target_program_id), + config.account.data.clone().into_inner(), + config_bytes(outbox_account_id, outbox_program_id, target_program_id).to_vec(), "bridge-lock config already pins a different outbox or mint target" ); } let mut config_account = config.account.clone(); - config_account.data = config_bytes(outbox_program_id, target_program_id) + config_account.data = config_bytes(outbox_account_id, outbox_program_id, target_program_id) .to_vec() .try_into() .expect("pinned ids fit in account data"); diff --git a/lez/programs/cross_zone_inbox/core/src/lib.rs b/lez/programs/cross_zone_inbox/core/src/lib.rs index 2c92f9ab3..f7de6db93 100644 --- a/lez/programs/cross_zone_inbox/core/src/lib.rs +++ b/lez/programs/cross_zone_inbox/core/src/lib.rs @@ -13,6 +13,7 @@ const INBOX_CONFIG_SEED: [u8; 32] = *b"/LEZ/v0.3/CrossZoneInboxCfg/000/"; /// indistinguishable under one domain. Belt and braces, since the image id /// already relocates every PDA in this crate whenever the crate changes. const INBOX_SEEN_SEED_DOMAIN: [u8; 32] = *b"/LEZ/v0.3/CrossZoneInboxSeen/01/"; +const SOURCE_MARKER_SEED_DOMAIN: AccountId = AccountId::new(*b"/LEZ/v0.3/CrossZoneSource/00000/"); /// Raw 32-byte zone (channel) id; the host maps it to the zone-sdk `ChannelId`. pub type ZoneId = [u8; 32]; @@ -30,8 +31,10 @@ pub type MessageKey = [u8; 32]; /// genesis, rather than in the inbox. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] pub struct CrossZoneRoute { - /// The program on the peer zone that emitted the message. - pub src_program_id: ProgramId, + /// The dispatch address of the program on the peer zone that emitted the message (matched + /// against its `OutboxRecord.emitter`, itself the peer's state-machine-verified caller + /// address — not derivable from any `ProgramId`). + pub src_account_id: AccountId, /// The program on this zone it may be delivered to. pub target_program_id: ProgramId, } @@ -106,8 +109,13 @@ pub struct CrossZoneMessage { /// without either trusting what the peer wrote. pub src_block_hash: [u8; 32], pub src_tx_index: u32, - pub src_program_id: ProgramId, + /// The emitting program's dispatch address on the peer zone (its `OutboxRecord.emitter`). + pub src_account_id: AccountId, pub target_program_id: ProgramId, + /// The target program's real dispatch address, used as the `ChainedCall` target. Kept + /// alongside `target_program_id` (its image id, still needed for identity/allowlist + /// bookkeeping) since the two no longer coincide under PDA-based deployment. + pub target_account_id: AccountId, pub payload: Vec, /// Reserved for a future source-state proof; MUST be `None` in v1. pub l1_inclusion_witness: Option>, @@ -226,11 +234,23 @@ impl SeenShard { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub enum Instruction { /// Delivers a finalized peer message to its target program. - Dispatch(CrossZoneMessage), + Dispatch { + message: CrossZoneMessage, + /// This inbox's own image id. The guest cannot learn this at runtime, so the trusted + /// caller (the watcher/verifier) supplies it to recompute the inbox's own PDAs; a wrong + /// value only fails the guest's own self-consistency assertions, since real + /// authorization is independently enforced by the state layer against the account's + /// `program_owner`. + self_program_id: ProgramId, + }, /// Initializes the inbox config account at genesis. Written once, into a /// default (unclaimed) config PDA; the guest refuses a non-default pre-state, /// so it cannot be re-run to overwrite the allowlists. - InitConfig(InboxConfig), + InitConfig { + config: InboxConfig, + /// See [`Dispatch::self_program_id`](Instruction::Dispatch). + self_program_id: ProgramId, + }, } /// Content-addressed replay key for a delivered message. @@ -297,6 +317,41 @@ pub fn inbox_seen_shard_seed(src_zone: &ZoneId, src_block_id: u64) -> PdaSeed { PdaSeed::new(seed) } +/// The account naming who sent a delivery, which the inbox passes at position 0 +/// of the chained call so the target can authenticate its own sources. +/// +/// Nothing writes or claims it, so the state machine's uninitialized-account rule +/// skips it for being unchanged rather than for being default: anyone may send it +/// balance, and the inbox and the targets all round-trip it untouched. Unlike the +/// claimed PDAs elsewhere in this crate, this address is never verified against a +/// real image id by the state machine (it is not a `Claim::Pda`), so it is a +/// plain hash of the inbox's and source's real dispatch addresses rather than a +/// `for_public_pda` derivation — both the inbox and every target already know +/// these addresses without needing to recover any `ProgramId`. +/// +/// The address is derivable by anyone, so it is not a secret and not a +/// capability. What makes it mean something is that a target checks it only after +/// pinning its caller to the inbox, and only the inbox can be that caller. +#[must_use] +pub fn inbox_source_marker_account_id( + inbox_account_id: AccountId, + src_zone: &ZoneId, + src_account_id: AccountId, +) -> AccountId { + use risc0_zkvm::sha::{Impl, Sha256 as _}; + + let mut bytes = [0_u8; 128]; + bytes[..32].copy_from_slice(SOURCE_MARKER_SEED_DOMAIN.as_ref()); + bytes[32..64].copy_from_slice(inbox_account_id.value()); + bytes[64..96].copy_from_slice(src_zone); + bytes[96..].copy_from_slice(src_account_id.value()); + + let hash: [u8; 32] = Impl::hash_bytes(&bytes) + .as_bytes() + .try_into() + .unwrap_or_else(|_| unreachable!()); + AccountId::new(hash) +} #[cfg(test)] mod tests { use lee_core::account::data::DATA_MAX_LENGTH_BYTES; diff --git a/lez/programs/cross_zone_inbox/src/main.rs b/lez/programs/cross_zone_inbox/src/main.rs index bc0357648..05d44cc59 100644 --- a/lez/programs/cross_zone_inbox/src/main.rs +++ b/lez/programs/cross_zone_inbox/src/main.rs @@ -32,19 +32,27 @@ fn main() { ); match instruction { - Instruction::Dispatch(msg) => dispatch( + Instruction::Dispatch { + message, + self_program_id, + } => dispatch( self_account_id, caller_account_id, pre_states, instruction_words, - &msg, + &message, + self_program_id, ), - Instruction::InitConfig(config) => init_config( + Instruction::InitConfig { + config, + self_program_id, + } => init_config( self_account_id, caller_account_id, pre_states, instruction_words, &config, + self_program_id, ), } } @@ -70,17 +78,13 @@ fn dispatch( pre_states: Vec, instruction_words: Vec, msg: &CrossZoneMessage, + self_program_id: ProgramId, ) { assert!( msg.l1_inclusion_witness.is_none(), "l1_inclusion_witness must be None in v1" ); - // Recover the real `ProgramId` (RISC0 image id): on this branch every program account lives - // at the direct `AccountId::from(program_id)` bijection, so this round-trip is exact. Needed - // for the PDA-derivation helpers below, which are pinned to the actual image id. - let self_program_id = ProgramId::from(self_account_id); - // pre_states layout: [config, seen_shard, source marker, then the target accounts]. let mut accounts = pre_states.into_iter(); let config = accounts.next().expect("config account required"); @@ -103,7 +107,7 @@ fn dispatch( // here is what makes a target's own check meaningful. assert_eq!( marker.account_id, - inbox_source_marker_account_id(self_program_id, &msg.src_zone, msg.src_program_id), + inbox_source_marker_account_id(self_account_id, &msg.src_zone, msg.src_account_id), "Third account must be the source marker PDA for this message" ); @@ -160,7 +164,7 @@ fn dispatch( let mut call_pre_states = vec![marker.clone()]; call_pre_states.extend(target_accounts.clone()); let call = ChainedCall { - program_account_id: msg.target_program_id.into(), + program_account_id: msg.target_account_id, pre_states: call_pre_states, instruction_data, pda_seeds: vec![], @@ -192,13 +196,14 @@ fn init_config( pre_states: Vec, instruction_words: Vec, config: &InboxConfig, + self_program_id: ProgramId, ) { // pre_states: [config PDA]. let [config_meta] = <[AccountWithMetadata; 1]>::try_from(pre_states) .expect("InitConfig requires the config account"); assert_eq!( config_meta.account_id, - inbox_config_account_id(self_account_id.into()), + inbox_config_account_id(self_program_id), "account must be the inbox config PDA" ); // Init-once, idempotent under genesis replay: a `default` config is a first diff --git a/lez/programs/cross_zone_outbox/core/src/lib.rs b/lez/programs/cross_zone_outbox/core/src/lib.rs index 5fa219139..70c0aa314 100644 --- a/lez/programs/cross_zone_outbox/core/src/lib.rs +++ b/lez/programs/cross_zone_outbox/core/src/lib.rs @@ -25,6 +25,11 @@ pub enum Instruction { /// Required accounts (1): /// - Outbox PDA account Emit { + /// This program's own image id. The guest cannot learn this at runtime, so the trusted + /// caller supplies it to recompute the outbox slot PDA; a wrong value only fails the + /// guest's own self-consistency assertion, since real authorization is independently + /// enforced by the state layer against the account's `program_owner`. + self_program_id: ProgramId, target_zone: ZoneId, target_program_id: ProgramId, /// Accounts the destination inbox must hand to the target program's @@ -44,11 +49,11 @@ pub enum Instruction { /// watcher and are not stored here. #[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct OutboxRecord { - /// The program that called `Emit`, which is the immediate chained caller. - /// Cross-zone discovery names the top-level program instead, so joining a - /// record against a delivery is only sound while every emitter refuses to be - /// called by another program. - pub emitter: ProgramId, + /// The dispatch address of the program that called `Emit`, which is the immediate chained + /// caller (state-machine verified, via `caller_account_id`). Cross-zone discovery names the + /// top-level program instead, so joining a record against a delivery is only sound while + /// every emitter refuses to be called by another program. + pub emitter: AccountId, pub target_zone: ZoneId, pub ordinal: u32, pub target_program_id: ProgramId, @@ -69,16 +74,17 @@ impl OutboxRecord { } } -/// PDA holding one emitted message, keyed by the emitting program, the -/// destination zone, and a per-emitter per-zone ordinal. +/// PDA holding one emitted message, keyed by the emitting program's dispatch +/// address, the destination zone, and a per-emitter per-zone ordinal. /// -/// `emitter` is the program that called `Emit`, which the guest takes from -/// `caller_account_id` rather than from the instruction. Without it in the -/// address two programs share a slot and one overwrites the other. +/// `emitter` is the dispatch address of the program that called `Emit`, which +/// the guest takes from `caller_account_id` rather than from the instruction. +/// Without it in the address two programs share a slot and one overwrites the +/// other. #[must_use] pub fn outbox_pda( outbox_id: ProgramId, - emitter: ProgramId, + emitter: AccountId, target_zone: &ZoneId, ordinal: u32, ) -> AccountId { @@ -87,14 +93,12 @@ pub fn outbox_pda( /// Seed of an outbox message PDA, exposed so the guest can claim the account. #[must_use] -pub fn outbox_pda_seed(emitter: ProgramId, target_zone: &ZoneId, ordinal: u32) -> PdaSeed { +pub fn outbox_pda_seed(emitter: AccountId, target_zone: &ZoneId, ordinal: u32) -> PdaSeed { use risc0_zkvm::sha::{Impl, Sha256 as _}; let mut bytes = [0_u8; 100]; bytes[..32].copy_from_slice(&OUTBOX_SEED_DOMAIN); - for (word, chunk) in emitter.iter().zip(bytes[32..64].chunks_exact_mut(4)) { - chunk.copy_from_slice(&word.to_le_bytes()); - } + bytes[32..64].copy_from_slice(emitter.value()); bytes[64..96].copy_from_slice(target_zone); bytes[96..].copy_from_slice(&ordinal.to_le_bytes()); @@ -110,7 +114,7 @@ mod tests { use super::*; const OUTBOX: ProgramId = [3; 8]; - const EMITTER: ProgramId = [4; 8]; + const EMITTER: AccountId = AccountId::new([4; 32]); #[test] fn outbox_pda_is_unique_per_zone_and_ordinal() { @@ -136,7 +140,7 @@ mod tests { #[test] fn outbox_pda_is_unique_per_emitter() { let zone = [1; 32]; - let other: ProgramId = [5; 8]; + let other = AccountId::new([5; 32]); assert_ne!( outbox_pda(OUTBOX, EMITTER, &zone, 0), @@ -147,7 +151,7 @@ mod tests { #[test] fn outbox_record_round_trips() { let record = OutboxRecord { - emitter: EMITTER, + emitter: AccountId::new([4; 32]), target_zone: [1; 32], ordinal: 7, target_program_id: [6; 8], diff --git a/lez/programs/cross_zone_outbox/src/main.rs b/lez/programs/cross_zone_outbox/src/main.rs index 520e0274c..8c0e9199c 100644 --- a/lez/programs/cross_zone_outbox/src/main.rs +++ b/lez/programs/cross_zone_outbox/src/main.rs @@ -1,7 +1,7 @@ use cross_zone_outbox_core::{Instruction, OutboxRecord, outbox_pda, outbox_pda_seed}; use lee_core::{ account::{Account, AccountWithMetadata}, - program::{AccountPostState, Claim, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs}, + program::{AccountPostState, Claim, ProgramInput, ProgramOutput, read_lee_inputs}, }; fn main() { @@ -20,37 +20,35 @@ fn main() { // immediate chained caller, not the top-level program that cross-zone // discovery names; the two coincide only while every emitter refuses to be // called by another program, which both do today. - let Some(emitter) = caller_account_id.map(ProgramId::from) else { + let Some(emitter) = caller_account_id else { panic!("Outbox is only callable through a chain call from a user program"); }; - let (target_zone, target_program_id, target_accounts, payload, ordinal) = match instruction { - Instruction::Emit { - target_zone, - target_program_id, - target_accounts, - payload, - ordinal, - } => ( - target_zone, - target_program_id, - target_accounts, - payload, - ordinal, - ), - }; + let (self_program_id, target_zone, target_program_id, target_accounts, payload, ordinal) = + match instruction { + Instruction::Emit { + self_program_id, + target_zone, + target_program_id, + target_accounts, + payload, + ordinal, + } => ( + self_program_id, + target_zone, + target_program_id, + target_accounts, + payload, + ordinal, + ), + }; let [outbox] = <[AccountWithMetadata; 1]>::try_from(pre_states).expect("Emit requires exactly 1 account"); assert_eq!( outbox.account_id, - outbox_pda( - ProgramId::from(self_account_id), - emitter, - &target_zone, - ordinal - ), + outbox_pda(self_program_id, emitter, &target_zone, ordinal), "Account must be the outbox PDA for (emitter, target_zone, ordinal)" ); diff --git a/lez/programs/faucet/core/src/lib.rs b/lez/programs/faucet/core/src/lib.rs index 6a3ae4adc..43ca172fe 100644 --- a/lez/programs/faucet/core/src/lib.rs +++ b/lez/programs/faucet/core/src/lib.rs @@ -14,7 +14,14 @@ pub enum Instruction { /// - Faucet PDA account /// - Recipient vault PDA account GenesisTransferVault { - vault_program_id: ProgramId, + /// This program's own image id. The guest cannot learn this at runtime (a RISC0 guest + /// has no way to read its own image id), so the trusted genesis caller supplies it to + /// recompute the faucet PDA; a wrong value only fails the guest's own self-consistency + /// assertion, since real authorization is independently enforced by the state layer + /// against the account's `program_owner`. + self_program_id: ProgramId, + /// The vault program's real dispatch address. + vault_account_id: AccountId, recipient_id: AccountId, amount: u128, }, @@ -26,7 +33,11 @@ pub enum Instruction { /// Required accounts (2): /// - Faucet PDA account /// - Recipient account - GenesisTransferDirect { amount: u128 }, + GenesisTransferDirect { + /// See `GenesisTransferVault::self_program_id`. + self_program_id: ProgramId, + amount: u128, + }, } #[must_use] diff --git a/lez/programs/faucet/src/main.rs b/lez/programs/faucet/src/main.rs index 295cb7b89..6132e8909 100644 --- a/lez/programs/faucet/src/main.rs +++ b/lez/programs/faucet/src/main.rs @@ -33,7 +33,8 @@ fn main() { let chained_calls = match instruction { Instruction::GenesisTransferVault { - vault_program_id, + self_program_id, + vault_account_id, recipient_id, amount, } => { @@ -43,7 +44,7 @@ fn main() { assert_eq!( faucet.account_id, - faucet_core::compute_faucet_account_id(self_account_id.into()), + faucet_core::compute_faucet_account_id(self_program_id), "First account must be faucet PDA" ); @@ -52,7 +53,7 @@ fn main() { vec![ ChainedCall::new( - vault_program_id.into(), + vault_account_id, vec![faucet_for_vault, recipient_vault], &vault_core::Instruction::Transfer { recipient_id, @@ -62,14 +63,17 @@ fn main() { .with_pda_seeds(vec![faucet_core::compute_faucet_seed()]), ] } - Instruction::GenesisTransferDirect { amount } => { + Instruction::GenesisTransferDirect { + self_program_id, + amount, + } => { let [faucet, recipient] = pre_states .try_into() .expect("TransferDirect requires exactly 2 accounts"); assert_eq!( faucet.account_id, - faucet_core::compute_faucet_account_id(self_account_id.into()), + faucet_core::compute_faucet_account_id(self_program_id), "First account must be faucet PDA" ); diff --git a/lez/programs/ping_core/src/lib.rs b/lez/programs/ping_core/src/lib.rs index b83665766..a9af1d007 100644 --- a/lez/programs/ping_core/src/lib.rs +++ b/lez/programs/ping_core/src/lib.rs @@ -21,13 +21,24 @@ pub enum ReceiverInstruction { /// /// Required accounts (3): the source marker, the receiver config PDA, then /// the record PDA. - Record { payload: Vec }, + Record { + /// This program's own image id. The guest cannot learn this at runtime, so the trusted + /// caller supplies it to recompute the config and record PDAs; a wrong value only fails + /// the guest's own self-consistency assertions, since real authorization is + /// independently enforced by the state layer against the account's `program_owner`. + self_program_id: ProgramId, + payload: Vec, + }, /// Pins the deliverer and the peer sources it may deliver from, written once /// into a default config PDA at genesis. A re-run holding anything different /// is refused; an identical one is a no-op, which is what genesis replay does. /// /// Required accounts (1): the receiver config PDA. - InitConfig(ReceiverConfig), + InitConfig { + /// See [`Record::self_program_id`](ReceiverInstruction::Record). + self_program_id: ProgramId, + config: ReceiverConfig, + }, /// Replaces the authorized sources. Refused unless the config names an /// authority and that account authorized the transaction. /// @@ -53,16 +64,16 @@ pub enum ReceiverInstruction { /// it. #[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)] pub struct ReceiverConfig { - /// The program allowed to call `Record`: the cross-zone inbox. - pub deliverer: ProgramId, + /// The dispatch address of the program allowed to call `Record`: the cross-zone inbox. + pub deliverer: AccountId, /// The program allowed to reach the authority instructions through a chained /// call, or `None` for top-level only. See `WrappedTokenConfig::governance`. pub governance: Option, /// The account allowed to change `sources`, or `None` for a list fixed at /// genesis. Seeded unset; see `WrappedTokenConfig::authority` for why. pub authority: Option, - /// The `(src_zone, src_program_id)` pairs a delivery may originate from. - pub sources: Vec<(ZoneId, ProgramId)>, + /// The `(src_zone, src_account_id)` pairs a delivery may originate from. + pub sources: Vec<(ZoneId, AccountId)>, } impl ReceiverConfig { @@ -88,6 +99,11 @@ pub enum SenderInstruction { /// /// Required accounts (2): the sender config PDA, then the outbox PDA. Send { + /// This program's own image id. The guest cannot learn this at runtime, so the trusted + /// caller supplies it to recompute the sender's own config PDA; a wrong value only fails + /// the guest's own self-consistency assertion, since real authorization is independently + /// enforced by the state layer against the account's `program_owner`. + self_program_id: ProgramId, target_zone: [u8; 32], target_program_id: ProgramId, target_accounts: Vec<[u8; 32]>, @@ -99,7 +115,15 @@ pub enum SenderInstruction { /// is a no-op, which is what genesis replay does. /// /// Required accounts (1): the sender config PDA. - InitConfig { outbox_program_id: ProgramId }, + InitConfig { + /// See [`Send::self_program_id`](SenderInstruction::Send). + self_program_id: ProgramId, + /// The outbox program's real dispatch address, used as the chained-call target. + outbox_account_id: AccountId, + /// The outbox program's own image id, supplied back to it as its `self_program_id` when + /// dispatching `cross_zone_outbox_core::Instruction::Emit`. + outbox_program_id: ProgramId, + }, } /// The account a `ping_receiver` records the latest delivered payload into. @@ -137,27 +161,39 @@ pub const fn receiver_config_seed() -> PdaSeed { PdaSeed::new(RECEIVER_CONFIG_SEED) } -/// Encodes the pinned outbox program id for the config account's data. +/// Encodes the pinned outbox's dispatch address and image id for the config +/// account's data. #[must_use] -pub fn outbox_bytes(outbox_program_id: ProgramId) -> [u8; 32] { - let mut bytes = [0_u8; 32]; - for (word, chunk) in outbox_program_id.iter().zip(bytes.chunks_exact_mut(4)) { +pub fn outbox_bytes(outbox_account_id: AccountId, outbox_program_id: ProgramId) -> [u8; 64] { + let mut bytes = [0_u8; 64]; + bytes[..32].copy_from_slice(outbox_account_id.value()); + for (word, chunk) in outbox_program_id + .iter() + .zip(bytes[32..].chunks_exact_mut(4)) + { chunk.copy_from_slice(&word.to_le_bytes()); } bytes } -/// Decodes the pinned outbox program id from the config account's data. +/// Decodes the pinned outbox's dispatch address and image id from the config +/// account's data. #[must_use] -pub fn read_outbox(data: &[u8]) -> Option { - if data.len() < 32 { +pub fn read_outbox(data: &[u8]) -> Option<(AccountId, ProgramId)> { + if data.len() < 64 { return None; } + assert!(data.len() >= 64); + let outbox_account_id = + AccountId::new(data[..32].try_into().unwrap_or_else(|_| unreachable!())); let mut outbox_program_id = [0_u32; 8]; - for (word, chunk) in outbox_program_id.iter_mut().zip(data[..32].chunks_exact(4)) { + for (word, chunk) in outbox_program_id + .iter_mut() + .zip(data[32..64].chunks_exact(4)) + { *word = u32::from_le_bytes(chunk.try_into().unwrap_or_else(|_| unreachable!())); } - Some(outbox_program_id) + Some((outbox_account_id, outbox_program_id)) } #[cfg(test)] @@ -170,6 +206,7 @@ mod tests { #[test] fn send_is_the_first_variant() { let send = SenderInstruction::Send { + self_program_id: [2; 8], target_zone: [7; 32], target_program_id: [1; 8], target_accounts: vec![], @@ -184,7 +221,10 @@ mod tests { /// decoded by the destination, so its tag word is wire format. #[test] fn record_is_the_first_variant() { - let record = ReceiverInstruction::Record { payload: vec![] }; + let record = ReceiverInstruction::Record { + self_program_id: [1; 8], + payload: vec![], + }; let words = risc0_zkvm::serde::to_vec(&record).expect("Record serializes"); assert_eq!(words[0], 0); } @@ -197,17 +237,21 @@ mod tests { #[test] fn receiver_config_round_trips() { let config = ReceiverConfig { - deliverer: [1; 8], + deliverer: AccountId::new([1; 32]), governance: None, authority: None, - sources: vec![([7; 32], [9; 8])], + sources: vec![([7; 32], AccountId::new([9; 32]))], }; assert_eq!(ReceiverConfig::from_bytes(&config.to_bytes()), Some(config)); } #[test] fn outbox_id_round_trips() { - let outbox: ProgramId = [9; 8]; - assert_eq!(read_outbox(&outbox_bytes(outbox)), Some(outbox)); + let outbox_account_id = AccountId::new([9; 32]); + let outbox_program_id: ProgramId = [3; 8]; + assert_eq!( + read_outbox(&outbox_bytes(outbox_account_id, outbox_program_id)), + Some((outbox_account_id, outbox_program_id)) + ); } } diff --git a/lez/programs/ping_receiver/src/main.rs b/lez/programs/ping_receiver/src/main.rs index 36fd814f9..cb744ad50 100644 --- a/lez/programs/ping_receiver/src/main.rs +++ b/lez/programs/ping_receiver/src/main.rs @@ -23,18 +23,26 @@ fn main() { ) = read_lee_inputs::(); match instruction { - ReceiverInstruction::Record { payload } => record( + ReceiverInstruction::Record { + self_program_id, + payload, + } => record( self_account_id, caller_account_id, pre_states, instruction_words, + self_program_id, payload, ), - ReceiverInstruction::InitConfig(config) => init_config( + ReceiverInstruction::InitConfig { + self_program_id, + config, + } => init_config( self_account_id, caller_account_id, pre_states, instruction_words, + self_program_id, &config, ), ReceiverInstruction::RenounceAuthority => renounce_authority( @@ -58,13 +66,9 @@ fn record( caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: ProgramId, payload: Vec, ) { - // Recover the real `ProgramId` (RISC0 image id): on this branch every program account lives - // at the direct `AccountId::from(program_id)` bijection, so this round-trip is exact. Needed - // for the PDA-derivation helpers below, which are pinned to the actual image id. - let self_program_id = ProgramId::from(self_account_id); - // pre_states: [source marker, config PDA, record PDA]. let [marker, config, record] = <[AccountWithMetadata; 3]>::try_from(pre_states) .expect("Record requires the source marker, config, and record accounts"); @@ -78,15 +82,15 @@ fn record( .expect("config account holds a receiver config"); assert_eq!( caller_account_id, - Some(cfg.deliverer.into()), + Some(cfg.deliverer), "Record is only callable by the authorized deliverer (the cross-zone inbox)" ); // Which peer sent it is this program's own business. Without this the record // says only that some program on some configured peer wrote it. assert!( - cfg.sources.iter().any(|(src_zone, src_program_id)| { + cfg.sources.iter().any(|(src_zone, src_account_id)| { marker.account_id - == inbox_source_marker_account_id(cfg.deliverer, src_zone, *src_program_id) + == inbox_source_marker_account_id(cfg.deliverer, src_zone, *src_account_id) }), "Record is only callable for a peer source this receiver authorizes" ); @@ -273,6 +277,7 @@ fn init_config( caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: ProgramId, config_value: &ReceiverConfig, ) { assert!( @@ -285,7 +290,7 @@ fn init_config( .expect("InitConfig requires the config account"); assert_eq!( config.account_id, - receiver_config_account_id(self_account_id.into()), + receiver_config_account_id(self_program_id), "account must be the receiver config PDA" ); // Init-once, idempotent under genesis replay: a `default` config is a first diff --git a/lez/programs/ping_sender/src/main.rs b/lez/programs/ping_sender/src/main.rs index fdb3f7b6b..04a220b45 100644 --- a/lez/programs/ping_sender/src/main.rs +++ b/lez/programs/ping_sender/src/main.rs @@ -28,6 +28,7 @@ fn main() { match instruction { SenderInstruction::Send { + self_program_id, target_zone, target_program_id, target_accounts, @@ -38,17 +39,24 @@ fn main() { caller_account_id, pre_states, instruction_words, + self_program_id, target_zone, target_program_id, target_accounts, payload, ordinal, ), - SenderInstruction::InitConfig { outbox_program_id } => init_config( + SenderInstruction::InitConfig { + self_program_id, + outbox_account_id, + outbox_program_id, + } => init_config( self_account_id, caller_account_id, pre_states, instruction_words, + self_program_id, + outbox_account_id, outbox_program_id, ), } @@ -63,6 +71,7 @@ fn send( caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: ProgramId, target_zone: [u8; 32], target_program_id: ProgramId, target_accounts: Vec<[u8; 32]>, @@ -78,16 +87,17 @@ fn send( // skip the real outbox and leave no record of itself. assert_eq!( config.account_id, - sender_config_account_id(self_account_id.into()), + sender_config_account_id(self_program_id), "first account must be the ping-sender config PDA" ); - let outbox_program_id = - read_outbox(&config.account.data).expect("config account holds an outbox program id"); + let (outbox_account_id, outbox_program_id) = read_outbox(&config.account.data) + .expect("config account holds an outbox dispatch address and image id"); let call = ChainedCall::new( - outbox_program_id.into(), + outbox_account_id, vec![outbox.clone()], &OutboxInstruction::Emit { + self_program_id: outbox_program_id, target_zone, target_program_id, target_accounts, @@ -115,6 +125,8 @@ fn init_config( caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: ProgramId, + outbox_account_id: AccountId, outbox_program_id: ProgramId, ) { // pre_states: [config PDA]. @@ -122,7 +134,7 @@ fn init_config( .expect("InitConfig requires the config account"); assert_eq!( config.account_id, - sender_config_account_id(self_account_id.into()), + sender_config_account_id(self_program_id), "account must be the ping-sender config PDA" ); // Init-once, idempotent under genesis replay: a `default` config is a first @@ -135,14 +147,14 @@ fn init_config( "ping-sender config PDA is owned by another program" ); assert_eq!( - *config.account.data, - outbox_bytes(outbox_program_id), + config.account.data.clone().into_inner(), + outbox_bytes(outbox_account_id, outbox_program_id).to_vec(), "ping-sender config already pins a different outbox" ); } let mut config_account = config.account.clone(); - config_account.data = outbox_bytes(outbox_program_id) + config_account.data = outbox_bytes(outbox_account_id, outbox_program_id) .to_vec() .try_into() .expect("outbox id fits in account data"); diff --git a/lez/programs/program_loader/core/src/lib.rs b/lez/programs/program_loader/core/src/lib.rs index b28582d31..80d3f9e33 100644 --- a/lez/programs/program_loader/core/src/lib.rs +++ b/lez/programs/program_loader/core/src/lib.rs @@ -114,6 +114,17 @@ pub fn deploy_segment_account_id( ) } +/// The dispatch address a program with `image_id` lives at once deployed via `Deploy` with no +/// upgrade authority. +/// +/// `segment_number` 0, `update_auth` `AccountId::default()`. What every genesis-seeded builtin, +/// and any `Deploy` submitted with a default `update_auth`, dispatches at. +#[must_use] +pub fn immutable_deploy_account_id(image_id: ProgramId) -> AccountId { + let loader_id = ProgramId::from(lee_core::program::RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID); + deploy_header_account_id(loader_id, image_id, 0, AccountId::default()) +} + /// Executes the `Deploy` instruction: verifies `bytecode` decodes as a valid RISC0 program /// binary, derives its header and segment PDAs, and claims both. Called natively from /// dispatch's `RESERVED_DEPLOYMENT_PROGRAM_ACCOUNT_ID` shortcut (see that constant's doc diff --git a/lez/programs/wrapped_token/core/src/lib.rs b/lez/programs/wrapped_token/core/src/lib.rs index d5ffa9a21..5b808ca9a 100644 --- a/lez/programs/wrapped_token/core/src/lib.rs +++ b/lez/programs/wrapped_token/core/src/lib.rs @@ -33,13 +33,25 @@ pub enum Instruction { /// /// Required accounts (3): the source marker, the wrapped-token config PDA, /// then the recipient's holding PDA. - Mint { recipient: [u8; 32], amount: u128 }, + Mint { + /// This program's own image id. The guest cannot learn this at runtime, so the trusted + /// caller supplies it to recompute the config and holding PDAs; a wrong value only fails + /// the guest's own self-consistency assertions, since real authorization is + /// independently enforced by the state layer against the account's `program_owner`. + self_program_id: ProgramId, + recipient: [u8; 32], + amount: u128, + }, /// Pins the minter and the peer sources it may mint for, written once into a /// default config PDA at genesis. A re-run holding anything different is /// refused; an identical one is a no-op, which is what genesis replay does. /// /// Required accounts (1): the wrapped-token config PDA. - InitConfig(WrappedTokenConfig), + InitConfig { + /// See [`Mint::self_program_id`](Instruction::Mint). + self_program_id: ProgramId, + config: WrappedTokenConfig, + }, /// Replaces the authorized sources. Refused unless the config names an /// authority and that account authorized the transaction. /// @@ -64,8 +76,8 @@ pub enum Instruction { /// list is variable length. #[derive(Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)] pub struct WrappedTokenConfig { - /// The program allowed to call `Mint`: the cross-zone inbox. - pub minter: ProgramId, + /// The dispatch address of the program allowed to call `Mint`: the cross-zone inbox. + pub minter: AccountId, /// The program allowed to reach `UpdateSources` and `RenounceAuthority` /// through a chained call, or `None` for top-level only. /// @@ -81,9 +93,9 @@ pub struct WrappedTokenConfig { /// is a governance program worth pointing it at. An `AccountId` rather than /// a key, so a PDA of such a program can hold it and act by delegation. pub authority: Option, - /// The `(src_zone, src_program_id)` pairs a mint may originate from. Empty on + /// The `(src_zone, src_account_id)` pairs a mint may originate from. Empty on /// a zone with no peers, which authorizes nothing. - pub sources: Vec<(ZoneId, ProgramId)>, + pub sources: Vec<(ZoneId, AccountId)>, } impl WrappedTokenConfig { @@ -151,10 +163,13 @@ mod tests { #[test] fn config_round_trips() { let config = WrappedTokenConfig { - minter: [1, 2, 3, 4, 5, 6, 7, 8], + minter: AccountId::new([1; 32]), governance: Some([2; 8]), authority: Some(AccountId::new([5; 32])), - sources: vec![([7; 32], [9; 8]), ([8; 32], [4; 8])], + sources: vec![ + ([7; 32], AccountId::new([9; 32])), + ([8; 32], AccountId::new([4; 32])), + ], }; assert_eq!( WrappedTokenConfig::from_bytes(&config.to_bytes()), @@ -174,6 +189,7 @@ mod tests { #[test] fn mint_is_the_first_variant() { let mint = Instruction::Mint { + self_program_id: [2; 8], recipient: [3; 32], amount: 1, }; diff --git a/lez/programs/wrapped_token/src/main.rs b/lez/programs/wrapped_token/src/main.rs index 67857ed1c..44d1db909 100644 --- a/lez/programs/wrapped_token/src/main.rs +++ b/lez/programs/wrapped_token/src/main.rs @@ -23,19 +23,28 @@ fn main() { ) = read_lee_inputs::(); match instruction { - Instruction::Mint { recipient, amount } => mint( + Instruction::Mint { + self_program_id, + recipient, + amount, + } => mint( self_account_id, caller_account_id, pre_states, instruction_words, + self_program_id, recipient, amount, ), - Instruction::InitConfig(config) => init_config( + Instruction::InitConfig { + self_program_id, + config, + } => init_config( self_account_id, caller_account_id, pre_states, instruction_words, + self_program_id, &config, ), Instruction::RenounceAuthority => renounce_authority( @@ -59,14 +68,10 @@ fn mint( caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: lee_core::program::ProgramId, recipient: [u8; 32], amount: u128, ) { - // Recover the real `ProgramId` (RISC0 image id): on this branch every program account lives - // at the direct `AccountId::from(program_id)` bijection, so this round-trip is exact. Needed - // for the PDA-derivation helpers below, which are pinned to the actual image id. - let self_program_id = lee_core::program::ProgramId::from(self_account_id); - // pre_states: [source marker, config PDA, recipient holding PDA]. let [marker, config, holding] = <[AccountWithMetadata; 3]>::try_from(pre_states) .expect("Mint requires the source marker, config, and recipient holding accounts"); @@ -82,7 +87,7 @@ fn mint( .expect("config account holds a wrapped-token config"); assert_eq!( caller_account_id, - Some(cfg.minter.into()), + Some(cfg.minter), "Mint is only callable by the authorized minter (the cross-zone inbox)" ); // The inbox vouches only that the message arrived; which peer sent it is this @@ -90,9 +95,9 @@ fn mint( // anyone's word for it. The marker's address is the source, so re-deriving it // from an authorized pair is the whole check. assert!( - cfg.sources.iter().any(|(src_zone, src_program_id)| { + cfg.sources.iter().any(|(src_zone, src_account_id)| { marker.account_id - == inbox_source_marker_account_id(cfg.minter, src_zone, *src_program_id) + == inbox_source_marker_account_id(cfg.minter, src_zone, *src_account_id) }), "Mint is only callable for a peer source this token authorizes" ); @@ -293,6 +298,7 @@ fn init_config( caller_account_id: Option, pre_states: Vec, instruction_words: Vec, + self_program_id: lee_core::program::ProgramId, config_value: &WrappedTokenConfig, ) { assert!( @@ -305,7 +311,7 @@ fn init_config( .expect("InitConfig requires the config account"); assert_eq!( config.account_id, - config_account_id(self_account_id.into()), + config_account_id(self_program_id), "account must be the wrapped-token config PDA" ); // Init-once, idempotent under genesis replay: a `default` config is a first diff --git a/lez/sequencer/actors/rpc_server/src/actor/service.rs b/lez/sequencer/actors/rpc_server/src/actor/service.rs index 6c3afc892..ac71a8d37 100644 --- a/lez/sequencer/actors/rpc_server/src/actor/service.rs +++ b/lez/sequencer/actors/rpc_server/src/actor/service.rs @@ -83,9 +83,7 @@ impl sequencer_service_rpc::Rpc // an inbound cross-zone delivery. Chained user calls are already rejected // by the inbox guest's caller-is-none assertion. if let LeeTransaction::Public(public_tx) = &authenticated_tx - && sequencer_core::is_sequencer_only_program(lee::ProgramId::from( - public_tx.message().program_account_id, - )) + && sequencer_core::is_sequencer_only_program(public_tx.message().program_account_id) { return Err(ErrorObjectOwned::owned( ErrorCode::InvalidParams.code(), diff --git a/lez/sequencer/core/src/cross_zone_watcher.rs b/lez/sequencer/core/src/cross_zone_watcher.rs index 112e08146..9bafeb18f 100644 --- a/lez/sequencer/core/src/cross_zone_watcher.rs +++ b/lez/sequencer/core/src/cross_zone_watcher.rs @@ -534,8 +534,9 @@ async fn record_block_deliveries( continue; }; let message = public_tx.message(); - let message_program_id = lee_core::program::ProgramId::from(message.program_account_id); - let Some(emission) = extract_emission(message_program_id, &message.instruction_data) else { + let Some(emission) = + extract_emission(message.program_account_id, &message.instruction_data) + else { continue; }; @@ -548,7 +549,9 @@ async fn record_block_deliveries( // lettered. Kept host-side only, never in `extract_emission` or the // verifier's re-derivation, where a check that depends on this build would // make the two disagree and halt ingestion. - if is_sequencer_only_program(emission.target_program_id) { + if is_sequencer_only_program(program_loader_core::immutable_deploy_account_id( + emission.target_program_id, + )) { warn!( "Watcher dropping message from peer {}: a peer may not dispatch into a sequencer-only program", hex::encode(peer_zone) @@ -563,7 +566,7 @@ async fn record_block_deliveries( src_block_id: block.header.block_id, src_block_hash: block_hash.0, src_tx_index, - src_program_id: message_program_id, + src_account_id: message.program_account_id, }, emission.target_program_id, &emission.target_accounts, @@ -1058,7 +1061,7 @@ mod tests { let LeeTransaction::Public(public_tx) = tx else { panic!("a dispatch is a public transaction"); }; - let Ok(cross_zone_inbox_core::Instruction::Dispatch(msg)) = + let Ok(cross_zone_inbox_core::Instruction::Dispatch { message: msg, .. }) = risc0_zkvm::serde::from_slice(&public_tx.message().instruction_data) else { panic!("the recorded transaction is an inbox dispatch"); diff --git a/lez/sequencer/core/src/lib.rs b/lez/sequencer/core/src/lib.rs index f6da05afd..e782bf1b7 100644 --- a/lez/sequencer/core/src/lib.rs +++ b/lez/sequencer/core/src/lib.rs @@ -2013,13 +2013,16 @@ fn build_stake_genesis_transactions(staked: &[FoundingStake]) -> Vec bool { - cross_zone::is_sequencer_only_program(program_id) +pub fn is_sequencer_only_program(account_id: AccountId) -> bool { + cross_zone::is_sequencer_only_program(account_id) } fn build_supply_account_genesis_transaction( @@ -2085,11 +2088,12 @@ fn build_supply_account_genesis_transaction( let recipient_vault_id = vault_core::compute_vault_account_id(vault_program_id, *account_id); let message = Message::try_new( - faucet_program_id.into(), + program_loader_core::immutable_deploy_account_id(faucet_program_id), vec![system_accounts::faucet_account_id(), recipient_vault_id], Vec::new(), faucet_core::Instruction::GenesisTransferVault { - vault_program_id, + self_program_id: faucet_program_id, + vault_account_id: program_loader_core::immutable_deploy_account_id(vault_program_id), recipient_id: *account_id, amount: balance, }, @@ -2105,10 +2109,13 @@ fn build_supply_bridge_account_genesis_transaction(balance: u128) -> PublicTrans let bridge_account_id = system_accounts::bridge_account_id(); let message = Message::try_new( - faucet_program_id.into(), + program_loader_core::immutable_deploy_account_id(faucet_program_id), vec![system_accounts::faucet_account_id(), bridge_account_id], Vec::new(), - faucet_core::Instruction::GenesisTransferDirect { amount: balance }, + faucet_core::Instruction::GenesisTransferDirect { + self_program_id: faucet_program_id, + amount: balance, + }, ) .expect("Failed to serialize bridge genesis transfer instruction"); let witness_set = lee::public_transaction::WitnessSet::from_raw_parts(Vec::new()); @@ -2139,7 +2146,7 @@ fn build_bridge_deposit_tx_from_event(event: &PendingDepositEventRecord) -> Resu bridge_core::deposit_receipt_account_id(bridge_program_id, event.deposit_op_id.0); let message = Message::try_new( - bridge_program_id.into(), + program_loader_core::immutable_deploy_account_id(bridge_program_id), vec![ system_accounts::bridge_account_id(), recipient_vault_id, @@ -2148,7 +2155,9 @@ fn build_bridge_deposit_tx_from_event(event: &PendingDepositEventRecord) -> Resu Vec::new(), bridge_core::Instruction::Deposit { l1_deposit_op_id: event.deposit_op_id.0, + self_program_id: bridge_program_id, vault_program_id, + vault_account_id: program_loader_core::immutable_deploy_account_id(vault_program_id), recipient_id: metadata.recipient_id, amount: event.amount, }, @@ -2259,7 +2268,7 @@ fn resubmittable_txs(block: &Block) -> Vec { #[must_use] fn is_sequencer_only_tx(tx: &LeeTransaction) -> bool { matches!(tx, LeeTransaction::Public(tx) - if is_sequencer_only_program(lee::ProgramId::from(tx.message().program_account_id))) + if is_sequencer_only_program(tx.message().program_account_id)) } /// The cross-zone message an inbox dispatch delivers, or `None` if `tx` is not @@ -2271,15 +2280,17 @@ fn extract_cross_zone_dispatch(tx: &LeeTransaction) -> Option }; let message = tx.message(); - if message.program_account_id != programs::cross_zone_inbox().id().into() { + if message.program_account_id + != program_loader_core::immutable_deploy_account_id(programs::cross_zone_inbox().id()) + { return None; } match risc0_zkvm::serde::from_slice::( &message.instruction_data, ) { - Ok(cross_zone_inbox_core::Instruction::Dispatch(msg)) => Some(msg), - Ok(cross_zone_inbox_core::Instruction::InitConfig(_)) | Err(_) => None, + Ok(cross_zone_inbox_core::Instruction::Dispatch { message, .. }) => Some(message), + Ok(cross_zone_inbox_core::Instruction::InitConfig { .. }) | Err(_) => None, } } @@ -2379,7 +2390,9 @@ fn extract_bridge_deposit_id(tx: &LeeTransaction) -> Option { }; let message = tx.message(); - if message.program_account_id != programs::bridge().id().into() { + if message.program_account_id + != program_loader_core::immutable_deploy_account_id(programs::bridge().id()) + { return None; } @@ -2402,7 +2415,9 @@ fn extract_bridge_withdraw_data(tx: &LeeTransaction) -> Option { }; let message = tx.message(); - if message.program_account_id != programs::bridge().id().into() { + if message.program_account_id + != program_loader_core::immutable_deploy_account_id(programs::bridge().id()) + { return None; } diff --git a/lez/sequencer/core/src/tests.rs b/lez/sequencer/core/src/tests.rs index 166486eb7..a5de8cfc3 100644 --- a/lez/sequencer/core/src/tests.rs +++ b/lez/sequencer/core/src/tests.rs @@ -151,13 +151,21 @@ fn setup_sequencer_config() -> SequencerConfig { #[test] fn only_the_cross_zone_inbox_is_sequencer_only() { - assert!(is_sequencer_only_program(programs::cross_zone_inbox().id())); + assert!(is_sequencer_only_program( + program_loader_core::immutable_deploy_account_id(programs::cross_zone_inbox().id()) + )); assert!(!is_sequencer_only_program( - programs::cross_zone_outbox().id() + program_loader_core::immutable_deploy_account_id(programs::cross_zone_outbox().id()) + )); + assert!(!is_sequencer_only_program( + program_loader_core::immutable_deploy_account_id(programs::wrapped_token().id()) + )); + assert!(!is_sequencer_only_program( + program_loader_core::immutable_deploy_account_id(programs::ping_sender().id()) + )); + assert!(!is_sequencer_only_program( + program_loader_core::immutable_deploy_account_id(programs::clock().id()) )); - assert!(!is_sequencer_only_program(programs::wrapped_token().id())); - assert!(!is_sequencer_only_program(programs::ping_sender().id())); - assert!(!is_sequencer_only_program(programs::clock().id())); } #[test] @@ -222,7 +230,9 @@ fn tx_is_bridge_deposit( return false; }; - if public_tx.message.program_account_id != programs::bridge().id().into() { + if public_tx.message.program_account_id + != program_loader_core::immutable_deploy_account_id(programs::bridge().id()) + { return false; } @@ -251,7 +261,9 @@ fn cross_zone_test_config() -> SequencerConfig { peers: vec![CrossZonePeer { channel_id: PEER_ZONE, allowed_routes: vec![CrossZoneRoute { - src_program_id: programs::ping_sender().id(), + src_account_id: program_loader_core::immutable_deploy_account_id( + programs::ping_sender().id(), + ), target_program_id: programs::ping_receiver().id(), }], expected_block_signing_pubkeys: Vec::new(), @@ -267,6 +279,7 @@ fn cross_zone_test_config() -> SequencerConfig { /// form an emitter on the peer zone puts in the message payload. fn ping_payload(payload: &[u8]) -> Vec { risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + self_program_id: programs::ping_receiver().id(), payload: payload.to_vec(), }) .expect("ping instruction serializes") @@ -286,7 +299,7 @@ fn dispatch_tx(src_block_id: u64, payload: Vec) -> LeeTransaction { src_block_id, src_block_hash: peer_block_hash(src_block_id), src_tx_index: 0, - src_program_id: programs::ping_sender().id(), + src_account_id: program_loader_core::immutable_deploy_account_id(programs::ping_sender().id()), }, receiver_id, &[ @@ -1626,7 +1639,7 @@ async fn transactions_touching_clock_account_are_dropped_from_block() { // be dropped because their diffs touch the clock accounts. let crafted_clock_tx = { let message = lee::public_transaction::Message::try_new( - programs::clock().id().into(), + program_loader_core::immutable_deploy_account_id(programs::clock().id()), system_accounts::clock_account_ids().to_vec(), vec![], 42_u64, @@ -1766,7 +1779,7 @@ async fn block_production_aborts_when_clock_account_data_is_corrupted() { // 0, // ); // let sender_private_account = Account { -// program_owner: programs::authenticated_transfer().id().into(), +// program_owner: programs::authenticated_transfer().deployed_account_id(), // balance: 100, // nonce: Nonce(0xdead_beef), // data: Data::default(), @@ -1869,9 +1882,9 @@ fn time_locked_transfer_transaction( amount: u128, deadline: u64, ) -> PublicTransaction { - let program_id = test_programs::time_locked_transfer().id(); + let program_id = test_programs::time_locked_transfer().deployed_account_id(); let message = lee::public_transaction::Message::try_new( - program_id.into(), + program_id, vec![from, to, clock_account_id], vec![Nonce(from_nonce)], (amount, deadline), @@ -1893,7 +1906,7 @@ fn time_locked_transfer_succeeds_when_deadline_has_passed() { state.force_insert_account( recipient_id, Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: programs::authenticated_transfer().deployed_account_id(), ..Account::default() }, ); @@ -1903,7 +1916,7 @@ fn time_locked_transfer_succeeds_when_deadline_has_passed() { state.force_insert_account( sender_id, Account { - program_owner: test_programs::time_locked_transfer().id().into(), + program_owner: test_programs::time_locked_transfer().deployed_account_id(), balance: 100, ..Account::default() }, @@ -1942,7 +1955,7 @@ fn time_locked_transfer_fails_when_deadline_is_in_the_future() { state.force_insert_account( recipient_id, Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: programs::authenticated_transfer().deployed_account_id(), ..Account::default() }, ); @@ -1952,7 +1965,7 @@ fn time_locked_transfer_fails_when_deadline_is_in_the_future() { state.force_insert_account( sender_id, Account { - program_owner: test_programs::time_locked_transfer().id().into(), + program_owner: test_programs::time_locked_transfer().deployed_account_id(), balance: 100, ..Account::default() }, @@ -1996,9 +2009,9 @@ fn pinata_cooldown_transaction( winner_id: AccountId, clock_account_id: AccountId, ) -> PublicTransaction { - let program_id = test_programs::pinata_cooldown().id(); + let program_id = test_programs::pinata_cooldown().deployed_account_id(); let message = lee::public_transaction::Message::try_new( - program_id.into(), + program_id, vec![pinata_id, winner_id, clock_account_id], vec![], (), @@ -2027,14 +2040,14 @@ fn pinata_cooldown_claim_succeeds_after_cooldown() { state.force_insert_account( winner_id, Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: programs::authenticated_transfer().deployed_account_id(), ..Account::default() }, ); state.force_insert_account( pinata_id, Account { - program_owner: test_programs::pinata_cooldown().id().into(), + program_owner: test_programs::pinata_cooldown().deployed_account_id(), balance: 1000, data: pinata_cooldown_data(prize, cooldown_ms, last_claim_timestamp) .try_into() @@ -2074,14 +2087,14 @@ fn pinata_cooldown_claim_fails_during_cooldown() { state.force_insert_account( winner_id, Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: programs::authenticated_transfer().deployed_account_id(), ..Account::default() }, ); state.force_insert_account( pinata_id, Account { - program_owner: test_programs::pinata_cooldown().id().into(), + program_owner: test_programs::pinata_cooldown().deployed_account_id(), balance: 1000, data: pinata_cooldown_data(prize, cooldown_ms, last_claim_timestamp) .try_into() @@ -2120,7 +2133,7 @@ fn pda_mechanism_with_pinata_token_program() { balance: 150, }; let expected_winner_token_holding_post = Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), data: Data::from(&expected_winner_account_holding), ..Account::default() }; @@ -2131,7 +2144,7 @@ fn pda_mechanism_with_pinata_token_program() { state.force_insert_account( pinata_definition_id, Account { - program_owner: pinata_token.id().into(), + program_owner: pinata_token.deployed_account_id(), // Difficulty: 3 data: vec![3; 33].try_into().unwrap(), ..Account::default() @@ -2158,7 +2171,7 @@ fn pda_mechanism_with_pinata_token_program() { state.force_insert_account( pinata_token_definition_id, Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), data: Data::from(&token_definition), ..Account::default() }, @@ -2166,7 +2179,7 @@ fn pda_mechanism_with_pinata_token_program() { state.force_insert_account( pinata_token_holding_id, Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), data: Data::from(&token_holding), ..Account::default() }, @@ -2174,7 +2187,7 @@ fn pda_mechanism_with_pinata_token_program() { state.force_insert_account( winner_token_holding_id, Account { - program_owner: token.id().into(), + program_owner: token.deployed_account_id(), data: Data::from(&winner_holding), ..Account::default() }, @@ -2183,7 +2196,7 @@ fn pda_mechanism_with_pinata_token_program() { // Submit a solution to the pinata program to claim the prize let solution: u128 = 989_106; let message = lee::public_transaction::Message::try_new( - pinata_token.id().into(), + pinata_token.deployed_account_id(), vec![ pinata_definition_id, pinata_token_holding_id, @@ -2219,7 +2232,7 @@ fn resubmittable_txs_drops_clock_and_bridge_deposits() { .unwrap(); let withdraw_tx = { let message = lee::public_transaction::Message::try_new( - programs::bridge().id().into(), + program_loader_core::immutable_deploy_account_id(programs::bridge().id()), vec![system_accounts::bridge_account_id()], vec![], bridge_core::Instruction::Withdraw { @@ -3883,7 +3896,7 @@ fn loader_deploys_program_via_chained_call() { .unwrap(); let message = lee::public_transaction::Message::try_new( - forwarder.id().into(), + forwarder.deployed_account_id(), vec![header, segment], vec![], (loader_id, inner_instruction_data), diff --git a/lez/storage/src/indexer/tests.rs b/lez/storage/src/indexer/tests.rs index 148454efe..21e33ebe8 100644 --- a/lez/storage/src/indexer/tests.rs +++ b/lez/storage/src/indexer/tests.rs @@ -31,7 +31,7 @@ fn initial_state() -> lee::V03State { ( id, Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: programs::authenticated_transfer().deployed_account_id(), balance, ..Account::default() }, diff --git a/lez/system_accounts/Cargo.toml b/lez/system_accounts/Cargo.toml index 0c6a9fd40..2764137e4 100644 --- a/lez/system_accounts/Cargo.toml +++ b/lez/system_accounts/Cargo.toml @@ -13,4 +13,5 @@ faucet_core.workspace = true bridge_core.workspace = true clock_core.workspace = true sequencer_stake_core.workspace = true +program_loader_core.workspace = true programs.workspace = true diff --git a/lez/system_accounts/src/lib.rs b/lez/system_accounts/src/lib.rs index 38997cdc7..7378a022c 100644 --- a/lez/system_accounts/src/lib.rs +++ b/lez/system_accounts/src/lib.rs @@ -32,7 +32,7 @@ pub fn pinata_account_id() -> AccountId { #[must_use] pub fn pinata_account() -> Account { Account { - program_owner: programs::pinata().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id(programs::pinata().id()), balance: 1_500_000, // Difficulty: 3 data: vec![3; 33].try_into().expect("Should fit"), @@ -48,7 +48,9 @@ pub fn faucet_account_id() -> AccountId { #[must_use] pub fn faucet_account() -> Account { Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id( + programs::authenticated_transfer().id(), + ), balance: u128::MAX, ..Account::default() } @@ -62,7 +64,9 @@ pub fn bridge_account_id() -> AccountId { #[must_use] pub fn bridge_account() -> Account { Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id( + programs::authenticated_transfer().id(), + ), ..Account::default() } } @@ -97,7 +101,7 @@ pub fn sequencer_stake_config_account() -> Account { #[must_use] pub fn clock_account() -> Account { Account { - program_owner: programs::clock().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id(programs::clock().id()), data: ClockAccountData { block_id: 0, timestamp: 0, diff --git a/lez/testnet_initial_state/Cargo.toml b/lez/testnet_initial_state/Cargo.toml index f06d5f51f..b22feb377 100644 --- a/lez/testnet_initial_state/Cargo.toml +++ b/lez/testnet_initial_state/Cargo.toml @@ -8,6 +8,7 @@ license.workspace = true key_protocol.workspace = true lee.workspace = true lee_core.workspace = true +program_loader_core.workspace = true system_accounts.workspace = true programs.workspace = true diff --git a/lez/testnet_initial_state/src/lib.rs b/lez/testnet_initial_state/src/lib.rs index 3e3a18a5d..fc01e1b2d 100644 --- a/lez/testnet_initial_state/src/lib.rs +++ b/lez/testnet_initial_state/src/lib.rs @@ -154,7 +154,8 @@ fn initial_private_accounts() -> Vec<(lee_core::Commitment, lee_core::Nullifier) let mut acc = init_comm_data.account.clone(); - acc.program_owner = programs::authenticated_transfer().id().into(); + acc.program_owner = + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()); ( lee_core::Commitment::new(&account_id, &acc), @@ -190,7 +191,9 @@ fn initial_public_accounts() -> HashMap { ( acc_data.account_id, Account { - program_owner: programs::authenticated_transfer().id().into(), + program_owner: program_loader_core::immutable_deploy_account_id( + programs::authenticated_transfer().id(), + ), balance: acc_data.balance, ..Default::default() }, diff --git a/lez/wallet-ffi/Cargo.toml b/lez/wallet-ffi/Cargo.toml index 25d5f2a50..da0199875 100644 --- a/lez/wallet-ffi/Cargo.toml +++ b/lez/wallet-ffi/Cargo.toml @@ -16,6 +16,7 @@ lee.workspace = true lee_core.workspace = true common.workspace = true programs.workspace = true +program_loader_core.workspace = true tokio.workspace = true key_protocol.workspace = true diff --git a/lez/wallet-ffi/src/generic_transaction.rs b/lez/wallet-ffi/src/generic_transaction.rs index 61c0e3347..c680c0db6 100644 --- a/lez/wallet-ffi/src/generic_transaction.rs +++ b/lez/wallet-ffi/src/generic_transaction.rs @@ -80,7 +80,8 @@ impl TryFrom<&FfiProgramWithDependencies> for ProgramWithDependencies { fn try_from(value: &FfiProgramWithDependencies) -> Result { let mut program_map = HashMap::new(); - let orig_program = (&value.program).try_into()?; + let orig_program: Program = (&value.program).try_into()?; + let orig_program_id = orig_program.id(); // Alignment will be different, we need to read elements one-by-one for i in 0..value.deps_size { @@ -88,10 +89,14 @@ impl TryFrom<&FfiProgramWithDependencies> for ProgramWithDependencies { .ok_or(WalletFfiError::NullPointer)? .try_into()?; - program_map.insert(program_dep.id().into(), program_dep); + program_map.insert( + program_loader_core::immutable_deploy_account_id(program_dep.id()), + program_dep, + ); } - Ok(Self::new(orig_program, program_map)) + Ok(Self::new(orig_program, program_map) + .with_program_account_id(program_loader_core::immutable_deploy_account_id(orig_program_id))) } } diff --git a/lez/wallet/Cargo.toml b/lez/wallet/Cargo.toml index a2da75640..d88490a8a 100644 --- a/lez/wallet/Cargo.toml +++ b/lez/wallet/Cargo.toml @@ -23,6 +23,7 @@ keycard_wallet.workspace = true programs.workspace = true system_accounts.workspace = true associated_token_account_core.workspace = true +program_loader_core.workspace = true bip39.workspace = true rpassword = "7" diff --git a/lez/wallet/src/cli/account.rs b/lez/wallet/src/cli/account.rs index 92863892b..d6e5f52ea 100644 --- a/lez/wallet/src/cli/account.rs +++ b/lez/wallet/src/cli/account.rs @@ -2,7 +2,7 @@ use anyhow::{Context as _, Result}; use clap::Subcommand; use itertools::Itertools as _; use key_protocol::key_management::{KeyChain, key_tree::chain_index::ChainIndex}; -use lee::{Account, AccountId, PublicKey}; +use lee::{Account, PublicKey}; use lee_core::Identifier; use token_core::{TokenDefinition, TokenHolding}; @@ -643,8 +643,9 @@ impl WalletSubcommand for ImportSubcommand { /// Formats account details for display, returning (description, `json_view`). fn format_account_details(account: &Account) -> (String, String) { - let auth_tr_prog_id: AccountId = programs::authenticated_transfer().id().into(); - let token_prog_id: AccountId = programs::token().id().into(); + let auth_tr_prog_id = + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()); + let token_prog_id = program_loader_core::immutable_deploy_account_id(programs::token().id()); match &account.program_owner { o if *o == auth_tr_prog_id => { diff --git a/lez/wallet/src/lib.rs b/lez/wallet/src/lib.rs index 5889334ed..ae3083cb2 100644 --- a/lez/wallet/src/lib.rs +++ b/lez/wallet/src/lib.rs @@ -860,7 +860,7 @@ impl WalletCore { let nonces = acc_manager.public_account_nonces(); let message = lee::public_transaction::Message::new_preserialized( - program_id.into(), + program_loader_core::immutable_deploy_account_id(program_id), account_ids, nonces, instruction_data, diff --git a/lez/wallet/src/program_facades/ata.rs b/lez/wallet/src/program_facades/ata.rs index c9b66feca..a53792a80 100644 --- a/lez/wallet/src/program_facades/ata.rs +++ b/lez/wallet/src/program_facades/ata.rs @@ -223,6 +223,8 @@ impl Ata<'_> { fn ata_with_token_dependency() -> ProgramWithDependencies { let token = programs::token(); let mut deps = HashMap::new(); - deps.insert(token.id().into(), token); - ProgramWithDependencies::new(programs::ata(), deps) + deps.insert(program_loader_core::immutable_deploy_account_id(token.id()), token); + ProgramWithDependencies::new(programs::ata(), deps).with_program_account_id( + program_loader_core::immutable_deploy_account_id(programs::ata().id()), + ) } diff --git a/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs b/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs index 04ca723a1..14d5d7ed3 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/deshielded.rs @@ -1,7 +1,7 @@ use common::HashType; use lee::AccountId; -use super::{NativeTokenTransfer, auth_transfer_preparation}; +use super::{NativeTokenTransfer, auth_transfer_preparation, auth_transfer_program_with_deps}; use crate::{AccountIdentity, ExecutionFailureKind}; impl NativeTokenTransfer<'_> { @@ -11,7 +11,7 @@ impl NativeTokenTransfer<'_> { to: AccountId, balance_to_move: u128, ) -> Result<(HashType, lee_core::SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); + let (instruction_data, _program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 .send_privacy_preserving_tx_with_pre_check( @@ -22,7 +22,7 @@ impl NativeTokenTransfer<'_> { AccountIdentity::PublicNoSign(to), ], instruction_data, - &program.into(), + &auth_transfer_program_with_deps(), tx_pre_check, ) .await diff --git a/lez/wallet/src/program_facades/native_token_transfer/mod.rs b/lez/wallet/src/program_facades/native_token_transfer/mod.rs index c4e673fa8..c2dd31aba 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/mod.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/mod.rs @@ -1,4 +1,6 @@ -use lee::{Account, program::Program}; +use lee::{ + Account, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, +}; use lee_core::program::InstructionData; use crate::{ExecutionFailureKind, WalletCore}; @@ -14,6 +16,12 @@ pub mod shielded; )] pub struct NativeTokenTransfer<'wallet>(pub &'wallet WalletCore); +pub(super) fn auth_transfer_program_with_deps() -> ProgramWithDependencies { + ProgramWithDependencies::from(programs::authenticated_transfer()).with_program_account_id( + program_loader_core::immutable_deploy_account_id(programs::authenticated_transfer().id()), + ) +} + fn auth_transfer_preparation( balance_to_move: u128, ) -> ( diff --git a/lez/wallet/src/program_facades/native_token_transfer/private.rs b/lez/wallet/src/program_facades/native_token_transfer/private.rs index 712d67741..f0d23e50a 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/private.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/private.rs @@ -4,7 +4,7 @@ use common::HashType; use lee::{AccountId, program::Program}; use lee_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; -use super::{NativeTokenTransfer, auth_transfer_preparation}; +use super::{NativeTokenTransfer, auth_transfer_preparation, auth_transfer_program_with_deps}; use crate::{AccountIdentity, ExecutionFailureKind}; impl NativeTokenTransfer<'_> { @@ -23,7 +23,7 @@ impl NativeTokenTransfer<'_> { .send_privacy_preserving_tx( vec![account], Program::serialize_instruction(instruction).unwrap(), - &programs::authenticated_transfer().into(), + &auth_transfer_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -41,7 +41,7 @@ impl NativeTokenTransfer<'_> { to_identifier: Identifier, balance_to_move: u128, ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { - let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); + let (instruction_data, _program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 .send_privacy_preserving_tx_with_pre_check( @@ -56,7 +56,7 @@ impl NativeTokenTransfer<'_> { }, ], instruction_data, - &program.into(), + &auth_transfer_program_with_deps(), tx_pre_check, ) .await @@ -74,7 +74,7 @@ impl NativeTokenTransfer<'_> { to: AccountId, balance_to_move: u128, ) -> Result<(HashType, [SharedSecretKey; 2]), ExecutionFailureKind> { - let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); + let (instruction_data, _program, tx_pre_check) = auth_transfer_preparation(balance_to_move); let from_account = self .0 @@ -89,7 +89,7 @@ impl NativeTokenTransfer<'_> { .send_privacy_preserving_tx_with_pre_check( vec![from_account, to_account], instruction_data, - &program.into(), + &auth_transfer_program_with_deps(), tx_pre_check, ) .await diff --git a/lez/wallet/src/program_facades/native_token_transfer/shielded.rs b/lez/wallet/src/program_facades/native_token_transfer/shielded.rs index 002b11766..dadf5885e 100644 --- a/lez/wallet/src/program_facades/native_token_transfer/shielded.rs +++ b/lez/wallet/src/program_facades/native_token_transfer/shielded.rs @@ -2,7 +2,7 @@ use common::HashType; use lee::AccountId; use lee_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; -use super::{NativeTokenTransfer, auth_transfer_preparation}; +use super::{NativeTokenTransfer, auth_transfer_preparation, auth_transfer_program_with_deps}; use crate::{AccountIdentity, ExecutionFailureKind}; impl NativeTokenTransfer<'_> { @@ -12,7 +12,7 @@ impl NativeTokenTransfer<'_> { to: AccountId, balance_to_move: u128, ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); + let (instruction_data, _program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 .send_privacy_preserving_tx_with_pre_check( vec![ @@ -22,7 +22,7 @@ impl NativeTokenTransfer<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &program.into(), + &auth_transfer_program_with_deps(), tx_pre_check, ) .await @@ -43,7 +43,7 @@ impl NativeTokenTransfer<'_> { to_identifier: Identifier, balance_to_move: u128, ) -> Result<(HashType, SharedSecretKey), ExecutionFailureKind> { - let (instruction_data, program, tx_pre_check) = auth_transfer_preparation(balance_to_move); + let (instruction_data, _program, tx_pre_check) = auth_transfer_preparation(balance_to_move); self.0 .send_privacy_preserving_tx_with_pre_check( vec![ @@ -55,7 +55,7 @@ impl NativeTokenTransfer<'_> { }, ], instruction_data, - &program.into(), + &auth_transfer_program_with_deps(), tx_pre_check, ) .await diff --git a/lez/wallet/src/program_facades/pinata.rs b/lez/wallet/src/program_facades/pinata.rs index 3a1ff8981..6c51a892c 100644 --- a/lez/wallet/src/program_facades/pinata.rs +++ b/lez/wallet/src/program_facades/pinata.rs @@ -1,5 +1,7 @@ use common::HashType; -use lee::{AccountId, program::Program}; +use lee::{ + AccountId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, +}; use lee_core::{MembershipProof, SharedSecretKey}; use crate::{AccountIdentity, ExecutionFailureKind, WalletCore}; @@ -60,7 +62,7 @@ impl Pinata<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], lee::program::Program::serialize_instruction(solution).unwrap(), - &programs::pinata().into(), + &pinata_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -72,3 +74,9 @@ impl Pinata<'_> { }) } } + +fn pinata_program_with_deps() -> ProgramWithDependencies { + ProgramWithDependencies::from(programs::pinata()).with_program_account_id( + program_loader_core::immutable_deploy_account_id(programs::pinata().id()), + ) +} diff --git a/lez/wallet/src/program_facades/token.rs b/lez/wallet/src/program_facades/token.rs index d634976ff..48c6a0558 100644 --- a/lez/wallet/src/program_facades/token.rs +++ b/lez/wallet/src/program_facades/token.rs @@ -1,5 +1,7 @@ use common::HashType; -use lee::{AccountId, program::Program}; +use lee::{ + AccountId, privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program, +}; use lee_core::{Identifier, NullifierPublicKey, SharedSecretKey, encryption::ViewingPublicKey}; use token_core::Instruction; @@ -48,7 +50,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -80,7 +82,7 @@ impl Token<'_> { AccountIdentity::Public(supply_account_id), ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -114,7 +116,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -169,7 +171,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -207,7 +209,7 @@ impl Token<'_> { }, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -239,7 +241,7 @@ impl Token<'_> { AccountIdentity::Public(recipient_account_id), ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -271,7 +273,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -307,7 +309,7 @@ impl Token<'_> { }, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -363,7 +365,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -395,7 +397,7 @@ impl Token<'_> { AccountIdentity::Public(holder_account_id), ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -428,7 +430,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -484,7 +486,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -522,7 +524,7 @@ impl Token<'_> { }, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -554,7 +556,7 @@ impl Token<'_> { AccountIdentity::Public(holder_account_id), ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -587,7 +589,7 @@ impl Token<'_> { .ok_or(ExecutionFailureKind::KeyNotFoundError)?, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -624,7 +626,7 @@ impl Token<'_> { }, ], instruction_data, - &programs::token().into(), + &token_program_with_deps(), ) .await .map(|(resp, secrets)| { @@ -636,3 +638,9 @@ impl Token<'_> { }) } } + +fn token_program_with_deps() -> ProgramWithDependencies { + ProgramWithDependencies::from(programs::token()).with_program_account_id( + program_loader_core::immutable_deploy_account_id(programs::token().id()), + ) +} diff --git a/lez/wallet/src/program_facades/vault.rs b/lez/wallet/src/program_facades/vault.rs index d809db60f..8aa075ba2 100644 --- a/lez/wallet/src/program_facades/vault.rs +++ b/lez/wallet/src/program_facades/vault.rs @@ -132,6 +132,11 @@ impl Vault<'_> { fn vault_with_auth_dependency() -> ProgramWithDependencies { let auth_transfer = programs::authenticated_transfer(); let mut deps = HashMap::new(); - deps.insert(auth_transfer.id().into(), auth_transfer); - ProgramWithDependencies::new(programs::vault(), deps) + deps.insert( + program_loader_core::immutable_deploy_account_id(auth_transfer.id()), + auth_transfer, + ); + ProgramWithDependencies::new(programs::vault(), deps).with_program_account_id( + program_loader_core::immutable_deploy_account_id(programs::vault().id()), + ) } diff --git a/test_programs/guest/src/bin/chain_caller.rs b/test_programs/guest/src/bin/chain_caller.rs index b4b932dc3..3267fd0a9 100644 --- a/test_programs/guest/src/bin/chain_caller.rs +++ b/test_programs/guest/src/bin/chain_caller.rs @@ -1,22 +1,25 @@ use authenticated_transfer_core::Instruction as AuthTransferInstruction; -use lee_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, + }, }; use risc0_zkvm::serde::to_vec; -type Instruction = (u128, ProgramId, u32, Option); +type Instruction = (u128, AccountId, u32, Option); /// A program that calls another program `num_chain_calls` times. /// It permutes the order of the input accounts on the subsequent call -/// The `ProgramId` in the instruction must be the `program_id` of the authenticated transfers -/// program. +/// The `AccountId` in the instruction must be the dispatch address of the authenticated +/// transfers program. fn main() { let ( ProgramInput { self_account_id, caller_account_id, pre_states, - instruction: (balance, auth_transfer_id, num_chain_calls, pda_seed), + instruction: (balance, auth_transfer_account_id, num_chain_calls, pda_seed), }, instruction_words, ) = read_lee_inputs::(); @@ -37,7 +40,7 @@ fn main() { let mut chained_calls = Vec::new(); for _i in 0..num_chain_calls { let new_chained_call = ChainedCall { - program_account_id: auth_transfer_id.into(), + program_account_id: auth_transfer_account_id, instruction_data: instruction_data.clone(), pre_states: vec![running_sender_pre.clone(), running_recipient_pre.clone()], /* <- Account order permutation here */ pda_seeds: pda_seed.iter().copied().collect(), diff --git a/test_programs/guest/src/bin/chained_call_forwarder.rs b/test_programs/guest/src/bin/chained_call_forwarder.rs index 10486badb..ae506f46c 100644 --- a/test_programs/guest/src/bin/chained_call_forwarder.rs +++ b/test_programs/guest/src/bin/chained_call_forwarder.rs @@ -1,15 +1,17 @@ -//! Forwards a single chained call to `target_program_id` with `instruction_data`, passing -//! through whatever `pre_states` this program itself was invoked with unchanged. +//! Forwards a single chained call to `target_program_id`'s dispatch address with +//! `instruction_data`, passing through whatever `pre_states` this program itself was invoked +//! with unchanged. //! //! Exists purely as test infrastructure: lets a test exercise "program X invokes program Y via //! a chained call" for an arbitrary Y and instruction, without needing a purpose-built guest for //! every target program under test. -use lee_core::program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs}, }; -type Instruction = (ProgramId, Vec); +type Instruction = (AccountId, Vec); fn main() { let ( @@ -28,7 +30,7 @@ fn main() { .collect(); let chained_call = ChainedCall { - program_account_id: target_program_id.into(), + program_account_id: target_program_id, instruction_data, pre_states: pre_states.clone(), pda_seeds: vec![], diff --git a/test_programs/guest/src/bin/clock_chain_caller.rs b/test_programs/guest/src/bin/clock_chain_caller.rs index 6bcdbcfb5..16026fd4f 100644 --- a/test_programs/guest/src/bin/clock_chain_caller.rs +++ b/test_programs/guest/src/bin/clock_chain_caller.rs @@ -1,12 +1,11 @@ use lee_core::{ Timestamp, - program::{ - AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, - }, + account::AccountId, + program::{AccountPostState, ChainedCall, ProgramInput, ProgramOutput, read_lee_inputs}, }; use risc0_zkvm::serde::to_vec; -type Instruction = (ProgramId, Timestamp); // (clock_program_id, timestamp) +type Instruction = (AccountId, Timestamp); // (clock_program_id, timestamp) /// A program that chain-calls the clock program with the clock accounts it received as pre-states. /// Used in tests to verify that user transactions cannot modify clock accounts, even indirectly @@ -28,7 +27,7 @@ fn main() { .collect(); let chained_call = ChainedCall { - program_account_id: clock_program_id.into(), + program_account_id: clock_program_id, instruction_data: to_vec(×tamp).unwrap(), pre_states: pre_states.clone(), pda_seeds: vec![], diff --git a/test_programs/guest/src/bin/faucet_chain_caller.rs b/test_programs/guest/src/bin/faucet_chain_caller.rs index f0f73cb65..f1aec6bdc 100644 --- a/test_programs/guest/src/bin/faucet_chain_caller.rs +++ b/test_programs/guest/src/bin/faucet_chain_caller.rs @@ -6,8 +6,8 @@ use lee_core::{ }; use risc0_zkvm::serde::to_vec; -type Instruction = (ProgramId, ProgramId, AccountId, u128); -// (faucet_program_id, vault_program_id, recipient_id, amount) +type Instruction = (ProgramId, AccountId, AccountId, AccountId, u128); +// (faucet_program_id, faucet_account_id, vault_account_id, recipient_id, amount) fn main() { let ( @@ -15,7 +15,8 @@ fn main() { self_account_id, caller_account_id, pre_states, - instruction: (faucet_program_id, vault_program_id, recipient_id, amount), + instruction: + (faucet_program_id, faucet_account_id, vault_account_id, recipient_id, amount), }, instruction_words, ) = read_lee_inputs::(); @@ -29,9 +30,10 @@ fn main() { let [faucet_pre, vault_pda_pre] = [pre_states[0].clone(), pre_states[1].clone()]; let chained_calls = vec![ChainedCall { - program_account_id: faucet_program_id.into(), + program_account_id: faucet_account_id, instruction_data: to_vec(&faucet_core::Instruction::GenesisTransferVault { - vault_program_id, + self_program_id: faucet_program_id, + vault_account_id, recipient_id, amount, }) diff --git a/test_programs/guest/src/bin/pda_spend_proxy.rs b/test_programs/guest/src/bin/pda_spend_proxy.rs index 7af8c86de..a0c1eb70e 100644 --- a/test_programs/guest/src/bin/pda_spend_proxy.rs +++ b/test_programs/guest/src/bin/pda_spend_proxy.rs @@ -1,5 +1,8 @@ -use lee_core::program::{ - AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, +use lee_core::{ + account::AccountId, + program::{ + AccountPostState, ChainedCall, PdaSeed, ProgramInput, ProgramOutput, read_lee_inputs, + }, }; use risc0_zkvm::serde::to_vec; @@ -7,7 +10,8 @@ use risc0_zkvm::serde::to_vec; /// /// `pre_states = [pda, recipient]`. Debits the PDA and credits the recipient. /// The PDA-to-npk binding is established via `pda_seeds` in the chained call to `auth_transfer`. -type Instruction = (PdaSeed, u128, ProgramId); +/// The `AccountId` in the instruction must be the dispatch address of `auth_transfer`. +type Instruction = (PdaSeed, u128, AccountId); fn main() { let ( @@ -31,7 +35,7 @@ fn main() { first_for_callee.is_authorized = true; let chained_call = ChainedCall { - program_account_id: auth_transfer_id.into(), + program_account_id: auth_transfer_id, instruction_data: to_vec(&authenticated_transfer_core::Instruction::Transfer { amount }) .unwrap(), pre_states: vec![first_for_callee, second.clone()], diff --git a/tools/cross_zone_chat/Cargo.toml b/tools/cross_zone_chat/Cargo.toml index a7c5de31a..27f89ba82 100644 --- a/tools/cross_zone_chat/Cargo.toml +++ b/tools/cross_zone_chat/Cargo.toml @@ -11,6 +11,7 @@ workspace = true test_fixtures.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } programs.workspace = true +program_loader_core.workspace = true ping_core.workspace = true cross_zone_outbox_core.workspace = true cross_zone_inbox_core.workspace = true diff --git a/tools/cross_zone_chat/src/main.rs b/tools/cross_zone_chat/src/main.rs index ddc0b0f5c..a789d9b80 100644 --- a/tools/cross_zone_chat/src/main.rs +++ b/tools/cross_zone_chat/src/main.rs @@ -370,7 +370,9 @@ fn watch_peer(peer: ZoneId, receiver_id: ProgramId) -> CrossZoneConfig { peers: vec![CrossZonePeer { channel_id: peer, allowed_routes: vec![CrossZoneRoute { - src_program_id: programs::ping_sender().id(), + src_account_id: program_loader_core::immutable_deploy_account_id( + programs::ping_sender().id(), + ), target_program_id: receiver_id, }], expected_block_signing_pubkeys: Vec::new(), @@ -412,7 +414,12 @@ async fn next_free_ordinal(client: &SequencerClient, target_zone: &ZoneId) -> Re for offset in 0..ORDINAL_PROBE_LIMIT { let ordinal = start.wrapping_add(offset); - let slot = outbox_pda(outbox_id, emitter, target_zone, ordinal); + let slot = outbox_pda( + outbox_id, + program_loader_core::immutable_deploy_account_id(emitter), + target_zone, + ordinal, + ); // Retried rather than propagated: by here the run has already paid for a // Bedrock bring-up and two sequencer boots, and every other RPC caller // in this tool rides out a transient error rather than ending the run. @@ -517,7 +524,7 @@ async fn poll_finality(state: Arc) { fn decode_inbox_text(instruction_data: &[u32]) -> Option { let instruction: Instruction = risc0_zkvm::serde::from_slice::(instruction_data).ok()?; - let Instruction::Dispatch(message) = instruction else { + let Instruction::Dispatch { message, .. } = instruction else { return None; }; decode_payload(&message.payload) @@ -544,7 +551,7 @@ fn decode_payload(payload: &[u8]) -> Option { .collect(); let instruction: ReceiverInstruction = risc0_zkvm::serde::from_slice::(&words).ok()?; - let ReceiverInstruction::Record { payload: bytes } = instruction else { + let ReceiverInstruction::Record { payload: bytes, .. } = instruction else { return None; }; Some(String::from_utf8_lossy(&bytes).into_owned()) @@ -557,12 +564,15 @@ fn build_send_tx(other_zone: ZoneId, ordinal: u32, text: &str) -> LeeTransaction let outbox_id = programs::cross_zone_outbox().id(); let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + self_program_id: receiver_id, payload: text.as_bytes().to_vec(), }) .expect("serialize record instruction"); let payload: Vec = words.iter().flat_map(|word| word.to_le_bytes()).collect(); + let sender_id = programs::ping_sender().id(); let send = SenderInstruction::Send { + self_program_id: sender_id, target_zone: other_zone, target_program_id: receiver_id, target_accounts: vec![ @@ -573,10 +583,14 @@ fn build_send_tx(other_zone: ZoneId, ordinal: u32, text: &str) -> LeeTransaction ordinal, }; - let sender_id = programs::ping_sender().id(); - let outbox_account = outbox_pda(outbox_id, sender_id, &other_zone, ordinal); + let outbox_account = outbox_pda( + outbox_id, + program_loader_core::immutable_deploy_account_id(sender_id), + &other_zone, + ordinal, + ); let message = Message::try_new( - sender_id.into(), + program_loader_core::immutable_deploy_account_id(sender_id), vec![sender_config_account_id(sender_id), outbox_account], vec![], send, diff --git a/tools/cycle_bench/src/main.rs b/tools/cycle_bench/src/main.rs index 4c965367f..1786e5aba 100644 --- a/tools/cycle_bench/src/main.rs +++ b/tools/cycle_bench/src/main.rs @@ -314,7 +314,7 @@ fn token_holding( ) -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0, data: Data::from(&TokenHolding::Fungible { definition_id, @@ -334,7 +334,7 @@ fn token_definition( ) -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: programs::token().id().into(), + program_owner: programs::token().deployed_account_id(), balance: 0, data: Data::from(&TokenDefinition::Fungible { name: String::from("test"), @@ -372,7 +372,7 @@ fn token_burn_pre_states() -> Vec { fn clock_account(account_id: AccountId, block_id: u64) -> AccountWithMetadata { AccountWithMetadata { account: Account { - program_owner: programs::clock().id().into(), + program_owner: programs::clock().deployed_account_id(), balance: 0, data: ClockAccountData { block_id, @@ -426,7 +426,7 @@ fn amm_pool_account() -> AccountWithMetadata { let lp_supply = (reserve_a * reserve_b).isqrt(); AccountWithMetadata { account: Account { - program_owner: programs::amm().id().into(), + program_owner: programs::amm().deployed_account_id(), balance: 0, data: Data::from(&PoolDefinition { definition_token_a_id: amm_token_a_def_id(), diff --git a/tools/cycle_bench/src/ppe/ppe_impl.rs b/tools/cycle_bench/src/ppe/ppe_impl.rs index ea39d7f79..623ad9723 100644 --- a/tools/cycle_bench/src/ppe/ppe_impl.rs +++ b/tools/cycle_bench/src/ppe/ppe_impl.rs @@ -43,15 +43,16 @@ pub fn run_auth_transfer_in_ppe() -> PpeBenchResult { pub fn prove_auth_transfer_in_ppe() -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> { let auth_transfer = programs::authenticated_transfer(); - let auth_transfer_id = auth_transfer.id(); - let pwd = ProgramWithDependencies::from(auth_transfer); + let auth_transfer_account_id = auth_transfer.deployed_account_id(); + let pwd = ProgramWithDependencies::from(auth_transfer) + .with_program_account_id(auth_transfer_account_id); // For PPE to allow the sender's balance to be decremented by this // program, the sender must already be claimed by auth_transfer. // Recipient stays default-owned so the first call can claim it. let sender = AccountWithMetadata { account: Account { - program_owner: auth_transfer_id.into(), + program_owner: auth_transfer_account_id, balance: 1_000_000, ..Account::default() }, @@ -107,9 +108,9 @@ fn prove_chain_caller( ) -> anyhow::Result<(PrivacyPreservingCircuitOutput, Proof)> { let chain_caller = test_programs::chain_caller(); let auth_transfer = programs::authenticated_transfer(); - let auth_transfer_id = auth_transfer.id(); + let auth_transfer_account_id = auth_transfer.deployed_account_id(); let mut deps = HashMap::new(); - deps.insert(auth_transfer.id().into(), auth_transfer); + deps.insert(auth_transfer_account_id, auth_transfer); let pwd = ProgramWithDependencies::new(chain_caller, deps); // Both accounts pre-claimed by auth_transfer. chain_caller doesn't @@ -117,7 +118,7 @@ fn prove_chain_caller( // would cause a state mismatch on subsequent chained calls. let recipient_pre = AccountWithMetadata { account: Account { - program_owner: auth_transfer_id.into(), + program_owner: auth_transfer_account_id, ..Account::default() }, is_authorized: true, @@ -125,7 +126,7 @@ fn prove_chain_caller( }; let sender_pre = AccountWithMetadata { account: Account { - program_owner: auth_transfer_id.into(), + program_owner: auth_transfer_account_id, balance: 1_000_000, ..Account::default() }, @@ -137,7 +138,7 @@ fn prove_chain_caller( let balance: u128 = 1; let pda_seed: Option = None; - let instruction = (balance, auth_transfer_id, num_chain_calls, pda_seed); + let instruction = (balance, auth_transfer_account_id, num_chain_calls, pda_seed); let instruction_data = to_vec(&instruction)?; let account_identities = vec![InputAccountIdentity::Public; pre_states.len()];