Add Rust BPF RefCell borrow helpers (#8047)
This commit is contained in:
@ -28,7 +28,7 @@ impl From<MyError> for ProgramError {
|
|||||||
entrypoint!(process_instruction);
|
entrypoint!(process_instruction);
|
||||||
fn process_instruction(
|
fn process_instruction(
|
||||||
_program_id: &Pubkey,
|
_program_id: &Pubkey,
|
||||||
_accounts: &[AccountInfo],
|
accounts: &[AccountInfo],
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
) -> Result<(), ProgramError> {
|
) -> Result<(), ProgramError> {
|
||||||
match instruction_data[0] {
|
match instruction_data[0] {
|
||||||
@ -38,7 +38,7 @@ fn process_instruction(
|
|||||||
}
|
}
|
||||||
2 => {
|
2 => {
|
||||||
info!("return a builtin");
|
info!("return a builtin");
|
||||||
Err(ProgramError::AccountBorrowFailed)
|
Err(ProgramError::InvalidAccountData)
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
info!("return custom error");
|
info!("return custom error");
|
||||||
@ -52,6 +52,12 @@ fn process_instruction(
|
|||||||
info!("return error that conflicts with builtin");
|
info!("return error that conflicts with builtin");
|
||||||
Err(MyError::ConflictingBuiltin.into())
|
Err(MyError::ConflictingBuiltin.into())
|
||||||
}
|
}
|
||||||
|
6 => {
|
||||||
|
let data = accounts[0].try_borrow_mut_data()?;
|
||||||
|
let data2 = accounts[0].try_borrow_mut_data()?;
|
||||||
|
assert_eq!(*data, *data2);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
info!("Unrecognized command");
|
info!("Unrecognized command");
|
||||||
Err(ProgramError::InvalidInstructionData)
|
Err(ProgramError::InvalidInstructionData)
|
||||||
|
@ -384,7 +384,7 @@ mod bpf {
|
|||||||
let result = bank_client.send_instruction(&mint_keypair, instruction);
|
let result = bank_client.send_instruction(&mint_keypair, instruction);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().unwrap(),
|
result.unwrap_err().unwrap(),
|
||||||
TransactionError::InstructionError(0, InstructionError::AccountBorrowFailed)
|
TransactionError::InstructionError(0, InstructionError::InvalidAccountData)
|
||||||
);
|
);
|
||||||
|
|
||||||
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
|
let instruction = Instruction::new(program_id, &3u8, account_metas.clone());
|
||||||
@ -413,6 +413,13 @@ mod bpf {
|
|||||||
|
|
||||||
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
|
let instruction = Instruction::new(program_id, &6u8, account_metas.clone());
|
||||||
let result = bank_client.send_instruction(&mint_keypair, instruction);
|
let result = bank_client.send_instruction(&mint_keypair, instruction);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().unwrap(),
|
||||||
|
TransactionError::InstructionError(0, InstructionError::AccountBorrowFailed)
|
||||||
|
);
|
||||||
|
|
||||||
|
let instruction = Instruction::new(program_id, &7u8, account_metas.clone());
|
||||||
|
let result = bank_client.send_instruction(&mint_keypair, instruction);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result.unwrap_err().unwrap(),
|
result.unwrap_err().unwrap(),
|
||||||
TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
|
TransactionError::InstructionError(0, InstructionError::InvalidInstructionData)
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
use crate::{account::Account, pubkey::Pubkey};
|
use crate::{account::Account, program_error::ProgramError, pubkey::Pubkey};
|
||||||
use std::{cell::RefCell, cmp, fmt, rc::Rc};
|
use std::{
|
||||||
|
cell::{Ref, RefCell, RefMut},
|
||||||
|
cmp, fmt,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
/// Account information
|
/// Account information
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -55,14 +59,50 @@ impl<'a> AccountInfo<'a> {
|
|||||||
**self.lamports.borrow()
|
**self.lamports.borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_lamports(&self) -> Result<u64, ProgramError> {
|
||||||
|
Ok(**self.try_borrow_lamports()?)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data_len(&self) -> usize {
|
pub fn data_len(&self) -> usize {
|
||||||
self.data.borrow().len()
|
self.data.borrow().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_data_len(&self) -> Result<usize, ProgramError> {
|
||||||
|
Ok(self.try_borrow_data()?.len())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn data_is_empty(&self) -> bool {
|
pub fn data_is_empty(&self) -> bool {
|
||||||
self.data.borrow().is_empty()
|
self.data.borrow().is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn try_data_is_empty(&self) -> Result<bool, ProgramError> {
|
||||||
|
Ok(self.try_borrow_data()?.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_borrow_lamports(&self) -> Result<Ref<&mut u64>, ProgramError> {
|
||||||
|
self.lamports
|
||||||
|
.try_borrow()
|
||||||
|
.map_err(|_| ProgramError::AccountBorrowFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_borrow_mut_lamports(&self) -> Result<RefMut<&'a mut u64>, ProgramError> {
|
||||||
|
self.lamports
|
||||||
|
.try_borrow_mut()
|
||||||
|
.map_err(|_| ProgramError::AccountBorrowFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_borrow_data(&self) -> Result<Ref<&mut [u8]>, ProgramError> {
|
||||||
|
self.data
|
||||||
|
.try_borrow()
|
||||||
|
.map_err(|_| ProgramError::AccountBorrowFailed)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_borrow_mut_data(&self) -> Result<RefMut<&'a mut [u8]>, ProgramError> {
|
||||||
|
self.data
|
||||||
|
.try_borrow_mut()
|
||||||
|
.map_err(|_| ProgramError::AccountBorrowFailed)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
key: &'a Pubkey,
|
key: &'a Pubkey,
|
||||||
is_signer: bool,
|
is_signer: bool,
|
||||||
|
@ -75,10 +75,10 @@ pub enum InstructionError {
|
|||||||
/// The instruction expected an executable account
|
/// The instruction expected an executable account
|
||||||
AccountNotExecutable,
|
AccountNotExecutable,
|
||||||
|
|
||||||
/// Failed to borrow a reference to an account, already borrowed
|
/// Failed to borrow a reference to account data, already borrowed
|
||||||
AccountBorrowFailed,
|
AccountBorrowFailed,
|
||||||
|
|
||||||
/// Account has an outstanding reference after a program's execution
|
/// Account data has an outstanding reference after a program's execution
|
||||||
AccountBorrowOutstanding,
|
AccountBorrowOutstanding,
|
||||||
|
|
||||||
/// The same account was multiply passed to an on-chain program's entrypoint, but the program
|
/// The same account was multiply passed to an on-chain program's entrypoint, but the program
|
||||||
|
@ -30,7 +30,7 @@ pub enum ProgramError {
|
|||||||
UninitializedAccount,
|
UninitializedAccount,
|
||||||
/// The instruction expected additional account keys
|
/// The instruction expected additional account keys
|
||||||
NotEnoughAccountKeys,
|
NotEnoughAccountKeys,
|
||||||
/// Failed to borrow a reference to an account, already borrowed
|
/// Failed to borrow a reference to account data, already borrowed
|
||||||
AccountBorrowFailed,
|
AccountBorrowFailed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user