Line data Source code
1 : /* fd_solfuzz_exec.c contains internal executors */
2 :
3 : #include "fd_solfuzz_private.h"
4 : #include "generated/block.pb.h"
5 : #include "generated/invoke.pb.h"
6 : #include "generated/txn.pb.h"
7 : #include "generated/vm.pb.h"
8 : #include "generated/elf.pb.h"
9 : #include "../fd_executor_err.h"
10 : #include <assert.h>
11 :
12 : /*
13 : * fixtures
14 : */
15 :
16 : static int
17 : sol_compat_cmp_binary_strict( void const * effects,
18 : void const * expected,
19 : pb_msgdesc_t const * encode_type,
20 0 : fd_spad_t * spad ) {
21 0 : #define MAX_SZ 32*1024*1024
22 0 : FD_SPAD_FRAME_BEGIN( spad ) {
23 0 : if( effects==NULL ) {
24 0 : FD_LOG_WARNING(( "No output effects" ));
25 0 : return 0;
26 0 : }
27 :
28 : /* Note: Most likely this spad allocation won't fail. If it does, you may need to bump
29 : the allocated spad memory amount in fd_exec_sol_compat.c. */
30 0 : ulong out_sz = MAX_SZ;
31 0 : uchar * out = fd_spad_alloc( spad, 1UL, out_sz );
32 0 : if( !sol_compat_encode( out, &out_sz, effects, encode_type ) ) {
33 0 : FD_LOG_WARNING(( "Error encoding effects" ));
34 0 : return 0;
35 0 : }
36 :
37 0 : ulong exp_sz = MAX_SZ;
38 0 : uchar * exp = fd_spad_alloc( spad, 1UL, exp_sz );
39 0 : if( !sol_compat_encode( exp, &exp_sz, expected, encode_type ) ) {
40 0 : FD_LOG_WARNING(( "Error encoding expected" ));
41 0 : return 0;
42 0 : }
43 :
44 0 : if( out_sz!=exp_sz ) {
45 0 : FD_LOG_WARNING(( "Binary cmp failed: different size. out_sz=%lu exp_sz=%lu", out_sz, exp_sz ));
46 0 : return 0;
47 0 : }
48 0 : if( !fd_memeq( out, exp, out_sz ) ) {
49 0 : FD_LOG_WARNING(( "Binary cmp failed: different values." ));
50 0 : return 0;
51 0 : }
52 :
53 0 : return 1;
54 0 : } FD_SPAD_FRAME_END;
55 0 : #undef MAX_SIZE
56 0 : }
57 :
58 : static int
59 : _diff_txn_acct( fd_exec_test_acct_state_t * expected,
60 0 : fd_exec_test_acct_state_t * actual ) {
61 : /* AcctState -> address (This must hold true when calling this function!) */
62 0 : assert( fd_memeq( expected->address, actual->address, sizeof(fd_pubkey_t) ) );
63 :
64 : /* AcctState -> lamports */
65 0 : if( expected->lamports != actual->lamports ) {
66 0 : FD_LOG_WARNING(( "Lamports mismatch: expected=%lu actual=%lu", expected->lamports, actual->lamports ));
67 0 : return 0;
68 0 : }
69 :
70 : /* AcctState -> data */
71 0 : if( expected->data != NULL || actual->data != NULL ) {
72 0 : if( expected->data == NULL ) {
73 0 : FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" ));
74 0 : return 0;
75 0 : }
76 :
77 0 : if( actual->data == NULL ) {
78 0 : FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" ));
79 0 : return 0;
80 0 : }
81 :
82 0 : if( expected->data->size != actual->data->size ) {
83 0 : FD_LOG_WARNING(( "Account data size mismatch: expected=%u actual=%u", expected->data->size, actual->data->size ));
84 0 : return 0;
85 0 : }
86 :
87 0 : if( !fd_memeq( expected->data->bytes, actual->data->bytes, expected->data->size ) ) {
88 0 : FD_LOG_WARNING(( "Account data mismatch" ));
89 0 : return 0;
90 0 : }
91 0 : }
92 :
93 : /* AcctState -> executable */
94 0 : if( expected->executable != actual->executable ) {
95 0 : FD_LOG_WARNING(( "Executable mismatch: expected=%d actual=%d", expected->executable, actual->executable ));
96 0 : return 0;
97 0 : }
98 :
99 : /* AcctState -> owner */
100 0 : if( !fd_memeq( expected->owner, actual->owner, sizeof(fd_pubkey_t) ) ) {
101 0 : char a[ FD_BASE58_ENCODED_32_SZ ];
102 0 : char b[ FD_BASE58_ENCODED_32_SZ ];
103 0 : FD_LOG_WARNING(( "Owner mismatch: expected=%s, actual=%s", fd_acct_addr_cstr( a, expected->owner ), fd_acct_addr_cstr( b, actual->owner ) ));
104 0 : return 0;
105 0 : }
106 :
107 0 : return 1;
108 0 : }
109 :
110 :
111 : static int
112 : _diff_resulting_states( fd_exec_test_resulting_state_t * expected,
113 0 : fd_exec_test_resulting_state_t * actual ) {
114 : // Verify that the number of accounts are the same
115 0 : if( expected->acct_states_count != actual->acct_states_count ) {
116 0 : FD_LOG_WARNING(( "Account states count mismatch: expected=%u actual=%u", expected->acct_states_count, actual->acct_states_count ));
117 0 : return 0;
118 0 : }
119 :
120 : // Verify that the account states are the same
121 0 : for( ulong i = 0; i < expected->acct_states_count; ++i ) {
122 0 : for( ulong j = 0; j < actual->acct_states_count; ++j ) {
123 0 : if( fd_memeq( expected->acct_states[i].address, actual->acct_states[j].address, sizeof(fd_pubkey_t) ) ) {
124 0 : if( !_diff_txn_acct( &expected->acct_states[i], &actual->acct_states[j] ) ) {
125 0 : return 0;
126 0 : }
127 0 : }
128 0 : }
129 0 : }
130 :
131 : // TODO: resulting_state -> rent_debits, resulting_state->transaction_rent
132 0 : return 1;
133 0 : }
134 :
135 : static int
136 : sol_compat_cmp_txn( fd_exec_test_txn_result_t * expected,
137 0 : fd_exec_test_txn_result_t * actual ) {
138 : /* TxnResult -> executed */
139 0 : if( expected->executed != actual->executed ) {
140 0 : FD_LOG_WARNING(( "Executed mismatch: expected=%d actual=%d", expected->executed, actual->executed ));
141 0 : return 0;
142 0 : }
143 :
144 : /* TxnResult -> sanitization_error */
145 0 : if( expected->sanitization_error != actual->sanitization_error ) {
146 0 : FD_LOG_WARNING(( "Sanitization error mismatch: expected=%d actual=%d", expected->sanitization_error, actual->sanitization_error ));
147 0 : return 0;
148 0 : }
149 :
150 : /* TxnResult -> resulting_state */
151 0 : if( !_diff_resulting_states( &expected->resulting_state, &actual->resulting_state ) ) {
152 0 : return 0;
153 0 : }
154 :
155 : /* TxnResult -> rent */
156 0 : if( expected->rent != actual->rent ) {
157 0 : FD_LOG_WARNING(( "Rent mismatch: expected=%lu actual=%lu", expected->rent, actual->rent ));
158 0 : return 0;
159 0 : }
160 :
161 : /* TxnResult -> is_ok */
162 0 : if( expected->is_ok != actual->is_ok ) {
163 0 : FD_LOG_WARNING(( "Is ok mismatch: expected=%d actual=%d", expected->is_ok, actual->is_ok ));
164 0 : return 0;
165 0 : }
166 :
167 : /* TxnResult -> status */
168 0 : if( expected->status != actual->status ) {
169 0 : FD_LOG_WARNING(( "Status mismatch: expected=%u actual=%u", expected->status, actual->status ));
170 0 : return 0;
171 0 : }
172 :
173 : /* TxnResult -> instruction_error */
174 0 : if( expected->instruction_error != actual->instruction_error ) {
175 0 : FD_LOG_WARNING(( "Instruction error mismatch: expected=%u actual=%u", expected->instruction_error, actual->instruction_error ));
176 0 : return 0;
177 0 : }
178 :
179 0 : if( expected->instruction_error ) {
180 : /* TxnResult -> instruction_error_index */
181 0 : if( expected->instruction_error_index != actual->instruction_error_index ) {
182 0 : FD_LOG_WARNING(( "Instruction error index mismatch: expected=%u actual=%u", expected->instruction_error_index, actual->instruction_error_index ));
183 0 : return 0;
184 0 : }
185 :
186 : /* TxnResult -> custom_error */
187 0 : if( expected->instruction_error == (ulong) -FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR && expected->custom_error != actual->custom_error ) {
188 0 : FD_LOG_WARNING(( "Custom error mismatch: expected=%u actual=%u", expected->custom_error, actual->custom_error ));
189 0 : return 0;
190 0 : }
191 0 : }
192 :
193 : /* TxnResult -> return_data */
194 0 : if( expected->return_data != NULL || actual->return_data != NULL ) {
195 0 : if( expected->return_data == NULL ) {
196 0 : FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" ));
197 0 : return 0;
198 0 : }
199 :
200 0 : if( actual->return_data == NULL ) {
201 0 : FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" ));
202 0 : return 0;
203 0 : }
204 :
205 0 : if( expected->return_data->size != actual->return_data->size ) {
206 0 : FD_LOG_WARNING(( "Return data size mismatch: expected=%u actual=%u", expected->return_data->size, actual->return_data->size ));
207 0 : return 0;
208 0 : }
209 :
210 0 : if( !fd_memeq( expected->return_data->bytes, actual->return_data->bytes, expected->return_data->size ) ) {
211 0 : FD_LOG_WARNING(( "Return data mismatch" ));
212 0 : return 0;
213 0 : }
214 0 : }
215 :
216 : /* TxnResult -> executed_units */
217 0 : if( expected->executed_units != actual->executed_units ) {
218 0 : FD_LOG_WARNING(( "Executed units mismatch: expected=%lu actual=%lu", expected->executed_units, actual->executed_units ));
219 0 : return 0;
220 0 : }
221 :
222 : /* TxnResult -> fee_details */
223 0 : if( expected->has_fee_details != actual->has_fee_details ) {
224 0 : FD_LOG_WARNING(( "Has fee details mismatch: expected=%d actual=%d", expected->has_fee_details, actual->has_fee_details ));
225 0 : return 0;
226 0 : }
227 :
228 0 : if( expected->has_fee_details ) {
229 0 : if( expected->fee_details.transaction_fee != actual->fee_details.transaction_fee ) {
230 0 : FD_LOG_WARNING(( "Transaction fee mismatch: expected=%lu actual=%lu", expected->fee_details.transaction_fee, actual->fee_details.transaction_fee ));
231 0 : return 0;
232 0 : }
233 :
234 0 : if( expected->fee_details.prioritization_fee != actual->fee_details.prioritization_fee ) {
235 0 : FD_LOG_WARNING(( "Priority fee mismatch: expected=%lu actual=%lu", expected->fee_details.prioritization_fee, actual->fee_details.prioritization_fee ));
236 0 : return 0;
237 0 : }
238 0 : }
239 :
240 : /* TxnResult -> loaded_accounts_data_size */
241 0 : if( expected->loaded_accounts_data_size != actual->loaded_accounts_data_size ) {
242 0 : FD_LOG_WARNING(( "Loaded accounts data size mismatch: expected=%lu actual=%lu", expected->loaded_accounts_data_size, actual->loaded_accounts_data_size ));
243 0 : return 0;
244 0 : }
245 :
246 0 : return 1;
247 0 : }
248 :
249 : int
250 : fd_solfuzz_instr_fixture( fd_solfuzz_runner_t * runner,
251 : uchar const * in,
252 0 : ulong in_sz ) {
253 : // Decode fixture
254 0 : fd_exec_test_instr_fixture_t fixture[1] = {0};
255 0 : void * res = sol_compat_decode_lenient( &fixture, in, in_sz, &fd_exec_test_instr_fixture_t_msg );
256 0 : if( !res ) {
257 0 : FD_LOG_WARNING(( "Invalid instr fixture." ));
258 0 : return 0;
259 0 : }
260 :
261 0 : int ok = 0;
262 : // Execute
263 0 : void * output = NULL;
264 0 : fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_instr_run );
265 :
266 : // Compare effects
267 0 : ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_instr_effects_t_msg, runner->spad );
268 :
269 : // Cleanup
270 0 : pb_release( &fd_exec_test_instr_fixture_t_msg, fixture );
271 0 : return ok;
272 0 : }
273 :
274 : int
275 : fd_solfuzz_txn_fixture( fd_solfuzz_runner_t * runner,
276 : uchar const * in,
277 0 : ulong in_sz ) {
278 : // Decode fixture
279 0 : fd_exec_test_txn_fixture_t fixture[1] = {0};
280 0 : void * res = sol_compat_decode_lenient( &fixture, in, in_sz, &fd_exec_test_txn_fixture_t_msg );
281 0 : if( !res ) {
282 0 : FD_LOG_WARNING(( "Invalid txn fixture." ));
283 0 : return 0;
284 0 : }
285 :
286 0 : fd_spad_push( runner->spad );
287 0 : int ok = 0;
288 0 : void * output = NULL;
289 0 : fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_txn_run );
290 0 : if( FD_LIKELY( output ) ) {
291 : // Compare effects
292 0 : fd_exec_test_txn_result_t * effects = output;
293 0 : ok = sol_compat_cmp_txn( &fixture->output, effects );
294 0 : }
295 0 : fd_spad_pop( runner->spad );
296 :
297 : // Cleanup
298 0 : pb_release( &fd_exec_test_txn_fixture_t_msg, fixture );
299 0 : return ok;
300 0 : }
301 :
302 : int
303 : fd_solfuzz_block_fixture( fd_solfuzz_runner_t * runner,
304 : uchar const * in,
305 0 : ulong in_sz ) {
306 : // Decode fixture
307 0 : fd_exec_test_block_fixture_t fixture[1] = {0};
308 0 : void * res = sol_compat_decode_lenient( &fixture, in, in_sz, &fd_exec_test_block_fixture_t_msg );
309 0 : if( !res ) {
310 0 : FD_LOG_WARNING(( "Invalid block fixture" ));
311 0 : return 0;
312 0 : }
313 :
314 0 : fd_spad_push( runner->spad );
315 0 : void * output = NULL;
316 0 : fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_block_run );
317 0 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_block_effects_t_msg, runner->spad );
318 0 : fd_spad_pop( runner->spad );
319 :
320 : // Cleanup
321 0 : pb_release( &fd_exec_test_block_fixture_t_msg, fixture );
322 0 : return ok;
323 0 : }
324 :
325 : int
326 : fd_solfuzz_elf_loader_fixture( fd_solfuzz_runner_t * runner,
327 : uchar const * in,
328 0 : ulong in_sz ) {
329 : // Decode fixture
330 0 : fd_exec_test_elf_loader_fixture_t fixture[1] = {0};
331 0 : void * res = sol_compat_decode_lenient( &fixture, in, in_sz, &fd_exec_test_elf_loader_fixture_t_msg );
332 0 : if( !res ) {
333 0 : FD_LOG_WARNING(( "Invalid elf_loader fixture." ));
334 0 : return 0;
335 0 : }
336 :
337 0 : fd_spad_push( runner->spad );
338 0 : void * output = NULL;
339 0 : fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_elf_loader_run );
340 0 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_elf_loader_effects_t_msg, runner->spad );
341 0 : fd_spad_pop( runner->spad );
342 :
343 : // Cleanup
344 0 : pb_release( &fd_exec_test_elf_loader_fixture_t_msg, fixture );
345 0 : return ok;
346 0 : }
347 :
348 : int
349 : fd_solfuzz_syscall_fixture( fd_solfuzz_runner_t * runner,
350 : uchar const * in,
351 0 : ulong in_sz ) {
352 : // Decode fixture
353 0 : fd_exec_test_syscall_fixture_t fixture[1] = {0};
354 0 : if( !sol_compat_decode_lenient( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) {
355 0 : FD_LOG_WARNING(( "Invalid syscall fixture." ));
356 0 : return 0;
357 0 : }
358 :
359 0 : fd_spad_push( runner->spad );
360 0 : void * output = NULL;
361 0 : fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_syscall_run );
362 0 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg, runner->spad );
363 0 : fd_spad_pop( runner->spad );
364 :
365 : // Cleanup
366 0 : pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture );
367 0 : return ok;
368 0 : }
369 :
370 : int
371 : fd_solfuzz_vm_interp_fixture( fd_solfuzz_runner_t * runner,
372 : uchar const * in,
373 0 : ulong in_sz ) {
374 : // Decode fixture
375 0 : fd_exec_test_syscall_fixture_t fixture[1] = {0};
376 0 : if( !sol_compat_decode_lenient( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) {
377 0 : FD_LOG_WARNING(( "Invalid syscall fixture." ));
378 0 : return 0;
379 0 : }
380 :
381 0 : fd_spad_push( runner->spad );
382 0 : void * output = NULL;
383 0 : fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_vm_interp_run );
384 0 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg, runner->spad );
385 0 : fd_spad_pop( runner->spad );
386 :
387 : // Cleanup
388 0 : pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture );
389 0 : return ok;
390 0 : }
|