LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_instr_harness.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 278 305 91.1 %
Date: 2026-03-19 18:19:27 Functions: 3 3 100.0 %

          Line data    Source code
       1             : #undef FD_SPAD_USE_HANDHOLDING
       2             : #define FD_SPAD_USE_HANDHOLDING 1
       3             : 
       4             : #include "fd_solfuzz_private.h"
       5             : #include "fd_instr_harness.h"
       6             : #include "../fd_executor.h"
       7             : #include "../fd_runtime.h"
       8             : #include "../program/fd_bpf_loader_program.h"
       9             : #include "../program/fd_loader_v4_program.h"
      10             : #include "../program/fd_precompiles.h"
      11             : #include "../fd_system_ids.h"
      12             : #include "../../accdb/fd_accdb_admin_v1.h"
      13             : #include "../../progcache/fd_progcache_admin.h"
      14             : #include "../../log_collector/fd_log_collector.h"
      15             : #include <assert.h>
      16             : 
      17             : void
      18             : fd_solfuzz_pb_instr_ctx_create( fd_solfuzz_runner_t *                runner,
      19             :                                 fd_exec_instr_ctx_t *                ctx,
      20       24500 :                                 fd_exec_test_instr_context_t const * test_ctx ) {
      21             : 
      22       24500 :   memset( ctx, 0, sizeof(fd_exec_instr_ctx_t) );
      23             : 
      24             :   /* Generate unique ID for funk txn */
      25             : 
      26       24500 :   fd_funk_txn_xid_t xid[1] = {{ .ul={ LONG_MAX, LONG_MAX } }};
      27             : 
      28             :   /* Create temporary funk transaction and txn / slot / epoch contexts */
      29             : 
      30       24500 :   fd_funk_txn_xid_t parent_xid; fd_funk_txn_xid_set_root( &parent_xid );
      31       24500 :   fd_accdb_attach_child        ( runner->accdb_admin,     &parent_xid, xid );
      32       24500 :   fd_progcache_txn_attach_child( runner->progcache->join, &parent_xid, xid );
      33             : 
      34       24500 :   fd_txn_in_t *  txn_in  = fd_spad_alloc( runner->spad, alignof(fd_txn_in_t), sizeof(fd_txn_in_t) );
      35       24500 :   fd_txn_out_t * txn_out = fd_spad_alloc( runner->spad, alignof(fd_txn_out_t), sizeof(fd_txn_out_t) );
      36             : 
      37       24500 :   fd_log_collector_t * log = fd_spad_alloc( runner->spad, alignof(fd_log_collector_t), sizeof(fd_log_collector_t) );
      38             : 
      39       24500 :   fd_runtime_t * runtime = runner->runtime;
      40             : 
      41       24500 :   runtime->log.log_collector = log;
      42             : 
      43       24500 :   ctx->txn_out = txn_out;
      44       24500 :   ctx->txn_in  = txn_in;
      45             : 
      46       24500 :   memset( txn_out->accounts.account, 0, sizeof(fd_accdb_rw_t) * MAX_TX_ACCOUNT_LOCKS );
      47             : 
      48             :   /* Bank manager */
      49       24500 :   fd_banks_clear_bank( runner->banks, runner->bank, 4UL );
      50             : 
      51             :   /* Restore features */
      52       24500 :   FD_TEST( test_ctx->has_features );
      53       24500 :   fd_features_t * features = fd_bank_features_modify( runner->bank );
      54       24500 :   fd_exec_test_feature_set_t const * feature_set = &test_ctx->features;
      55       24500 :   FD_TEST( fd_solfuzz_pb_restore_features( features, feature_set ) );
      56             : 
      57             :   /* Blockhash queue init */
      58       24500 :   ulong blockhash_seed; FD_TEST( fd_rng_secure( &blockhash_seed, sizeof(ulong) ) );
      59       24500 :   fd_blockhashes_t * blockhashes = fd_blockhashes_init( fd_bank_block_hash_queue_modify( runner->bank ), blockhash_seed );
      60       24500 :   fd_memset( fd_blockhash_deq_push_tail_nocopy( blockhashes->d.deque ), 0, sizeof(fd_hash_t) );
      61             : 
      62             :   /* Set up mock txn descriptor and payload
      63             :      FIXME: More fields may need to be initialized. This seems to be
      64             :      the minimal set of fields needed to retain full context for
      65             :      precompile execution. */
      66       24500 :   fd_txn_p_t * txn            = fd_spad_alloc_check( runner->spad, alignof(fd_txn_p_t), sizeof(fd_txn_p_t) );
      67       24500 :   fd_txn_t *   txn_descriptor = TXN( txn );
      68       24500 :   if( test_ctx->data ) {
      69       19570 :     memcpy( txn->payload, test_ctx->data->bytes, test_ctx->data->size );
      70       19570 :     txn->payload_sz = test_ctx->data->size;
      71       19570 :   } else {
      72        4930 :     txn->payload_sz = 0;
      73        4930 :   }
      74       24500 :   txn_descriptor->transaction_version = FD_TXN_VLEGACY;
      75       24500 :   txn_descriptor->acct_addr_cnt       = (ushort)test_ctx->accounts_count;
      76       24500 :   txn_descriptor->instr_cnt           = 1;
      77       24500 :   txn_descriptor->instr[0]            = (fd_txn_instr_t) {
      78       24500 :     .acct_cnt = (ushort)test_ctx->accounts_count,
      79       24500 :     .data_off = 0,
      80       24500 :     .data_sz  = (ushort)txn->payload_sz,
      81       24500 :   };
      82             : 
      83       24500 :   runtime->log.enable_log_collector = 0;
      84             : 
      85       24500 :   fd_compute_budget_details_new( &txn_out->details.compute_budget );
      86       24500 :   runtime->instr.stack_sz            = 0;
      87       24500 :   txn_out->accounts.cnt     = 0UL;
      88       24500 :   runtime->accounts.executable_cnt   = 0UL;
      89             : 
      90       24500 :   txn_out->details.programs_to_reverify_cnt  = 0UL;
      91       24500 :   txn_out->details.loaded_accounts_data_size = 0UL;
      92       24500 :   txn_out->details.accounts_resize_delta     = 0L;
      93             : 
      94       24500 :   memset( txn_out->details.return_data.program_id.key, 0, sizeof(fd_pubkey_t) );
      95       24500 :   txn_out->details.return_data.len = 0;
      96             : 
      97       24500 :   runtime->log.capture_ctx    = NULL;
      98       24500 :   runtime->log.dump_proto_ctx = NULL;
      99       24500 :   runtime->log.txn_dump_ctx   = NULL;
     100             : 
     101       24500 :   runtime->instr.trace_length = 1UL;
     102             : 
     103       24500 :   txn_out->err.exec_err       = 0;
     104       24500 :   txn_out->err.exec_err_kind  = FD_EXECUTOR_ERR_KIND_NONE;
     105       24500 :   runtime->instr.current_idx  = 0;
     106             : 
     107       24500 :   txn_in->txn                                        = txn;
     108       24500 :   txn_out->details.compute_budget.compute_unit_limit = test_ctx->cu_avail;
     109       24500 :   txn_out->details.compute_budget.compute_meter      = test_ctx->cu_avail;
     110       24500 :   runtime->log.enable_vm_tracing                     = runner->enable_vm_tracing;
     111       24500 :   runtime->log.tracing_mem                           = runner->enable_vm_tracing ?
     112           0 :                                                        fd_spad_alloc_check( runner->spad, FD_RUNTIME_VM_TRACE_STATIC_ALIGN, FD_RUNTIME_VM_TRACE_STATIC_FOOTPRINT * FD_MAX_INSTRUCTION_STACK_DEPTH ) :
     113       24500 :                                                        NULL;
     114             : 
     115             :   /* Set up instruction context */
     116       24500 :   fd_instr_info_t * info = &runtime->instr.trace[ 0UL ];
     117       24500 :   memset( info, 0, sizeof(fd_instr_info_t) );
     118       24500 :   info->stack_height = 1;
     119             : 
     120       24500 :   if( test_ctx->data ) {
     121       19570 :     if( FD_UNLIKELY( test_ctx->data->size>FD_INSTR_DATA_MAX ) ) {
     122           0 :       FD_LOG_ERR(( "invariant violation: instr data sz is too large %u > %lu", test_ctx->data->size, FD_INSTR_DATA_MAX ));
     123           0 :     }
     124       19570 :     info->data_sz = (ushort)test_ctx->data->size;
     125       19570 :     memcpy( info->data, test_ctx->data->bytes, info->data_sz );
     126       19570 :   }
     127             : 
     128             :   /* Prepare borrowed account table (correctly handles aliasing) */
     129             : 
     130       24500 :   if( FD_UNLIKELY( test_ctx->accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) {
     131           0 :     FD_LOG_ERR(( "invariant violation: too many accounts (%lu > %lu)",
     132           0 :                  (ulong)test_ctx->accounts_count, (ulong)MAX_TX_ACCOUNT_LOCKS ));
     133           0 :   }
     134             : 
     135             :   /* Load accounts from input */
     136             : 
     137       24500 :   fd_account_meta_t * metas[MAX_TX_ACCOUNT_LOCKS] = {0};
     138       24500 :   txn_out->accounts.cnt = test_ctx->accounts_count;
     139             : 
     140       24500 :   int has_program_id = 0;
     141             : 
     142      348542 :   for( ulong j=0UL; j < test_ctx->accounts_count; j++ ) {
     143      324042 :     fd_pubkey_t * acc_key = (fd_pubkey_t *)test_ctx->accounts[j].address;
     144             : 
     145      324042 :     memcpy( &(txn_out->accounts.keys[j]), test_ctx->accounts[j].address, sizeof(fd_pubkey_t) );
     146      324042 :     runtime->accounts.refcnt[j] = 0UL;
     147             : 
     148      324042 :     uchar *             data     = fd_spad_alloc( runner->spad, FD_ACCOUNT_REC_ALIGN, FD_ACC_TOT_SZ_MAX );
     149      324042 :     fd_account_meta_t * meta     = (fd_account_meta_t *)data;
     150      324042 :     uint dlen = test_ctx->accounts[j].data ? test_ctx->accounts[j].data->size : 0U;
     151      324042 :     if( test_ctx->accounts[j].data ) {
     152      288196 :       fd_memcpy( meta+1, test_ctx->accounts[j].data->bytes, dlen );
     153      288196 :     }
     154      324042 :     meta->dlen = dlen;
     155      324042 :     meta->lamports = test_ctx->accounts[j].lamports;
     156      324042 :     meta->executable = test_ctx->accounts[j].executable;
     157      324042 :     fd_memcpy( meta->owner, test_ctx->accounts[j].owner, sizeof(fd_pubkey_t) );
     158      324042 :     metas[j] = meta;
     159      324042 :     fd_accdb_rw_init_nodb( &txn_out->accounts.account[j], acc_key, metas[j], FD_RUNTIME_ACC_SZ_MAX );
     160      324042 :     txn_out->accounts.keys[j] = *acc_key;
     161             : 
     162      324042 :     if( !memcmp( acc_key, test_ctx->program_id, sizeof(fd_pubkey_t) ) ) {
     163       24548 :       has_program_id   = 1;
     164       24548 :       info->program_id = (uchar)j;
     165       24548 :     }
     166      324042 :   }
     167             : 
     168             :   /* Ensure the program id is in the set of accounts */
     169       24500 :   FD_TEST( has_program_id );
     170             : 
     171             :   /* Load in executable accounts */
     172      350935 :   for( ulong i = 0; i < txn_out->accounts.cnt; i++ ) {
     173             : 
     174      326435 :     fd_account_meta_t * meta  = txn_out->accounts.account[i].meta;
     175      326435 :     fd_pubkey_t const * owner = fd_type_pun_const( meta->owner );
     176             : 
     177      326435 :     if( !fd_executor_pubkey_is_bpf_loader( owner ) ) {
     178      267823 :       continue;
     179      267823 :     }
     180             : 
     181       58612 :     if( FD_UNLIKELY( !memcmp( owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     182       38443 :       fd_bpf_upgradeable_loader_state_t program_loader_state[1];
     183       38443 :       int err = fd_bpf_loader_program_get_state( meta, program_loader_state );
     184       38443 :       if( FD_UNLIKELY( err!=FD_EXECUTOR_INSTR_SUCCESS ) ) {
     185       10593 :         continue;
     186       10593 :       }
     187             : 
     188       27850 :       if( !fd_bpf_upgradeable_loader_state_is_program( program_loader_state ) ) {
     189       15057 :         continue;
     190       15057 :       }
     191             : 
     192       12793 :       fd_pubkey_t * programdata_acc = &program_loader_state->inner.program.programdata_address;
     193             : 
     194       12793 :       meta = NULL;
     195      133970 :       for( ulong j=0UL; j<test_ctx->accounts_count; j++ ) {
     196      132367 :         if( !memcmp( test_ctx->accounts[j].address, programdata_acc, sizeof(fd_pubkey_t) ) ) {
     197       11190 :           meta = txn_out->accounts.account[j].meta;
     198       11190 :           break;
     199       11190 :         }
     200      132367 :       }
     201       12793 :       if( FD_UNLIKELY( meta==NULL ) ) {
     202        1640 :         continue;
     203        1640 :       }
     204             : 
     205       11153 :       FD_TEST( runtime->accounts.executable_cnt < MAX_TX_ACCOUNT_LOCKS );
     206       11153 :       fd_accdb_ro_t * ro = &runtime->accounts.executable[ runtime->accounts.executable_cnt ];
     207       11153 :       fd_accdb_ro_init_nodb( ro, programdata_acc, meta );
     208       11153 :       runtime->accounts.executable_cnt++;
     209       20169 :     } else if( FD_UNLIKELY( !memcmp( meta->owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ||
     210       20169 :                             !memcmp( meta->owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     211       19481 :       meta = txn_out->accounts.account[i].meta;
     212       19481 :     } else if( !memcmp( owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
     213         929 :       int err;
     214         929 :       fd_loader_v4_state_t const * state = fd_loader_v4_get_state( fd_account_data( meta ), meta->dlen, &err );
     215         929 :       if( FD_UNLIKELY( err ) ) {
     216         443 :         continue;
     217         443 :       }
     218             : 
     219             :       /* The program must be deployed or finalized. */
     220         486 :       if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( state ) ) ) {
     221         105 :         continue;
     222         105 :       }
     223         381 :       meta = txn_out->accounts.account[i].meta;
     224         381 :     }
     225             : 
     226       30774 :     FD_SPAD_FRAME_BEGIN( runner->spad ) {
     227       30774 :       uchar * scratch = fd_spad_alloc( runner->spad, FD_FUNK_REC_ALIGN, meta->dlen );
     228       30774 :       fd_progcache_inject_rec( runner->progcache->join,
     229       30774 :                                &txn_out->accounts.keys[i],
     230       30774 :                                owner,
     231       30774 :                                meta,
     232       30774 :                                features,
     233       30774 :                                fd_bank_slot_get( runner->bank ),
     234       30774 :                                scratch,
     235       30774 :                                meta->dlen );
     236       30774 :     } FD_SPAD_FRAME_END;
     237       30774 :   }
     238             : 
     239       24500 :   fd_funk_txn_xid_t exec_xid[1] = {{ .ul={ fd_bank_slot_get( runner->bank ), runner->bank->data->idx } }};
     240       24500 :   fd_accdb_attach_child        ( runner->accdb_admin,     xid, exec_xid );
     241       24500 :   fd_progcache_txn_attach_child( runner->progcache->join, xid, exec_xid );
     242             : 
     243             :   /* Load instruction accounts */
     244             : 
     245       24500 :   if( FD_UNLIKELY( test_ctx->instr_accounts_count > FD_INSTR_ACCT_MAX ) ) {
     246           0 :     FD_LOG_ERR(( "invariant violation: too many instruction accounts (%lu > %lu)",
     247           0 :                  (ulong)test_ctx->instr_accounts_count, (ulong)FD_INSTR_ACCT_MAX ));
     248           0 :   }
     249             : 
     250             :   /* Restore sysvar cache */
     251       24500 :   fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( runner->bank );
     252       24500 :   ctx->sysvar_cache = sysvar_cache;
     253      351897 :   for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
     254      327397 :     fd_sysvar_cache_restore_from_ref( sysvar_cache, txn_out->accounts.account[i].ro );
     255      327397 :   }
     256             : 
     257       24500 :   ctx->runtime = runtime;
     258             : 
     259       24500 :   fd_sol_sysvar_clock_t clock_[1];
     260       24500 :   fd_sol_sysvar_clock_t * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, clock_ );
     261       24500 :   FD_TEST( clock );
     262       24500 :   fd_bank_slot_set( runner->bank, clock->slot );
     263             : 
     264       24500 :   fd_epoch_schedule_t epoch_schedule_[1];
     265       24500 :   fd_epoch_schedule_t * epoch_schedule = fd_sysvar_cache_epoch_schedule_read( ctx->sysvar_cache, epoch_schedule_ );
     266       24500 :   FD_TEST( epoch_schedule );
     267       24500 :   fd_bank_epoch_schedule_set( runner->bank, *epoch_schedule );
     268             : 
     269       24500 :   fd_rent_t rent_[1];
     270       24500 :   fd_rent_t * rent = fd_sysvar_cache_rent_read( ctx->sysvar_cache, rent_ );
     271       24500 :   FD_TEST( rent );
     272       24500 :   fd_bank_rent_set( runner->bank, *rent );
     273             : 
     274       24500 :   fd_block_block_hash_entry_t const * deq = fd_sysvar_cache_recent_hashes_join_const( ctx->sysvar_cache );
     275       24500 :   FD_TEST( deq );
     276       24548 :   if( !deq_fd_block_block_hash_entry_t_empty( deq ) ) {
     277       24548 :     fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_tail_const( deq );
     278       24552 :     if( last ) {
     279       24552 :       fd_blockhashes_t * blockhashes = fd_bank_block_hash_queue_modify( runner->bank );
     280       24552 :       fd_blockhashes_pop_new( blockhashes );
     281       24552 :       fd_blockhash_info_t * info = fd_blockhashes_push_new( blockhashes, &last->blockhash );
     282       24552 :       info->fee_calculator = last->fee_calculator;
     283             : 
     284       24552 :       fd_bank_rbh_lamports_per_sig_set( runner->bank, last->fee_calculator.lamports_per_signature );
     285       24552 :     }
     286       24548 :   }
     287       24500 :   fd_sysvar_cache_recent_hashes_leave_const( ctx->sysvar_cache, deq );
     288             : 
     289       24500 :   uchar acc_idx_seen[ FD_TXN_ACCT_ADDR_MAX ] = {0};
     290      173404 :   for( ulong j=0UL; j < test_ctx->instr_accounts_count; j++ ) {
     291      148904 :     uint index = test_ctx->instr_accounts[j].index;
     292      148904 :     if( index >= test_ctx->accounts_count ) {
     293           0 :       FD_LOG_ERR(( "invariant violation: instruction account index out of range (%u > %u)",
     294           0 :                    index, test_ctx->instr_accounts_count ));
     295           0 :     }
     296             : 
     297             :     /* Setup instruction accounts */
     298      148904 :     fd_instr_info_setup_instr_account( info,
     299      148904 :                                        acc_idx_seen,
     300      148904 :                                        (ushort)index,
     301      148904 :                                        (ushort)j,
     302      148904 :                                        (ushort)j,
     303      148904 :                                        test_ctx->instr_accounts[j].is_writable,
     304      148904 :                                        test_ctx->instr_accounts[j].is_signer );
     305      148904 :   }
     306       24500 :   info->acct_cnt          = (ushort)test_ctx->instr_accounts_count;
     307             : 
     308       24500 :   ctx->instr              = info;
     309       24500 :   ctx->runtime->progcache = runner->progcache;
     310       24500 :   ctx->runtime->accdb     = runner->accdb;
     311             : 
     312       24500 :   runtime->log.enable_log_collector = 0;
     313             : 
     314       24500 :   fd_log_collector_init( ctx->runtime->log.log_collector, 1 );
     315       24500 :   fd_base58_encode_32( txn_out->accounts.keys[ ctx->instr->program_id ].uc, NULL, ctx->program_id_base58 );
     316       24500 : }
     317             : 
     318             : void
     319             : fd_solfuzz_pb_instr_ctx_destroy( fd_solfuzz_runner_t * runner,
     320       24592 :                                  fd_exec_instr_ctx_t * ctx ) {
     321       24592 :   if( !ctx ) return;
     322       24592 :   fd_accdb_v1_clear( runner->accdb_admin );
     323       24592 :   fd_progcache_clear( runner->progcache->join );
     324             : 
     325             :   /* In order to check for leaks in the workspace, we need to compact the
     326             :      allocators. Without doing this, empty superblocks may be retained
     327             :      by the fd_alloc instance, which mean we cannot check for leaks. */
     328       24592 :   fd_alloc_compact( fd_accdb_admin_v1_funk( runner->accdb_admin )->alloc );
     329       24592 :   fd_alloc_compact( runner->progcache->join->alloc );
     330       24592 : }
     331             : 
     332             : ulong
     333             : fd_solfuzz_pb_instr_run( fd_solfuzz_runner_t * runner,
     334             :                          void const *          input_,
     335             :                          void **               output_,
     336             :                          void *                output_buf,
     337       19787 :                          ulong                 output_bufsz ) {
     338       19787 :   fd_exec_test_instr_context_t const * input  = fd_type_pun_const( input_ );
     339       19787 :   fd_exec_test_instr_effects_t **      output = fd_type_pun( output_ );
     340             : 
     341             :   /* Convert the Protobuf inputs to a fd_exec context */
     342       19787 :   fd_exec_instr_ctx_t ctx[1];
     343       19787 :   fd_solfuzz_pb_instr_ctx_create( runner, ctx, input );
     344             : 
     345       19787 :   fd_instr_info_t * instr = (fd_instr_info_t *) ctx->instr;
     346             : 
     347             :   /* Execute the test */
     348       19787 :   int exec_result = fd_execute_instr( ctx->runtime, runner->bank, ctx->txn_in, ctx->txn_out, instr );
     349             : 
     350             :   /* Allocate space to capture outputs */
     351       19787 :   ulong output_end = (ulong)output_buf + output_bufsz;
     352       19787 :   FD_SCRATCH_ALLOC_INIT( l, output_buf );
     353             : 
     354       19787 :   fd_exec_test_instr_effects_t * effects =
     355       19787 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_instr_effects_t),
     356       19787 :                                 sizeof (fd_exec_test_instr_effects_t) );
     357       19787 :   if( FD_UNLIKELY( _l > output_end ) ) {
     358           0 :     fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
     359           0 :     return 0UL;
     360           0 :   }
     361       19787 :   fd_memset( effects, 0, sizeof(fd_exec_test_instr_effects_t) );
     362             : 
     363             :   /* Capture error code */
     364             : 
     365       19787 :   effects->result   = -exec_result;
     366       19787 :   effects->cu_avail = ctx->txn_out->details.compute_budget.compute_meter;
     367             : 
     368             :   /* Don't capture custom error codes if the program is a precompile */
     369       19787 :   if( FD_LIKELY( effects->result ) ) {
     370       18313 :     int program_id_idx = ctx->instr[ 0UL ].program_id;
     371       18313 :     if( exec_result==FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR &&
     372       18313 :         fd_executor_lookup_native_precompile_program( &ctx->txn_out->accounts.keys[ program_id_idx ] )==NULL ) {
     373         915 :       effects->custom_err = ctx->txn_out->err.custom_err;
     374         915 :     }
     375       18313 :   }
     376             : 
     377             :   /* Allocate space for captured accounts */
     378       19787 :   ulong modified_acct_cnt = ctx->txn_out->accounts.cnt;
     379             : 
     380       19787 :   fd_exec_test_acct_state_t * modified_accts =
     381       19787 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_acct_state_t),
     382       19787 :                                 sizeof (fd_exec_test_acct_state_t) * modified_acct_cnt );
     383       19787 :   if( FD_UNLIKELY( _l > output_end ) ) {
     384           0 :     fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
     385           0 :     return 0;
     386           0 :   }
     387       19787 :   effects->modified_accounts       = modified_accts;
     388       19787 :   effects->modified_accounts_count = 0UL;
     389             : 
     390             :   /* Capture borrowed accounts */
     391             : 
     392      301763 :   for( ulong j=0UL; j < ctx->txn_out->accounts.cnt; j++ ) {
     393      281976 :     fd_pubkey_t * acc_key = &ctx->txn_out->accounts.keys[j];
     394      281976 :     fd_account_meta_t * acc = ctx->txn_out->accounts.account[j].meta;
     395      281976 :     if( !acc ) {
     396           0 :       continue;
     397           0 :     }
     398             : 
     399      281976 :     ulong modified_idx = effects->modified_accounts_count;
     400      281976 :     assert( modified_idx < modified_acct_cnt );
     401             : 
     402           0 :     fd_exec_test_acct_state_t * out_acct = &effects->modified_accounts[ modified_idx ];
     403      281976 :     memset( out_acct, 0, sizeof(fd_exec_test_acct_state_t) );
     404             :     /* Copy over account content */
     405             : 
     406      281976 :     memcpy( out_acct->address, acc_key, sizeof(fd_pubkey_t) );
     407      281976 :     out_acct->lamports = acc->lamports;
     408      281976 :     if( acc->dlen>0UL ) {
     409      248865 :       out_acct->data =
     410      248865 :         FD_SCRATCH_ALLOC_APPEND( l, alignof(pb_bytes_array_t),
     411      248865 :                                     PB_BYTES_ARRAY_T_ALLOCSIZE( acc->dlen ) );
     412      248865 :       if( FD_UNLIKELY( _l > output_end ) ) {
     413           0 :         fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
     414           0 :         return 0UL;
     415           0 :       }
     416      248865 :       out_acct->data->size = (pb_size_t)acc->dlen;
     417      248865 :       fd_memcpy( out_acct->data->bytes, fd_account_data( acc ), acc->dlen );
     418      248865 :     }
     419             : 
     420      281976 :     out_acct->executable = acc->executable;
     421      281976 :     memcpy( out_acct->owner, acc->owner, sizeof(fd_pubkey_t) );
     422             : 
     423      281976 :     effects->modified_accounts_count++;
     424      281976 :   }
     425             : 
     426             :   /* Capture return data */
     427       19787 :   fd_txn_return_data_t * return_data = &ctx->txn_out->details.return_data;
     428       19787 :   if( return_data->len>0UL ) {
     429          21 :     effects->return_data = FD_SCRATCH_ALLOC_APPEND(l, alignof(pb_bytes_array_t),
     430          21 :                                 PB_BYTES_ARRAY_T_ALLOCSIZE( return_data->len ) );
     431          21 :     if( FD_UNLIKELY( _l > output_end ) ) {
     432           0 :       fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
     433           0 :       return 0UL;
     434           0 :     }
     435          21 :     effects->return_data->size = (pb_size_t)return_data->len;
     436          21 :     fd_memcpy( effects->return_data->bytes, return_data->data, return_data->len );
     437          21 :   }
     438             : 
     439       19787 :   ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     440       19787 :   fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
     441             : 
     442       19787 :   *output = effects;
     443       19787 :   return actual_end - (ulong)output_buf;
     444       19787 : }

Generated by: LCOV version 1.14