Line data Source code
1 : #include "fd_exec_sol_compat.h"
2 : #include "../../nanopb/pb_encode.h"
3 : #include "../../nanopb/pb_decode.h"
4 : #include "generated/elf.pb.h"
5 : #include "generated/invoke.pb.h"
6 : #include "generated/shred.pb.h"
7 : #include "generated/vm.pb.h"
8 : #include <assert.h>
9 : #include <stdlib.h>
10 : #include "../../vm/fd_vm.h"
11 : #include "fd_vm_test.h"
12 : #include "fd_pack_test.h"
13 : #include "../../features/fd_features.h"
14 : #include "../fd_executor_err.h"
15 : #include "../../fd_flamenco.h"
16 : #include "../../../ballet/shred/fd_shred.h"
17 : #include "../fd_acc_mgr.h"
18 :
19 : /* This file defines stable APIs for compatibility testing.
20 :
21 : For the "compat" shared library used by the differential fuzzer,
22 : ideally the symbols defined in this file would be the only visible
23 : globals. Unfortunately, we currently export all symbols, which leads
24 : to great symbol table bloat from fd_types.c. */
25 :
26 : typedef struct {
27 : ulong struct_size;
28 : ulong * cleaned_up_features;
29 : ulong cleaned_up_feature_cnt;
30 : ulong * supported_features;
31 : ulong supported_feature_cnt;
32 : } sol_compat_features_t;
33 :
34 : static sol_compat_features_t features;
35 : static uchar * smem;
36 : static const ulong smax = 1UL<<27;
37 :
38 : static uchar * spad_mem;
39 :
40 : static fd_wksp_t * wksp = NULL;
41 :
42 1225350 : #define WKSP_TAG 2
43 :
44 : void
45 0 : sol_compat_init( int log_level ) {
46 0 : assert( !smem );
47 0 : int argc = 1;
48 0 : char * argv[2] = { (char *)"fd_exec_sol_compat", NULL };
49 0 : char ** argv_ = argv;
50 0 : if ( !getenv( "FD_LOG_PATH" ) ) {
51 0 : setenv( "FD_LOG_PATH", "", 1 );
52 0 : }
53 0 : fd_log_enable_unclean_exit();
54 0 : fd_boot( &argc, &argv_ );
55 0 : fd_log_level_logfile_set( log_level );
56 0 : fd_flamenco_boot( NULL, NULL );
57 0 : fd_log_level_core_set(4); /* abort on FD_LOG_ERR */
58 :
59 0 : sol_compat_wksp_init();
60 0 : }
61 :
62 : void
63 420 : sol_compat_wksp_init( void ) {
64 420 : ulong cpu_idx = fd_tile_cpu_id( fd_tile_idx() );
65 420 : if( cpu_idx>=fd_shmem_cpu_cnt() ) cpu_idx = 0UL;
66 420 : wksp = fd_wksp_new_anonymous( FD_SHMEM_NORMAL_PAGE_SZ, 65536UL * 18UL, fd_shmem_cpu_idx( fd_shmem_numa_idx( cpu_idx ) ), "wksp", 0UL );
67 420 : assert( wksp );
68 :
69 420 : spad_mem = fd_wksp_alloc_laddr( wksp, FD_SPAD_ALIGN, FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ, 3 ); /* 4738713960 B */
70 420 : assert( spad_mem );
71 :
72 0 : smem = malloc( smax ); /* 128 MB */
73 420 : assert( smem );
74 :
75 0 : features.struct_size = sizeof(sol_compat_features_t);
76 420 : features.cleaned_up_features = malloc( FD_FEATURE_ID_CNT * sizeof(ulong) );
77 420 : features.supported_features = malloc( FD_FEATURE_ID_CNT * sizeof(ulong) );
78 :
79 91980 : for( const fd_feature_id_t * current_feature = fd_feature_iter_init(); !fd_feature_iter_done( current_feature ); current_feature = fd_feature_iter_next( current_feature ) ) {
80 : // Skip reverted features
81 91560 : if( current_feature->reverted ) continue;
82 :
83 88620 : if( current_feature->cleaned_up[0]!=UINT_MAX ) {
84 53760 : memcpy( &features.cleaned_up_features[features.cleaned_up_feature_cnt++], ¤t_feature->id, sizeof(ulong) );
85 53760 : } else {
86 34860 : memcpy( &features.supported_features[features.supported_feature_cnt++], ¤t_feature->id, sizeof(ulong) );
87 34860 : }
88 88620 : }
89 420 : }
90 :
91 : void
92 420 : sol_compat_fini( void ) {
93 420 : fd_wksp_free_laddr( spad_mem );
94 420 : fd_wksp_delete_anonymous( wksp );
95 420 : free( smem );
96 420 : free( features.cleaned_up_features );
97 420 : free( features.supported_features );
98 420 : wksp = NULL;
99 420 : smem = NULL;
100 420 : spad_mem = NULL;
101 420 : }
102 :
103 : void
104 408450 : sol_compat_check_wksp_usage( void ) {
105 408450 : fd_wksp_usage_t usage[1];
106 408450 : ulong tags[1] = { WKSP_TAG };
107 408450 : fd_wksp_usage( wksp, tags, 1, usage );
108 408450 : if( usage->used_sz ) {
109 0 : FD_LOG_ERR(( "%lu bytes leaked in %lu allocations", usage->used_sz, usage->used_cnt ));
110 0 : }
111 408450 : }
112 :
113 : sol_compat_features_t const *
114 0 : sol_compat_get_features_v1( void ) {
115 0 : return &features;
116 0 : }
117 :
118 : fd_exec_instr_test_runner_t *
119 408450 : sol_compat_setup_scratch_and_runner( void * fmem ) {
120 : // Setup scratch
121 408450 : fd_scratch_attach( smem, fmem, smax, 64UL );
122 : /* Push frame */
123 408450 : fd_scratch_push();
124 :
125 : // Setup test runner
126 408450 : void * runner_mem = fd_wksp_alloc_laddr( wksp, fd_exec_instr_test_runner_align(), fd_exec_instr_test_runner_footprint(), WKSP_TAG );
127 408450 : fd_exec_instr_test_runner_t * runner = fd_exec_instr_test_runner_new( runner_mem, spad_mem, WKSP_TAG );
128 408450 : return runner;
129 408450 : }
130 :
131 : void
132 408450 : sol_compat_cleanup_scratch_and_runner( fd_exec_instr_test_runner_t * runner ) {
133 : /* Cleanup test runner */
134 408450 : fd_wksp_free_laddr( fd_exec_instr_test_runner_delete( runner ) );
135 :
136 : /* Pop frame */
137 408450 : fd_scratch_pop();
138 : /* Cleanup scratch */
139 408450 : fd_scratch_detach( NULL );
140 408450 : }
141 :
142 : void *
143 : sol_compat_decode( void * decoded,
144 : uchar const * in,
145 : ulong in_sz,
146 408450 : pb_msgdesc_t const * decode_type ) {
147 408450 : pb_istream_t istream = pb_istream_from_buffer( in, in_sz );
148 408450 : int decode_ok = pb_decode_ex( &istream, decode_type, decoded, PB_DECODE_NOINIT );
149 408450 : if( !decode_ok ) {
150 0 : pb_release( decode_type, decoded );
151 0 : return NULL;
152 0 : }
153 408450 : return decoded;
154 408450 : }
155 :
156 : void const *
157 : sol_compat_encode( uchar * out,
158 : ulong * out_sz,
159 : void const * to_encode,
160 791418 : pb_msgdesc_t const * encode_type ) {
161 791418 : pb_ostream_t ostream = pb_ostream_from_buffer( out, *out_sz );
162 791418 : int encode_ok = pb_encode( &ostream, encode_type, to_encode );
163 791418 : if( !encode_ok ) {
164 0 : return NULL;
165 0 : }
166 791418 : *out_sz = ostream.bytes_written;
167 791418 : return to_encode;
168 791418 : }
169 :
170 : typedef ulong( exec_test_run_fn_t )( fd_exec_instr_test_runner_t *,
171 : void const *,
172 : void **,
173 : void *,
174 : ulong );
175 :
176 : void
177 : sol_compat_execute_wrapper( fd_exec_instr_test_runner_t * runner,
178 : void * input,
179 : void ** output,
180 408450 : exec_test_run_fn_t * exec_test_run_fn ) {
181 :
182 408450 : assert( fd_scratch_prepare_is_safe( 1UL ) );
183 0 : ulong out_bufsz = 100000000; /* 100 MB */
184 408450 : void * out0 = fd_scratch_prepare( 1UL );
185 408450 : assert( out_bufsz < fd_scratch_free() );
186 0 : fd_scratch_publish( (void *)( (ulong)out0 + out_bufsz ) );
187 :
188 408450 : ulong out_used = exec_test_run_fn( runner, input, output, out0, out_bufsz );
189 408450 : if( FD_UNLIKELY( !out_used ) ) {
190 0 : *output = NULL;
191 0 : }
192 :
193 408450 : fd_scratch_trim( (void *)( (ulong)out0 + out_used ) );
194 408450 : }
195 :
196 : /*
197 : * fixtures
198 : */
199 :
200 : int
201 : sol_compat_cmp_binary_strict( void const * effects,
202 : void const * expected,
203 395709 : pb_msgdesc_t const * encode_type ) {
204 791418 : #define MAX_SZ 32*1024*1024
205 395709 : FD_SCRATCH_SCOPE_BEGIN {
206 395709 : if( effects==NULL ) {
207 0 : FD_LOG_WARNING(( "No output effects" ));
208 0 : return 0;
209 0 : }
210 :
211 : /* Note: Most likely this scratch allocation won't fail. If it does, you may need to bump
212 : the allocated scratch memory amount in fd_exec_sol_compat.c. */
213 395709 : ulong out_sz = MAX_SZ;
214 395709 : uchar * out = fd_scratch_alloc( 1UL, out_sz );
215 395709 : if( !sol_compat_encode( out, &out_sz, effects, encode_type ) ) {
216 0 : FD_LOG_WARNING(( "Error encoding effects" ));
217 0 : return 0;
218 0 : }
219 395709 : fd_scratch_trim( out+out_sz );
220 :
221 395709 : ulong exp_sz = MAX_SZ;
222 395709 : uchar * exp = fd_scratch_alloc( 1UL, exp_sz );
223 395709 : if( !sol_compat_encode( exp, &exp_sz, expected, encode_type ) ) {
224 0 : FD_LOG_WARNING(( "Error encoding expected" ));
225 0 : return 0;
226 0 : }
227 395709 : fd_scratch_trim( exp+exp_sz );
228 :
229 395709 : if( out_sz!=exp_sz ) {
230 0 : FD_LOG_WARNING(( "Binary cmp failed: different size. out_sz=%lu exp_sz=%lu", out_sz, exp_sz ));
231 0 : return 0;
232 0 : }
233 395709 : if( !fd_memeq( out, exp, out_sz ) ) {
234 0 : FD_LOG_WARNING(( "Binary cmp failed: different values." ));
235 0 : return 0;
236 0 : }
237 :
238 395709 : return 1;
239 395709 : } FD_SCRATCH_SCOPE_END;
240 395709 : #undef MAX_SIZE
241 395709 : }
242 :
243 : static int
244 : _diff_txn_acct( fd_exec_test_acct_state_t * expected,
245 13326 : fd_exec_test_acct_state_t * actual ) {
246 : /* AcctState -> address (This must hold true when calling this function!) */
247 13326 : assert( fd_memeq( expected->address, actual->address, sizeof(fd_pubkey_t) ) );
248 :
249 : /* AcctState -> lamports */
250 13326 : if( expected->lamports != actual->lamports ) {
251 0 : FD_LOG_WARNING(( "Lamports mismatch: expected=%lu actual=%lu", expected->lamports, actual->lamports ));
252 0 : return 0;
253 0 : }
254 :
255 : /* AcctState -> data */
256 13326 : if( expected->data != NULL || actual->data != NULL ) {
257 4773 : if( expected->data == NULL ) {
258 0 : FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" ));
259 0 : return 0;
260 0 : }
261 :
262 4773 : if( actual->data == NULL ) {
263 0 : FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" ));
264 0 : return 0;
265 0 : }
266 :
267 4773 : if( expected->data->size != actual->data->size ) {
268 0 : FD_LOG_WARNING(( "Account data size mismatch: expected=%u actual=%u", expected->data->size, actual->data->size ));
269 0 : return 0;
270 0 : }
271 :
272 4773 : if( !fd_memeq( expected->data->bytes, actual->data->bytes, expected->data->size ) ) {
273 0 : FD_LOG_WARNING(( "Account data mismatch" ));
274 0 : return 0;
275 0 : }
276 4773 : }
277 :
278 : /* AcctState -> executable */
279 13326 : if( expected->executable != actual->executable ) {
280 0 : FD_LOG_WARNING(( "Executable mismatch: expected=%d actual=%d", expected->executable, actual->executable ));
281 0 : return 0;
282 0 : }
283 :
284 : /* AcctState -> rent_epoch */
285 13326 : if( expected->rent_epoch != actual->rent_epoch ) {
286 0 : FD_LOG_WARNING(( "Rent epoch mismatch: expected=%lu actual=%lu", expected->rent_epoch, actual->rent_epoch ));
287 0 : return 0;
288 0 : }
289 :
290 : /* AcctState -> owner */
291 13326 : if( !fd_memeq( expected->owner, actual->owner, sizeof(fd_pubkey_t) ) ) {
292 0 : char a[ FD_BASE58_ENCODED_32_SZ ];
293 0 : char b[ FD_BASE58_ENCODED_32_SZ ];
294 0 : FD_LOG_WARNING(( "Owner mismatch: expected=%s, actual=%s", fd_acct_addr_cstr( a, expected->owner ), fd_acct_addr_cstr( b, actual->owner ) ));
295 0 : return 0;
296 0 : }
297 :
298 13326 : return 1;
299 13326 : }
300 :
301 :
302 : static int
303 : _diff_resulting_states( fd_exec_test_resulting_state_t * expected,
304 12741 : fd_exec_test_resulting_state_t * actual ) {
305 : // Verify that the number of accounts are the same
306 12741 : if( expected->acct_states_count != actual->acct_states_count ) {
307 0 : FD_LOG_WARNING(( "Account states count mismatch: expected=%u actual=%u", expected->acct_states_count, actual->acct_states_count ));
308 0 : return 0;
309 0 : }
310 :
311 : // Verify that the account states are the same
312 26067 : for( ulong i = 0; i < expected->acct_states_count; ++i ) {
313 69990 : for( ulong j = 0; j < actual->acct_states_count; ++j ) {
314 56664 : if( fd_memeq( expected->acct_states[i].address, actual->acct_states[j].address, sizeof(fd_pubkey_t) ) ) {
315 13326 : if( !_diff_txn_acct( &expected->acct_states[i], &actual->acct_states[j] ) ) {
316 0 : return 0;
317 0 : }
318 13326 : }
319 56664 : }
320 13326 : }
321 :
322 : // TODO: resulting_state -> rent_debits, resulting_state->transaction_rent
323 12741 : return 1;
324 12741 : }
325 :
326 : int
327 : sol_compat_cmp_txn( fd_exec_test_txn_result_t * expected,
328 12741 : fd_exec_test_txn_result_t * actual ) {
329 : /* TxnResult -> executed */
330 12741 : if( expected->executed != actual->executed ) {
331 0 : FD_LOG_WARNING(( "Executed mismatch: expected=%d actual=%d", expected->executed, actual->executed ));
332 0 : return 0;
333 0 : }
334 :
335 : /* TxnResult -> sanitization_error */
336 12741 : if( expected->sanitization_error != actual->sanitization_error ) {
337 0 : FD_LOG_WARNING(( "Sanitization error mismatch: expected=%d actual=%d", expected->sanitization_error, actual->sanitization_error ));
338 0 : return 0;
339 0 : }
340 :
341 : /* TxnResult -> resulting_state */
342 12741 : if( !_diff_resulting_states( &expected->resulting_state, &actual->resulting_state ) ) {
343 0 : return 0;
344 0 : }
345 :
346 : /* TxnResult -> rent */
347 12741 : if( expected->rent != actual->rent ) {
348 0 : FD_LOG_WARNING(( "Rent mismatch: expected=%lu actual=%lu", expected->rent, actual->rent ));
349 0 : return 0;
350 0 : }
351 :
352 : /* TxnResult -> is_ok */
353 12741 : if( expected->is_ok != actual->is_ok ) {
354 0 : FD_LOG_WARNING(( "Is ok mismatch: expected=%d actual=%d", expected->is_ok, actual->is_ok ));
355 0 : return 0;
356 0 : }
357 :
358 : /* TxnResult -> status */
359 12741 : if( expected->status != actual->status ) {
360 0 : FD_LOG_WARNING(( "Status mismatch: expected=%u actual=%u", expected->status, actual->status ));
361 0 : return 0;
362 0 : }
363 :
364 : /* TxnResult -> instruction_error */
365 12741 : if( expected->instruction_error != actual->instruction_error ) {
366 0 : FD_LOG_WARNING(( "Instruction error mismatch: expected=%u actual=%u", expected->instruction_error, actual->instruction_error ));
367 0 : return 0;
368 0 : }
369 :
370 12741 : if( expected->instruction_error ) {
371 : /* TxnResult -> instruction_error_index */
372 7674 : if( expected->instruction_error_index != actual->instruction_error_index ) {
373 0 : FD_LOG_WARNING(( "Instruction error index mismatch: expected=%u actual=%u", expected->instruction_error_index, actual->instruction_error_index ));
374 0 : return 0;
375 0 : }
376 :
377 : /* TxnResult -> custom_error */
378 7674 : if( expected->instruction_error == (ulong) -FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR && expected->custom_error != actual->custom_error ) {
379 0 : FD_LOG_WARNING(( "Custom error mismatch: expected=%u actual=%u", expected->custom_error, actual->custom_error ));
380 0 : return 0;
381 0 : }
382 7674 : }
383 :
384 : /* TxnResult -> return_data */
385 12741 : if( expected->return_data != NULL || actual->return_data != NULL ) {
386 39 : if( expected->return_data == NULL ) {
387 0 : FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" ));
388 0 : return 0;
389 0 : }
390 :
391 39 : if( actual->return_data == NULL ) {
392 0 : FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" ));
393 0 : return 0;
394 0 : }
395 :
396 39 : if( expected->return_data->size != actual->return_data->size ) {
397 0 : FD_LOG_WARNING(( "Return data size mismatch: expected=%u actual=%u", expected->return_data->size, actual->return_data->size ));
398 0 : return 0;
399 0 : }
400 :
401 39 : if( !fd_memeq( expected->return_data->bytes, actual->return_data->bytes, expected->return_data->size ) ) {
402 0 : FD_LOG_WARNING(( "Return data mismatch" ));
403 0 : return 0;
404 0 : }
405 39 : }
406 :
407 : /* TxnResult -> executed_units */
408 12741 : if( expected->executed_units != actual->executed_units ) {
409 0 : FD_LOG_WARNING(( "Executed units mismatch: expected=%lu actual=%lu", expected->executed_units, actual->executed_units ));
410 0 : return 0;
411 0 : }
412 :
413 : /* TxnResult -> fee_details */
414 12741 : if( expected->fee_details.transaction_fee != actual->fee_details.transaction_fee ) {
415 0 : FD_LOG_WARNING(( "Transaction fee mismatch: expected=%lu actual=%lu", expected->fee_details.transaction_fee, actual->fee_details.transaction_fee ));
416 0 : return 0;
417 0 : }
418 :
419 12741 : if( expected->fee_details.prioritization_fee != actual->fee_details.prioritization_fee ) {
420 0 : FD_LOG_WARNING(( "Priority fee mismatch: expected=%lu actual=%lu", expected->fee_details.prioritization_fee, actual->fee_details.prioritization_fee ));
421 0 : return 0;
422 0 : }
423 :
424 12741 : return 1;
425 12741 : }
426 :
427 : int
428 : sol_compat_cmp_success_fail_only( void const * _effects,
429 0 : void const * _expected ) {
430 0 : fd_exec_test_instr_effects_t * effects = (fd_exec_test_instr_effects_t *)_effects;
431 0 : fd_exec_test_instr_effects_t * expected = (fd_exec_test_instr_effects_t *)_expected;
432 :
433 0 : if( effects==NULL ) {
434 0 : FD_LOG_WARNING(( "No output effects" ));
435 0 : return 0;
436 0 : }
437 :
438 0 : if( effects->custom_err || expected->custom_err ) {
439 0 : FD_LOG_WARNING(( "Unexpected custom error" ));
440 0 : return 0;
441 0 : }
442 :
443 0 : int res = effects->result;
444 0 : int exp = expected->result;
445 :
446 0 : if( res==exp ) {
447 0 : return 1;
448 0 : }
449 :
450 0 : if( res>0 && exp>0 ) {
451 0 : FD_LOG_INFO(( "Accepted: res=%d exp=%d", res, exp ));
452 0 : return 1;
453 0 : }
454 :
455 0 : return 0;
456 0 : }
457 :
458 : int
459 : sol_compat_instr_fixture( fd_exec_instr_test_runner_t * runner,
460 : uchar const * in,
461 61992 : ulong in_sz ) {
462 : // Decode fixture
463 61992 : fd_exec_test_instr_fixture_t fixture[1] = {0};
464 61992 : void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_instr_fixture_t_msg );
465 61992 : if ( res==NULL ) {
466 0 : FD_LOG_WARNING(( "Invalid instr fixture." ));
467 0 : return 0;
468 0 : }
469 :
470 : // Execute
471 61992 : void * output = NULL;
472 61992 : sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_exec_instr_test_run );
473 :
474 : // Compare effects
475 61992 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_instr_effects_t_msg );
476 :
477 : // Cleanup
478 61992 : pb_release( &fd_exec_test_instr_fixture_t_msg, fixture );
479 61992 : return ok;
480 61992 : }
481 :
482 : int
483 : sol_compat_txn_fixture( fd_exec_instr_test_runner_t * runner,
484 : uchar const * in,
485 12741 : ulong in_sz ) {
486 12741 : FD_SCRATCH_SCOPE_BEGIN {
487 : // Decode fixture
488 12741 : fd_exec_test_txn_fixture_t fixture[1] = {0};
489 12741 : void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_txn_fixture_t_msg );
490 12741 : if ( res==NULL ) {
491 0 : FD_LOG_WARNING(( "Invalid txn fixture." ));
492 0 : return 0;
493 0 : }
494 :
495 : // Execute
496 12741 : void * output = NULL;
497 12741 : sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_exec_txn_test_run );
498 :
499 : // Compare effects
500 12741 : fd_exec_test_txn_result_t * effects = (fd_exec_test_txn_result_t *) output;
501 12741 : int ok = sol_compat_cmp_txn( &fixture->output, effects );
502 :
503 : // Cleanup
504 12741 : pb_release( &fd_exec_test_txn_fixture_t_msg, fixture );
505 12741 : return ok;
506 12741 : } FD_SCRATCH_SCOPE_END;
507 12741 : }
508 :
509 : int
510 : sol_compat_elf_loader_fixture( fd_exec_instr_test_runner_t * runner,
511 : uchar const * in,
512 591 : ulong in_sz ) {
513 : // Decode fixture
514 591 : fd_exec_test_elf_loader_fixture_t fixture[1] = {0};
515 591 : void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_elf_loader_fixture_t_msg );
516 591 : if ( res==NULL ) {
517 0 : FD_LOG_WARNING(( "Invalid elf_loader fixture." ));
518 0 : return 0;
519 0 : }
520 :
521 : // Execute
522 591 : void * output = NULL;
523 591 : sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_sbpf_program_load_test_run );
524 :
525 : // Compare effects
526 591 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_elf_loader_effects_t_msg );
527 :
528 : // Cleanup
529 591 : pb_release( &fd_exec_test_elf_loader_fixture_t_msg, fixture );
530 591 : return ok;
531 591 : }
532 :
533 : int
534 : sol_compat_syscall_fixture( fd_exec_instr_test_runner_t * runner,
535 : uchar const * in,
536 12711 : ulong in_sz ) {
537 : // Decode fixture
538 12711 : fd_exec_test_syscall_fixture_t fixture[1] = {0};
539 12711 : if ( !sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) {
540 0 : FD_LOG_WARNING(( "Invalid syscall fixture." ));
541 0 : return 0;
542 0 : }
543 :
544 : // Execute
545 12711 : void * output = NULL;
546 12711 : sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_exec_vm_syscall_test_run );
547 :
548 : // Compare effects
549 12711 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg );
550 :
551 : // Cleanup
552 12711 : pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture );
553 12711 : return ok;
554 12711 : }
555 :
556 : int
557 : sol_compat_vm_interp_fixture( fd_exec_instr_test_runner_t * runner,
558 : uchar const * in,
559 320415 : ulong in_sz ) {
560 : // Decode fixture
561 320415 : fd_exec_test_syscall_fixture_t fixture[1] = {0};
562 320415 : if ( !sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) {
563 0 : FD_LOG_WARNING(( "Invalid syscall fixture." ));
564 0 : return 0;
565 0 : }
566 :
567 : // Execute
568 320415 : void * output = NULL;
569 320415 : sol_compat_execute_wrapper( runner, &fixture->input, &output, (exec_test_run_fn_t *)fd_exec_vm_interp_test_run );
570 :
571 : // Compare effects
572 320415 : int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg );
573 :
574 : // Cleanup
575 320415 : pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture );
576 320415 : return ok;
577 320415 : }
578 :
579 : /*
580 : * execute_v1
581 : */
582 :
583 : int
584 : sol_compat_instr_execute_v1( uchar * out,
585 : ulong * out_sz,
586 : uchar const * in,
587 0 : ulong in_sz ) {
588 : // Setup
589 0 : ulong fmem[ 64 ];
590 0 : fd_exec_instr_test_runner_t * runner = sol_compat_setup_scratch_and_runner( fmem );
591 :
592 : // Decode context
593 0 : fd_exec_test_instr_context_t input[1] = {0};
594 0 : void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_instr_context_t_msg );
595 0 : if ( res==NULL ) {
596 0 : sol_compat_cleanup_scratch_and_runner( runner );
597 0 : return 0;
598 0 : }
599 :
600 : // Execute
601 0 : void * output = NULL;
602 0 : sol_compat_execute_wrapper( runner, input, &output, fd_exec_instr_test_run );
603 :
604 : // Encode effects
605 0 : int ok = 0;
606 0 : if( output ) {
607 0 : ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_instr_effects_t_msg );
608 0 : }
609 :
610 : // Cleanup
611 0 : pb_release( &fd_exec_test_instr_context_t_msg, input );
612 0 : sol_compat_cleanup_scratch_and_runner( runner );
613 :
614 : // Check wksp usage is 0
615 0 : sol_compat_check_wksp_usage();
616 :
617 0 : return ok;
618 0 : }
619 :
620 : int
621 : sol_compat_txn_execute_v1( uchar * out,
622 : ulong * out_sz,
623 : uchar const * in,
624 0 : ulong in_sz ) {
625 : // Setup
626 0 : ulong fmem[ 64 ];
627 0 : fd_exec_instr_test_runner_t * runner = sol_compat_setup_scratch_and_runner( fmem );
628 :
629 : // Decode context
630 0 : fd_exec_test_txn_context_t input[1] = {0};
631 0 : void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_txn_context_t_msg );
632 0 : if ( res==NULL ) {
633 0 : sol_compat_cleanup_scratch_and_runner( runner );
634 0 : return 0;
635 0 : }
636 :
637 : // Execute
638 0 : void * output = NULL;
639 0 : sol_compat_execute_wrapper( runner, input, &output, fd_exec_txn_test_run );
640 :
641 : // Encode effects
642 0 : int ok = 0;
643 0 : if( output ) {
644 0 : ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_txn_result_t_msg );
645 0 : }
646 :
647 : // Cleanup
648 0 : pb_release( &fd_exec_test_txn_context_t_msg, input );
649 0 : sol_compat_cleanup_scratch_and_runner( runner );
650 :
651 : // Check wksp usage is 0
652 0 : sol_compat_check_wksp_usage();
653 0 : return ok;
654 0 : }
655 :
656 : int
657 : sol_compat_elf_loader_v1( uchar * out,
658 : ulong * out_sz,
659 : uchar const * in,
660 0 : ulong in_sz ) {
661 0 : ulong fmem[ 64 ];
662 0 : fd_scratch_attach( smem, fmem, smax, 64UL );
663 0 : fd_scratch_push();
664 :
665 0 : pb_istream_t istream = pb_istream_from_buffer( in, in_sz );
666 0 : fd_exec_test_elf_loader_ctx_t input[1] = {0};
667 0 : int decode_ok = pb_decode_ex( &istream, &fd_exec_test_elf_loader_ctx_t_msg, input, PB_DECODE_NOINIT );
668 0 : if( !decode_ok ) {
669 0 : pb_release( &fd_exec_test_elf_loader_ctx_t_msg, input );
670 0 : return 0;
671 0 : }
672 :
673 0 : fd_exec_test_elf_loader_effects_t * output = NULL;
674 0 : do {
675 0 : ulong out_bufsz = 100000000;
676 0 : void * out0 = fd_scratch_prepare( 1UL );
677 0 : assert( out_bufsz < fd_scratch_free() );
678 0 : fd_scratch_publish( (void *)( (ulong)out0 + out_bufsz ) );
679 0 : ulong out_used = fd_sbpf_program_load_test_run( NULL, fd_type_pun_const( input ), fd_type_pun( &output ), out0, out_bufsz );
680 0 : if( FD_UNLIKELY( !out_used ) ) {
681 0 : output = NULL;
682 0 : break;
683 0 : }
684 0 : } while(0);
685 :
686 0 : int ok = 0;
687 :
688 0 : if( output ) {
689 0 : pb_ostream_t ostream = pb_ostream_from_buffer( out, *out_sz );
690 0 : int encode_ok = pb_encode( &ostream, &fd_exec_test_elf_loader_effects_t_msg, output );
691 0 : if( encode_ok ) {
692 0 : *out_sz = ostream.bytes_written;
693 0 : ok = 1;
694 0 : }
695 0 : }
696 :
697 0 : pb_release( &fd_exec_test_elf_loader_ctx_t_msg, input );
698 0 : fd_scratch_pop();
699 0 : fd_scratch_detach( NULL );
700 :
701 : // Check wksp usage is 0
702 0 : sol_compat_check_wksp_usage();
703 :
704 0 : return ok;
705 0 : }
706 :
707 :
708 : int
709 : sol_compat_vm_syscall_execute_v1( uchar * out,
710 : ulong * out_sz,
711 : uchar const * in,
712 0 : ulong in_sz ) {
713 : // Setup
714 0 : ulong fmem[ 64 ];
715 0 : fd_exec_instr_test_runner_t * runner = sol_compat_setup_scratch_and_runner( fmem );
716 :
717 : // Decode context
718 0 : fd_exec_test_syscall_context_t input[1] = {0};
719 0 : void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg );
720 0 : if ( res==NULL ) {
721 0 : sol_compat_cleanup_scratch_and_runner( runner );
722 0 : return 0;
723 0 : }
724 :
725 : // Execute
726 0 : void * output = NULL;
727 0 : sol_compat_execute_wrapper( runner, input, &output, fd_exec_vm_syscall_test_run );
728 :
729 : // Encode effects
730 0 : int ok = 0;
731 0 : if( output ) {
732 0 : ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg );
733 0 : }
734 :
735 : // Cleanup
736 0 : pb_release( &fd_exec_test_syscall_context_t_msg, input );
737 0 : sol_compat_cleanup_scratch_and_runner( runner );
738 :
739 : // Check wksp usage is 0
740 0 : sol_compat_check_wksp_usage();
741 :
742 0 : return ok;
743 0 : }
744 :
745 : /* We still need a separate entrypoint since other harnesses (namely sfuzz-agave)
746 : do something other than wrap their vm_syscall equivalent */
747 : int
748 : sol_compat_vm_cpi_syscall_v1( uchar * out,
749 : ulong * out_sz,
750 : uchar const * in,
751 0 : ulong in_sz ) {
752 : /* Just a wrapper to vm_syscall_execute_v1 */
753 0 : return sol_compat_vm_syscall_execute_v1( out, out_sz, in, in_sz );
754 0 : }
755 :
756 : int
757 : sol_compat_vm_interp_v1( uchar * out,
758 : ulong * out_sz,
759 : uchar const * in,
760 0 : ulong in_sz ) {
761 : // Setup
762 0 : ulong fmem[ 64 ];
763 0 : fd_exec_instr_test_runner_t * runner = sol_compat_setup_scratch_and_runner( fmem );
764 :
765 : // Decode context
766 0 : fd_exec_test_syscall_context_t input[1] = {0};
767 0 : void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg );
768 0 : if ( res==NULL ) {
769 0 : sol_compat_cleanup_scratch_and_runner( runner );
770 0 : return 0;
771 0 : }
772 :
773 : // Execute
774 0 : void * output = NULL;
775 0 : sol_compat_execute_wrapper( runner, input, &output, (exec_test_run_fn_t *)fd_exec_vm_interp_test_run );
776 :
777 : // Encode effects
778 0 : int ok = 0;
779 0 : if( output ) {
780 0 : ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg );
781 0 : }
782 :
783 : // Cleanup
784 0 : pb_release( &fd_exec_test_syscall_context_t_msg, input );
785 0 : sol_compat_cleanup_scratch_and_runner( runner );
786 :
787 : // Check wksp usage is 0
788 0 : sol_compat_check_wksp_usage();
789 :
790 0 : return ok;
791 0 : }
792 :
793 : int sol_compat_shred_parse_v1( uchar * out,
794 : ulong * out_sz,
795 : uchar const * in,
796 0 : ulong in_sz ) {
797 0 : fd_exec_test_shred_binary_t input[1] = {0};
798 0 : void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_shred_binary_t_msg );
799 0 : if( FD_UNLIKELY( res==NULL ) ) {
800 0 : return 0;
801 0 : }
802 0 : if( FD_UNLIKELY( input[0].data==NULL ) ) {
803 0 : pb_release( &fd_exec_test_shred_binary_t_msg, input );
804 0 : return 0;
805 0 : }
806 0 : fd_exec_test_accepts_shred_t output[1] = {0};
807 0 : output[0].valid = !!fd_shred_parse( input[0].data->bytes, input[0].data->size );
808 0 : pb_release( &fd_exec_test_shred_binary_t_msg, input );
809 0 : return !!sol_compat_encode( out, out_sz, output, &fd_exec_test_accepts_shred_t_msg );
810 0 : }
811 :
812 : int
813 : sol_compat_pack_compute_budget_v1( uchar * out,
814 : ulong * out_sz,
815 : uchar const * in,
816 0 : ulong in_sz ) {
817 0 : ulong fmem[ 64 ];
818 0 : fd_exec_instr_test_runner_t * runner = sol_compat_setup_scratch_and_runner( fmem );
819 :
820 0 : fd_exec_test_pack_compute_budget_context_t input[1] = {0};
821 0 : void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_pack_compute_budget_context_t_msg );
822 0 : if( res==NULL ) {
823 0 : sol_compat_cleanup_scratch_and_runner( runner );
824 0 : return 0;
825 0 : }
826 :
827 0 : void * output = NULL;
828 0 : sol_compat_execute_wrapper( runner, input, &output, fd_exec_pack_cpb_test_run );
829 :
830 0 : int ok = 0;
831 0 : if( output ) {
832 0 : ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_pack_compute_budget_effects_t_msg );
833 0 : }
834 :
835 0 : pb_release( &fd_exec_test_pack_compute_budget_context_t_msg, input );
836 0 : sol_compat_cleanup_scratch_and_runner( runner );
837 :
838 : // Check wksp usage is 0
839 0 : sol_compat_check_wksp_usage();
840 0 : return ok;
841 0 : }
|