Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.

Commit 0c36e4c

Browse files
authored
Adds stable layout types to pass to the runtime (#30192)
1 parent fa22389 commit 0c36e4c

File tree

17 files changed

+423
-35
lines changed

17 files changed

+423
-35
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program-runtime/src/invoke_context.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ use {
1717
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
1818
feature_set::{enable_early_verification_of_account_modifications, FeatureSet},
1919
hash::Hash,
20-
instruction::{AccountMeta, Instruction, InstructionError},
20+
instruction::{AccountMeta, InstructionError},
2121
native_loader,
2222
pubkey::Pubkey,
2323
rent::Rent,
2424
saturating_add_assign,
25+
stable_layout::stable_instruction::StableInstruction,
2526
transaction_context::{
2627
IndexOfAccount, InstructionAccount, TransactionAccount, TransactionContext,
2728
},
@@ -489,7 +490,7 @@ impl<'a> InvokeContext<'a> {
489490
/// Entrypoint for a cross-program invocation from a builtin program
490491
pub fn native_invoke(
491492
&mut self,
492-
instruction: Instruction,
493+
instruction: StableInstruction,
493494
signers: &[Pubkey],
494495
) -> Result<(), InstructionError> {
495496
let (instruction_accounts, program_indices) =
@@ -509,7 +510,7 @@ impl<'a> InvokeContext<'a> {
509510
#[allow(clippy::type_complexity)]
510511
pub fn prepare_instruction(
511512
&mut self,
512-
instruction: &Instruction,
513+
instruction: &StableInstruction,
513514
signers: &[Pubkey],
514515
) -> Result<(Vec<InstructionAccount>, Vec<IndexOfAccount>), InstructionError> {
515516
// Finds the index of each account in the instruction by its pubkey.
@@ -1036,7 +1037,7 @@ mod tests {
10361037
super::*,
10371038
crate::compute_budget,
10381039
serde::{Deserialize, Serialize},
1039-
solana_sdk::account::WritableAccount,
1040+
solana_sdk::{account::WritableAccount, instruction::Instruction},
10401041
};
10411042

10421043
#[derive(Debug, Serialize, Deserialize)]
@@ -1161,7 +1162,7 @@ mod tests {
11611162
assert_eq!(result, Err(InstructionError::UnbalancedInstruction));
11621163
result?;
11631164
invoke_context
1164-
.native_invoke(inner_instruction, &[])
1165+
.native_invoke(inner_instruction.into(), &[])
11651166
.and(invoke_context.pop())?;
11661167
}
11671168
MockInstruction::UnbalancedPop => instruction_context
@@ -1336,7 +1337,7 @@ mod tests {
13361337
let inner_instruction =
13371338
Instruction::new_with_bincode(callee_program_id, &case.0, metas.clone());
13381339
let result = invoke_context
1339-
.native_invoke(inner_instruction, &[])
1340+
.native_invoke(inner_instruction.into(), &[])
13401341
.and(invoke_context.pop());
13411342
assert_eq!(result, case.1);
13421343
}
@@ -1359,6 +1360,7 @@ mod tests {
13591360
},
13601361
metas.clone(),
13611362
);
1363+
let inner_instruction = StableInstruction::from(inner_instruction);
13621364
let (inner_instruction_accounts, program_indices) = invoke_context
13631365
.prepare_instruction(&inner_instruction, &[])
13641366
.unwrap();

program-test/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use {
4040
pubkey::Pubkey,
4141
rent::Rent,
4242
signature::{Keypair, Signer},
43+
stable_layout::stable_instruction::StableInstruction,
4344
sysvar::{Sysvar, SysvarId},
4445
},
4546
solana_vote_program::vote_state::{self, VoteState, VoteStateVersions},
@@ -227,6 +228,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
227228
account_infos: &[AccountInfo],
228229
signers_seeds: &[&[&[u8]]],
229230
) -> ProgramResult {
231+
let instruction = StableInstruction::from(instruction.clone());
230232
let invoke_context = get_invoke_context();
231233
let log_collector = invoke_context.get_log_collector();
232234
let transaction_context = &invoke_context.transaction_context;
@@ -249,7 +251,7 @@ impl solana_sdk::program_stubs::SyscallStubs for SyscallStubs {
249251
.collect::<Vec<_>>();
250252

251253
let (instruction_accounts, program_indices) = invoke_context
252-
.prepare_instruction(instruction, &signers)
254+
.prepare_instruction(&instruction, &signers)
253255
.unwrap();
254256

255257
// Copy caller's account_info modifications into invoke_context accounts

programs/address-lookup-table/src/processor.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -144,18 +144,18 @@ impl Processor {
144144

145145
if required_lamports > 0 {
146146
invoke_context.native_invoke(
147-
system_instruction::transfer(&payer_key, &table_key, required_lamports),
147+
system_instruction::transfer(&payer_key, &table_key, required_lamports).into(),
148148
&[payer_key],
149149
)?;
150150
}
151151

152152
invoke_context.native_invoke(
153-
system_instruction::allocate(&table_key, table_account_data_len as u64),
153+
system_instruction::allocate(&table_key, table_account_data_len as u64).into(),
154154
&[table_key],
155155
)?;
156156

157157
invoke_context.native_invoke(
158-
system_instruction::assign(&table_key, &crate::id()),
158+
system_instruction::assign(&table_key, &crate::id()).into(),
159159
&[table_key],
160160
)?;
161161

@@ -332,7 +332,7 @@ impl Processor {
332332
drop(payer_account);
333333

334334
invoke_context.native_invoke(
335-
system_instruction::transfer(&payer_key, &table_key, required_lamports),
335+
system_instruction::transfer(&payer_key, &table_key, required_lamports).into(),
336336
&[payer_key],
337337
)?;
338338
}

programs/bpf_loader/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ solana-zk-token-sdk = { path = "../../zk-token-sdk", version = "=1.16.0" }
2222
solana_rbpf = "=0.2.38"
2323
thiserror = "1.0"
2424

25+
[dev-dependencies]
26+
memoffset = "0.8"
27+
2528
[lib]
2629
crate-type = ["lib"]
2730
name = "solana_bpf_loader_program"

programs/bpf_loader/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ fn process_loader_upgradeable_instruction(
736736
.iter()
737737
.map(|seeds| Pubkey::create_program_address(seeds, caller_program_id))
738738
.collect::<Result<Vec<Pubkey>, solana_sdk::pubkey::PubkeyError>>()?;
739-
invoke_context.native_invoke(instruction, signers.as_slice())?;
739+
invoke_context.native_invoke(instruction.into(), signers.as_slice())?;
740740

741741
// Load and verify the program bits
742742
let transaction_context = &invoke_context.transaction_context;
@@ -1360,7 +1360,8 @@ fn process_loader_upgradeable_instruction(
13601360
)?;
13611361

13621362
invoke_context.native_invoke(
1363-
system_instruction::transfer(&payer_key, &programdata_key, required_payment),
1363+
system_instruction::transfer(&payer_key, &programdata_key, required_payment)
1364+
.into(),
13641365
&[],
13651366
)?;
13661367
}

programs/bpf_loader/src/syscalls/cpi.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use {
33
crate::declare_syscall,
44
solana_sdk::{
55
feature_set::enable_bpf_loader_set_authority_checked_ix,
6+
stable_layout::stable_instruction::StableInstruction,
67
syscalls::{
78
MAX_CPI_ACCOUNT_INFOS, MAX_CPI_INSTRUCTION_ACCOUNTS, MAX_CPI_INSTRUCTION_DATA_LEN,
89
},
@@ -211,7 +212,7 @@ trait SyscallInvokeSigned {
211212
addr: u64,
212213
memory_mapping: &mut MemoryMapping,
213214
invoke_context: &mut InvokeContext,
214-
) -> Result<Instruction, EbpfError>;
215+
) -> Result<StableInstruction, EbpfError>;
215216
fn translate_accounts<'a>(
216217
instruction_accounts: &[InstructionAccount],
217218
program_indices: &[IndexOfAccount],
@@ -258,8 +259,8 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
258259
addr: u64,
259260
memory_mapping: &mut MemoryMapping,
260261
invoke_context: &mut InvokeContext,
261-
) -> Result<Instruction, EbpfError> {
262-
let ix = translate_type::<Instruction>(
262+
) -> Result<StableInstruction, EbpfError> {
263+
let ix = translate_type::<StableInstruction>(
263264
memory_mapping,
264265
addr,
265266
invoke_context.get_check_aligned(),
@@ -296,10 +297,11 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust {
296297
invoke_context.get_check_size(),
297298
)?
298299
.to_vec();
299-
Ok(Instruction {
300+
301+
Ok(StableInstruction {
302+
accounts: accounts.into(),
303+
data: data.into(),
300304
program_id: ix.program_id,
301-
accounts,
302-
data,
303305
})
304306
}
305307

@@ -469,7 +471,7 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
469471
addr: u64,
470472
memory_mapping: &mut MemoryMapping,
471473
invoke_context: &mut InvokeContext,
472-
) -> Result<Instruction, EbpfError> {
474+
) -> Result<StableInstruction, EbpfError> {
473475
let ix_c = translate_type::<SolInstruction>(
474476
memory_mapping,
475477
addr,
@@ -530,10 +532,10 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC {
530532
})
531533
.collect::<Result<Vec<AccountMeta>, EbpfError>>()?;
532534

533-
Ok(Instruction {
535+
Ok(StableInstruction {
536+
accounts: accounts.into(),
537+
data: data.into(),
534538
program_id: *program_id,
535-
accounts,
536-
data,
537539
})
538540
}
539541

@@ -1128,6 +1130,7 @@ mod tests {
11281130
solana_sdk::{
11291131
account::{Account, AccountSharedData},
11301132
clock::Epoch,
1133+
instruction::Instruction,
11311134
rent::Rent,
11321135
transaction_context::{TransactionAccount, TransactionContext},
11331136
},
@@ -1693,12 +1696,12 @@ mod tests {
16931696
fn into_region(self, vm_addr: u64) -> (Vec<u8>, MemoryRegion) {
16941697
let accounts_len = mem::size_of::<AccountMeta>() * self.accounts.len();
16951698

1696-
let size = mem::size_of::<Instruction>() + accounts_len + self.data.len();
1699+
let size = mem::size_of::<StableInstruction>() + accounts_len + self.data.len();
16971700

16981701
let mut data = vec![0; size];
16991702

17001703
let vm_addr = vm_addr as usize;
1701-
let accounts_addr = vm_addr + mem::size_of::<Instruction>();
1704+
let accounts_addr = vm_addr + mem::size_of::<StableInstruction>();
17021705
let data_addr = accounts_addr + accounts_len;
17031706

17041707
let ins = Instruction {
@@ -1714,6 +1717,7 @@ mod tests {
17141717
Vec::from_raw_parts(data_addr as *mut _, self.data.len(), self.data.len())
17151718
},
17161719
};
1720+
let ins = StableInstruction::from(ins);
17171721

17181722
unsafe {
17191723
ptr::write_unaligned(data.as_mut_ptr().cast(), ins);

programs/bpf_loader/src/syscalls/mod.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use {
4444
},
4545
hash::{Hasher, HASH_BYTES},
4646
instruction::{
47-
AccountMeta, Instruction, InstructionError, ProcessedSiblingInstruction,
47+
AccountMeta, InstructionError, ProcessedSiblingInstruction,
4848
TRANSACTION_LEVEL_STACK_HEIGHT,
4949
},
5050
keccak, native_loader,
@@ -1821,7 +1821,9 @@ mod tests {
18211821
bpf_loader,
18221822
fee_calculator::FeeCalculator,
18231823
hash::hashv,
1824+
instruction::Instruction,
18241825
program::check_type_assumptions,
1826+
stable_layout::stable_instruction::StableInstruction,
18251827
sysvar::{clock::Clock, epoch_schedule::EpochSchedule, rent::Rent},
18261828
transaction_context::TransactionContext,
18271829
},
@@ -1936,17 +1938,18 @@ mod tests {
19361938
&"foobar",
19371939
vec![AccountMeta::new(solana_sdk::pubkey::new_rand(), false)],
19381940
);
1941+
let instruction = StableInstruction::from(instruction);
19391942
let addr = &instruction as *const _ as u64;
19401943
let mut memory_region = MemoryRegion {
19411944
host_addr: addr,
19421945
vm_addr: 0x100000000,
1943-
len: std::mem::size_of::<Instruction>() as u64,
1946+
len: std::mem::size_of::<StableInstruction>() as u64,
19441947
vm_gap_shift: 63,
19451948
is_writable: false,
19461949
};
19471950
let mut memory_mapping = MemoryMapping::new(vec![memory_region.clone()], &config).unwrap();
19481951
let translated_instruction =
1949-
translate_type::<Instruction>(&memory_mapping, 0x100000000, true).unwrap();
1952+
translate_type::<StableInstruction>(&memory_mapping, 0x100000000, true).unwrap();
19501953
assert_eq!(instruction, *translated_instruction);
19511954
memory_region.len = 1;
19521955
let memory_region_index = memory_mapping
@@ -1957,7 +1960,7 @@ mod tests {
19571960
memory_mapping
19581961
.replace_region(memory_region_index, memory_region)
19591962
.unwrap();
1960-
assert!(translate_type::<Instruction>(&memory_mapping, 0x100000000, true).is_err());
1963+
assert!(translate_type::<StableInstruction>(&memory_mapping, 0x100000000, true).is_err());
19611964
}
19621965

19631966
#[test]

sdk/program/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ pub mod serialize_utils;
521521
pub mod short_vec;
522522
pub mod slot_hashes;
523523
pub mod slot_history;
524+
pub mod stable_layout;
524525
pub mod stake;
525526
pub mod stake_history;
526527
pub mod syscalls;

sdk/program/src/program.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
use crate::{
1212
account_info::AccountInfo, entrypoint::ProgramResult, instruction::Instruction, pubkey::Pubkey,
13+
stable_layout::stable_instruction::StableInstruction,
1314
};
1415

1516
/// Invoke a cross-program instruction.
@@ -292,9 +293,10 @@ pub fn invoke_signed_unchecked(
292293
) -> ProgramResult {
293294
#[cfg(target_os = "solana")]
294295
{
296+
let instruction = StableInstruction::from(instruction.clone());
295297
let result = unsafe {
296298
crate::syscalls::sol_invoke_signed_rust(
297-
instruction as *const _ as *const u8,
299+
&instruction as *const _ as *const u8,
298300
account_infos as *const _ as *const u8,
299301
account_infos.len() as u64,
300302
signers_seeds as *const _ as *const u8,
@@ -432,17 +434,18 @@ pub fn check_type_assumptions() {
432434
accounts: vec![account_meta1.clone(), account_meta2.clone()],
433435
data: data.clone(),
434436
};
437+
let instruction = StableInstruction::from(instruction);
435438
let instruction_addr = &instruction as *const _ as u64;
436439

437440
// program id
438-
assert_eq!(offset_of!(Instruction, program_id), 48);
441+
assert_eq!(offset_of!(StableInstruction, program_id), 48);
439442
let pubkey_ptr = (instruction_addr + 48) as *const Pubkey;
440443
unsafe {
441444
assert_eq!(*pubkey_ptr, pubkey1);
442445
}
443446

444447
// accounts
445-
assert_eq!(offset_of!(Instruction, accounts), 0);
448+
assert_eq!(offset_of!(StableInstruction, accounts), 0);
446449
let accounts_ptr = (instruction_addr) as *const *const AccountMeta;
447450
let accounts_cap = (instruction_addr + 8) as *const usize;
448451
let accounts_len = (instruction_addr + 16) as *const usize;
@@ -455,7 +458,7 @@ pub fn check_type_assumptions() {
455458
}
456459

457460
// data
458-
assert_eq!(offset_of!(Instruction, data), 24);
461+
assert_eq!(offset_of!(StableInstruction, data), 24);
459462
let data_ptr = (instruction_addr + 24) as *const *const [u8; 5];
460463
let data_cap = (instruction_addr + 24 + 8) as *const usize;
461464
let data_len = (instruction_addr + 24 + 16) as *const usize;

sdk/program/src/stable_layout.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![doc(hidden)]
2+
//! Types with stable memory layouts
3+
//!
4+
//! Internal use only; here be dragons!
5+
6+
pub mod stable_instruction;
7+
pub mod stable_rc;
8+
pub mod stable_ref_cell;
9+
pub mod stable_slice;
10+
pub mod stable_vec;

0 commit comments

Comments
 (0)