diff --git a/banks-interface/src/lib.rs b/banks-interface/src/lib.rs index 244bd0ab975..81ab76cc575 100644 --- a/banks-interface/src/lib.rs +++ b/banks-interface/src/lib.rs @@ -36,6 +36,7 @@ pub struct TransactionStatus { pub struct TransactionSimulationDetails { pub logs: Vec, pub units_consumed: u64, + pub loaded_accounts_data_size: u32, pub return_data: Option, pub inner_instructions: Option>, } diff --git a/banks-server/src/banks_server.rs b/banks-server/src/banks_server.rs index fae5d1ace4e..5e02c5778e2 100644 --- a/banks-server/src/banks_server.rs +++ b/banks-server/src/banks_server.rs @@ -183,6 +183,7 @@ fn simulate_transaction( logs, post_simulation_accounts: _, units_consumed, + loaded_accounts_data_size, return_data, inner_instructions, } = bank.simulate_transaction_unchecked(&sanitized_transaction, true); @@ -190,6 +191,7 @@ fn simulate_transaction( let simulation_details = TransactionSimulationDetails { logs, units_consumed, + loaded_accounts_data_size, return_data, inner_instructions, }; diff --git a/rpc-client-api/src/client_error.rs b/rpc-client-api/src/client_error.rs index e8a7aca9a2a..49f2cad8474 100644 --- a/rpc-client-api/src/client_error.rs +++ b/rpc-client-api/src/client_error.rs @@ -8,6 +8,7 @@ use { }; #[derive(ThisError, Debug)] +#[allow(clippy::large_enum_variant)] pub enum ErrorKind { #[error(transparent)] Io(#[from] io::Error), diff --git a/rpc-client-types/src/response.rs b/rpc-client-types/src/response.rs index 05764cbafa7..117c5be7597 100644 --- a/rpc-client-types/src/response.rs +++ b/rpc-client-types/src/response.rs @@ -401,6 +401,7 @@ pub struct RpcSimulateTransactionResult { pub logs: Option>, pub accounts: Option>>, pub units_consumed: Option, + pub loaded_accounts_data_size: Option, pub return_data: Option, pub inner_instructions: Option>, pub replacement_blockhash: Option, diff --git a/rpc-client/src/mock_sender.rs b/rpc-client/src/mock_sender.rs index e2b7e5562b5..ac330e68267 100644 --- a/rpc-client/src/mock_sender.rs +++ b/rpc-client/src/mock_sender.rs @@ -305,6 +305,7 @@ impl RpcSender for MockSender { logs: None, accounts: None, units_consumed: None, + loaded_accounts_data_size: None, return_data: None, inner_instructions: None, replacement_blockhash: None diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 88f34b0fb57..aacf0ae0d86 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -3900,6 +3900,7 @@ pub mod rpc_full { logs, post_simulation_accounts: _, units_consumed, + loaded_accounts_data_size, return_data, inner_instructions: _, // Always `None` due to `enable_cpi_recording = false` } = preflight_bank.simulate_transaction(&transaction, false) @@ -3919,6 +3920,7 @@ pub mod rpc_full { logs: Some(logs), accounts: None, units_consumed: Some(units_consumed), + loaded_accounts_data_size: Some(loaded_accounts_data_size), return_data: return_data.map(|return_data| return_data.into()), inner_instructions: None, replacement_blockhash: None, @@ -3998,6 +4000,7 @@ pub mod rpc_full { logs, post_simulation_accounts, units_consumed, + loaded_accounts_data_size, return_data, inner_instructions, } = bank.simulate_transaction(&transaction, enable_cpi_recording); @@ -4064,6 +4067,7 @@ pub mod rpc_full { logs: Some(logs), accounts, units_consumed: Some(units_consumed), + loaded_accounts_data_size: Some(loaded_accounts_data_size), return_data: return_data.map(|return_data| return_data.into()), inner_instructions, replacement_blockhash: blockhash, @@ -5976,6 +5980,12 @@ pub mod tests { // Simulation bank must be frozen bank.freeze(); + let loaded_account_data_size = bank + .get_account(&system_program::id()) + .unwrap() + .data() + .len() as u32; + // Good signature with sigVerify=true let req = format!( r#"{{"jsonrpc":"2.0", @@ -6015,6 +6025,7 @@ pub mod tests { ], "err":null, "innerInstructions": null, + "loadedAccountsDataSize": loaded_account_data_size, "logs":[ "Program 11111111111111111111111111111111 invoke [1]", "Program 11111111111111111111111111111111 success" @@ -6101,6 +6112,7 @@ pub mod tests { "accounts":null, "err":null, "innerInstructions":null, + "loadedAccountsDataSize": loaded_account_data_size, "logs":[ "Program 11111111111111111111111111111111 invoke [1]", "Program 11111111111111111111111111111111 success" @@ -6131,6 +6143,7 @@ pub mod tests { "accounts":null, "err":null, "innerInstructions":null, + "loadedAccountsDataSize": loaded_account_data_size, "logs":[ "Program 11111111111111111111111111111111 invoke [1]", "Program 11111111111111111111111111111111 success" @@ -6185,6 +6198,7 @@ pub mod tests { "err":"BlockhashNotFound", "accounts":null, "innerInstructions":null, + "loadedAccountsDataSize":0, "logs":[], "replacementBlockhash": null, "returnData": null, @@ -6218,6 +6232,7 @@ pub mod tests { "accounts":null, "err":null, "innerInstructions":null, + "loadedAccountsDataSize": loaded_account_data_size, "logs":[ "Program 11111111111111111111111111111111 invoke [1]", "Program 11111111111111111111111111111111 success" @@ -6310,6 +6325,17 @@ pub mod tests { // Simulation bank must be frozen bank.freeze(); + let loaded_accounts_data_size = bank + .get_account(&token_account_pubkey) + .unwrap() + .data() + .len() as u32 + + bank + .get_account(&system_program::id()) + .unwrap() + .data() + .len() as u32; + let req = format!( r#"{{"jsonrpc":"2.0", "id":1, @@ -6366,6 +6392,7 @@ pub mod tests { ], "err": null, "innerInstructions": null, + "loadedAccountsDataSize": loaded_accounts_data_size, "logs":[ "Program 11111111111111111111111111111111 invoke [1]", "Program 11111111111111111111111111111111 success" @@ -6422,6 +6449,17 @@ pub mod tests { // Simulation bank must be frozen bank.freeze(); + let loaded_accounts_data_size = bank + .get_account(&TestBuiltinEntrypoint::PROGRAM_ID) + .unwrap() + .data() + .len() as u32 + + bank + .get_account(&system_program::id()) + .unwrap() + .data() + .len() as u32; + // `innerInstructions` not provided, should not be in response let req = format!( r#"{{"jsonrpc":"2.0", @@ -6443,6 +6481,7 @@ pub mod tests { "accounts": null, "err":null, "innerInstructions": null, + "loadedAccountsDataSize": loaded_accounts_data_size, "logs":[ "Program TestProgram11111111111111111111111111111111 invoke [1]", "I am logging from a builtin program!", @@ -6486,6 +6525,7 @@ pub mod tests { "accounts": null, "err":null, "innerInstructions": null, + "loadedAccountsDataSize": loaded_accounts_data_size, "logs":[ "Program TestProgram11111111111111111111111111111111 invoke [1]", "I am logging from a builtin program!", @@ -6550,6 +6590,7 @@ pub mod tests { ] } ], + "loadedAccountsDataSize": loaded_accounts_data_size, "logs":[ "Program TestProgram11111111111111111111111111111111 invoke [1]", "I am logging from a builtin program!", @@ -6811,7 +6852,7 @@ pub mod tests { assert_eq!( res, Some( - r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","innerInstructions":null,"logs":[],"replacementBlockhash":null,"returnData":null,"unitsConsumed":0}},"id":1}"#.to_string(), + r#"{"jsonrpc":"2.0","error":{"code":-32002,"message":"Transaction simulation failed: Blockhash not found","data":{"accounts":null,"err":"BlockhashNotFound","innerInstructions":null,"loadedAccountsDataSize":0,"logs":[],"replacementBlockhash":null,"returnData":null,"unitsConsumed":0}},"id":1}"#.to_string(), ) ); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 84dfee10ff8..028990fb4d8 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -339,6 +339,7 @@ pub struct TransactionSimulationResult { pub logs: TransactionLogMessages, pub post_simulation_accounts: Vec, pub units_consumed: u64, + pub loaded_accounts_data_size: u32, pub return_data: Option, pub inner_instructions: Option>, } @@ -3311,6 +3312,7 @@ impl Bank { return_data, inner_instructions, units_consumed, + loaded_accounts_data_size, ) = match processing_result { Ok(processed_tx) => match processed_tx { ProcessedTransaction::Executed(executed_tx) => { @@ -3328,13 +3330,20 @@ impl Bank { details.return_data, details.inner_instructions, details.executed_units, + executed_tx.loaded_transaction.loaded_accounts_data_size, ) } - ProcessedTransaction::FeesOnly(fees_only_tx) => { - (vec![], Err(fees_only_tx.load_error), None, None, None, 0) - } + ProcessedTransaction::FeesOnly(fees_only_tx) => ( + vec![], + Err(fees_only_tx.load_error), + None, + None, + None, + 0, + fees_only_tx.rollback_accounts.data_size() as u32, + ), }, - Err(error) => (vec![], Err(error), None, None, None, 0), + Err(error) => (vec![], Err(error), None, None, None, 0, 0), }; let logs = logs.unwrap_or_default(); @@ -3343,6 +3352,7 @@ impl Bank { logs, post_simulation_accounts, units_consumed, + loaded_accounts_data_size, return_data, inner_instructions, } diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index f7a1c977e45..ca3cbdefa9c 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -13167,6 +13167,8 @@ fn test_failed_simulation_compute_units() { const TEST_UNITS: u64 = 10_000; const MOCK_BUILTIN_UNITS: u64 = 1; let expected_consumed_units = TEST_UNITS + MOCK_BUILTIN_UNITS; + let expected_loaded_program_account_data_size = + bank.get_account(&program_id).unwrap().data().len() as u32; declare_process_instruction!(MockBuiltin, MOCK_BUILTIN_UNITS, |invoke_context| { invoke_context.consume_checked(TEST_UNITS).unwrap(); Err(InstructionError::InvalidInstructionData) @@ -13182,6 +13184,10 @@ fn test_failed_simulation_compute_units() { let sanitized = RuntimeTransaction::from_transaction_for_tests(transaction); let simulation = bank.simulate_transaction(&sanitized, false); assert_eq!(expected_consumed_units, simulation.units_consumed); + assert_eq!( + expected_loaded_program_account_data_size, + simulation.loaded_accounts_data_size + ); } /// Test that simulations report the load error of fees-only transactions @@ -13211,6 +13217,7 @@ fn test_failed_simulation_load_error() { logs: vec![], post_simulation_accounts: vec![], units_consumed: 0, + loaded_accounts_data_size: 0, return_data: None, inner_instructions: None, } diff --git a/svm/examples/json-rpc/server/src/rpc_process.rs b/svm/examples/json-rpc/server/src/rpc_process.rs index 74968fce11e..69a67be816a 100644 --- a/svm/examples/json-rpc/server/src/rpc_process.rs +++ b/svm/examples/json-rpc/server/src/rpc_process.rs @@ -120,6 +120,7 @@ struct TransactionSimulationResult { pub logs: TransactionLogMessages, pub post_simulation_accounts: Vec, pub units_consumed: u64, + pub loaded_accounts_data_size: u32, pub return_data: Option, pub inner_instructions: Option>, } @@ -365,12 +366,14 @@ impl JsonRpcRequestProcessor { }; let logs = logs.unwrap_or_default(); let units_consumed: u64 = 0; + let loaded_accounts_data_size: u32 = 0; TransactionSimulationResult { result: flattened_result, logs, post_simulation_accounts, units_consumed, + loaded_accounts_data_size, return_data, inner_instructions, } @@ -686,6 +689,7 @@ pub mod rpc { logs, post_simulation_accounts, units_consumed, + loaded_accounts_data_size, return_data, inner_instructions, } = meta.simulate_transaction_unchecked(&transaction, enable_cpi_recording); @@ -751,6 +755,7 @@ pub mod rpc { logs: Some(logs), accounts, units_consumed: Some(units_consumed), + loaded_accounts_data_size: Some(loaded_accounts_data_size), return_data: return_data.map(|return_data| return_data.into()), inner_instructions, replacement_blockhash: None, diff --git a/svm/src/account_loader.rs b/svm/src/account_loader.rs index c715d518f0a..c9bc08026ed 100644 --- a/svm/src/account_loader.rs +++ b/svm/src/account_loader.rs @@ -123,11 +123,7 @@ pub(crate) struct LoadedTransactionAccount { #[cfg_attr(feature = "dev-context-only-utils", derive(Default))] #[cfg_attr( feature = "dev-context-only-utils", - field_qualifiers( - program_indices(pub), - loaded_accounts_data_size(pub), - compute_budget(pub) - ) + field_qualifiers(program_indices(pub), compute_budget(pub)) )] pub struct LoadedTransaction { pub accounts: Vec, @@ -137,7 +133,7 @@ pub struct LoadedTransaction { pub(crate) compute_budget: SVMTransactionExecutionBudget, pub rent: TransactionRent, pub rent_debits: RentDebits, - pub(crate) loaded_accounts_data_size: u32, + pub loaded_accounts_data_size: u32, } #[derive(PartialEq, Eq, Debug, Clone)]