88 crate :: {
99 accounts:: { compile_accounts, CompiledAccounts } ,
1010 result:: { Check , InstructionResult } ,
11+ sysvar:: Sysvars ,
1112 Mollusk , DEFAULT_LOADER_KEY ,
1213 } ,
1314 mollusk_svm_fuzz_fixture_firedancer:: {
1920 metadata:: Metadata as FuzzMetadata ,
2021 Fixture as FuzzFixture ,
2122 } ,
23+ solana_compute_budget:: compute_budget:: ComputeBudget ,
2224 solana_sdk:: {
2325 account:: AccountSharedData ,
24- instruction:: { Instruction , InstructionError } ,
26+ instruction:: { AccountMeta , Instruction , InstructionError } ,
2527 pubkey:: Pubkey ,
2628 } ,
2729} ;
@@ -54,6 +56,16 @@ fn instr_err_to_num(error: &InstructionError) -> i32 {
5456 i32:: from_le_bytes ( ( & serialized_err[ 0 ..4 ] ) . try_into ( ) . unwrap ( ) ) + 1
5557}
5658
59+ fn num_to_instr_err ( num : i32 , custom_code : u32 ) -> InstructionError {
60+ let val = ( num - 1 ) as u64 ;
61+ let le = val. to_le_bytes ( ) ;
62+ let mut deser = bincode:: deserialize ( & le) . unwrap ( ) ;
63+ if custom_code != 0 && matches ! ( deser, InstructionError :: Custom ( _) ) {
64+ deser = InstructionError :: Custom ( custom_code) ;
65+ }
66+ deser
67+ }
68+
5769fn build_fixture_context (
5870 mollusk : & Mollusk ,
5971 instruction : & Instruction ,
@@ -98,6 +110,56 @@ fn build_fixture_context(
98110 }
99111}
100112
113+ fn parse_fixture_context (
114+ context : & FuzzContext ,
115+ ) -> ( Mollusk , Instruction , Vec < ( Pubkey , AccountSharedData ) > ) {
116+ let FuzzContext {
117+ program_id,
118+ accounts,
119+ instruction_accounts,
120+ instruction_data,
121+ compute_units_available,
122+ epoch_context,
123+ ..
124+ } = context;
125+
126+ let compute_budget = ComputeBudget {
127+ compute_unit_limit : * compute_units_available,
128+ ..Default :: default ( )
129+ } ;
130+
131+ let accounts = accounts
132+ . iter ( )
133+ . map ( |( key, acct, _) | ( * key, acct. clone ( ) ) )
134+ . collect :: < Vec < _ > > ( ) ;
135+
136+ let mollusk = Mollusk {
137+ compute_budget,
138+ feature_set : epoch_context. feature_set . clone ( ) ,
139+ sysvars : Sysvars :: fill_from_accounts ( & accounts) ,
140+ ..Default :: default ( )
141+ } ;
142+
143+ let metas = instruction_accounts
144+ . iter ( )
145+ . map ( |ia| {
146+ let pubkey = accounts
147+ . get ( ia. index_in_caller as usize )
148+ . expect ( "Index out of bounds" )
149+ . 0 ;
150+ AccountMeta {
151+ pubkey,
152+ is_signer : ia. is_signer ,
153+ is_writable : ia. is_writable ,
154+ }
155+ } )
156+ . collect :: < Vec < _ > > ( ) ;
157+
158+ let instruction = Instruction :: new_with_bytes ( * program_id, instruction_data, metas) ;
159+
160+ ( mollusk, instruction, accounts)
161+ }
162+
101163fn build_fixture_effects ( context : & FuzzContext , result : & InstructionResult ) -> FuzzEffects {
102164 let mut program_custom_code = 0 ;
103165 let program_result = match & result. raw_result {
@@ -136,6 +198,47 @@ fn build_fixture_effects(context: &FuzzContext, result: &InstructionResult) -> F
136198 }
137199}
138200
201+ fn parse_fixture_effects (
202+ mollusk : & Mollusk ,
203+ accounts : & [ ( Pubkey , AccountSharedData ) ] ,
204+ effects : & FuzzEffects ,
205+ ) -> InstructionResult {
206+ let raw_result = if effects. program_result == 0 {
207+ Ok ( ( ) )
208+ } else {
209+ Err ( num_to_instr_err (
210+ effects. program_result ,
211+ effects. program_custom_code ,
212+ ) )
213+ } ;
214+
215+ let program_result = raw_result. clone ( ) . into ( ) ;
216+
217+ let resulting_accounts = accounts
218+ . iter ( )
219+ . map ( |( key, acct) | {
220+ let resulting_account = effects
221+ . modified_accounts
222+ . iter ( )
223+ . find ( |( k, _, _) | k == key)
224+ . map ( |( _, acct, _) | acct. clone ( ) )
225+ . unwrap_or_else ( || acct. clone ( ) ) ;
226+ ( * key, resulting_account)
227+ } )
228+ . collect ( ) ;
229+
230+ InstructionResult {
231+ program_result,
232+ raw_result,
233+ execution_time : 0 , // TODO: Omitted for now.
234+ compute_units_consumed : mollusk
235+ . compute_budget
236+ . compute_unit_limit
237+ . saturating_sub ( effects. compute_units_available ) ,
238+ resulting_accounts,
239+ }
240+ }
241+
139242fn instruction_metadata ( ) -> FuzzMetadata {
140243 FuzzMetadata {
141244 // Mollusk is always an instruction harness.
@@ -160,3 +263,50 @@ pub fn build_fixture_from_mollusk_test(
160263 output,
161264 }
162265}
266+
267+ pub fn load_firedancer_fixture (
268+ fixture : & mollusk_svm_fuzz_fixture_firedancer:: Fixture ,
269+ ) -> (
270+ Mollusk ,
271+ Instruction ,
272+ Vec < ( Pubkey , AccountSharedData ) > ,
273+ InstructionResult ,
274+ ) {
275+ let ( mollusk, instruction, accounts) = parse_fixture_context ( & fixture. input ) ;
276+ let result = parse_fixture_effects ( & mollusk, & accounts, & fixture. output ) ;
277+ ( mollusk, instruction, accounts, result)
278+ }
279+
280+ #[ test]
281+ fn test_num_to_instr_err ( ) {
282+ [
283+ InstructionError :: InvalidArgument ,
284+ InstructionError :: InvalidInstructionData ,
285+ InstructionError :: InvalidAccountData ,
286+ InstructionError :: AccountDataTooSmall ,
287+ InstructionError :: InsufficientFunds ,
288+ InstructionError :: IncorrectProgramId ,
289+ InstructionError :: MissingRequiredSignature ,
290+ InstructionError :: AccountAlreadyInitialized ,
291+ InstructionError :: UninitializedAccount ,
292+ InstructionError :: UnbalancedInstruction ,
293+ InstructionError :: ModifiedProgramId ,
294+ InstructionError :: Custom ( 0 ) ,
295+ InstructionError :: Custom ( 1 ) ,
296+ InstructionError :: Custom ( 2 ) ,
297+ InstructionError :: Custom ( 5 ) ,
298+ InstructionError :: Custom ( 400 ) ,
299+ InstructionError :: Custom ( 600 ) ,
300+ InstructionError :: Custom ( 1_000 ) ,
301+ ]
302+ . into_iter ( )
303+ . for_each ( |ie| {
304+ let mut custom_code = 0 ;
305+ if let InstructionError :: Custom ( c) = & ie {
306+ custom_code = * c;
307+ }
308+ let result = instr_err_to_num ( & ie) ;
309+ let err = num_to_instr_err ( result, custom_code) ;
310+ assert_eq ! ( ie, err) ;
311+ } )
312+ }
0 commit comments