diff --git a/core/src/validator.rs b/core/src/validator.rs index be30f05e02..8b3d1dd9fb 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -863,9 +863,6 @@ impl TestValidator { genesis_config .native_instruction_processors .push(solana_bpf_loader_program!()); - genesis_config - .native_instruction_processors - .push(solana_bpf_loader_deprecated_program!()); genesis_config.rent.lamports_per_byte_year = 1; genesis_config.rent.exemption_threshold = 1.0; diff --git a/genesis-programs/src/lib.rs b/genesis-programs/src/lib.rs index 86d2935d38..ca951cee03 100644 --- a/genesis-programs/src/lib.rs +++ b/genesis-programs/src/lib.rs @@ -36,8 +36,9 @@ pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option match epoch { // No inflation at epoch 0 0 => Some(Inflation::new_disabled()), - // Inflation starts The epoch of Epoch::MAX is a placeholder and is - // expected to be reduced in a future hard fork. + // Inflation starts + // The epoch of Epoch::MAX is a placeholder and is expected to be reduced in + // a future hard fork. Epoch::MAX => Some(Inflation::default()), _ => None, }, @@ -48,36 +49,38 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option { if epoch == 0 { - // Programs used for testing Some(vec![ + // Enable all Stable programs solana_bpf_loader_program!(), - solana_bpf_loader_deprecated_program!(), solana_vest_program!(), + // Programs that are only available in Development mode solana_budget_program!(), solana_exchange_program!(), ]) - } else if epoch == std::u64::MAX { - // The epoch of std::u64::MAX is a placeholder and is expected - // to be reduced in a future network update. - Some(vec![solana_bpf_loader_program!()]) } else { None } } OperatingMode::Stable => { - if epoch == std::u64::MAX { - // The epoch of std::u64::MAX is a placeholder and is expected - // to be reduced in a future network update. - Some(vec![solana_bpf_loader_program!(), solana_vest_program!()]) + if epoch == std::u64::MAX - 1 { + // The epoch of std::u64::MAX - 1 is a placeholder and is expected to be reduced in + // a future hard fork. + Some(vec![solana_bpf_loader_program!()]) + } else if epoch == std::u64::MAX { + // The epoch of std::u64::MAX is a placeholder and is expected to be reduced in a + // future hard fork. + Some(vec![solana_vest_program!()]) } else { None } } OperatingMode::Preview => { - if epoch == std::u64::MAX { - // The epoch of std::u64::MAX is a placeholder and is expected - // to be reduced in a future network update. - Some(vec![solana_bpf_loader_program!(), solana_vest_program!()]) + if epoch == 0 { + Some(vec![solana_bpf_loader_program!()]) + } else if epoch == std::u64::MAX { + // The epoch of std::u64::MAX is a placeholder and is expected to be reduced in a + // future hard fork. + Some(vec![solana_vest_program!()]) } else { None } @@ -135,7 +138,7 @@ mod tests { fn test_development_programs() { assert_eq!( get_programs(OperatingMode::Development, 0).unwrap().len(), - 5 + 4 ); assert_eq!(get_programs(OperatingMode::Development, 1), None); } @@ -156,6 +159,7 @@ mod tests { #[test] fn test_softlaunch_programs() { assert_eq!(get_programs(OperatingMode::Stable, 1), None); + assert!(get_programs(OperatingMode::Stable, std::u64::MAX - 1).is_some()); assert!(get_programs(OperatingMode::Stable, std::u64::MAX).is_some()); } } diff --git a/local-cluster/tests/local_cluster.rs b/local-cluster/tests/local_cluster.rs index 07f1adc3e6..2da53aca94 100644 --- a/local-cluster/tests/local_cluster.rs +++ b/local-cluster/tests/local_cluster.rs @@ -562,13 +562,7 @@ fn test_stable_operating_mode() { } // Programs that are not available at epoch 0 - for program_id in [ - &solana_sdk::bpf_loader::id(), - &solana_sdk::bpf_loader_deprecated::id(), - &solana_vest_program::id(), - ] - .iter() - { + for program_id in [&solana_sdk::bpf_loader::id(), &solana_vest_program::id()].iter() { assert_eq!( ( program_id, diff --git a/programs/bpf/c/src/invoked/invoked.c b/programs/bpf/c/src/invoked/invoked.c index db6473f826..3e72256a60 100644 --- a/programs/bpf/c/src/invoked/invoked.c +++ b/programs/bpf/c/src/invoked/invoked.c @@ -23,11 +23,6 @@ extern uint64_t entrypoint(const uint8_t *input) { sol_assert(sol_deserialize(input, ¶ms, 4)); SolPubkey bpf_loader_id = - (SolPubkey){.x = {2, 168, 246, 145, 78, 136, 161, 110, 57, 90, 225, - 40, 148, 143, 250, 105, 86, 147, 55, 104, 24, 221, - 71, 67, 82, 33, 243, 198, 0, 0, 0, 0}}; - - SolPubkey bpf_loader_deprecated_id = (SolPubkey){.x = {2, 168, 246, 145, 78, 136, 161, 107, 189, 35, 149, 133, 95, 100, 4, 217, 180, 244, 86, 183, 130, 27, 176, 20, 87, 73, 66, 140, 0, 0, 0, 0}}; diff --git a/programs/bpf_loader/src/deprecated.rs b/programs/bpf_loader/src/deprecated.rs deleted file mode 100644 index b2564c9ad1..0000000000 --- a/programs/bpf_loader/src/deprecated.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::process_instruction; - -solana_sdk::declare_loader!( - solana_sdk::bpf_loader_deprecated::ID, - solana_bpf_loader_deprecated_program, - process_instruction, - solana_bpf_loader_program, - deprecated::id -); diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index eb3d01ac2a..90553572d4 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -1,15 +1,10 @@ pub mod alloc; pub mod allocator_bump; pub mod bpf_verifier; -pub mod deprecated; -pub mod serialization; pub mod syscalls; -use crate::{ - bpf_verifier::VerifierError, - serialization::{deserialize_parameters, serialize_parameters}, - syscalls::SyscallError, -}; +use crate::{bpf_verifier::VerifierError, syscalls::SyscallError}; +use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; use num_derive::{FromPrimitive, ToPrimitive}; use solana_rbpf::{ ebpf::{EbpfError, UserDefinedError}, @@ -18,7 +13,7 @@ use solana_rbpf::{ }; use solana_sdk::{ account::{is_executable, next_keyed_account, KeyedAccount}, - bpf_loader, bpf_loader_deprecated, + bpf_loader, decode_error::DecodeError, entrypoint::SUCCESS, entrypoint_native::InvokeContext, @@ -27,13 +22,13 @@ use solana_sdk::{ program_utils::limited_deserialize, pubkey::Pubkey, }; +use std::{io::prelude::*, mem}; use thiserror::Error; solana_sdk::declare_loader!( solana_sdk::bpf_loader::ID, solana_bpf_loader_program, - process_instruction, - solana_bpf_loader_program + process_instruction ); #[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)] @@ -91,6 +86,75 @@ pub fn is_dup(accounts: &[KeyedAccount], keyed_account: &KeyedAccount) -> (bool, (false, 0) } +pub fn serialize_parameters( + program_id: &Pubkey, + keyed_accounts: &[KeyedAccount], + data: &[u8], +) -> Result, InstructionError> { + assert_eq!(32, mem::size_of::()); + + let mut v: Vec = Vec::new(); + v.write_u64::(keyed_accounts.len() as u64) + .unwrap(); + for (i, keyed_account) in keyed_accounts.iter().enumerate() { + let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account); + if is_dup { + v.write_u8(position as u8).unwrap(); + } else { + v.write_u8(std::u8::MAX).unwrap(); + v.write_u8(keyed_account.signer_key().is_some() as u8) + .unwrap(); + v.write_u8(keyed_account.is_writable() as u8).unwrap(); + v.write_all(keyed_account.unsigned_key().as_ref()).unwrap(); + v.write_u64::(keyed_account.lamports()?) + .unwrap(); + v.write_u64::(keyed_account.data_len()? as u64) + .unwrap(); + v.write_all(&keyed_account.try_account_ref()?.data).unwrap(); + v.write_all(keyed_account.owner()?.as_ref()).unwrap(); + v.write_u8(keyed_account.executable()? as u8).unwrap(); + v.write_u64::(keyed_account.rent_epoch()? as u64) + .unwrap(); + } + } + v.write_u64::(data.len() as u64).unwrap(); + v.write_all(data).unwrap(); + v.write_all(program_id.as_ref()).unwrap(); + Ok(v) +} + +pub fn deserialize_parameters( + keyed_accounts: &[KeyedAccount], + buffer: &[u8], +) -> Result<(), InstructionError> { + assert_eq!(32, mem::size_of::()); + + let mut start = mem::size_of::(); // number of accounts + for (i, keyed_account) in keyed_accounts.iter().enumerate() { + let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account); + start += 1; // is_dup + if !is_dup { + start += mem::size_of::(); // is_signer + start += mem::size_of::(); // is_writable + start += mem::size_of::(); // pubkey + keyed_account.try_account_ref_mut()?.lamports = + LittleEndian::read_u64(&buffer[start..]); + start += mem::size_of::() // lamports + + mem::size_of::(); // data length + let end = start + keyed_account.data_len()?; + keyed_account + .try_account_ref_mut()? + .data + .clone_from_slice(&buffer[start..end]); + start += keyed_account.data_len()? // data + + mem::size_of::() // owner + + mem::size_of::() // executable + + mem::size_of::(); // rent_epoch + } + } + Ok(()) +} + macro_rules! log{ ($logger:ident, $message:expr) => { if let Ok(mut logger) = $logger.try_borrow_mut() { @@ -112,7 +176,7 @@ pub fn process_instruction( instruction_data: &[u8], invoke_context: &mut dyn InvokeContext, ) -> Result<(), InstructionError> { - debug_assert!(bpf_loader::check_id(program_id) || bpf_loader_deprecated::check_id(program_id)); + debug_assert!(bpf_loader::check_id(program_id)); let logger = invoke_context.get_logger(); @@ -127,7 +191,6 @@ pub fn process_instruction( let parameter_accounts = keyed_accounts_iter.as_slice(); let parameter_bytes = serialize_parameters( - program_id, program.unsigned_key(), parameter_accounts, &instruction_data, @@ -173,7 +236,7 @@ pub fn process_instruction( } } } - deserialize_parameters(program_id, parameter_accounts, ¶meter_bytes)?; + deserialize_parameters(parameter_accounts, ¶meter_bytes)?; log!(logger, "BPF program {} success", program.unsigned_key()); } else if !keyed_accounts.is_empty() { match limited_deserialize(instruction_data)? { @@ -286,7 +349,6 @@ mod tests { // Ensure that we can invoke this macro from the same crate // where it is defined. solana_bpf_loader_program!(); - solana_bpf_loader_deprecated_program!(); } #[test] @@ -376,7 +438,7 @@ mod tests { fn test_bpf_loader_finalize() { let program_id = Pubkey::new_rand(); let program_key = Pubkey::new_rand(); - let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed"); + let mut file = File::open("test_elfs/noop.so").expect("file open failed"); let mut elf = Vec::new(); let rent = Rent::default(); file.read_to_end(&mut elf).unwrap(); @@ -442,7 +504,7 @@ mod tests { let program_key = Pubkey::new_rand(); // Create program account - let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed"); + let mut file = File::open("test_elfs/noop.so").expect("file open failed"); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); let program_account = Account::new_ref(1, 0, &program_id); @@ -516,94 +578,6 @@ mod tests { ); } - #[test] - fn test_bpf_loader_serialize_unaligned() { - let program_id = Pubkey::new_rand(); - let program_key = Pubkey::new_rand(); - - // Create program account - let mut file = File::open("test_elfs/noop_unaligned.so").expect("file open failed"); - let mut elf = Vec::new(); - file.read_to_end(&mut elf).unwrap(); - let program_account = Account::new_ref(1, 0, &program_id); - program_account.borrow_mut().data = elf; - program_account.borrow_mut().executable = true; - let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)]; - - // Case: With program and parameter account - let parameter_account = Account::new_ref(1, 0, &program_id); - keyed_accounts.push(KeyedAccount::new(&program_key, false, ¶meter_account)); - assert_eq!( - Ok(()), - process_instruction( - &bpf_loader_deprecated::id(), - &keyed_accounts, - &[], - &mut MockInvokeContext::default() - ) - ); - - // Case: With duplicate accounts - let duplicate_key = Pubkey::new_rand(); - let parameter_account = Account::new_ref(1, 0, &program_id); - let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)]; - keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_account)); - keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_account)); - assert_eq!( - Ok(()), - process_instruction( - &bpf_loader_deprecated::id(), - &keyed_accounts, - &[], - &mut MockInvokeContext::default() - ) - ); - } - - #[test] - fn test_bpf_loader_serialize_aligned() { - let program_id = Pubkey::new_rand(); - let program_key = Pubkey::new_rand(); - - // Create program account - let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed"); - let mut elf = Vec::new(); - file.read_to_end(&mut elf).unwrap(); - let program_account = Account::new_ref(1, 0, &program_id); - program_account.borrow_mut().data = elf; - program_account.borrow_mut().executable = true; - let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)]; - - // Case: With program and parameter account - let parameter_account = Account::new_ref(1, 0, &program_id); - keyed_accounts.push(KeyedAccount::new(&program_key, false, ¶meter_account)); - assert_eq!( - Ok(()), - process_instruction( - &bpf_loader::id(), - &keyed_accounts, - &[], - &mut MockInvokeContext::default() - ) - ); - - // Case: With duplicate accounts - let duplicate_key = Pubkey::new_rand(); - let parameter_account = Account::new_ref(1, 0, &program_id); - let mut keyed_accounts = vec![KeyedAccount::new(&program_key, false, &program_account)]; - keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_account)); - keyed_accounts.push(KeyedAccount::new(&duplicate_key, false, ¶meter_account)); - assert_eq!( - Ok(()), - process_instruction( - &bpf_loader::id(), - &keyed_accounts, - &[], - &mut MockInvokeContext::default() - ) - ); - } - /// fuzzing utility function fn fuzz( bytes: &[u8], @@ -634,7 +608,7 @@ mod tests { let program_key = Pubkey::new_rand(); // Create program account - let mut file = File::open("test_elfs/noop_aligned.so").expect("file open failed"); + let mut file = File::open("test_elfs/noop.so").expect("file open failed"); let mut elf = Vec::new(); file.read_to_end(&mut elf).unwrap(); diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs deleted file mode 100644 index 87137efa1a..0000000000 --- a/programs/bpf_loader/src/serialization.rs +++ /dev/null @@ -1,410 +0,0 @@ -use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; -use solana_sdk::{ - account::KeyedAccount, bpf_loader_deprecated, instruction::InstructionError, pubkey::Pubkey, -}; -use std::{ - io::prelude::*, - mem::{self, align_of}, -}; - -/// Look for a duplicate account and return its position if found -pub fn is_dup(accounts: &[KeyedAccount], keyed_account: &KeyedAccount) -> (bool, usize) { - for (i, account) in accounts.iter().enumerate() { - if account == keyed_account { - return (true, i); - } - } - (false, 0) -} - -pub fn serialize_parameters( - loader_id: &Pubkey, - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - data: &[u8], -) -> Result, InstructionError> { - if *loader_id == bpf_loader_deprecated::id() { - serialize_parameters_unaligned(program_id, keyed_accounts, data) - } else { - serialize_parameters_aligned(program_id, keyed_accounts, data) - } -} - -pub fn deserialize_parameters( - loader_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - buffer: &[u8], -) -> Result<(), InstructionError> { - if *loader_id == bpf_loader_deprecated::id() { - deserialize_parameters_unaligned(keyed_accounts, buffer) - } else { - deserialize_parameters_aligned(keyed_accounts, buffer) - } -} - -pub fn serialize_parameters_unaligned( - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - instruction_data: &[u8], -) -> Result, InstructionError> { - assert_eq!(32, mem::size_of::()); - - let mut v: Vec = Vec::new(); - v.write_u64::(keyed_accounts.len() as u64) - .unwrap(); - for (i, keyed_account) in keyed_accounts.iter().enumerate() { - let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account); - if is_dup { - v.write_u8(position as u8).unwrap(); - } else { - v.write_u8(std::u8::MAX).unwrap(); - v.write_u8(keyed_account.signer_key().is_some() as u8) - .unwrap(); - v.write_u8(keyed_account.is_writable() as u8).unwrap(); - v.write_all(keyed_account.unsigned_key().as_ref()).unwrap(); - v.write_u64::(keyed_account.lamports()?) - .unwrap(); - v.write_u64::(keyed_account.data_len()? as u64) - .unwrap(); - v.write_all(&keyed_account.try_account_ref()?.data).unwrap(); - v.write_all(keyed_account.owner()?.as_ref()).unwrap(); - v.write_u8(keyed_account.executable()? as u8).unwrap(); - v.write_u64::(keyed_account.rent_epoch()? as u64) - .unwrap(); - } - } - v.write_u64::(instruction_data.len() as u64) - .unwrap(); - v.write_all(instruction_data).unwrap(); - v.write_all(program_id.as_ref()).unwrap(); - Ok(v) -} - -pub fn deserialize_parameters_unaligned( - keyed_accounts: &[KeyedAccount], - buffer: &[u8], -) -> Result<(), InstructionError> { - assert_eq!(32, mem::size_of::()); - - let mut start = mem::size_of::(); // number of accounts - for (i, keyed_account) in keyed_accounts.iter().enumerate() { - let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account); - start += 1; // is_dup - if !is_dup { - start += mem::size_of::(); // is_signer - start += mem::size_of::(); // is_writable - start += mem::size_of::(); // pubkey - keyed_account.try_account_ref_mut()?.lamports = - LittleEndian::read_u64(&buffer[start..]); - start += mem::size_of::() // lamports - + mem::size_of::(); // data length - let end = start + keyed_account.data_len()?; - keyed_account - .try_account_ref_mut()? - .data - .clone_from_slice(&buffer[start..end]); - start += keyed_account.data_len()? // data - + mem::size_of::() // owner - + mem::size_of::() // executable - + mem::size_of::(); // rent_epoch - } - } - Ok(()) -} - -pub fn serialize_parameters_aligned( - program_id: &Pubkey, - keyed_accounts: &[KeyedAccount], - instruction_data: &[u8], -) -> Result, InstructionError> { - assert_eq!(32, mem::size_of::()); - - // TODO use with capacity would be nice, but don't know account data sizes... - let mut v: Vec = Vec::new(); - v.write_u64::(keyed_accounts.len() as u64) - .unwrap(); - - // TODO panic? - if v.as_ptr().align_offset(align_of::()) != 0 { - panic!(); - } - for (i, keyed_account) in keyed_accounts.iter().enumerate() { - let (is_dup, position) = is_dup(&keyed_accounts[..i], keyed_account); - if is_dup { - v.write_u8(position as u8).unwrap(); - v.write_all(&[0u8, 0, 0, 0, 0, 0, 0]).unwrap(); // 7 bytes of padding to make 64-bit aligned - } else { - v.write_u8(std::u8::MAX).unwrap(); - v.write_u8(keyed_account.signer_key().is_some() as u8) - .unwrap(); - v.write_u8(keyed_account.is_writable() as u8).unwrap(); - v.write_u8(keyed_account.executable()? as u8).unwrap(); - v.write_all(&[0u8, 0, 0, 0]).unwrap(); // 4 bytes of padding to make 128-bit aligned - v.write_all(keyed_account.unsigned_key().as_ref()).unwrap(); - v.write_all(keyed_account.owner()?.as_ref()).unwrap(); - v.write_u64::(keyed_account.lamports()?) - .unwrap(); - v.write_u64::(keyed_account.data_len()? as u64) - .unwrap(); - v.write_all(&keyed_account.try_account_ref()?.data).unwrap(); - for _ in 0..16 - (v.len() % 16) { - v.write_u8(0).unwrap(); // 128 bit aligned again - } - v.write_u64::(keyed_account.rent_epoch()? as u64) - .unwrap(); - } - } - v.write_u64::(instruction_data.len() as u64) - .unwrap(); - v.write_all(instruction_data).unwrap(); - v.write_all(program_id.as_ref()).unwrap(); - Ok(v) -} - -pub fn deserialize_parameters_aligned( - keyed_accounts: &[KeyedAccount], - buffer: &[u8], -) -> Result<(), InstructionError> { - assert_eq!(32, mem::size_of::()); - - let mut start = mem::size_of::(); // number of accounts - for (i, keyed_account) in keyed_accounts.iter().enumerate() { - let (is_dup, _) = is_dup(&keyed_accounts[..i], keyed_account); - start += 1; // is_dup - if !is_dup { - start += mem::size_of::() // is_signer - + mem::size_of::() // is_writable - + mem::size_of::() // executable - + 4 // padding - + mem::size_of::() // pubkey - + mem::size_of::(); // owner - keyed_account.try_account_ref_mut()?.lamports = - LittleEndian::read_u64(&buffer[start..]); - start += mem::size_of::() // lamports - + mem::size_of::(); // data length - let end = start + keyed_account.data_len()?; - keyed_account - .try_account_ref_mut()? - .data - .clone_from_slice(&buffer[start..end]); - start += keyed_account.data_len()?; // data - start += 16 - (start % 16); // padding - start += mem::size_of::(); // rent_epoch - } else { - start += 7; // padding - } - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use solana_sdk::{ - account::Account, account_info::AccountInfo, bpf_loader, entrypoint::deserialize, - }; - use std::{ - cell::RefCell, - mem::size_of, - rc::Rc, - // Hide Result from bindgen gets confused about generics in non-generic type declarations - slice::{from_raw_parts, from_raw_parts_mut}, - }; - - #[test] - fn test_serialize_parameters() { - let program_id = Pubkey::new_rand(); - let dup_key = Pubkey::new_rand(); - let keys = vec![dup_key, dup_key, Pubkey::new_rand(), Pubkey::new_rand()]; - let accounts = [ - RefCell::new(Account { - lamports: 1, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }), - // dup of first - RefCell::new(Account { - lamports: 1, - data: vec![1u8, 2, 3, 4, 5], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 100, - }), - RefCell::new(Account { - lamports: 2, - data: vec![11u8, 12, 13, 14, 15, 16, 17, 18, 19], - owner: bpf_loader::id(), - executable: true, - rent_epoch: 200, - }), - RefCell::new(Account { - lamports: 3, - data: vec![], - owner: bpf_loader::id(), - executable: false, - rent_epoch: 3100, - }), - ]; - - let keyed_accounts: Vec<_> = keys - .iter() - .zip(&accounts) - .map(|(key, account)| KeyedAccount::new(&key, false, &account)) - .collect(); - let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; - - // check serialize_parameters_aligned - - let mut serialized = serialize_parameters( - &bpf_loader::id(), - &program_id, - &keyed_accounts, - &instruction_data, - ) - .unwrap(); - let (de_program_id, de_accounts, de_instruction_data) = - unsafe { deserialize(&mut serialized[0] as *mut u8) }; - - assert_eq!(&program_id, de_program_id); - assert_eq!(instruction_data, de_instruction_data); - assert_eq!( - (&de_instruction_data[0] as *const u8).align_offset(align_of::()), - 0 - ); - for ((account, account_info), key) in accounts.iter().zip(de_accounts).zip(keys.clone()) { - assert_eq!(key, *account_info.key); - let account = account.borrow(); - assert_eq!(account.lamports, account_info.lamports()); - assert_eq!(&account.data[..], &account_info.data.borrow()[..]); - assert_eq!(&account.owner, account_info.owner); - assert_eq!(account.executable, account_info.executable); - assert_eq!(account.rent_epoch, account_info.rent_epoch); - - assert_eq!( - (*account_info.lamports.borrow() as *const u64).align_offset(align_of::()), - 0 - ); - assert_eq!( - account_info - .data - .borrow() - .as_ptr() - .align_offset(align_of::()), - 0 - ); - } - - // check serialize_parameters_unaligned - - let mut serialized = serialize_parameters( - &bpf_loader_deprecated::id(), - &program_id, - &keyed_accounts, - &instruction_data, - ) - .unwrap(); - let (de_program_id, de_accounts, de_instruction_data) = - unsafe { deserialize_unaligned(&mut serialized[0] as *mut u8) }; - - assert_eq!(&program_id, de_program_id); - assert_eq!(instruction_data, de_instruction_data); - for ((account, account_info), key) in accounts.iter().zip(de_accounts).zip(keys) { - assert_eq!(key, *account_info.key); - let account = account.borrow(); - assert_eq!(account.lamports, account_info.lamports()); - assert_eq!(&account.data[..], &account_info.data.borrow()[..]); - assert_eq!(&account.owner, account_info.owner); - assert_eq!(account.executable, account_info.executable); - assert_eq!(account.rent_epoch, account_info.rent_epoch); - } - } - - // the old bpf_loader in-program deserializer bpf_loader::id() - #[allow(clippy::type_complexity)] - pub unsafe fn deserialize_unaligned<'a>( - input: *mut u8, - ) -> (&'a Pubkey, Vec>, &'a [u8]) { - let mut offset: usize = 0; - - // number of accounts present - - #[allow(clippy::cast_ptr_alignment)] - let num_accounts = *(input.add(offset) as *const u64) as usize; - offset += size_of::(); - - // account Infos - - let mut accounts = Vec::with_capacity(num_accounts); - for _ in 0..num_accounts { - let dup_info = *(input.add(offset) as *const u8); - offset += size_of::(); - if dup_info == std::u8::MAX { - #[allow(clippy::cast_ptr_alignment)] - let is_signer = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let is_writable = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - let key: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64))); - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let data_len = *(input.add(offset) as *const u64) as usize; - offset += size_of::(); - - let data = Rc::new(RefCell::new({ - from_raw_parts_mut(input.add(offset), data_len) - })); - offset += data_len; - - let owner: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let executable = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - #[allow(clippy::cast_ptr_alignment)] - let rent_epoch = *(input.add(offset) as *const u64); - offset += size_of::(); - - accounts.push(AccountInfo { - is_signer, - is_writable, - key, - lamports, - data, - owner, - executable, - rent_epoch, - }); - } else { - // duplicate account, clone the original - accounts.push(accounts[dup_info as usize].clone()); - } - } - - // instruction data - - #[allow(clippy::cast_ptr_alignment)] - let instruction_data_len = *(input.add(offset) as *const u64) as usize; - offset += size_of::(); - - let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) }; - offset += instruction_data_len; - - // program Id - - let program_id: &Pubkey = &*(input.add(offset) as *const Pubkey); - - (program_id, accounts, instruction_data) - } -} diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 51d7f8e445..b2adc123ef 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -50,8 +50,6 @@ pub enum SyscallError { InstructionError(InstructionError), #[error("Cross-program invocation with unauthorized signer or writable account")] PrivilegeEscalation, - #[error("Unaligned pointer")] - UnalignedPointer, } impl From for EbpfError { fn from(error: SyscallError) -> Self { @@ -143,24 +141,20 @@ macro_rules! translate { #[macro_export] macro_rules! translate_type_mut { - ($t:ty, $vm_addr:expr, $regions:expr) => {{ - if ($vm_addr as u64 as *mut $t).align_offset(align_of::<$t>()) != 0 { - Err(SyscallError::UnalignedPointer.into()) - } else { - unsafe { - match translate_addr::( - $vm_addr as u64, - size_of::<$t>(), - file!(), - line!() as usize - ELF_INSN_DUMP_OFFSET + 1, - $regions, - ) { - Ok(value) => Ok(&mut *(value as *mut $t)), - Err(e) => Err(e), - } + ($t:ty, $vm_addr:expr, $regions:expr) => { + unsafe { + match translate_addr::( + $vm_addr as u64, + size_of::<$t>(), + file!(), + line!() as usize - ELF_INSN_DUMP_OFFSET + 1, + $regions, + ) { + Ok(value) => Ok(&mut *(value as *mut $t)), + Err(e) => Err(e), } } - }}; + }; } #[macro_export] macro_rules! translate_type { @@ -174,22 +168,18 @@ macro_rules! translate_type { #[macro_export] macro_rules! translate_slice_mut { - ($t:ty, $vm_addr:expr, $len: expr, $regions:expr) => {{ - if ($vm_addr as u64 as *mut $t).align_offset(align_of::<$t>()) != 0 { - Err(SyscallError::UnalignedPointer.into()) - } else { - match translate_addr::( - $vm_addr as u64, - $len as usize * size_of::<$t>(), - file!(), - line!() as usize - ELF_INSN_DUMP_OFFSET + 1, - $regions, - ) { - Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut $t, $len as usize) }), - Err(e) => Err(e), - } + ($t:ty, $vm_addr:expr, $len: expr, $regions:expr) => { + match translate_addr::( + $vm_addr as u64, + $len as usize * size_of::<$t>(), + file!(), + line!() as usize - ELF_INSN_DUMP_OFFSET + 1, + $regions, + ) { + Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut $t, $len as usize) }), + Err(e) => Err(e), } - }}; + }; } #[macro_export] macro_rules! translate_slice { @@ -469,7 +459,7 @@ impl<'a> SyscallProcessInstruction<'a> for SyscallProcessInstructionRust<'a> { let lamports_ref = { // Double translate lamports out of RefCell let ptr = translate_type!(u64, account_info.lamports.as_ptr(), ro_regions)?; - translate_type_mut!(u64, *ptr, rw_regions)? + translate_type_mut!(u64, *(ptr as *const u64), rw_regions)? }; let data = { // Double translate data out of RefCell @@ -931,17 +921,13 @@ mod tests { vec![AccountMeta::new(Pubkey::new_rand(), false)], ); let addr = &instruction as *const _ as u64; - let mut regions = vec![MemoryRegion { + let regions = vec![MemoryRegion { addr_host: addr, - addr_vm: 96, + addr_vm: 100, len: std::mem::size_of::() as u64, }]; - let translated_instruction = translate_type!(Instruction, 96, ®ions).unwrap(); + let translated_instruction = translate_type!(Instruction, 100, ®ions).unwrap(); assert_eq!(instruction, *translated_instruction); - regions[0].len = 1; - assert!(translate_type!(Instruction, 100, ®ions).is_err()); - regions[0].len = std::mem::size_of::() as u64 * 2; - assert!(translate_type!(Instruction, 100, ®ions).is_err()); } #[test] diff --git a/programs/bpf_loader/test_elfs/noop_unaligned.so b/programs/bpf_loader/test_elfs/noop.so similarity index 100% rename from programs/bpf_loader/test_elfs/noop_unaligned.so rename to programs/bpf_loader/test_elfs/noop.so diff --git a/programs/bpf_loader/test_elfs/noop_aligned.so b/programs/bpf_loader/test_elfs/noop_aligned.so deleted file mode 100755 index 28bbdc0980..0000000000 Binary files a/programs/bpf_loader/test_elfs/noop_aligned.so and /dev/null differ diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index f9c9c2ad59..305a8b4aa6 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -290,15 +290,12 @@ static bool sol_deserialize( if (dup_info == UINT8_MAX) { input += sizeof(uint8_t); input += sizeof(uint8_t); + input += sizeof(SolPubkey); + input += sizeof(uint64_t); + input += *(uint64_t *) input; + input += sizeof(uint64_t); + input += sizeof(SolPubkey); input += sizeof(uint8_t); - input += 4; // padding - input += sizeof(SolPubkey); - input += sizeof(SolPubkey); - input += sizeof(uint64_t); - uint64_t data_len = *(uint64_t *) input; - input += sizeof(uint64_t); - input += data_len; - input += 16 - (data_len % 16); // padding input += sizeof(uint64_t); } continue; @@ -312,20 +309,10 @@ static bool sol_deserialize( params->ka[i].is_writable = *(uint8_t *) input != 0; input += sizeof(uint8_t); - // executable? - params->ka[i].executable = *(uint8_t *) input; - input += sizeof(uint8_t); - - input += 4; // padding - // key params->ka[i].key = (SolPubkey *) input; input += sizeof(SolPubkey); - // owner - params->ka[i].owner = (SolPubkey *) input; - input += sizeof(SolPubkey); - // lamports params->ka[i].lamports = (uint64_t *) input; input += sizeof(uint64_t); @@ -336,22 +323,26 @@ static bool sol_deserialize( params->ka[i].data = (uint8_t *) input; input += params->ka[i].data_len; - input += 16 - (params->ka[i].data_len % 16); // padding + // owner + params->ka[i].owner = (SolPubkey *) input; + input += sizeof(SolPubkey); + + // executable? + params->ka[i].executable = *(uint8_t *) input; + input += sizeof(uint8_t); // rent epoch params->ka[i].rent_epoch = *(uint64_t *) input; input += sizeof(uint64_t); } else { params->ka[i].is_signer = params->ka[dup_info].is_signer; - params->ka[i].is_writable = params->ka[dup_info].is_writable; - params->ka[i].executable = params->ka[dup_info].executable; params->ka[i].key = params->ka[dup_info].key; - params->ka[i].owner = params->ka[dup_info].owner; params->ka[i].lamports = params->ka[dup_info].lamports; params->ka[i].data_len = params->ka[dup_info].data_len; params->ka[i].data = params->ka[dup_info].data; + params->ka[i].owner = params->ka[dup_info].owner; + params->ka[i].executable = params->ka[dup_info].executable; params->ka[i].rent_epoch = params->ka[dup_info].rent_epoch; - input += 7; // padding } } diff --git a/sdk/src/bpf_loader.rs b/sdk/src/bpf_loader.rs index cf6fa767b9..33461caa0a 100644 --- a/sdk/src/bpf_loader.rs +++ b/sdk/src/bpf_loader.rs @@ -1 +1 @@ -crate::declare_id!("BPFLoader2111111111111111111111111111111111"); +crate::declare_id!("BPFLoader1111111111111111111111111111111111"); diff --git a/sdk/src/bpf_loader_deprecated.rs b/sdk/src/bpf_loader_deprecated.rs deleted file mode 100644 index 33461caa0a..0000000000 --- a/sdk/src/bpf_loader_deprecated.rs +++ /dev/null @@ -1 +0,0 @@ -crate::declare_id!("BPFLoader1111111111111111111111111111111111"); diff --git a/sdk/src/entrypoint.rs b/sdk/src/entrypoint.rs index 6be53a323d..5bc7da2ab3 100644 --- a/sdk/src/entrypoint.rs +++ b/sdk/src/entrypoint.rs @@ -76,18 +76,9 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec(); - #[allow(clippy::cast_ptr_alignment)] - let executable = *(input.add(offset) as *const u8) != 0; - offset += size_of::(); - - offset += 4; // padding - let key: &Pubkey = &*(input.add(offset) as *const Pubkey); offset += size_of::(); - let owner: &Pubkey = &*(input.add(offset) as *const Pubkey); - offset += size_of::(); - #[allow(clippy::cast_ptr_alignment)] let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64))); offset += size_of::(); @@ -101,7 +92,12 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec(); + + #[allow(clippy::cast_ptr_alignment)] + let executable = *(input.add(offset) as *const u8) != 0; + offset += size_of::(); #[allow(clippy::cast_ptr_alignment)] let rent_epoch = *(input.add(offset) as *const u64); @@ -118,8 +114,6 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec { + ($name:ident) => { #[macro_export] macro_rules! $name { () => { @@ -66,8 +66,8 @@ macro_rules! declare_name { // `respan!` respans the path `$crate::id`, which we then call (hence the extra // parens) ( - stringify!($filename).to_string(), - ::solana_sdk::respan!($crate::$id, $name)(), + stringify!($name).to_string(), + ::solana_sdk::respan!($crate::id, $name)(), ) }; } @@ -77,11 +77,11 @@ macro_rules! declare_name { #[rustversion::not(since(1.46.0))] #[macro_export] macro_rules! declare_name { - ($name:ident, $filename:ident, $id:path) => { + ($name:ident) => { #[macro_export] macro_rules! $name { () => { - (stringify!($filename).to_string(), $crate::$id()) + (stringify!($name).to_string(), $crate::id()) }; } }; @@ -90,10 +90,8 @@ macro_rules! declare_name { /// Convenience macro to declare a native program /// /// bs58_string: bs58 string representation the program's id -/// name: Name of the program -/// filename: must match the library name in Cargo.toml +/// name: Name of the program, must match the library name in Cargo.toml /// entrypoint: Program's entrypoint, must be of `type Entrypoint` -/// id: Path to the program id access function, used if not called in `src/lib` /// /// # Examples /// @@ -161,7 +159,7 @@ macro_rules! declare_name { macro_rules! declare_program( ($bs58_string:expr, $name:ident, $entrypoint:expr) => ( $crate::declare_id!($bs58_string); - $crate::declare_name!($name, $name, id); + $crate::declare_name!($name); #[no_mangle] pub extern "C" fn $name( @@ -176,16 +174,12 @@ macro_rules! declare_program( /// Same as declare_program but for native loaders #[macro_export] -macro_rules! declare_loader { - ($bs58_string:expr, $name:ident, $entrypoint:expr) => { - $crate::declare_loader!($bs58_string, $name, $entrypoint, $name, id); - }; - ($bs58_string:expr, $name:ident, $entrypoint:expr, $filename:ident) => { - $crate::declare_loader!($bs58_string, $name, $entrypoint, $filename, id); - }; - ($bs58_string:expr, $name:ident, $entrypoint:expr, $filename:ident, $id:path) => { +macro_rules! declare_loader( + ($bs58_string:expr, $name:ident, $entrypoint:expr) => ( $crate::declare_id!($bs58_string); - $crate::declare_name!($name, $filename, $id); + $crate::declare_name!($name); + + #[no_mangle] pub extern "C" fn $name( @@ -196,8 +190,8 @@ macro_rules! declare_loader { ) -> Result<(), $crate::instruction::InstructionError> { $entrypoint(program_id, keyed_accounts, instruction_data, invoke_context) } - }; -} + ) +); pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>; diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 68d791710b..cdc28eb5f3 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -6,7 +6,6 @@ extern crate self as solana_sdk; pub mod account; pub mod account_utils; pub mod bpf_loader; -pub mod bpf_loader_deprecated; pub mod clock; pub mod commitment_config; pub mod decode_error;