From 4b63ab6cfba3897e12527f58a58f25bf916bef76 Mon Sep 17 00:00:00 2001 From: Sarfaraz Nawaz Date: Tue, 26 May 2026 12:03:32 +0530 Subject: [PATCH 1/2] chore: log all access violations --- svm/src/access_permissions.rs | 37 +++++++++++++++++++++----------- svm/src/transaction_processor.rs | 13 +++++++++++ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/svm/src/access_permissions.rs b/svm/src/access_permissions.rs index f1e2416..285bf4b 100644 --- a/svm/src/access_permissions.rs +++ b/svm/src/access_permissions.rs @@ -4,7 +4,7 @@ use solana_sdk_ids::loader_v4; use solana_svm_transaction::svm_message::SVMMessage; use solana_transaction_error::TransactionError; -use crate::transaction_execution_result::ExecutedTransaction; +use crate::{account_loader::LoadedTransaction, transaction_execution_result::ExecutedTransaction}; const MAGIC_PROGRAM_ID: Pubkey = Pubkey::from_str_const("Magic11111111111111111111111111111111111111"); @@ -46,30 +46,43 @@ impl ExecutedTransaction { } } - let mut offender = None; let is_mutable = |acc: &AccountSharedData| { acc.delegated() || acc.ephemeral() || acc.confined() || acc.undelegating() }; + + let logs = self.execution_details.log_messages.get_or_insert_default(); + let mut first = true; // For non-privileged payers, validate the rest of the accounts. // Skip the fee payer (index 0), as its writability is validated elsewhere. for (i, (pk, acc)) in accounts.iter().enumerate().skip(1) { // Enforce that any account intended to be writable must be a delegated account. if message.is_writable(i) && !is_mutable(acc) { - offender.replace((i, pk)); - break; + if first { + self.execution_details.status = Err(TransactionError::InvalidWritableAccount); + logs.push("Program Magic11111111111111111111111111111111111111 failed: InvalidWritableAccount" .to_string()); + } + first = false; + logs.push(format!( + "MagicBlock SVM check: Account {i} ({pk}) was illegally used as writable" + )); } } - if let Some((i, offender)) = offender { - self.execution_details.status = Err(TransactionError::InvalidWritableAccount); - let logs = self.execution_details.log_messages.get_or_insert_default(); + } + + pub(crate) fn log_accounts_info( + loaded_transaction: &LoadedTransaction, + message: &impl SVMMessage, + ) -> Vec { + let mut logs = vec![]; + for (i, (pk, acc)) in loaded_transaction.accounts.iter().enumerate().skip(1) { logs.push(format!( - "Program log: Account {i}: {offender} was illegally used as writable" + "{i}: {pk} => {}, {}, {}", + acc.delegated(), + acc.undelegating(), + message.is_writable(i) )); - logs.push( - "Program Magic11111111111111111111111111111111111111 failed: InvalidWritableAccount" - .to_string(), - ); } + logs } } diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index 20f7384..221a7a2 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -509,6 +509,7 @@ impl TransactionBatchProcessor { }; } + let before = ExecutedTransaction::log_accounts_info(&loaded_transaction, tx); let mut executed_tx = self.execute_loaded_transaction( callbacks, tx, @@ -521,6 +522,18 @@ impl TransactionBatchProcessor { ); executed_tx.validate_accounts_access(tx); + let after = + ExecutedTransaction::log_accounts_info(&executed_tx.loaded_transaction, tx); + + let logs = executed_tx + .execution_details + .log_messages + .get_or_insert_default(); + logs.push("before".to_owned()); + logs.extend(before); + logs.push("after".to_owned()); + logs.extend(after); + // Update loaded accounts cache with account states which might have changed. // Also update local program cache with modifications made by the transaction, // if it executed successfully. From 3b03e65c7a79246801f8d6666681f2c95dc0e823 Mon Sep 17 00:00:00 2001 From: Sarfaraz Nawaz Date: Tue, 26 May 2026 12:06:30 +0530 Subject: [PATCH 2/2] delete log_accounts_info --- svm/src/access_permissions.rs | 18 +----------------- svm/src/transaction_processor.rs | 12 ------------ 2 files changed, 1 insertion(+), 29 deletions(-) diff --git a/svm/src/access_permissions.rs b/svm/src/access_permissions.rs index 285bf4b..bbb8569 100644 --- a/svm/src/access_permissions.rs +++ b/svm/src/access_permissions.rs @@ -4,7 +4,7 @@ use solana_sdk_ids::loader_v4; use solana_svm_transaction::svm_message::SVMMessage; use solana_transaction_error::TransactionError; -use crate::{account_loader::LoadedTransaction, transaction_execution_result::ExecutedTransaction}; +use crate::transaction_execution_result::ExecutedTransaction; const MAGIC_PROGRAM_ID: Pubkey = Pubkey::from_str_const("Magic11111111111111111111111111111111111111"); @@ -68,22 +68,6 @@ impl ExecutedTransaction { } } } - - pub(crate) fn log_accounts_info( - loaded_transaction: &LoadedTransaction, - message: &impl SVMMessage, - ) -> Vec { - let mut logs = vec![]; - for (i, (pk, acc)) in loaded_transaction.accounts.iter().enumerate().skip(1) { - logs.push(format!( - "{i}: {pk} => {}, {}, {}", - acc.delegated(), - acc.undelegating(), - message.is_writable(i) - )); - } - logs - } } fn has_privileged_access(message: &impl SVMMessage) -> bool { diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index 221a7a2..2bbe6ac 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -509,7 +509,6 @@ impl TransactionBatchProcessor { }; } - let before = ExecutedTransaction::log_accounts_info(&loaded_transaction, tx); let mut executed_tx = self.execute_loaded_transaction( callbacks, tx, @@ -522,17 +521,6 @@ impl TransactionBatchProcessor { ); executed_tx.validate_accounts_access(tx); - let after = - ExecutedTransaction::log_accounts_info(&executed_tx.loaded_transaction, tx); - - let logs = executed_tx - .execution_details - .log_messages - .get_or_insert_default(); - logs.push("before".to_owned()); - logs.extend(before); - logs.push("after".to_owned()); - logs.extend(after); // Update loaded accounts cache with account states which might have changed. // Also update local program cache with modifications made by the transaction,