@@ -469,8 +469,28 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
469469 // This check is unnecessary for other load results (like `FeesOnly`),
470470 // as those states imply the transaction failed to load these other accounts,
471471 // and the fee payer is validated separately.
472- if let Err ( err) = loaded_transaction. validate_accounts_access( tx) {
473- processing_results. push( Err ( err) ) ;
472+ if let Err ( ( err, offender) ) = loaded_transaction. validate_accounts_access( tx) {
473+ // If an account access violation was detected, we construct a fake
474+ // execution for the convenience of the user, so that the transaction
475+ // will be persisted to the ledger with some useful debug information
476+ let execution_details = TransactionExecutionDetails {
477+ status: Err ( err) ,
478+ log_messages: Some ( vec![ format!(
479+ "Account {offender} was used as writeable\
480+ without being delegated to this ER"
481+ ) ] ) ,
482+ accounts_data_len_delta: 0 ,
483+ return_data: None ,
484+ executed_units: 0 ,
485+ inner_instructions: None ,
486+ } ;
487+ let txn = ExecutedTransaction {
488+ loaded_transaction,
489+ execution_details,
490+ programs_modified_by_tx: Default :: default ( ) ,
491+ } ;
492+ let result = ProcessedTransaction :: Executed ( Box :: new( txn) ) ;
493+ processing_results. push( Ok ( result) ) ;
474494 continue ;
475495 }
476496 // observe all the account balances before executing the transaction
@@ -2398,86 +2418,6 @@ mod tests {
23982418 ) ;
23992419 }
24002420
2401- #[ test]
2402- fn test_validate_transaction_fee_payer_rent_paying ( ) {
2403- let lamports_per_signature = 5000 ;
2404- let message = new_unchecked_sanitized_message ( Message :: new_with_blockhash (
2405- & [ ] ,
2406- Some ( & Pubkey :: new_unique ( ) ) ,
2407- & Hash :: new_unique ( ) ,
2408- ) ) ;
2409- let compute_budget_limits = process_compute_budget_instructions (
2410- SVMMessage :: program_instructions_iter ( & message) ,
2411- & FeatureSet :: default ( ) ,
2412- )
2413- . unwrap ( ) ;
2414- let fee_payer_address = message. fee_payer ( ) ;
2415- let mut rent_collector = RentCollector :: default ( ) ;
2416- rent_collector. rent . lamports_per_byte_year = 1_000_000 ;
2417- let min_balance = rent_collector. rent . minimum_balance ( 0 ) ;
2418- let transaction_fee = lamports_per_signature;
2419- let starting_balance = min_balance - 1 ;
2420- let mut fee_payer_account = AccountSharedData :: new ( starting_balance, 0 , & Pubkey :: default ( ) ) ;
2421- fee_payer_account. set_delegated ( true ) ;
2422- let fee_payer_rent_debit = rent_collector
2423- . get_rent_due (
2424- fee_payer_account. lamports ( ) ,
2425- fee_payer_account. data ( ) . len ( ) ,
2426- fee_payer_account. rent_epoch ( ) ,
2427- )
2428- . lamports ( ) ;
2429- assert ! ( fee_payer_rent_debit > 0 ) ;
2430-
2431- let mut mock_accounts = HashMap :: new ( ) ;
2432- mock_accounts. insert ( * fee_payer_address, fee_payer_account. clone ( ) ) ;
2433- let mock_bank = MockBankCallback {
2434- account_shared_data : Arc :: new ( RwLock :: new ( mock_accounts) ) ,
2435- ..Default :: default ( )
2436- } ;
2437- let mut account_loader = ( & mock_bank) . into ( ) ;
2438-
2439- let mut error_counters = TransactionErrorMetrics :: default ( ) ;
2440- let result =
2441- TransactionBatchProcessor :: < TestForkGraph > :: validate_transaction_nonce_and_fee_payer (
2442- & mut account_loader,
2443- & message,
2444- CheckedTransactionDetails :: new ( None , lamports_per_signature) ,
2445- & Hash :: default ( ) ,
2446- FeeStructure :: default ( ) . lamports_per_signature ,
2447- & rent_collector,
2448- & mut error_counters,
2449- & mock_bank,
2450- ) ;
2451-
2452- let post_validation_fee_payer_account = {
2453- let mut account = fee_payer_account. clone ( ) ;
2454- account. set_rent_epoch ( 1 ) ;
2455- account. set_lamports ( starting_balance - transaction_fee - fee_payer_rent_debit) ;
2456- account
2457- } ;
2458-
2459- assert_eq ! (
2460- result,
2461- Ok ( ValidatedTransactionDetails {
2462- rollback_accounts: RollbackAccounts :: new(
2463- None , // nonce
2464- * fee_payer_address,
2465- post_validation_fee_payer_account. clone( ) ,
2466- fee_payer_rent_debit,
2467- 0 , // rent epoch
2468- ) ,
2469- compute_budget_limits,
2470- fee_details: FeeDetails :: new( transaction_fee, 0 ) ,
2471- loaded_fee_payer_account: LoadedTransactionAccount {
2472- loaded_size: fee_payer_account. data( ) . len( ) ,
2473- account: post_validation_fee_payer_account,
2474- rent_collected: fee_payer_rent_debit,
2475- } ,
2476- fee_payer_address: * fee_payer_address,
2477- } )
2478- ) ;
2479- }
2480-
24812421 #[ test]
24822422 fn test_validate_transaction_fee_payer_not_found ( ) {
24832423 let lamports_per_signature = 5000 ;
0 commit comments