LCOV - code coverage report
Current view: top level - app/ledger - main.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 875 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 19 0.0 %

          Line data    Source code
       1             : #include <errno.h>
       2             : #include "../../flamenco/fd_flamenco.h"
       3             : #include "../../flamenco/runtime/fd_hashes.h"
       4             : #include "../../flamenco/types/fd_types.h"
       5             : #include "../../flamenco/runtime/fd_runtime.h"
       6             : #include "../../flamenco/runtime/fd_runtime_public.h"
       7             : #include "../../flamenco/runtime/fd_rocksdb.h"
       8             : #include "../../flamenco/runtime/fd_txncache.h"
       9             : #include "../../flamenco/rewards/fd_rewards.h"
      10             : #include "../../ballet/base58/fd_base58.h"
      11             : #include "../../flamenco/runtime/context/fd_capture_ctx.h"
      12             : #include "../../flamenco/runtime/fd_blockstore.h"
      13             : #include "../../flamenco/shredcap/fd_shredcap.h"
      14             : #include "../../flamenco/runtime/program/fd_bpf_program_util.h"
      15             : #include "../../flamenco/snapshot/fd_snapshot.h"
      16             : 
      17             : struct fd_ledger_args {
      18             :   fd_wksp_t *           wksp;                    /* wksp for blockstore */
      19             :   fd_wksp_t *           funk_wksp;               /* wksp for funk */
      20             :   fd_wksp_t *           status_cache_wksp;       /* wksp for status cache. */
      21             :   fd_blockstore_t       blockstore_ljoin;
      22             :   fd_blockstore_t *     blockstore;              /* blockstore for replay */
      23             :   fd_funk_t             funk[1];                 /* handle to funk */
      24             :   fd_alloc_t *          alloc;                   /* handle to alloc */
      25             :   char const *          cmd;                     /* user passed command to fd_ledger */
      26             :   ulong                 start_slot;              /* start slot for offline replay */
      27             :   ulong                 end_slot;                /* end slot for offline replay */
      28             :   uint                  hashseed;                /* hashseed */
      29             :   char const *          checkpt;                 /* wksp checkpoint */
      30             :   char const *          checkpt_funk;            /* wksp checkpoint for a funk wksp */
      31             :   char const *          checkpt_status_cache;    /* status cache checkpoint */
      32             :   char const *          restore;                 /* wksp restore */
      33             :   char const *          allocator;               /* allocator used during replay (libc/wksp) */
      34             :   ulong                 shred_max;               /* maximum number of shreds*/
      35             :   ulong                 slot_history_max;        /* number of slots stored by blockstore*/
      36             :   ulong                 txns_max;                /* txns_max*/
      37             :   uint                  index_max;               /* size of funk index (same as rec max) */
      38             :   ulong                 funk_page_cnt;
      39             :   char const *          snapshot;                /* path to agave snapshot */
      40             :   char const *          incremental;             /* path to agave incremental snapshot */
      41             :   char const *          genesis;                 /* path to agave genesis */
      42             :   char const *          mini_db_dir;             /* path to minifed rocksdb that's to be created */
      43             :   int                   copy_txn_status;         /* determine if txns should be copied to the blockstore during minify/replay */
      44             :   int                   funk_only;               /* determine if only funk should be ingested */
      45             :   char const *          shredcap;                /* path to replay using shredcap instead of rocksdb */
      46             :   int                   abort_on_mismatch;       /* determine if execution should abort on mismatch*/
      47             :   char const *          capture_fpath;           /* solcap: path for solcap file to be created */
      48             :   ulong                 solcap_start_slot;       /* solcap capture start slot */
      49             :   int                   capture_txns;            /* solcap: determine if transaction results should be captured for solcap*/
      50             :   char const *          checkpt_path;            /* path to dump funk wksp checkpoints during execution*/
      51             :   ulong                 checkpt_freq;            /* how often funk wksp checkpoints will be dumped (defaults to never) */
      52             :   int                   checkpt_mismatch;        /* determine if a funk wksp checkpoint should be dumped on a mismatch*/
      53             : 
      54             :   int                   dump_instr_to_pb;        /* instruction dumping: should insns be dumped */
      55             :   int                   dump_txn_to_pb;          /* txn dumping: should txns be dumped */
      56             :   int                   dump_block_to_pb;        /* block dumping: should blocks be dumped */
      57             :   int                   dump_syscall_to_pb;      /* syscall dumping: should syscalls be dumped */
      58             :   int                   dump_elf_to_pb;          /* elf dumping: should elfs be dumped */
      59             :   ulong                 dump_proto_start_slot;   /* instruction / txn dumping: what slot to start dumping*/
      60             :   char const *          dump_proto_sig_filter;   /* instruction / txn dumping: specify txn sig to dump at */
      61             :   char const *          dump_proto_output_dir;   /* instruction / txn dumping: output directory for protobuf messages */
      62             : 
      63             :   int                   verify_funk;             /* verify funk before execution starts */
      64             :   uint                  verify_acc_hash;         /* verify account hash from the snapshot */
      65             :   uint                  check_acc_hash;          /* check account hash by reconstructing with data */
      66             :   ulong                 trash_hash;              /* trash hash to be used for negative cases*/
      67             :   ulong                 vote_acct_max;           /* max number of vote accounts */
      68             :   char const *          rocksdb_list[32];        /* max number of rocksdb dirs that can be passed in */
      69             :   ulong                 rocksdb_list_slot[32];   /* start slot for each rocksdb dir that's passed in assuming there are mulitple */
      70             :   ulong                 rocksdb_list_cnt;        /* number of rocksdb dirs passed in */
      71             :   char *                rocksdb_list_strdup;
      72             :   uint                  cluster_version[3];      /* What version of solana is the genesis block? */
      73             :   char const *          one_off_features[32];    /* List of one off feature pubkeys to enable for execution agnostic of cluster version */
      74             :   uint                  one_off_features_cnt;    /* Number of one off features */
      75             :   char *                one_off_features_strdup;
      76             :   double                allowed_mem_delta;       /* Percent of memory in the blockstore wksp that can be
      77             :                                                     used and not freed between the start of end of execution.
      78             :                                                     If the difference in usage exceeds this value, error out. */
      79             : 
      80             :   /* These values are setup and maintained before replay */
      81             :   fd_capture_ctx_t *    capture_ctx;             /* capture_ctx is used in runtime_replay for various debugging tasks */
      82             :   fd_exec_slot_ctx_t *  slot_ctx;                /* slot_ctx */
      83             :   fd_tpool_t *          tpool;                   /* thread pool for execution */
      84             :   uchar                 tpool_mem[FD_TPOOL_FOOTPRINT( FD_TILE_MAX )] __attribute__( ( aligned( FD_TPOOL_ALIGN ) ) );
      85             : 
      86             :   fd_spad_t *           exec_spads[ 128UL ];          /* bump allocators that are eventually assigned to each txn_ctx */
      87             :   ulong                 exec_spad_cnt;                /* number of bump allocators, bounded by number of threads */
      88             :   fd_spad_t *           runtime_spad;            /* bump allocator used for runtime scoped allocations */
      89             :   ulong                 thread_mem_bound;        /* how much spad is allocated by a tpool thread. The default
      90             :                                                     value is the full runtime bound. If a value of 0 is passed
      91             :                                                     in, then a reduced bound will be used. */
      92             :   ulong                 runtime_mem_bound;       /* how much to allocate for a runtime-scoped spad */
      93             : 
      94             :   fd_valloc_t           valloc; /* wksp valloc that should NOT be used for runtime allocations */
      95             : 
      96             :   char const *          lthash;
      97             : };
      98             : typedef struct fd_ledger_args fd_ledger_args_t;
      99             : 
     100             : /* Allocations ****************************************************************/
     101             : 
     102             : static void
     103           0 : init_exec_spads( fd_ledger_args_t * args, int has_tpool ) {
     104             : 
     105           0 :   FD_LOG_NOTICE(( "setting up exec_spads" ));
     106             : 
     107             :   /* Allocate memory for the account mem space. In live execution, each of
     108             :      the spad allocations should be tied to its respective execution thread.
     109             :      In the future, the spad should be allocated from its tiles' workspace.
     110             :      It is important that the exec_spads are only allocated on startup for
     111             :      performance reasons to avoid dynamic allocation in the critical path. */
     112             : 
     113           0 :   if( has_tpool ) {
     114           0 :     args->exec_spad_cnt = fd_tpool_worker_cnt( args->tpool );
     115           0 :     for( ulong i=0UL; i<fd_tpool_worker_cnt( args->tpool ); i++ ) {
     116           0 :       ulong       total_mem_sz = args->thread_mem_bound;
     117           0 :       uchar *     mem          = fd_wksp_alloc_laddr( args->wksp, FD_SPAD_ALIGN, FD_SPAD_FOOTPRINT( total_mem_sz ), 999UL );
     118           0 :       fd_spad_t * spad         = fd_spad_join( fd_spad_new( mem, total_mem_sz ) );
     119           0 :       if( FD_UNLIKELY( !spad ) ) {
     120           0 :         FD_LOG_ERR(( "failed to allocate spad" ));
     121           0 :       }
     122           0 :       args->exec_spads[ i ] = spad;
     123           0 :     }
     124           0 :   }
     125           0 : }
     126             : 
     127             : /* Runtime Replay *************************************************************/
     128             : static int
     129           0 : init_tpool( fd_ledger_args_t * ledger_args ) {
     130             : 
     131           0 :   ulong tcnt = fd_tile_cnt();
     132           0 :   fd_tpool_t * tpool = NULL;
     133             : 
     134           0 :   ulong start_idx = 1UL;
     135           0 :   if( tcnt>=1UL ) {
     136           0 :     tpool = fd_tpool_init( ledger_args->tpool_mem, tcnt, 0UL );
     137           0 :     if( tpool == NULL ) {
     138           0 :       FD_LOG_ERR(( "failed to create thread pool" ));
     139           0 :     }
     140           0 :     for( ulong i=1UL; i<tcnt; ++i ) {
     141           0 :       if( fd_tpool_worker_push( tpool, start_idx++ ) == NULL ) {
     142           0 :         FD_LOG_ERR(( "failed to launch worker" ));
     143           0 :       }
     144           0 :       else {
     145           0 :         FD_LOG_INFO(( "launched worker %lu", start_idx - 1UL ));
     146           0 :       }
     147           0 :     }
     148           0 :   }
     149             : 
     150           0 :   ledger_args->tpool = tpool;
     151             : 
     152           0 :   return 0;
     153           0 : }
     154             : 
     155             : void
     156           0 : args_cleanup( fd_ledger_args_t * ledger_args ) {
     157           0 :   if( ledger_args->rocksdb_list_strdup )     free( ledger_args->rocksdb_list_strdup );
     158           0 :   if( ledger_args->one_off_features_strdup ) free( ledger_args->one_off_features_strdup );
     159           0 : }
     160             : 
     161             : int
     162           0 : runtime_replay( fd_ledger_args_t * ledger_args ) {
     163           0 :   int ret = 0;
     164             : 
     165           0 :   fd_features_restore( ledger_args->slot_ctx, ledger_args->runtime_spad );
     166             : 
     167           0 :   fd_runtime_update_leaders( ledger_args->slot_ctx->bank, ledger_args->slot_ctx->slot, ledger_args->runtime_spad );
     168             : 
     169           0 :   fd_calculate_epoch_accounts_hash_values( ledger_args->slot_ctx );
     170             : 
     171           0 :   long              replay_time = -fd_log_wallclock();
     172           0 :   ulong             txn_cnt     = 0;
     173           0 :   ulong             slot_cnt    = 0;
     174           0 :   fd_blockstore_t * blockstore  = ledger_args->blockstore;
     175             : 
     176           0 :   ulong prev_slot  = ledger_args->slot_ctx->slot;
     177           0 :   ulong start_slot = ledger_args->slot_ctx->slot + 1;
     178             : 
     179             :   /* On demand rocksdb ingest */
     180           0 :   fd_rocksdb_t           rocks_db         = {0};
     181           0 :   fd_rocksdb_root_iter_t iter             = {0};
     182           0 :   fd_slot_meta_t         slot_meta        = {0};
     183           0 :   ulong                  curr_rocksdb_idx = 0UL;
     184             : 
     185           0 :   char * err = fd_rocksdb_init( &rocks_db, ledger_args->rocksdb_list[ 0UL ] );
     186           0 :   if( FD_UNLIKELY( err!=NULL ) ) {
     187           0 :     FD_LOG_ERR(( "fd_rocksdb_init at path=%s returned error=%s", ledger_args->rocksdb_list[ 0UL ], err ));
     188           0 :   }
     189           0 :   fd_rocksdb_root_iter_new( &iter );
     190             : 
     191           0 :   int block_found = -1;
     192           0 :   while ( block_found!=0 && start_slot<=ledger_args->end_slot ) {
     193           0 :     block_found = fd_rocksdb_root_iter_seek( &iter, &rocks_db, start_slot, &slot_meta, ledger_args->valloc );
     194           0 :     if ( block_found!=0 ) {
     195           0 :       start_slot++;
     196           0 :     }
     197           0 :   }
     198             : 
     199             :   /* Setup trash_hash */
     200           0 :   uchar trash_hash_buf[32];
     201           0 :   memset( trash_hash_buf, 0xFE, sizeof(trash_hash_buf) );
     202             : 
     203             :   /* Calculate and store wksp free size before execution. */
     204           0 :   fd_wksp_usage_t init_usage = {0};
     205           0 :   fd_wksp_usage( fd_blockstore_wksp( ledger_args->blockstore ), NULL, 0UL, &init_usage );
     206             : 
     207           0 :   ulong block_slot = start_slot;
     208           0 :   uchar aborted = 0U;
     209             : 
     210             :   // set up to let us easily jump to the end of execution
     211           0 :   do {
     212             : 
     213           0 :   if( FD_UNLIKELY( block_found!=0 ) ) {
     214           0 :     if( 0 == ledger_args->end_slot )
     215           0 :       break; // special case just letting us do the genesis block
     216           0 :     FD_LOG_ERR(( "unable to seek to any slot" ));
     217           0 :   }
     218             : 
     219           0 :   for( ulong slot = start_slot; slot<=ledger_args->end_slot && !aborted; ++slot ) {
     220             : 
     221           0 :     fd_bank_prev_slot_set( ledger_args->slot_ctx->bank, prev_slot );
     222             : 
     223           0 :     FD_LOG_DEBUG(( "reading slot %lu", slot ));
     224             : 
     225             :     /* If we have reached a new block, load one in from rocksdb to the blockstore */
     226           0 :     bool block_exists = fd_blockstore_shreds_complete( blockstore, slot);
     227           0 :     if( !block_exists && slot_meta.slot == slot ) {
     228           0 :       int err = fd_rocksdb_import_block_blockstore( &rocks_db,
     229           0 :                                                     &slot_meta, blockstore,
     230           0 :                                                     ledger_args->copy_txn_status,
     231           0 :                                                     slot == (ledger_args->trash_hash) ? trash_hash_buf : NULL,
     232           0 :                                                     ledger_args->valloc );
     233           0 :       if( FD_UNLIKELY( err ) ) {
     234           0 :         FD_LOG_ERR(( "Failed to import block %lu", start_slot ));
     235           0 :       }
     236             : 
     237             :       /* Remove the previous block from the blockstore */
     238           0 :       if( FD_LIKELY( block_slot < slot ) ) {
     239             :         /* Mark the block as successfully processed */
     240             : 
     241           0 :         fd_block_map_query_t query[1] = {0};
     242           0 :         int err = fd_block_map_prepare( blockstore->block_map, &block_slot, NULL, query, FD_MAP_FLAG_BLOCKING );
     243           0 :         fd_block_info_t * block_info = fd_block_map_query_ele( query );
     244             : 
     245           0 :         if( FD_UNLIKELY( err || block_info->slot != block_slot ) ) FD_LOG_ERR(( "failed to prepare block map query" ));
     246             : 
     247           0 :         block_info->flags = fd_uchar_clear_bit( block_info->flags, FD_BLOCK_FLAG_REPLAYING );
     248           0 :         block_info->flags = fd_uchar_set_bit( block_info->flags, FD_BLOCK_FLAG_PROCESSED );
     249             : 
     250           0 :         fd_block_map_publish( query );
     251             : 
     252             :         /* Remove the old block from the blockstore */
     253             :         /*for( uint idx = 0; idx <= slot_complete_idx; idx++ ) {
     254             :           fd_blockstore_shred_remove( blockstore, block_slot, idx );
     255             :         }*/
     256           0 :         fd_blockstore_block_allocs_remove( blockstore, block_slot );
     257           0 :         fd_blockstore_slot_remove( blockstore, block_slot );
     258           0 :       }
     259             :       /* Mark the new block as replaying */
     260           0 :       fd_block_map_query_t query[1] = {0};
     261           0 :       err = fd_block_map_prepare( blockstore->block_map, &slot, NULL, query, FD_MAP_FLAG_BLOCKING );
     262           0 :       fd_block_info_t * block_info = fd_block_map_query_ele( query );
     263           0 :       if( FD_UNLIKELY( err || block_info->slot != slot ) ) FD_LOG_ERR(( "failed to prepare block map query" ));
     264           0 :       block_info->flags = fd_uchar_set_bit( block_info->flags, FD_BLOCK_FLAG_REPLAYING );
     265           0 :       fd_block_map_publish( query );
     266             : 
     267           0 :       block_slot = slot;
     268           0 :     }
     269             : 
     270           0 :     fd_block_t * blk = fd_blockstore_block_query( blockstore, slot );
     271           0 :     if( blk == NULL ) {
     272           0 :       FD_LOG_WARNING(( "failed to read slot %lu", slot ));
     273           0 :       continue;
     274           0 :     }
     275             : 
     276           0 :     fd_bank_tick_height_set( ledger_args->slot_ctx->bank, fd_bank_max_tick_height_get( ledger_args->slot_ctx->bank ) );
     277             : 
     278           0 :     ulong * max_tick_height = fd_bank_max_tick_height_modify( ledger_args->slot_ctx->bank );
     279           0 :     ulong ticks_per_slot = fd_bank_ticks_per_slot_get( ledger_args->slot_ctx->bank );
     280           0 :     if( FD_UNLIKELY( FD_RUNTIME_EXECUTE_SUCCESS != fd_runtime_compute_max_tick_height( ticks_per_slot, slot, max_tick_height ) ) ) {
     281           0 :       FD_LOG_ERR(( "couldn't compute max tick height slot %lu ticks_per_slot %lu", slot, ticks_per_slot ));
     282           0 :     }
     283             : 
     284           0 :     ledger_args->slot_ctx->bank = fd_banks_clone_from_parent( ledger_args->slot_ctx->banks, slot, prev_slot );
     285             : 
     286           0 :     ulong blk_txn_cnt = 0UL;
     287           0 :     FD_LOG_NOTICE(( "Used memory in spad before slot=%lu %lu", slot, ledger_args->runtime_spad->mem_used ));
     288           0 :     FD_TEST( fd_runtime_block_eval_tpool( ledger_args->slot_ctx,
     289           0 :                                           slot,
     290           0 :                                           blk,
     291           0 :                                           ledger_args->capture_ctx,
     292           0 :                                           ledger_args->tpool,
     293           0 :                                           1,
     294           0 :                                           &blk_txn_cnt,
     295           0 :                                           ledger_args->exec_spads,
     296           0 :                                           ledger_args->exec_spad_cnt,
     297           0 :                                           ledger_args->runtime_spad,
     298           0 :                                           ledger_args->blockstore ) == FD_RUNTIME_EXECUTE_SUCCESS );
     299           0 :     txn_cnt += blk_txn_cnt;
     300           0 :     slot_cnt++;
     301             : 
     302           0 :     fd_hash_t expected;
     303           0 :     int err = fd_blockstore_block_hash_query( blockstore, slot, &expected );
     304           0 :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR( ( "slot %lu is missing its hash", slot ) );
     305           0 :     else if( FD_UNLIKELY( 0 != memcmp( fd_bank_poh_query( ledger_args->slot_ctx->bank ), expected.hash, sizeof(fd_hash_t) ) ) ) {
     306           0 :       char expected_hash[ FD_BASE58_ENCODED_32_SZ ];
     307           0 :       fd_acct_addr_cstr( expected_hash, expected.hash );
     308           0 :       char poh_hash[ FD_BASE58_ENCODED_32_SZ ];
     309           0 :       fd_acct_addr_cstr( poh_hash, fd_bank_poh_query( ledger_args->slot_ctx->bank )->hash );
     310           0 :       FD_LOG_WARNING(( "PoH hash mismatch! slot=%lu expected=%s, got=%s",
     311           0 :                         slot,
     312           0 :                         expected_hash,
     313           0 :                         poh_hash ));
     314             : 
     315           0 :       if( ledger_args->checkpt_mismatch ) {
     316           0 :         fd_runtime_checkpt( ledger_args->capture_ctx, ledger_args->slot_ctx, ULONG_MAX );
     317           0 :       }
     318           0 :       if( ledger_args->abort_on_mismatch ) {
     319           0 :         ret = 1;
     320           0 :         aborted = 1U;
     321           0 :         break;
     322           0 :       }
     323           0 :     }
     324             : 
     325           0 :     fd_hash_t const * bank_hash_bm = fd_bank_bank_hash_query( ledger_args->slot_ctx->bank );
     326           0 :     err = fd_blockstore_bank_hash_query( blockstore, slot, &expected );
     327           0 :     if( FD_UNLIKELY( err) ) {
     328           0 :       FD_LOG_ERR(( "slot %lu is missing its bank hash", slot ));
     329           0 :     } else if( FD_UNLIKELY( 0 != memcmp( bank_hash_bm,
     330           0 :                                          expected.hash,
     331           0 :                                          32UL ) ) ) {
     332             : 
     333           0 :       char expected_hash[ FD_BASE58_ENCODED_32_SZ ];
     334           0 :       fd_acct_addr_cstr( expected_hash, expected.hash );
     335           0 :       char bank_hash[ FD_BASE58_ENCODED_32_SZ ];
     336           0 :       fd_acct_addr_cstr( bank_hash, bank_hash_bm->hash );
     337             : 
     338           0 :       FD_LOG_WARNING(( "Bank hash mismatch! slot=%lu expected=%s, got=%s",
     339           0 :                         slot,
     340           0 :                         expected_hash,
     341           0 :                         bank_hash ));
     342             : 
     343           0 :       if( ledger_args->checkpt_mismatch ) {
     344           0 :         fd_runtime_checkpt( ledger_args->capture_ctx, ledger_args->slot_ctx, ULONG_MAX );
     345           0 :       }
     346           0 :       if( ledger_args->abort_on_mismatch ) {
     347           0 :         ret = 1;
     348           0 :         break;
     349           0 :       }
     350           0 :     }
     351             : 
     352           0 :     prev_slot = slot;
     353             : 
     354           0 :     if( slot<ledger_args->end_slot ) {
     355             :       /* TODO: This currently doesn't support switching over on slots that occur on a fork */
     356             :       /* If need to go to next rocksdb, switch over */
     357           0 :       if( FD_UNLIKELY( ledger_args->rocksdb_list_cnt>1UL &&
     358           0 :                        slot+1UL==ledger_args->rocksdb_list_slot[curr_rocksdb_idx] ) ) {
     359           0 :         curr_rocksdb_idx++;
     360           0 :         FD_LOG_WARNING(( "Switching to next rocksdb=%s", ledger_args->rocksdb_list[curr_rocksdb_idx] ));
     361           0 :         fd_rocksdb_root_iter_destroy( &iter );
     362           0 :         fd_rocksdb_destroy( &rocks_db );
     363             : 
     364           0 :         fd_memset( &rocks_db,  0, sizeof(fd_rocksdb_t)           );
     365           0 :         fd_memset( &iter,      0, sizeof(fd_rocksdb_root_iter_t) );
     366           0 :         fd_memset( &slot_meta, 0, sizeof(fd_slot_meta_t)         );
     367             : 
     368           0 :         char * err = fd_rocksdb_init( &rocks_db, ledger_args->rocksdb_list[curr_rocksdb_idx] );
     369           0 :         if( FD_UNLIKELY( err!=NULL ) ) {
     370           0 :           FD_LOG_ERR(( "fd_rocksdb_init at path=%s returned error=%s", ledger_args->rocksdb_list[curr_rocksdb_idx], err ));
     371           0 :         }
     372           0 :         fd_rocksdb_root_iter_new( &iter );
     373           0 :         int ret = fd_rocksdb_root_iter_seek( &iter, &rocks_db, slot+1UL, &slot_meta, ledger_args->valloc );
     374           0 :         if( ret<0 ) {
     375           0 :           FD_LOG_ERR(( "Failed to seek to slot %lu", slot+1UL ));
     376           0 :         }
     377           0 :       } else {
     378             :         /* Otherwise look for next slot in current rocksdb */
     379           0 :         int ret = fd_rocksdb_root_iter_next( &iter, &slot_meta, ledger_args->valloc );
     380           0 :         if( ret<0 ) {
     381           0 :           ret = fd_rocksdb_get_meta( &rocks_db, slot+1UL, &slot_meta, ledger_args->valloc );
     382           0 :           if( ret<0 ) {
     383           0 :             FD_LOG_ERR(( "Failed to get meta for slot %lu", slot+1UL ));
     384           0 :           }
     385           0 :         }
     386           0 :       }
     387           0 :     }
     388           0 :   }
     389             : 
     390           0 :   } while(0);
     391             : 
     392             :   /* Throw an error if the blockstore wksp has a usage which exceeds the allowed
     393             :      threshold. This likely indicates that a memory leak was introduced. */
     394             : 
     395           0 :   fd_wksp_usage_t final_usage = {0};
     396           0 :   fd_wksp_usage( fd_blockstore_wksp( ledger_args->blockstore ), NULL, 0UL, &final_usage );
     397             : 
     398           0 :   ulong  mem_delta      = fd_ulong_sat_sub( init_usage.free_sz, final_usage.free_sz );
     399           0 :   double pcnt_mem_delta = (double)mem_delta / (double)init_usage.free_sz;
     400           0 :   if( pcnt_mem_delta > ledger_args->allowed_mem_delta ) {
     401           0 :     FD_LOG_ERR(( "Memory usage delta (%4f%%) exceeded allowed limit (%4f%%)", 100UL * pcnt_mem_delta, 100UL * ledger_args->allowed_mem_delta ));
     402           0 :   } else {
     403           0 :     FD_LOG_NOTICE(( "Memory usage delta (%4f%%) within allowed limit (%4f%%)", 100UL * pcnt_mem_delta, 100UL * ledger_args->allowed_mem_delta ));
     404           0 :   }
     405             : 
     406             : #if FD_SPAD_TRACK_USAGE
     407             :   for( ulong i=0UL; i<ledger_args->exec_spad_cnt; i++ ) {
     408             :     fd_spad_t * spad = ledger_args->exec_spads[ i ];
     409             :     double pcnt_mem_wmark = (double)fd_spad_mem_wmark( spad ) / (double)fd_spad_mem_max( spad );
     410             :     pcnt_mem_wmark *= 100;
     411             :     FD_LOG_NOTICE(( "spad %2lu mem_wmark %10lu (%6.2f%%) mem_max %10lu", i, fd_spad_mem_wmark( spad ), pcnt_mem_wmark, fd_spad_mem_max( spad ) ));
     412             :   }
     413             : #endif
     414             : 
     415           0 :   if( ledger_args->tpool ) {
     416           0 :     fd_tpool_fini( ledger_args->tpool );
     417           0 :   }
     418             : 
     419           0 :   fd_rocksdb_root_iter_destroy( &iter );
     420           0 :   fd_rocksdb_destroy( &rocks_db );
     421             : 
     422           0 :   replay_time += fd_log_wallclock();
     423           0 :   double replay_time_s = (double)replay_time * 1e-9;
     424           0 :   double tps           = (double)txn_cnt / replay_time_s;
     425           0 :   double sec_per_slot  = replay_time_s / (double)slot_cnt;
     426           0 :   FD_LOG_NOTICE((
     427           0 :         "replay completed - slots: %lu, elapsed: %6.6f s, txns: %lu, tps: %6.6f, sec/slot: %6.6f",
     428           0 :         slot_cnt,
     429           0 :         replay_time_s,
     430           0 :         txn_cnt,
     431           0 :         tps,
     432           0 :         sec_per_slot ));
     433             : 
     434           0 :   if( slot_cnt == 0 ) {
     435           0 :     if( 0 != ledger_args->end_slot )
     436           0 :       FD_LOG_ERR(( "No slots replayed" ));
     437           0 :     else
     438           0 :       FD_LOG_WARNING(( "No slots replayed" ));
     439           0 :   }
     440             : 
     441           0 :   args_cleanup( ledger_args );
     442             : 
     443           0 :   return ret;
     444           0 : }
     445             : 
     446             : /***************************** Helpers ****************************************/
     447             : static fd_valloc_t
     448           0 : allocator_setup( fd_wksp_t * wksp ) {
     449             : 
     450           0 :   if( FD_UNLIKELY( !wksp ) ) {
     451           0 :     FD_LOG_ERR(( "workspace is NULL" ));
     452           0 :   }
     453             : 
     454           0 :   void * alloc_shmem = fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), 3UL );
     455           0 :   if( FD_UNLIKELY( !alloc_shmem ) ) { FD_LOG_ERR( ( "fd_alloc too large for workspace" ) ); }
     456           0 :   void * alloc_shalloc = fd_alloc_new( alloc_shmem, 3UL );
     457           0 :   if( FD_UNLIKELY( !alloc_shalloc ) ) { FD_LOG_ERR( ( "fd_alloc_new failed" ) ); }
     458           0 :   fd_alloc_t * alloc = fd_alloc_join( alloc_shalloc, 3UL );
     459           0 :   if( FD_UNLIKELY( !alloc ) ) { FD_LOG_ERR( ( "fd_alloc_join failed" ) ); }
     460           0 :   fd_valloc_t valloc = fd_alloc_virtual( alloc );
     461           0 :   return valloc;
     462             : 
     463             :   /* NOTE: Enable this if leak hunting */
     464             :   //return fd_backtracing_alloc_virtual( &valloc );
     465             : 
     466           0 : }
     467             : 
     468             : void
     469           0 : fd_ledger_capture_setup( fd_ledger_args_t * args ) {
     470           0 :   fd_flamenco_boot( NULL, NULL );
     471             : 
     472             :   /* Setup capture context */
     473           0 :   int has_solcap           = args->capture_fpath && args->capture_fpath[0] != '\0';
     474           0 :   int has_checkpt          = args->checkpt_path && args->checkpt_path[0] != '\0';
     475           0 :   int has_checkpt_funk     = args->checkpt_funk && args->checkpt_funk[0] != '\0';
     476           0 :   int has_dump_to_protobuf = args->dump_instr_to_pb || args->dump_txn_to_pb || args->dump_block_to_pb || args->dump_syscall_to_pb || args->dump_elf_to_pb;
     477             : 
     478           0 :   if( has_solcap || has_checkpt || has_checkpt_funk || has_dump_to_protobuf ) {
     479           0 :     FILE * capture_file = NULL;
     480             : 
     481           0 :     void * capture_ctx_mem = fd_valloc_malloc( args->valloc, FD_CAPTURE_CTX_ALIGN, FD_CAPTURE_CTX_FOOTPRINT );
     482           0 :     FD_TEST( capture_ctx_mem );
     483           0 :     fd_memset( capture_ctx_mem, 0, sizeof( fd_capture_ctx_t ) );
     484           0 :     args->capture_ctx = fd_capture_ctx_new( capture_ctx_mem );
     485             : 
     486           0 :     args->capture_ctx->checkpt_freq = ULONG_MAX;
     487           0 :     args->capture_ctx->solcap_start_slot = args->solcap_start_slot;
     488             : 
     489           0 :     if( has_solcap ) {
     490           0 :       capture_file = fopen( args->capture_fpath, "w+" );
     491           0 :       if( FD_UNLIKELY( !capture_file ) ) {
     492           0 :         FD_LOG_ERR(( "fopen(%s) failed (%d-%s)", args->capture_fpath, errno, strerror( errno ) ));
     493           0 :       }
     494           0 :       fd_solcap_writer_init( args->capture_ctx->capture, capture_file );
     495           0 :       args->capture_ctx->capture_txns = args->capture_txns;
     496           0 :     } else {
     497           0 :       args->capture_ctx->capture = NULL;
     498           0 :     }
     499             : 
     500           0 :     if( has_checkpt || has_checkpt_funk ) {
     501           0 :       args->capture_ctx->checkpt_path = ( has_checkpt ? args->checkpt_path : args->checkpt_funk );
     502           0 :       args->capture_ctx->checkpt_freq = args->checkpt_freq;
     503           0 :     }
     504           0 :     if( has_dump_to_protobuf ) {
     505           0 :       args->capture_ctx->dump_instr_to_pb      = args->dump_instr_to_pb;
     506           0 :       args->capture_ctx->dump_txn_to_pb        = args->dump_txn_to_pb;
     507           0 :       args->capture_ctx->dump_block_to_pb      = args->dump_block_to_pb;
     508           0 :       args->capture_ctx->dump_syscall_to_pb    = args->dump_syscall_to_pb;
     509           0 :       args->capture_ctx->dump_elf_to_pb        = args->dump_elf_to_pb;
     510           0 :       args->capture_ctx->dump_proto_sig_filter = args->dump_proto_sig_filter;
     511           0 :       args->capture_ctx->dump_proto_output_dir = args->dump_proto_output_dir;
     512           0 :       args->capture_ctx->dump_proto_start_slot = args->dump_proto_start_slot;
     513           0 :     }
     514           0 :   }
     515           0 : }
     516             : 
     517             : void
     518           0 : fd_ledger_main_setup( fd_ledger_args_t * args ) {
     519           0 :   fd_flamenco_boot( NULL, NULL );
     520             : 
     521             :   /* Finish other runtime setup steps */
     522           0 :   fd_features_restore( args->slot_ctx, args->runtime_spad );
     523           0 :   fd_runtime_update_leaders( args->slot_ctx->bank, args->slot_ctx->slot, args->runtime_spad );
     524           0 :   fd_calculate_epoch_accounts_hash_values( args->slot_ctx );
     525             : 
     526             :   /* After both snapshots have been loaded in, we can determine if we should
     527             :       start distributing rewards. */
     528             : 
     529           0 :   fd_rewards_recalculate_partitioned_rewards( args->slot_ctx,
     530           0 :                                               args->tpool,
     531           0 :                                               args->exec_spads,
     532           0 :                                               args->exec_spad_cnt,
     533           0 :                                               args->runtime_spad );
     534             : 
     535           0 : }
     536             : 
     537             : void
     538           0 : fd_ledger_main_teardown( fd_ledger_args_t * args ) {
     539             :   /* Flush solcap file and cleanup */
     540           0 :   if( args->capture_ctx && args->capture_ctx->capture ) {
     541           0 :     fd_solcap_writer_flush( args->capture_ctx->capture );
     542           0 :     fd_solcap_writer_delete( args->capture_ctx->capture );
     543           0 :   }
     544             : 
     545           0 :   fd_exec_slot_ctx_delete( fd_exec_slot_ctx_leave( args->slot_ctx ) );
     546           0 : }
     547             : 
     548             : void
     549             : ingest_rocksdb( char const *      file,
     550             :                 ulong             start_slot,
     551             :                 ulong             end_slot,
     552             :                 fd_blockstore_t * blockstore,
     553             :                 int               txn_status,
     554             :                 ulong             trash_hash,
     555           0 :                 fd_valloc_t       valloc ) {
     556             : 
     557           0 :   fd_rocksdb_t rocks_db;
     558           0 :   char * err = fd_rocksdb_init( &rocks_db, file );
     559           0 :   if( FD_UNLIKELY( err!=NULL ) ) {
     560           0 :     FD_LOG_ERR(( "fd_rocksdb_init returned %s", err ));
     561           0 :   }
     562             : 
     563           0 :   ulong last_slot = fd_rocksdb_last_slot( &rocks_db, &err );
     564           0 :   if( FD_UNLIKELY( err!=NULL ) ) {
     565           0 :     FD_LOG_ERR(( "fd_rocksdb_last_slot returned %s", err ));
     566           0 :   }
     567             : 
     568           0 :   if( last_slot < start_slot ) {
     569           0 :     FD_LOG_ERR(( "rocksdb blocks are older than snapshot. first=%lu last=%lu wanted=%lu",
     570           0 :                  fd_rocksdb_first_slot(&rocks_db, &err), last_slot, start_slot ));
     571           0 :   }
     572             : 
     573           0 :   FD_LOG_NOTICE(( "ingesting rocksdb from start=%lu to end=%lu", start_slot, end_slot ));
     574             : 
     575           0 :   fd_rocksdb_root_iter_t iter = {0};
     576           0 :   fd_rocksdb_root_iter_new( &iter );
     577             : 
     578           0 :   fd_slot_meta_t slot_meta = {0};
     579           0 :   fd_memset( &slot_meta, 0, sizeof(slot_meta) );
     580             : 
     581           0 :   int block_found = -1;
     582           0 :   while ( block_found!=0 && start_slot<=end_slot ) {
     583           0 :     block_found = fd_rocksdb_root_iter_seek( &iter, &rocks_db, start_slot, &slot_meta, valloc );
     584           0 :     if ( block_found!=0 ) {
     585           0 :       start_slot++;
     586           0 :     }
     587           0 :   }
     588           0 :   if( FD_UNLIKELY( block_found!=0 ) ) {
     589           0 :     FD_LOG_ERR(( "unable to seek to any slot" ));
     590           0 :   }
     591             : 
     592           0 :   uchar trash_hash_buf[32];
     593           0 :   memset( trash_hash_buf, 0xFE, sizeof(trash_hash_buf) );
     594             : 
     595           0 :   ulong blk_cnt = 0;
     596           0 :   do {
     597           0 :     ulong slot = slot_meta.slot;
     598           0 :     if( slot > end_slot ) {
     599           0 :       break;
     600           0 :     }
     601             : 
     602             :     /* Read and deshred block from RocksDB */
     603           0 :     if( blk_cnt % 100 == 0 ) {
     604           0 :       FD_LOG_WARNING(( "imported %lu blocks", blk_cnt ));
     605           0 :     }
     606             : 
     607           0 :     int err = fd_rocksdb_import_block_blockstore( &rocks_db,
     608           0 :                                                   &slot_meta,
     609           0 :                                                   blockstore,
     610           0 :                                                   txn_status,
     611           0 :                                                   (slot == trash_hash) ? trash_hash_buf : NULL,
     612           0 :                                                   valloc );
     613           0 :     if( FD_UNLIKELY( err ) ) {
     614           0 :       FD_LOG_ERR(( "fd_rocksdb_get_block failed" ));
     615           0 :     }
     616             : 
     617           0 :     ++blk_cnt;
     618             : 
     619           0 :     memset( &slot_meta, 0, sizeof(fd_slot_meta_t) );
     620             : 
     621           0 :     int ret = fd_rocksdb_root_iter_next( &iter, &slot_meta, valloc );
     622           0 :     if( ret < 0 ) {
     623             :       // FD_LOG_WARNING(("Failed for slot %lu", slot + 1));
     624           0 :       ret = fd_rocksdb_get_meta( &rocks_db, slot + 1, &slot_meta, valloc );
     625           0 :       if( ret < 0 ) {
     626           0 :         break;
     627           0 :       }
     628           0 :     }
     629             :       // FD_LOG_ERR(("fd_rocksdb_root_iter_seek returned %d", ret));
     630           0 :   } while (1);
     631             : 
     632           0 :   fd_rocksdb_root_iter_destroy( &iter );
     633           0 :   fd_rocksdb_destroy( &rocks_db );
     634             : 
     635           0 :   FD_LOG_NOTICE(( "ingested %lu blocks", blk_cnt ));
     636           0 : }
     637             : 
     638             : void
     639           0 : parse_one_off_features( fd_ledger_args_t * args, char const * one_off_features ) {
     640           0 :   if( !one_off_features ) {
     641           0 :     FD_LOG_NOTICE(( "No one-off features passed in" ));
     642           0 :     return;
     643           0 :   }
     644             : 
     645           0 :   char * one_off_features_str = strdup( one_off_features );
     646           0 :   args->one_off_features_strdup = one_off_features_str;
     647           0 :   char * token = NULL;
     648           0 :   token = strtok( one_off_features_str, "," );
     649           0 :   while( token ) {
     650           0 :     args->one_off_features[ args->one_off_features_cnt++ ] = token;
     651           0 :     token = strtok( NULL, "," );
     652           0 :   }
     653             : 
     654           0 :   FD_LOG_NOTICE(( "Found %u one off features to include", args->one_off_features_cnt ));
     655           0 : }
     656             : 
     657             : void
     658             : parse_rocksdb_list( fd_ledger_args_t * args,
     659             :                     char const *       rocksdb_list,
     660           0 :                     char const *       rocksdb_start_slots ) {
     661             :   /* First parse the paths to the different rocksdb */
     662           0 :   if( FD_UNLIKELY( !rocksdb_list ) ) {
     663           0 :     FD_LOG_NOTICE(( "No rocksdb list passed in" ));
     664           0 :     return;
     665           0 :   }
     666             : 
     667           0 :   char * rocksdb_str = strdup( rocksdb_list );
     668           0 :   args->rocksdb_list_strdup = rocksdb_str;
     669           0 :   char * token       = NULL;
     670           0 :   token = strtok( rocksdb_str, "," );
     671           0 :   while( token ) {
     672           0 :     args->rocksdb_list[ args->rocksdb_list_cnt++ ] = token;
     673           0 :     token = strtok( NULL, "," );
     674           0 :   }
     675             : 
     676             :   /* Now repeat for the start slots assuming there are multiple */
     677           0 :   if( rocksdb_start_slots == NULL && args->rocksdb_list_cnt > 1 ) {
     678           0 :     FD_LOG_ERR(( "Multiple rocksdb dirs passed in but no start slots" ));
     679           0 :   }
     680           0 :   ulong index = 0UL;
     681           0 :   if( rocksdb_start_slots ) {
     682           0 :     char * rocksdb_start_slot_str = strdup( rocksdb_start_slots );
     683           0 :     token = NULL;
     684           0 :     token = strtok( rocksdb_start_slot_str, "," );
     685           0 :     while( token ) {
     686           0 :       args->rocksdb_list_slot[ index++ ] = strtoul( token, NULL, 10 );
     687           0 :       token = strtok( NULL, "," );
     688           0 :     }
     689           0 :   }
     690             : 
     691           0 :   if( index != args->rocksdb_list_cnt - 1UL ) {
     692           0 :     FD_LOG_ERR(( "Number of rocksdb dirs passed in doesn't match number of start slots" ));
     693           0 :   }
     694           0 : }
     695             : 
     696             : void
     697           0 : init_funk( fd_ledger_args_t * args ) {
     698           0 :   ulong funk_tag = 42UL;
     699           0 :   void * funk_shmem = fd_funk_new( fd_wksp_alloc_laddr(
     700           0 :       args->funk_wksp,
     701           0 :       fd_funk_align(),
     702           0 :       fd_funk_footprint( args->txns_max, args->index_max ),
     703           0 :       funk_tag
     704           0 :     ),
     705           0 :     funk_tag,
     706           0 :     args->hashseed,
     707           0 :     args->txns_max,
     708           0 :     args->index_max
     709           0 :   );
     710           0 :   if( FD_UNLIKELY( !funk_shmem ) ) {
     711           0 :     FD_LOG_ERR(( "Failed to allocate shmem for funk" ));
     712           0 :   }
     713           0 :   fd_funk_join( args->funk, funk_shmem );
     714           0 :   FD_LOG_NOTICE(( "Funk database is at %s:0x%lx", fd_wksp_name( args->wksp ), fd_wksp_gaddr_fast( args->funk_wksp, args->funk ) ));
     715           0 : }
     716             : 
     717             : void
     718           0 : init_blockstore( fd_ledger_args_t * args ) {
     719           0 :   fd_wksp_tag_query_info_t info;
     720           0 :   ulong blockstore_tag = FD_BLOCKSTORE_MAGIC;
     721           0 :   void * shmem;
     722           0 :   if( fd_wksp_tag_query( args->wksp, &blockstore_tag, 1, &info, 1 ) > 0 ) {
     723           0 :     shmem = fd_wksp_laddr_fast( args->wksp, info.gaddr_lo );
     724           0 :     args->blockstore = fd_blockstore_join( &args->blockstore_ljoin, shmem );
     725           0 :     if( args->blockstore->shmem->magic != FD_BLOCKSTORE_MAGIC ) {
     726           0 :       FD_LOG_ERR(( "failed to join a blockstore" ));
     727           0 :     }
     728           0 :     FD_LOG_NOTICE(( "joined blockstore" ));
     729           0 :   } else {
     730           0 :     ulong txn_max = 256UL;
     731           0 :     shmem = fd_wksp_alloc_laddr( args->wksp, fd_blockstore_align(), fd_blockstore_footprint( args->shred_max, args->slot_history_max, 16, txn_max ), blockstore_tag );
     732           0 :     if( shmem == NULL ) {
     733           0 :       FD_LOG_ERR(( "failed to allocate a blockstore" ));
     734           0 :     }
     735           0 :     args->blockstore = fd_blockstore_join( &args->blockstore_ljoin, fd_blockstore_new( shmem, 1, args->hashseed, args->shred_max, args->slot_history_max, 16, txn_max ) );
     736           0 :     if( args->blockstore->shmem->magic != FD_BLOCKSTORE_MAGIC ) {
     737           0 :       fd_wksp_free_laddr( shmem );
     738           0 :       FD_LOG_ERR(( "failed to allocate a blockstore" ));
     739           0 :     }
     740           0 :     FD_LOG_NOTICE(( "allocating a new blockstore" ));
     741           0 :   }
     742           0 : }
     743             : 
     744             : void
     745           0 : checkpt( fd_ledger_args_t * args ) {
     746           0 :   if( !args->checkpt && !args->checkpt_funk && !args->checkpt_status_cache ) {
     747           0 :     FD_LOG_WARNING(( "No checkpt argument specified" ));
     748           0 :   }
     749             : 
     750           0 :   if( args->checkpt_funk ) {
     751           0 :     if( args->funk_wksp == NULL ) {
     752           0 :       FD_LOG_ERR(( "funk_wksp is NULL" ));
     753           0 :     }
     754           0 :     FD_LOG_NOTICE(( "writing funk checkpt %s", args->checkpt_funk ));
     755           0 :     unlink( args->checkpt_funk );
     756           0 :     int err = fd_wksp_checkpt( args->funk_wksp, args->checkpt_funk, 0666, 0, NULL );
     757           0 :     if( err ) {
     758           0 :       FD_LOG_ERR(( "funk checkpt failed: error %d", err ));
     759           0 :     }
     760           0 :   }
     761           0 :   if( args->checkpt ) {
     762           0 :     FD_LOG_NOTICE(( "writing %s", args->checkpt ));
     763           0 :     unlink( args->checkpt );
     764           0 :     int err = fd_wksp_checkpt( args->wksp, args->checkpt, 0666, 0, NULL );
     765           0 :     if( err ) {
     766           0 :       FD_LOG_ERR(( "checkpt failed: error %d", err ));
     767           0 :     }
     768           0 :   }
     769           0 :   if( args->checkpt_status_cache ) {
     770           0 :     FD_LOG_NOTICE(( "writing %s", args->checkpt_status_cache ));
     771           0 :     unlink( args->checkpt_status_cache );
     772           0 :     int err = fd_wksp_checkpt( args->status_cache_wksp, args->checkpt_status_cache, 0666, 0, NULL );
     773           0 :     if( err ) {
     774           0 :       FD_LOG_ERR(( "status cache checkpt failed: error %d", err ));
     775           0 :     }
     776           0 :   }
     777           0 : }
     778             : 
     779             : void
     780           0 : wksp_restore( fd_ledger_args_t * args ) {
     781           0 :   if( args->restore != NULL ) {
     782           0 :     FD_LOG_NOTICE(( "restoring wksp %s", args->restore ));
     783           0 :     fd_wksp_restore( args->wksp, args->restore, args->hashseed );
     784           0 :   }
     785           0 : }
     786             : 
     787             : /********************* Main Command Functions and Setup ***********************/
     788             : void
     789           0 : minify( fd_ledger_args_t * args ) {
     790             :     /* Example commmand:
     791             :     fd_ledger --cmd minify --rocksdb <LARGE_ROCKSDB> --minified-rocksdb <MINI_ROCKSDB>
     792             :               --start-slot <START_SLOT> --end-slot <END_SLOT> --copy-txn-status 1
     793             :   */
     794           0 :   if( args->rocksdb_list[ 0UL ] == NULL ) {
     795           0 :     FD_LOG_ERR(( "rocksdb path is NULL" ));
     796           0 :   }
     797           0 :   if( args->mini_db_dir == NULL ) {
     798           0 :     FD_LOG_ERR(( "minified rocksdb path is NULL" ));
     799           0 :   }
     800             : 
     801           0 :   args->valloc = allocator_setup( args->wksp );
     802           0 :   init_exec_spads( args, 0 );
     803             : 
     804           0 :   fd_rocksdb_t big_rocksdb;
     805           0 :   char * err = fd_rocksdb_init( &big_rocksdb, args->rocksdb_list[ 0UL ] );
     806           0 :   if( FD_UNLIKELY( err!=NULL ) ) {
     807           0 :     FD_LOG_ERR(( "fd_rocksdb_init at path=%s returned error=%s", args->rocksdb_list[ 0UL ], err ));
     808           0 :   }
     809             : 
     810             :   /* If the directory for the minified rocksdb already exists, error out */
     811           0 :   struct stat statbuf;
     812           0 :   if( stat( args->mini_db_dir, &statbuf ) == 0 ) {
     813           0 :     FD_LOG_ERR(( "path for mini_db_dir=%s already exists", args->mini_db_dir ));
     814           0 :   }
     815             : 
     816             :   /* Create a new smaller rocksdb */
     817           0 :   fd_rocksdb_t mini_rocksdb;
     818           0 :   fd_rocksdb_new( &mini_rocksdb, args->mini_db_dir );
     819             : 
     820             :   /* Correctly bound off start and end slot */
     821           0 :   ulong first_slot = fd_rocksdb_first_slot( &big_rocksdb, &err );
     822           0 :   ulong last_slot  = fd_rocksdb_last_slot( &big_rocksdb, &err );
     823           0 :   if( args->start_slot < first_slot ) { args->start_slot = first_slot; }
     824           0 :   if( args->end_slot > last_slot )    { args->end_slot = last_slot; }
     825             : 
     826           0 :   FD_LOG_NOTICE(( "copying over rocks db for range [%lu, %lu]", args->start_slot, args->end_slot ));
     827             : 
     828             :   /* Copy over all slot indexed columns */
     829           0 :   for( ulong cf_idx = 1; cf_idx < FD_ROCKSDB_CF_CNT; ++cf_idx ) {
     830           0 :     fd_rocksdb_copy_over_slot_indexed_range( &big_rocksdb, &mini_rocksdb, cf_idx,
     831           0 :                                               args->start_slot, args->end_slot );
     832           0 :   }
     833           0 :   FD_LOG_NOTICE(("copied over all slot indexed columns"));
     834             : 
     835             :   /* Copy over transactions. This is more complicated because first, a temporary
     836             :       blockstore will be populated. This will be used to look up transactions
     837             :       which can be quickly queried */
     838           0 :   if( args->copy_txn_status ) {
     839           0 :     init_blockstore( args );
     840             :     /* Ingest block range into blockstore */
     841           0 :     ingest_rocksdb( args->rocksdb_list[ 0UL ],
     842           0 :                     args->start_slot,
     843           0 :                     args->end_slot,
     844           0 :                     args->blockstore,
     845           0 :                     0,
     846           0 :                     ULONG_MAX,
     847           0 :                     args->valloc );
     848             : 
     849           0 :     fd_rocksdb_copy_over_txn_status_range( &big_rocksdb, &mini_rocksdb, args->blockstore,
     850           0 :                                            args->start_slot, args->end_slot );
     851           0 :     FD_LOG_NOTICE(( "copied over all transaction statuses" ));
     852           0 :   } else {
     853           0 :     FD_LOG_NOTICE(( "skipping copying of transaction statuses" ));
     854           0 :   }
     855             : 
     856             :   /* TODO: Currently, the address signatures column family isn't copied as it
     857             :            is indexed on the pubkey. */
     858             : 
     859           0 :   fd_rocksdb_destroy( &big_rocksdb );
     860           0 :   fd_rocksdb_destroy( &mini_rocksdb );
     861           0 : }
     862             : 
     863             : void
     864           0 : ingest( fd_ledger_args_t * args ) {
     865             :   /* Setup funk, blockstore, and slot_ctx */
     866           0 :   wksp_restore( args );
     867           0 :   init_funk( args );
     868           0 :   if( !args->funk_only ) {
     869           0 :     init_blockstore( args );
     870           0 :   }
     871             : 
     872           0 :   init_tpool( args );
     873           0 :   init_exec_spads( args, 1 );
     874             : 
     875           0 :   fd_funk_t * funk = args->funk;
     876             : 
     877           0 :   args->valloc = allocator_setup( args->wksp );
     878             : 
     879           0 :   uchar slot_ctx_mem[FD_EXEC_SLOT_CTX_FOOTPRINT] __attribute__((aligned(FD_EXEC_SLOT_CTX_ALIGN)));
     880           0 :   fd_exec_slot_ctx_t * slot_ctx = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( slot_ctx_mem ) );
     881           0 :   args->slot_ctx = slot_ctx;
     882             : 
     883           0 :   slot_ctx->funk = funk;
     884             : 
     885             :   // if( args->status_cache_wksp ) {
     886             :   //   void * status_cache_mem = fd_spad_alloc_check( spad,
     887             :   //                                                  fd_txncache_align(),
     888             :   //                                                  fd_txncache_footprint( FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS,
     889             :   //                                                                             FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS,
     890             :   //                                                                             MAX_CACHE_TXNS_PER_SLOT,
     891             :   //                                                                             FD_TXNCACHE_DEFAULT_MAX_CONSTIPATED_SLOTS ) );
     892             :   //   FD_TEST( status_cache_mem );
     893             :   //   slot_ctx->status_cache  = fd_txncache_join( fd_txncache_new( status_cache_mem,
     894             :   //                                                                FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS,
     895             :   //                                                                FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS,
     896             :   //                                                                MAX_CACHE_TXNS_PER_SLOT,
     897             :   //                                                                FD_TXNCACHE_DEFAULT_MAX_CONSTIPATED_SLOTS ) );
     898             :   //   FD_TEST( slot_ctx->status_cache );
     899             :   // }
     900             : 
     901             :   /* Load in snapshot(s) */
     902           0 :   if( args->snapshot ) {
     903           0 :     fd_snapshot_load_all( args->snapshot,
     904           0 :                           FD_SNAPSHOT_SRC_FILE,
     905           0 :                           NULL,
     906           0 :                           slot_ctx,
     907           0 :                           NULL,
     908           0 :                           args->tpool,
     909           0 :                           args->verify_acc_hash,
     910           0 :                           args->check_acc_hash ,
     911           0 :                           FD_SNAPSHOT_TYPE_FULL,
     912           0 :                           args->exec_spads,
     913           0 :                           args->exec_spad_cnt,
     914           0 :                           args->runtime_spad );
     915           0 :     FD_LOG_NOTICE(( "imported records from snapshot" ));
     916           0 :   }
     917           0 :   if( args->incremental ) {
     918           0 :     fd_snapshot_load_all( args->incremental,
     919           0 :                           FD_SNAPSHOT_SRC_FILE,
     920           0 :                           NULL,
     921           0 :                           slot_ctx,
     922           0 :                           NULL,
     923           0 :                           args->tpool,
     924           0 :                           args->verify_acc_hash,
     925           0 :                           args->check_acc_hash,
     926           0 :                           FD_SNAPSHOT_TYPE_INCREMENTAL,
     927           0 :                           args->exec_spads,
     928           0 :                           args->exec_spad_cnt,
     929           0 :                           args->runtime_spad );
     930           0 :     FD_LOG_NOTICE(( "imported records from incremental snapshot" ));
     931           0 :   }
     932             : 
     933           0 :   if( args->genesis ) {
     934           0 :     fd_runtime_read_genesis( slot_ctx, args->genesis, args->snapshot != NULL, NULL, args->runtime_spad );
     935           0 :   }
     936             : 
     937             :   /* At this point the account state has been ingested into funk. Intake rocksdb */
     938           0 :   if( args->start_slot == 0 ) {
     939           0 :     args->start_slot = slot_ctx->slot + 1;
     940           0 :   }
     941           0 :   fd_blockstore_t * blockstore = args->blockstore;
     942           0 :   if( blockstore ) {
     943           0 :     blockstore->shmem->lps = blockstore->shmem->hcs = blockstore->shmem->wmk = slot_ctx->slot;
     944           0 :   }
     945             : 
     946           0 :   if( args->funk_only ) {
     947           0 :     FD_LOG_NOTICE(( "using funk only, skipping blockstore ingest" ));
     948           0 :   } else if( args->shredcap ) {
     949           0 :     FD_LOG_NOTICE(( "using shredcap" ));
     950           0 :     fd_shredcap_populate_blockstore( args->shredcap, blockstore, args->start_slot, args->end_slot );
     951           0 :   } else if( args->rocksdb_list[ 0UL ] ) {
     952           0 :     if( args->end_slot >= slot_ctx->slot + args->slot_history_max ) {
     953           0 :       args->end_slot = slot_ctx->slot + args->slot_history_max - 1;
     954           0 :     }
     955           0 :     ingest_rocksdb( args->rocksdb_list[ 0UL ], args->start_slot, args->end_slot,
     956           0 :                     blockstore, args->copy_txn_status, args->trash_hash, args->valloc );
     957           0 :   }
     958             : 
     959             : #ifdef FD_FUNK_HANDHOLDING
     960             :   if( args->verify_funk ) {
     961             :     FD_LOG_NOTICE(( "fd_funk_verify() start" ));
     962             :     if( fd_funk_verify( funk ) ) {
     963             :       FD_LOG_ERR(( "fd_funk_verify() failed" ));
     964             :     }
     965             :   }
     966             : #endif
     967             : 
     968           0 :   checkpt( args );
     969           0 : }
     970             : 
     971             : int
     972           0 : replay( fd_ledger_args_t * args ) {
     973             :   /* Allows for ingest and direct replay. This can be done with a full checkpoint
     974             :      that contains a blockstore and funk, a checkpoint that just has funk, or directly
     975             :      using a rocksdb and snapshot.
     976             : 
     977             :     On demand block ingest is enabled by default and can be disabled with
     978             :     '--on-demand-block-ingest 0'. The number of blocks retained in a blockstore during
     979             :     on demand block ingest can be set with '--on-demand-block-history <N slots>'
     980             : 
     981             :     In order to replay from a checkpoint, use '--checkpoint <path to checkpoint>'.
     982             : 
     983             :     To use a checkpoint, but to consume blocks on demand use '--funkonly true'.
     984             :     This option MUST be used if the checkpoint was generated during a replay with
     985             :     on demand block ingest.
     986             : 
     987             :     For blocks to contain transaction status information use '--txnstatus true'
     988             : 
     989             :     Example command loading in from on demand checkpoint and replaying with on demand block ingest.
     990             :     It creates a checkpoint every 1000 slots.
     991             :     fd_ledger --funk-restore <CHECKPOINT_TO_LOAD_IN> --cmd replay --page-cnt 20
     992             :               --abort-on-mismatch 1 --tile-cpus 5-21 --allocator wksp
     993             :               --rocksdb dump/rocksdb --checkpt-path dump/checkpoint_new
     994             :               --checkpt-freq 1000 --funk-only 1 --on-demand-block-ingest 1 --funk-page-cnt 350
     995             : 
     996             :     Example command directly loading in a rocksdb and snapshot and replaying.
     997             :     fd_ledger --reset 1 --cmd replay --rocksdb dump/mainnet-257068890/rocksdb --index-max 5000000
     998             :               --end-slot 257068895 --txn-max 100 --page-cnt 16 --verify-acc-hash 1
     999             :               --snapshot dump/mainnet-257068890/snapshot-257068890-uRVtagPzKhYorycp4CRtKdWrYPij6iBxCYYXmqRvdSp.tar.zst
    1000             :               --slot-history 5000 --allocator wksp --tile-cpus 5-21 --funk-page-cnt 16
    1001             :   */
    1002             : 
    1003           0 :   args->valloc = allocator_setup( args->wksp );
    1004             : 
    1005           0 :   wksp_restore( args ); /* Restores checkpointed workspace(s) */
    1006             : 
    1007           0 :   init_funk( args ); /* Joins or creates funk based on if one exists in the workspace */
    1008           0 :   init_blockstore( args ); /* Does the same for the blockstore */
    1009             : 
    1010           0 :   init_tpool( args ); /* Sets up tpool */
    1011           0 :   init_exec_spads( args, 1 ); /* Sets up spad */
    1012             : 
    1013           0 :   uchar *      banks_mem = fd_wksp_alloc_laddr( args->wksp, fd_banks_align(), fd_banks_footprint( 8UL ), 0xABCABC123 );
    1014           0 :   fd_banks_t * banks     = fd_banks_join( fd_banks_new( banks_mem, 8UL ) );
    1015           0 :   FD_TEST( banks );
    1016             : 
    1017           0 :   void * runtime_public_mem = fd_wksp_alloc_laddr( args->wksp,
    1018           0 :     fd_runtime_public_align(),
    1019           0 :     fd_runtime_public_footprint( args->runtime_mem_bound ), 0x3E64F44C9F44366AUL );
    1020           0 :   if( FD_UNLIKELY( !runtime_public_mem ) ) {
    1021           0 :     FD_LOG_ERR(( "Unable to allocate runtime_public mem" ));
    1022           0 :   }
    1023             : 
    1024           0 :   fd_runtime_public_t * runtime_public = fd_runtime_public_join( fd_runtime_public_new( runtime_public_mem, args->runtime_mem_bound ) );
    1025           0 :   args->runtime_spad = fd_spad_join( fd_wksp_laddr( args->wksp, runtime_public->runtime_spad_gaddr ) );
    1026           0 :   if( FD_UNLIKELY( !args->runtime_spad ) ) {
    1027           0 :     FD_LOG_ERR(( "Unable to join runtime spad" ));
    1028           0 :   }
    1029             : 
    1030           0 :   fd_spad_t * spad = args->runtime_spad;
    1031             : 
    1032           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
    1033             : 
    1034             :   /* Setup slot_ctx */
    1035           0 :   fd_funk_t * funk = args->funk;
    1036             : 
    1037             :   /* TODO: This is very hacky, needs to be cleaned up */
    1038             : 
    1039           0 :   void * slot_ctx_mem        = fd_spad_alloc_check( spad, FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT );
    1040           0 :   args->slot_ctx             = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( slot_ctx_mem ) );
    1041           0 :   args->slot_ctx->funk       = funk;
    1042             : 
    1043           0 :   args->slot_ctx->banks    = banks;
    1044           0 :   FD_TEST( args->slot_ctx->banks );
    1045             : 
    1046           0 :   args->slot_ctx->bank = fd_banks_init_bank( args->slot_ctx->banks, 0UL );
    1047             : 
    1048           0 :   fd_cluster_version_t * cluster_version = fd_bank_cluster_version_modify( args->slot_ctx->bank );
    1049           0 :   cluster_version->major = args->cluster_version[0];
    1050           0 :   cluster_version->minor = args->cluster_version[1];
    1051           0 :   cluster_version->patch = args->cluster_version[2];
    1052             : 
    1053           0 :   fd_features_t * features = fd_bank_features_modify( args->slot_ctx->bank );
    1054             : 
    1055           0 :   fd_features_enable_cleaned_up( features, fd_bank_cluster_version_query( args->slot_ctx->bank ) );
    1056           0 :   fd_features_enable_one_offs( features, args->one_off_features, args->one_off_features_cnt, 0UL );
    1057             : 
    1058             :   // void * status_cache_mem = fd_spad_alloc_check( spad,
    1059             :   //     FD_TXNCACHE_ALIGN,
    1060             :   //     fd_txncache_footprint( FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS,
    1061             :   //                            FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS,
    1062             :   //                            MAX_CACHE_TXNS_PER_SLOT,
    1063             :   //                            FD_TXNCACHE_DEFAULT_MAX_CONSTIPATED_SLOTS) );
    1064             :   // args->slot_ctx->status_cache = fd_txncache_join( fd_txncache_new( status_cache_mem,
    1065             :   //                                                                   FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS,
    1066             :   //                                                                   FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS,
    1067             :   //                                                                   MAX_CACHE_TXNS_PER_SLOT,
    1068             :   //                                                                   FD_TXNCACHE_DEFAULT_MAX_CONSTIPATED_SLOTS ) );
    1069             :   // if( FD_UNLIKELY( !args->slot_ctx->status_cache ) ) {
    1070             :   //   FD_LOG_ERR(( "Status cache was not allocated" ));
    1071             :   // }
    1072             : 
    1073             :   /* Check number of records in funk. If rec_cnt == 0, then it can be assumed
    1074             :      that you need to load in snapshot(s). */
    1075             : 
    1076             :   /* Load in snapshot(s) */
    1077           0 :   if( args->snapshot ) {
    1078           0 :     fd_snapshot_load_all( args->snapshot,
    1079           0 :                           FD_SNAPSHOT_SRC_FILE,
    1080           0 :                           NULL,
    1081           0 :                           args->slot_ctx,
    1082           0 :                           NULL,
    1083           0 :                           args->tpool,
    1084           0 :                           args->verify_acc_hash,
    1085           0 :                           args->check_acc_hash,
    1086           0 :                           FD_SNAPSHOT_TYPE_FULL,
    1087           0 :                           args->exec_spads,
    1088           0 :                           args->exec_spad_cnt,
    1089           0 :                           args->runtime_spad );
    1090           0 :     FD_LOG_NOTICE(( "imported from snapshot" ));
    1091           0 :     if( args->incremental ) {
    1092           0 :       fd_snapshot_load_all( args->incremental,
    1093           0 :                             FD_SNAPSHOT_SRC_FILE,
    1094           0 :                             NULL,
    1095           0 :                             args->slot_ctx,
    1096           0 :                             NULL,
    1097           0 :                             args->tpool,
    1098           0 :                             args->verify_acc_hash,
    1099           0 :                             args->check_acc_hash,
    1100           0 :                             FD_SNAPSHOT_TYPE_INCREMENTAL,
    1101           0 :                             args->exec_spads,
    1102           0 :                             args->exec_spad_cnt,
    1103           0 :                             args->runtime_spad );
    1104           0 :       FD_LOG_NOTICE(( "imported from snapshot" ));
    1105           0 :     }
    1106           0 :   }
    1107             : 
    1108           0 :   FD_LOG_NOTICE(( "Used memory in spad after loading in snapshot %lu", args->runtime_spad->mem_used ));
    1109             : 
    1110           0 :   fd_ledger_capture_setup( args );
    1111             : 
    1112           0 :   if( args->genesis ) {
    1113           0 :     fd_runtime_read_genesis( args->slot_ctx, args->genesis, args->snapshot != NULL, args->capture_ctx, args->runtime_spad );
    1114           0 :   }
    1115             : 
    1116           0 :   fd_ledger_main_setup( args );
    1117             : 
    1118           0 :   fd_blockstore_init( args->blockstore,
    1119           0 :                       -1,
    1120           0 :                       FD_BLOCKSTORE_ARCHIVE_MIN_SIZE,
    1121           0 :                       args->slot_ctx->slot );
    1122           0 :   fd_buf_shred_pool_reset( args->blockstore->shred_pool, 0 );
    1123             : 
    1124           0 :   FD_LOG_WARNING(( "setup done" ));
    1125             : 
    1126           0 :   int ret = runtime_replay( args );
    1127             : 
    1128           0 :   fd_ledger_main_teardown( args );
    1129             : 
    1130           0 :   return ret;
    1131             : 
    1132           0 :   } FD_SPAD_FRAME_END;
    1133           0 : }
    1134             : 
    1135             : /* Parse user arguments and setup shared data structures used across commands */
    1136             : int
    1137           0 : initial_setup( int argc, char ** argv, fd_ledger_args_t * args ) {
    1138           0 :   if( FD_UNLIKELY( argc==1 ) ) {
    1139           0 :     return 1;
    1140           0 :   }
    1141             : 
    1142           0 :   fd_boot( &argc, &argv );
    1143           0 :   fd_flamenco_boot( &argc, &argv );
    1144             : 
    1145           0 :   char const * wksp_name             = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--wksp-name",             NULL, NULL                                               );
    1146           0 :   ulong        funk_page_cnt         = fd_env_strip_cmdline_ulong ( &argc, &argv, "--funk-page-cnt",         NULL, 5                                                  );
    1147           0 :   ulong        page_cnt              = fd_env_strip_cmdline_ulong ( &argc, &argv, "--page-cnt",              NULL, 5                                                  );
    1148           0 :   int          reset                 = fd_env_strip_cmdline_int   ( &argc, &argv, "--reset",                 NULL, 0                                                  );
    1149           0 :   char const * cmd                   = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--cmd",                   NULL, NULL                                               );
    1150           0 :   uint        index_max              = fd_env_strip_cmdline_uint  ( &argc, &argv, "--index-max",             NULL, 450000000                                          );
    1151           0 :   ulong        txns_max              = fd_env_strip_cmdline_ulong ( &argc, &argv, "--txn-max",               NULL,      100                                          );
    1152           0 :   int          verify_funk           = fd_env_strip_cmdline_int   ( &argc, &argv, "--verify-funky",          NULL, 0                                                  );
    1153           0 :   char const * snapshot              = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--snapshot",              NULL, NULL                                               );
    1154           0 :   char const * incremental           = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--incremental",           NULL, NULL                                               );
    1155           0 :   char const * genesis               = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--genesis",               NULL, NULL                                               );
    1156           0 :   int          copy_txn_status       = fd_env_strip_cmdline_int   ( &argc, &argv, "--copy-txn-status",       NULL, 0                                                  );
    1157           0 :   ulong        slot_history_max      = fd_env_strip_cmdline_ulong ( &argc, &argv, "--slot-history",          NULL, 100UL                                              );
    1158           0 :   ulong        shred_max             = fd_env_strip_cmdline_ulong ( &argc, &argv, "--shred-max",             NULL, 1UL << 17                                          );
    1159           0 :   ulong        start_slot            = fd_env_strip_cmdline_ulong ( &argc, &argv, "--start-slot",            NULL, 0UL                                                );
    1160           0 :   ulong        end_slot              = fd_env_strip_cmdline_ulong ( &argc, &argv, "--end-slot",              NULL, ULONG_MAX                                          );
    1161           0 :   uint         verify_acc_hash       = fd_env_strip_cmdline_uint  ( &argc, &argv, "--verify-acc-hash",       NULL, 1                                                  );
    1162           0 :   uint         check_acc_hash        = fd_env_strip_cmdline_uint  ( &argc, &argv, "--check-acc-hash",        NULL, 1                                                  );
    1163           0 :   char const * restore               = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--restore",               NULL, NULL                                               );
    1164           0 :   char const * shredcap              = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--shred-cap",             NULL, NULL                                               );
    1165           0 :   ulong        trash_hash            = fd_env_strip_cmdline_ulong ( &argc, &argv, "--trash-hash",            NULL, ULONG_MAX                                          );
    1166           0 :   char const * mini_db_dir           = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--minified-rocksdb",      NULL, NULL                                               );
    1167           0 :   int          funk_only             = fd_env_strip_cmdline_int   ( &argc, &argv, "--funk-only",             NULL, 0                                                  );
    1168           0 :   char const * checkpt               = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--checkpt",               NULL, NULL                                               );
    1169           0 :   char const * checkpt_funk          = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--checkpt-funk",          NULL, NULL                                               );
    1170           0 :   char const * capture_fpath         = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--capture-solcap",        NULL, NULL                                               );
    1171           0 :   ulong        solcap_start_slot     = fd_env_strip_cmdline_ulong ( &argc, &argv, "--solcap-start-slot",     NULL, 0                                                  );
    1172           0 :   int          capture_txns          = fd_env_strip_cmdline_int   ( &argc, &argv, "--capture-txns",          NULL, 1                                                  );
    1173           0 :   char const * checkpt_path          = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--checkpt-path",          NULL, NULL                                               );
    1174           0 :   ulong        checkpt_freq          = fd_env_strip_cmdline_ulong ( &argc, &argv, "--checkpt-freq",          NULL, ULONG_MAX                                          );
    1175           0 :   int          checkpt_mismatch      = fd_env_strip_cmdline_int   ( &argc, &argv, "--checkpt-mismatch",      NULL, 0                                                  );
    1176           0 :   char const * allocator             = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--allocator",             NULL, "wksp"                                             );
    1177           0 :   int          abort_on_mismatch     = fd_env_strip_cmdline_int   ( &argc, &argv, "--abort-on-mismatch",     NULL, 1                                                  );
    1178           0 :   int          dump_instr_to_pb      = fd_env_strip_cmdline_int   ( &argc, &argv, "--dump-insn-to-pb",       NULL, 0                                                  );
    1179           0 :   int          dump_txn_to_pb        = fd_env_strip_cmdline_int   ( &argc, &argv, "--dump-txn-to-pb",        NULL, 0                                                  );
    1180           0 :   int          dump_block_to_pb      = fd_env_strip_cmdline_int   ( &argc, &argv, "--dump-block-to-pb",      NULL, 0                                                  );
    1181           0 :   int          dump_syscall_to_pb    = fd_env_strip_cmdline_int   ( &argc, &argv, "--dump-syscall-to-pb",    NULL, 0                                                  );
    1182           0 :   int          dump_elf_to_pb        = fd_env_strip_cmdline_int   ( &argc, &argv, "--dump-elf-to-pb",        NULL, 0                                                  );
    1183           0 :   ulong        dump_proto_start_slot = fd_env_strip_cmdline_ulong ( &argc, &argv, "--dump-proto-start-slot", NULL, 0                                                  );
    1184           0 :   char const * dump_proto_sig_filter = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--dump-proto-sig-filter", NULL, NULL                                               );
    1185           0 :   char const * dump_proto_output_dir = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--dump-proto-output-dir", NULL, NULL                                               );
    1186           0 :   ulong        vote_acct_max         = fd_env_strip_cmdline_ulong ( &argc, &argv, "--vote_acct_max",         NULL, 2000000UL                                          );
    1187           0 :   char const * rocksdb_list          = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--rocksdb",               NULL, NULL                                               );
    1188           0 :   char const * rocksdb_list_starts   = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--rocksdb-starts",        NULL, NULL                                               );
    1189           0 :   char const * cluster_version       = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--cluster-version",       NULL, "2.0.0"                                            );
    1190           0 :   char const * checkpt_status_cache  = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--checkpt-status-cache",  NULL, NULL                                               );
    1191           0 :   char const * one_off_features      = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--one-off-features",      NULL, NULL                                               );
    1192           0 :   char const * lthash                = fd_env_strip_cmdline_cstr  ( &argc, &argv, "--lthash",                NULL, "false"                                            );
    1193           0 :   double       allowed_mem_delta     = fd_env_strip_cmdline_double( &argc, &argv, "--allowed-mem-delta",     NULL, 0.1                                                );
    1194           0 :   ulong        thread_mem_bound      = fd_env_strip_cmdline_ulong ( &argc, &argv, "--thread-mem-bound",      NULL, FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT );
    1195           0 :   ulong        runtime_mem_bound     = fd_env_strip_cmdline_ulong ( &argc, &argv, "--runtime-mem-bound",     NULL, (ulong)10e9                                        );
    1196             : 
    1197           0 :   if( FD_UNLIKELY( !verify_acc_hash ) ) {
    1198             :     /* We've got full snapshots that contain all 0s for the account
    1199             :        hash in account meta.  Running hash verify allows us to
    1200             :        populate the hash in account meta with real values. */
    1201           0 :     FD_LOG_WARNING(( "verify-acc-hash should be 1" ));
    1202           0 :   }
    1203             : 
    1204             :   // TODO: Add argument validation. Make sure that we aren't including any arguments that aren't parsed for
    1205             : 
    1206           0 :   char hostname[64];
    1207           0 :   gethostname( hostname, sizeof(hostname) );
    1208           0 :   ulong hashseed = fd_hash( 0, hostname, strnlen( hostname, sizeof(hostname) ) );
    1209           0 :   args->hashseed = (uint)hashseed;
    1210             : 
    1211             :   /* Setup workspace */
    1212           0 :   fd_wksp_t * wksp;
    1213           0 :   if( wksp_name == NULL ) {
    1214           0 :     FD_LOG_NOTICE(( "--wksp not specified, using an anonymous local workspace" ));
    1215           0 :     wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, page_cnt, 0, "wksp", 0UL );
    1216           0 :   } else {
    1217           0 :     fd_shmem_info_t shmem_info[1];
    1218           0 :     if( FD_UNLIKELY( fd_shmem_info( wksp_name, 0UL, shmem_info ) ) )
    1219           0 :       FD_LOG_ERR(( "unable to query region \"%s\"\n\tprobably does not exist or bad permissions", wksp_name ));
    1220           0 :     wksp = fd_wksp_attach( wksp_name );
    1221           0 :   }
    1222             : 
    1223           0 :   if( wksp == NULL ) {
    1224           0 :     FD_LOG_ERR(( "failed to attach to workspace %s", wksp_name ));
    1225           0 :   }
    1226           0 :   if( reset ) {
    1227           0 :     fd_wksp_reset( wksp, args->hashseed );
    1228           0 :   }
    1229           0 :   args->wksp = wksp;
    1230             : 
    1231           0 :   args->funk_wksp = fd_wksp_new_anonymous( FD_SHMEM_NORMAL_PAGE_SZ,
    1232           0 :     funk_page_cnt*(1UL<<18),
    1233           0 :     0,
    1234           0 :     "funk",
    1235           0 :     0
    1236           0 :   );
    1237           0 :   if( FD_UNLIKELY( !args->funk_wksp ) ) {
    1238           0 :     FD_LOG_ERR(( "failed to create funk workspace" ));
    1239           0 :   }
    1240             : 
    1241           0 :   if( checkpt_status_cache && checkpt_status_cache[0] != '\0' ) {
    1242           0 :     FD_LOG_NOTICE(( "Creating status cache wksp" ));
    1243           0 :     fd_wksp_t * status_cache_wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, 23UL, 0, "status_cache_wksp", 0UL );
    1244           0 :     fd_wksp_reset( status_cache_wksp, args->hashseed );
    1245           0 :     args->status_cache_wksp = status_cache_wksp;
    1246           0 :   } else {
    1247           0 :     args->status_cache_wksp = NULL;
    1248           0 :   }
    1249             : 
    1250             :   /* Setup alloc */
    1251           0 :   #define FD_ALLOC_TAG (422UL)
    1252           0 :   void * alloc_shmem = fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), FD_ALLOC_TAG );
    1253           0 :   if( FD_UNLIKELY( !alloc_shmem ) ) { FD_LOG_ERR( ( "fd_alloc too large for workspace" ) ); }
    1254           0 :   void * alloc_shalloc = fd_alloc_new( alloc_shmem, FD_ALLOC_TAG );
    1255           0 :   if( FD_UNLIKELY( !alloc_shalloc ) ) { FD_LOG_ERR( ( "fd_alloc_new failed" ) ); }
    1256           0 :   fd_alloc_t * alloc = fd_alloc_join( alloc_shalloc, FD_ALLOC_TAG );
    1257           0 :   args->alloc = alloc;
    1258           0 :   #undef FD_ALLOC_TAG
    1259             : 
    1260             :   /* Copy over arguments */
    1261           0 :   args->cmd                     = cmd;
    1262           0 :   args->start_slot              = start_slot;
    1263           0 :   args->end_slot                = end_slot;
    1264           0 :   args->checkpt                 = checkpt;
    1265           0 :   args->checkpt_funk            = checkpt_funk;
    1266           0 :   args->shred_max               = shred_max;
    1267           0 :   args->slot_history_max        = slot_history_max;
    1268           0 :   args->txns_max                = txns_max;
    1269           0 :   args->index_max               = index_max;
    1270           0 :   args->funk_page_cnt           = funk_page_cnt;
    1271           0 :   args->restore                 = restore;
    1272           0 :   args->mini_db_dir             = mini_db_dir;
    1273           0 :   args->funk_only               = funk_only;
    1274           0 :   args->copy_txn_status         = copy_txn_status;
    1275           0 :   args->snapshot                = snapshot;
    1276           0 :   args->incremental             = incremental;
    1277           0 :   args->genesis                 = genesis;
    1278           0 :   args->shredcap                = shredcap;
    1279           0 :   args->verify_funk             = verify_funk;
    1280           0 :   args->check_acc_hash          = check_acc_hash;
    1281           0 :   args->verify_acc_hash         = verify_acc_hash;
    1282           0 :   args->trash_hash              = trash_hash;
    1283           0 :   args->capture_fpath           = capture_fpath;
    1284           0 :   args->solcap_start_slot       = solcap_start_slot;
    1285           0 :   args->capture_txns            = capture_txns;
    1286           0 :   args->checkpt_path            = checkpt_path;
    1287           0 :   args->checkpt_freq            = checkpt_freq;
    1288           0 :   args->checkpt_mismatch        = checkpt_mismatch;
    1289           0 :   args->allocator               = allocator;
    1290           0 :   args->abort_on_mismatch       = abort_on_mismatch;
    1291           0 :   args->dump_instr_to_pb        = dump_instr_to_pb;
    1292           0 :   args->dump_txn_to_pb          = dump_txn_to_pb;
    1293           0 :   args->dump_block_to_pb        = dump_block_to_pb;
    1294           0 :   args->dump_syscall_to_pb      = dump_syscall_to_pb;
    1295           0 :   args->dump_elf_to_pb          = dump_elf_to_pb;
    1296           0 :   args->dump_proto_start_slot   = dump_proto_start_slot;
    1297           0 :   args->dump_proto_sig_filter   = dump_proto_sig_filter;
    1298           0 :   args->dump_proto_output_dir   = dump_proto_output_dir;
    1299           0 :   args->vote_acct_max           = vote_acct_max;
    1300           0 :   args->rocksdb_list_cnt        = 0UL;
    1301           0 :   args->checkpt_status_cache    = checkpt_status_cache;
    1302           0 :   args->one_off_features_cnt    = 0UL;
    1303           0 :   args->allowed_mem_delta       = allowed_mem_delta;
    1304           0 :   args->lthash                  = lthash;
    1305           0 :   args->thread_mem_bound        = thread_mem_bound ? thread_mem_bound : FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT;
    1306           0 :   args->runtime_mem_bound       = runtime_mem_bound;
    1307           0 :   parse_one_off_features( args, one_off_features );
    1308           0 :   parse_rocksdb_list( args, rocksdb_list, rocksdb_list_starts );
    1309             : 
    1310           0 :   if( FD_UNLIKELY( sscanf( cluster_version, "%u.%u.%u", &args->cluster_version[0], &args->cluster_version[1], &args->cluster_version[2] )!=3 ) ) {
    1311           0 :     FD_LOG_ERR(( "failed to decode cluster version" ));;
    1312           0 :   }
    1313             : 
    1314           0 :   if( args->rocksdb_list_cnt==1UL ) {
    1315           0 :     FD_LOG_NOTICE(( "rocksdb=%s", args->rocksdb_list[0] ));
    1316           0 :   } else {
    1317           0 :     for( ulong i=0UL; i<args->rocksdb_list_cnt; ++i ) {
    1318           0 :       FD_LOG_NOTICE(( "rocksdb_list[ %lu ]=%s slot=%lu", i, args->rocksdb_list[i], args->rocksdb_list_slot[i-1] ));
    1319           0 :     }
    1320           0 :   }
    1321             : 
    1322           0 :   return 0;
    1323           0 : }
    1324             : 
    1325             : int main( int argc, char ** argv ) {
    1326             :   /* Declaring this on the stack gets the alignment wrong when using asan */
    1327             :   fd_ledger_args_t * args = fd_alloca( alignof(fd_ledger_args_t), sizeof(fd_ledger_args_t) );
    1328             :   memset( args, 0, sizeof(fd_ledger_args_t) );
    1329             :   initial_setup( argc, argv, args );
    1330             : 
    1331             :   /* TODO: Need to implement snapshot minification. */
    1332             : 
    1333             :   if( args->cmd == NULL ) {
    1334             :     FD_LOG_ERR(( "no command specified" ));
    1335             :   } else if( strcmp( args->cmd, "replay" ) == 0 ) {
    1336             :     return replay( args );
    1337             :   } else if( strcmp( args->cmd, "ingest" ) == 0 ) {
    1338             :     ingest( args );
    1339             :   } else if( strcmp( args->cmd, "minify" ) == 0 ) {
    1340             :     minify( args );
    1341             :   } else {
    1342             :     FD_LOG_ERR(( "unknown command=%s", args->cmd ));
    1343             :   }
    1344             : 
    1345             :   return 0;
    1346             : }

Generated by: LCOV version 1.14