LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_dump_pb.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 1004 0.0 %
Date: 2026-09-12 04:25:37 Functions: 0 31 0.0 %

          Line data    Source code
       1             : #include "fd_dump_pb.h"
       2             : #include "fd_solfuzz_private.h"
       3             : #include "generated/block.pb.h"
       4             : #include "generated/instr.pb.h"
       5             : #include "generated/txn.pb.h"
       6             : #include "generated/vm.pb.h"
       7             : #include "../fd_system_ids.h"
       8             : #include "../fd_bank.h"
       9             : #include "../fd_runtime.h"
      10             : #include "../fd_alut.h"
      11             : #include "../program/fd_precompiles.h"
      12             : #include "../../../third_party/nanopb/pb_encode.h"
      13             : #include "../fd_runtime_stack.h"
      14             : #include "../../../util/fd_hash32.h"
      15             : 
      16             : #include <stdio.h> /* fopen */
      17             : #include <unistd.h> /* access */
      18             : 
      19             : 
      20             : struct fd_dump_account_key {
      21             :   fd_pubkey_t key;
      22             : };
      23             : typedef struct fd_dump_account_key fd_dump_account_t;
      24             : 
      25           0 : #define FD_DUMP_ACCOUNT_KEY_MAP_LG_SLOT_CNT (20)
      26             : 
      27             : #define MAP_NAME              fd_dump_account_key_map
      28           0 : #define MAP_T                 fd_dump_account_t
      29           0 : #define MAP_LG_SLOT_CNT       FD_DUMP_ACCOUNT_KEY_MAP_LG_SLOT_CNT
      30           0 : #define MAP_KEY_T             fd_pubkey_t
      31           0 : #define MAP_KEY_NULL          fd_solana_system_program_id
      32           0 : #define MAP_KEY_INVAL(k)      fd_pubkey_eq( &(k), &fd_solana_system_program_id )
      33           0 : #define MAP_KEY_EQUAL(k0,k1)  fd_pubkey_eq( &(k0), &(k1) )
      34             : #define MAP_KEY_EQUAL_IS_SLOW (0)
      35             : #define MAP_MEMOIZE           (0)
      36           0 : #define MAP_KEY_HASH(key)     ((uint)fd_hash32( (key).uc, 0UL ))
      37             : #include "../../../util/tmpl/fd_map.c"
      38             : 
      39             : struct fd_dump_account_key_set {
      40             :   fd_dump_account_t * map;
      41             :   ulong               cnt;
      42             :   uchar               system_program_dumped;
      43             : };
      44             : typedef struct fd_dump_account_key_set fd_dump_account_key_set_t;
      45             : 
      46             : struct fd_dump_account_key_iter {
      47             :   fd_dump_account_key_set_t const * set;
      48             :   ulong                             slot_idx;
      49             :   uchar                             system_program;
      50             : };
      51             : typedef struct fd_dump_account_key_iter fd_dump_account_key_iter_t;
      52             : 
      53             : static void
      54           0 : fd_dump_account_key_iter_advance_map( fd_dump_account_key_iter_t * iter ) {
      55           0 :   while( iter->slot_idx<fd_dump_account_key_map_slot_cnt() &&
      56           0 :          fd_dump_account_key_map_key_inval( iter->set->map[iter->slot_idx].key ) ) {
      57           0 :     iter->slot_idx++;
      58           0 :   }
      59           0 : }
      60             : 
      61             : static fd_dump_account_key_iter_t *
      62             : fd_dump_account_key_iter_init( fd_dump_account_key_iter_t *      iter,
      63           0 :                                fd_dump_account_key_set_t const * set ) {
      64           0 :   iter->set            = set;
      65           0 :   iter->slot_idx       = 0UL;
      66           0 :   iter->system_program = set->system_program_dumped;
      67           0 :   if( !iter->system_program ) fd_dump_account_key_iter_advance_map( iter );
      68           0 :   return iter;
      69           0 : }
      70             : 
      71             : static int
      72           0 : fd_dump_account_key_iter_done( fd_dump_account_key_iter_t const * iter ) {
      73           0 :   return (!iter->system_program) & (iter->slot_idx>=fd_dump_account_key_map_slot_cnt());
      74           0 : }
      75             : 
      76             : static fd_pubkey_t const *
      77           0 : fd_dump_account_key_iter_ele( fd_dump_account_key_iter_t const * iter ) {
      78           0 :   return iter->system_program ? &fd_solana_system_program_id : &iter->set->map[iter->slot_idx].key;
      79           0 : }
      80             : 
      81             : static void
      82           0 : fd_dump_account_key_iter_next( fd_dump_account_key_iter_t * iter ) {
      83           0 :   if( iter->system_program ) {
      84           0 :     iter->system_program = 0;
      85           0 :   } else {
      86           0 :     iter->slot_idx++;
      87           0 :   }
      88           0 :   fd_dump_account_key_iter_advance_map( iter );
      89           0 : }
      90             : 
      91             : /***** CONSTANTS *****/
      92             : static fd_pubkey_t const * fd_dump_sysvar_ids[] = {
      93             :   &fd_sysvar_recent_block_hashes_id,
      94             :   &fd_sysvar_clock_id,
      95             :   &fd_sysvar_slot_history_id,
      96             :   &fd_sysvar_slot_hashes_id,
      97             :   &fd_sysvar_epoch_schedule_id,
      98             :   &fd_sysvar_epoch_rewards_id,
      99             :   &fd_sysvar_fees_id,
     100             :   &fd_sysvar_rent_id,
     101             :   &fd_sysvar_stake_history_id,
     102             :   &fd_sysvar_last_restart_slot_id,
     103             :   &fd_sysvar_instructions_id,
     104             : };
     105             : static ulong const num_sysvar_entries = (sizeof(fd_dump_sysvar_ids) / sizeof(fd_pubkey_t *));
     106             : 
     107             : static fd_pubkey_t const * fd_dump_builtin_ids[] = {
     108             :   &fd_solana_system_program_id,
     109             :   &fd_solana_vote_program_id,
     110             :   &fd_solana_stake_program_id,
     111             :   &fd_solana_bpf_loader_v4_program_id,
     112             :   &fd_solana_bpf_loader_deprecated_program_id,
     113             :   &fd_solana_bpf_loader_program_id,
     114             :   &fd_solana_bpf_loader_upgradeable_program_id,
     115             :   &fd_solana_compute_budget_program_id,
     116             :   &fd_solana_keccak_secp_256k_program_id,
     117             :   &fd_solana_secp256r1_program_id,
     118             :   &fd_solana_zk_elgamal_proof_program_id,
     119             :   &fd_solana_ed25519_sig_verify_program_id,
     120             : };
     121             : static ulong const num_loaded_builtins = (sizeof(fd_dump_builtin_ids) / sizeof(fd_pubkey_t *));
     122             : 
     123             : /***** UTILITY FUNCTIONS *****/
     124             : 
     125             : /** FEATURE DUMPING **/
     126             : static void
     127             : dump_sorted_features( fd_features_t const *        features,
     128             :                       fd_exec_test_feature_set_t * output_feature_set,
     129           0 :                       fd_spad_t *                  spad ) {
     130             :   /* NOTE: Caller must have a spad frame prepared */
     131           0 :   uint64_t * unsorted_features = fd_spad_alloc( spad, alignof(uint64_t), FD_FEATURE_ID_CNT * sizeof(uint64_t) );
     132           0 :   ulong num_features = 0;
     133           0 :   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 ) ) {
     134           0 :     if (features->f[current_feature->index] != FD_FEATURE_DISABLED) {
     135           0 :       unsorted_features[num_features++] = (uint64_t) current_feature->id.ul[0];
     136           0 :     }
     137           0 :   }
     138             : 
     139             :   // Set feature set in message
     140           0 :   output_feature_set->features_count = (pb_size_t)num_features;
     141           0 :   output_feature_set->features       = unsorted_features;
     142           0 : }
     143             : 
     144             : /** ACCOUNT DUMPING **/
     145             : static void
     146             : dump_account_state( fd_acc_t const *            acc,
     147             :                     fd_exec_test_acct_state_t * output_account,
     148           0 :                     fd_spad_t *                 spad ) {
     149             :     // Address
     150           0 :     fd_memcpy(output_account->address, acc->pubkey, sizeof(fd_pubkey_t));
     151             : 
     152             :     // Lamports
     153           0 :     output_account->lamports = (uint64_t)acc->lamports;
     154             : 
     155             :     // Data
     156           0 :     pb_bytes_array_t * data = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE( acc->data_len ) );
     157           0 :     data->size = (pb_size_t) acc->data_len;
     158           0 :     fd_memcpy( data->bytes, acc->data, acc->data_len );
     159           0 :     output_account->which_data_repr = FD_EXEC_TEST_ACCT_STATE_DATA_TAG;
     160           0 :     output_account->data_repr.data  = data;
     161             : 
     162             :     // Executable
     163           0 :     output_account->executable = (bool)acc->executable;
     164             : 
     165             :     // Owner
     166           0 :     fd_memcpy(output_account->owner, acc->owner, sizeof(fd_pubkey_t));
     167           0 : }
     168             : 
     169             : static uchar
     170             : account_already_dumped( fd_exec_test_acct_state_t const * dumped_accounts,
     171             :                         ulong                             dumped_cnt,
     172           0 :                         fd_pubkey_t const *               account_key ) {
     173           0 :   for( ulong i=0UL; i<dumped_cnt; i++ ) {
     174           0 :     if( !memcmp( account_key, dumped_accounts[i].address, sizeof(fd_pubkey_t) ) ) {
     175           0 :       return 1;
     176           0 :     }
     177           0 :   }
     178           0 :   return 0;
     179           0 : }
     180             : 
     181             : /* Dumps a borrowed account if it exists and has not been dumped yet.
     182             :    Sets up the output borrowed account if it exists. Returns 0 if the
     183             :    account exists, 1 otherwise.
     184             :    TODO: This can be optimized by using a set. */
     185             : static uchar
     186             : dump_account_if_not_already_dumped( fd_accdb_t *                accdb,
     187             :                                     fd_accdb_fork_id_t          fork_id,
     188             :                                     fd_pubkey_t const *         account_key,
     189             :                                     fd_spad_t *                 spad,
     190             :                                     fd_exec_test_acct_state_t * out_acct_states,
     191             :                                     pb_size_t *                 out_acct_states_cnt,
     192           0 :                                     fd_acc_t *                  out_ro ) {
     193           0 :   fd_acc_t ro = fd_accdb_read_one( accdb, fork_id, account_key->uc );
     194           0 :   if( FD_UNLIKELY( !ro.lamports ) ) {
     195           0 :     fd_accdb_unread_one( accdb, &ro );
     196           0 :     return 1;
     197           0 :   }
     198             : 
     199           0 :   if( !account_already_dumped( out_acct_states, *out_acct_states_cnt, account_key ) ) {
     200           0 :     dump_account_state( &ro, &out_acct_states[*out_acct_states_cnt], spad );
     201           0 :     (*out_acct_states_cnt)++;
     202           0 :   }
     203             : 
     204           0 :   if( out_ro ) {
     205           0 :     *out_ro = ro;
     206           0 :   } else {
     207           0 :     fd_accdb_unread_one( accdb, &ro );
     208           0 :   }
     209           0 :   return 0;
     210           0 : }
     211             : 
     212             : static void
     213             : dump_executable_account_if_exists( fd_accdb_t *                      accdb,
     214             :                                    fd_accdb_fork_id_t                fork_id,
     215             :                                    fd_exec_test_acct_state_t const * program_account,
     216             :                                    fd_spad_t *                       spad,
     217             :                                    fd_exec_test_acct_state_t *       out_account_states,
     218           0 :                                    pb_size_t *                       out_account_states_count ) {
     219           0 :   if( FD_LIKELY( memcmp( program_account->owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     220           0 :     return;
     221           0 :   }
     222             : 
     223           0 :   pb_bytes_array_t const * program_data = fd_solfuzz_acct_data( program_account );
     224           0 :   if( FD_UNLIKELY( !program_data ) ) {
     225           0 :     return;
     226           0 :   }
     227             : 
     228           0 :   fd_bpf_state_t program_loader_state[1];
     229           0 :   if( FD_UNLIKELY( fd_bpf_state_decode(
     230           0 :       program_loader_state,
     231           0 :       program_data->bytes,
     232           0 :       program_data->size ) ) ) {
     233           0 :     return;
     234           0 :   }
     235           0 :   if( program_loader_state->discriminant!=FD_BPF_STATE_PROGRAM ) {
     236           0 :     return;
     237           0 :   }
     238             : 
     239           0 :   fd_pubkey_t * programdata_acc = &program_loader_state->inner.program.programdata_address;
     240           0 :   dump_account_if_not_already_dumped( accdb, fork_id, programdata_acc, spad, out_account_states, out_account_states_count, NULL );
     241           0 : }
     242             : 
     243             : static void
     244             : dump_sanitized_transaction( fd_accdb_t *                           accdb,
     245             :                             fd_accdb_fork_id_t                     fork_id,
     246             :                             fd_txn_t const *                       txn_descriptor,
     247             :                             uchar const *                          txn_payload,
     248             :                             fd_spad_t *                            spad,
     249           0 :                             fd_exec_test_sanitized_transaction_t * sanitized_transaction ) {
     250           0 :   fd_txn_acct_addr_lut_t const * address_lookup_tables = fd_txn_get_address_tables_const( txn_descriptor );
     251             : 
     252             :   /* Transaction Context -> tx -> message */
     253           0 :   sanitized_transaction->has_message = true;
     254           0 :   fd_exec_test_transaction_message_t * message = &sanitized_transaction->message;
     255             : 
     256             :   /* Transaction Context -> tx -> message -> version / v1_config */
     257           0 :   int is_v1     = txn_descriptor->transaction_version==FD_TXN_V1;
     258           0 :   int is_legacy = txn_descriptor->transaction_version==FD_TXN_VLEGACY;
     259           0 :   message->version       = is_v1     ? FD_EXEC_TEST_TRANSACTION_VERSION_TRANSACTION_VERSION_V1
     260           0 :                          : is_legacy ? FD_EXEC_TEST_TRANSACTION_VERSION_TRANSACTION_VERSION_LEGACY
     261           0 :                          :             FD_EXEC_TEST_TRANSACTION_VERSION_TRANSACTION_VERSION_V0;
     262           0 :   message->has_v1_config = (bool)is_v1;
     263           0 :   if( is_v1 ) {
     264           0 :     uint          mask = fd_uint_load_4( txn_payload+4UL );
     265           0 :     uchar const * v    = txn_payload + txn_descriptor->v1_txn_config_values_off;
     266           0 :     fd_exec_test_transaction_config_t * cfg = &message->v1_config;
     267           0 :     if( mask & 0x01U ) { cfg->has_priority_fee = 1;                    cfg->priority_fee = FD_LOAD( ulong, v );                   v += 8UL; }
     268           0 :     if( mask & 0x04U ) { cfg->has_compute_unit_limit = 1;              cfg->compute_unit_limit = FD_LOAD( uint, v );              v += 4UL; }
     269           0 :     if( mask & 0x08U ) { cfg->has_loaded_accounts_data_size_limit = 1; cfg->loaded_accounts_data_size_limit = FD_LOAD( uint, v ); v += 4UL; }
     270           0 :     if( mask & 0x10U ) { cfg->has_heap_size = 1;                       cfg->heap_size = FD_LOAD( uint, v );                                 }
     271           0 :   }
     272             : 
     273             :   /* Transaction Context -> tx -> message -> header */
     274           0 :   message->has_header = true;
     275           0 :   fd_exec_test_message_header_t * header = &message->header;
     276             : 
     277             :   /* Transaction Context -> tx -> message -> header -> num_required_signatures */
     278           0 :   header->num_required_signatures = txn_descriptor->signature_cnt;
     279             : 
     280             :   /* Transaction Context -> tx -> message -> header -> num_readonly_signed_accounts */
     281           0 :   header->num_readonly_signed_accounts = txn_descriptor->readonly_signed_cnt;
     282             : 
     283             :   /* Transaction Context -> tx -> message -> header -> num_readonly_unsigned_accounts */
     284           0 :   header->num_readonly_unsigned_accounts = txn_descriptor->readonly_unsigned_cnt;
     285             : 
     286             :   /* Transaction Context -> tx -> message -> account_keys */
     287           0 :   message->account_keys_count = txn_descriptor->acct_addr_cnt;
     288           0 :   message->account_keys = fd_spad_alloc( spad, alignof(pb_bytes_array_t *), PB_BYTES_ARRAY_T_ALLOCSIZE(txn_descriptor->acct_addr_cnt * sizeof(pb_bytes_array_t *)) );
     289           0 :   fd_acct_addr_t const * account_keys = fd_txn_get_acct_addrs( txn_descriptor, txn_payload );
     290           0 :   for( ulong i = 0; i < txn_descriptor->acct_addr_cnt; i++ ) {
     291           0 :     pb_bytes_array_t * account_key = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE(sizeof(fd_pubkey_t)) );
     292           0 :     account_key->size = sizeof(fd_pubkey_t);
     293           0 :     memcpy( account_key->bytes, &account_keys[i], sizeof(fd_pubkey_t) );
     294           0 :     message->account_keys[i] = account_key;
     295           0 :   }
     296             : 
     297             :   /* Transaction Context -> tx -> message -> recent_blockhash */
     298           0 :   uchar const * recent_blockhash = fd_txn_get_recent_blockhash( txn_descriptor, txn_payload );
     299           0 :   memcpy( message->recent_blockhash, recent_blockhash, sizeof(fd_hash_t) );
     300             : 
     301             :   /* Transaction Context -> tx -> message -> instructions */
     302           0 :   message->instructions_count = txn_descriptor->instr_cnt;
     303           0 :   message->instructions = fd_spad_alloc( spad, alignof(fd_exec_test_compiled_instruction_t), txn_descriptor->instr_cnt * sizeof(fd_exec_test_compiled_instruction_t) );
     304           0 :   for( ulong i = 0; i < txn_descriptor->instr_cnt; ++i ) {
     305           0 :     fd_txn_instr_t instr = txn_descriptor->instr[i];
     306           0 :     fd_exec_test_compiled_instruction_t * compiled_instruction = &message->instructions[i];
     307             : 
     308             :     // compiled instruction -> program_id_index
     309           0 :     compiled_instruction->program_id_index = instr.program_id;
     310             : 
     311             :     // compiled instruction -> accounts
     312           0 :     compiled_instruction->accounts_count = instr.acct_cnt;
     313           0 :     compiled_instruction->accounts = fd_spad_alloc( spad, alignof(uint32_t), instr.acct_cnt * sizeof(uint32_t) );
     314           0 :     uchar const * instr_accounts = fd_txn_get_instr_accts( &instr, txn_payload );
     315           0 :     for( ulong j = 0; j < instr.acct_cnt; ++j ) {
     316           0 :       uchar instr_acct_index = instr_accounts[j];
     317           0 :       compiled_instruction->accounts[j] = instr_acct_index;
     318           0 :     }
     319             : 
     320             :     // compiled instruction -> data
     321           0 :     uchar const * instr_data = fd_txn_get_instr_data( &instr, txn_payload );
     322           0 :     compiled_instruction->data = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE(instr.data_sz) );
     323           0 :     compiled_instruction->data->size = instr.data_sz;
     324           0 :     memcpy( compiled_instruction->data->bytes, instr_data, instr.data_sz );
     325           0 :   }
     326             : 
     327             :   /* ALUT stuff (V0 only: legacy and V1 have none) */
     328           0 :   message->address_table_lookups_count = 0;
     329           0 :   if( !is_legacy && !is_v1 ) {
     330             :     /* Transaction Context -> tx -> message -> address_table_lookups */
     331           0 :     message->address_table_lookups_count = txn_descriptor->addr_table_lookup_cnt;
     332           0 :     message->address_table_lookups = fd_spad_alloc( spad,
     333           0 :                                                     alignof(fd_exec_test_message_address_table_lookup_t),
     334           0 :                                                     txn_descriptor->addr_table_lookup_cnt * sizeof(fd_exec_test_message_address_table_lookup_t) );
     335           0 :     for( ulong i = 0; i < txn_descriptor->addr_table_lookup_cnt; ++i ) {
     336             :       // alut -> account_key
     337           0 :       fd_pubkey_t * alut_key = (fd_pubkey_t *) (txn_payload + address_lookup_tables[i].addr_off);
     338           0 :       memcpy( message->address_table_lookups[i].account_key, alut_key, sizeof(fd_pubkey_t) );
     339             : 
     340             :       // Access ALUT account data to access its keys
     341           0 :       fd_acc_t acc = fd_accdb_read_one( accdb, fork_id, alut_key->uc );
     342           0 :       if( FD_UNLIKELY( !acc.lamports ) ) FD_LOG_ERR(( "addr lut not found" ));
     343             : 
     344             :       // alut -> writable_indexes
     345           0 :       message->address_table_lookups[i].writable_indexes_count = address_lookup_tables[i].writable_cnt;
     346           0 :       message->address_table_lookups[i].writable_indexes = fd_spad_alloc( spad, alignof(uint32_t), address_lookup_tables[i].writable_cnt * sizeof(uint32_t) );
     347           0 :       uchar * writable_indexes = (uchar *) (txn_payload + address_lookup_tables[i].writable_off);
     348           0 :       for( ulong j = 0; j < address_lookup_tables[i].writable_cnt; ++j ) {
     349           0 :         message->address_table_lookups[i].writable_indexes[j] = writable_indexes[j];
     350           0 :       }
     351             : 
     352             :       // alut -> readonly_indexes
     353           0 :       message->address_table_lookups[i].readonly_indexes_count = address_lookup_tables[i].readonly_cnt;
     354           0 :       message->address_table_lookups[i].readonly_indexes = fd_spad_alloc( spad, alignof(uint32_t), address_lookup_tables[i].readonly_cnt * sizeof(uint32_t) );
     355           0 :       uchar * readonly_indexes = (uchar *) (txn_payload + address_lookup_tables[i].readonly_off);
     356           0 :       for( ulong j = 0; j < address_lookup_tables[i].readonly_cnt; ++j ) {
     357           0 :         message->address_table_lookups[i].readonly_indexes[j] = readonly_indexes[j];
     358           0 :       }
     359             : 
     360           0 :       fd_accdb_unread_one( accdb, &acc );
     361           0 :     }
     362           0 :   }
     363             : 
     364             :   /* Transaction Context -> tx -> message_hash */
     365             :   // Skip because it does not matter what's in here
     366             : 
     367             :   /* Transaction Context -> tx -> signatures */
     368           0 :   sanitized_transaction->signatures_count = txn_descriptor->signature_cnt;
     369           0 :   sanitized_transaction->signatures = fd_spad_alloc( spad, alignof(pb_bytes_array_t *), PB_BYTES_ARRAY_T_ALLOCSIZE(txn_descriptor->signature_cnt * sizeof(pb_bytes_array_t *)) );
     370           0 :   fd_ed25519_sig_t const * signatures = fd_txn_get_signatures( txn_descriptor, txn_payload );
     371           0 :   for( uchar i = 0; i < txn_descriptor->signature_cnt; ++i ) {
     372           0 :     pb_bytes_array_t * signature = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE(sizeof(fd_ed25519_sig_t)) );
     373           0 :     signature->size = sizeof(fd_ed25519_sig_t);
     374           0 :     memcpy( signature->bytes, &signatures[i], sizeof(fd_ed25519_sig_t) );
     375           0 :     sanitized_transaction->signatures[i] = signature;
     376           0 :   }
     377           0 : }
     378             : 
     379             : static void
     380             : dump_fee_rate_governor( fd_bank_t *                        bank,
     381           0 :                         fd_exec_test_fee_rate_governor_t * out ) {
     382           0 :   fd_fee_rate_governor_t const * frg = &bank->f.fee_rate_governor;
     383           0 :   *out = (fd_exec_test_fee_rate_governor_t){
     384           0 :     .target_lamports_per_signature = frg->target_lamports_per_signature,
     385           0 :     .target_signatures_per_slot    = frg->target_signatures_per_slot,
     386           0 :     .min_lamports_per_signature    = frg->min_lamports_per_signature,
     387           0 :     .max_lamports_per_signature    = frg->max_lamports_per_signature,
     388           0 :     .burn_percent                  = frg->burn_percent,
     389           0 :   };
     390           0 : }
     391             : 
     392             : static void
     393             : dump_blockhash_queue( fd_bank_t *                             bank,
     394             :                       fd_spad_t *                             spad,
     395             :                       fd_exec_test_blockhash_queue_entry_t ** entries_out,
     396           0 :                       pb_size_t *                             count_out ) {
     397           0 :   fd_blockhashes_t const * bhq      = &bank->f.block_hash_queue;
     398           0 :   ulong                    bhq_size = fd_ulong_min( FD_BLOCKHASHES_MAX, fd_blockhash_deq_cnt( bhq->d.deque ) );
     399             : 
     400           0 :   fd_exec_test_blockhash_queue_entry_t * entries = fd_spad_alloc( spad,
     401           0 :       alignof(fd_exec_test_blockhash_queue_entry_t),
     402           0 :       bhq_size * sizeof(fd_exec_test_blockhash_queue_entry_t) );
     403             : 
     404           0 :   ulong cnt = 0UL;
     405           0 :   for( fd_blockhash_deq_iter_t iter=fd_blockhash_deq_iter_init_rev( bhq->d.deque );
     406           0 :        !fd_blockhash_deq_iter_done_rev( bhq->d.deque, iter ) && cnt<bhq_size;
     407           0 :        iter=fd_blockhash_deq_iter_prev( bhq->d.deque, iter ), cnt++ ) {
     408           0 :     fd_blockhash_info_t const * ele   = fd_blockhash_deq_iter_ele_const( bhq->d.deque, iter );
     409           0 :     fd_exec_test_blockhash_queue_entry_t * entry = &entries[bhq_size-cnt-1UL];
     410           0 :     fd_memcpy( entry->blockhash, ele->hash.uc, sizeof(fd_hash_t) );
     411           0 :     entry->lamports_per_signature = ele->lamports_per_signature;
     412           0 :   }
     413             : 
     414           0 :   *entries_out = entries;
     415           0 :   *count_out   = (pb_size_t)bhq_size;
     416           0 : }
     417             : 
     418             : static void
     419             : dump_txn_bank( fd_bank_t *                  bank,
     420             :                fd_spad_t *                  spad,
     421           0 :                fd_exec_test_txn_context_t * txn_context ) {
     422           0 :   txn_context->has_bank              = true;
     423           0 :   fd_exec_test_txn_bank_t * txn_bank = &txn_context->bank;
     424             : 
     425             :   /* TxnBank -> blockhash_queue */
     426           0 :   dump_blockhash_queue( bank, spad, &txn_bank->blockhash_queue, &txn_bank->blockhash_queue_count );
     427             : 
     428             :   /* TxnBank -> rbh_lamports_per_signature */
     429           0 :   txn_bank->rbh_lamports_per_signature = (uint)bank->f.rbh_lamports_per_sig;
     430             : 
     431             :   /* TxnBank -> fee_rate_governor */
     432           0 :   txn_bank->has_fee_rate_governor = true;
     433           0 :   dump_fee_rate_governor( bank, &txn_bank->fee_rate_governor );
     434             : 
     435             :   /* TxnBank -> total_epoch_stake */
     436           0 :   txn_bank->total_epoch_stake = bank->f.total_epoch_stake;
     437             : 
     438             :   /* TxnBank -> features */
     439           0 :   txn_bank->has_features = true;
     440           0 :   dump_sorted_features( &bank->f.features, &txn_bank->features, spad );
     441           0 : }
     442             : 
     443             : /** SECONDARY FUNCTIONS **/
     444             : 
     445             : /* add_account_to_dumped_accounts adds an account to the dumped accounts
     446             :    set if it does not exist already. Returns 0 if the account already
     447             :    exists, and 1 if the account was added successfully.
     448             : 
     449             :    TODO: Txn dumping should be optimized to use these functions. */
     450             : static uchar
     451             : add_account_to_dumped_accounts( fd_dump_account_key_set_t * dumped_accounts,
     452           0 :                                 fd_pubkey_t const *         pubkey ) {
     453           0 :   if( fd_pubkey_eq( pubkey, &fd_solana_system_program_id ) ) {
     454           0 :     if( dumped_accounts->system_program_dumped ) return 0;
     455           0 :     dumped_accounts->system_program_dumped = 1;
     456           0 :     dumped_accounts->cnt++;
     457           0 :     return 1;
     458           0 :   }
     459             : 
     460             :   /* If the key already exists, return early. */
     461           0 :   if( fd_dump_account_key_map_query( dumped_accounts->map, *pubkey, NULL ) ) {
     462           0 :     return 0;
     463           0 :   }
     464             : 
     465           0 :   if( FD_UNLIKELY( dumped_accounts->cnt-dumped_accounts->system_program_dumped>=fd_dump_account_key_map_key_max() ) ) {
     466           0 :     FD_LOG_CRIT(( "too many dumped accounts for fd_dump_account_key_map" ));
     467           0 :   }
     468           0 :   fd_dump_account_t * new_ele = fd_dump_account_key_map_insert( dumped_accounts->map, *pubkey );
     469           0 :   if( FD_UNLIKELY( !new_ele ) ) FD_LOG_CRIT(( "fd_dump_account_key_map_insert failed" ));
     470           0 :   dumped_accounts->cnt++;
     471           0 :   return 1;
     472           0 : }
     473             : 
     474             : /* add_account_and_programdata_to_dumped_accounts adds an account and
     475             :    its programdata account (if the account is a v3 program) to the
     476             :    dumped accounts set if they do not exist already. */
     477             : static void
     478             : add_account_and_programdata_to_dumped_accounts( fd_accdb_t *                accdb,
     479             :                                                 fd_accdb_fork_id_t          fork_id,
     480             :                                                 fd_dump_account_key_set_t * dumped_accounts,
     481           0 :                                                 fd_pubkey_t const *         pubkey ) {
     482             :   /* Add the current account to the dumped accounts set. We can save
     483             :      some time by enforcing an invariant that "if current account was
     484             :      dumped, then programdata account was also dumped," so we save
     485             :      ourselves a call to accdb. */
     486           0 :   uchar ret = add_account_to_dumped_accounts( dumped_accounts, pubkey );
     487           0 :   if( ret==0 ) return;
     488             : 
     489             :   /* Read the account from accdb to see if its a program account and if
     490             :      it needs to be dumped. */
     491           0 :   fd_acc_t program_account = fd_accdb_read_one( accdb, fork_id, pubkey->uc );
     492           0 :   if( FD_UNLIKELY( !program_account.lamports ) ) {
     493           0 :     fd_accdb_unread_one( accdb, &program_account );
     494           0 :     return;
     495           0 :   }
     496             : 
     497             :   /* Return if its not owned by the v3 loader */
     498           0 :   if( FD_LIKELY( !fd_pubkey_eq( (fd_pubkey_t*)program_account.owner, &fd_solana_bpf_loader_upgradeable_program_id ) ) ) {
     499           0 :     fd_accdb_unread_one( accdb, &program_account );
     500           0 :     return;
     501           0 :   }
     502             : 
     503             :   /* Get the program account state */
     504           0 :   fd_bpf_state_t program_account_state[1];
     505           0 :   if( FD_UNLIKELY( fd_bpf_state_decode(
     506           0 :       program_account_state,
     507           0 :       program_account.data,
     508           0 :       program_account.data_len ) ) ) {
     509           0 :     fd_accdb_unread_one( accdb, &program_account );
     510           0 :     return;
     511           0 :   }
     512           0 :   if( program_account_state->discriminant!=FD_BPF_STATE_PROGRAM ) {
     513           0 :     fd_accdb_unread_one( accdb, &program_account );
     514           0 :     return;
     515           0 :   }
     516             : 
     517             :   /* Dump the programdata address */
     518           0 :   add_account_to_dumped_accounts( dumped_accounts, &program_account_state->inner.program.programdata_address );
     519           0 :   fd_accdb_unread_one( accdb, &program_account );
     520           0 : }
     521             : 
     522             : /* add_lut_account_to_dumped_accounts adds an address lookup table
     523             :    account AND all pubkeys in the lookup table to the dumped accounts
     524             :    set if they do not exist already. */
     525             : static void
     526             : add_lut_accounts_to_dumped_accounts( fd_accdb_t *                accdb,
     527             :                                      fd_accdb_fork_id_t          fork_id,
     528             :                                      fd_dump_account_key_set_t * dumped_accounts,
     529           0 :                                      fd_pubkey_t const *         pubkey ) {
     530             :   /* Add the current account to the dumped accounts set. */
     531           0 :   add_account_to_dumped_accounts( dumped_accounts, pubkey );
     532             : 
     533             :   /* Read the account and dump all pubkeys within the lookup table. */
     534           0 :   fd_acc_t lut_account = fd_accdb_read_one( accdb, fork_id, pubkey->uc );
     535           0 :   if( FD_UNLIKELY( !lut_account.lamports ) ) {
     536           0 :     fd_accdb_unread_one( accdb, &lut_account );
     537           0 :     return;
     538           0 :   }
     539             : 
     540             :   /* Decode the ALUT account and dump all pubkeys within the lookup
     541             :      table. */
     542           0 :   if( lut_account.data_len<FD_LOOKUP_TABLE_META_SIZE || (lut_account.data_len&0x1fUL) ) {
     543           0 :     fd_accdb_unread_one( accdb, &lut_account );
     544           0 :     return;
     545           0 :   }
     546             : 
     547             :   /* Copy the addresses out and release before nested acquires. */
     548           0 :   fd_pubkey_t lookup_addrs[ 256 ]; /* LOOKUP_TABLE_MAX_ADDRESSES */
     549           0 :   ulong       lookup_addrs_cnt = fd_ulong_min( (lut_account.data_len-FD_LOOKUP_TABLE_META_SIZE)>>5UL, 256UL );
     550           0 :   fd_memcpy( lookup_addrs, lut_account.data+FD_LOOKUP_TABLE_META_SIZE, lookup_addrs_cnt*sizeof(fd_pubkey_t) );
     551           0 :   fd_accdb_unread_one( accdb, &lut_account );
     552             : 
     553           0 :   for( ulong i=0UL; i<lookup_addrs_cnt; i++ ) {
     554           0 :     fd_pubkey_t const * referenced_pubkey = &lookup_addrs[i];
     555           0 :     add_account_and_programdata_to_dumped_accounts( accdb, fork_id, dumped_accounts, referenced_pubkey );
     556           0 :   }
     557           0 : }
     558             : 
     559             : static void
     560             : create_block_context_protobuf_from_block( fd_block_dump_ctx_t * dump_ctx,
     561             :                                           fd_banks_t *          banks,
     562             :                                           fd_bank_t *           bank,
     563             :                                           fd_accdb_t *          accdb,
     564           0 :                                           fd_runtime_stack_t *  runtime_stack ) {
     565             :   /* We should use the bank fields from the parent slot in order to
     566             :      capture the block context from before the current block was
     567             :      executed, since dumping is happening in the block finalize step. */
     568           0 :   fd_bank_t * parent_bank = fd_banks_get_parent( banks, bank );
     569           0 :   fd_exec_test_block_context_t * block_context  = &dump_ctx->block_context;
     570           0 :   ulong                          dump_txn_count = dump_ctx->txns_to_dump_cnt;
     571           0 :   fd_spad_t *                    spad           = dump_ctx->spad;
     572             : 
     573             :   /* Get vote and stake delegation infos */
     574           0 :   fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( parent_bank );
     575           0 :   ulong              fork_id     = parent_bank->vote_stakes_fork_id;
     576           0 :   ulong vote_account_t_1_cnt = fd_vote_stakes_cnt_t_1( vote_stakes, fork_id );
     577           0 :   ulong vote_account_t_2_cnt = fd_vote_stakes_cnt_t_2( vote_stakes, fork_id );
     578           0 :   uchar vote_stakes_iter_mem[ FD_VOTE_STAKES_ITER_FOOTPRINT ] __attribute__((aligned(FD_VOTE_STAKES_ITER_ALIGN)));
     579             : 
     580           0 :   ushort stake_delegations_fork_ids[ banks->max_total_banks ];
     581           0 :   ulong  stake_delegations_fork_id_cnt = fd_banks_stake_delegations_fork_ids( banks, parent_bank, stake_delegations_fork_ids );
     582           0 :   fd_stake_history_t   stake_delegations_history_[1];
     583           0 :   fd_stake_history_t * stake_delegations_history = fd_sysvar_cache_stake_history_view( &parent_bank->f.sysvar_cache, stake_delegations_history_ );
     584             : 
     585           0 :   fd_stake_delegations_t * stake_delegations = fd_bank_stake_delegations_modify( parent_bank );
     586           0 :   fd_stake_delegations_mark_fork_deltas( stake_delegations,
     587           0 :                                          parent_bank->f.epoch,
     588           0 :                                          stake_delegations_history,
     589           0 :                                          &parent_bank->f.warmup_cooldown_rate_epoch,
     590           0 :                                          FD_FEATURE_ACTIVE_BANK( parent_bank, upgrade_bpf_stake_program_to_v5_1 ),
     591           0 :                                          stake_delegations_fork_ids,
     592           0 :                                          stake_delegations_fork_id_cnt );
     593             : 
     594             :   /* Collect account states in a temporary set before iterating over
     595             :      them and dumping them out. */
     596           0 :   void *              dumped_accounts_mem = fd_spad_alloc( spad, fd_dump_account_key_map_align(), fd_dump_account_key_map_footprint() );
     597           0 :   fd_dump_account_t * dumped_accounts_map = fd_dump_account_key_map_join( fd_dump_account_key_map_new( dumped_accounts_mem ) );
     598           0 :   fd_dump_account_key_set_t   dumped_accounts[1] = {{ dumped_accounts_map, 0UL, 0 }};
     599             : 
     600             :   /* BlockContext -> txns */
     601           0 :   block_context->txns_count = (pb_size_t)dump_txn_count;
     602           0 :   block_context->txns       = fd_spad_alloc( spad, alignof(fd_exec_test_sanitized_transaction_t), dump_ctx->txns_to_dump_cnt * sizeof(fd_exec_test_sanitized_transaction_t) );
     603           0 :   fd_memset( block_context->txns, 0, dump_ctx->txns_to_dump_cnt * sizeof(fd_exec_test_sanitized_transaction_t) );
     604             : 
     605             :   /* Dump sanitized transactions from the transaction descriptors */
     606           0 :   for( ulong i=0UL; i<dump_ctx->txns_to_dump_cnt; i++ ) {
     607           0 :     fd_txn_p_t const * txn_ptr        = &dump_ctx->txns_to_dump[i];
     608           0 :     fd_txn_t const *   txn_descriptor = TXN( txn_ptr );
     609           0 :     dump_sanitized_transaction( accdb, parent_bank->accdb_fork_id, txn_descriptor, txn_ptr->payload, spad, &block_context->txns[i] );
     610             : 
     611             :     /* Dump account + alut + programdata accounts (if applicable).
     612             :        1. Dump the raw txn account keys
     613             :        2. Dump the ALUT accounts
     614             :        3. Dump all referenced accounts in the ALUTs
     615             :        4. Dump any executable accounts */
     616             : 
     617             :     // 1 + 4. Dump any account keys that are referenced by transactions
     618             :     // + any programdata accounts (if applicable).
     619           0 :     fd_acct_addr_t const * account_keys = fd_txn_get_acct_addrs( txn_descriptor, txn_ptr->payload );
     620           0 :     for( ushort l=0; l<txn_descriptor->acct_addr_cnt; l++ ) {
     621           0 :       fd_pubkey_t const * account_key = fd_type_pun_const( &account_keys[l] );
     622           0 :       add_account_and_programdata_to_dumped_accounts( accdb, parent_bank->accdb_fork_id, dumped_accounts, account_key );
     623           0 :     }
     624             : 
     625             :     // 2 + 3 + 4. Dump any ALUT accounts + any accounts referenced in
     626             :     // the ALUTs + any programdata accounts (if applicable).
     627           0 :     fd_txn_acct_addr_lut_t const * txn_lookup_tables = fd_txn_get_address_tables_const( txn_descriptor );
     628           0 :     for( ushort l=0; l<txn_descriptor->addr_table_lookup_cnt; l++ ) {
     629           0 :       fd_txn_acct_addr_lut_t const * lookup_table = &txn_lookup_tables[l];
     630           0 :       fd_pubkey_t const *            lut_key      = fd_type_pun_const( txn_ptr->payload+lookup_table->addr_off );
     631           0 :       add_lut_accounts_to_dumped_accounts( accdb, parent_bank->accdb_fork_id, dumped_accounts, lut_key );
     632           0 :     }
     633           0 :   }
     634             : 
     635             :   /* Dump sysvars */
     636           0 :   for( ulong i=0UL; i<num_sysvar_entries; i++ ) {
     637           0 :     add_account_to_dumped_accounts( dumped_accounts, fd_dump_sysvar_ids[i] );
     638           0 :   }
     639             : 
     640             :   /* Dump builtins */
     641           0 :   for( ulong i=0UL; i<num_loaded_builtins; i++ ) {
     642           0 :     add_account_to_dumped_accounts( dumped_accounts, fd_dump_builtin_ids[i] );
     643           0 :   }
     644             : 
     645             :   /* Dump stake accounts for this epoch */
     646           0 :   fd_stake_delegations_iter_t iter_[1];
     647           0 :   for( fd_stake_delegations_iter_t * iter = fd_stake_delegations_iter_init( iter_, stake_delegations, accdb, parent_bank->accdb_fork_id, parent_bank->f.epoch, &parent_bank->f.warmup_cooldown_rate_epoch );
     648           0 :        !fd_stake_delegations_iter_done( iter );
     649           0 :        fd_stake_delegations_iter_next( iter ) ) {
     650           0 :     fd_stake_delegation_t const * stake_delegation = fd_stake_delegations_iter_ele( iter );
     651           0 :     add_account_to_dumped_accounts( dumped_accounts, &stake_delegation->stake_account );
     652           0 :   }
     653           0 :   fd_stake_delegations_unmark_fork_deltas( stake_delegations,
     654           0 :                                            parent_bank->f.epoch-1UL,
     655           0 :                                            stake_delegations_history,
     656           0 :                                            &parent_bank->f.warmup_cooldown_rate_epoch,
     657           0 :                                            FD_FEATURE_ACTIVE_BANK( parent_bank, upgrade_bpf_stake_program_to_v5_1 ),
     658           0 :                                            stake_delegations_fork_ids,
     659           0 :                                            stake_delegations_fork_id_cnt );
     660             : 
     661             :   /* BlockBank -> vote_accounts_t_1 and vote_accounts_t_2 */
     662           0 :   fd_exec_test_prev_vote_account_t * va_t1 = fd_spad_alloc( spad,
     663           0 :       alignof(fd_exec_test_prev_vote_account_t),
     664           0 :       vote_account_t_1_cnt * sizeof(fd_exec_test_prev_vote_account_t) );
     665           0 :   fd_exec_test_prev_vote_account_t * va_t2 = fd_spad_alloc( spad,
     666           0 :       alignof(fd_exec_test_prev_vote_account_t),
     667           0 :       vote_account_t_2_cnt * sizeof(fd_exec_test_prev_vote_account_t) );
     668           0 :   pb_size_t va_t1_cnt = 0U;
     669           0 :   pb_size_t va_t2_cnt = 0U;
     670             : 
     671             :   /* SIMD-0232 collector overrides are tagged with the source epoch.
     672             :      Empty protobuf fields represent the vote/node defaults. */
     673           0 :   fd_collector_overrides_t * collector_overrides = fd_bank_collector_overrides( parent_bank );
     674           0 :   ushort co_fork_idx  = parent_bank->collector_overrides_fork_id;
     675           0 :   ulong  co_epoch_t_1 = parent_bank->f.epoch;
     676           0 :   ulong  co_epoch_t_2 = fd_ulong_sat_sub( parent_bank->f.epoch, 1UL );
     677             : 
     678           0 :   for( fd_vote_stakes_iter_t * iter = fd_vote_stakes_iter_init( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, vote_stakes_iter_mem );
     679           0 :        !fd_vote_stakes_iter_done( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, iter );
     680           0 :        fd_vote_stakes_iter_next( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, iter ) ) {
     681           0 :     fd_pubkey_t pubkey;
     682           0 :     ulong       stake;
     683           0 :     fd_pubkey_t node;
     684           0 :     ushort      commission;
     685           0 :     fd_vote_stakes_iter_ele( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_1, iter, &pubkey, &node, &stake,
     686           0 :                              NULL, NULL, &commission, NULL, NULL, NULL, NULL );
     687           0 :     add_account_to_dumped_accounts( dumped_accounts, &pubkey );
     688             : 
     689           0 :     fd_exec_test_prev_vote_account_t * acc = &va_t1[ va_t1_cnt++ ];
     690           0 :     fd_memcpy( acc->address,     &pubkey, sizeof(fd_pubkey_t) );
     691           0 :     fd_memcpy( acc->node_pubkey, &node,   sizeof(fd_pubkey_t) );
     692           0 :     acc->stake               = stake;
     693           0 :     acc->commission_bps      = commission;
     694           0 :     acc->version             = FD_EXEC_TEST_VOTE_ACCOUNT_VERSION_V4;
     695           0 :     acc->epoch_credits_count = 0U;
     696           0 :     acc->inflation_rewards_collector.size = 0U;
     697           0 :     acc->block_revenue_collector.size     = 0U;
     698             : 
     699           0 :     fd_pubkey_t inflation_collector;
     700           0 :     fd_pubkey_t block_collector;
     701           0 :     int co_flags = fd_collector_overrides_query( collector_overrides, co_fork_idx, co_epoch_t_1, &pubkey,
     702           0 :                                                  &inflation_collector, &block_collector );
     703           0 :     if( co_flags & FD_COLLECTOR_OVERRIDE_INFLATION ) {
     704           0 :       acc->inflation_rewards_collector.size = 32U;
     705           0 :       fd_memcpy( acc->inflation_rewards_collector.bytes, &inflation_collector, sizeof(fd_pubkey_t) );
     706           0 :     }
     707           0 :     if( co_flags & FD_COLLECTOR_OVERRIDE_BLOCK ) {
     708           0 :       acc->block_revenue_collector.size = 32U;
     709           0 :       fd_memcpy( acc->block_revenue_collector.bytes, &block_collector, sizeof(fd_pubkey_t) );
     710           0 :     }
     711           0 :   }
     712             : 
     713           0 :   for( fd_vote_stakes_iter_t * iter = fd_vote_stakes_iter_init( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, vote_stakes_iter_mem );
     714           0 :        !fd_vote_stakes_iter_done( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, iter );
     715           0 :        fd_vote_stakes_iter_next( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, iter ) ) {
     716           0 :     fd_pubkey_t pubkey;
     717           0 :     ulong       stake;
     718           0 :     fd_pubkey_t node;
     719           0 :     ushort      commission;
     720           0 :     fd_vote_stakes_iter_ele( vote_stakes, fork_id, FD_VOTE_STAKES_ITER_T_2, iter, &pubkey, &node, &stake,
     721           0 :                              NULL, NULL, &commission, NULL, NULL, NULL, NULL );
     722           0 :     add_account_to_dumped_accounts( dumped_accounts, &pubkey );
     723             : 
     724           0 :     fd_exec_test_prev_vote_account_t * acc = &va_t2[ va_t2_cnt++ ];
     725           0 :     fd_memcpy( acc->address,     &pubkey, sizeof(fd_pubkey_t) );
     726           0 :     fd_memcpy( acc->node_pubkey, &node,   sizeof(fd_pubkey_t) );
     727           0 :     acc->stake               = stake;
     728           0 :     acc->commission_bps      = commission;
     729           0 :     acc->version             = FD_EXEC_TEST_VOTE_ACCOUNT_VERSION_V4;
     730           0 :     acc->epoch_credits_count = 0U;
     731           0 :     acc->inflation_rewards_collector.size = 0U;
     732           0 :     acc->block_revenue_collector.size     = 0U;
     733             : 
     734           0 :     fd_pubkey_t inflation_collector;
     735           0 :     fd_pubkey_t block_collector;
     736           0 :     int co_flags = fd_collector_overrides_query( collector_overrides, co_fork_idx, co_epoch_t_2, &pubkey,
     737           0 :                                                  &inflation_collector, &block_collector );
     738           0 :     if( co_flags & FD_COLLECTOR_OVERRIDE_INFLATION ) {
     739           0 :       acc->inflation_rewards_collector.size = 32U;
     740           0 :       fd_memcpy( acc->inflation_rewards_collector.bytes, &inflation_collector, sizeof(fd_pubkey_t) );
     741           0 :     }
     742           0 :     if( co_flags & FD_COLLECTOR_OVERRIDE_BLOCK ) {
     743           0 :       acc->block_revenue_collector.size = 32U;
     744           0 :       fd_memcpy( acc->block_revenue_collector.bytes, &block_collector, sizeof(fd_pubkey_t) );
     745           0 :     }
     746           0 :   }
     747             : 
     748             :   /* Dump epoch_credits from runtime_stack->stakes.vote_ele if the
     749             :      vote_ele_map has been populated (happens after epoch boundary
     750             :      reward calculation).  Needed for the harness to correctly
     751             :      recalculate partitioned epoch rewards. */
     752           0 :   fd_vote_rewards_map_t * vote_ele_map = runtime_stack->stakes.vote_map;
     753           0 :   for( pb_size_t i=0U; i<va_t1_cnt; i++ ) {
     754           0 :     fd_pubkey_t va_pubkey = FD_LOAD( fd_pubkey_t, va_t1[i].address );
     755           0 :     uint idx = (uint)fd_vote_rewards_map_idx_query( vote_ele_map, &va_pubkey, UINT_MAX, runtime_stack->stakes.vote_ele );
     756           0 :     if( idx==UINT_MAX ) continue;
     757           0 :     fd_epoch_credits_t const * ec = &fd_bank_epoch_credits( parent_bank )[idx];
     758           0 :     ulong cnt  = ec->cnt;
     759           0 :     ulong base = ec->base_credits;
     760           0 :     va_t1[i].epoch_credits_count = (pb_size_t)cnt;
     761           0 :     va_t1[i].epoch_credits = fd_spad_alloc( spad, alignof(fd_exec_test_epoch_credit_t), cnt * sizeof(fd_exec_test_epoch_credit_t) );
     762           0 :     for( ulong j=0; j<cnt; j++ ) {
     763           0 :       va_t1[i].epoch_credits[j].epoch        = ec->epoch[j];
     764           0 :       va_t1[i].epoch_credits[j].credits      = base + ec->credits_delta[j];
     765           0 :       va_t1[i].epoch_credits[j].prev_credits = base + ec->prev_credits_delta[j];
     766           0 :     }
     767           0 :   }
     768             : 
     769             :   /* BlockContext -> acct_states
     770             :      Iterate over the set and dump all the account keys in one pass. */
     771           0 :   block_context->acct_states_count = 0U;
     772           0 :   block_context->acct_states       = fd_spad_alloc(
     773           0 :       spad,
     774           0 :       alignof(fd_exec_test_acct_state_t),
     775           0 :       dumped_accounts->cnt*sizeof(fd_exec_test_acct_state_t) );
     776           0 :   fd_dump_account_key_iter_t dumped_accounts_iter_[1];
     777           0 :   for( fd_dump_account_key_iter_t * iter = fd_dump_account_key_iter_init( dumped_accounts_iter_, dumped_accounts );
     778           0 :        !fd_dump_account_key_iter_done( iter );
     779           0 :        fd_dump_account_key_iter_next( iter ) ) {
     780           0 :     fd_pubkey_t const * pubkey = fd_dump_account_key_iter_ele( iter );
     781           0 :     fd_acc_t acc = fd_accdb_read_one( accdb, parent_bank->accdb_fork_id, pubkey->uc );
     782           0 :     if( FD_UNLIKELY( !acc.lamports ) ) {
     783           0 :       fd_accdb_unread_one( accdb, &acc );
     784           0 :       continue;
     785           0 :     }
     786           0 :     dump_account_state(
     787           0 :         &acc,
     788           0 :         &block_context->acct_states[block_context->acct_states_count++],
     789           0 :         spad );
     790           0 :     fd_accdb_unread_one( accdb, &acc );
     791           0 :   }
     792             : 
     793             :   /* BlockContext -> bank */
     794           0 :   block_context->has_bank = true;
     795           0 :   fd_exec_test_block_bank_t * block_bank = &block_context->bank;
     796             : 
     797             :   /* BlockBank -> blockhash_queue */
     798           0 :   dump_blockhash_queue( parent_bank, spad, &block_bank->blockhash_queue, &block_bank->blockhash_queue_count );
     799             : 
     800             :   /* BlockBank -> rbh_lamports_per_signature */
     801           0 :   block_bank->rbh_lamports_per_signature = (uint)parent_bank->f.rbh_lamports_per_sig;
     802             : 
     803             :   /* BlockBank -> fee_rate_governor */
     804           0 :   block_bank->has_fee_rate_governor = true;
     805           0 :   dump_fee_rate_governor( parent_bank, &block_bank->fee_rate_governor );
     806             : 
     807             :   /* BlockBank -> slot */
     808           0 :   block_bank->slot = bank->f.slot;
     809             : 
     810             :   /* BlockBank -> parent_slot */
     811           0 :   block_bank->parent_slot = bank->f.parent_slot;
     812             : 
     813             :   /* BlockBank -> capitalization */
     814           0 :   block_bank->capitalization = parent_bank->f.capitalization;
     815             : 
     816             :   /* BlockBank -> ns_per_slot */
     817           0 :   fd_w_u128_t ns_per_slot = { .ud = bank->f.slot_params.ns_per_slot };
     818           0 :   fd_memcpy( block_bank->ns_per_slot, &ns_per_slot.ud, sizeof(uint128) );
     819             : 
     820             :   /* BlockBank -> inflation */
     821           0 :   block_bank->has_inflation = true;
     822           0 :   fd_inflation_t const * inflation = &parent_bank->f.inflation;
     823           0 :   block_bank->inflation = (fd_exec_test_inflation_t){
     824           0 :     .initial         = inflation->initial,
     825           0 :     .terminal        = inflation->terminal,
     826           0 :     .taper           = inflation->taper,
     827           0 :     .foundation      = inflation->foundation,
     828           0 :     .foundation_term = inflation->foundation_term,
     829           0 :   };
     830             : 
     831             :   /* BlockBank -> block_height */
     832           0 :   block_bank->block_height = bank->f.block_height;
     833             : 
     834             :   /* BlockBank -> poh */
     835           0 :   fd_memcpy( block_bank->poh, &bank->f.poh, sizeof(fd_hash_t) );
     836             : 
     837             :   /* BlockBank -> parent_bank_hash */
     838           0 :   fd_memcpy( block_bank->parent_bank_hash, &parent_bank->f.bank_hash, sizeof(fd_hash_t) );
     839             : 
     840             :   /* BlockBank -> parent_lt_hash */
     841           0 :   fd_lthash_value_t const * parent_lthash = fd_bank_lthash_locking_query( parent_bank );
     842           0 :   fd_memcpy( block_bank->parent_lt_hash, parent_lthash, sizeof(fd_lthash_value_t) );
     843           0 :   fd_bank_lthash_end_locking_query( parent_bank );
     844             : 
     845             :   /* BlockBank -> parent_signature_count */
     846           0 :   block_bank->parent_signature_count = parent_bank->f.parent_signature_cnt;
     847             : 
     848             :   /* BlockBank -> features */
     849           0 :   block_bank->has_features = true;
     850           0 :   dump_sorted_features( &parent_bank->f.features, &block_bank->features, spad );
     851             : 
     852             :   /* BlockBank -> vote_accounts_t_1 / vote_accounts_t_2 */
     853           0 :   block_bank->vote_accounts_t_1       = va_t1;
     854           0 :   block_bank->vote_accounts_t_1_count = va_t1_cnt;
     855           0 :   block_bank->vote_accounts_t_2       = va_t2;
     856           0 :   block_bank->vote_accounts_t_2_count = va_t2_cnt;
     857           0 : }
     858             : 
     859             : static void
     860             : create_txn_context_protobuf_from_txn( fd_exec_test_txn_context_t * txn_context_msg,
     861             :                                       fd_runtime_t *               runtime,
     862             :                                       fd_bank_t *                  bank,
     863             :                                       fd_txn_in_t const *          txn_in,
     864             :                                       fd_txn_out_t *               txn_out,
     865           0 :                                       fd_spad_t *                  spad ) {
     866           0 :   fd_txn_t const * txn_descriptor = TXN( txn_in->txn );
     867           0 :   uchar const *    txn_payload    = (uchar const *) txn_in->txn->payload;
     868           0 :   (void)txn_out;
     869             : 
     870             :   /* Transaction Context -> account_shared_data
     871             :      Contains:
     872             :       - Account data for regular accounts
     873             :       - Account data for LUT accounts
     874             :       - Account data for executable accounts
     875             :       - Account data for (almost) all sysvars */
     876           0 :   txn_context_msg->account_shared_data_count = 0;
     877           0 :   txn_context_msg->account_shared_data = fd_spad_alloc( spad,
     878           0 :                                                         alignof(fd_exec_test_acct_state_t),
     879           0 :                                                         (256UL*2UL + txn_descriptor->addr_table_lookup_cnt + num_sysvar_entries) * sizeof(fd_exec_test_acct_state_t) );
     880             : 
     881             :   /* Dump regular accounts first */
     882           0 :   fd_acct_addr_t const * account_keys = fd_txn_get_acct_addrs( txn_descriptor, txn_payload );
     883           0 :   for( ushort i=0; i<txn_descriptor->acct_addr_cnt; i++ ) {
     884           0 :     dump_account_if_not_already_dumped(
     885           0 :       runtime->accdb,
     886           0 :       bank->accdb_fork_id,
     887           0 :       fd_type_pun_const( &account_keys[i] ),
     888           0 :       spad,
     889           0 :       txn_context_msg->account_shared_data,
     890           0 :       &txn_context_msg->account_shared_data_count,
     891           0 :       NULL
     892           0 :     );
     893           0 :   }
     894             : 
     895             :   // Dump LUT accounts
     896           0 :   fd_txn_acct_addr_lut_t const * address_lookup_tables = fd_txn_get_address_tables_const( txn_descriptor );
     897           0 :   for( ulong i = 0; i < txn_descriptor->addr_table_lookup_cnt; ++i ) {
     898           0 :     fd_txn_acct_addr_lut_t const * addr_lut  = &address_lookup_tables[i];
     899           0 :     fd_pubkey_t * alut_key = (fd_pubkey_t *) (txn_payload + addr_lut->addr_off);
     900             : 
     901             :     // Dump the LUT account itself if not already dumped
     902           0 :     fd_acc_t acc;
     903           0 :     int ret = dump_account_if_not_already_dumped(
     904           0 :         runtime->accdb,
     905           0 :         bank->accdb_fork_id,
     906           0 :         alut_key,
     907           0 :         spad,
     908           0 :         txn_context_msg->account_shared_data,
     909           0 :         &txn_context_msg->account_shared_data_count,
     910           0 :         &acc
     911           0 :     );
     912           0 :     if( FD_UNLIKELY( ret ) ) continue;
     913             : 
     914           0 :     if( FD_UNLIKELY( acc.data_len < FD_LOOKUP_TABLE_META_SIZE ) ) {
     915             :       /* Skip over invalid address lookup tables */
     916           0 :       fd_accdb_unread_one( runtime->accdb, &acc );
     917           0 :       continue;
     918           0 :     }
     919             : 
     920             :     /* Copy the addresses out and release before nested acquires. */
     921           0 :     fd_pubkey_t lookup_addrs[ 256 ]; /* LOOKUP_TABLE_MAX_ADDRESSES */
     922           0 :     ulong       lookup_addrs_cnt = fd_ulong_min( (acc.data_len - FD_LOOKUP_TABLE_META_SIZE) / sizeof(fd_pubkey_t), 256UL );
     923           0 :     fd_memcpy( lookup_addrs, acc.data + FD_LOOKUP_TABLE_META_SIZE, lookup_addrs_cnt*sizeof(fd_pubkey_t) );
     924           0 :     fd_accdb_unread_one( runtime->accdb, &acc );
     925             : 
     926             :     /* Dump any account state referenced in ALUTs */
     927           0 :     uchar const * writable_lut_idxs = txn_payload + addr_lut->writable_off;
     928           0 :     for( ulong j=0; j<addr_lut->writable_cnt; j++ ) {
     929           0 :       if( writable_lut_idxs[j] >= lookup_addrs_cnt ) {
     930           0 :         continue;
     931           0 :       }
     932           0 :       fd_pubkey_t const * referenced_addr = lookup_addrs + writable_lut_idxs[j];
     933           0 :       dump_account_if_not_already_dumped(
     934           0 :           runtime->accdb,
     935           0 :           bank->accdb_fork_id,
     936           0 :           referenced_addr,
     937           0 :           spad,
     938           0 :           txn_context_msg->account_shared_data,
     939           0 :           &txn_context_msg->account_shared_data_count,
     940           0 :           NULL
     941           0 :       );
     942           0 :     }
     943             : 
     944           0 :     uchar const * readonly_lut_idxs = txn_payload + addr_lut->readonly_off;
     945           0 :     for( ulong j = 0; j < addr_lut->readonly_cnt; j++ ) {
     946           0 :       if( readonly_lut_idxs[j] >= lookup_addrs_cnt ) {
     947           0 :         continue;
     948           0 :       }
     949           0 :       fd_pubkey_t const * referenced_addr = lookup_addrs + readonly_lut_idxs[j];
     950           0 :       dump_account_if_not_already_dumped(
     951           0 :           runtime->accdb,
     952           0 :           bank->accdb_fork_id,
     953           0 :           referenced_addr,
     954           0 :           spad,
     955           0 :           txn_context_msg->account_shared_data,
     956           0 :           &txn_context_msg->account_shared_data_count,
     957           0 :           NULL
     958           0 :       );
     959           0 :     }
     960           0 :   }
     961             : 
     962             :   /* Dump the programdata accounts for any potential v3-owned program accounts */
     963           0 :   uint accounts_dumped_so_far = txn_context_msg->account_shared_data_count;
     964           0 :   for( uint i=0U; i<accounts_dumped_so_far; i++ ) {
     965           0 :     fd_exec_test_acct_state_t const * maybe_program_account = &txn_context_msg->account_shared_data[i];
     966           0 :     dump_executable_account_if_exists( runtime->accdb, bank->accdb_fork_id, maybe_program_account, spad, txn_context_msg->account_shared_data, &txn_context_msg->account_shared_data_count );
     967           0 :   }
     968             : 
     969             :   /* Dump sysvars */
     970           0 :   for( ulong i = 0; i < num_sysvar_entries; i++ ) {
     971           0 :     dump_account_if_not_already_dumped(
     972           0 :         runtime->accdb,
     973           0 :         bank->accdb_fork_id,
     974           0 :         fd_dump_sysvar_ids[i],
     975           0 :         spad,
     976           0 :         txn_context_msg->account_shared_data,
     977           0 :         &txn_context_msg->account_shared_data_count,
     978           0 :         NULL
     979           0 :     );
     980           0 :   }
     981             : 
     982             :   /* Transaction Context -> tx */
     983           0 :   txn_context_msg->has_tx = true;
     984           0 :   fd_exec_test_sanitized_transaction_t * sanitized_transaction = &txn_context_msg->tx;
     985           0 :   dump_sanitized_transaction( runtime->accdb, bank->accdb_fork_id, txn_descriptor, txn_payload, spad, sanitized_transaction );
     986             : 
     987             :   /* Transaction Context -> bank */
     988           0 :   dump_txn_bank( bank, spad, txn_context_msg );
     989           0 : }
     990             : 
     991             : static void
     992             : create_instr_context_protobuf_from_instructions( fd_exec_test_instr_context_t * instr_context,
     993             :                                                  fd_runtime_t *                 runtime,
     994             :                                                  fd_bank_t *                    bank,
     995             :                                                  fd_txn_out_t *                 txn_out,
     996             :                                                  fd_instr_info_t const *        instr,
     997           0 :                                                  fd_spad_t *                    spad ) {
     998             :   /* Program ID */
     999           0 :   fd_memcpy( instr_context->program_id, txn_out->accounts.keys[ instr->program_id ].uc, sizeof(fd_pubkey_t) );
    1000             : 
    1001             :   /* Accounts */
    1002           0 :   instr_context->accounts_count = (pb_size_t) txn_out->accounts.cnt;
    1003           0 :   instr_context->accounts = fd_spad_alloc( spad, alignof(fd_exec_test_acct_state_t), (instr_context->accounts_count + num_sysvar_entries + txn_out->accounts.executable_cnt) * sizeof(fd_exec_test_acct_state_t));
    1004           0 :   for( ulong i = 0; i < txn_out->accounts.cnt; i++ ) {
    1005             :     // Copy account information over
    1006           0 :     fd_exec_test_acct_state_t * output_account = &instr_context->accounts[i];
    1007           0 :     dump_account_state( txn_out->accounts.account[ i ], output_account, spad );
    1008           0 :   }
    1009             : 
    1010             :   /* Add sysvar cache variables */
    1011           0 :   uchar * sysvar_data = fd_spad_alloc( spad, 1UL, FD_RUNTIME_ACC_SZ_MAX );
    1012           0 :   for( ulong i = 0; i < num_sysvar_entries; i++ ) {
    1013           0 :     if( account_already_dumped( instr_context->accounts, instr_context->accounts_count, fd_dump_sysvar_ids[i] ) ) continue;
    1014             : 
    1015           0 :     fd_acc_t acc = {0};
    1016           0 :     fd_memcpy( acc.pubkey, fd_dump_sysvar_ids[i]->uc, sizeof(fd_pubkey_t) );
    1017           0 :     acc.data = sysvar_data;
    1018           0 :     fd_accdb_read_one_nocache(
    1019           0 :       runtime->accdb,
    1020           0 :       bank->accdb_fork_id,
    1021           0 :       fd_dump_sysvar_ids[i]->uc,
    1022           0 :       &acc.lamports,
    1023           0 :       &acc.executable,
    1024           0 :       acc.owner,
    1025           0 :       acc.data,
    1026           0 :       &acc.data_len
    1027           0 :     );
    1028           0 :     if( FD_UNLIKELY( !acc.lamports ) ) continue;
    1029             : 
    1030           0 :     fd_exec_test_acct_state_t * output_account = &instr_context->accounts[instr_context->accounts_count++];
    1031           0 :     dump_account_state( &acc, output_account, spad );
    1032           0 :   }
    1033             : 
    1034             :   /* Add executable accounts */
    1035           0 :   for( ulong i = 0; i < txn_out->accounts.executable_cnt; i++ ) {
    1036             :     // Make sure the account doesn't exist in the output accounts yet
    1037           0 :     fd_acc_t const * ro = txn_out->accounts.executable[i];
    1038           0 :     bool account_exists = false;
    1039           0 :     for( ulong j = 0; j < instr_context->accounts_count; j++ ) {
    1040           0 :       if( 0 == memcmp( instr_context->accounts[j].address, ro->pubkey, sizeof(fd_pubkey_t) ) ) {
    1041           0 :         account_exists = true;
    1042           0 :         break;
    1043           0 :       }
    1044           0 :     }
    1045             :     // Copy it into output
    1046           0 :     if( !account_exists ) {
    1047           0 :       fd_exec_test_acct_state_t * output_account = &instr_context->accounts[instr_context->accounts_count++];
    1048           0 :       dump_account_state( ro, output_account, spad );
    1049           0 :     }
    1050           0 :   }
    1051             : 
    1052             :   /* Instruction Accounts */
    1053           0 :   instr_context->instr_accounts_count = (pb_size_t) instr->acct_cnt;
    1054           0 :   instr_context->instr_accounts = fd_spad_alloc( spad, alignof(fd_exec_test_instr_acct_t), instr_context->instr_accounts_count * sizeof(fd_exec_test_instr_acct_t) );
    1055           0 :   for( ushort i = 0; i < instr->acct_cnt; i++ ) {
    1056           0 :     fd_exec_test_instr_acct_t * output_instr_account = &instr_context->instr_accounts[i];
    1057             : 
    1058           0 :     output_instr_account->index       = instr->accounts[i].index_in_transaction;
    1059           0 :     output_instr_account->is_writable = instr->accounts[i].is_writable;
    1060           0 :     output_instr_account->is_signer   = instr->accounts[i].is_signer;
    1061           0 :   }
    1062             : 
    1063             :   /* Data */
    1064           0 :   instr_context->data = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE( instr->data_sz ) );
    1065           0 :   instr_context->data->size = (pb_size_t) instr->data_sz;
    1066           0 :   fd_memcpy( instr_context->data->bytes, instr->data, instr->data_sz );
    1067             : 
    1068             :   /* Compute Units */
    1069           0 :   instr_context->cu_avail = txn_out->details.compute_budget.compute_meter;
    1070             : 
    1071             :   /* Feature set */
    1072           0 :   instr_context->has_features = true;
    1073           0 :   dump_sorted_features( &bank->f.features, &instr_context->features, spad );
    1074           0 : }
    1075             : 
    1076             : /***** PUBLIC APIs *****/
    1077             : 
    1078             : void
    1079             : fd_dump_instr_to_protobuf( fd_runtime_t *      runtime,
    1080             :                            fd_bank_t *         bank,
    1081             :                            fd_txn_in_t const * txn_in,
    1082             :                            fd_txn_out_t *      txn_out,
    1083             :                            fd_instr_info_t *   instr,
    1084           0 :                            ushort              instruction_idx ) {
    1085             :   /* Check program ID filter, if it exists */
    1086           0 :   if( runtime->log.dump_proto_ctx->has_dump_instr_program_id_filter &&
    1087           0 :       memcmp( txn_out->accounts.keys[ instr->program_id ].uc, runtime->log.dump_proto_ctx->dump_instr_program_id_filter, sizeof(fd_pubkey_t) ) ) {
    1088           0 :     return;
    1089           0 :   }
    1090             : 
    1091           0 :   fd_spad_t * spad = fd_spad_join( fd_spad_new( runtime->log.dumping_mem, 1UL<<28UL ) );
    1092             : 
    1093           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
    1094             :     // Get base58-encoded tx signature
    1095           0 :     const fd_ed25519_sig_t * signatures = fd_txn_get_signatures( TXN( txn_in->txn ), txn_in->txn->payload );
    1096           0 :     char encoded_signature[FD_BASE58_ENCODED_64_SZ];
    1097           0 :     fd_base58_encode_64( signatures[0], NULL, encoded_signature );
    1098             : 
    1099           0 :     fd_exec_test_instr_context_t instr_context = FD_EXEC_TEST_INSTR_CONTEXT_INIT_DEFAULT;
    1100           0 :     create_instr_context_protobuf_from_instructions( &instr_context, runtime, bank, txn_out, instr, spad );
    1101             : 
    1102             :     /* Output to file */
    1103           0 :     ulong        out_buf_size = 100 * 1024 * 1024;
    1104           0 :     uint8_t *    out          = fd_spad_alloc( spad, alignof(uchar) , out_buf_size );
    1105           0 :     pb_ostream_t stream       = pb_ostream_from_buffer( out, out_buf_size );
    1106           0 :     if (pb_encode(&stream, FD_EXEC_TEST_INSTR_CONTEXT_FIELDS, &instr_context)) {
    1107           0 :       char output_filepath[ PATH_MAX ];
    1108           0 :       snprintf( output_filepath, PATH_MAX, "%s/instr-%s-%hu.instrctx", runtime->log.dump_proto_ctx->dump_proto_output_dir, encoded_signature, instruction_idx );
    1109           0 :       FILE * file = fopen(output_filepath, "wb");
    1110           0 :       if( file ) {
    1111           0 :         fwrite( out, 1, stream.bytes_written, file );
    1112           0 :         fclose( file );
    1113           0 :       }
    1114           0 :     }
    1115           0 :   } FD_SPAD_FRAME_END;
    1116           0 : }
    1117             : 
    1118             : /* Writes a single account state into the resulting_state field of a
    1119             :    TxnResult protobuf.  Sub-allocations for account data are bump-
    1120             :    allocated from the caller's scratch region via _l. */
    1121             : static void
    1122             : write_account_to_result( fd_acc_t const *            acc,
    1123             :                          fd_exec_test_acct_state_t * out_accounts,
    1124             :                          pb_size_t *                 out_accounts_cnt,
    1125             :                          ulong *                     scratch_cur,
    1126           0 :                          ulong                       scratch_end ) {
    1127           0 :   fd_exec_test_acct_state_t * out_acct = &out_accounts[ *out_accounts_cnt ];
    1128           0 :   (*out_accounts_cnt)++;
    1129             : 
    1130           0 :   memset( out_acct, 0, sizeof(fd_exec_test_acct_state_t) );
    1131           0 :   memcpy( out_acct->address, acc->pubkey, sizeof(fd_pubkey_t) );
    1132           0 :   out_acct->lamports = acc->lamports;
    1133             : 
    1134           0 :   fd_solfuzz_acct_set_data_hash( out_acct, acc->data, acc->data_len );
    1135           0 :   (void)scratch_cur; (void)scratch_end;
    1136             : 
    1137           0 :   out_acct->executable = acc->executable;
    1138           0 :   memcpy( out_acct->owner, acc->owner, sizeof(fd_pubkey_t) );
    1139           0 : }
    1140             : 
    1141             : static void
    1142             : write_account_to_result1( uchar const *               pubkey,
    1143             :                           ulong                       lamports,
    1144             :                           uchar const *               owner,
    1145             :                           ulong                       data_len,
    1146             :                           uchar const *               _data,
    1147             :                           int                         executable,
    1148             :                           fd_exec_test_acct_state_t * out_accounts,
    1149             :                           pb_size_t *                 out_accounts_cnt,
    1150             :                           ulong *                     scratch_cur,
    1151           0 :                           ulong                       scratch_end ) {
    1152           0 :   fd_exec_test_acct_state_t * out_acct = &out_accounts[ *out_accounts_cnt ];
    1153           0 :   (*out_accounts_cnt)++;
    1154             : 
    1155           0 :   memset( out_acct, 0, sizeof(fd_exec_test_acct_state_t) );
    1156           0 :   memcpy( out_acct->address, pubkey, sizeof(fd_pubkey_t) );
    1157           0 :   out_acct->lamports = lamports;
    1158             : 
    1159           0 :   fd_solfuzz_acct_set_data_hash( out_acct, _data, data_len );
    1160           0 :   (void)scratch_cur; (void)scratch_end;
    1161             : 
    1162           0 :   out_acct->executable = executable;
    1163           0 :   memcpy( out_acct->owner, owner, sizeof(fd_pubkey_t) );
    1164           0 : }
    1165             : 
    1166             : ulong
    1167             : create_txn_result_protobuf_from_txn( fd_exec_test_txn_result_t ** txn_result_out,
    1168             :                                      void *                       out_buf,
    1169             :                                      ulong                        out_bufsz,
    1170             :                                      fd_txn_in_t const *          txn_in,
    1171             :                                      fd_txn_out_t *               txn_out,
    1172           0 :                                      int                          exec_res ) {
    1173           0 :   FD_SCRATCH_ALLOC_INIT( l, out_buf );
    1174           0 :   ulong out_end = (ulong)out_buf + out_bufsz;
    1175             : 
    1176           0 :   fd_exec_test_txn_result_t * txn_result =
    1177           0 :     FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_txn_result_t),
    1178           0 :                                 sizeof(fd_exec_test_txn_result_t) );
    1179           0 :   if( FD_UNLIKELY( _l > out_end ) ) abort();
    1180           0 :   fd_memset( txn_result, 0, sizeof(fd_exec_test_txn_result_t) );
    1181             : 
    1182             :   /* Map nonce errors into the agave expected ones. */
    1183           0 :   if( FD_UNLIKELY( exec_res==FD_RUNTIME_TXN_ERR_BLOCKHASH_NONCE_ALREADY_ADVANCED ||
    1184           0 :                    exec_res==FD_RUNTIME_TXN_ERR_BLOCKHASH_FAIL_ADVANCE_NONCE_INSTR ||
    1185           0 :                    exec_res==FD_RUNTIME_TXN_ERR_BLOCKHASH_FAIL_WRONG_NONCE )) {
    1186           0 :     exec_res = FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND;
    1187           0 :   }
    1188             : 
    1189             :   /* Basic result fields */
    1190           0 :   txn_result->executed                  = txn_out->err.is_committable;
    1191           0 :   txn_result->modified_accounts_count   = 0;
    1192           0 :   txn_result->rollback_accounts_count   = 0;
    1193           0 :   txn_result->txn_error                 = (uint32_t) -exec_res;
    1194           0 :   txn_result->instruction_error         = 0;
    1195           0 :   txn_result->instruction_error_index   = 0;
    1196           0 :   txn_result->custom_error              = 0;
    1197           0 :   txn_result->has_fee_details           = false;
    1198           0 :   txn_result->loaded_accounts_data_size = txn_out->details.loaded_accounts_data_size;
    1199             : 
    1200           0 :   if( !txn_out->err.is_committable ) {
    1201           0 :     if( txn_out->err.is_fees_only ) {
    1202           0 :       txn_result->has_fee_details                = true;
    1203           0 :       txn_result->fee_details.prioritization_fee = txn_out->details.priority_fee;
    1204           0 :       txn_result->fee_details.transaction_fee    = txn_out->details.execution_fee;
    1205           0 :     }
    1206             : 
    1207           0 :     if( exec_res==FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ) {
    1208           0 :       txn_result->instruction_error       = (uint32_t) -txn_out->err.exec_err;
    1209           0 :       txn_result->instruction_error_index = txn_out->err.exec_err_idx;
    1210           0 :       if( txn_out->err.exec_err==FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR ) {
    1211           0 :         txn_result->custom_error = txn_out->err.custom_err;
    1212           0 :       }
    1213           0 :     }
    1214             : 
    1215           0 :     *txn_result_out = txn_result;
    1216           0 :     return FD_SCRATCH_ALLOC_FINI( l, 1UL ) - (ulong)out_buf;
    1217           0 :   }
    1218             : 
    1219             :   /* Capture instruction error code for executed transactions */
    1220           0 :   if( exec_res==FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ) {
    1221           0 :     fd_txn_t const * txn            = TXN( txn_in->txn );
    1222           0 :     uint             instr_err_idx  = txn_out->err.exec_err_idx;
    1223           0 :     int              program_id_idx = txn->instr[instr_err_idx].program_id;
    1224             : 
    1225           0 :     txn_result->instruction_error       = (uint32_t) -txn_out->err.exec_err;
    1226           0 :     txn_result->instruction_error_index = instr_err_idx;
    1227             : 
    1228           0 :     if( txn_out->err.exec_err==FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR &&
    1229           0 :         fd_executor_lookup_native_precompile_program( &txn_out->accounts.keys[ program_id_idx ] )==NULL ) {
    1230           0 :       txn_result->custom_error = txn_out->err.custom_err;
    1231           0 :     }
    1232           0 :   }
    1233             : 
    1234           0 :   txn_result->has_fee_details                = true;
    1235           0 :   txn_result->fee_details.transaction_fee    = txn_out->details.execution_fee;
    1236           0 :   txn_result->fee_details.prioritization_fee = txn_out->details.priority_fee;
    1237           0 :   txn_result->executed_units                 = txn_out->details.compute_budget.compute_unit_limit - txn_out->details.compute_budget.compute_meter;
    1238             : 
    1239             :   /* Return data */
    1240           0 :   txn_result->return_data_hash = fd_solfuzz_hash( txn_out->details.return_data.data, txn_out->details.return_data.len );
    1241             : 
    1242             :   /* Modified accounts */
    1243           0 :   txn_result->modified_accounts = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_acct_state_t), sizeof(fd_exec_test_acct_state_t) * txn_out->accounts.cnt );
    1244           0 :   txn_result->rollback_accounts = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_acct_state_t), sizeof(fd_exec_test_acct_state_t) * 2UL );
    1245           0 :   if( FD_UNLIKELY( _l > out_end ) ) abort();
    1246             : 
    1247           0 :   if( ( txn_out->err.is_fees_only || exec_res!=FD_RUNTIME_EXECUTE_SUCCESS ) && !txn_out->err.is_noop ) {
    1248             :     /* If the transaction errored, capture the rollback accounts (fee payer and nonce). */
    1249           0 :     if( FD_LIKELY( txn_out->accounts.nonce_idx_in_txn!=FD_FEE_PAYER_TXN_IDX ) ) {
    1250           0 :       write_account_to_result1(
    1251           0 :         txn_out->accounts.keys[FD_FEE_PAYER_TXN_IDX].uc,
    1252           0 :         txn_out->accounts.fee_payer_rollback_lamports,
    1253           0 :         txn_out->accounts.account[ FD_FEE_PAYER_TXN_IDX ]->prior_owner,
    1254           0 :         txn_out->accounts.account[ FD_FEE_PAYER_TXN_IDX ]->prior_data_len,
    1255           0 :         txn_out->accounts.account[ FD_FEE_PAYER_TXN_IDX ]->prior_data,
    1256           0 :         txn_out->accounts.account[ FD_FEE_PAYER_TXN_IDX ]->prior_executable,
    1257           0 :         txn_result->rollback_accounts,
    1258           0 :         &txn_result->rollback_accounts_count,
    1259           0 :         &_l,
    1260           0 :         out_end
    1261           0 :       );
    1262           0 :     }
    1263             : 
    1264           0 :     if( txn_out->accounts.nonce_idx_in_txn!=ULONG_MAX ) {
    1265             :       /* When the nonce account is also the fee payer, the rollback must
    1266             :          reflect the fee debit (the fee is still charged on a failed
    1267             :          nonce txn).  prior_lamports is the pre-fee balance, so use the
    1268             :          post-fee fee_payer_rollback_lamports for that account instead. */
    1269           0 :       ulong nonce_rollback_lamports =
    1270           0 :         ( txn_out->accounts.nonce_idx_in_txn==FD_FEE_PAYER_TXN_IDX )
    1271           0 :           ? txn_out->accounts.fee_payer_rollback_lamports
    1272           0 :           : txn_out->accounts.account[ txn_out->accounts.nonce_idx_in_txn ]->prior_lamports;
    1273           0 :       write_account_to_result1(
    1274           0 :         txn_out->accounts.keys[txn_out->accounts.nonce_idx_in_txn].uc,
    1275           0 :         nonce_rollback_lamports,
    1276           0 :         txn_out->accounts.account[ txn_out->accounts.nonce_idx_in_txn ]->prior_owner,
    1277           0 :         txn_out->accounts.nonce_rollback_data_len,
    1278           0 :         txn_out->accounts.nonce_rollback_data,
    1279           0 :         txn_out->accounts.account[ txn_out->accounts.nonce_idx_in_txn ]->prior_executable,
    1280           0 :         txn_result->rollback_accounts,
    1281           0 :         &txn_result->rollback_accounts_count,
    1282           0 :         &_l,
    1283           0 :         out_end
    1284           0 :       );
    1285           0 :     }
    1286           0 :   }
    1287             : 
    1288           0 :   if( !txn_out->err.is_fees_only && !txn_out->err.is_noop ) {
    1289             :     /* Executed: writable accounts. */
    1290           0 :     for( ulong j=0UL; j<txn_out->accounts.cnt; j++ ) {
    1291           0 :       if( !fd_runtime_account_is_writable_idx( txn_in, txn_out, (ushort)j ) ) {
    1292           0 :         continue;
    1293           0 :       }
    1294             : 
    1295           0 :       write_account_to_result(
    1296           0 :         txn_out->accounts.account[j],
    1297           0 :         txn_result->modified_accounts,
    1298           0 :         &txn_result->modified_accounts_count,
    1299           0 :         &_l,
    1300           0 :         out_end
    1301           0 :       );
    1302           0 :     }
    1303           0 :   }
    1304             : 
    1305           0 :   *txn_result_out = txn_result;
    1306           0 :   return FD_SCRATCH_ALLOC_FINI( l, 1UL ) - (ulong)out_buf;
    1307           0 : }
    1308             : 
    1309             : void
    1310             : fd_dump_txn_to_protobuf( fd_runtime_t *      runtime,
    1311             :                          fd_bank_t *         bank,
    1312             :                          fd_txn_in_t const * txn_in,
    1313           0 :                          fd_txn_out_t *      txn_out ) {
    1314           0 :   fd_spad_t * spad = fd_spad_join( fd_spad_new( runtime->log.dumping_mem, 1UL<<28UL ) );
    1315             : 
    1316           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
    1317             :     // Get base58-encoded tx signature
    1318           0 :     const fd_ed25519_sig_t * signatures = fd_txn_get_signatures( TXN( txn_in->txn ), txn_in->txn->payload );
    1319           0 :     char encoded_signature[FD_BASE58_ENCODED_64_SZ];
    1320           0 :     fd_base58_encode_64( signatures[0], NULL, encoded_signature );
    1321             : 
    1322           0 :     fd_exec_test_txn_context_t txn_context_msg = FD_EXEC_TEST_TXN_CONTEXT_INIT_DEFAULT;
    1323           0 :     create_txn_context_protobuf_from_txn( &txn_context_msg, runtime, bank, txn_in, txn_out, spad );
    1324             : 
    1325             :     /* Output to file */
    1326           0 :     ulong        out_buf_size = 100UL<<20UL; // 100 MB
    1327           0 :     uchar *      out          = fd_spad_alloc( spad, alignof(uchar), out_buf_size );
    1328           0 :     pb_ostream_t stream       = pb_ostream_from_buffer( out, out_buf_size );
    1329           0 :     if( pb_encode( &stream, FD_EXEC_TEST_TXN_CONTEXT_FIELDS, &txn_context_msg ) ) {
    1330           0 :       char output_filepath[ PATH_MAX ];
    1331           0 :       snprintf( output_filepath, PATH_MAX, "%s/txn-%s.txnctx", runtime->log.dump_proto_ctx->dump_proto_output_dir, encoded_signature );
    1332           0 :       FILE * file = fopen(output_filepath, "wb");
    1333           0 :       if( file ) {
    1334           0 :         fwrite( out, 1, stream.bytes_written, file );
    1335           0 :         fclose( file );
    1336           0 :       }
    1337           0 :     }
    1338           0 :   } FD_SPAD_FRAME_END;
    1339           0 : }
    1340             : 
    1341             : void
    1342             : fd_dump_txn_context_to_protobuf( fd_txn_dump_ctx_t * txn_dump_ctx,
    1343             :                                  fd_runtime_t *      runtime,
    1344             :                                  fd_bank_t *         bank,
    1345             :                                  fd_txn_in_t const * txn_in,
    1346           0 :                                  fd_txn_out_t *      txn_out ) {
    1347           0 :   fd_txn_dump_context_reset( txn_dump_ctx );
    1348             : 
    1349           0 :   txn_dump_ctx->fixture.has_metadata = true;
    1350           0 :   strncpy(
    1351           0 :       txn_dump_ctx->fixture.metadata.fn_entrypoint,
    1352           0 :       "sol_compat_txn_execute_v1",
    1353           0 :       sizeof(txn_dump_ctx->fixture.metadata.fn_entrypoint)-1UL
    1354           0 :   );
    1355             : 
    1356           0 :   txn_dump_ctx->fixture.has_input = true;
    1357           0 :   create_txn_context_protobuf_from_txn( &txn_dump_ctx->fixture.input,
    1358           0 :                                         runtime, bank, txn_in, txn_out,
    1359           0 :                                         txn_dump_ctx->spad );
    1360           0 : }
    1361             : 
    1362             : void
    1363             : fd_dump_txn_result_to_protobuf( fd_txn_dump_ctx_t * txn_dump_ctx,
    1364             :                                 fd_txn_in_t const * txn_in,
    1365             :                                 fd_txn_out_t *      txn_out,
    1366           0 :                                 int                 exec_res ) {
    1367           0 :   txn_dump_ctx->fixture.has_output = true;
    1368             : 
    1369           0 :   ulong  buf_sz = 100UL<<20UL;
    1370           0 :   void * buf    = fd_spad_alloc( txn_dump_ctx->spad, alignof(fd_exec_test_txn_result_t), buf_sz );
    1371           0 :   fd_exec_test_txn_result_t * result = NULL;
    1372           0 :   create_txn_result_protobuf_from_txn( &result, buf, buf_sz, txn_in, txn_out, exec_res );
    1373           0 :   txn_dump_ctx->fixture.output = *result;
    1374           0 : }
    1375             : 
    1376             : void
    1377             : fd_dump_txn_fixture_to_file( fd_txn_dump_ctx_t *         txn_dump_ctx,
    1378             :                              fd_dump_proto_ctx_t const * dump_proto_ctx,
    1379           0 :                              fd_txn_in_t const *         txn_in ) {
    1380           0 :   const fd_ed25519_sig_t * signatures = fd_txn_get_signatures( TXN( txn_in->txn ), txn_in->txn->payload );
    1381           0 :   char encoded_signature[FD_BASE58_ENCODED_64_SZ];
    1382           0 :   fd_base58_encode_64( signatures[0], NULL, encoded_signature );
    1383             : 
    1384           0 :   FD_SPAD_FRAME_BEGIN( txn_dump_ctx->spad ) {
    1385           0 :     ulong        out_buf_size = 100UL<<20UL;
    1386           0 :     uchar *      out          = fd_spad_alloc( txn_dump_ctx->spad, alignof(uchar), out_buf_size );
    1387           0 :     pb_ostream_t stream       = pb_ostream_from_buffer( out, out_buf_size );
    1388             : 
    1389           0 :     char output_filepath[ PATH_MAX ];
    1390             : 
    1391           0 :     if( dump_proto_ctx->dump_txn_as_fixture ) {
    1392           0 :       if( pb_encode( &stream, FD_EXEC_TEST_TXN_FIXTURE_FIELDS, &txn_dump_ctx->fixture ) ) {
    1393           0 :         snprintf( output_filepath, PATH_MAX, "%s/txn-%s.fix", dump_proto_ctx->dump_proto_output_dir, encoded_signature );
    1394           0 :         FILE * file = fopen( output_filepath, "wb" );
    1395           0 :         if( file ) {
    1396           0 :           fwrite( out, 1, stream.bytes_written, file );
    1397           0 :           fclose( file );
    1398           0 :         }
    1399           0 :       }
    1400           0 :     } else {
    1401           0 :       if( pb_encode( &stream, FD_EXEC_TEST_TXN_CONTEXT_FIELDS, &txn_dump_ctx->fixture.input ) ) {
    1402           0 :         snprintf( output_filepath, PATH_MAX, "%s/txn-%s.txnctx", dump_proto_ctx->dump_proto_output_dir, encoded_signature );
    1403           0 :         FILE * file = fopen( output_filepath, "wb" );
    1404           0 :         if( file ) {
    1405           0 :           fwrite( out, 1, stream.bytes_written, file );
    1406           0 :           fclose( file );
    1407           0 :         }
    1408           0 :       }
    1409           0 :     }
    1410           0 :   } FD_SPAD_FRAME_END;
    1411           0 : }
    1412             : 
    1413             : void
    1414             : fd_dump_block_to_protobuf_collect_tx( fd_block_dump_ctx_t * dump_block_ctx,
    1415           0 :                                       fd_txn_p_t const *    txn ) {
    1416           0 :   if( FD_UNLIKELY( dump_block_ctx->txns_to_dump_cnt>=FD_BLOCK_DUMP_CTX_MAX_TXN_CNT ) ) {
    1417           0 :     FD_LOG_ERR(( "Please increase FD_BLOCK_DUMP_CTX_MAX_TXN_CNT to dump more than %lu transactions.", FD_BLOCK_DUMP_CTX_MAX_TXN_CNT ));
    1418           0 :     return;
    1419           0 :   }
    1420           0 :   fd_memcpy( &dump_block_ctx->txns_to_dump[dump_block_ctx->txns_to_dump_cnt++], txn, sizeof(fd_txn_p_t) );
    1421           0 : }
    1422             : 
    1423             : void
    1424             : fd_dump_block_to_protobuf( fd_block_dump_ctx_t *       dump_block_ctx,
    1425             :                            fd_banks_t *                banks,
    1426             :                            fd_bank_t *                 bank,
    1427             :                            fd_accdb_t *                accdb,
    1428             :                            fd_dump_proto_ctx_t const * dump_proto_ctx,
    1429           0 :                            fd_runtime_stack_t *        runtime_stack ) {
    1430           0 :   if( FD_UNLIKELY( dump_block_ctx==NULL ) ) {
    1431           0 :     FD_LOG_WARNING(( "Block dumping context may not be NULL when dumping blocks." ));
    1432           0 :     return;
    1433           0 :   }
    1434             : 
    1435           0 : FD_SPAD_FRAME_BEGIN( dump_block_ctx->spad ) {
    1436           0 :   if( FD_UNLIKELY( dump_proto_ctx==NULL ) ) {
    1437           0 :     FD_LOG_WARNING(( "Protobuf dumping context may not be NULL when dumping blocks." ));
    1438           0 :     return;
    1439           0 :   }
    1440             : 
    1441             :   /* Dump the block context */
    1442           0 :   create_block_context_protobuf_from_block( dump_block_ctx, banks, bank, accdb, runtime_stack );
    1443             : 
    1444             :   /* Output to file */
    1445           0 :   ulong        out_buf_size = 1UL<<30UL; /* 1 GB */
    1446           0 :   uint8_t *    out          = fd_spad_alloc( dump_block_ctx->spad, alignof(uint8_t), out_buf_size );
    1447           0 :   pb_ostream_t stream       = pb_ostream_from_buffer( out, out_buf_size );
    1448           0 :   if( pb_encode( &stream, FD_EXEC_TEST_BLOCK_CONTEXT_FIELDS, &dump_block_ctx->block_context ) ) {
    1449           0 :     char output_filepath[ PATH_MAX ];
    1450           0 :     snprintf( output_filepath, PATH_MAX, "%s/block-%lu.blockctx", dump_proto_ctx->dump_proto_output_dir, bank->f.slot );
    1451           0 :     FILE * file = fopen(output_filepath, "wb");
    1452           0 :     if( file ) {
    1453           0 :       fwrite( out, 1, stream.bytes_written, file );
    1454           0 :       fclose( file );
    1455           0 :     }
    1456           0 :   }
    1457           0 : } FD_SPAD_FRAME_END;
    1458           0 : }
    1459             : 
    1460             : void
    1461             : fd_dump_vm_syscall_to_protobuf( fd_vm_t const * vm,
    1462           0 :                                 char const *    fn_name ) {
    1463           0 :   char const * syscall_name_filter = vm->instr_ctx->runtime->log.dump_proto_ctx->dump_syscall_name_filter;
    1464           0 :   if( syscall_name_filter && strlen( syscall_name_filter ) && strcmp( syscall_name_filter, fn_name ) ) {
    1465           0 :     return;
    1466           0 :   }
    1467             : 
    1468           0 :   fd_spad_t * spad = fd_spad_join( fd_spad_new( vm->instr_ctx->runtime->log.dumping_mem, 1UL<<28UL ) );
    1469             : 
    1470           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
    1471             : 
    1472           0 :   fd_ed25519_sig_t signature;
    1473           0 :   memcpy( signature, (uchar const *)vm->instr_ctx->txn_in->txn->payload + TXN( vm->instr_ctx->txn_in->txn )->signature_off, sizeof(fd_ed25519_sig_t) );
    1474           0 :   char encoded_signature[FD_BASE58_ENCODED_64_SZ];
    1475           0 :   fd_base58_encode_64( signature, NULL, encoded_signature );
    1476             : 
    1477           0 :   char filename[ PATH_MAX ];
    1478           0 :   snprintf( filename,
    1479           0 :           PATH_MAX,
    1480           0 :           "%s/syscall-%s-%s-%d-%hhu-%lu.sysctx",
    1481           0 :           vm->instr_ctx->runtime->log.dump_proto_ctx->dump_proto_output_dir,
    1482           0 :           fn_name,
    1483           0 :           encoded_signature,
    1484           0 :           vm->instr_ctx->runtime->instr.current_idx,
    1485           0 :           vm->instr_ctx->runtime->instr.stack_sz,
    1486           0 :           vm->cu );
    1487             : 
    1488             :   /* The generated filename should be unique for every call. Silently return otherwise. */
    1489           0 :   if( FD_UNLIKELY( access( filename, F_OK )!=-1 ) ) {
    1490           0 :     return;
    1491           0 :   }
    1492             : 
    1493           0 :   fd_exec_test_syscall_context_t sys_ctx = FD_EXEC_TEST_SYSCALL_CONTEXT_INIT_ZERO;
    1494             : 
    1495             :   /* SyscallContext -> vm_ctx */
    1496           0 :   sys_ctx.has_vm_ctx = 1;
    1497             : 
    1498             :   /* SyscallContext -> vm_ctx -> heap_max */
    1499           0 :   sys_ctx.vm_ctx.heap_max = vm->heap_max; /* should be equiv. to txn_ctx->heap_sz */
    1500             : 
    1501             :   /* SyscallContext -> vm_ctx -> rodata */
    1502           0 :   sys_ctx.vm_ctx.rodata = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE( vm->rodata_sz ) );
    1503           0 :   sys_ctx.vm_ctx.rodata->size = (pb_size_t) vm->rodata_sz;
    1504           0 :   fd_memcpy( sys_ctx.vm_ctx.rodata->bytes, vm->rodata, vm->rodata_sz );
    1505             : 
    1506             :   /* SyscallContext -> vm_ctx -> r0-11 */
    1507           0 :   sys_ctx.vm_ctx.r0  = vm->reg[0];
    1508           0 :   sys_ctx.vm_ctx.r1  = vm->reg[1];
    1509           0 :   sys_ctx.vm_ctx.r2  = vm->reg[2];
    1510           0 :   sys_ctx.vm_ctx.r3  = vm->reg[3];
    1511           0 :   sys_ctx.vm_ctx.r4  = vm->reg[4];
    1512           0 :   sys_ctx.vm_ctx.r5  = vm->reg[5];
    1513           0 :   sys_ctx.vm_ctx.r6  = vm->reg[6];
    1514           0 :   sys_ctx.vm_ctx.r7  = vm->reg[7];
    1515           0 :   sys_ctx.vm_ctx.r8  = vm->reg[8];
    1516           0 :   sys_ctx.vm_ctx.r9  = vm->reg[9];
    1517           0 :   sys_ctx.vm_ctx.r10 = vm->reg[10];
    1518           0 :   sys_ctx.vm_ctx.r11 = vm->reg[11];
    1519             : 
    1520             :   /* SyscallContext -> vm_ctx -> entry_pc */
    1521           0 :   sys_ctx.vm_ctx.entry_pc = vm->entry_pc;
    1522             : 
    1523             :   /* SyscallContext -> vm_ctx -> return_data */
    1524           0 :   sys_ctx.vm_ctx.has_return_data = 1;
    1525             : 
    1526             :   /* SyscallContext -> vm_ctx -> return_data -> data */
    1527           0 :   sys_ctx.vm_ctx.return_data.data = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE( vm->instr_ctx->txn_out->details.return_data.len ) );
    1528           0 :   sys_ctx.vm_ctx.return_data.data->size = (pb_size_t)vm->instr_ctx->txn_out->details.return_data.len;
    1529           0 :   fd_memcpy( sys_ctx.vm_ctx.return_data.data->bytes, vm->instr_ctx->txn_out->details.return_data.data, vm->instr_ctx->txn_out->details.return_data.len );
    1530             : 
    1531             :   /* SyscallContext -> vm_ctx -> return_data -> program_id */
    1532           0 :   sys_ctx.vm_ctx.return_data.program_id = fd_spad_alloc( spad, alignof(pb_bytes_array_t), sizeof(fd_pubkey_t) );
    1533           0 :   sys_ctx.vm_ctx.return_data.program_id->size = sizeof(fd_pubkey_t);
    1534           0 :   fd_memcpy( sys_ctx.vm_ctx.return_data.program_id->bytes, vm->instr_ctx->txn_out->details.return_data.program_id.key, sizeof(fd_pubkey_t) );
    1535             : 
    1536             :   /* SyscallContext -> vm_ctx -> sbpf_version */
    1537           0 :   sys_ctx.vm_ctx.sbpf_version = (uint)vm->sbpf_version;
    1538             : 
    1539             :   /* SyscallContext -> instr_ctx */
    1540           0 :   sys_ctx.has_instr_ctx = 1;
    1541           0 :   create_instr_context_protobuf_from_instructions( &sys_ctx.instr_ctx,
    1542           0 :                                                    vm->instr_ctx->runtime,
    1543           0 :                                                    vm->instr_ctx->bank,
    1544           0 :                                                    vm->instr_ctx->txn_out,
    1545           0 :                                                    vm->instr_ctx->instr,
    1546           0 :                                                    spad );
    1547             : 
    1548             :   /* SyscallContext -> syscall_invocation */
    1549           0 :   sys_ctx.has_syscall_invocation = 1;
    1550             : 
    1551             :   /* SyscallContext -> syscall_invocation -> function_name */
    1552           0 :   sys_ctx.syscall_invocation.function_name.size = fd_uint_min( (uint) strlen(fn_name), sizeof(sys_ctx.syscall_invocation.function_name.bytes) );
    1553           0 :   fd_memcpy( sys_ctx.syscall_invocation.function_name.bytes,
    1554           0 :              fn_name,
    1555           0 :              sys_ctx.syscall_invocation.function_name.size );
    1556             : 
    1557             :   /* SyscallContext -> syscall_invocation -> heap_prefix */
    1558           0 :   sys_ctx.syscall_invocation.heap_prefix = fd_spad_alloc( spad, 8UL, PB_BYTES_ARRAY_T_ALLOCSIZE( vm->heap_max ) );
    1559           0 :   sys_ctx.syscall_invocation.heap_prefix->size = (pb_size_t) vm->instr_ctx->txn_out->details.compute_budget.heap_size;
    1560           0 :   fd_memcpy( sys_ctx.syscall_invocation.heap_prefix->bytes, vm->heap, vm->instr_ctx->txn_out->details.compute_budget.heap_size );
    1561             : 
    1562             :   /* SyscallContext -> syscall_invocation -> stack_prefix */
    1563           0 :   pb_size_t stack_sz = (pb_size_t)FD_VM_STACK_MAX;
    1564           0 :   sys_ctx.syscall_invocation.stack_prefix = fd_spad_alloc( spad, 8UL, PB_BYTES_ARRAY_T_ALLOCSIZE( stack_sz ) );
    1565           0 :   sys_ctx.syscall_invocation.stack_prefix->size = stack_sz;
    1566           0 :   fd_memcpy( sys_ctx.syscall_invocation.stack_prefix->bytes, vm->stack, stack_sz );
    1567             : 
    1568             :   /* Output to file */
    1569           0 :   ulong out_buf_size = 1UL<<29UL; /* 128 MB */
    1570           0 :   uint8_t * out = fd_spad_alloc( spad, alignof(uint8_t), out_buf_size );
    1571           0 :   pb_ostream_t stream = pb_ostream_from_buffer( out, out_buf_size );
    1572           0 :   if( pb_encode( &stream, FD_EXEC_TEST_SYSCALL_CONTEXT_FIELDS, &sys_ctx ) ) {
    1573           0 :     FILE * file = fopen(filename, "wb");
    1574           0 :     if( file ) {
    1575           0 :       fwrite( out, 1, stream.bytes_written, file );
    1576           0 :       fclose( file );
    1577           0 :     }
    1578           0 :   }
    1579           0 :   } FD_SPAD_FRAME_END;
    1580           0 : }

Generated by: LCOV version 1.14