This reverts commit 3296c13ef2
.
This commit is contained in:
@ -863,9 +863,6 @@ impl TestValidator {
|
|||||||
genesis_config
|
genesis_config
|
||||||
.native_instruction_processors
|
.native_instruction_processors
|
||||||
.push(solana_bpf_loader_program!());
|
.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.lamports_per_byte_year = 1;
|
||||||
genesis_config.rent.exemption_threshold = 1.0;
|
genesis_config.rent.exemption_threshold = 1.0;
|
||||||
|
@ -36,8 +36,9 @@ pub fn get_inflation(operating_mode: OperatingMode, epoch: Epoch) -> Option<Infl
|
|||||||
OperatingMode::Stable => match epoch {
|
OperatingMode::Stable => match epoch {
|
||||||
// No inflation at epoch 0
|
// No inflation at epoch 0
|
||||||
0 => Some(Inflation::new_disabled()),
|
0 => Some(Inflation::new_disabled()),
|
||||||
// Inflation starts The epoch of Epoch::MAX is a placeholder and is
|
// Inflation starts
|
||||||
// expected to be reduced in a future hard fork.
|
// The epoch of Epoch::MAX is a placeholder and is expected to be reduced in
|
||||||
|
// a future hard fork.
|
||||||
Epoch::MAX => Some(Inflation::default()),
|
Epoch::MAX => Some(Inflation::default()),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
@ -48,36 +49,38 @@ pub fn get_programs(operating_mode: OperatingMode, epoch: Epoch) -> Option<Vec<(
|
|||||||
match operating_mode {
|
match operating_mode {
|
||||||
OperatingMode::Development => {
|
OperatingMode::Development => {
|
||||||
if epoch == 0 {
|
if epoch == 0 {
|
||||||
// Programs used for testing
|
|
||||||
Some(vec![
|
Some(vec![
|
||||||
|
// Enable all Stable programs
|
||||||
solana_bpf_loader_program!(),
|
solana_bpf_loader_program!(),
|
||||||
solana_bpf_loader_deprecated_program!(),
|
|
||||||
solana_vest_program!(),
|
solana_vest_program!(),
|
||||||
|
// Programs that are only available in Development mode
|
||||||
solana_budget_program!(),
|
solana_budget_program!(),
|
||||||
solana_exchange_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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperatingMode::Stable => {
|
OperatingMode::Stable => {
|
||||||
if epoch == std::u64::MAX {
|
if epoch == std::u64::MAX - 1 {
|
||||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
// The epoch of std::u64::MAX - 1 is a placeholder and is expected to be reduced in
|
||||||
// to be reduced in a future network update.
|
// a future hard fork.
|
||||||
Some(vec![solana_bpf_loader_program!(), solana_vest_program!()])
|
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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OperatingMode::Preview => {
|
OperatingMode::Preview => {
|
||||||
if epoch == std::u64::MAX {
|
if epoch == 0 {
|
||||||
// The epoch of std::u64::MAX is a placeholder and is expected
|
Some(vec![solana_bpf_loader_program!()])
|
||||||
// to be reduced in a future network update.
|
} else if epoch == std::u64::MAX {
|
||||||
Some(vec![solana_bpf_loader_program!(), solana_vest_program!()])
|
// 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 {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -135,7 +138,7 @@ mod tests {
|
|||||||
fn test_development_programs() {
|
fn test_development_programs() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
get_programs(OperatingMode::Development, 0).unwrap().len(),
|
get_programs(OperatingMode::Development, 0).unwrap().len(),
|
||||||
5
|
4
|
||||||
);
|
);
|
||||||
assert_eq!(get_programs(OperatingMode::Development, 1), None);
|
assert_eq!(get_programs(OperatingMode::Development, 1), None);
|
||||||
}
|
}
|
||||||
@ -156,6 +159,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_softlaunch_programs() {
|
fn test_softlaunch_programs() {
|
||||||
assert_eq!(get_programs(OperatingMode::Stable, 1), None);
|
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());
|
assert!(get_programs(OperatingMode::Stable, std::u64::MAX).is_some());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -562,13 +562,7 @@ fn test_stable_operating_mode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Programs that are not available at epoch 0
|
// Programs that are not available at epoch 0
|
||||||
for program_id in [
|
for program_id in [&solana_sdk::bpf_loader::id(), &solana_vest_program::id()].iter() {
|
||||||
&solana_sdk::bpf_loader::id(),
|
|
||||||
&solana_sdk::bpf_loader_deprecated::id(),
|
|
||||||
&solana_vest_program::id(),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
{
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
(
|
(
|
||||||
program_id,
|
program_id,
|
||||||
|
@ -23,11 +23,6 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||||||
sol_assert(sol_deserialize(input, ¶ms, 4));
|
sol_assert(sol_deserialize(input, ¶ms, 4));
|
||||||
|
|
||||||
SolPubkey bpf_loader_id =
|
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,
|
(SolPubkey){.x = {2, 168, 246, 145, 78, 136, 161, 107, 189, 35, 149,
|
||||||
133, 95, 100, 4, 217, 180, 244, 86, 183, 130, 27,
|
133, 95, 100, 4, 217, 180, 244, 86, 183, 130, 27,
|
||||||
176, 20, 87, 73, 66, 140, 0, 0, 0, 0}};
|
176, 20, 87, 73, 66, 140, 0, 0, 0, 0}};
|
||||||
|
@ -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
|
|
||||||
);
|
|
@ -1,15 +1,10 @@
|
|||||||
pub mod alloc;
|
pub mod alloc;
|
||||||
pub mod allocator_bump;
|
pub mod allocator_bump;
|
||||||
pub mod bpf_verifier;
|
pub mod bpf_verifier;
|
||||||
pub mod deprecated;
|
|
||||||
pub mod serialization;
|
|
||||||
pub mod syscalls;
|
pub mod syscalls;
|
||||||
|
|
||||||
use crate::{
|
use crate::{bpf_verifier::VerifierError, syscalls::SyscallError};
|
||||||
bpf_verifier::VerifierError,
|
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
|
||||||
serialization::{deserialize_parameters, serialize_parameters},
|
|
||||||
syscalls::SyscallError,
|
|
||||||
};
|
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use solana_rbpf::{
|
use solana_rbpf::{
|
||||||
ebpf::{EbpfError, UserDefinedError},
|
ebpf::{EbpfError, UserDefinedError},
|
||||||
@ -18,7 +13,7 @@ use solana_rbpf::{
|
|||||||
};
|
};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{is_executable, next_keyed_account, KeyedAccount},
|
account::{is_executable, next_keyed_account, KeyedAccount},
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader,
|
||||||
decode_error::DecodeError,
|
decode_error::DecodeError,
|
||||||
entrypoint::SUCCESS,
|
entrypoint::SUCCESS,
|
||||||
entrypoint_native::InvokeContext,
|
entrypoint_native::InvokeContext,
|
||||||
@ -27,13 +22,13 @@ use solana_sdk::{
|
|||||||
program_utils::limited_deserialize,
|
program_utils::limited_deserialize,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
};
|
};
|
||||||
|
use std::{io::prelude::*, mem};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
solana_sdk::declare_loader!(
|
solana_sdk::declare_loader!(
|
||||||
solana_sdk::bpf_loader::ID,
|
solana_sdk::bpf_loader::ID,
|
||||||
solana_bpf_loader_program,
|
solana_bpf_loader_program,
|
||||||
process_instruction,
|
process_instruction
|
||||||
solana_bpf_loader_program
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
|
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
|
||||||
@ -91,6 +86,75 @@ pub fn is_dup(accounts: &[KeyedAccount], keyed_account: &KeyedAccount) -> (bool,
|
|||||||
(false, 0)
|
(false, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialize_parameters(
|
||||||
|
program_id: &Pubkey,
|
||||||
|
keyed_accounts: &[KeyedAccount],
|
||||||
|
data: &[u8],
|
||||||
|
) -> Result<Vec<u8>, InstructionError> {
|
||||||
|
assert_eq!(32, mem::size_of::<Pubkey>());
|
||||||
|
|
||||||
|
let mut v: Vec<u8> = Vec::new();
|
||||||
|
v.write_u64::<LittleEndian>(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::<LittleEndian>(keyed_account.lamports()?)
|
||||||
|
.unwrap();
|
||||||
|
v.write_u64::<LittleEndian>(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::<LittleEndian>(keyed_account.rent_epoch()? as u64)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v.write_u64::<LittleEndian>(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::<Pubkey>());
|
||||||
|
|
||||||
|
let mut start = mem::size_of::<u64>(); // 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::<u8>(); // is_signer
|
||||||
|
start += mem::size_of::<u8>(); // is_writable
|
||||||
|
start += mem::size_of::<Pubkey>(); // pubkey
|
||||||
|
keyed_account.try_account_ref_mut()?.lamports =
|
||||||
|
LittleEndian::read_u64(&buffer[start..]);
|
||||||
|
start += mem::size_of::<u64>() // lamports
|
||||||
|
+ mem::size_of::<u64>(); // 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::<Pubkey>() // owner
|
||||||
|
+ mem::size_of::<u8>() // executable
|
||||||
|
+ mem::size_of::<u64>(); // rent_epoch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! log{
|
macro_rules! log{
|
||||||
($logger:ident, $message:expr) => {
|
($logger:ident, $message:expr) => {
|
||||||
if let Ok(mut logger) = $logger.try_borrow_mut() {
|
if let Ok(mut logger) = $logger.try_borrow_mut() {
|
||||||
@ -112,7 +176,7 @@ pub fn process_instruction(
|
|||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
invoke_context: &mut dyn InvokeContext,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> 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();
|
let logger = invoke_context.get_logger();
|
||||||
|
|
||||||
@ -127,7 +191,6 @@ pub fn process_instruction(
|
|||||||
|
|
||||||
let parameter_accounts = keyed_accounts_iter.as_slice();
|
let parameter_accounts = keyed_accounts_iter.as_slice();
|
||||||
let parameter_bytes = serialize_parameters(
|
let parameter_bytes = serialize_parameters(
|
||||||
program_id,
|
|
||||||
program.unsigned_key(),
|
program.unsigned_key(),
|
||||||
parameter_accounts,
|
parameter_accounts,
|
||||||
&instruction_data,
|
&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());
|
log!(logger, "BPF program {} success", program.unsigned_key());
|
||||||
} else if !keyed_accounts.is_empty() {
|
} else if !keyed_accounts.is_empty() {
|
||||||
match limited_deserialize(instruction_data)? {
|
match limited_deserialize(instruction_data)? {
|
||||||
@ -286,7 +349,6 @@ mod tests {
|
|||||||
// Ensure that we can invoke this macro from the same crate
|
// Ensure that we can invoke this macro from the same crate
|
||||||
// where it is defined.
|
// where it is defined.
|
||||||
solana_bpf_loader_program!();
|
solana_bpf_loader_program!();
|
||||||
solana_bpf_loader_deprecated_program!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -376,7 +438,7 @@ mod tests {
|
|||||||
fn test_bpf_loader_finalize() {
|
fn test_bpf_loader_finalize() {
|
||||||
let program_id = Pubkey::new_rand();
|
let program_id = Pubkey::new_rand();
|
||||||
let program_key = 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 mut elf = Vec::new();
|
||||||
let rent = Rent::default();
|
let rent = Rent::default();
|
||||||
file.read_to_end(&mut elf).unwrap();
|
file.read_to_end(&mut elf).unwrap();
|
||||||
@ -442,7 +504,7 @@ mod tests {
|
|||||||
let program_key = Pubkey::new_rand();
|
let program_key = Pubkey::new_rand();
|
||||||
|
|
||||||
// Create program account
|
// 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();
|
let mut elf = Vec::new();
|
||||||
file.read_to_end(&mut elf).unwrap();
|
file.read_to_end(&mut elf).unwrap();
|
||||||
let program_account = Account::new_ref(1, 0, &program_id);
|
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
|
/// fuzzing utility function
|
||||||
fn fuzz<F>(
|
fn fuzz<F>(
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
@ -634,7 +608,7 @@ mod tests {
|
|||||||
let program_key = Pubkey::new_rand();
|
let program_key = Pubkey::new_rand();
|
||||||
|
|
||||||
// Create program account
|
// 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();
|
let mut elf = Vec::new();
|
||||||
file.read_to_end(&mut elf).unwrap();
|
file.read_to_end(&mut elf).unwrap();
|
||||||
|
|
||||||
|
@ -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<Vec<u8>, 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<Vec<u8>, InstructionError> {
|
|
||||||
assert_eq!(32, mem::size_of::<Pubkey>());
|
|
||||||
|
|
||||||
let mut v: Vec<u8> = Vec::new();
|
|
||||||
v.write_u64::<LittleEndian>(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::<LittleEndian>(keyed_account.lamports()?)
|
|
||||||
.unwrap();
|
|
||||||
v.write_u64::<LittleEndian>(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::<LittleEndian>(keyed_account.rent_epoch()? as u64)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v.write_u64::<LittleEndian>(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::<Pubkey>());
|
|
||||||
|
|
||||||
let mut start = mem::size_of::<u64>(); // 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::<u8>(); // is_signer
|
|
||||||
start += mem::size_of::<u8>(); // is_writable
|
|
||||||
start += mem::size_of::<Pubkey>(); // pubkey
|
|
||||||
keyed_account.try_account_ref_mut()?.lamports =
|
|
||||||
LittleEndian::read_u64(&buffer[start..]);
|
|
||||||
start += mem::size_of::<u64>() // lamports
|
|
||||||
+ mem::size_of::<u64>(); // 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::<Pubkey>() // owner
|
|
||||||
+ mem::size_of::<u8>() // executable
|
|
||||||
+ mem::size_of::<u64>(); // rent_epoch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn serialize_parameters_aligned(
|
|
||||||
program_id: &Pubkey,
|
|
||||||
keyed_accounts: &[KeyedAccount],
|
|
||||||
instruction_data: &[u8],
|
|
||||||
) -> Result<Vec<u8>, InstructionError> {
|
|
||||||
assert_eq!(32, mem::size_of::<Pubkey>());
|
|
||||||
|
|
||||||
// TODO use with capacity would be nice, but don't know account data sizes...
|
|
||||||
let mut v: Vec<u8> = Vec::new();
|
|
||||||
v.write_u64::<LittleEndian>(keyed_accounts.len() as u64)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// TODO panic?
|
|
||||||
if v.as_ptr().align_offset(align_of::<u128>()) != 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::<LittleEndian>(keyed_account.lamports()?)
|
|
||||||
.unwrap();
|
|
||||||
v.write_u64::<LittleEndian>(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::<LittleEndian>(keyed_account.rent_epoch()? as u64)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v.write_u64::<LittleEndian>(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::<Pubkey>());
|
|
||||||
|
|
||||||
let mut start = mem::size_of::<u64>(); // 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::<u8>() // is_signer
|
|
||||||
+ mem::size_of::<u8>() // is_writable
|
|
||||||
+ mem::size_of::<u8>() // executable
|
|
||||||
+ 4 // padding
|
|
||||||
+ mem::size_of::<Pubkey>() // pubkey
|
|
||||||
+ mem::size_of::<Pubkey>(); // owner
|
|
||||||
keyed_account.try_account_ref_mut()?.lamports =
|
|
||||||
LittleEndian::read_u64(&buffer[start..]);
|
|
||||||
start += mem::size_of::<u64>() // lamports
|
|
||||||
+ mem::size_of::<u64>(); // 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::<u64>(); // 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::<u128>()),
|
|
||||||
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::<u64>()),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
account_info
|
|
||||||
.data
|
|
||||||
.borrow()
|
|
||||||
.as_ptr()
|
|
||||||
.align_offset(align_of::<u128>()),
|
|
||||||
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<AccountInfo<'a>>, &'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::<u64>();
|
|
||||||
|
|
||||||
// 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::<u8>();
|
|
||||||
if dup_info == std::u8::MAX {
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
let is_signer = *(input.add(offset) as *const u8) != 0;
|
|
||||||
offset += size_of::<u8>();
|
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
let is_writable = *(input.add(offset) as *const u8) != 0;
|
|
||||||
offset += size_of::<u8>();
|
|
||||||
|
|
||||||
let key: &Pubkey = &*(input.add(offset) as *const Pubkey);
|
|
||||||
offset += size_of::<Pubkey>();
|
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64)));
|
|
||||||
offset += size_of::<u64>();
|
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
let data_len = *(input.add(offset) as *const u64) as usize;
|
|
||||||
offset += size_of::<u64>();
|
|
||||||
|
|
||||||
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::<Pubkey>();
|
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
let executable = *(input.add(offset) as *const u8) != 0;
|
|
||||||
offset += size_of::<u8>();
|
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
let rent_epoch = *(input.add(offset) as *const u64);
|
|
||||||
offset += size_of::<u64>();
|
|
||||||
|
|
||||||
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::<u64>();
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -50,8 +50,6 @@ pub enum SyscallError {
|
|||||||
InstructionError(InstructionError),
|
InstructionError(InstructionError),
|
||||||
#[error("Cross-program invocation with unauthorized signer or writable account")]
|
#[error("Cross-program invocation with unauthorized signer or writable account")]
|
||||||
PrivilegeEscalation,
|
PrivilegeEscalation,
|
||||||
#[error("Unaligned pointer")]
|
|
||||||
UnalignedPointer,
|
|
||||||
}
|
}
|
||||||
impl From<SyscallError> for EbpfError<BPFError> {
|
impl From<SyscallError> for EbpfError<BPFError> {
|
||||||
fn from(error: SyscallError) -> Self {
|
fn from(error: SyscallError) -> Self {
|
||||||
@ -143,10 +141,7 @@ macro_rules! translate {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! translate_type_mut {
|
macro_rules! translate_type_mut {
|
||||||
($t:ty, $vm_addr:expr, $regions:expr) => {{
|
($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 {
|
unsafe {
|
||||||
match translate_addr::<BPFError>(
|
match translate_addr::<BPFError>(
|
||||||
$vm_addr as u64,
|
$vm_addr as u64,
|
||||||
@ -159,8 +154,7 @@ macro_rules! translate_type_mut {
|
|||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! translate_type {
|
macro_rules! translate_type {
|
||||||
@ -174,10 +168,7 @@ macro_rules! translate_type {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! translate_slice_mut {
|
macro_rules! translate_slice_mut {
|
||||||
($t:ty, $vm_addr:expr, $len: expr, $regions:expr) => {{
|
($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::<BPFError>(
|
match translate_addr::<BPFError>(
|
||||||
$vm_addr as u64,
|
$vm_addr as u64,
|
||||||
$len as usize * size_of::<$t>(),
|
$len as usize * size_of::<$t>(),
|
||||||
@ -188,8 +179,7 @@ macro_rules! translate_slice_mut {
|
|||||||
Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut $t, $len as usize) }),
|
Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut $t, $len as usize) }),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! translate_slice {
|
macro_rules! translate_slice {
|
||||||
@ -469,7 +459,7 @@ impl<'a> SyscallProcessInstruction<'a> for SyscallProcessInstructionRust<'a> {
|
|||||||
let lamports_ref = {
|
let lamports_ref = {
|
||||||
// Double translate lamports out of RefCell
|
// Double translate lamports out of RefCell
|
||||||
let ptr = translate_type!(u64, account_info.lamports.as_ptr(), ro_regions)?;
|
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 = {
|
let data = {
|
||||||
// Double translate data out of RefCell
|
// Double translate data out of RefCell
|
||||||
@ -931,17 +921,13 @@ mod tests {
|
|||||||
vec![AccountMeta::new(Pubkey::new_rand(), false)],
|
vec![AccountMeta::new(Pubkey::new_rand(), false)],
|
||||||
);
|
);
|
||||||
let addr = &instruction as *const _ as u64;
|
let addr = &instruction as *const _ as u64;
|
||||||
let mut regions = vec![MemoryRegion {
|
let regions = vec![MemoryRegion {
|
||||||
addr_host: addr,
|
addr_host: addr,
|
||||||
addr_vm: 96,
|
addr_vm: 100,
|
||||||
len: std::mem::size_of::<Instruction>() as u64,
|
len: std::mem::size_of::<Instruction>() 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);
|
assert_eq!(instruction, *translated_instruction);
|
||||||
regions[0].len = 1;
|
|
||||||
assert!(translate_type!(Instruction, 100, ®ions).is_err());
|
|
||||||
regions[0].len = std::mem::size_of::<Instruction>() as u64 * 2;
|
|
||||||
assert!(translate_type!(Instruction, 100, ®ions).is_err());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Binary file not shown.
@ -290,15 +290,12 @@ static bool sol_deserialize(
|
|||||||
if (dup_info == UINT8_MAX) {
|
if (dup_info == UINT8_MAX) {
|
||||||
input += sizeof(uint8_t);
|
input += sizeof(uint8_t);
|
||||||
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 += 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);
|
input += sizeof(uint64_t);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -312,20 +309,10 @@ static bool sol_deserialize(
|
|||||||
params->ka[i].is_writable = *(uint8_t *) input != 0;
|
params->ka[i].is_writable = *(uint8_t *) input != 0;
|
||||||
input += sizeof(uint8_t);
|
input += sizeof(uint8_t);
|
||||||
|
|
||||||
// executable?
|
|
||||||
params->ka[i].executable = *(uint8_t *) input;
|
|
||||||
input += sizeof(uint8_t);
|
|
||||||
|
|
||||||
input += 4; // padding
|
|
||||||
|
|
||||||
// key
|
// key
|
||||||
params->ka[i].key = (SolPubkey *) input;
|
params->ka[i].key = (SolPubkey *) input;
|
||||||
input += sizeof(SolPubkey);
|
input += sizeof(SolPubkey);
|
||||||
|
|
||||||
// owner
|
|
||||||
params->ka[i].owner = (SolPubkey *) input;
|
|
||||||
input += sizeof(SolPubkey);
|
|
||||||
|
|
||||||
// lamports
|
// lamports
|
||||||
params->ka[i].lamports = (uint64_t *) input;
|
params->ka[i].lamports = (uint64_t *) input;
|
||||||
input += sizeof(uint64_t);
|
input += sizeof(uint64_t);
|
||||||
@ -336,22 +323,26 @@ static bool sol_deserialize(
|
|||||||
params->ka[i].data = (uint8_t *) input;
|
params->ka[i].data = (uint8_t *) input;
|
||||||
input += params->ka[i].data_len;
|
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
|
// rent epoch
|
||||||
params->ka[i].rent_epoch = *(uint64_t *) input;
|
params->ka[i].rent_epoch = *(uint64_t *) input;
|
||||||
input += sizeof(uint64_t);
|
input += sizeof(uint64_t);
|
||||||
} else {
|
} else {
|
||||||
params->ka[i].is_signer = params->ka[dup_info].is_signer;
|
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].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].lamports = params->ka[dup_info].lamports;
|
||||||
params->ka[i].data_len = params->ka[dup_info].data_len;
|
params->ka[i].data_len = params->ka[dup_info].data_len;
|
||||||
params->ka[i].data = params->ka[dup_info].data;
|
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;
|
params->ka[i].rent_epoch = params->ka[dup_info].rent_epoch;
|
||||||
input += 7; // padding
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
crate::declare_id!("BPFLoader2111111111111111111111111111111111");
|
crate::declare_id!("BPFLoader1111111111111111111111111111111111");
|
||||||
|
@ -1 +0,0 @@
|
|||||||
crate::declare_id!("BPFLoader1111111111111111111111111111111111");
|
|
@ -76,18 +76,9 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec<AccountInfo<'a
|
|||||||
let is_writable = *(input.add(offset) as *const u8) != 0;
|
let is_writable = *(input.add(offset) as *const u8) != 0;
|
||||||
offset += size_of::<u8>();
|
offset += size_of::<u8>();
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
|
||||||
let executable = *(input.add(offset) as *const u8) != 0;
|
|
||||||
offset += size_of::<u8>();
|
|
||||||
|
|
||||||
offset += 4; // padding
|
|
||||||
|
|
||||||
let key: &Pubkey = &*(input.add(offset) as *const Pubkey);
|
let key: &Pubkey = &*(input.add(offset) as *const Pubkey);
|
||||||
offset += size_of::<Pubkey>();
|
offset += size_of::<Pubkey>();
|
||||||
|
|
||||||
let owner: &Pubkey = &*(input.add(offset) as *const Pubkey);
|
|
||||||
offset += size_of::<Pubkey>();
|
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64)));
|
let lamports = Rc::new(RefCell::new(&mut *(input.add(offset) as *mut u64)));
|
||||||
offset += size_of::<u64>();
|
offset += size_of::<u64>();
|
||||||
@ -101,7 +92,12 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec<AccountInfo<'a
|
|||||||
}));
|
}));
|
||||||
offset += data_len;
|
offset += data_len;
|
||||||
|
|
||||||
offset += 16 - (offset % 16); // padding
|
let owner: &Pubkey = &*(input.add(offset) as *const Pubkey);
|
||||||
|
offset += size_of::<Pubkey>();
|
||||||
|
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
let executable = *(input.add(offset) as *const u8) != 0;
|
||||||
|
offset += size_of::<u8>();
|
||||||
|
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
let rent_epoch = *(input.add(offset) as *const u64);
|
let rent_epoch = *(input.add(offset) as *const u64);
|
||||||
@ -118,8 +114,6 @@ pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a Pubkey, Vec<AccountInfo<'a
|
|||||||
rent_epoch,
|
rent_epoch,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
offset += 7; // padding
|
|
||||||
|
|
||||||
// Duplicate account, clone the original
|
// Duplicate account, clone the original
|
||||||
accounts.push(accounts[dup_info as usize].clone());
|
accounts.push(accounts[dup_info as usize].clone());
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ pub type LoaderEntrypoint = unsafe extern "C" fn(
|
|||||||
#[rustversion::since(1.46.0)]
|
#[rustversion::since(1.46.0)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! declare_name {
|
macro_rules! declare_name {
|
||||||
($name:ident, $filename:ident, $id:path) => {
|
($name:ident) => {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! $name {
|
macro_rules! $name {
|
||||||
() => {
|
() => {
|
||||||
@ -66,8 +66,8 @@ macro_rules! declare_name {
|
|||||||
// `respan!` respans the path `$crate::id`, which we then call (hence the extra
|
// `respan!` respans the path `$crate::id`, which we then call (hence the extra
|
||||||
// parens)
|
// parens)
|
||||||
(
|
(
|
||||||
stringify!($filename).to_string(),
|
stringify!($name).to_string(),
|
||||||
::solana_sdk::respan!($crate::$id, $name)(),
|
::solana_sdk::respan!($crate::id, $name)(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -77,11 +77,11 @@ macro_rules! declare_name {
|
|||||||
#[rustversion::not(since(1.46.0))]
|
#[rustversion::not(since(1.46.0))]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! declare_name {
|
macro_rules! declare_name {
|
||||||
($name:ident, $filename:ident, $id:path) => {
|
($name:ident) => {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! $name {
|
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
|
/// Convenience macro to declare a native program
|
||||||
///
|
///
|
||||||
/// bs58_string: bs58 string representation the program's id
|
/// bs58_string: bs58 string representation the program's id
|
||||||
/// name: Name of the program
|
/// name: Name of the program, must match the library name in Cargo.toml
|
||||||
/// filename: must match the library name in Cargo.toml
|
|
||||||
/// entrypoint: Program's entrypoint, must be of `type Entrypoint`
|
/// 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
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -161,7 +159,7 @@ macro_rules! declare_name {
|
|||||||
macro_rules! declare_program(
|
macro_rules! declare_program(
|
||||||
($bs58_string:expr, $name:ident, $entrypoint:expr) => (
|
($bs58_string:expr, $name:ident, $entrypoint:expr) => (
|
||||||
$crate::declare_id!($bs58_string);
|
$crate::declare_id!($bs58_string);
|
||||||
$crate::declare_name!($name, $name, id);
|
$crate::declare_name!($name);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn $name(
|
pub extern "C" fn $name(
|
||||||
@ -176,16 +174,12 @@ macro_rules! declare_program(
|
|||||||
|
|
||||||
/// Same as declare_program but for native loaders
|
/// Same as declare_program but for native loaders
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! declare_loader {
|
macro_rules! declare_loader(
|
||||||
($bs58_string:expr, $name:ident, $entrypoint:expr) => {
|
($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) => {
|
|
||||||
$crate::declare_id!($bs58_string);
|
$crate::declare_id!($bs58_string);
|
||||||
$crate::declare_name!($name, $filename, $id);
|
$crate::declare_name!($name);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn $name(
|
pub extern "C" fn $name(
|
||||||
@ -196,8 +190,8 @@ macro_rules! declare_loader {
|
|||||||
) -> Result<(), $crate::instruction::InstructionError> {
|
) -> Result<(), $crate::instruction::InstructionError> {
|
||||||
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
|
$entrypoint(program_id, keyed_accounts, instruction_data, invoke_context)
|
||||||
}
|
}
|
||||||
};
|
)
|
||||||
}
|
);
|
||||||
|
|
||||||
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
pub type ProcessInstruction = fn(&Pubkey, &[KeyedAccount], &[u8]) -> Result<(), InstructionError>;
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ extern crate self as solana_sdk;
|
|||||||
pub mod account;
|
pub mod account;
|
||||||
pub mod account_utils;
|
pub mod account_utils;
|
||||||
pub mod bpf_loader;
|
pub mod bpf_loader;
|
||||||
pub mod bpf_loader_deprecated;
|
|
||||||
pub mod clock;
|
pub mod clock;
|
||||||
pub mod commitment_config;
|
pub mod commitment_config;
|
||||||
pub mod decode_error;
|
pub mod decode_error;
|
||||||
|
Reference in New Issue
Block a user