Skip to content

Commit

Permalink
Adds stable layout types to pass to the runtime (solana-labs#30192)
Browse files Browse the repository at this point in the history
  • Loading branch information
brooksprumo authored and nickfrosty committed Mar 12, 2023
1 parent daa2fcd commit 158ea9c
Show file tree
Hide file tree
Showing 17 changed files with 423 additions and 35 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 8 additions & 6 deletions program-runtime/src/invoke_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ use {
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
feature_set::{enable_early_verification_of_account_modifications, FeatureSet},
hash::Hash,
instruction::{AccountMeta, Instruction, InstructionError},
instruction::{AccountMeta, InstructionError},
native_loader,
pubkey::Pubkey,
rent::Rent,
saturating_add_assign,
stable_layout::stable_instruction::StableInstruction,
transaction_context::{
IndexOfAccount, InstructionAccount, TransactionAccount, TransactionContext,
},
Expand Down Expand Up @@ -489,7 +490,7 @@ impl<'a> InvokeContext<'a> {
/// Entrypoint for a cross-program invocation from a builtin program
pub fn native_invoke(
&mut self,
instruction: Instruction,
instruction: StableInstruction,
signers: &[Pubkey],
) -> Result<(), InstructionError> {
let (instruction_accounts, program_indices) =
Expand All @@ -509,7 +510,7 @@ impl<'a> InvokeContext<'a> {
#[allow(clippy::type_complexity)]
pub fn prepare_instruction(
&mut self,
instruction: &Instruction,
instruction: &StableInstruction,
signers: &[Pubkey],
) -> Result<(Vec<InstructionAccount>, Vec<IndexOfAccount>), InstructionError> {
// Finds the index of each account in the instruction by its pubkey.
Expand Down Expand Up @@ -1036,7 +1037,7 @@ mod tests {
super::*,
crate::compute_budget,
serde::{Deserialize, Serialize},
solana_sdk::account::WritableAccount,
solana_sdk::{account::WritableAccount, instruction::Instruction},
};

#[derive(Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -1161,7 +1162,7 @@ mod tests {
assert_eq!(result, Err(InstructionError::UnbalancedInstruction));
result?;
invoke_context
.native_invoke(inner_instruction, &[])
.native_invoke(inner_instruction.into(), &[])
.and(invoke_context.pop())?;
}
MockInstruction::UnbalancedPop => instruction_context
Expand Down Expand Up @@ -1336,7 +1337,7 @@ mod tests {
let inner_instruction =
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
let result = invoke_context
.native_invoke(inner_instruction, &[])
.native_invoke(inner_instruction.into(), &[])
.and(invoke_context.pop());
assert_eq!(result, case.1);
}
Expand All @@ -1359,6 +1360,7 @@ mod tests {
},
metas.clone(),
);
let inner_instruction = StableInstruction::from(inner_instruction);
let (inner_instruction_accounts, program_indices) = invoke_context
.prepare_instruction(&inner_instruction, &[])
.unwrap();
Expand Down
4 changes: 3 additions & 1 deletion program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use {
pubkey::Pubkey,
rent::Rent,
signature::{Keypair, Signer},
stable_layout::stable_instruction::StableInstruction,
sysvar::{Sysvar, SysvarId},
},
solana_vote_program::vote_state::{self, VoteState, VoteStateVersions},
Expand Down Expand Up @@ -227,6 +228,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
account_infos: &[AccountInfo],
signers_seeds: &[&[&[u8]]],
) -> ProgramResult {
let instruction = StableInstruction::from(instruction.clone());
let invoke_context = get_invoke_context();
let log_collector = invoke_context.get_log_collector();
let transaction_context = &invoke_context.transaction_context;
Expand All @@ -249,7 +251,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
.collect::<Vec<_>>();

let (instruction_accounts, program_indices) = invoke_context
.prepare_instruction(instruction, &signers)
.prepare_instruction(&instruction, &signers)
.unwrap();

// Copy caller's account_info modifications into invoke_context accounts
Expand Down
8 changes: 4 additions & 4 deletions programs/address-lookup-table/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,18 +144,18 @@ impl Processor {

if required_lamports > 0 {
invoke_context.native_invoke(
system_instruction::transfer(&payer_key, &table_key, required_lamports),
system_instruction::transfer(&payer_key, &table_key, required_lamports).into(),
&[payer_key],
)?;
}

invoke_context.native_invoke(
system_instruction::allocate(&table_key, table_account_data_len as u64),
system_instruction::allocate(&table_key, table_account_data_len as u64).into(),
&[table_key],
)?;

invoke_context.native_invoke(
system_instruction::assign(&table_key, &crate::id()),
system_instruction::assign(&table_key, &crate::id()).into(),
&[table_key],
)?;

Expand Down Expand Up @@ -332,7 +332,7 @@ impl Processor {
drop(payer_account);

invoke_context.native_invoke(
system_instruction::transfer(&payer_key, &table_key, required_lamports),
system_instruction::transfer(&payer_key, &table_key, required_lamports).into(),
&[payer_key],
)?;
}
Expand Down
3 changes: 3 additions & 0 deletions programs/bpf_loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.16.0" }
solana_rbpf = "=0.2.38"
thiserror = "1.0"

[dev-dependencies]
memoffset = "0.8"

[lib]
crate-type = ["lib"]
name = "solana_bpf_loader_program"
Expand Down
5 changes: 3 additions & 2 deletions programs/bpf_loader/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ fn process_loader_upgradeable_instruction(
.iter()
.map(|seeds| Pubkey::create_program_address(seeds, caller_program_id))
.collect::<Result<Vec<Pubkey>, solana_sdk::pubkey::PubkeyError>>()?;
invoke_context.native_invoke(instruction, signers.as_slice())?;
invoke_context.native_invoke(instruction.into(), signers.as_slice())?;

// Load and verify the program bits
let transaction_context = &invoke_context.transaction_context;
Expand Down Expand Up @@ -1360,7 +1360,8 @@ fn process_loader_upgradeable_instruction(
)?;

invoke_context.native_invoke(
system_instruction::transfer(&payer_key, &programdata_key, required_payment),
system_instruction::transfer(&payer_key, &programdata_key, required_payment)
.into(),
&[],
)?;
}
Expand Down
28 changes: 16 additions & 12 deletions programs/bpf_loader/src/syscalls/cpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use {
crate::declare_syscall,
solana_sdk::{
feature_set::enable_bpf_loader_set_authority_checked_ix,
stable_layout::stable_instruction::StableInstruction,
syscalls::{
MAX_CPI_ACCOUNT_INFOS, MAX_CPI_INSTRUCTION_ACCOUNTS, MAX_CPI_INSTRUCTION_DATA_LEN,
},
Expand Down Expand Up @@ -211,7 +212,7 @@ trait SyscallInvokeSigned {
addr: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<Instruction, EbpfError>;
) -> Result<StableInstruction, EbpfError>;
fn translate_accounts<'a>(
instruction_accounts: &[InstructionAccount],
program_indices: &[IndexOfAccount],
Expand Down Expand Up @@ -258,8 +259,8 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
addr: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<Instruction, EbpfError> {
let ix = translate_type::<Instruction>(
) -> Result<StableInstruction, EbpfError> {
let ix = translate_type::<StableInstruction>(
memory_mapping,
addr,
invoke_context.get_check_aligned(),
Expand Down Expand Up @@ -296,10 +297,11 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
invoke_context.get_check_size(),
)?
.to_vec();
Ok(Instruction {

Ok(StableInstruction {
accounts: accounts.into(),
data: data.into(),
program_id: ix.program_id,
accounts,
data,
})
}

Expand Down Expand Up @@ -469,7 +471,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
addr: u64,
memory_mapping: &mut MemoryMapping,
invoke_context: &mut InvokeContext,
) -> Result<Instruction, EbpfError> {
) -> Result<StableInstruction, EbpfError> {
let ix_c = translate_type::<SolInstruction>(
memory_mapping,
addr,
Expand Down Expand Up @@ -530,10 +532,10 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
})
.collect::<Result<Vec<AccountMeta>, EbpfError>>()?;

Ok(Instruction {
Ok(StableInstruction {
accounts: accounts.into(),
data: data.into(),
program_id: *program_id,
accounts,
data,
})
}

Expand Down Expand Up @@ -1128,6 +1130,7 @@ mod tests {
solana_sdk::{
account::{Account, AccountSharedData},
clock::Epoch,
instruction::Instruction,
rent::Rent,
transaction_context::{TransactionAccount, TransactionContext},
},
Expand Down Expand Up @@ -1693,12 +1696,12 @@ mod tests {
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::<Instruction>() + accounts_len + self.data.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::<Instruction>();
let accounts_addr = vm_addr + mem::size_of::<StableInstruction>();
let data_addr = accounts_addr + accounts_len;

let ins = Instruction {
Expand All @@ -1714,6 +1717,7 @@ mod tests {
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);
Expand Down
11 changes: 7 additions & 4 deletions programs/bpf_loader/src/syscalls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use {
},
hash::{Hasher, HASH_BYTES},
instruction::{
AccountMeta, Instruction, InstructionError, ProcessedSiblingInstruction,
AccountMeta, InstructionError, ProcessedSiblingInstruction,
TRANSACTION_LEVEL_STACK_HEIGHT,
},
keccak, native_loader,
Expand Down Expand Up @@ -1821,7 +1821,9 @@ mod tests {
bpf_loader,
fee_calculator::FeeCalculator,
hash::hashv,
instruction::Instruction,
program::check_type_assumptions,
stable_layout::stable_instruction::StableInstruction,
sysvar::{clock::Clock, epoch_schedule::EpochSchedule, rent::Rent},
transaction_context::TransactionContext,
},
Expand Down Expand Up @@ -1936,17 +1938,18 @@ mod tests {
&"foobar",
vec![AccountMeta::new(solana_sdk::pubkey::new_rand(), false)],
);
let instruction = StableInstruction::from(instruction);
let addr = &instruction as *const _ as u64;
let mut memory_region = MemoryRegion {
host_addr: addr,
vm_addr: 0x100000000,
len: std::mem::size_of::<Instruction>() as u64,
len: std::mem::size_of::<StableInstruction>() as u64,
vm_gap_shift: 63,
is_writable: false,
};
let mut memory_mapping = MemoryMapping::new(vec![memory_region.clone()], &config).unwrap();
let translated_instruction =
translate_type::<Instruction>(&memory_mapping, 0x100000000, true).unwrap();
translate_type::<StableInstruction>(&memory_mapping, 0x100000000, true).unwrap();
assert_eq!(instruction, *translated_instruction);
memory_region.len = 1;
let memory_region_index = memory_mapping
Expand All @@ -1957,7 +1960,7 @@ mod tests {
memory_mapping
.replace_region(memory_region_index, memory_region)
.unwrap();
assert!(translate_type::<Instruction>(&memory_mapping, 0x100000000, true).is_err());
assert!(translate_type::<StableInstruction>(&memory_mapping, 0x100000000, true).is_err());
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions sdk/program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ pub mod serialize_utils;
pub mod short_vec;
pub mod slot_hashes;
pub mod slot_history;
pub mod stable_layout;
pub mod stake;
pub mod stake_history;
pub mod syscalls;
Expand Down
11 changes: 7 additions & 4 deletions sdk/program/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use crate::{
account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, pubkey::Pubkey,
stable_layout::stable_instruction::StableInstruction,
};

/// Invoke a cross-program instruction.
Expand Down Expand Up @@ -292,9 +293,10 @@ pub fn invoke_signed_unchecked(
) -> ProgramResult {
#[cfg(target_os = "solana")]
{
let instruction = StableInstruction::from(instruction.clone());
let result = unsafe {
crate::syscalls::sol_invoke_signed_rust(
instruction as *const _ as *const u8,
&instruction as *const _ as *const u8,
account_infos as *const _ as *const u8,
account_infos.len() as u64,
signers_seeds as *const _ as *const u8,
Expand Down Expand Up @@ -432,17 +434,18 @@ pub fn check_type_assumptions() {
accounts: vec![account_meta1.clone(), account_meta2.clone()],
data: data.clone(),
};
let instruction = StableInstruction::from(instruction);
let instruction_addr = &instruction as *const _ as u64;

// program id
assert_eq!(offset_of!(Instruction, program_id), 48);
assert_eq!(offset_of!(StableInstruction, program_id), 48);
let pubkey_ptr = (instruction_addr + 48) as *const Pubkey;
unsafe {
assert_eq!(*pubkey_ptr, pubkey1);
}

// accounts
assert_eq!(offset_of!(Instruction, accounts), 0);
assert_eq!(offset_of!(StableInstruction, accounts), 0);
let accounts_ptr = (instruction_addr) as *const *const AccountMeta;
let accounts_cap = (instruction_addr + 8) as *const usize;
let accounts_len = (instruction_addr + 16) as *const usize;
Expand All @@ -455,7 +458,7 @@ pub fn check_type_assumptions() {
}

// data
assert_eq!(offset_of!(Instruction, data), 24);
assert_eq!(offset_of!(StableInstruction, data), 24);
let data_ptr = (instruction_addr + 24) as *const *const [u8; 5];
let data_cap = (instruction_addr + 24 + 8) as *const usize;
let data_len = (instruction_addr + 24 + 16) as *const usize;
Expand Down
10 changes: 10 additions & 0 deletions sdk/program/src/stable_layout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![doc(hidden)]
//! Types with stable memory layouts
//!
//! Internal use only; here be dragons!
pub mod stable_instruction;
pub mod stable_rc;
pub mod stable_ref_cell;
pub mod stable_slice;
pub mod stable_vec;
Loading

0 comments on commit 158ea9c

Please sign in to comment.