Respect RefCell when calling invoke (#12858)
* Respect RefCell when calling invoke * nudge
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");
|
info!("Test create_program_address");
|
||||||
{
|
{
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -105,8 +105,13 @@ fn process_transaction_and_record_inner(
|
|||||||
let signature = tx.signatures.get(0).unwrap().clone();
|
let signature = tx.signatures.get(0).unwrap().clone();
|
||||||
let txs = vec![tx];
|
let txs = vec![tx];
|
||||||
let tx_batch = bank.prepare_batch(&txs, None);
|
let tx_batch = bank.prepare_batch(&txs, None);
|
||||||
let (mut results, _, mut inner, _transaction_logs) =
|
let (mut results, _, mut inner, _transaction_logs) = bank.load_execute_and_commit_transactions(
|
||||||
bank.load_execute_and_commit_transactions(&tx_batch, MAX_PROCESSING_AGE, false, true, false);
|
&tx_batch,
|
||||||
|
MAX_PROCESSING_AGE,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
);
|
||||||
let inner_instructions = inner.swap_remove(0);
|
let inner_instructions = inner.swap_remove(0);
|
||||||
let result = results
|
let result = results
|
||||||
.fee_collection_results
|
.fee_collection_results
|
||||||
@ -439,16 +444,25 @@ fn test_program_bpf_invoke() {
|
|||||||
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
const TEST_PRIVILEGE_ESCALATION_WRITABLE: u8 = 3;
|
||||||
const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4;
|
const TEST_PPROGRAM_NOT_EXECUTABLE: u8 = 4;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Languages {
|
||||||
|
C,
|
||||||
|
Rust,
|
||||||
|
}
|
||||||
let mut programs = Vec::new();
|
let mut programs = Vec::new();
|
||||||
#[cfg(feature = "bpf_c")]
|
#[cfg(feature = "bpf_c")]
|
||||||
{
|
{
|
||||||
programs.extend_from_slice(&[("invoke", "invoked")]);
|
programs.push((Languages::C, "invoke", "invoked"));
|
||||||
}
|
}
|
||||||
#[cfg(feature = "bpf_rust")]
|
#[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() {
|
for program in programs.iter() {
|
||||||
println!("Test program: {:?}", program);
|
println!("Test program: {:?}", program);
|
||||||
|
|
||||||
@ -464,9 +478,9 @@ fn test_program_bpf_invoke() {
|
|||||||
let bank_client = BankClient::new_shared(&bank);
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
|
||||||
let invoke_program_id =
|
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);
|
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 argument_keypair = Keypair::new();
|
||||||
let account = Account::new(42, 100, &invoke_program_id);
|
let account = Account::new(42, 100, &invoke_program_id);
|
||||||
@ -526,9 +540,9 @@ fn test_program_bpf_invoke() {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|ix| message.account_keys[ix.program_id_index as usize].clone())
|
.map(|ix| message.account_keys[ix.program_id_index as usize].clone())
|
||||||
.collect();
|
.collect();
|
||||||
assert_eq!(
|
|
||||||
invoked_programs,
|
let expected_invoked_programs = match program.0 {
|
||||||
vec![
|
Languages::C => vec![
|
||||||
solana_sdk::system_program::id(),
|
solana_sdk::system_program::id(),
|
||||||
solana_sdk::system_program::id(),
|
solana_sdk::system_program::id(),
|
||||||
invoked_program_id.clone(),
|
invoked_program_id.clone(),
|
||||||
@ -541,14 +555,37 @@ fn test_program_bpf_invoke() {
|
|||||||
invoked_program_id.clone(),
|
invoked_program_id.clone(),
|
||||||
invoked_program_id.clone(),
|
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
|
// failure cases
|
||||||
|
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
invoke_program_id,
|
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(),
|
account_metas.clone(),
|
||||||
);
|
);
|
||||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||||
@ -576,7 +613,12 @@ fn test_program_bpf_invoke() {
|
|||||||
|
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
invoke_program_id,
|
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(),
|
account_metas.clone(),
|
||||||
);
|
);
|
||||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||||
@ -603,7 +645,12 @@ fn test_program_bpf_invoke() {
|
|||||||
|
|
||||||
let instruction = Instruction::new(
|
let instruction = Instruction::new(
|
||||||
invoke_program_id,
|
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(),
|
account_metas.clone(),
|
||||||
);
|
);
|
||||||
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
let message = Message::new(&[instruction], Some(&mint_pubkey));
|
||||||
|
@ -16,6 +16,22 @@ pub fn invoke_signed(
|
|||||||
account_infos: &[AccountInfo],
|
account_infos: &[AccountInfo],
|
||||||
signers_seeds: &[&[&[u8]]],
|
signers_seeds: &[&[&[u8]]],
|
||||||
) -> ProgramResult {
|
) -> 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 {
|
let result = unsafe {
|
||||||
sol_invoke_signed_rust(
|
sol_invoke_signed_rust(
|
||||||
instruction as *const _ as *const u8,
|
instruction as *const _ as *const u8,
|
||||||
|
Reference in New Issue
Block a user