Browse Source

program-runtime: port over remaining CPI implementation from syscalls lib (#8046)

Joe C 2 months ago
parent
commit
8b52ec885b
6 changed files with 538 additions and 685 deletions
  1. 1 0
      Cargo.lock
  2. 1 0
      program-runtime/Cargo.toml
  3. 514 20
      program-runtime/src/cpi.rs
  4. 1 0
      programs/sbf/Cargo.lock
  5. 20 661
      syscalls/src/cpi.rs
  6. 1 4
      syscalls/src/lib.rs

+ 1 - 0
Cargo.lock

@@ -9769,6 +9769,7 @@ dependencies = [
  "solana-sdk-ids",
  "solana-signer",
  "solana-slot-hashes",
+ "solana-stable-layout",
  "solana-stake-interface",
  "solana-svm-callback",
  "solana-svm-feature-set",

+ 1 - 0
program-runtime/Cargo.toml

@@ -53,6 +53,7 @@ solana-rent = { workspace = true }
 solana-sbpf = { workspace = true, features = ["jit"] }
 solana-sdk-ids = { workspace = true }
 solana-slot-hashes = { workspace = true }
+solana-stable-layout = { workspace = true }
 solana-stake-interface = { workspace = true, features = ["bincode", "sysvar"] }
 solana-svm-callback = { workspace = true }
 solana-svm-feature-set = { workspace = true }

+ 514 - 20
program-runtime/src/cpi.rs

@@ -3,21 +3,23 @@
 use {
     crate::{
         invoke_context::{InvokeContext, SerializedAccountMetadata},
-        memory::{translate_slice, translate_type, translate_type_mut_for_cpi},
+        memory::{translate_slice, translate_type, translate_type_mut_for_cpi, translate_vm_slice},
         serialization::{create_memory_region_of_account, modify_memory_region_of_account},
     },
-    solana_instruction::{error::InstructionError, Instruction},
+    solana_account_info::AccountInfo,
+    solana_instruction::{error::InstructionError, AccountMeta, Instruction},
     solana_loader_v3_interface::instruction as bpf_loader_upgradeable,
     solana_program_entrypoint::MAX_PERMITTED_DATA_INCREASE,
-    solana_pubkey::{Pubkey, PubkeyError},
+    solana_pubkey::{Pubkey, PubkeyError, MAX_SEEDS},
     solana_sbpf::{ebpf, memory_region::MemoryMapping},
     solana_sdk_ids::{bpf_loader, bpf_loader_deprecated, native_loader},
+    solana_stable_layout::stable_instruction::StableInstruction,
     solana_svm_log_collector::ic_msg,
     solana_svm_measure::measure::Measure,
     solana_svm_timings::ExecuteTimings,
     solana_transaction_context::{
-        BorrowedInstructionAccount, IndexOfAccount, MAX_ACCOUNTS_PER_INSTRUCTION,
-        MAX_INSTRUCTION_DATA_LEN,
+        vm_slice::VmSlice, BorrowedInstructionAccount, IndexOfAccount,
+        MAX_ACCOUNTS_PER_INSTRUCTION, MAX_INSTRUCTION_DATA_LEN,
     },
     std::mem,
     thiserror::Error,
@@ -56,11 +58,13 @@ pub enum CpiError {
 type Error = Box<dyn std::error::Error>;
 
 const SUCCESS: u64 = 0;
+/// Maximum signers
+const MAX_SIGNERS: usize = 16;
 
 /// Rust representation of C's SolInstruction
 #[derive(Debug)]
 #[repr(C)]
-pub struct SolInstruction {
+struct SolInstruction {
     pub program_id_addr: u64,
     pub accounts_addr: u64,
     pub accounts_len: u64,
@@ -71,7 +75,7 @@ pub struct SolInstruction {
 /// Rust representation of C's SolAccountMeta
 #[derive(Debug)]
 #[repr(C)]
-pub struct SolAccountMeta {
+struct SolAccountMeta {
     pub pubkey_addr: u64,
     pub is_writable: bool,
     pub is_signer: bool,
@@ -80,7 +84,7 @@ pub struct SolAccountMeta {
 /// Rust representation of C's SolAccountInfo
 #[derive(Debug)]
 #[repr(C)]
-pub struct SolAccountInfo {
+struct SolAccountInfo {
     pub key_addr: u64,
     pub lamports_addr: u64,
     pub data_len: u64,
@@ -95,7 +99,7 @@ pub struct SolAccountInfo {
 /// Rust representation of C's SolSignerSeed
 #[derive(Debug)]
 #[repr(C)]
-pub struct SolSignerSeedC {
+struct SolSignerSeedC {
     pub addr: u64,
     pub len: u64,
 }
@@ -103,7 +107,7 @@ pub struct SolSignerSeedC {
 /// Rust representation of C's SolSignerSeeds
 #[derive(Debug)]
 #[repr(C)]
-pub struct SolSignerSeedsC {
+struct SolSignerSeedsC {
     pub addr: u64,
     pub len: u64,
 }
@@ -132,7 +136,7 @@ fn check_account_info_pointer(
 }
 
 /// Check that an instruction's account and data lengths are within limits
-pub fn check_instruction_size(num_accounts: usize, data_len: usize) -> Result<(), Error> {
+fn check_instruction_size(num_accounts: usize, data_len: usize) -> Result<(), Error> {
     if num_accounts > MAX_ACCOUNTS_PER_INSTRUCTION {
         return Err(Box::new(CpiError::MaxInstructionAccountsExceeded {
             num_accounts: num_accounts as u64,
@@ -149,7 +153,7 @@ pub fn check_instruction_size(num_accounts: usize, data_len: usize) -> Result<()
 }
 
 /// Check that the number of account infos is within the CPI limit
-pub fn check_account_infos(
+fn check_account_infos(
     num_account_infos: usize,
     invoke_context: &mut InvokeContext,
 ) -> Result<(), Error> {
@@ -173,7 +177,7 @@ pub fn check_account_infos(
 }
 
 /// Check whether a program is authorized for CPI
-pub fn check_authorized_program(
+fn check_authorized_program(
     program_id: &Pubkey,
     instruction_data: &[u8],
     invoke_context: &InvokeContext,
@@ -388,7 +392,7 @@ impl<'a> CallerAccount<'a> {
     }
 
     // Create a CallerAccount given a SolAccountInfo.
-    pub fn from_sol_account_info(
+    fn from_sol_account_info(
         invoke_context: &InvokeContext,
         memory_mapping: &solana_sbpf::memory_region::MemoryMapping<'_>,
         check_aligned: bool,
@@ -505,6 +509,253 @@ pub trait SyscallInvokeSigned {
     ) -> Result<Vec<Pubkey>, Error>;
 }
 
+pub fn translate_instruction_rust(
+    addr: u64,
+    memory_mapping: &MemoryMapping,
+    invoke_context: &mut InvokeContext,
+    check_aligned: bool,
+) -> Result<Instruction, Error> {
+    let ix = translate_type::<StableInstruction>(memory_mapping, addr, check_aligned)?;
+    let account_metas = translate_slice::<AccountMeta>(
+        memory_mapping,
+        ix.accounts.as_vaddr(),
+        ix.accounts.len(),
+        check_aligned,
+    )?;
+    let data = translate_slice::<u8>(
+        memory_mapping,
+        ix.data.as_vaddr(),
+        ix.data.len(),
+        check_aligned,
+    )?
+    .to_vec();
+
+    check_instruction_size(account_metas.len(), data.len())?;
+
+    consume_compute_meter(
+        invoke_context,
+        (data.len() as u64)
+            .checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
+            .unwrap_or(u64::MAX),
+    )?;
+
+    let mut accounts = Vec::with_capacity(account_metas.len());
+    #[allow(clippy::needless_range_loop)]
+    for account_index in 0..account_metas.len() {
+        #[allow(clippy::indexing_slicing)]
+        let account_meta = &account_metas[account_index];
+        if unsafe {
+            std::ptr::read_volatile(&account_meta.is_signer as *const _ as *const u8) > 1
+                || std::ptr::read_volatile(&account_meta.is_writable as *const _ as *const u8) > 1
+        } {
+            return Err(Box::new(InstructionError::InvalidArgument));
+        }
+        accounts.push(account_meta.clone());
+    }
+
+    Ok(Instruction {
+        accounts,
+        data,
+        program_id: ix.program_id,
+    })
+}
+
+pub fn translate_accounts_rust<'a>(
+    account_infos_addr: u64,
+    account_infos_len: u64,
+    memory_mapping: &MemoryMapping<'_>,
+    invoke_context: &mut InvokeContext,
+    check_aligned: bool,
+) -> Result<Vec<TranslatedAccount<'a>>, Error> {
+    let (account_infos, account_info_keys) = translate_account_infos(
+        account_infos_addr,
+        account_infos_len,
+        |account_info: &AccountInfo| account_info.key as *const _ as u64,
+        memory_mapping,
+        invoke_context,
+        check_aligned,
+    )?;
+
+    translate_and_update_accounts(
+        &account_info_keys,
+        account_infos,
+        account_infos_addr,
+        invoke_context,
+        memory_mapping,
+        check_aligned,
+        CallerAccount::from_account_info,
+    )
+}
+
+pub fn translate_signers_rust(
+    program_id: &Pubkey,
+    signers_seeds_addr: u64,
+    signers_seeds_len: u64,
+    memory_mapping: &MemoryMapping,
+    check_aligned: bool,
+) -> Result<Vec<Pubkey>, Error> {
+    let mut signers = Vec::new();
+    if signers_seeds_len > 0 {
+        let signers_seeds = translate_slice::<VmSlice<VmSlice<u8>>>(
+            memory_mapping,
+            signers_seeds_addr,
+            signers_seeds_len,
+            check_aligned,
+        )?;
+        if signers_seeds.len() > MAX_SIGNERS {
+            return Err(Box::new(CpiError::TooManySigners));
+        }
+        for signer_seeds in signers_seeds.iter() {
+            let untranslated_seeds = translate_slice::<VmSlice<u8>>(
+                memory_mapping,
+                signer_seeds.ptr(),
+                signer_seeds.len(),
+                check_aligned,
+            )?;
+            if untranslated_seeds.len() > MAX_SEEDS {
+                return Err(Box::new(InstructionError::MaxSeedLengthExceeded));
+            }
+            let seeds = untranslated_seeds
+                .iter()
+                .map(|untranslated_seed| {
+                    translate_vm_slice(untranslated_seed, memory_mapping, check_aligned)
+                })
+                .collect::<Result<Vec<_>, Error>>()?;
+            let signer =
+                Pubkey::create_program_address(&seeds, program_id).map_err(CpiError::BadSeeds)?;
+            signers.push(signer);
+        }
+        Ok(signers)
+    } else {
+        Ok(vec![])
+    }
+}
+
+pub fn translate_instruction_c(
+    addr: u64,
+    memory_mapping: &MemoryMapping,
+    invoke_context: &mut InvokeContext,
+    check_aligned: bool,
+) -> Result<Instruction, Error> {
+    let ix_c = translate_type::<SolInstruction>(memory_mapping, addr, check_aligned)?;
+
+    let program_id = translate_type::<Pubkey>(memory_mapping, ix_c.program_id_addr, check_aligned)?;
+    let account_metas = translate_slice::<SolAccountMeta>(
+        memory_mapping,
+        ix_c.accounts_addr,
+        ix_c.accounts_len,
+        check_aligned,
+    )?;
+    let data = translate_slice::<u8>(memory_mapping, ix_c.data_addr, ix_c.data_len, check_aligned)?
+        .to_vec();
+
+    check_instruction_size(ix_c.accounts_len as usize, data.len())?;
+
+    consume_compute_meter(
+        invoke_context,
+        (data.len() as u64)
+            .checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
+            .unwrap_or(u64::MAX),
+    )?;
+
+    let mut accounts = Vec::with_capacity(ix_c.accounts_len as usize);
+    #[allow(clippy::needless_range_loop)]
+    for account_index in 0..ix_c.accounts_len as usize {
+        #[allow(clippy::indexing_slicing)]
+        let account_meta = &account_metas[account_index];
+        if unsafe {
+            std::ptr::read_volatile(&account_meta.is_signer as *const _ as *const u8) > 1
+                || std::ptr::read_volatile(&account_meta.is_writable as *const _ as *const u8) > 1
+        } {
+            return Err(Box::new(InstructionError::InvalidArgument));
+        }
+        let pubkey =
+            translate_type::<Pubkey>(memory_mapping, account_meta.pubkey_addr, check_aligned)?;
+        accounts.push(AccountMeta {
+            pubkey: *pubkey,
+            is_signer: account_meta.is_signer,
+            is_writable: account_meta.is_writable,
+        });
+    }
+
+    Ok(Instruction {
+        accounts,
+        data,
+        program_id: *program_id,
+    })
+}
+
+pub fn translate_accounts_c<'a>(
+    account_infos_addr: u64,
+    account_infos_len: u64,
+    memory_mapping: &MemoryMapping<'_>,
+    invoke_context: &mut InvokeContext,
+    check_aligned: bool,
+) -> Result<Vec<TranslatedAccount<'a>>, Error> {
+    let (account_infos, account_info_keys) = translate_account_infos(
+        account_infos_addr,
+        account_infos_len,
+        |account_info: &SolAccountInfo| account_info.key_addr,
+        memory_mapping,
+        invoke_context,
+        check_aligned,
+    )?;
+
+    translate_and_update_accounts(
+        &account_info_keys,
+        account_infos,
+        account_infos_addr,
+        invoke_context,
+        memory_mapping,
+        check_aligned,
+        CallerAccount::from_sol_account_info,
+    )
+}
+
+pub fn translate_signers_c(
+    program_id: &Pubkey,
+    signers_seeds_addr: u64,
+    signers_seeds_len: u64,
+    memory_mapping: &MemoryMapping,
+    check_aligned: bool,
+) -> Result<Vec<Pubkey>, Error> {
+    if signers_seeds_len > 0 {
+        let signers_seeds = translate_slice::<SolSignerSeedsC>(
+            memory_mapping,
+            signers_seeds_addr,
+            signers_seeds_len,
+            check_aligned,
+        )?;
+        if signers_seeds.len() > MAX_SIGNERS {
+            return Err(Box::new(CpiError::TooManySigners));
+        }
+        Ok(signers_seeds
+            .iter()
+            .map(|signer_seeds| {
+                let seeds = translate_slice::<SolSignerSeedC>(
+                    memory_mapping,
+                    signer_seeds.addr,
+                    signer_seeds.len,
+                    check_aligned,
+                )?;
+                if seeds.len() > MAX_SEEDS {
+                    return Err(Box::new(InstructionError::MaxSeedLengthExceeded) as Error);
+                }
+                let seeds_bytes = seeds
+                    .iter()
+                    .map(|seed| {
+                        translate_slice::<u8>(memory_mapping, seed.addr, seed.len, check_aligned)
+                    })
+                    .collect::<Result<Vec<_>, Error>>()?;
+                Pubkey::create_program_address(&seeds_bytes, program_id)
+                    .map_err(|err| Box::new(CpiError::BadSeeds(err)) as Error)
+            })
+            .collect::<Result<Vec<_>, Error>>()?)
+    } else {
+        Ok(vec![])
+    }
+}
+
 /// Call process instruction, common to both Rust and C
 pub fn cpi_common<S: SyscallInvokeSigned>(
     invoke_context: &mut InvokeContext,
@@ -616,7 +867,7 @@ pub struct TranslatedAccount<'a> {
     pub update_caller_account_info: bool,
 }
 
-pub fn translate_account_infos<'a, T, F>(
+fn translate_account_infos<'a, T, F>(
     account_infos_addr: u64,
     account_infos_len: u64,
     key_addr: F,
@@ -665,7 +916,7 @@ where
 
 // Finish translating accounts, build CallerAccount values and update callee
 // accounts in preparation of executing the callee.
-pub fn translate_and_update_accounts<'a, T, F>(
+fn translate_and_update_accounts<'a, T, F>(
     account_info_keys: &[&Pubkey],
     account_infos: &[T],
     account_infos_addr: u64,
@@ -806,7 +1057,7 @@ fn consume_compute_meter(invoke_context: &InvokeContext, amount: u64) -> Result<
 //
 // When true is returned, the caller account must be updated after CPI. This
 // is only set for stricter_abi_and_runtime_constraints when the pointer may have changed.
-pub fn update_callee_account(
+fn update_callee_account(
     check_aligned: bool,
     caller_account: &CallerAccount,
     mut callee_account: BorrowedInstructionAccount<'_>,
@@ -862,7 +1113,7 @@ pub fn update_callee_account(
     Ok(must_update_caller)
 }
 
-pub fn update_caller_account_region(
+fn update_caller_account_region(
     memory_mapping: &mut MemoryMapping,
     check_aligned: bool,
     caller_account: &CallerAccount,
@@ -911,7 +1162,7 @@ pub fn update_caller_account_region(
 // Safety: Once `stricter_abi_and_runtime_constraints` is enabled all fields of [CallerAccount] used
 // in this function should never point inside the address space reserved for
 // accounts (regardless of the current size of an account).
-pub fn update_caller_account(
+fn update_caller_account(
     invoke_context: &InvokeContext,
     memory_mapping: &MemoryMapping<'_>,
     check_aligned: bool,
@@ -1005,7 +1256,8 @@ mod tests {
     use {
         super::*,
         crate::{
-            invoke_context::SerializedAccountMetadata, memory::translate_type,
+            invoke_context::{BpfAllocator, SerializedAccountMetadata, SyscallContext},
+            memory::translate_type,
             with_mock_invoke_context_with_feature_set,
         },
         assert_matches::assert_matches,
@@ -1282,6 +1534,52 @@ mod tests {
         }
     }
 
+    struct MockInstruction {
+        program_id: Pubkey,
+        accounts: Vec<AccountMeta>,
+        data: Vec<u8>,
+    }
+
+    impl MockInstruction {
+        fn into_region(self, vm_addr: u64) -> (Vec<u8>, MemoryRegion) {
+            let accounts_len = mem::size_of::<AccountMeta>() * self.accounts.len();
+
+            let size = mem::size_of::<StableInstruction>() + accounts_len + self.data.len();
+
+            let mut data = vec![0; size];
+
+            let vm_addr = vm_addr as usize;
+            let accounts_addr = vm_addr + mem::size_of::<StableInstruction>();
+            let data_addr = accounts_addr + accounts_len;
+
+            let ins = Instruction {
+                program_id: self.program_id,
+                accounts: unsafe {
+                    Vec::from_raw_parts(
+                        accounts_addr as *mut _,
+                        self.accounts.len(),
+                        self.accounts.len(),
+                    )
+                },
+                data: unsafe {
+                    Vec::from_raw_parts(data_addr as *mut _, self.data.len(), self.data.len())
+                },
+            };
+            let ins = StableInstruction::from(ins);
+
+            unsafe {
+                ptr::write_unaligned(data.as_mut_ptr().cast(), ins);
+                data[accounts_addr - vm_addr..][..accounts_len].copy_from_slice(
+                    slice::from_raw_parts(self.accounts.as_ptr().cast(), accounts_len),
+                );
+                data[data_addr - vm_addr..].copy_from_slice(&self.data);
+            }
+
+            let region = MemoryRegion::new_writable(data.as_mut_slice(), vm_addr as u64);
+            (data, region)
+        }
+    }
+
     #[repr(C)]
     struct RcBox<T> {
         strong: Cell<usize>,
@@ -1357,6 +1655,202 @@ mod tests {
         ]
     }
 
+    fn mock_signers(signers: &[&[u8]], vm_addr: u64) -> (Vec<u8>, MemoryRegion) {
+        let vm_addr = vm_addr as usize;
+
+        // calculate size
+        let fat_ptr_size_of_slice = mem::size_of::<&[()]>(); // pointer size + length size
+        let singers_length = signers.len();
+        let sum_signers_data_length: usize = signers.iter().map(|s| s.len()).sum();
+
+        // init data vec
+        let total_size = fat_ptr_size_of_slice
+            + singers_length * fat_ptr_size_of_slice
+            + sum_signers_data_length;
+        let mut data = vec![0; total_size];
+
+        // data is composed by 3 parts
+        // A.
+        // [ singers address, singers length, ...,
+        // B.                                      |
+        //                                         signer1 address, signer1 length, signer2 address ...,
+        //                                         ^ p1 --->
+        // C.                                                                                           |
+        //                                                                                              signer1 data, signer2 data, ... ]
+        //                                                                                              ^ p2 --->
+
+        // A.
+        data[..fat_ptr_size_of_slice / 2]
+            .clone_from_slice(&(fat_ptr_size_of_slice + vm_addr).to_le_bytes());
+        data[fat_ptr_size_of_slice / 2..fat_ptr_size_of_slice]
+            .clone_from_slice(&(singers_length).to_le_bytes());
+
+        // B. + C.
+        let (mut p1, mut p2) = (
+            fat_ptr_size_of_slice,
+            fat_ptr_size_of_slice + singers_length * fat_ptr_size_of_slice,
+        );
+        for signer in signers.iter() {
+            let signer_length = signer.len();
+
+            // B.
+            data[p1..p1 + fat_ptr_size_of_slice / 2]
+                .clone_from_slice(&(p2 + vm_addr).to_le_bytes());
+            data[p1 + fat_ptr_size_of_slice / 2..p1 + fat_ptr_size_of_slice]
+                .clone_from_slice(&(signer_length).to_le_bytes());
+            p1 += fat_ptr_size_of_slice;
+
+            // C.
+            data[p2..p2 + signer_length].clone_from_slice(signer);
+            p2 += signer_length;
+        }
+
+        let region = MemoryRegion::new_writable(data.as_mut_slice(), vm_addr as u64);
+        (data, region)
+    }
+
+    #[test]
+    fn test_translate_instruction() {
+        let transaction_accounts =
+            transaction_with_one_writable_instruction_account(b"foo".to_vec());
+        mock_invoke_context!(
+            invoke_context,
+            transaction_context,
+            b"instruction data",
+            transaction_accounts,
+            0,
+            &[1]
+        );
+
+        let program_id = Pubkey::new_unique();
+        let accounts = vec![AccountMeta {
+            pubkey: Pubkey::new_unique(),
+            is_signer: true,
+            is_writable: false,
+        }];
+        let data = b"ins data".to_vec();
+        let vm_addr = MM_INPUT_START;
+        let (_mem, region) = MockInstruction {
+            program_id,
+            accounts: accounts.clone(),
+            data: data.clone(),
+        }
+        .into_region(vm_addr);
+
+        let config = Config {
+            aligned_memory_mapping: false,
+            ..Config::default()
+        };
+        let memory_mapping = MemoryMapping::new(vec![region], &config, SBPFVersion::V3).unwrap();
+
+        let ins = translate_instruction_rust(
+            vm_addr,
+            &memory_mapping,
+            &mut invoke_context,
+            true, // check_aligned
+        )
+        .unwrap();
+        assert_eq!(ins.program_id, program_id);
+        assert_eq!(ins.accounts, accounts);
+        assert_eq!(ins.data, data);
+    }
+
+    #[test]
+    fn test_translate_signers() {
+        let transaction_accounts =
+            transaction_with_one_writable_instruction_account(b"foo".to_vec());
+        mock_invoke_context!(
+            invoke_context,
+            transaction_context,
+            b"instruction data",
+            transaction_accounts,
+            0,
+            &[1]
+        );
+
+        let program_id = Pubkey::new_unique();
+        let (derived_key, bump_seed) = Pubkey::find_program_address(&[b"foo"], &program_id);
+
+        let vm_addr = MM_INPUT_START;
+        let (_mem, region) = mock_signers(&[b"foo", &[bump_seed]], vm_addr);
+
+        let config = Config {
+            aligned_memory_mapping: false,
+            ..Config::default()
+        };
+        let memory_mapping = MemoryMapping::new(vec![region], &config, SBPFVersion::V3).unwrap();
+
+        let signers = translate_signers_rust(
+            &program_id,
+            vm_addr,
+            1,
+            &memory_mapping,
+            true, // check_aligned
+        )
+        .unwrap();
+        assert_eq!(signers[0], derived_key);
+    }
+
+    #[test]
+    fn test_translate_accounts_rust() {
+        let transaction_accounts =
+            transaction_with_one_writable_instruction_account(b"foobar".to_vec());
+        let account = transaction_accounts[1].1.clone();
+        let key = transaction_accounts[1].0;
+        let original_data_len = account.data().len();
+
+        let vm_addr = MM_INPUT_START;
+        let (_mem, region, account_metadata) =
+            MockAccountInfo::new(key, &account).into_region(vm_addr);
+
+        let config = Config {
+            aligned_memory_mapping: false,
+            ..Config::default()
+        };
+        let memory_mapping = MemoryMapping::new(vec![region], &config, SBPFVersion::V3).unwrap();
+
+        mock_invoke_context!(
+            invoke_context,
+            transaction_context,
+            b"instruction data",
+            transaction_accounts,
+            0,
+            &[1, 1]
+        );
+
+        invoke_context
+            .set_syscall_context(SyscallContext {
+                allocator: BpfAllocator::new(solana_program_entrypoint::HEAP_LENGTH as u64),
+                accounts_metadata: vec![account_metadata],
+                trace_log: Vec::new(),
+            })
+            .unwrap();
+
+        invoke_context
+            .transaction_context
+            .configure_next_instruction_for_tests(
+                0,
+                vec![
+                    InstructionAccount::new(1, false, true),
+                    InstructionAccount::new(1, false, true),
+                ],
+                &[],
+            )
+            .unwrap();
+        let accounts = translate_accounts_rust(
+            vm_addr,
+            1,
+            &memory_mapping,
+            &mut invoke_context,
+            true, // check_aligned
+        )
+        .unwrap();
+        assert_eq!(accounts.len(), 1);
+        let caller_account = &accounts[0].caller_account;
+        assert_eq!(caller_account.serialized_data, account.data());
+        assert_eq!(caller_account.original_data_len, original_data_len);
+    }
+
     #[test]
     fn test_caller_account_from_account_info() {
         let transaction_accounts =

+ 1 - 0
programs/sbf/Cargo.lock

@@ -7670,6 +7670,7 @@ dependencies = [
  "solana-sbpf",
  "solana-sdk-ids",
  "solana-slot-hashes",
+ "solana-stable-layout",
  "solana-stake-interface",
  "solana-svm-callback",
  "solana-svm-feature-set",

+ 20 - 661
syscalls/src/cpi.rs

@@ -1,16 +1,11 @@
 use {
     super::*,
     solana_instruction::Instruction,
-    solana_program_runtime::{
-        cpi::{
-            check_instruction_size, cpi_common, translate_account_infos,
-            translate_and_update_accounts, CallerAccount, SolAccountInfo, SolAccountMeta,
-            SolInstruction, SolSignerSeedC, SolSignerSeedsC, SyscallInvokeSigned,
-            TranslatedAccount,
-        },
-        memory::{translate_slice, translate_type, translate_vm_slice},
+    solana_program_runtime::cpi::{
+        cpi_common, translate_accounts_c, translate_accounts_rust, translate_instruction_c,
+        translate_instruction_rust, translate_signers_c, translate_signers_rust,
+        SyscallInvokeSigned, TranslatedAccount,
     },
-    solana_stable_layout::stable_instruction::StableInstruction,
 };
 
 declare_builtin_function!(
@@ -44,50 +39,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
         invoke_context: &mut InvokeContext,
         check_aligned: bool,
     ) -> Result<Instruction, Error> {
-        let ix = translate_type::<StableInstruction>(memory_mapping, addr, check_aligned)?;
-        let account_metas = translate_slice::<AccountMeta>(
-            memory_mapping,
-            ix.accounts.as_vaddr(),
-            ix.accounts.len(),
-            check_aligned,
-        )?;
-        let data = translate_slice::<u8>(
-            memory_mapping,
-            ix.data.as_vaddr(),
-            ix.data.len(),
-            check_aligned,
-        )?
-        .to_vec();
-
-        check_instruction_size(account_metas.len(), data.len())?;
-
-        consume_compute_meter(
-            invoke_context,
-            (data.len() as u64)
-                .checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
-                .unwrap_or(u64::MAX),
-        )?;
-
-        let mut accounts = Vec::with_capacity(account_metas.len());
-        #[allow(clippy::needless_range_loop)]
-        for account_index in 0..account_metas.len() {
-            #[allow(clippy::indexing_slicing)]
-            let account_meta = &account_metas[account_index];
-            if unsafe {
-                std::ptr::read_volatile(&account_meta.is_signer as *const _ as *const u8) > 1
-                    || std::ptr::read_volatile(&account_meta.is_writable as *const _ as *const u8)
-                        > 1
-            } {
-                return Err(Box::new(InstructionError::InvalidArgument));
-            }
-            accounts.push(account_meta.clone());
-        }
-
-        Ok(Instruction {
-            accounts,
-            data,
-            program_id: ix.program_id,
-        })
+        translate_instruction_rust(addr, memory_mapping, invoke_context, check_aligned)
     }
 
     fn translate_accounts<'a>(
@@ -97,23 +49,12 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
         invoke_context: &mut InvokeContext,
         check_aligned: bool,
     ) -> Result<Vec<TranslatedAccount<'a>>, Error> {
-        let (account_infos, account_info_keys) = translate_account_infos(
+        translate_accounts_rust(
             account_infos_addr,
             account_infos_len,
-            |account_info: &AccountInfo| account_info.key as *const _ as u64,
             memory_mapping,
             invoke_context,
             check_aligned,
-        )?;
-
-        translate_and_update_accounts(
-            &account_info_keys,
-            account_infos,
-            account_infos_addr,
-            invoke_context,
-            memory_mapping,
-            check_aligned,
-            CallerAccount::from_account_info,
         )
     }
 
@@ -124,41 +65,13 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
         memory_mapping: &MemoryMapping,
         check_aligned: bool,
     ) -> Result<Vec<Pubkey>, Error> {
-        let mut signers = Vec::new();
-        if signers_seeds_len > 0 {
-            let signers_seeds = translate_slice::<VmSlice<VmSlice<u8>>>(
-                memory_mapping,
-                signers_seeds_addr,
-                signers_seeds_len,
-                check_aligned,
-            )?;
-            if signers_seeds.len() > MAX_SIGNERS {
-                return Err(Box::new(SyscallError::TooManySigners));
-            }
-            for signer_seeds in signers_seeds.iter() {
-                let untranslated_seeds = translate_slice::<VmSlice<u8>>(
-                    memory_mapping,
-                    signer_seeds.ptr(),
-                    signer_seeds.len(),
-                    check_aligned,
-                )?;
-                if untranslated_seeds.len() > MAX_SEEDS {
-                    return Err(Box::new(InstructionError::MaxSeedLengthExceeded));
-                }
-                let seeds = untranslated_seeds
-                    .iter()
-                    .map(|untranslated_seed| {
-                        translate_vm_slice(untranslated_seed, memory_mapping, check_aligned)
-                    })
-                    .collect::<Result<Vec<_>, Error>>()?;
-                let signer = Pubkey::create_program_address(&seeds, program_id)
-                    .map_err(SyscallError::BadSeeds)?;
-                signers.push(signer);
-            }
-            Ok(signers)
-        } else {
-            Ok(vec![])
-        }
+        translate_signers_rust(
+            program_id,
+            signers_seeds_addr,
+            signers_seeds_len,
+            memory_mapping,
+            check_aligned,
+        )
     }
 }
 
@@ -193,55 +106,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
         invoke_context: &mut InvokeContext,
         check_aligned: bool,
     ) -> Result<Instruction, Error> {
-        let ix_c = translate_type::<SolInstruction>(memory_mapping, addr, check_aligned)?;
-
-        let program_id =
-            translate_type::<Pubkey>(memory_mapping, ix_c.program_id_addr, check_aligned)?;
-        let account_metas = translate_slice::<SolAccountMeta>(
-            memory_mapping,
-            ix_c.accounts_addr,
-            ix_c.accounts_len,
-            check_aligned,
-        )?;
-        let data =
-            translate_slice::<u8>(memory_mapping, ix_c.data_addr, ix_c.data_len, check_aligned)?
-                .to_vec();
-
-        check_instruction_size(ix_c.accounts_len as usize, data.len())?;
-
-        consume_compute_meter(
-            invoke_context,
-            (data.len() as u64)
-                .checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
-                .unwrap_or(u64::MAX),
-        )?;
-
-        let mut accounts = Vec::with_capacity(ix_c.accounts_len as usize);
-        #[allow(clippy::needless_range_loop)]
-        for account_index in 0..ix_c.accounts_len as usize {
-            #[allow(clippy::indexing_slicing)]
-            let account_meta = &account_metas[account_index];
-            if unsafe {
-                std::ptr::read_volatile(&account_meta.is_signer as *const _ as *const u8) > 1
-                    || std::ptr::read_volatile(&account_meta.is_writable as *const _ as *const u8)
-                        > 1
-            } {
-                return Err(Box::new(InstructionError::InvalidArgument));
-            }
-            let pubkey =
-                translate_type::<Pubkey>(memory_mapping, account_meta.pubkey_addr, check_aligned)?;
-            accounts.push(AccountMeta {
-                pubkey: *pubkey,
-                is_signer: account_meta.is_signer,
-                is_writable: account_meta.is_writable,
-            });
-        }
-
-        Ok(Instruction {
-            accounts,
-            data,
-            program_id: *program_id,
-        })
+        translate_instruction_c(addr, memory_mapping, invoke_context, check_aligned)
     }
 
     fn translate_accounts<'a>(
@@ -251,23 +116,12 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
         invoke_context: &mut InvokeContext,
         check_aligned: bool,
     ) -> Result<Vec<TranslatedAccount<'a>>, Error> {
-        let (account_infos, account_info_keys) = translate_account_infos(
+        translate_accounts_c(
             account_infos_addr,
             account_infos_len,
-            |account_info: &SolAccountInfo| account_info.key_addr,
             memory_mapping,
             invoke_context,
             check_aligned,
-        )?;
-
-        translate_and_update_accounts(
-            &account_info_keys,
-            account_infos,
-            account_infos_addr,
-            invoke_context,
-            memory_mapping,
-            check_aligned,
-            CallerAccount::from_sol_account_info,
         )
     }
 
@@ -278,507 +132,12 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
         memory_mapping: &MemoryMapping,
         check_aligned: bool,
     ) -> Result<Vec<Pubkey>, Error> {
-        if signers_seeds_len > 0 {
-            let signers_seeds = translate_slice::<SolSignerSeedsC>(
-                memory_mapping,
-                signers_seeds_addr,
-                signers_seeds_len,
-                check_aligned,
-            )?;
-            if signers_seeds.len() > MAX_SIGNERS {
-                return Err(Box::new(SyscallError::TooManySigners));
-            }
-            Ok(signers_seeds
-                .iter()
-                .map(|signer_seeds| {
-                    let seeds = translate_slice::<SolSignerSeedC>(
-                        memory_mapping,
-                        signer_seeds.addr,
-                        signer_seeds.len,
-                        check_aligned,
-                    )?;
-                    if seeds.len() > MAX_SEEDS {
-                        return Err(Box::new(InstructionError::MaxSeedLengthExceeded) as Error);
-                    }
-                    let seeds_bytes = seeds
-                        .iter()
-                        .map(|seed| {
-                            translate_slice::<u8>(
-                                memory_mapping,
-                                seed.addr,
-                                seed.len,
-                                check_aligned,
-                            )
-                        })
-                        .collect::<Result<Vec<_>, Error>>()?;
-                    Pubkey::create_program_address(&seeds_bytes, program_id)
-                        .map_err(|err| Box::new(SyscallError::BadSeeds(err)) as Error)
-                })
-                .collect::<Result<Vec<_>, Error>>()?)
-        } else {
-            Ok(vec![])
-        }
-    }
-}
-
-#[allow(clippy::indexing_slicing)]
-#[allow(clippy::arithmetic_side_effects)]
-#[cfg(test)]
-mod tests {
-    use {
-        super::*,
-        solana_account::{Account, AccountSharedData, ReadableAccount},
-        solana_instruction::Instruction,
-        solana_program_runtime::{
-            invoke_context::{BpfAllocator, SerializedAccountMetadata, SyscallContext},
-            with_mock_invoke_context_with_feature_set,
-        },
-        solana_sbpf::{
-            ebpf::MM_INPUT_START, memory_region::MemoryRegion, program::SBPFVersion, vm::Config,
-        },
-        solana_sdk_ids::bpf_loader,
-        solana_transaction_context::{
-            transaction_accounts::TransactionAccount, IndexOfAccount, InstructionAccount,
-        },
-        std::{
-            cell::{Cell, RefCell},
-            mem, ptr,
-            rc::Rc,
-            slice,
-        },
-    };
-
-    macro_rules! mock_invoke_context {
-        ($invoke_context:ident,
-         $transaction_context:ident,
-         $instruction_data:expr,
-         $transaction_accounts:expr,
-         $program_account:expr,
-         $instruction_accounts:expr) => {
-            let instruction_data = $instruction_data;
-            let instruction_accounts = $instruction_accounts
-                .iter()
-                .map(|index_in_transaction| {
-                    InstructionAccount::new(
-                        *index_in_transaction as IndexOfAccount,
-                        false,
-                        $transaction_accounts[*index_in_transaction as usize].2,
-                    )
-                })
-                .collect::<Vec<_>>();
-            let transaction_accounts = $transaction_accounts
-                .into_iter()
-                .map(|a| (a.0, a.1))
-                .collect::<Vec<TransactionAccount>>();
-            let mut feature_set = SVMFeatureSet::all_enabled();
-            feature_set.stricter_abi_and_runtime_constraints = false;
-            let feature_set = &feature_set;
-            with_mock_invoke_context_with_feature_set!(
-                $invoke_context,
-                $transaction_context,
-                feature_set,
-                transaction_accounts
-            );
-            $invoke_context
-                .transaction_context
-                .configure_next_instruction_for_tests(
-                    $program_account,
-                    instruction_accounts,
-                    instruction_data,
-                )
-                .unwrap();
-            $invoke_context.push().unwrap();
-        };
-    }
-
-    #[test]
-    fn test_translate_instruction() {
-        let transaction_accounts =
-            transaction_with_one_writable_instruction_account(b"foo".to_vec());
-        mock_invoke_context!(
-            invoke_context,
-            transaction_context,
-            b"instruction data",
-            transaction_accounts,
-            0,
-            &[1]
-        );
-
-        let program_id = Pubkey::new_unique();
-        let accounts = vec![AccountMeta {
-            pubkey: Pubkey::new_unique(),
-            is_signer: true,
-            is_writable: false,
-        }];
-        let data = b"ins data".to_vec();
-        let vm_addr = MM_INPUT_START;
-        let (_mem, region) = MockInstruction {
+        translate_signers_c(
             program_id,
-            accounts: accounts.clone(),
-            data: data.clone(),
-        }
-        .into_region(vm_addr);
-
-        let config = Config {
-            aligned_memory_mapping: false,
-            ..Config::default()
-        };
-        let memory_mapping = MemoryMapping::new(vec![region], &config, SBPFVersion::V3).unwrap();
-
-        let ins = SyscallInvokeSignedRust::translate_instruction(
-            vm_addr,
-            &memory_mapping,
-            &mut invoke_context,
-            true, // check_aligned
-        )
-        .unwrap();
-        assert_eq!(ins.program_id, program_id);
-        assert_eq!(ins.accounts, accounts);
-        assert_eq!(ins.data, data);
-    }
-
-    #[test]
-    fn test_translate_signers() {
-        let transaction_accounts =
-            transaction_with_one_writable_instruction_account(b"foo".to_vec());
-        mock_invoke_context!(
-            invoke_context,
-            transaction_context,
-            b"instruction data",
-            transaction_accounts,
-            0,
-            &[1]
-        );
-
-        let program_id = Pubkey::new_unique();
-        let (derived_key, bump_seed) = Pubkey::find_program_address(&[b"foo"], &program_id);
-
-        let vm_addr = MM_INPUT_START;
-        let (_mem, region) = mock_signers(&[b"foo", &[bump_seed]], vm_addr);
-
-        let config = Config {
-            aligned_memory_mapping: false,
-            ..Config::default()
-        };
-        let memory_mapping = MemoryMapping::new(vec![region], &config, SBPFVersion::V3).unwrap();
-
-        let signers = SyscallInvokeSignedRust::translate_signers(
-            &program_id,
-            vm_addr,
-            1,
-            &memory_mapping,
-            true, // check_aligned
-        )
-        .unwrap();
-        assert_eq!(signers[0], derived_key);
-    }
-
-    #[test]
-    fn test_translate_accounts_rust() {
-        let transaction_accounts =
-            transaction_with_one_writable_instruction_account(b"foobar".to_vec());
-        let account = transaction_accounts[1].1.clone();
-        let key = transaction_accounts[1].0;
-        let original_data_len = account.data().len();
-
-        let vm_addr = MM_INPUT_START;
-        let (_mem, region, account_metadata) =
-            MockAccountInfo::new(key, &account).into_region(vm_addr);
-
-        let config = Config {
-            aligned_memory_mapping: false,
-            ..Config::default()
-        };
-        let memory_mapping = MemoryMapping::new(vec![region], &config, SBPFVersion::V3).unwrap();
-
-        mock_invoke_context!(
-            invoke_context,
-            transaction_context,
-            b"instruction data",
-            transaction_accounts,
-            0,
-            &[1, 1]
-        );
-
-        invoke_context
-            .set_syscall_context(SyscallContext {
-                allocator: BpfAllocator::new(solana_program_entrypoint::HEAP_LENGTH as u64),
-                accounts_metadata: vec![account_metadata],
-                trace_log: Vec::new(),
-            })
-            .unwrap();
-
-        invoke_context
-            .transaction_context
-            .configure_next_instruction_for_tests(
-                0,
-                vec![
-                    InstructionAccount::new(1, false, true),
-                    InstructionAccount::new(1, false, true),
-                ],
-                &[],
-            )
-            .unwrap();
-        let accounts = SyscallInvokeSignedRust::translate_accounts(
-            vm_addr,
-            1,
-            &memory_mapping,
-            &mut invoke_context,
-            true, // check_aligned
+            signers_seeds_addr,
+            signers_seeds_len,
+            memory_mapping,
+            check_aligned,
         )
-        .unwrap();
-        assert_eq!(accounts.len(), 1);
-        let caller_account = &accounts[0].caller_account;
-        assert_eq!(caller_account.serialized_data, account.data());
-        assert_eq!(caller_account.original_data_len, original_data_len);
-    }
-
-    type TestTransactionAccount = (Pubkey, AccountSharedData, bool);
-
-    fn transaction_with_one_writable_instruction_account(
-        data: Vec<u8>,
-    ) -> Vec<TestTransactionAccount> {
-        let program_id = Pubkey::new_unique();
-        let account = AccountSharedData::from(Account {
-            lamports: 1,
-            data,
-            owner: program_id,
-            executable: false,
-            rent_epoch: 100,
-        });
-        vec![
-            (
-                program_id,
-                AccountSharedData::from(Account {
-                    lamports: 0,
-                    data: vec![],
-                    owner: bpf_loader::id(),
-                    executable: true,
-                    rent_epoch: 0,
-                }),
-                false,
-            ),
-            (Pubkey::new_unique(), account, true),
-        ]
-    }
-
-    struct MockInstruction {
-        program_id: Pubkey,
-        accounts: Vec<AccountMeta>,
-        data: Vec<u8>,
-    }
-
-    impl MockInstruction {
-        fn into_region(self, vm_addr: u64) -> (Vec<u8>, MemoryRegion) {
-            let accounts_len = mem::size_of::<AccountMeta>() * self.accounts.len();
-
-            let size = mem::size_of::<StableInstruction>() + accounts_len + self.data.len();
-
-            let mut data = vec![0; size];
-
-            let vm_addr = vm_addr as usize;
-            let accounts_addr = vm_addr + mem::size_of::<StableInstruction>();
-            let data_addr = accounts_addr + accounts_len;
-
-            let ins = Instruction {
-                program_id: self.program_id,
-                accounts: unsafe {
-                    Vec::from_raw_parts(
-                        accounts_addr as *mut _,
-                        self.accounts.len(),
-                        self.accounts.len(),
-                    )
-                },
-                data: unsafe {
-                    Vec::from_raw_parts(data_addr as *mut _, self.data.len(), self.data.len())
-                },
-            };
-            let ins = StableInstruction::from(ins);
-
-            unsafe {
-                ptr::write_unaligned(data.as_mut_ptr().cast(), ins);
-                data[accounts_addr - vm_addr..][..accounts_len].copy_from_slice(
-                    slice::from_raw_parts(self.accounts.as_ptr().cast(), accounts_len),
-                );
-                data[data_addr - vm_addr..].copy_from_slice(&self.data);
-            }
-
-            let region = MemoryRegion::new_writable(data.as_mut_slice(), vm_addr as u64);
-            (data, region)
-        }
-    }
-
-    fn mock_signers(signers: &[&[u8]], vm_addr: u64) -> (Vec<u8>, MemoryRegion) {
-        let vm_addr = vm_addr as usize;
-
-        // calculate size
-        let fat_ptr_size_of_slice = mem::size_of::<&[()]>(); // pointer size + length size
-        let singers_length = signers.len();
-        let sum_signers_data_length: usize = signers.iter().map(|s| s.len()).sum();
-
-        // init data vec
-        let total_size = fat_ptr_size_of_slice
-            + singers_length * fat_ptr_size_of_slice
-            + sum_signers_data_length;
-        let mut data = vec![0; total_size];
-
-        // data is composed by 3 parts
-        // A.
-        // [ singers address, singers length, ...,
-        // B.                                      |
-        //                                         signer1 address, signer1 length, signer2 address ...,
-        //                                         ^ p1 --->
-        // C.                                                                                           |
-        //                                                                                              signer1 data, signer2 data, ... ]
-        //                                                                                              ^ p2 --->
-
-        // A.
-        data[..fat_ptr_size_of_slice / 2]
-            .clone_from_slice(&(fat_ptr_size_of_slice + vm_addr).to_le_bytes());
-        data[fat_ptr_size_of_slice / 2..fat_ptr_size_of_slice]
-            .clone_from_slice(&(singers_length).to_le_bytes());
-
-        // B. + C.
-        let (mut p1, mut p2) = (
-            fat_ptr_size_of_slice,
-            fat_ptr_size_of_slice + singers_length * fat_ptr_size_of_slice,
-        );
-        for signer in signers.iter() {
-            let signer_length = signer.len();
-
-            // B.
-            data[p1..p1 + fat_ptr_size_of_slice / 2]
-                .clone_from_slice(&(p2 + vm_addr).to_le_bytes());
-            data[p1 + fat_ptr_size_of_slice / 2..p1 + fat_ptr_size_of_slice]
-                .clone_from_slice(&(signer_length).to_le_bytes());
-            p1 += fat_ptr_size_of_slice;
-
-            // C.
-            data[p2..p2 + signer_length].clone_from_slice(signer);
-            p2 += signer_length;
-        }
-
-        let region = MemoryRegion::new_writable(data.as_mut_slice(), vm_addr as u64);
-        (data, region)
-    }
-
-    struct MockAccountInfo<'a> {
-        key: Pubkey,
-        is_signer: bool,
-        is_writable: bool,
-        lamports: u64,
-        data: &'a [u8],
-        owner: Pubkey,
-        executable: bool,
-        _unused: u64,
-    }
-
-    impl MockAccountInfo<'_> {
-        fn new(key: Pubkey, account: &AccountSharedData) -> MockAccountInfo {
-            MockAccountInfo {
-                key,
-                is_signer: false,
-                is_writable: false,
-                lamports: account.lamports(),
-                data: account.data(),
-                owner: *account.owner(),
-                executable: account.executable(),
-                _unused: account.rent_epoch(),
-            }
-        }
-
-        fn into_region(self, vm_addr: u64) -> (Vec<u8>, MemoryRegion, SerializedAccountMetadata) {
-            let size = mem::size_of::<AccountInfo>()
-                + mem::size_of::<Pubkey>() * 2
-                + mem::size_of::<RcBox<RefCell<&mut u64>>>()
-                + mem::size_of::<u64>()
-                + mem::size_of::<RcBox<RefCell<&mut [u8]>>>()
-                + self.data.len();
-            let mut data = vec![0; size];
-
-            let vm_addr = vm_addr as usize;
-            let key_addr = vm_addr + mem::size_of::<AccountInfo>();
-            let lamports_cell_addr = key_addr + mem::size_of::<Pubkey>();
-            let lamports_addr = lamports_cell_addr + mem::size_of::<RcBox<RefCell<&mut u64>>>();
-            let owner_addr = lamports_addr + mem::size_of::<u64>();
-            let data_cell_addr = owner_addr + mem::size_of::<Pubkey>();
-            let data_addr = data_cell_addr + mem::size_of::<RcBox<RefCell<&mut [u8]>>>();
-
-            #[allow(deprecated)]
-            #[allow(clippy::used_underscore_binding)]
-            let info = AccountInfo {
-                key: unsafe { (key_addr as *const Pubkey).as_ref() }.unwrap(),
-                is_signer: self.is_signer,
-                is_writable: self.is_writable,
-                lamports: unsafe {
-                    Rc::from_raw((lamports_cell_addr + RcBox::<&mut u64>::VALUE_OFFSET) as *const _)
-                },
-                data: unsafe {
-                    Rc::from_raw((data_cell_addr + RcBox::<&mut [u8]>::VALUE_OFFSET) as *const _)
-                },
-                owner: unsafe { (owner_addr as *const Pubkey).as_ref() }.unwrap(),
-                executable: self.executable,
-                _unused: self._unused,
-            };
-
-            unsafe {
-                ptr::write_unaligned(data.as_mut_ptr().cast(), info);
-                ptr::write_unaligned(
-                    (data.as_mut_ptr() as usize + key_addr - vm_addr) as *mut _,
-                    self.key,
-                );
-                ptr::write_unaligned(
-                    (data.as_mut_ptr() as usize + lamports_cell_addr - vm_addr) as *mut _,
-                    RcBox::new(RefCell::new((lamports_addr as *mut u64).as_mut().unwrap())),
-                );
-                ptr::write_unaligned(
-                    (data.as_mut_ptr() as usize + lamports_addr - vm_addr) as *mut _,
-                    self.lamports,
-                );
-                ptr::write_unaligned(
-                    (data.as_mut_ptr() as usize + owner_addr - vm_addr) as *mut _,
-                    self.owner,
-                );
-                ptr::write_unaligned(
-                    (data.as_mut_ptr() as usize + data_cell_addr - vm_addr) as *mut _,
-                    RcBox::new(RefCell::new(slice::from_raw_parts_mut(
-                        data_addr as *mut u8,
-                        self.data.len(),
-                    ))),
-                );
-                data[data_addr - vm_addr..].copy_from_slice(self.data);
-            }
-
-            let region = MemoryRegion::new_writable(data.as_mut_slice(), vm_addr as u64);
-            (
-                data,
-                region,
-                SerializedAccountMetadata {
-                    original_data_len: self.data.len(),
-                    vm_key_addr: key_addr as u64,
-                    vm_lamports_addr: lamports_addr as u64,
-                    vm_owner_addr: owner_addr as u64,
-                    vm_data_addr: data_addr as u64,
-                },
-            )
-        }
-    }
-
-    #[repr(C)]
-    struct RcBox<T> {
-        strong: Cell<usize>,
-        weak: Cell<usize>,
-        value: T,
-    }
-
-    impl<T> RcBox<T> {
-        const VALUE_OFFSET: usize = mem::size_of::<Cell<usize>>() * 2;
-        fn new(value: T) -> RcBox<T> {
-            RcBox {
-                strong: Cell::new(0),
-                weak: Cell::new(0),
-                value,
-            }
-        }
     }
 }

+ 1 - 4
syscalls/src/lib.rs

@@ -14,7 +14,6 @@ use solana_program_runtime::memory::translate_vm_slice;
 #[allow(deprecated)]
 use {
     crate::mem_ops::is_nonoverlapping,
-    solana_account_info::AccountInfo,
     solana_big_mod_exp::{big_mod_exp, BigModExpParams},
     solana_blake3_hasher as blake3,
     solana_bn254::prelude::{
@@ -64,9 +63,6 @@ mod logging;
 mod mem_ops;
 mod sysvar;
 
-/// Maximum signers
-const MAX_SIGNERS: usize = 16;
-
 /// Error definitions
 #[derive(Debug, ThisError, PartialEq, Eq)]
 pub enum SyscallError {
@@ -2056,6 +2052,7 @@ mod tests {
         assert_matches::assert_matches,
         core::slice,
         solana_account::{create_account_shared_data_for_test, AccountSharedData},
+        solana_account_info::AccountInfo,
         solana_clock::Clock,
         solana_epoch_rewards::EpochRewards,
         solana_epoch_schedule::EpochSchedule,