Translate data length and owner as writable (#13914)
This commit is contained in:
18
programs/bpf/rust/ro_modify/Cargo.toml
Normal file
18
programs/bpf/rust/ro_modify/Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "solana-bpf-rust-ro-modify"
|
||||
version = "1.5.0"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "1.5.0" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
2
programs/bpf/rust/ro_modify/Xargo.toml
Normal file
2
programs/bpf/rust/ro_modify/Xargo.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[target.bpfel-unknown-unknown.dependencies.std]
|
||||
features = []
|
222
programs/bpf/rust/ro_modify/src/lib.rs
Normal file
222
programs/bpf/rust/ro_modify/src/lib.rs
Normal file
@ -0,0 +1,222 @@
|
||||
use solana_program::{
|
||||
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, program::invoke,
|
||||
program_error::ProgramError, pubkey::Pubkey, system_instruction,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolInstruction {
|
||||
program_id_addr: u64,
|
||||
accounts_addr: u64,
|
||||
accounts_len: usize,
|
||||
data_addr: u64,
|
||||
data_len: usize,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolAccountMeta
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolAccountMeta {
|
||||
pubkey_addr: u64,
|
||||
is_writable: bool,
|
||||
is_signer: bool,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolAccountInfo
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
struct SolAccountInfo {
|
||||
key_addr: u64,
|
||||
lamports_addr: u64,
|
||||
data_len: u64,
|
||||
data_addr: u64,
|
||||
owner_addr: u64,
|
||||
rent_epoch: u64,
|
||||
is_signer: bool,
|
||||
is_writable: bool,
|
||||
executable: bool,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolSignerSeed
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolSignerSeedC {
|
||||
addr: u64,
|
||||
len: u64,
|
||||
}
|
||||
|
||||
/// Rust representation of C's SolSignerSeeds
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SolSignerSeedsC {
|
||||
addr: u64,
|
||||
len: u64,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn sol_invoke_signed_c(
|
||||
instruction_addr: *const SolInstruction,
|
||||
account_infos_addr: *const SolAccountInfo,
|
||||
account_infos_len: u64,
|
||||
signers_seeds_addr: *const SolSignerSeedsC,
|
||||
signers_seeds_len: u64,
|
||||
) -> u64;
|
||||
}
|
||||
|
||||
const READONLY_ACCOUNTS: &[SolAccountInfo] = &[
|
||||
SolAccountInfo {
|
||||
is_signer: false,
|
||||
is_writable: false,
|
||||
executable: true,
|
||||
key_addr: 0x400000010,
|
||||
owner_addr: 0x400000030,
|
||||
lamports_addr: 0x400000050,
|
||||
rent_epoch: 0,
|
||||
data_addr: 0x400000060,
|
||||
data_len: 14,
|
||||
},
|
||||
SolAccountInfo {
|
||||
is_signer: true,
|
||||
is_writable: true,
|
||||
executable: false,
|
||||
key_addr: 0x400002880,
|
||||
owner_addr: 0x4000028A0,
|
||||
lamports_addr: 0x4000028c0,
|
||||
rent_epoch: 0,
|
||||
data_addr: 0x4000028d0,
|
||||
data_len: 0,
|
||||
},
|
||||
];
|
||||
|
||||
const PUBKEY: Pubkey = Pubkey::new_from_array([
|
||||
0_u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0,
|
||||
]);
|
||||
|
||||
fn check_preconditions(
|
||||
in_infos: &[AccountInfo],
|
||||
static_infos: &[SolAccountInfo],
|
||||
) -> Result<(), ProgramError> {
|
||||
for (in_info, static_info) in in_infos.iter().zip(static_infos) {
|
||||
check!(in_info.key.as_ref().as_ptr() as u64, static_info.key_addr);
|
||||
check!(
|
||||
in_info.owner.as_ref().as_ptr() as u64,
|
||||
static_info.owner_addr
|
||||
);
|
||||
check!(
|
||||
unsafe { *in_info.lamports.as_ptr() as *const u64 as u64 },
|
||||
static_info.lamports_addr
|
||||
);
|
||||
check!(
|
||||
in_info.try_borrow_data()?.as_ptr() as u64,
|
||||
static_info.data_addr
|
||||
);
|
||||
check!(in_info.data_len() as u64, static_info.data_len);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
program_id: &Pubkey,
|
||||
accounts: &[AccountInfo],
|
||||
instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
check_preconditions(accounts, READONLY_ACCOUNTS)?;
|
||||
|
||||
match instruction_data[0] {
|
||||
1 => {
|
||||
let system_instruction = system_instruction::allocate(accounts[1].key, 42);
|
||||
let metas = &[SolAccountMeta {
|
||||
is_signer: true,
|
||||
is_writable: true,
|
||||
pubkey_addr: accounts[1].key as *const _ as u64,
|
||||
}];
|
||||
let instruction = SolInstruction {
|
||||
accounts_addr: metas.as_ptr() as u64,
|
||||
accounts_len: metas.len(),
|
||||
data_addr: system_instruction.data.as_ptr() as u64,
|
||||
data_len: system_instruction.data.len(),
|
||||
program_id_addr: accounts[0].key as *const Pubkey as u64,
|
||||
};
|
||||
unsafe {
|
||||
check!(
|
||||
0,
|
||||
sol_invoke_signed_c(
|
||||
&instruction as *const _,
|
||||
READONLY_ACCOUNTS.as_ptr(),
|
||||
READONLY_ACCOUNTS.len() as u64,
|
||||
std::ptr::null::<SolSignerSeedsC>(),
|
||||
0,
|
||||
)
|
||||
);
|
||||
}
|
||||
let ptr = &READONLY_ACCOUNTS[1].data_len as *const _ as u64 as *mut u64;
|
||||
check!(42, unsafe { read_val(ptr) });
|
||||
}
|
||||
2 => {
|
||||
// Not sure how to get a const data length in an Rc<RefCell<&mut [u8]>>
|
||||
}
|
||||
3 => {
|
||||
let mut new_accounts =
|
||||
&mut [READONLY_ACCOUNTS[0].clone(), READONLY_ACCOUNTS[1].clone()];
|
||||
new_accounts[1].owner_addr = &PUBKEY as *const _ as u64;
|
||||
let system_instruction = system_instruction::assign(accounts[1].key, program_id);
|
||||
let metas = &[SolAccountMeta {
|
||||
is_signer: true,
|
||||
is_writable: true,
|
||||
pubkey_addr: accounts[1].key as *const _ as u64,
|
||||
}];
|
||||
let instruction = SolInstruction {
|
||||
accounts_addr: metas.as_ptr() as u64,
|
||||
accounts_len: metas.len(),
|
||||
data_addr: system_instruction.data.as_ptr() as u64,
|
||||
data_len: system_instruction.data.len(),
|
||||
program_id_addr: accounts[0].key as *const Pubkey as u64,
|
||||
};
|
||||
unsafe {
|
||||
check!(
|
||||
0,
|
||||
sol_invoke_signed_c(
|
||||
&instruction as *const _,
|
||||
new_accounts.as_ptr(),
|
||||
new_accounts.len() as u64,
|
||||
std::ptr::null::<SolSignerSeedsC>(),
|
||||
0,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
4 => {
|
||||
let mut new_account = accounts[1].clone();
|
||||
new_account.owner = &PUBKEY;
|
||||
let instruction = system_instruction::assign(accounts[1].key, program_id);
|
||||
invoke(&instruction, &[accounts[0].clone(), new_account])?;
|
||||
}
|
||||
_ => check!(0, 1),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! check {
|
||||
($left:expr, $right:expr) => {
|
||||
if $left != $right {
|
||||
msg!(
|
||||
"Condition failure: {:?} != {:?} at line {:?}",
|
||||
$left,
|
||||
$right,
|
||||
line!()
|
||||
);
|
||||
return Err(ProgramError::Custom(0));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Skirt the compiler and force a read from a const value
|
||||
/// # Safety
|
||||
#[inline(never)]
|
||||
pub unsafe fn read_val<T: Copy>(ptr: *mut T) -> T {
|
||||
*ptr
|
||||
}
|
Reference in New Issue
Block a user