@@ -872,8 +872,21 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
872872 let return_data = transaction_context. get_return_data ( ) . 1 . to_vec ( ) ;
873873
874874 Some ( InstrEffects {
875- custom_err : if let Err ( InstructionError :: Custom ( x) ) = result {
876- Some ( x)
875+ custom_err : if let Err ( InstructionError :: Custom ( code) ) = result {
876+ #[ cfg( feature = "core-bpf" ) ]
877+ // See comment below under `result` for special-casing of custom
878+ // errors for Core BPF programs.
879+ if program_id == & solana_sdk:: address_lookup_table:: program:: id ( )
880+ && ( code == 10 || code == 11 )
881+ {
882+ None
883+ } else if program_id == & solana_sdk:: config:: program:: id ( ) && ( code == 0 || code == 1 ) {
884+ None
885+ } else {
886+ Some ( code)
887+ }
888+ #[ cfg( not( feature = "core-bpf" ) ) ]
889+ Some ( code)
877890 } else {
878891 None
879892 } ,
@@ -904,6 +917,47 @@ fn execute_instr(mut input: InstrContext) -> Option<InstrEffects> {
904917 {
905918 return InstructionError :: ComputationalBudgetExceeded ;
906919 }
920+ #[ cfg( feature = "core-bpf" ) ]
921+ // Another such error case arises when a program performs a write
922+ // to an account, but the data it writes is the exact same data
923+ // that's currently stored in the account state.
924+ //
925+ // For builtins, the `TransactionContext` is invoked when any write
926+ // is performed, asking it whether or not a write is allowed,
927+ // regardless of the data being written. If the account is not
928+ // writable, it throws `InstructionError::ReadonlyDataModified`.
929+ //
930+ // For BPF programs, writes to readonly accounts are caught _after_
931+ // the VM finishes execution, when the loader inspects the
932+ // serialized input data region. If a write was performed that did
933+ // not modify serialized account state, then no error is thrown.
934+ //
935+ // As a result, Core BPF programs have been outfitted with custom
936+ // errors when `is_writable` checks fail. These errors are
937+ // special-cased below to avoid fixture mismatches.
938+ match err {
939+ InstructionError :: Custom ( code) => {
940+ if program_id == & solana_sdk:: address_lookup_table:: program:: id ( ) {
941+ // Special-cased custom error codes for the ALT program.
942+ if code == 10 {
943+ return InstructionError :: ExecutableDataModified ;
944+ }
945+ if code == 11 {
946+ return InstructionError :: ReadonlyDataModified ;
947+ }
948+ }
949+ if program_id == & solana_sdk:: config:: program:: id ( ) {
950+ // Special-cased custom error codes for the Config program.
951+ if code == 0 {
952+ return InstructionError :: ExecutableDataModified ;
953+ }
954+ if code == 1 {
955+ return InstructionError :: ReadonlyDataModified ;
956+ }
957+ }
958+ }
959+ _ => { }
960+ }
907961 err
908962 } ) ,
909963 modified_accounts : transaction_context
0 commit comments