LCOV - code coverage report
Current view: top level - flamenco/capture - fd_solcap_yaml.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 295 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #include "../fd_flamenco.h"
       2             : #include "fd_solcap_proto.h"
       3             : #include "fd_solcap_reader.h"
       4             : #include "fd_solcap.pb.h"
       5             : #include "../nanopb/pb_decode.h"
       6             : #include "../../util/textstream/fd_textstream.h"
       7             : #include "../runtime/fd_executor.h"
       8             : #include <errno.h>
       9             : #include <stdio.h>
      10             : 
      11             : static int
      12           0 : usage( void ) {
      13           0 :   fprintf( stderr,
      14           0 :     "Usage: fd_solcap_yaml [options] {FILE}\n"
      15           0 :     "\n"
      16           0 :     "Print a runtime capture file as YAML.\n"
      17           0 :     "\n"
      18           0 :     "Options:\n"
      19           0 :     "  --page-sz      {gigantic|huge|normal}    Page size\n"
      20           0 :     "  --page-cnt     {count}                   Page count\n"
      21           0 :     "  --scratch-mb   1024                      Scratch mem MiB\n"
      22           0 :     "  -v             {level}                   YAML verbosity\n"
      23           0 :     "  --start-slot   {slot}                    Start slot\n"
      24           0 :     "  --end-slot     {slot}                    End slot\n"
      25           0 :     "\n" );
      26           0 :   return 0;
      27           0 : }
      28             : 
      29             : /* process_account reads and dumps a single account.  If verbose>4,
      30             :    includes a base64 dump of account content. */
      31             : 
      32             : static int
      33             : process_account( FILE * file,
      34             :                  long   goff,
      35           0 :                  int    verbose ) {
      36             : 
      37             :   /* Remember stream cursor */
      38             : 
      39           0 :   long pos = ftell( file );
      40           0 :   if( FD_UNLIKELY( pos<0L ) ) {
      41           0 :     FD_LOG_ERR(( "ftell failed (%d-%s)", errno, strerror( errno ) ));
      42           0 :     return 0;
      43           0 :   }
      44             : 
      45             :   /* Seek to chunk */
      46             : 
      47           0 :   if( FD_UNLIKELY( 0!=fseek( file, goff, SEEK_SET ) ) ) {
      48           0 :     FD_LOG_ERR(( "fseek failed (%d-%s)", errno, strerror( errno ) ));
      49           0 :     return 0;
      50           0 :   }
      51             : 
      52             :   /* Read chunk */
      53             : 
      54           0 :   fd_solcap_chunk_t chunk[1];
      55           0 :   ulong n = fread( chunk, sizeof(fd_solcap_chunk_t), 1UL, file );
      56           0 :   if( FD_UNLIKELY( n!=1UL ) ) {
      57           0 :     FD_LOG_ERR(( "fread chunk failed (%d-%s)", errno, strerror( errno ) ));
      58           0 :     return 0;
      59           0 :   }
      60           0 :   if( FD_UNLIKELY( chunk->magic != FD_SOLCAP_V1_ACCT_MAGIC ) ) {
      61           0 :     FD_LOG_ERR(( "expected account table chunk at %#lx, got magic=0x%016lx", (ulong)goff, chunk->magic ));
      62           0 :     return 0;
      63           0 :   }
      64             : 
      65             :   /* Read metadata */
      66             : 
      67           0 :   fd_solcap_AccountMeta meta[1];
      68           0 :   do {
      69             : 
      70           0 :     uchar meta_buf[ 512UL ];
      71           0 :     ulong meta_sz = chunk->meta_sz;
      72           0 :     if( FD_UNLIKELY( meta_sz > sizeof(meta_buf ) ) )
      73           0 :       FD_LOG_ERR(( "invalid account meta size (%lu)", meta_sz ));
      74             : 
      75           0 :     if( FD_UNLIKELY( 0!=fseek( file, (long)chunk->meta_coff - (long)sizeof(fd_solcap_chunk_t), SEEK_CUR ) ) )
      76           0 :       FD_LOG_ERR(( "fseek to account meta failed (%d-%s)", errno, strerror( errno ) ));
      77             : 
      78           0 :     if( FD_UNLIKELY( meta_sz != fread( meta_buf, 1UL, meta_sz, file ) ) )
      79           0 :       FD_LOG_ERR(( "fread account meta failed (%d-%s)", errno, strerror( errno ) ));
      80             : 
      81           0 :     pb_istream_t stream = pb_istream_from_buffer( meta_buf, meta_sz );
      82           0 :     if( FD_UNLIKELY( !pb_decode( &stream, fd_solcap_AccountMeta_fields, meta ) ) ) {
      83           0 :       FD_LOG_HEXDUMP_DEBUG(( "account meta", meta_buf, meta_sz ));
      84           0 :       FD_LOG_ERR(( "pb_decode account meta failed (%s)", PB_GET_ERROR(&stream) ));
      85           0 :     }
      86             : 
      87           0 :     long rewind = (long)chunk->meta_coff + (long)meta_sz;
      88           0 :     if( FD_UNLIKELY( 0!=fseek( file, -rewind, SEEK_CUR ) ) )
      89           0 :       FD_LOG_ERR(( "fseek failed (%d-%s)", errno, strerror( errno ) ));
      90             : 
      91           0 :   } while(0);
      92             : 
      93           0 :   printf(
      94           0 :     "      owner:      '%s'\n"
      95           0 :     "      lamports:   %lu\n"
      96           0 :     "      slot:       %lu\n"
      97           0 :     "      rent_epoch: %lu\n"
      98           0 :     "      executable: %s\n"
      99           0 :     "      data_sz:    %lu\n",
     100           0 :     FD_BASE58_ENC_32_ALLOCA( meta->owner ),
     101           0 :     meta->lamports,
     102           0 :     meta->slot,
     103           0 :     meta->rent_epoch,
     104           0 :     meta->executable ? "true" : "false",
     105           0 :     meta->data_sz );
     106             : 
     107             :   /* Optionally print account data */
     108             : 
     109           0 :   if( verbose>4 ) {
     110           0 :     printf( "      data: '" );
     111             : 
     112             :     /* Seek to account data */
     113           0 :     if( FD_UNLIKELY( 0!=fseek( file, goff + meta->data_coff, SEEK_SET ) ) )
     114           0 :       FD_LOG_ERR(( "fseek to account data failed (%d-%s)", errno, strerror( errno ) ));
     115             : 
     116             :     /* Streaming Base64 encode.
     117             : 
     118             :        Process inputs in "parts" with length divided by 3, 4 such that
     119             :        no padding is in the middle of the encoding.  Technically Base64
     120             :        allows padding in the middle, but it's cleaner to only have
     121             :        padding at the end of the message. */
     122           0 : #   define PART_RAW_SZ (720UL)
     123           0 : #   define PART_BLK_SZ (4UL*(PART_RAW_SZ+2UL)/3UL)  /* see fd_textstream_encode_base64 */
     124           0 :     ulong data_sz = meta->data_sz;
     125           0 :     while( data_sz>0UL ) {
     126           0 :       ulong n = fd_ulong_min( data_sz, PART_RAW_SZ );
     127             : 
     128             :       /* Read chunk */
     129           0 :       uchar buf[ PART_RAW_SZ ];
     130           0 :       if( FD_UNLIKELY( 1UL!=fread( buf, n, 1UL, file ) ) )
     131           0 :         FD_LOG_ERR(( "fread account data failed (%d-%s)", errno, strerror( errno ) ));
     132             : 
     133             :       /* Encode chunk */
     134           0 :       fd_valloc_t valloc = fd_scratch_virtual();
     135           0 :       fd_scratch_push();
     136             : 
     137           0 :       fd_textstream_t  _data_out[1];
     138           0 :       fd_textstream_t * data_out = fd_textstream_new( _data_out, valloc, PART_BLK_SZ );
     139           0 :       fd_textstream_encode_base64( data_out, buf, n );
     140             : 
     141             :       /* Get pointer to encoded chunk */
     142           0 :       FD_TEST( 1UL==fd_textstream_get_iov_count( data_out ) );
     143           0 :       struct fd_iovec iov[1];
     144           0 :       FD_TEST( 0  ==fd_textstream_get_iov( data_out, iov ) );
     145             : 
     146             :       /* Print encoded chunk */
     147           0 :       FD_TEST( 1UL==fwrite( iov[0].iov_base, iov[0].iov_len, 1UL, stdout ) );
     148             : 
     149             :       /* Wind up for next iteration */
     150           0 :       data_sz -= n;
     151           0 :       fd_textstream_destroy( data_out );  /* technically noop */
     152           0 :       fd_scratch_pop();
     153           0 :     }
     154           0 : #   undef PART_RAW_SZ
     155           0 : #   undef PART_BLK_SZ
     156             : 
     157             :     /* Finish YAML entry */
     158           0 :     printf( "'\n" );
     159           0 :   }
     160             : 
     161             :   /* Restore cursor */
     162             : 
     163           0 :   if( FD_UNLIKELY( 0!=fseek( file, pos, SEEK_SET ) ) ) {
     164           0 :     FD_LOG_ERR(( "fseek failed (%d-%s)", errno, strerror( errno ) ));
     165           0 :     return 0;
     166           0 :   }
     167             : 
     168           0 :   return 1;
     169           0 : }
     170             : 
     171             : /* process_account_table reads and dumps an account table chunk.
     172             :    If verbose>3, also prints account content.  Returns 1 on success and
     173             :    0 on failure.  On success, restores stream cursor to position on
     174             :    function entry. */
     175             : 
     176             : static int
     177             : process_account_table( FILE * file,
     178             :                        ulong  slot,
     179           0 :                        int    verbose ) {
     180             : 
     181             :   /* Remember stream cursor */
     182             : 
     183           0 :   long pos = ftell( file );
     184           0 :   if( FD_UNLIKELY( pos<0L ) ) {
     185           0 :     FD_LOG_ERR(( "ftell failed (%d-%s)", errno, strerror( errno ) ));
     186           0 :     return 0;
     187           0 :   }
     188             : 
     189             :   /* Read chunk */
     190             : 
     191           0 :   fd_solcap_chunk_t chunk[1];
     192           0 :   ulong n = fread( chunk, sizeof(fd_solcap_chunk_t), 1UL, file );
     193           0 :   if( FD_UNLIKELY( n!=1UL ) ) {
     194           0 :     FD_LOG_ERR(( "fread chunk failed (%d-%s)", errno, strerror( errno ) ));
     195           0 :     return 0;
     196           0 :   }
     197           0 :   if( FD_UNLIKELY( chunk->magic != FD_SOLCAP_V1_ACTB_MAGIC ) ) {
     198           0 :     FD_LOG_ERR(( "expected account table chunk, got 0x%016lx", chunk->magic ));
     199           0 :     return 0;
     200           0 :   }
     201             : 
     202             :   /* Read metadata */
     203             : 
     204           0 :   fd_solcap_AccountTableMeta meta[1];
     205           0 :   do {
     206             : 
     207           0 :     uchar meta_buf[ 512UL ];
     208           0 :     ulong meta_sz = chunk->meta_sz;
     209           0 :     if( FD_UNLIKELY( meta_sz > sizeof(meta_buf ) ) ) {
     210           0 :       FD_LOG_ERR(( "invalid accounts table meta size (%lu)", meta_sz ));
     211           0 :       return 0;
     212           0 :     }
     213             : 
     214           0 :     if( FD_UNLIKELY( 0!=fseek( file, (long)chunk->meta_coff - (long)sizeof(fd_solcap_chunk_t), SEEK_CUR ) ) ) {
     215           0 :       FD_LOG_ERR(( "fseek to accounts table meta failed (%d-%s)", errno, strerror( errno ) ));
     216           0 :       return 0;
     217           0 :     }
     218             : 
     219           0 :     if( FD_UNLIKELY( meta_sz != fread( meta_buf, 1UL, meta_sz, file ) ) ) {
     220           0 :       FD_LOG_ERR(( "fread accounts table meta failed (%d-%s)", errno, strerror( errno ) ));
     221           0 :       return 0;
     222           0 :     }
     223             : 
     224           0 :     pb_istream_t stream = pb_istream_from_buffer( meta_buf, meta_sz );
     225           0 :     if( FD_UNLIKELY( !pb_decode( &stream, fd_solcap_AccountTableMeta_fields, meta ) ) ) {
     226           0 :       FD_LOG_HEXDUMP_DEBUG(( "accounts table meta", meta_buf, meta_sz ));
     227           0 :       FD_LOG_ERR(( "pb_decode accounts table meta failed (%s)", PB_GET_ERROR(&stream) ));
     228           0 :       return 0;
     229           0 :     }
     230             : 
     231           0 :     long rewind = (long)chunk->meta_coff + (long)meta_sz;
     232           0 :     if( FD_UNLIKELY( 0!=fseek( file, -rewind, SEEK_CUR ) ) ) {
     233           0 :       FD_LOG_ERR(( "fseek failed (%d-%s)", errno, strerror( errno ) ));
     234           0 :       return 0;
     235           0 :     }
     236             : 
     237           0 :   } while(0);
     238             : 
     239             :   /* TODO verify meta.slot */
     240             : 
     241             :   /* Seek to accounts table */
     242             : 
     243           0 :   if( FD_UNLIKELY( 0!=fseek( file, (long)meta->account_table_coff, SEEK_CUR ) ) ) {
     244           0 :     FD_LOG_ERR(( "fseek to accounts table failed (%d-%s)", errno, strerror( errno ) ));
     245           0 :     return 0;
     246           0 :   }
     247             : 
     248             :   /* Read accounts table */
     249             : 
     250           0 :   for( ulong i=0UL; i < meta->account_table_cnt; i++ ) {
     251             :     /* Read account */
     252             : 
     253           0 :     fd_solcap_account_tbl_t entry[1];
     254           0 :     if( FD_UNLIKELY( 1UL!=fread( entry, sizeof(fd_solcap_account_tbl_t), 1UL, file ) ) ) {
     255           0 :       FD_LOG_ERR(( "fread accounts table entry failed (%d-%s)", errno, strerror( errno ) ));
     256           0 :       return 0;
     257           0 :     }
     258             : 
     259             :     /* Write to YAML */
     260             : 
     261           0 :     printf(
     262           0 :       "    - pubkey:   '%s'\n"
     263           0 :       "      hash:     '%s'\n"
     264           0 :       "      explorer: 'https://explorer.solana.com/block/%lu?accountFilter=%s&filter=all'\n",
     265           0 :       FD_BASE58_ENC_32_ALLOCA( entry->key ),
     266           0 :       FD_BASE58_ENC_32_ALLOCA( entry->hash ),
     267           0 :       slot,
     268           0 :       FD_BASE58_ENC_32_ALLOCA( entry->key ) );
     269             : 
     270             :     /* Fetch account details */
     271             : 
     272           0 :     if( verbose > 3 ) {
     273           0 :       long acc_goff = (long)pos + entry->acc_coff;
     274           0 :       if( FD_UNLIKELY( !process_account( file, acc_goff, verbose ) ) ) {
     275           0 :         FD_LOG_ERR(( "process_account() failed" ));
     276           0 :         return 0;
     277           0 :       }
     278           0 :     }
     279             : 
     280           0 :   } /* end for */
     281             : 
     282             :   /* Restore cursor */
     283             : 
     284           0 :   if( FD_UNLIKELY( 0!=fseek( file, pos, SEEK_SET ) ) ) {
     285           0 :     FD_LOG_ERR(( "fseek failed (%d-%s)", errno, strerror( errno ) ));
     286           0 :     return 0;
     287           0 :   }
     288             : 
     289           0 :   return 0;
     290           0 : }
     291             : 
     292             : /* process_bank reads and dumps a bank chunk.  If verbose>1, also
     293             :    processes account table.  Returns errno (0 on success).  Stream
     294             :    cursor is undefined on return. */
     295             : 
     296             : static int
     297             : process_bank( fd_solcap_chunk_t const * chunk,
     298             :               FILE *                    file,
     299             :               int                       verbose,
     300             :               long                      chunk_gaddr,
     301             :               ulong                     start_slot,
     302             :               ulong                     end_slot,
     303           0 :               int                       has_txns ) {
     304             : 
     305           0 : # define FD_SOLCAP_BANK_PREIMAGE_FOOTPRINT (512UL)
     306           0 :   if( FD_UNLIKELY( chunk->meta_sz > FD_SOLCAP_BANK_PREIMAGE_FOOTPRINT ) ) {
     307           0 :     FD_LOG_ERR(( "invalid bank preimage meta size (%u)", chunk->meta_sz ));
     308           0 :     return ENOMEM;
     309           0 :   }
     310             : 
     311             :   /* Read bank preimage meta */
     312             : 
     313           0 :   uchar meta_buf[ 512UL ];
     314           0 :   if( FD_UNLIKELY( 0!=fseek( file, chunk_gaddr + (long)chunk->meta_coff, SEEK_SET ) ) ) {
     315           0 :     FD_LOG_ERR(( "fseek bank preimage meta failed (%d-%s)", errno, strerror( errno ) ));
     316           0 :     return errno;
     317           0 :   }
     318           0 :   if( FD_UNLIKELY( chunk->meta_sz != fread( meta_buf, 1UL, chunk->meta_sz, file ) ) ) {
     319           0 :     FD_LOG_ERR(( "fread bank preimage meta failed (%d-%s)", errno, strerror( errno ) ));
     320           0 :     return errno;
     321           0 :   }
     322             : 
     323             :   /* Deserialize bank preimage meta */
     324             : 
     325           0 :   pb_istream_t stream = pb_istream_from_buffer( meta_buf, chunk->meta_sz );
     326             : 
     327           0 :   fd_solcap_BankPreimage meta;
     328           0 :   if( FD_UNLIKELY( !pb_decode( &stream, fd_solcap_BankPreimage_fields, &meta ) ) ) {
     329           0 :     FD_LOG_HEXDUMP_DEBUG(( "bank preimage meta", meta_buf, chunk->meta_sz ));
     330           0 :     FD_LOG_ERR(( "pb_decode bank preimage meta failed (%s)", PB_GET_ERROR(&stream) ));
     331           0 :     return EPROTO;
     332           0 :   }
     333             : 
     334           0 :   if ( meta.slot < start_slot || meta.slot > end_slot ) {
     335           0 :     return 0;
     336           0 :   }
     337             : 
     338             :   /* Write YAML */
     339           0 :   if ( verbose < 3 || !has_txns )
     340           0 :     printf( "- slot: %lu\n", meta.slot );
     341             : 
     342           0 :   printf(
     343           0 :       "  - bank_hash:          '%s'\n",
     344           0 :       FD_BASE58_ENC_32_ALLOCA( meta.bank_hash ) );
     345             : 
     346           0 :   if( verbose>=1 ) {
     347           0 :     printf(
     348           0 :       "  - prev_bank_hash:     '%s'\n"
     349           0 :       "  - account_delta_hash: '%s'\n"
     350           0 :       "  - poh_hash:           '%s'\n"
     351           0 :       "  - signature_cnt:      %lu\n",
     352           0 :       FD_BASE58_ENC_32_ALLOCA( meta.prev_bank_hash ),
     353           0 :       FD_BASE58_ENC_32_ALLOCA( meta.account_delta_hash ),
     354           0 :       FD_BASE58_ENC_32_ALLOCA( meta.poh_hash ),
     355           0 :       meta.signature_cnt );
     356           0 :   }
     357             : 
     358             :   /* Accounts */
     359             : 
     360           0 :   if( verbose >= 2 ) {
     361           0 :     if( meta.account_table_coff==0L ) {
     362           0 :       if( meta.account_cnt > 0UL )
     363           0 :         FD_LOG_WARNING(( "Capture does not include account info for slot=%lu", meta.slot ));
     364           0 :       return 0;
     365           0 :     }
     366             : 
     367           0 :     if( FD_UNLIKELY( 0!=fseek( file, chunk_gaddr + (long)meta.account_table_coff, SEEK_SET ) ) ) {
     368           0 :       FD_LOG_ERR(( "fseek to account table failed (%d-%s)", errno, strerror( errno ) ));
     369           0 :       return errno;
     370           0 :     }
     371             : 
     372           0 :     printf( "  - accounts_delta:\n" );
     373           0 :     if( FD_UNLIKELY( 0!=process_account_table( file, meta.slot, verbose ) ) )
     374           0 :       return errno;
     375           0 :   }
     376             : 
     377           0 :   return 0;
     378           0 : }
     379             : 
     380             : static ulong
     381             : process_txn( fd_solcap_chunk_t const * chunk,
     382             :              FILE *                    file,
     383             :              int                       verbose,
     384             :              long                      chunk_gaddr,
     385             :              ulong                     prev_slot,
     386             :              ulong                     start_slot,
     387           0 :              ulong                     end_slot ) {
     388             : 
     389           0 : if ( verbose < 3 )
     390           0 :   return 0;
     391             : 
     392           0 : # define FD_SOLCAP_TRANSACTION_FOOTPRINT (128UL)
     393           0 :   if( FD_UNLIKELY( chunk->meta_sz > FD_SOLCAP_TRANSACTION_FOOTPRINT ) ) {
     394           0 :     FD_LOG_ERR(( "invalid transaction meta size (%u)", chunk->meta_sz ));
     395           0 :   }
     396             : 
     397             :   /* Read transaction meta */
     398             : 
     399           0 :   uchar meta_buf[ 128UL ];
     400           0 :   if( FD_UNLIKELY( 0!=fseek( file, chunk_gaddr + (long)chunk->meta_coff, SEEK_SET ) ) ) {
     401           0 :     FD_LOG_ERR(( "fseek transaction meta failed (%d-%s)", errno, strerror( errno ) ));
     402           0 :   }
     403           0 :   if( FD_UNLIKELY( chunk->meta_sz != fread( meta_buf, 1UL, chunk->meta_sz, file ) ) ) {
     404           0 :     FD_LOG_ERR(( "fread transaction meta failed (%d-%s)", errno, strerror( errno ) ));
     405           0 :   }
     406             : 
     407             :   /* Deserialize transaction meta */
     408             : 
     409           0 :   pb_istream_t stream = pb_istream_from_buffer( meta_buf, chunk->meta_sz );
     410             : 
     411           0 :   fd_solcap_Transaction meta;
     412           0 :   if( FD_UNLIKELY( !pb_decode( &stream, fd_solcap_Transaction_fields, &meta ) ) ) {
     413           0 :     FD_LOG_HEXDUMP_DEBUG(( "transaction meta", meta_buf, chunk->meta_sz ));
     414           0 :     FD_LOG_ERR(( "pb_decode transaction meta failed (%s)", PB_GET_ERROR(&stream) ));
     415           0 :   }
     416             : 
     417           0 :   if ( meta.slot < start_slot || meta.slot > end_slot ) {
     418           0 :     return meta.slot;
     419           0 :   }
     420             : 
     421             :   /* Write YAML */
     422           0 :   if ( prev_slot == 0 || prev_slot != meta.slot ) {
     423           0 :     printf(
     424           0 :       "- slot: %lu\n"
     425           0 :       "  - txns:\n", meta.slot
     426           0 :     );
     427           0 :   }
     428             : 
     429           0 :   printf(
     430           0 :     "    - txn_sig:        '%s'\n"
     431           0 :     "      txn_err:         %d\n"
     432           0 :     "      cus_used:        %lu\n"
     433           0 :     "      instr_err_idx:   %d\n",
     434           0 :     FD_BASE58_ENC_64_ALLOCA( meta.txn_sig ),
     435           0 :     meta.fd_txn_err,
     436           0 :     meta.fd_cus_used,
     437           0 :     meta.instr_err_idx);
     438             : 
     439             :   /* Only print custom error if it has been set*/
     440           0 :   if ( meta.fd_txn_err == FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR) {
     441           0 :     printf( "      custom_err:      %u\n", meta.fd_custom_err );
     442           0 :   }
     443             : 
     444           0 :   if ( verbose < 4 )
     445           0 :     return meta.slot;
     446             : 
     447           0 :   if ( meta.solana_txn_err != ULONG_MAX || meta.solana_cus_used != ULONG_MAX ) {
     448           0 :     printf(
     449           0 :       "      solana_txn_err:  %lu\n"
     450           0 :       "      solana_cus_used: %lu\n",
     451           0 :       meta.solana_txn_err,
     452           0 :       meta.solana_cus_used );
     453           0 :   }
     454             : 
     455           0 :   printf(
     456           0 :     "      explorer:       'https://explorer.solana.com/tx/%s'\n"
     457           0 :     "      solscan:        'https://solscan.io/tx/%s'\n"
     458           0 :     "      solanafm:       'https://solana.fm/tx/%s'\n",
     459           0 :     FD_BASE58_ENC_64_ALLOCA( meta.txn_sig ),
     460           0 :     FD_BASE58_ENC_64_ALLOCA( meta.txn_sig ),
     461           0 :     FD_BASE58_ENC_64_ALLOCA( meta.txn_sig ) );
     462             : 
     463           0 :   return meta.slot;
     464           0 : }
     465             : 
     466             : int
     467             : main( int     argc,
     468             :       char ** argv ) {
     469             :   fd_boot( &argc, &argv );
     470             :   fd_flamenco_boot( &argc, &argv );
     471             : 
     472             :   /* Command line handling */
     473             : 
     474             :   for( int i=1; i<argc; i++ )
     475             :     if( 0==strcmp( argv[i], "--help" ) ) return usage();
     476             : 
     477             :   char const * _page_sz   = fd_env_strip_cmdline_cstr ( &argc, &argv, "--page-sz",    NULL, "gigantic" );
     478             :   ulong        page_cnt   = fd_env_strip_cmdline_ulong( &argc, &argv, "--page-cnt",   NULL, 2UL        );
     479             :   ulong        scratch_mb = fd_env_strip_cmdline_ulong( &argc, &argv, "--scratch-mb", NULL, 1024UL     );
     480             :   int          verbose    = fd_env_strip_cmdline_int  ( &argc, &argv, "-v",           NULL, 0          );
     481             :   ulong        start_slot = fd_env_strip_cmdline_ulong( &argc, &argv, "--start-slot", NULL, 0          );
     482             :   ulong        end_slot   = fd_env_strip_cmdline_ulong( &argc, &argv, "--end-slot",   NULL, ULONG_MAX  );
     483             : 
     484             :   ulong page_sz = fd_cstr_to_shmem_page_sz( _page_sz );
     485             :   if( FD_UNLIKELY( !page_sz ) ) FD_LOG_ERR(( "unsupported --page-sz" ));
     486             : 
     487             :   if( argc!=2 ) {
     488             :     fprintf( stderr, "ERROR: expected 1 argument, got %d\n", argc-1 );
     489             :     usage();
     490             :     return 1;
     491             :   }
     492             : 
     493             :   /* Create workspace and scratch allocator */
     494             : 
     495             :   fd_wksp_t * wksp = fd_wksp_new_anonymous( page_sz, page_cnt, fd_log_cpu_id(), "wksp", 0UL );
     496             :   if( FD_UNLIKELY( !wksp ) ) FD_LOG_ERR(( "fd_wksp_new_anonymous() failed" ));
     497             : 
     498             :   ulong  smax = scratch_mb << 20;
     499             :   void * smem = fd_wksp_alloc_laddr( wksp, fd_scratch_smem_align(), smax, 1UL );
     500             :   if( FD_UNLIKELY( !smem ) ) FD_LOG_ERR(( "Failed to alloc scratch mem" ));
     501             :   ulong  scratch_depth = 4UL;
     502             :   void * fmem = fd_wksp_alloc_laddr( wksp, fd_scratch_fmem_align(), fd_scratch_fmem_footprint( scratch_depth ), 2UL );
     503             :   if( FD_UNLIKELY( !fmem ) ) FD_LOG_ERR(( "Failed to alloc scratch frames" ));
     504             : 
     505             :   fd_scratch_attach( smem, fmem, smax, scratch_depth );
     506             : 
     507             :   /* Open file */
     508             : 
     509             :   char const * path = argv[ 1 ];
     510             :   FILE * file = fopen( path, "rb" );
     511             :   if( FD_UNLIKELY( !file ) )
     512             :     FD_LOG_ERR(( "fopen(%s) failed (%d-%s)", path, errno, strerror( errno ) ));
     513             : 
     514             :   /* Read file header */
     515             : 
     516             :   fd_solcap_fhdr_t fhdr[1];
     517             :   ulong n = fread( fhdr, sizeof(fd_solcap_fhdr_t), 1UL, file );
     518             :   if( FD_UNLIKELY( n!=1UL ) ) {
     519             :     FD_LOG_ERR(( "fread file header failed (%d-%s)", errno, strerror( errno ) ));
     520             :     return errno;
     521             :   }
     522             : 
     523             :   /* TODO Read file meta */
     524             : 
     525             :   /* Seek to first chunk */
     526             : 
     527             :   int err = fseek( file, (long)fhdr->chunk0_foff - (long)sizeof(fd_solcap_fhdr_t), SEEK_CUR );
     528             :   if( FD_UNLIKELY( err<0L ) ) {
     529             :     FD_LOG_ERR(( "fseek chunk0 failed (%d-%s)", errno, strerror( errno ) ));
     530             :     return errno;
     531             :   }
     532             : 
     533             :   /* Read chunks */
     534             : 
     535             :   fd_solcap_chunk_iter_t iter[1];
     536             :   fd_solcap_chunk_iter_new( iter, file );
     537             :   ulong previous_slot = 0;
     538             :   /* TODO replace this with fd_solcap_chunk_iter_find */
     539             :   for(;;) {
     540             :     long chunk_gaddr = fd_solcap_chunk_iter_next( iter );
     541             :     if( FD_UNLIKELY( chunk_gaddr<0L ) ) {
     542             :       int err = fd_solcap_chunk_iter_err( iter );
     543             :       if( err==0 ) break;
     544             :       FD_LOG_ERR(( "fd_solcap_chunk_iter_next() failed (%d-%s)", err, strerror( err ) ));
     545             :     }
     546             : 
     547             :     if( fd_solcap_chunk_iter_done( iter ) ) break;
     548             : 
     549             :     fd_solcap_chunk_t const * chunk = fd_solcap_chunk_iter_item( iter );
     550             :     if( FD_UNLIKELY( !chunk ) ) FD_LOG_ERR(( "fd_solcap_chunk_item() failed" ));
     551             : 
     552             :     /* TODO: figure out how to make solana.solcap yamls print slot */
     553             :     if( chunk->magic == FD_SOLCAP_V1_BANK_MAGIC )
     554             :       process_bank( chunk, file, verbose, chunk_gaddr, start_slot, end_slot, previous_slot != 0 );
     555             :     else if ( chunk->magic == FD_SOLCAP_V1_TRXN_MAGIC )
     556             :       previous_slot = process_txn( chunk, file, verbose, chunk_gaddr, previous_slot, start_slot, end_slot );
     557             :   }
     558             : 
     559             :   /* Cleanup */
     560             : 
     561             :   FD_LOG_NOTICE(( "Done" ));
     562             :   FD_TEST( fd_scratch_frame_used()==0UL );
     563             :   fd_wksp_free_laddr( fd_scratch_detach( NULL ) );
     564             :   fd_wksp_free_laddr( fmem                      );
     565             :   fclose( file );
     566             :   fd_flamenco_halt();
     567             :   fd_halt();
     568             :   return 0;
     569             : }

Generated by: LCOV version 1.14