diff --git a/ledger/src/blockstore_processor.rs b/ledger/src/blockstore_processor.rs index 3e580a68a..bff15785e 100644 --- a/ledger/src/blockstore_processor.rs +++ b/ledger/src/blockstore_processor.rs @@ -42,6 +42,7 @@ use { feature_set, genesis_config::GenesisConfig, hash::Hash, + instruction::InstructionError, pubkey::Pubkey, signature::{Keypair, Signature}, timing, @@ -224,6 +225,13 @@ fn execute_batch( .. } = tx_results; + if bank + .feature_set + .is_active(&feature_set::cap_accounts_data_len::id()) + { + check_accounts_data_size(&execution_results)?; + } + if let Some(transaction_status_sender) = transaction_status_sender { let transactions = batch.sanitized_transactions().to_vec(); let post_token_balances = if record_token_balances { @@ -1540,6 +1548,30 @@ pub fn fill_blockstore_slot_with_ticks( last_entry_hash } +/// Check the transaction execution results to see if any instruction errored by exceeding the max +/// accounts data size limit for all slots. If yes, the whole block needs to be failed. +fn check_accounts_data_size<'a>( + execution_results: impl IntoIterator, +) -> Result<()> { + if let Some(result) = execution_results + .into_iter() + .map(|execution_result| execution_result.flattened_result()) + .find(|result| { + matches!( + result, + Err(TransactionError::InstructionError( + _, + InstructionError::MaxAccountsDataSizeExceeded + )), + ) + }) + { + return result; + } + + Ok(()) +} + #[cfg(test)] pub mod tests { use { diff --git a/program-runtime/src/accounts_data_meter.rs b/program-runtime/src/accounts_data_meter.rs index ef9c1fb60..2c3f926ea 100644 --- a/program-runtime/src/accounts_data_meter.rs +++ b/program-runtime/src/accounts_data_meter.rs @@ -80,7 +80,7 @@ impl AccountsDataMeter { /// the remaining space, return an error and *do not* adjust accounts data space. pub fn adjust_delta(&mut self, amount: i64) -> Result<(), InstructionError> { if amount > self.remaining() as i64 { - return Err(InstructionError::AccountsDataBudgetExceeded); + return Err(InstructionError::MaxAccountsDataSizeExceeded); } self.adjust_delta_unchecked(amount); Ok(()) diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index dfeeef177..adb6c2628 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -1745,7 +1745,7 @@ mod tests { assert!(result.is_err()); assert!(matches!( result, - Err(solana_sdk::instruction::InstructionError::AccountsDataBudgetExceeded) + Err(solana_sdk::instruction::InstructionError::MaxAccountsDataSizeExceeded) )); assert_eq!(invoke_context.accounts_data_meter.remaining(), 0); } diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 5a44b1d2e..c19ae1f11 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -45,7 +45,7 @@ use { instruction::{AccountMeta, InstructionError}, loader_instruction::LoaderInstruction, loader_upgradeable_instruction::UpgradeableLoaderInstruction, - program_error::ACCOUNTS_DATA_BUDGET_EXCEEDED, + program_error::MAX_ACCOUNTS_DATA_SIZE_EXCEEDED, program_utils::limited_deserialize, pubkey::Pubkey, saturating_add_assign, @@ -1332,13 +1332,13 @@ impl Executor for BpfExecutor { } match result { Ok(status) if status != SUCCESS => { - let error: InstructionError = if status == ACCOUNTS_DATA_BUDGET_EXCEEDED + let error: InstructionError = if status == MAX_ACCOUNTS_DATA_SIZE_EXCEEDED && !invoke_context .feature_set .is_active(&cap_accounts_data_len::id()) { // Until the cap_accounts_data_len feature is enabled, map the - // ACCOUNTS_DATA_BUDGET_EXCEEDED error to InvalidError + // MAX_ACCOUNTS_DATA_SIZE_EXCEEDED error to InvalidError InstructionError::InvalidError } else { status.into() diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c16e39f45..4b122a0be 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -215,7 +215,7 @@ impl RentDebits { } type BankStatusCache = StatusCache>; -#[frozen_abi(digest = "6XkxpmzmKZguLZMS1KmU7N2dAcv8MmNhyobJCwRLkTdi")] +#[frozen_abi(digest = "HdYCU65Jwfv9sF3C8k6ZmjUAaXSkJwazebuur21v8JtY")] pub type BankSlotDelta = SlotDelta>; // Eager rent collection repeats in cyclic manner. @@ -16147,9 +16147,9 @@ pub(crate) mod tests { ); } - /// Test exceeding the accounts data budget by creating accounts in a loop + /// Test exceeding the max accounts data size by creating accounts in a loop #[test] - fn test_accounts_data_budget_exceeded() { + fn test_max_accounts_data_size_exceeded() { use { solana_program_runtime::accounts_data_meter::MAX_ACCOUNTS_DATA_LEN, solana_sdk::system_instruction::MAX_PERMITTED_DATA_LENGTH, @@ -16188,7 +16188,7 @@ pub(crate) mod tests { result, Err(TransactionError::InstructionError( _, - solana_sdk::instruction::InstructionError::AccountsDataBudgetExceeded, + solana_sdk::instruction::InstructionError::MaxAccountsDataSizeExceeded, )) )); } diff --git a/sdk/program/src/instruction.rs b/sdk/program/src/instruction.rs index a0077e891..0de8f9337 100644 --- a/sdk/program/src/instruction.rs +++ b/sdk/program/src/instruction.rs @@ -249,9 +249,9 @@ pub enum InstructionError { #[error("Provided owner is not allowed")] IllegalOwner, - /// Accounts data budget exceeded - #[error("Requested account data allocation exceeded the accounts data budget")] - AccountsDataBudgetExceeded, + /// Account data allocation exceeded the maximum accounts data size limit + #[error("Account data allocation exceeded the maximum accounts data size limit")] + MaxAccountsDataSizeExceeded, /// Active vote account close #[error("Cannot close vote account unless it stopped voting at least one full epoch ago")] diff --git a/sdk/program/src/program_error.rs b/sdk/program/src/program_error.rs index 0f8e02dab..d142ce6a2 100644 --- a/sdk/program/src/program_error.rs +++ b/sdk/program/src/program_error.rs @@ -49,8 +49,8 @@ pub enum ProgramError { UnsupportedSysvar, #[error("Provided owner is not allowed")] IllegalOwner, - #[error("Requested account data allocation exceeded the accounts data budget")] - AccountsDataBudgetExceeded, + #[error("Account data allocation exceeded the maximum accounts data size limit")] + MaxAccountsDataSizeExceeded, #[error("Cannot close vote account unless it stopped voting at least one full epoch ago")] ActiveVoteAccountClose, } @@ -91,7 +91,7 @@ impl PrintProgramError for ProgramError { Self::AccountNotRentExempt => msg!("Error: AccountNotRentExempt"), Self::UnsupportedSysvar => msg!("Error: UnsupportedSysvar"), Self::IllegalOwner => msg!("Error: IllegalOwner"), - Self::AccountsDataBudgetExceeded => msg!("Error: AccountsDataBudgetExceeded"), + Self::MaxAccountsDataSizeExceeded => msg!("Error: MaxAccountsDataSizeExceeded"), Self::ActiveVoteAccountClose => msg!("Error: ActiveVoteAccountClose"), } } @@ -123,7 +123,7 @@ pub const BORSH_IO_ERROR: u64 = to_builtin!(15); pub const ACCOUNT_NOT_RENT_EXEMPT: u64 = to_builtin!(16); pub const UNSUPPORTED_SYSVAR: u64 = to_builtin!(17); pub const ILLEGAL_OWNER: u64 = to_builtin!(18); -pub const ACCOUNTS_DATA_BUDGET_EXCEEDED: u64 = to_builtin!(19); +pub const MAX_ACCOUNTS_DATA_SIZE_EXCEEDED: u64 = to_builtin!(19); pub const ACTIVE_VOTE_ACCOUNT_CLOSE: u64 = to_builtin!(20); // Warning: Any new program errors added here must also be: // - Added to the below conversions @@ -151,7 +151,7 @@ impl From for u64 { ProgramError::AccountNotRentExempt => ACCOUNT_NOT_RENT_EXEMPT, ProgramError::UnsupportedSysvar => UNSUPPORTED_SYSVAR, ProgramError::IllegalOwner => ILLEGAL_OWNER, - ProgramError::AccountsDataBudgetExceeded => ACCOUNTS_DATA_BUDGET_EXCEEDED, + ProgramError::MaxAccountsDataSizeExceeded => MAX_ACCOUNTS_DATA_SIZE_EXCEEDED, ProgramError::ActiveVoteAccountClose => ACTIVE_VOTE_ACCOUNT_CLOSE, ProgramError::Custom(error) => { if error == 0 { @@ -185,7 +185,7 @@ impl From for ProgramError { ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt, UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar, ILLEGAL_OWNER => Self::IllegalOwner, - ACCOUNTS_DATA_BUDGET_EXCEEDED => Self::AccountsDataBudgetExceeded, + MAX_ACCOUNTS_DATA_SIZE_EXCEEDED => Self::MaxAccountsDataSizeExceeded, ACTIVE_VOTE_ACCOUNT_CLOSE => Self::ActiveVoteAccountClose, _ => Self::Custom(error as u32), } @@ -215,7 +215,7 @@ impl TryFrom for ProgramError { Self::Error::AccountNotRentExempt => Ok(Self::AccountNotRentExempt), Self::Error::UnsupportedSysvar => Ok(Self::UnsupportedSysvar), Self::Error::IllegalOwner => Ok(Self::IllegalOwner), - Self::Error::AccountsDataBudgetExceeded => Ok(Self::AccountsDataBudgetExceeded), + Self::Error::MaxAccountsDataSizeExceeded => Ok(Self::MaxAccountsDataSizeExceeded), Self::Error::ActiveVoteAccountClose => Ok(Self::ActiveVoteAccountClose), _ => Err(error), } @@ -247,7 +247,7 @@ where ACCOUNT_NOT_RENT_EXEMPT => Self::AccountNotRentExempt, UNSUPPORTED_SYSVAR => Self::UnsupportedSysvar, ILLEGAL_OWNER => Self::IllegalOwner, - ACCOUNTS_DATA_BUDGET_EXCEEDED => Self::AccountsDataBudgetExceeded, + MAX_ACCOUNTS_DATA_SIZE_EXCEEDED => Self::MaxAccountsDataSizeExceeded, ACTIVE_VOTE_ACCOUNT_CLOSE => Self::ActiveVoteAccountClose, _ => { // A valid custom error has no bits set in the upper 32 diff --git a/storage-proto/proto/transaction_by_addr.proto b/storage-proto/proto/transaction_by_addr.proto index c12cdd061..cd2bdd55e 100644 --- a/storage-proto/proto/transaction_by_addr.proto +++ b/storage-proto/proto/transaction_by_addr.proto @@ -112,7 +112,7 @@ enum InstructionErrorType { ARITHMETIC_OVERFLOW = 47; UNSUPPORTED_SYSVAR = 48; ILLEGAL_OWNER = 49; - ACCOUNTS_DATA_BUDGET_EXCEEDED = 50; + MAX_ACCOUNTS_DATA_SIZE_EXCEEDED = 50; ACTIVE_VOTE_ACCOUNT_CLOSE = 51; } diff --git a/storage-proto/src/convert.rs b/storage-proto/src/convert.rs index 98c8e57bb..6f682e789 100644 --- a/storage-proto/src/convert.rs +++ b/storage-proto/src/convert.rs @@ -670,7 +670,7 @@ impl TryFrom for TransactionError { 47 => InstructionError::ArithmeticOverflow, 48 => InstructionError::UnsupportedSysvar, 49 => InstructionError::IllegalOwner, - 50 => InstructionError::AccountsDataBudgetExceeded, + 50 => InstructionError::MaxAccountsDataSizeExceeded, 51 => InstructionError::ActiveVoteAccountClose, _ => return Err("Invalid InstructionError"), }; @@ -959,8 +959,8 @@ impl From for tx_by_addr::TransactionError { InstructionError::IllegalOwner => { tx_by_addr::InstructionErrorType::IllegalOwner } - InstructionError::AccountsDataBudgetExceeded => { - tx_by_addr::InstructionErrorType::AccountsDataBudgetExceeded + InstructionError::MaxAccountsDataSizeExceeded => { + tx_by_addr::InstructionErrorType::MaxAccountsDataSizeExceeded } InstructionError::ActiveVoteAccountClose => { tx_by_addr::InstructionErrorType::ActiveVoteAccountClose