* Respect RefCell when calling invoke
* nudge
(cherry picked from commit 969f7b015b
)
Co-authored-by: Jack May <jack@solana.com>
This commit is contained in:
@ -144,6 +144,92 @@ fn process_instruction(
|
||||
);
|
||||
}
|
||||
|
||||
info!("Test refcell usage");
|
||||
{
|
||||
let writable = INVOKED_ARGUMENT_INDEX;
|
||||
let readable = INVOKED_PROGRAM_INDEX;
|
||||
|
||||
let instruction = create_instruction(
|
||||
*accounts[INVOKED_PROGRAM_INDEX].key,
|
||||
&[
|
||||
(accounts[writable].key, true, true),
|
||||
(accounts[readable].key, false, false),
|
||||
],
|
||||
vec![TEST_RETURN_ERROR, 1, 2, 3, 4, 5],
|
||||
);
|
||||
|
||||
// success with this account configuration as a check
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::Custom(42))
|
||||
);
|
||||
|
||||
{
|
||||
// writable but lamports borrow_mut'd
|
||||
let _ref_mut = accounts[writable].try_borrow_mut_lamports()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
{
|
||||
// writable but data borrow_mut'd
|
||||
let _ref_mut = accounts[writable].try_borrow_mut_data()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
{
|
||||
// writable but lamports borrow'd
|
||||
let _ref_mut = accounts[writable].try_borrow_lamports()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
{
|
||||
// writable but data borrow'd
|
||||
let _ref_mut = accounts[writable].try_borrow_data()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
{
|
||||
// readable but lamports borrow_mut'd
|
||||
let _ref_mut = accounts[readable].try_borrow_mut_lamports()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
{
|
||||
// readable but data borrow_mut'd
|
||||
let _ref_mut = accounts[readable].try_borrow_mut_data()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::AccountBorrowFailed)
|
||||
);
|
||||
}
|
||||
{
|
||||
// readable but lamports borrow'd
|
||||
let _ref_mut = accounts[readable].try_borrow_lamports()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::Custom(42))
|
||||
);
|
||||
}
|
||||
{
|
||||
// readable but data borrow'd
|
||||
let _ref_mut = accounts[readable].try_borrow_data()?;
|
||||
assert_eq!(
|
||||
invoke(&instruction, accounts),
|
||||
Err(ProgramError::Custom(42))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Test create_program_address");
|
||||
{
|
||||
assert_eq!(
|
||||
|
@ -444,16 +444,25 @@ fn test_program_bpf_invoke() {
|
||||
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
||||
const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum Languages {
|
||||
C,
|
||||
Rust,
|
||||
}
|
||||
let mut programs = Vec::new();
|
||||
#[cfg(feature = "bpf_c")]
|
||||
{
|
||||
programs.extend_from_slice(&[("invoke", "invoked")]);
|
||||
programs.push((Languages::C, "invoke", "invoked"));
|
||||
}
|
||||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[("solana_bpf_rust_invoke", "solana_bpf_rust_invoked")]);
|
||||
programs.push((
|
||||
Languages::Rust,
|
||||
"solana_bpf_rust_invoke",
|
||||
"solana_bpf_rust_invoked",
|
||||
));
|
||||
}
|
||||
|
||||
for program in programs.iter() {
|
||||
println!("Test program: {:?}", program);
|
||||
|
||||
@ -469,9 +478,9 @@ fn test_program_bpf_invoke() {
|
||||
let bank_client = BankClient::new_shared(&bank);
|
||||
|
||||
let invoke_program_id =
|
||||
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.0);
|
||||
let invoked_program_id =
|
||||
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.1);
|
||||
let invoked_program_id =
|
||||
load_bpf_program(&bank_client, &bpf_loader::id(), &mint_keypair, program.2);
|
||||
|
||||
let argument_keypair = Keypair::new();
|
||||
let account = Account::new(42, 100, &invoke_program_id);
|
||||
@ -531,9 +540,9 @@ fn test_program_bpf_invoke() {
|
||||
.iter()
|
||||
.map(|ix| message.account_keys[ix.program_id_index as usize].clone())
|
||||
.collect();
|
||||
assert_eq!(
|
||||
invoked_programs,
|
||||
vec![
|
||||
|
||||
let expected_invoked_programs = match program.0 {
|
||||
Languages::C => vec![
|
||||
solana_sdk::system_program::id(),
|
||||
solana_sdk::system_program::id(),
|
||||
invoked_program_id.clone(),
|
||||
@ -546,14 +555,37 @@ fn test_program_bpf_invoke() {
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
]
|
||||
);
|
||||
],
|
||||
Languages::Rust => vec![
|
||||
solana_sdk::system_program::id(),
|
||||
solana_sdk::system_program::id(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
invoked_program_id.clone(),
|
||||
],
|
||||
};
|
||||
assert_eq!(invoked_programs, expected_invoked_programs);
|
||||
|
||||
// failure cases
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&[TEST_PRIVILEGE_ESCALATION_SIGNER, bump_seed1, bump_seed2, bump_seed3],
|
||||
&[
|
||||
TEST_PRIVILEGE_ESCALATION_SIGNER,
|
||||
bump_seed1,
|
||||
bump_seed2,
|
||||
bump_seed3,
|
||||
],
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
@ -581,7 +613,12 @@ fn test_program_bpf_invoke() {
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&[TEST_PRIVILEGE_ESCALATION_WRITABLE, bump_seed1, bump_seed2, bump_seed3],
|
||||
&[
|
||||
TEST_PRIVILEGE_ESCALATION_WRITABLE,
|
||||
bump_seed1,
|
||||
bump_seed2,
|
||||
bump_seed3,
|
||||
],
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
@ -608,7 +645,12 @@ fn test_program_bpf_invoke() {
|
||||
|
||||
let instruction = Instruction::new(
|
||||
invoke_program_id,
|
||||
&[TEST_PPROGRAM_NOT_EXECUTABLE, bump_seed1, bump_seed2, bump_seed3],
|
||||
&[
|
||||
TEST_PPROGRAM_NOT_EXECUTABLE,
|
||||
bump_seed1,
|
||||
bump_seed2,
|
||||
bump_seed3,
|
||||
],
|
||||
account_metas.clone(),
|
||||
);
|
||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||
|
@ -16,6 +16,22 @@ pub fn invoke_signed(
|
||||
account_infos: &[AccountInfo],
|
||||
signers_seeds: &[&[&[u8]]],
|
||||
) -> ProgramResult {
|
||||
// Check that the account RefCells are consistent with the request
|
||||
for account_meta in instruction.accounts.iter() {
|
||||
for account_info in account_infos.iter() {
|
||||
if account_meta.pubkey == *account_info.key {
|
||||
if account_meta.is_writable {
|
||||
let _ = account_info.try_borrow_mut_lamports()?;
|
||||
let _ = account_info.try_borrow_mut_data()?;
|
||||
} else {
|
||||
let _ = account_info.try_borrow_lamports()?;
|
||||
let _ = account_info.try_borrow_data()?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = unsafe {
|
||||
sol_invoke_signed_rust(
|
||||
instruction as *const _ as *const u8,
|
||||
|
Reference in New Issue
Block a user