diff --git a/Cargo.lock b/Cargo.lock index fa57ee283..7f52235a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1271,6 +1271,7 @@ dependencies = [ name = "bridge_lock_program" version = "0.1.0" dependencies = [ + "borsh", "bridge_lock_core", "cross_zone_outbox_core", "lee_core", @@ -2104,6 +2105,7 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" name = "cross_zone" version = "0.1.0" dependencies = [ + "borsh", "bridge_lock_core", "common", "cross_zone_inbox_core", @@ -2124,6 +2126,7 @@ version = "0.1.0" dependencies = [ "anyhow", "axum 0.8.9", + "borsh", "common", "cross_zone_inbox_core", "cross_zone_outbox_core", @@ -3180,6 +3183,7 @@ dependencies = [ name = "example_program_deployment_programs" version = "0.1.0" dependencies = [ + "borsh", "bytemuck", "hex", "lee_core", @@ -4775,6 +4779,7 @@ dependencies = [ "anyhow", "async-trait", "authenticated_transfer_core", + "borsh", "bridge_core", "bridge_lock_core", "bytesize", @@ -9417,6 +9422,7 @@ dependencies = [ "associated_token_account_core", "associated_token_account_program", "authenticated_transfer_core", + "borsh", "bridge_core", "bridge_lock_core", "build_utils", @@ -12191,6 +12197,7 @@ dependencies = [ name = "test_methods_guests" version = "0.1.0" dependencies = [ + "borsh", "lee_core", "risc0-zkvm", "serde", @@ -12201,6 +12208,7 @@ name = "test_program_guests" version = "0.1.0" dependencies = [ "authenticated_transfer_core", + "borsh", "clock_core", "faucet_core", "lee_core", diff --git a/examples/program_deployment/methods/guest/Cargo.toml b/examples/program_deployment/methods/guest/Cargo.toml index e57718538..03d478d0b 100644 --- a/examples/program_deployment/methods/guest/Cargo.toml +++ b/examples/program_deployment/methods/guest/Cargo.toml @@ -8,6 +8,7 @@ license = { workspace = true } workspace = true [dependencies] +borsh.workspace = true lee_core.workspace = true hex.workspace = true diff --git a/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs b/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs index 8f7edcab8..627204f55 100644 --- a/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs +++ b/examples/program_deployment/methods/guest/src/bin/simple_tail_call.rs @@ -46,7 +46,7 @@ fn main() { // Create the chained call let chained_call_greeting: Vec = b"Hello from tail call".to_vec(); - let chained_call_instruction_data = risc0_zkvm::serde::to_vec(&chained_call_greeting).unwrap(); + let chained_call_instruction_data = borsh::to_vec(&chained_call_greeting).unwrap(); let chained_call = ChainedCall { program_id: hello_world_program_id(), instruction_data: chained_call_instruction_data, diff --git a/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs b/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs index c4b2cd11d..3bd602aaa 100644 --- a/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs +++ b/examples/program_deployment/methods/guest/src/bin/tail_call_with_pda.rs @@ -51,7 +51,7 @@ fn main() { // Create the chained call let chained_call_greeting: Vec = b"Hello from tail call with Program Derived Account ID".to_vec(); - let chained_call_instruction_data = risc0_zkvm::serde::to_vec(&chained_call_greeting).unwrap(); + let chained_call_instruction_data = borsh::to_vec(&chained_call_greeting).unwrap(); // Flip the `is_authorized` flag to true let pre_state_for_chained_call = { diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 56aab0f18..9c9df812d 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -9,6 +9,7 @@ workspace = true [dependencies] # LEZ and workspace crates. +borsh.workspace = true test_fixtures.workspace = true lee_core = { workspace = true, features = ["host"] } lee.workspace = true diff --git a/integration_tests/tests/cross_zone_bridge.rs b/integration_tests/tests/cross_zone_bridge.rs index 2279069bb..76fd531df 100644 --- a/integration_tests/tests/cross_zone_bridge.rs +++ b/integration_tests/tests/cross_zone_bridge.rs @@ -150,7 +150,7 @@ fn build_lock_tx( recipient: RECIPIENT, amount: LOCK_AMOUNT, }; - let words = risc0_zkvm::serde::to_vec(&mint).expect("serialize mint"); + let words = borsh::to_vec(&mint).expect("serialize mint"); let payload: Vec = words.iter().flat_map(|word| word.to_le_bytes()).collect(); let target_accounts = vec![ diff --git a/integration_tests/tests/cross_zone_ping.rs b/integration_tests/tests/cross_zone_ping.rs index d7eae3497..e61b2bd78 100644 --- a/integration_tests/tests/cross_zone_ping.rs +++ b/integration_tests/tests/cross_zone_ping.rs @@ -117,7 +117,7 @@ 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 { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: PING_PAYLOAD.to_vec(), }) .expect("serialize ping instruction"); diff --git a/integration_tests/tests/cross_zone_state_machine.rs b/integration_tests/tests/cross_zone_state_machine.rs index 30725c680..966e8bf6f 100644 --- a/integration_tests/tests/cross_zone_state_machine.rs +++ b/integration_tests/tests/cross_zone_state_machine.rs @@ -26,12 +26,10 @@ use ping_core::{ sender_config_account_id, }; -/// Serializes an instruction to the risc0 word form the guests read. A macro -/// because the serde trait a generic fn would have to name is not a dependency -/// of this crate. +/// Serializes an instruction to the borsh bytes the guests read. macro_rules! words_of { ($instruction:expr) => { - risc0_zkvm::serde::to_vec($instruction).expect("serialize instruction") + borsh::to_vec($instruction).expect("serialize instruction") }; } @@ -216,7 +214,7 @@ fn signed_tx( program: lee_core::program::ProgramId, accounts: Vec, nonce: u128, - words: Vec, + words: Vec, key: &PrivateKey, ) -> PublicTransaction { let message = Message::new_preserialized(program, accounts, vec![nonce.into()], words); @@ -232,7 +230,7 @@ fn via_proxy( config: AccountId, authority: AccountId, delegated: Option, - words: Vec, + words: Vec, ) -> PublicTransaction { let message = Message::try_new( proxy_id, @@ -250,7 +248,7 @@ fn chained_via_inbox( target: lee_core::program::ProgramId, config_id: AccountId, authority: AccountId, - words: Vec, + words: Vec, ) -> PublicTransaction { let inbox_id = programs::cross_zone_inbox().id(); let msg = CrossZoneMessage { @@ -260,7 +258,7 @@ fn chained_via_inbox( src_tx_index: 0, src_program_id: programs::bridge_lock().id(), target_program_id: target, - payload: words.into_iter().flat_map(u32::to_le_bytes).collect(), + payload: words, l1_inclusion_witness: None, }; let message = Message::try_new( @@ -277,7 +275,7 @@ fn chained_via_inbox( /// given rather than the correct ones, so tests can vary them. 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 { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: b"ping".to_vec(), }) .expect("serialize ping instruction"); @@ -307,7 +305,7 @@ fn mint_payload_of(amount: u128) -> Vec { recipient: RECIPIENT, amount, }; - let words = risc0_zkvm::serde::to_vec(&mint).expect("serialize mint"); + let words = borsh::to_vec(&mint).expect("serialize mint"); words.iter().flat_map(|word| word.to_le_bytes()).collect() } @@ -394,7 +392,7 @@ fn inbox_dispatch_delivers_payload_to_ping_receiver() { // The payload is the ping_receiver instruction, serialized as risc0 words in // little-endian bytes (the contract the inbox reverses when forwarding). let inner = b"hello-cross-zone".to_vec(); - let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: inner.clone(), }) .expect("serialize ping instruction"); @@ -1145,7 +1143,7 @@ fn the_token_authority_path_holds() { // Substituting another account for the config is refused rather than read, // on both instructions. - let substituted = |words: Vec| { + let substituted = |words: Vec| { signed_tx( wrapped_token_id, vec![ping_record_pda(wrapped_token_id), authority], @@ -1268,7 +1266,7 @@ fn a_delivery_from_an_unauthorized_source_does_not_reach_ping_receiver() { vec![(src_zone, programs::bridge_lock().id())], ); - let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: b"ping".to_vec(), }) .expect("serialize ping instruction"); @@ -1322,7 +1320,7 @@ fn the_inbox_refuses_a_marker_that_does_not_match_the_message() { seed_inbox_config(&mut state, self_zone); seed_receiver_config(&mut state, None, vec![(src_zone, sender_id)]); - let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: b"ping".to_vec(), }) .expect("serialize ping instruction"); @@ -2292,7 +2290,7 @@ fn a_delivery_from_a_second_block_at_the_same_id_is_refused() { }, )]); - let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: b"from-the-other-block".to_vec(), }) .expect("serialize ping instruction"); @@ -2332,7 +2330,7 @@ fn a_delivery_from_a_second_block_at_the_same_id_is_refused() { // Control: the same delivery naming the bound block executes, so the refusal // above is the binding and not the transaction's shape. - let control_words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let control_words = borsh::to_vec(&ReceiverInstruction::Record { payload: b"from-the-bound-block".to_vec(), }) .expect("serialize ping instruction"); diff --git a/integration_tests/tests/cross_zone_verified.rs b/integration_tests/tests/cross_zone_verified.rs index a19ce29c8..d3b62daab 100644 --- a/integration_tests/tests/cross_zone_verified.rs +++ b/integration_tests/tests/cross_zone_verified.rs @@ -110,7 +110,7 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio let outbox_id = programs::cross_zone_outbox().id(); let ordinal = 0; - let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: PING_PAYLOAD.to_vec(), }) .expect("serialize ping instruction"); diff --git a/integration_tests/tests/cross_zone_watcher_restart.rs b/integration_tests/tests/cross_zone_watcher_restart.rs index f60f7a588..feb8bf891 100644 --- a/integration_tests/tests/cross_zone_watcher_restart.rs +++ b/integration_tests/tests/cross_zone_watcher_restart.rs @@ -188,7 +188,7 @@ fn build_ping_tx(target_zone: [u8; 32], receiver_id: ProgramId) -> LeeTransactio let outbox_id = programs::cross_zone_outbox().id(); let ordinal = 0; - let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: PING_PAYLOAD.to_vec(), }) .expect("serialize ping instruction"); diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index f2bb19f47..958bd2180 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -235,7 +235,7 @@ unsafe extern "C" { handle: *mut WalletHandle, account_identities: *const FfiAccountIdentity, account_identities_size: usize, - instruction_words: *const u32, + instruction_words: *const u8, instruction_words_size: usize, program_id: FfiProgramId, out_result: *mut FfiTransactionResult, @@ -251,7 +251,7 @@ unsafe extern "C" { handle: *mut WalletHandle, account_identities: *const FfiAccountIdentity, account_identities_size: usize, - instruction_words: *const u32, + instruction_words: *const u8, instruction_words_size: usize, program_with_dependencies: *const FfiProgramWithDependencies, out_result: *mut FfiTransactionResult, @@ -1635,7 +1635,7 @@ fn test_wallet_ffi_transfer_generic_public() -> Result<()> { }) .unwrap(); let instruction_words_size = instruction_data.len(); - let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32; + let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u8; let program_id = programs::authenticated_transfer().id(); @@ -1731,7 +1731,7 @@ fn test_wallet_ffi_transfer_generic_private() -> Result<()> { }) .unwrap(); let instruction_words_size = instruction_data.len(); - let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u32; + let instruction_words = Box::into_raw(instruction_data.into_boxed_slice()) as *const u8; let program: ProgramWithDependencies = programs::authenticated_transfer().into(); let program_with_dependencies: FfiProgramWithDependencies = program.into(); diff --git a/lee/state_machine/core/src/program/mod.rs b/lee/state_machine/core/src/program/mod.rs index ccb2f3332..1ec0d7a04 100644 --- a/lee/state_machine/core/src/program/mod.rs +++ b/lee/state_machine/core/src/program/mod.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use borsh::{BorshDeserialize, BorshSerialize}; -use risc0_zkvm::{DeserializeOwned, guest::env, serde::Deserializer}; +use risc0_zkvm::guest::env; use serde::{Deserialize, Serialize}; use crate::{ @@ -52,7 +52,7 @@ impl From for ProgramId { } } -pub type InstructionData = Vec; +pub type InstructionData = Vec; pub struct ProgramInput { pub self_program_id: ProgramId, pub caller_program_id: Option, @@ -270,7 +270,7 @@ pub struct ChainedCall { impl ChainedCall { /// Creates a new chained call serializing the given instruction. - pub fn new( + pub fn new( program_id: ProgramId, pre_states: Vec, instruction: &I, @@ -278,8 +278,8 @@ impl ChainedCall { Self { program_id, pre_states, - instruction_data: risc0_zkvm::serde::to_vec(instruction) - .expect("Serialization to Vec should not fail"), + instruction_data: borsh::to_vec(instruction) + .expect("borsh serialization is infallible"), pda_seeds: Vec::new(), } } @@ -716,14 +716,15 @@ pub fn read_input_frame() -> Vec { /// Reads the LEE inputs from the guest environment. #[must_use] -pub fn read_lee_inputs() -> (ProgramInput, InstructionData) { +pub fn read_lee_inputs() -> (ProgramInput, InstructionData) { let LeeInputHeader { self_program_id, caller_program_id, pre_states, instruction_data, } = borsh::from_slice(&read_input_frame()).expect("guest input must be a valid borsh header"); - let instruction = T::deserialize(&mut Deserializer::new(instruction_data.as_ref())).unwrap(); + let instruction = + borsh::from_slice(&instruction_data).expect("instruction must decode from borsh"); ( ProgramInput { self_program_id, diff --git a/lee/state_machine/src/program/mod.rs b/lee/state_machine/src/program/mod.rs index f464b8184..c827fc448 100644 --- a/lee/state_machine/src/program/mod.rs +++ b/lee/state_machine/src/program/mod.rs @@ -7,8 +7,7 @@ use lee_core::{ program::{InstructionData, LeeInputHeader, ProgramId, ProgramOutput}, to_frame, }; -use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; -use serde::Serialize; +use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor}; use crate::error::LeeError; @@ -48,10 +47,11 @@ impl Program { &self.elf } - pub fn serialize_instruction( + pub fn serialize_instruction( instruction: T, ) -> Result { - to_vec(&instruction).map_err(|e| LeeError::InstructionSerializationError(e.to_string())) + borsh::to_vec(&instruction) + .map_err(|e| LeeError::InstructionSerializationError(e.to_string())) } pub(crate) fn execute( @@ -90,7 +90,7 @@ impl Program { program_id: ProgramId, caller_program_id: Option, pre_states: &[AccountWithMetadata], - instruction_data: &[u32], + instruction_data: &[u8], env_builder: &mut ExecutorEnvBuilder, ) -> Result<(), LeeError> { let header = LeeInputHeader { diff --git a/lee/state_machine/src/public_transaction/message.rs b/lee/state_machine/src/public_transaction/message.rs index feafc5391..3eec42055 100644 --- a/lee/state_machine/src/public_transaction/message.rs +++ b/lee/state_machine/src/public_transaction/message.rs @@ -3,7 +3,6 @@ use lee_core::{ account::Nonce, program::{InstructionData, ProgramId}, }; -use serde::Serialize; use sha2::{Digest as _, Sha256}; use crate::{AccountId, error::LeeError, program::Program}; @@ -36,7 +35,7 @@ impl std::fmt::Debug for Message { } impl Message { - pub fn try_new( + pub fn try_new( program_id: ProgramId, account_ids: Vec, nonces: Vec, diff --git a/lee/state_machine/src/state/tests/mod.rs b/lee/state_machine/src/state/tests/mod.rs index 1f657c14b..1b1738114 100644 --- a/lee/state_machine/src/state/tests/mod.rs +++ b/lee/state_machine/src/state/tests/mod.rs @@ -159,20 +159,20 @@ impl TestPrivateKeys { // ── Flash Swap types (mirrors of guest types for host-side serialisation) ── -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, borsh::BorshSerialize, borsh::BorshDeserialize)] struct CallbackInstruction { return_funds: bool, token_program_id: ProgramId, amount: u128, } -#[derive(serde::Serialize, serde::Deserialize)] +#[derive(serde::Serialize, serde::Deserialize, borsh::BorshSerialize, borsh::BorshDeserialize)] enum FlashSwapInstruction { Initiate { token_program_id: ProgramId, callback_program_id: ProgramId, amount_out: u128, - callback_instruction_data: Vec, + callback_instruction_data: Vec, }, InvariantCheck { min_vault_balance: u128, diff --git a/lee/state_machine/test_methods/guest/Cargo.toml b/lee/state_machine/test_methods/guest/Cargo.toml index 75d34081a..df5306ede 100644 --- a/lee/state_machine/test_methods/guest/Cargo.toml +++ b/lee/state_machine/test_methods/guest/Cargo.toml @@ -8,6 +8,7 @@ license = { workspace = true } workspace = true [dependencies] +borsh.workspace = true lee_core.workspace = true risc0-zkvm.workspace = true diff --git a/lee/state_machine/test_methods/guest/src/bin/chain_caller.rs b/lee/state_machine/test_methods/guest/src/bin/chain_caller.rs index b812fc9e7..ee196f3fa 100644 --- a/lee/state_machine/test_methods/guest/src/bin/chain_caller.rs +++ b/lee/state_machine/test_methods/guest/src/bin/chain_caller.rs @@ -1,7 +1,7 @@ use lee_core::program::{ AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; type Instruction = (u128, ProgramId, u32, Option); 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 28f6509f1..83da2ca03 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 @@ -29,7 +29,7 @@ use lee_core::program::{ }; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, borsh::BorshSerialize, borsh::BorshDeserialize)] 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). @@ -62,7 +62,7 @@ fn main() { // Mark the receiver as authorized since it will be PDA-authorized in this chained call. let mut receiver_authorized = receiver_pre.clone(); receiver_authorized.is_authorized = true; - let transfer_instruction = risc0_zkvm::serde::to_vec(&instruction.amount) + let transfer_instruction = borsh::to_vec(&instruction.amount) .expect("transfer instruction serialization"); chained_calls.push(ChainedCall { 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 699d7c579..705c62eaf 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 @@ -42,7 +42,7 @@ use lee_core::program::{ }; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, borsh::BorshSerialize, borsh::BorshDeserialize)] pub enum FlashSwapInstruction { /// External entrypoint: initiate a flash swap. /// @@ -57,7 +57,7 @@ pub enum FlashSwapInstruction { token_program_id: ProgramId, callback_program_id: ProgramId, amount_out: u128, - callback_instruction_data: Vec, + callback_instruction_data: Vec, }, /// Internal: verify the vault invariant holds after callback execution. /// @@ -122,7 +122,7 @@ fn main() { let mut vault_authorized = vault_pre.clone(); vault_authorized.is_authorized = true; let transfer_instruction = - risc0_zkvm::serde::to_vec(&amount_out).expect("transfer instruction serialization"); + borsh::to_vec(&amount_out).expect("transfer instruction serialization"); let call_1 = ChainedCall { program_id: token_program_id, pre_states: vec![vault_authorized, receiver_pre.clone()], @@ -147,7 +147,7 @@ fn main() { // min_vault_balance and this call will panic, rolling back the entire // transaction. let invariant_instruction = - risc0_zkvm::serde::to_vec(&FlashSwapInstruction::InvariantCheck { + borsh::to_vec(&FlashSwapInstruction::InvariantCheck { min_vault_balance, }) .expect("invariant instruction serialization"); 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 80bd8aaa7..3f1851e6f 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 @@ -4,7 +4,7 @@ use lee_core::{ AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; type Instruction = (u128, ProgramId); 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 c5b367fc9..92f1da53c 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 @@ -85,7 +85,7 @@ fn main() { }; // Forward auth_transfer_id and amount to P2 so it can call authenticated_transfer. - let p2_instruction = risc0_zkvm::serde::to_vec(&(auth_transfer_id, amount)) + let p2_instruction = borsh::to_vec(&(auth_transfer_id, amount)) .expect("serialization is infallible"); ProgramOutput::new( 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 5ec7989d2..b063e3dbd 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 @@ -23,7 +23,7 @@ fn main() { // victim(is_authorized=true). So authorized_accounts = {victim}, and the // subsequent check passes. let auth_transfer_instruction = - risc0_zkvm::serde::to_vec(&amount).expect("serialization is infallible"); + borsh::to_vec(&amount).expect("serialization is infallible"); ProgramOutput::new( self_program_id, 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 86ef73b4a..e290b968e 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,7 +1,7 @@ use lee_core::program::{ AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; /// Proxy for spending from a private PDA via `simple_transfer`. /// 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 3b891e9af..2bbec21c3 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 @@ -2,7 +2,7 @@ use lee_core::program::{ AccountPostState, ChainedCall, Claim, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; /// Claims the sole `pre_state` as a PDA with `claim_seed`, then chains to `callee_program_id` /// delegating authorization with `delegated_seed` in `pda_seeds`. When `claim_seed == diff --git a/lee/state_machine/test_methods/guest/src/bin/selective_pda_delegator.rs b/lee/state_machine/test_methods/guest/src/bin/selective_pda_delegator.rs index e06f76974..6602f5b02 100644 --- a/lee/state_machine/test_methods/guest/src/bin/selective_pda_delegator.rs +++ b/lee/state_machine/test_methods/guest/src/bin/selective_pda_delegator.rs @@ -2,7 +2,7 @@ use lee_core::program::{ AccountPostState, ChainedCall, Claim, InstructionData, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; type Instruction = ( PdaSeed, diff --git a/lee/state_machine/test_methods/guest/src/bin/undeclaring_pda_delegator.rs b/lee/state_machine/test_methods/guest/src/bin/undeclaring_pda_delegator.rs index 2589ccdc9..6653bee9d 100644 --- a/lee/state_machine/test_methods/guest/src/bin/undeclaring_pda_delegator.rs +++ b/lee/state_machine/test_methods/guest/src/bin/undeclaring_pda_delegator.rs @@ -1,7 +1,7 @@ use lee_core::program::{ ChainedCall, InstructionData, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; type Instruction = ( Option, 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 91b2deada..bd02d8802 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 @@ -2,7 +2,7 @@ use lee_core::program::{ AccountPostState, BlockValidityWindow, ChainedCall, ProgramId, ProgramInput, ProgramOutput, TimestampValidityWindow, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; /// A program that sets a block validity window on its output and chains to another program with a /// potentially different block validity window. diff --git a/lez/cross_zone/Cargo.toml b/lez/cross_zone/Cargo.toml index be80ce13e..0f563a32b 100644 --- a/lez/cross_zone/Cargo.toml +++ b/lez/cross_zone/Cargo.toml @@ -12,6 +12,7 @@ workspace = true test-utils = [] [dependencies] +borsh.workspace = true lee.workspace = true lee_core.workspace = true programs.workspace = true diff --git a/lez/cross_zone/src/lib.rs b/lez/cross_zone/src/lib.rs index 681b2a6aa..1d5b9edfb 100644 --- a/lez/cross_zone/src/lib.rs +++ b/lez/cross_zone/src/lib.rs @@ -23,7 +23,6 @@ use lee_core::{ account::{Account, AccountId, Balance}, program::ProgramId, }; -use serde::Serialize; pub mod acceptance; #[cfg(any(test, feature = "test-utils"))] @@ -69,7 +68,7 @@ pub fn is_sequencer_only_program(program_id: ProgramId) -> bool { /// 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 { +pub fn extract_emission(program_id: ProgramId, instruction_data: &[u8]) -> Option { if program_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. @@ -79,7 +78,7 @@ pub fn extract_emission(program_id: ProgramId, instruction_data: &[u32]) -> Opti target_accounts, payload, .. - }) = risc0_zkvm::serde::from_slice(instruction_data) + }) = borsh::from_slice(instruction_data) else { return None; }; @@ -96,7 +95,7 @@ pub fn extract_emission(program_id: ProgramId, instruction_data: &[u32]) -> Opti target_accounts, payload, .. - }) = risc0_zkvm::serde::from_slice(instruction_data) + }) = borsh::from_slice(instruction_data) else { return None; }; @@ -330,7 +329,7 @@ pub fn build_ping_receiver_init_config_tx( /// Builds an unsigned, sequencer-origin genesis transaction invoking `instruction` /// on `program_id` over `account_ids`. -fn genesis_public_tx( +fn genesis_public_tx( program_id: ProgramId, account_ids: Vec, instruction: I, diff --git a/lez/indexer/core/src/cross_zone_verifier.rs b/lez/indexer/core/src/cross_zone_verifier.rs index f22f45713..eab002893 100644 --- a/lez/indexer/core/src/cross_zone_verifier.rs +++ b/lez/indexer/core/src/cross_zone_verifier.rs @@ -802,7 +802,7 @@ impl CrossZoneVerifier { if public_tx.message().program_id != programs::cross_zone_inbox().id() { return None; } - match risc0_zkvm::serde::from_slice::( + match borsh::from_slice::( &public_tx.message().instruction_data, ) { Ok(InboxInstruction::Dispatch(msg)) => Some(msg), diff --git a/lez/indexer/ffi/indexer_ffi.h b/lez/indexer/ffi/indexer_ffi.h index 561c5e5f2..6352223b2 100644 --- a/lez/indexer/ffi/indexer_ffi.h +++ b/lez/indexer/ffi/indexer_ffi.h @@ -159,13 +159,13 @@ typedef struct FfiVec_FfiNonce { typedef struct FfiVec_FfiNonce FfiNonceList; -typedef struct FfiVec_u32 { - uint32_t *entries; +typedef struct FfiVec_u8 { + uint8_t *entries; uintptr_t len; uintptr_t capacity; -} FfiVec_u32; +} FfiVec_u8; -typedef struct FfiVec_u32 FfiInstructionDataList; +typedef struct FfiVec_u8 FfiInstructionDataList; typedef struct FfiPublicMessage { struct FfiProgramId program_id; @@ -238,12 +238,6 @@ typedef struct FfiVec_FfiPublicAction { typedef struct FfiVec_FfiPublicAction FfiPublicActionList; -typedef struct FfiVec_u8 { - uint8_t *entries; - uintptr_t len; - uintptr_t capacity; -} FfiVec_u8; - typedef struct FfiVec_u8 FfiVecU8; typedef struct FfiEncryptedAccountData { diff --git a/lez/indexer/ffi/src/api/types/vectors.rs b/lez/indexer/ffi/src/api/types/vectors.rs index 4cccb949f..625a811b7 100644 --- a/lez/indexer/ffi/src/api/types/vectors.rs +++ b/lez/indexer/ffi/src/api/types/vectors.rs @@ -11,7 +11,7 @@ pub type FfiBlockBody = FfiVec; pub type FfiNonceList = FfiVec; -pub type FfiInstructionDataList = FfiVec; +pub type FfiInstructionDataList = FfiVec; pub type FfiSignaturePubKeyList = FfiVec; diff --git a/lez/indexer/service/protocol/src/lib.rs b/lez/indexer/service/protocol/src/lib.rs index 6f5df0461..6e33baa80 100644 --- a/lez/indexer/service/protocol/src/lib.rs +++ b/lez/indexer/service/protocol/src/lib.rs @@ -224,7 +224,7 @@ pub struct PublicMessage { pub instruction_data: InstructionData, } -pub type InstructionData = Vec; +pub type InstructionData = Vec; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] pub struct PublicActionWithID { diff --git a/lez/programs/Cargo.toml b/lez/programs/Cargo.toml index 609e7d7ff..ec611753b 100644 --- a/lez/programs/Cargo.toml +++ b/lez/programs/Cargo.toml @@ -123,6 +123,7 @@ programs = [ ] [dependencies] +borsh.workspace = true lee = { workspace = true, optional = true } lee_core = { workspace = true, optional = true } risc0-zkvm = { workspace = true, optional = true } diff --git a/lez/programs/bridge_lock/Cargo.toml b/lez/programs/bridge_lock/Cargo.toml index 8a4d6c20b..393cc2e77 100644 --- a/lez/programs/bridge_lock/Cargo.toml +++ b/lez/programs/bridge_lock/Cargo.toml @@ -8,6 +8,7 @@ license = { workspace = true } workspace = true [dependencies] +borsh.workspace = true lee_core.workspace = true bridge_lock_core.workspace = true cross_zone_outbox_core.workspace = true diff --git a/lez/programs/bridge_lock/core/src/lib.rs b/lez/programs/bridge_lock/core/src/lib.rs index fb15ae1b6..d3e49592c 100644 --- a/lez/programs/bridge_lock/core/src/lib.rs +++ b/lez/programs/bridge_lock/core/src/lib.rs @@ -134,7 +134,7 @@ mod tests { payload: vec![], ordinal: 0, }; - let words = risc0_zkvm::serde::to_vec(&lock).expect("Lock serializes"); + let words = borsh::to_vec(&lock).expect("Lock serializes"); assert_eq!(words[0], 0); } } diff --git a/lez/programs/bridge_lock/src/main.rs b/lez/programs/bridge_lock/src/main.rs index 5e0e9e24c..e3b04ddc1 100644 --- a/lez/programs/bridge_lock/src/main.rs +++ b/lez/programs/bridge_lock/src/main.rs @@ -70,7 +70,7 @@ fn lock( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, amount: u128, target_zone: [u8; 32], target_program_id: ProgramId, @@ -200,7 +200,7 @@ fn init_config( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, outbox_program_id: ProgramId, target_program_id: ProgramId, ) { @@ -247,16 +247,7 @@ fn init_config( .write(); } -/// Decodes the cross-zone payload (risc0 words, little-endian bytes) into the -/// wrapped-token instruction it carries. +/// Decodes the cross-zone payload (borsh bytes) into the wrapped-token instruction it carries. fn decode_mint(payload: &[u8]) -> WrappedInstruction { - assert!( - payload.len().is_multiple_of(4), - "payload must be u32-aligned instruction words" - ); - let words: Vec = payload - .chunks_exact(4) - .map(|chunk| u32::from_le_bytes(chunk.try_into().unwrap_or_else(|_| unreachable!()))) - .collect(); - risc0_zkvm::serde::from_slice(&words).expect("payload decodes to a wrapped-token instruction") + borsh::from_slice(payload).expect("payload decodes to a wrapped-token instruction") } diff --git a/lez/programs/cross_zone_inbox/src/main.rs b/lez/programs/cross_zone_inbox/src/main.rs index 638ad75f3..5143cd808 100644 --- a/lez/programs/cross_zone_inbox/src/main.rs +++ b/lez/programs/cross_zone_inbox/src/main.rs @@ -68,7 +68,7 @@ fn dispatch( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, msg: &CrossZoneMessage, ) { assert!( @@ -139,16 +139,8 @@ fn dispatch( Claim::Pda(inbox_seen_shard_seed(&msg.src_zone, msg.src_block_id)), ); - // The payload carries the target instruction as risc0 words, little-endian. - assert!( - msg.payload.len().is_multiple_of(4), - "payload must be u32-aligned instruction words" - ); - let instruction_data = msg - .payload - .chunks_exact(4) - .map(|c| u32::from_le_bytes(c.try_into().unwrap_or_else(|_| unreachable!()))) - .collect(); + // The payload carries the target instruction as borsh bytes: its instruction_data verbatim. + let instruction_data = msg.payload.clone(); // The marker leads, so a target reads its source at a fixed position // without knowing anything about the accounts that follow it. @@ -185,7 +177,7 @@ fn init_config( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, config: &InboxConfig, ) { // pre_states: [config PDA]. diff --git a/lez/programs/ping_core/src/lib.rs b/lez/programs/ping_core/src/lib.rs index 74b72bd4f..bf48023b1 100644 --- a/lez/programs/ping_core/src/lib.rs +++ b/lez/programs/ping_core/src/lib.rs @@ -176,7 +176,7 @@ mod tests { payload: vec![], ordinal: 0, }; - let words = risc0_zkvm::serde::to_vec(&send).expect("Send serializes"); + let words = borsh::to_vec(&send).expect("Send serializes"); assert_eq!(words[0], 0); } @@ -185,7 +185,7 @@ mod tests { #[test] fn record_is_the_first_variant() { let record = ReceiverInstruction::Record { payload: vec![] }; - let words = risc0_zkvm::serde::to_vec(&record).expect("Record serializes"); + let words = borsh::to_vec(&record).expect("Record serializes"); assert_eq!(words[0], 0); } diff --git a/lez/programs/ping_receiver/src/main.rs b/lez/programs/ping_receiver/src/main.rs index b9e90b6c4..ef5108270 100644 --- a/lez/programs/ping_receiver/src/main.rs +++ b/lez/programs/ping_receiver/src/main.rs @@ -57,7 +57,7 @@ fn record( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, payload: Vec, ) { // pre_states: [source marker, config PDA, record PDA]. @@ -116,7 +116,7 @@ fn renounce_authority( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, ) { // The config is read before the account list is validated, so who may call // is decided first; an inbox-delivered call fails here on its prepended marker. @@ -187,7 +187,7 @@ fn update_sources( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, sources: Vec<([u8; 32], ProgramId)>, ) { // The config is read before the account list is validated, so who may call @@ -259,7 +259,7 @@ fn init_config( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, config_value: &ReceiverConfig, ) { assert!( diff --git a/lez/programs/ping_sender/src/main.rs b/lez/programs/ping_sender/src/main.rs index d2b1baedb..269361e2e 100644 --- a/lez/programs/ping_sender/src/main.rs +++ b/lez/programs/ping_sender/src/main.rs @@ -62,7 +62,7 @@ fn send( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, target_zone: [u8; 32], target_program_id: ProgramId, target_accounts: Vec<[u8; 32]>, @@ -114,7 +114,7 @@ fn init_config( self_program_id: ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, outbox_program_id: ProgramId, ) { // pre_states: [config PDA]. diff --git a/lez/programs/wrapped_token/core/src/lib.rs b/lez/programs/wrapped_token/core/src/lib.rs index 85b30c292..d01459293 100644 --- a/lez/programs/wrapped_token/core/src/lib.rs +++ b/lez/programs/wrapped_token/core/src/lib.rs @@ -177,7 +177,7 @@ mod tests { recipient: [3; 32], amount: 1, }; - let words = risc0_zkvm::serde::to_vec(&mint).expect("Mint serializes"); + let words = borsh::to_vec(&mint).expect("Mint serializes"); assert_eq!(words[0], 0); } diff --git a/lez/programs/wrapped_token/src/main.rs b/lez/programs/wrapped_token/src/main.rs index 311ef2614..d06d3e3d2 100644 --- a/lez/programs/wrapped_token/src/main.rs +++ b/lez/programs/wrapped_token/src/main.rs @@ -58,7 +58,7 @@ fn mint( self_program_id: lee_core::program::ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, recipient: [u8; 32], amount: u128, ) { @@ -136,7 +136,7 @@ fn renounce_authority( self_program_id: lee_core::program::ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, ) { // The config is read before the account list is validated, so who may call // is decided first; an inbox-delivered call fails here on its prepended marker. @@ -207,7 +207,7 @@ fn update_sources( self_program_id: lee_core::program::ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, sources: Vec<([u8; 32], lee_core::program::ProgramId)>, ) { // The config is read before the account list is validated, so who may call @@ -279,7 +279,7 @@ fn init_config( self_program_id: lee_core::program::ProgramId, caller_program_id: Option, pre_states: Vec, - instruction_words: Vec, + instruction_words: Vec, config_value: &WrappedTokenConfig, ) { assert!( diff --git a/lez/sequencer/core/src/cross_zone_watcher.rs b/lez/sequencer/core/src/cross_zone_watcher.rs index c03cbf789..bb6834997 100644 --- a/lez/sequencer/core/src/cross_zone_watcher.rs +++ b/lez/sequencer/core/src/cross_zone_watcher.rs @@ -1058,7 +1058,7 @@ mod tests { panic!("a dispatch is a public transaction"); }; let Ok(cross_zone_inbox_core::Instruction::Dispatch(msg)) = - risc0_zkvm::serde::from_slice(&public_tx.message().instruction_data) + borsh::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 7b7b7db85..fb8291650 100644 --- a/lez/sequencer/core/src/lib.rs +++ b/lez/sequencer/core/src/lib.rs @@ -2194,7 +2194,7 @@ fn finalize_unstake_ownership_account(tx: &LeeTransaction) -> Option return None; } - match risc0_zkvm::serde::from_slice::( + match borsh::from_slice::( &message.instruction_data, ) { Ok(sequencer_stake_core::Instruction::FinalizeUnstake) => { @@ -2275,7 +2275,7 @@ fn extract_cross_zone_dispatch(tx: &LeeTransaction) -> Option return None; } - match risc0_zkvm::serde::from_slice::( + match borsh::from_slice::( &message.instruction_data, ) { Ok(cross_zone_inbox_core::Instruction::Dispatch(msg)) => Some(msg), @@ -2384,7 +2384,7 @@ fn extract_bridge_deposit_id(tx: &LeeTransaction) -> Option { } let instruction = - risc0_zkvm::serde::from_slice::(&message.instruction_data) + borsh::from_slice::(&message.instruction_data) .ok()?; match instruction { @@ -2407,7 +2407,7 @@ fn extract_bridge_withdraw_data(tx: &LeeTransaction) -> Option { } let instruction = - risc0_zkvm::serde::from_slice::(&message.instruction_data) + borsh::from_slice::(&message.instruction_data) .ok()?; let bridge_core::Instruction::Withdraw { diff --git a/lez/sequencer/core/src/tests.rs b/lez/sequencer/core/src/tests.rs index fcd9fd428..5c20e441c 100644 --- a/lez/sequencer/core/src/tests.rs +++ b/lez/sequencer/core/src/tests.rs @@ -224,7 +224,7 @@ fn tx_is_bridge_deposit( } let instruction: bridge_core::Instruction = - match risc0_zkvm::serde::from_slice(&public_tx.message.instruction_data) { + match borsh::from_slice(&public_tx.message.instruction_data) { Ok(instruction) => instruction, Err(_err) => return false, }; @@ -263,7 +263,7 @@ fn cross_zone_test_config() -> SequencerConfig { /// A `ping_receiver::Record` instruction as risc0 words, little-endian: the wire /// 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 { + borsh::to_vec(&ReceiverInstruction::Record { payload: payload.to_vec(), }) .expect("ping instruction serializes") diff --git a/lez/wallet-ffi/src/generic_transaction.rs b/lez/wallet-ffi/src/generic_transaction.rs index 6420e5e81..486518015 100644 --- a/lez/wallet-ffi/src/generic_transaction.rs +++ b/lez/wallet-ffi/src/generic_transaction.rs @@ -14,23 +14,6 @@ use crate::{ FfiAccountIdentity, FfiBytes32, FfiProgramId, WalletHandle, }; -#[repr(C)] -pub struct FfiInstructionWords { - pub instruction_words: *mut u32, - pub instruction_words_size: usize, - pub error: WalletFfiError, -} - -impl FfiInstructionWords { - const fn from_err(error: WalletFfiError) -> Self { - Self { - instruction_words: std::ptr::null_mut(), - instruction_words_size: 0, - error, - } - } -} - #[repr(C)] /// Intended to be created manually. pub struct FfiProgram { @@ -143,60 +126,12 @@ impl Default for FfiTransactionResult { } } -/// Serialize sequence of bytes into RISC0 readable words. -/// -/// # Parameters -/// - `input_instruction_data`: Valid pointer to a sequence of bytes -/// - `input_instruction_data_size`: Size of `input_instruction_data` -/// -/// # Returns -/// - `Success` on successful creation -/// - Error code on failure -/// -/// # Safety -/// - `input_instruction_data` must be a valid pointer -#[no_mangle] -pub unsafe extern "C" fn wallet_ffi_serialization_helper( - input_instruction_data: *const u8, - input_instruction_data_size: usize, -) -> FfiInstructionWords { - if input_instruction_data.is_null() { - print_error("Null input pointer for instruction_data"); - return FfiInstructionWords::from_err(WalletFfiError::NullPointer); - } - - let input_slice = - unsafe { std::slice::from_raw_parts(input_instruction_data, input_instruction_data_size) }; - let res_vec_u32_with_prefix = match risc0_zkvm::serde::to_vec(input_slice).map_err(|err| { - print_error(format!( - "Failed to serialize input into words with err {err}" - )); - WalletFfiError::SerializationError - }) { - Ok(res) => res, - Err(err) => return FfiInstructionWords::from_err(err), - }; - - // The resulting vec contains len as prefix - let res_vec_u32 = res_vec_u32_with_prefix[1..].to_vec(); - - let res_len = res_vec_u32.len(); - let res_boxed = res_vec_u32.into_boxed_slice(); - let res_ptr = Box::into_raw(res_boxed).cast::(); - - FfiInstructionWords { - instruction_words: res_ptr, - instruction_words_size: res_len, - error: WalletFfiError::Success, - } -} - /// Send generic public transaction. /// /// # Parameters /// - `handle`: Valid pointer to wallet handle /// - `account_identities`: Valid pointer to list of `FfiAccountIdentity` -/// - `instruction_words`: Valid pointer to instruction words +/// - `instruction_data`: Valid pointer to instruction words /// - `out_result`: Valid pointer to `FfiTransactionResult` /// /// # Returns @@ -206,15 +141,15 @@ pub unsafe extern "C" fn wallet_ffi_serialization_helper( /// # Safety /// - `handle` must be a valid pointer /// - `account_identities` must be a valid pointer -/// - `instruction_words` must be a valid pointer +/// - `instruction_data` must be a valid pointer /// - `out_result` must be a valid pointer #[no_mangle] pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( handle: *mut WalletHandle, account_identities: *const FfiAccountIdentity, account_identities_size: usize, - instruction_words: *const u32, - instruction_words_size: usize, + instruction_data: *const u8, + instruction_data_size: usize, program_id: FfiProgramId, out_result: *mut FfiTransactionResult, ) -> WalletFfiError { @@ -228,7 +163,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( return WalletFfiError::NullPointer; } - if instruction_words.is_null() { + if instruction_data.is_null() { print_error("Null input pointer for instruction data"); return WalletFfiError::NullPointer; } @@ -247,7 +182,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( }; let accounts_ffi = std::slice::from_raw_parts(account_identities, account_identities_size); - let instruction_data = std::slice::from_raw_parts(instruction_words, instruction_words_size); + let instruction_data = std::slice::from_raw_parts(instruction_data, instruction_data_size); let mut accounts = Vec::with_capacity(account_identities_size); @@ -288,7 +223,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( /// # Parameters /// - `handle`: Valid pointer to wallet handle /// - `account_identities`: Valid pointer to list of `FfiAccountIdentity` -/// - `instruction_words`: Valid pointer to instruction words +/// - `instruction_data`: Valid pointer to instruction words /// - `out_result`: Valid pointer to `FfiTransactionResult` /// /// # Returns @@ -298,15 +233,15 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( /// # Safety /// - `handle` must be a valid pointer /// - `account_identities` must be a valid pointer -/// - `instruction_words` must be a valid pointer +/// - `instruction_data` must be a valid pointer /// - `out_result` must be a valid pointer #[no_mangle] pub unsafe extern "C" fn wallet_ffi_send_generic_private_transaction( handle: *mut WalletHandle, account_identities: *const FfiAccountIdentity, account_identities_size: usize, - instruction_words: *const u32, - instruction_words_size: usize, + instruction_data: *const u8, + instruction_data_size: usize, program_with_dependencies: *const FfiProgramWithDependencies, out_result: *mut FfiTransactionResult, ) -> WalletFfiError { @@ -320,7 +255,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_private_transaction( return WalletFfiError::NullPointer; } - if instruction_words.is_null() { + if instruction_data.is_null() { print_error("Null input pointer for instruction data"); return WalletFfiError::NullPointer; } @@ -339,7 +274,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_private_transaction( }; let accounts_ffi = std::slice::from_raw_parts(account_identities, account_identities_size); - let instruction_data = std::slice::from_raw_parts(instruction_words, instruction_words_size); + let instruction_data = std::slice::from_raw_parts(instruction_data, instruction_data_size); let mut accounts = Vec::with_capacity(account_identities_size); @@ -453,29 +388,6 @@ pub unsafe extern "C" fn wallet_ffi_free_transaction_result(result: *mut FfiTran } } -/// Free a instruction words returned by `wallet_ffi_serialization_helper`. -/// -/// # Safety -/// The result must be either null or a valid result from a serialization helper function. -#[no_mangle] -pub unsafe extern "C" fn wallet_ffi_free_instruction_words(words: *mut FfiInstructionWords) { - if words.is_null() { - return; - } - - unsafe { - let words = &*words; - - if !words.instruction_words.is_null() { - let words = std::slice::from_raw_parts_mut( - words.instruction_words, - words.instruction_words_size, - ); - drop(Box::from_raw(std::ptr::from_mut::<[u32]>(words))); - } - } -} - #[cfg(test)] mod tests { use crate::generic_transaction::FfiProgram; diff --git a/lez/wallet-ffi/wallet_ffi.h b/lez/wallet-ffi/wallet_ffi.h index 0245b4144..7d996c20b 100644 --- a/lez/wallet-ffi/wallet_ffi.h +++ b/lez/wallet-ffi/wallet_ffi.h @@ -226,12 +226,6 @@ typedef struct FfiTransferResult { bool success; } FfiTransferResult; -typedef struct FfiInstructionWords { - uint32_t *instruction_words; - uintptr_t instruction_words_size; - enum WalletFfiError error; -} FfiInstructionWords; - /** * Struct representing an account identity, given to `AccountManager` at intialization. */ @@ -598,30 +592,13 @@ enum WalletFfiError wallet_ffi_bridge_withdraw(struct WalletHandle *handle, const struct FfiBytes32 *bedrock_account_pk, struct FfiTransferResult *out_result); -/** - * Serialize sequence of bytes into RISC0 readable words. - * - * # Parameters - * - `input_instruction_data`: Valid pointer to a sequence of bytes - * - `input_instruction_data_size`: Size of `input_instruction_data` - * - * # Returns - * - `Success` on successful creation - * - Error code on failure - * - * # Safety - * - `input_instruction_data` must be a valid pointer - */ -struct FfiInstructionWords wallet_ffi_serialization_helper(const uint8_t *input_instruction_data, - uintptr_t input_instruction_data_size); - /** * Send generic public transaction. * * # Parameters * - `handle`: Valid pointer to wallet handle * - `account_identities`: Valid pointer to list of `FfiAccountIdentity` - * - `instruction_words`: Valid pointer to instruction words + * - `instruction_data`: Valid pointer to instruction words * - `out_result`: Valid pointer to `FfiTransactionResult` * * # Returns @@ -631,14 +608,14 @@ struct FfiInstructionWords wallet_ffi_serialization_helper(const uint8_t *input_ * # Safety * - `handle` must be a valid pointer * - `account_identities` must be a valid pointer - * - `instruction_words` must be a valid pointer + * - `instruction_data` must be a valid pointer * - `out_result` must be a valid pointer */ enum WalletFfiError wallet_ffi_send_generic_public_transaction(struct WalletHandle *handle, const struct FfiAccountIdentity *account_identities, uintptr_t account_identities_size, - const uint32_t *instruction_words, - uintptr_t instruction_words_size, + const uint8_t *instruction_data, + uintptr_t instruction_data_size, struct FfiProgramId program_id, struct FfiTransactionResult *out_result); @@ -648,7 +625,7 @@ enum WalletFfiError wallet_ffi_send_generic_public_transaction(struct WalletHand * # Parameters * - `handle`: Valid pointer to wallet handle * - `account_identities`: Valid pointer to list of `FfiAccountIdentity` - * - `instruction_words`: Valid pointer to instruction words + * - `instruction_data`: Valid pointer to instruction words * - `out_result`: Valid pointer to `FfiTransactionResult` * * # Returns @@ -658,14 +635,14 @@ enum WalletFfiError wallet_ffi_send_generic_public_transaction(struct WalletHand * # Safety * - `handle` must be a valid pointer * - `account_identities` must be a valid pointer - * - `instruction_words` must be a valid pointer + * - `instruction_data` must be a valid pointer * - `out_result` must be a valid pointer */ enum WalletFfiError wallet_ffi_send_generic_private_transaction(struct WalletHandle *handle, const struct FfiAccountIdentity *account_identities, uintptr_t account_identities_size, - const uint32_t *instruction_words, - uintptr_t instruction_words_size, + const uint8_t *instruction_data, + uintptr_t instruction_data_size, const struct FfiProgramWithDependencies *program_with_dependencies, struct FfiTransactionResult *out_result); @@ -696,14 +673,6 @@ enum WalletFfiError wallet_ffi_poll_transaction_status(struct WalletHandle *hand */ void wallet_ffi_free_transaction_result(struct FfiTransactionResult *result); -/** - * Free a instruction words returned by `wallet_ffi_serialization_helper`. - * - * # Safety - * The result must be either null or a valid result from a serialization helper function. - */ -void wallet_ffi_free_instruction_words(struct FfiInstructionWords *words); - /** * Get the public key for a public account. * diff --git a/test_programs/guest/Cargo.toml b/test_programs/guest/Cargo.toml index 1d6f927dc..c6d58a7d8 100644 --- a/test_programs/guest/Cargo.toml +++ b/test_programs/guest/Cargo.toml @@ -8,6 +8,7 @@ license = { workspace = true } workspace = true [dependencies] +borsh.workspace = true lee_core.workspace = true authenticated_transfer_core.workspace = true clock_core.workspace = true diff --git a/test_programs/guest/src/bin/authority_proxy.rs b/test_programs/guest/src/bin/authority_proxy.rs index cdda55f96..2ef6f9f8a 100644 --- a/test_programs/guest/src/bin/authority_proxy.rs +++ b/test_programs/guest/src/bin/authority_proxy.rs @@ -10,7 +10,7 @@ use lee_core::{ /// forwarding every account it was given. With a seed, the PDA derived from /// `(self, seed)` is delegated through `pda_seeds` and flagged authorized in the /// call, which is how a program-held authority acts on a callee. -type Instruction = (ProgramId, Vec, Option); +type Instruction = (ProgramId, Vec, Option); fn main() { let ( diff --git a/test_programs/guest/src/bin/chain_caller.rs b/test_programs/guest/src/bin/chain_caller.rs index 0473f1d24..1c851b29c 100644 --- a/test_programs/guest/src/bin/chain_caller.rs +++ b/test_programs/guest/src/bin/chain_caller.rs @@ -2,7 +2,7 @@ use authenticated_transfer_core::Instruction as AuthTransferInstruction; use lee_core::program::{ AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; type Instruction = (u128, ProgramId, u32, Option); diff --git a/test_programs/guest/src/bin/clock_chain_caller.rs b/test_programs/guest/src/bin/clock_chain_caller.rs index fc9b81c35..9e79121e0 100644 --- a/test_programs/guest/src/bin/clock_chain_caller.rs +++ b/test_programs/guest/src/bin/clock_chain_caller.rs @@ -4,7 +4,7 @@ use lee_core::{ AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; type Instruction = (ProgramId, Timestamp); // (clock_program_id, timestamp) diff --git a/test_programs/guest/src/bin/faucet_chain_caller.rs b/test_programs/guest/src/bin/faucet_chain_caller.rs index 0b320a75d..1e25e5109 100644 --- a/test_programs/guest/src/bin/faucet_chain_caller.rs +++ b/test_programs/guest/src/bin/faucet_chain_caller.rs @@ -4,7 +4,7 @@ use lee_core::{ AccountPostState, ChainedCall, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; type Instruction = (ProgramId, ProgramId, AccountId, u128); // (faucet_program_id, vault_program_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 0b4c89145..ce39e7d3f 100644 --- a/test_programs/guest/src/bin/pda_spend_proxy.rs +++ b/test_programs/guest/src/bin/pda_spend_proxy.rs @@ -1,7 +1,7 @@ use lee_core::program::{ AccountPostState, ChainedCall, PdaSeed, ProgramId, ProgramInput, ProgramOutput, read_lee_inputs, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; /// Proxy for spending from a private PDA via `auth_transfer`. /// diff --git a/tools/cross_zone_chat/Cargo.toml b/tools/cross_zone_chat/Cargo.toml index a7c5de31a..22053eb56 100644 --- a/tools/cross_zone_chat/Cargo.toml +++ b/tools/cross_zone_chat/Cargo.toml @@ -8,6 +8,7 @@ license = { workspace = true } workspace = true [dependencies] +borsh.workspace = true test_fixtures.workspace = true sequencer_service_rpc = { workspace = true, features = ["client"] } programs.workspace = true diff --git a/tools/cross_zone_chat/src/main.rs b/tools/cross_zone_chat/src/main.rs index 3ed3d1253..ce735c186 100644 --- a/tools/cross_zone_chat/src/main.rs +++ b/tools/cross_zone_chat/src/main.rs @@ -514,9 +514,8 @@ async fn poll_finality(state: Arc) { } /// Recovers the chat text from an inbox dispatch tx's instruction data. -fn decode_inbox_text(instruction_data: &[u32]) -> Option { - let instruction: Instruction = - risc0_zkvm::serde::from_slice::(instruction_data).ok()?; +fn decode_inbox_text(instruction_data: &[u8]) -> Option { + let instruction: Instruction = borsh::from_slice::(instruction_data).ok()?; let Instruction::Dispatch(message) = instruction else { return None; }; @@ -524,26 +523,18 @@ fn decode_inbox_text(instruction_data: &[u32]) -> Option { } /// Recovers the outbox ordinal from a `ping_sender::Send` tx's instruction data. -fn decode_send_ordinal(instruction_data: &[u32]) -> Option { +fn decode_send_ordinal(instruction_data: &[u8]) -> Option { let instruction: SenderInstruction = - risc0_zkvm::serde::from_slice::(instruction_data).ok()?; + borsh::from_slice::(instruction_data).ok()?; let SenderInstruction::Send { ordinal, .. } = instruction else { return None; }; Some(ordinal) } -/// Decodes a `ping_receiver::Record` payload (risc0 words in LE bytes) to text. +/// Decodes a `ping_receiver::Record` payload (borsh bytes) to text. fn decode_payload(payload: &[u8]) -> Option { - let chunks = payload.chunks_exact(4); - if !chunks.remainder().is_empty() { - return None; - } - let words: Vec = chunks - .map(|chunk| u32::from_le_bytes(chunk.try_into().expect("chunks_exact(4) yields 4 bytes"))) - .collect(); - let instruction: ReceiverInstruction = - risc0_zkvm::serde::from_slice::(&words).ok()?; + let instruction: ReceiverInstruction = borsh::from_slice::(payload).ok()?; let ReceiverInstruction::Record { payload: bytes } = instruction else { return None; }; @@ -556,7 +547,7 @@ fn build_send_tx(other_zone: ZoneId, ordinal: u32, text: &str) -> LeeTransaction let receiver_id = programs::ping_receiver().id(); let outbox_id = programs::cross_zone_outbox().id(); - let words = risc0_zkvm::serde::to_vec(&ReceiverInstruction::Record { + let words = borsh::to_vec(&ReceiverInstruction::Record { payload: text.as_bytes().to_vec(), }) .expect("serialize record instruction"); diff --git a/tools/cycle_bench/src/main.rs b/tools/cycle_bench/src/main.rs index 97e0efdc7..f2c22eaa6 100644 --- a/tools/cycle_bench/src/main.rs +++ b/tools/cycle_bench/src/main.rs @@ -179,7 +179,7 @@ struct Case { } impl Case { - fn new( + fn new( program_name: &'static str, instruction_label: &'static str, program: Program, @@ -191,7 +191,7 @@ impl Case { instruction_label, program, pre_states, - instruction_words: risc0_zkvm::serde::to_vec(instruction)?, + instruction_words: borsh::to_vec(instruction)?, }) } diff --git a/tools/cycle_bench/src/ppe/ppe_impl.rs b/tools/cycle_bench/src/ppe/ppe_impl.rs index 8023e21bd..197aaee3e 100644 --- a/tools/cycle_bench/src/ppe/ppe_impl.rs +++ b/tools/cycle_bench/src/ppe/ppe_impl.rs @@ -13,7 +13,7 @@ use lee_core::{ InputAccountIdentity, PrivacyPreservingCircuitOutput, account::{Account, AccountId, AccountWithMetadata}, }; -use risc0_zkvm::serde::to_vec; +use borsh::to_vec; use super::PpeBenchResult;