Refactor: `TransactionContext` ABIv2 adjustments (#27476)

* Marks methods and structs which are only to be used by the program runtime.

* Removes TransactionContext::get_keys_of_accounts().

* Adds InstructionContext::get_instruction_accounts_lamport_sum().
This commit is contained in:
Alexander Meißner 2022-08-31 17:47:47 +02:00 committed by GitHub
parent bbc3c5c32d
commit 84b5a2bcf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 11 deletions

View File

@ -264,7 +264,13 @@ mod tests {
TransactionContext::new(accounts, Some(Rent::default()), 1, 3);
let program_indices = vec![vec![2]];
let executors = Rc::new(RefCell::new(Executors::default()));
let account_keys = transaction_context.get_keys_of_accounts().to_vec();
let account_keys = (0..transaction_context.get_number_of_accounts())
.map(|index| {
*transaction_context
.get_key_of_account_at_index(index)
.unwrap()
})
.collect::<Vec<_>>();
let account_metas = vec![
AccountMeta::new(writable_pubkey, true),
AccountMeta::new_readonly(readonly_pubkey, false),

View File

@ -1,14 +1,18 @@
//! Data shared between program runtime and built-in programs as well as SBF programs
#[cfg(not(target_os = "solana"))]
use crate::{
account::WritableAccount,
rent::Rent,
system_instruction::{
MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION, MAX_PERMITTED_DATA_LENGTH,
},
};
use {
crate::{
account::{AccountSharedData, ReadableAccount, WritableAccount},
account::{AccountSharedData, ReadableAccount},
instruction::InstructionError,
pubkey::Pubkey,
rent::Rent,
system_instruction::{
MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION, MAX_PERMITTED_DATA_LENGTH,
},
},
std::{
cell::{RefCell, RefMut},
@ -47,18 +51,22 @@ pub struct InstructionAccount {
pub struct TransactionContext {
account_keys: Pin<Box<[Pubkey]>>,
accounts: Pin<Box<[RefCell<AccountSharedData>]>>,
#[cfg(not(target_os = "solana"))]
account_touched_flags: RefCell<Pin<Box<[bool]>>>,
instruction_context_capacity: usize,
instruction_stack: Vec<usize>,
instruction_trace: Vec<InstructionContext>,
return_data: TransactionReturnData,
accounts_resize_delta: RefCell<i64>,
#[cfg(not(target_os = "solana"))]
rent: Option<Rent>,
#[cfg(not(target_os = "solana"))]
is_cap_accounts_data_allocations_per_transaction_enabled: bool,
}
impl TransactionContext {
/// Constructs a new TransactionContext
#[cfg(not(target_os = "solana"))]
pub fn new(
transaction_accounts: Vec<TransactionAccount>,
rent: Option<Rent>,
@ -86,6 +94,7 @@ impl TransactionContext {
}
/// Used in mock_process_instruction
#[cfg(not(target_os = "solana"))]
pub fn deconstruct_without_keys(self) -> Result<Vec<AccountSharedData>, InstructionError> {
if !self.instruction_stack.is_empty() {
return Err(InstructionError::CallDepth);
@ -97,6 +106,7 @@ impl TransactionContext {
}
/// Returns true if `enable_early_verification_of_account_modifications` is active
#[cfg(not(target_os = "solana"))]
pub fn is_early_verification_of_account_modifications_enabled(&self) -> bool {
self.rent.is_some()
}
@ -116,12 +126,8 @@ impl TransactionContext {
.ok_or(InstructionError::NotEnoughAccountKeys)
}
/// Returns the keys for the accounts loaded in this Transaction
pub fn get_keys_of_accounts(&self) -> &[Pubkey] {
&self.account_keys
}
/// Searches for an account by its key
#[cfg(not(target_os = "solana"))]
pub fn get_account_at_index(
&self,
index_in_transaction: usize,
@ -191,6 +197,7 @@ impl TransactionContext {
}
/// Pushes a new InstructionContext
#[cfg(not(target_os = "solana"))]
pub fn push(
&mut self,
program_accounts: &[usize],
@ -232,6 +239,7 @@ impl TransactionContext {
}
/// Pops the current InstructionContext
#[cfg(not(target_os = "solana"))]
pub fn pop(&mut self) -> Result<(), InstructionError> {
if self.instruction_stack.is_empty() {
return Err(InstructionError::CallDepth);
@ -283,6 +291,7 @@ impl TransactionContext {
}
/// Calculates the sum of all lamports within an instruction
#[cfg(not(target_os = "solana"))]
fn instruction_accounts_lamport_sum<'a, I>(
&'a self,
instruction_accounts: I,
@ -318,6 +327,7 @@ impl TransactionContext {
}
/// Enables enforcing a maximum accounts data allocation size per transaction
#[cfg(not(target_os = "solana"))]
pub fn enable_cap_accounts_data_allocations_per_transaction(&mut self) {
self.is_cap_accounts_data_allocations_per_transaction_enabled = true;
}
@ -344,6 +354,7 @@ pub struct InstructionContext {
impl InstructionContext {
/// New
#[cfg(not(target_os = "solana"))]
fn new(
nesting_level: usize,
instruction_accounts_lamport_sum: u128,
@ -367,6 +378,11 @@ impl InstructionContext {
self.nesting_level.saturating_add(1)
}
/// Returns the sum of lamports of the instruction accounts in this Instruction
pub fn get_instruction_accounts_lamport_sum(&self) -> u128 {
self.instruction_accounts_lamport_sum
}
/// Number of program accounts
pub fn get_number_of_program_accounts(&self) -> usize {
self.program_accounts.len()
@ -609,6 +625,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Assignes the owner of this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn set_owner(&mut self, pubkey: &[u8]) -> Result<(), InstructionError> {
if self
.transaction_context
@ -646,6 +663,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Overwrites the number of lamports of this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn set_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
if self
.transaction_context
@ -674,6 +692,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Adds lamports to this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn checked_add_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
self.set_lamports(
self.get_lamports()
@ -683,6 +702,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Subtracts lamports from this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn checked_sub_lamports(&mut self, lamports: u64) -> Result<(), InstructionError> {
self.set_lamports(
self.get_lamports()
@ -697,6 +717,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns a writable slice of the account data (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn get_data_mut(&mut self) -> Result<&mut [u8], InstructionError> {
self.can_data_be_changed()?;
self.touch()?;
@ -704,6 +725,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Overwrites the account data and size (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn set_data(&mut self, data: &[u8]) -> Result<(), InstructionError> {
self.can_data_be_resized(data.len())?;
self.can_data_be_changed()?;
@ -726,6 +748,7 @@ impl<'a> BorrowedAccount<'a> {
/// Resizes the account data (transaction wide)
///
/// Fills it with zeros at the end if is extended or truncates at the end otherwise.
#[cfg(not(target_os = "solana"))]
pub fn set_data_length(&mut self, new_length: usize) -> Result<(), InstructionError> {
self.can_data_be_resized(new_length)?;
self.can_data_be_changed()?;
@ -746,6 +769,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Deserializes the account data into a state
#[cfg(not(target_os = "solana"))]
pub fn get_state<T: serde::de::DeserializeOwned>(&self) -> Result<T, InstructionError> {
self.account
.deserialize_data()
@ -753,6 +777,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Serializes a state into the account data
#[cfg(not(target_os = "solana"))]
pub fn set_state<T: serde::Serialize>(&mut self, state: &T) -> Result<(), InstructionError> {
let data = self.get_data_mut()?;
let serialized_size =
@ -770,6 +795,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Configures whether this account is executable (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn set_executable(&mut self, is_executable: bool) -> Result<(), InstructionError> {
if let Some(rent) = self.transaction_context.rent {
// To become executable an account must be rent exempt
@ -799,6 +825,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns the rent epoch of this account (transaction wide)
#[cfg(not(target_os = "solana"))]
pub fn get_rent_epoch(&self) -> u64 {
self.account.rent_epoch()
}
@ -838,6 +865,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns an error if the account data can not be mutated by the current program
#[cfg(not(target_os = "solana"))]
pub fn can_data_be_changed(&self) -> Result<(), InstructionError> {
if !self
.transaction_context
@ -861,6 +889,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Returns an error if the account data can not be resized to the given length
#[cfg(not(target_os = "solana"))]
pub fn can_data_be_resized(&self, new_length: usize) -> Result<(), InstructionError> {
if !self
.transaction_context
@ -895,6 +924,7 @@ impl<'a> BorrowedAccount<'a> {
Ok(())
}
#[cfg(not(target_os = "solana"))]
fn touch(&self) -> Result<(), InstructionError> {
if self
.transaction_context
@ -913,6 +943,7 @@ impl<'a> BorrowedAccount<'a> {
}
/// Everything that needs to be recorded from a TransactionContext after execution
#[cfg(not(target_os = "solana"))]
pub struct ExecutionRecord {
pub accounts: Vec<TransactionAccount>,
pub return_data: TransactionReturnData,
@ -921,6 +952,7 @@ pub struct ExecutionRecord {
}
/// Used by the bank in the runtime to write back the processed accounts and recorded instructions
#[cfg(not(target_os = "solana"))]
impl From<TransactionContext> for ExecutionRecord {
fn from(context: TransactionContext) -> Self {
let account_touched_flags = context
@ -948,6 +980,7 @@ impl From<TransactionContext> for ExecutionRecord {
}
}
#[cfg(not(target_os = "solana"))]
fn is_zeroed(buf: &[u8]) -> bool {
const ZEROS_LEN: usize = 1024;
const ZEROS: [u8; ZEROS_LEN] = [0; ZEROS_LEN];