LCOV - code coverage report
Current view: top level - app/ledger - main.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 1034 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 21 0.0 %

          Line data    Source code
       1             : #include <stdio.h>
       2             : #include <stdlib.h>
       3             : #include <stddef.h>
       4             : #include <alloca.h>
       5             : #include <unistd.h>
       6             : #include <sys/types.h>
       7             : #include <sys/stat.h>
       8             : #include <fcntl.h>
       9             : #include <errno.h>
      10             : #include <strings.h>
      11             : #include "../../choreo/fd_choreo.h"
      12             : #include "../../disco/fd_disco.h"
      13             : #include "../../util/fd_util.h"
      14             : #include "../../flamenco/fd_flamenco.h"
      15             : #include "../../flamenco/nanopb/pb_decode.h"
      16             : #include "../../flamenco/runtime/fd_hashes.h"
      17             : #include "../../funk/fd_funk_filemap.h"
      18             : #include "../../flamenco/types/fd_types.h"
      19             : #include "../../flamenco/runtime/fd_runtime.h"
      20             : #include "../../flamenco/runtime/fd_account.h"
      21             : #include "../../flamenco/runtime/fd_rocksdb.h"
      22             : #include "../../flamenco/runtime/fd_txncache.h"
      23             : #include "../../ballet/base58/fd_base58.h"
      24             : #include "../../flamenco/types/fd_solana_block.pb.h"
      25             : #include "../../flamenco/runtime/context/fd_capture_ctx.h"
      26             : #include "../../flamenco/runtime/fd_blockstore.h"
      27             : #include "../../flamenco/runtime/program/fd_builtin_programs.h"
      28             : #include "../../flamenco/shredcap/fd_shredcap.h"
      29             : #include "../../flamenco/runtime/program/fd_bpf_program_util.h"
      30             : #include "../../flamenco/snapshot/fd_snapshot.h"
      31             : 
      32             : extern void fd_write_builtin_bogus_account( fd_exec_slot_ctx_t * slot_ctx, uchar const pubkey[ static 32 ], char const * data, ulong sz );
      33             : 
      34             : struct fd_ledger_args {
      35             :   fd_wksp_t *           wksp;                    /* wksp for blockstore */
      36             :   fd_wksp_t *           funk_wksp;               /* wksp for funk */
      37             :   fd_wksp_t *           status_cache_wksp;       /* wksp for status cache. */
      38             :   fd_blockstore_t *     blockstore;              /* blockstore for replay */
      39             :   fd_funk_t *           funk;                    /* handle to funk */
      40             :   fd_alloc_t *          alloc;                   /* handle to alloc */
      41             :   char const *          cmd;                     /* user passed command to fd_ledger */
      42             :   ulong                 start_slot;              /* start slot for offline replay */
      43             :   ulong                 end_slot;                /* end slot for offline replay */
      44             :   uint                  hashseed;                /* hashseed */
      45             :   char const *          checkpt;                 /* wksp checkpoint */
      46             :   char const *          checkpt_funk;            /* wksp checkpoint for a funk wksp */
      47             :   char const *          checkpt_archive;         /* funk archive format */
      48             :   char const *          checkpt_status_cache;    /* status cache checkpoint */
      49             :   char const *          restore;                 /* wksp restore */
      50             :   char const *          restore_funk;            /* wksp restore for a funk wksp */
      51             :   char const *          restore_archive;         /* restore from a funk archive */
      52             :   char const *          allocator;               /* allocator used during replay (libc/wksp) */
      53             :   ulong                 shred_max;               /* maximum number of shreds*/
      54             :   ulong                 slot_history_max;        /* number of slots stored by blockstore*/
      55             :   ulong                 txns_max;                /* txns_max*/
      56             :   ulong                 index_max;               /* size of funk index (same as rec max) */
      57             :   char const *          funk_file;               /* path to funk backing store */
      58             :   ulong                 funk_page_cnt;
      59             :   fd_funk_close_file_args_t funk_close_args;
      60             :   char const *          snapshot;                /* path to agave snapshot */
      61             :   char const *          incremental;             /* path to agave incremental snapshot */
      62             :   char const *          genesis;                 /* path to agave genesis */
      63             :   char const *          mini_db_dir;             /* path to minifed rocksdb that's to be created */
      64             :   int                   copy_txn_status;         /* determine if txns should be copied to the blockstore during minify/replay */
      65             :   int                   funk_only;               /* determine if only funk should be ingested */
      66             :   char const *          shredcap;                /* path to replay using shredcap instead of rocksdb */
      67             :   int                   abort_on_mismatch;       /* determine if execution should abort on mismatch*/
      68             :   int                   on_demand_block_ingest;  /* determine if block range should be ingested during execution or beforehand */
      69             :   ulong                 on_demand_block_history; /* how many blocks should the blockstore hold at once */
      70             :   ulong                 pages_pruned;            /* ledger pruning: how many pages should the pruned wksp have */
      71             :   ulong                 index_max_pruned;        /* ledger pruning: how large should the pruned funk index be */
      72             :   fd_funk_t *           pruned_funk;             /* ledger pruning: funk used by the pruned wksp */
      73             :   char const *          capture_fpath;           /* solcap: path for solcap file to be created */
      74             :   int                   capture_txns;            /* solcap: determine if transaction results should be captured for solcap*/
      75             :   char const *          checkpt_path;            /* path to dump funk wksp checkpoints during execution*/
      76             :   ulong                 checkpt_freq;            /* how often funk wksp checkpoints will be dumped (defaults to never) */
      77             :   int                   checkpt_mismatch;        /* determine if a funk wksp checkpoint should be dumped on a mismatch*/
      78             : 
      79             :   int                   dump_insn_to_pb;         /* instruction dumping: should insns be dumped */
      80             :   int                   dump_txn_to_pb;          /* txn dumping: should txns be dumped */
      81             :   ulong                 dump_proto_start_slot;   /* instruction / txn dumping: what slot to start dumping*/
      82             :   char const *          dump_proto_sig_filter;   /* instruction / txn dumping: specify txn sig to dump at */
      83             :   char const *          dump_proto_output_dir;   /* instruction / txn dumping: output directory for protobuf messages */
      84             : 
      85             :   int                   verify_funk;             /* verify funk before execution starts */
      86             :   uint                  verify_acc_hash;         /* verify account hash from the snapshot */
      87             :   uint                  check_acc_hash;          /* check account hash by reconstructing with data */
      88             :   ulong                 trash_hash;              /* trash hash to be used for negative cases*/
      89             :   ulong                 vote_acct_max;           /* max number of vote accounts */
      90             :   char const *          rocksdb_list[32];        /* max number of rocksdb dirs that can be passed in */
      91             :   ulong                 rocksdb_list_slot[32];   /* start slot for each rocksdb dir that's passed in assuming there are mulitple */
      92             :   ulong                 rocksdb_list_cnt;        /* number of rocksdb dirs passed in */
      93             :   uint                  cluster_version[3];         /* What version of solana is the genesis block? */
      94             :   char const *          one_off_features[32];    /* List of one off feature pubkeys to enable for execution agnostic of cluster version */
      95             :   uint                  one_off_features_cnt;    /* Number of one off features */
      96             : 
      97             :   /* These values are setup before replay */
      98             :   fd_capture_ctx_t *    capture_ctx;             /* capture_ctx is used in runtime_replay for various debugging tasks */
      99             :   fd_acc_mgr_t          acc_mgr[ 1UL ];          /* funk wrapper*/
     100             :   fd_exec_slot_ctx_t *  slot_ctx;                /* slot_ctx */
     101             :   fd_exec_epoch_ctx_t * epoch_ctx;               /* epoch_ctx */
     102             :   fd_tpool_t *          tpool;                   /* thread pool for execution */
     103             :   uchar                 tpool_mem[FD_TPOOL_FOOTPRINT( FD_TILE_MAX )] __attribute__( ( aligned( FD_TPOOL_ALIGN ) ) );
     104             :   fd_spad_t *           spads[ 128UL ];          /* scratchpad allocators that are eventually assigned to each txn_ctx */
     105             :   ulong                 spad_cnt;                /* number of scratchpads, bounded by number of threads */
     106             : 
     107             :   char const *      lthash;
     108             : };
     109             : typedef struct fd_ledger_args fd_ledger_args_t;
     110             : 
     111             : /* Runtime Replay *************************************************************/
     112             : static int
     113           0 : init_tpool( fd_ledger_args_t * ledger_args ) {
     114           0 :   ulong tcnt = fd_tile_cnt();
     115           0 :   uchar * tpool_scr_mem = NULL;
     116           0 :   fd_tpool_t * tpool = NULL;
     117           0 :   if( tcnt>=1UL ) {
     118           0 :     tpool = fd_tpool_init( ledger_args->tpool_mem, tcnt );
     119           0 :     if( tpool == NULL ) {
     120           0 :       FD_LOG_ERR(( "failed to create thread pool" ));
     121           0 :     }
     122           0 :     ulong scratch_sz = fd_scratch_smem_footprint( 256UL<<20UL );
     123           0 :     tpool_scr_mem = fd_valloc_malloc( ledger_args->slot_ctx->valloc, FD_SCRATCH_SMEM_ALIGN, scratch_sz*(tcnt) );
     124           0 :     if( tpool_scr_mem == NULL ) {
     125           0 :       FD_LOG_ERR( ( "failed to allocate thread pool scratch space" ) );
     126           0 :     }
     127           0 :     for( ulong i=1UL; i<tcnt; ++i ) {
     128           0 :       if( fd_tpool_worker_push( tpool, i, tpool_scr_mem + scratch_sz*(i-1UL), scratch_sz ) == NULL ) {
     129           0 :         FD_LOG_ERR(( "failed to launch worker" ));
     130           0 :       }
     131           0 :       else {
     132           0 :         FD_LOG_NOTICE(( "launched worker" ));
     133           0 :       }
     134           0 :     }
     135           0 :   }
     136           0 :   ledger_args->tpool = tpool;
     137           0 :   return 0;
     138           0 : }
     139             : 
     140             : int
     141           0 : runtime_replay( fd_ledger_args_t * ledger_args ) {
     142           0 :   fd_features_restore( ledger_args->slot_ctx );
     143             : 
     144           0 :   fd_runtime_update_leaders( ledger_args->slot_ctx, ledger_args->slot_ctx->slot_bank.slot );
     145             : 
     146           0 :   fd_calculate_epoch_accounts_hash_values( ledger_args->slot_ctx );
     147             : 
     148           0 :   long              replay_time = -fd_log_wallclock();
     149           0 :   ulong             txn_cnt     = 0;
     150           0 :   ulong             slot_cnt    = 0;
     151           0 :   fd_blockstore_t * blockstore  = ledger_args->slot_ctx->blockstore;
     152             : 
     153           0 :   ulong prev_slot  = ledger_args->slot_ctx->slot_bank.slot;
     154           0 :   ulong start_slot = ledger_args->slot_ctx->slot_bank.slot + 1;
     155             : 
     156             :   /* On demand rocksdb ingest */
     157           0 :   fd_rocksdb_t           rocks_db         = {0};
     158           0 :   fd_rocksdb_root_iter_t iter             = {0};
     159           0 :   fd_slot_meta_t         slot_meta        = {0};
     160           0 :   ulong                  curr_rocksdb_idx = 0UL;
     161           0 :   if( ledger_args->on_demand_block_ingest ) {
     162           0 :     char * err = fd_rocksdb_init( &rocks_db, ledger_args->rocksdb_list[ 0UL ] );
     163           0 :     if( FD_UNLIKELY( err!=NULL ) ) {
     164           0 :       FD_LOG_ERR(( "fd_rocksdb_init at path=%s returned error=%s", ledger_args->rocksdb_list[ 0UL ], err ));
     165           0 :     }
     166           0 :     fd_rocksdb_root_iter_new( &iter );
     167           0 :     if( fd_rocksdb_root_iter_seek( &iter, &rocks_db, start_slot, &slot_meta, ledger_args->slot_ctx->valloc ) ) {
     168           0 :       FD_LOG_ERR(( "unable to seek to first slot" ));
     169           0 :     }
     170           0 :   }
     171             : 
     172           0 :   if( ledger_args->capture_ctx && ledger_args->capture_ctx->pruned_funk != NULL ) {
     173             :     /* If prune enabled: setup rent partitions */
     174           0 :     fd_funk_start_write( ledger_args->capture_ctx->pruned_funk );
     175           0 :     fd_funk_t * funk = ledger_args->slot_ctx->acc_mgr->funk;
     176           0 :     fd_wksp_t * wksp = fd_funk_wksp( funk );
     177           0 :     fd_funk_partvec_t * partvec = fd_funk_get_partvec( funk, wksp );
     178           0 :     fd_funk_t * pruned_funk = ledger_args->capture_ctx->pruned_funk;
     179           0 :     fd_funk_set_num_partitions( pruned_funk, partvec->num_part );
     180           0 :     fd_funk_end_write( ledger_args->capture_ctx->pruned_funk );
     181           0 :   }
     182             : 
     183             :   /* Setup trash_hash */
     184           0 :   uchar trash_hash_buf[32];
     185           0 :   memset( trash_hash_buf, 0xFE, sizeof(trash_hash_buf) );
     186             : 
     187           0 :   for( ulong slot = start_slot; slot <= ledger_args->end_slot; ++slot ) {
     188           0 :     ledger_args->slot_ctx->slot_bank.prev_slot = prev_slot;
     189           0 :     ledger_args->slot_ctx->slot_bank.slot      = slot;
     190             : 
     191           0 :     FD_LOG_DEBUG(( "reading slot %lu", slot ));
     192             : 
     193           0 :     if( ledger_args->capture_ctx && ledger_args->capture_ctx->pruned_funk != NULL ) {
     194           0 :       fd_funk_start_write( ledger_args->capture_ctx->pruned_funk );
     195           0 :       fd_runtime_collect_rent_accounts_prune( slot, ledger_args->slot_ctx, ledger_args->capture_ctx );
     196           0 :       fd_funk_end_write( ledger_args->capture_ctx->pruned_funk );
     197           0 :     }
     198             : 
     199           0 :     if( ledger_args->on_demand_block_ingest ) {
     200           0 :       if( fd_blockstore_block_query( blockstore, slot ) == NULL && slot_meta.slot == slot ) {
     201           0 :         int err = fd_rocksdb_import_block_blockstore( &rocks_db, &slot_meta, blockstore,
     202           0 :                                                       ledger_args->copy_txn_status, slot == (ledger_args->trash_hash) ? trash_hash_buf : NULL );
     203           0 :         if( FD_UNLIKELY( err ) ) {
     204           0 :           FD_LOG_ERR(( "Failed to import block %lu", start_slot ));
     205           0 :         }
     206           0 :       }
     207           0 :       fd_blockstore_slot_remove( blockstore, slot - ledger_args->on_demand_block_history );
     208           0 :     }
     209             : 
     210           0 :     fd_blockstore_start_read( blockstore );
     211           0 :     fd_block_t * blk = fd_blockstore_block_query( blockstore, slot );
     212           0 :     if( blk == NULL ) {
     213           0 :       FD_LOG_WARNING( ( "failed to read slot %lu", slot ) );
     214           0 :       fd_blockstore_end_read( blockstore );
     215           0 :       continue;
     216           0 :     }
     217             : 
     218           0 :     uchar * val = fd_blockstore_block_data_laddr( blockstore, blk );
     219           0 :     ulong   sz  = blk->data_sz;
     220           0 :     fd_blockstore_end_read( blockstore );
     221             : 
     222           0 :     ulong blk_txn_cnt = 0;
     223           0 :     FD_TEST( fd_runtime_block_eval_tpool( ledger_args->slot_ctx,
     224           0 :                                           ledger_args->capture_ctx,
     225           0 :                                           val,
     226           0 :                                           sz,
     227           0 :                                           ledger_args->tpool,
     228           0 :                                           1,
     229           0 :                                           &blk_txn_cnt,
     230           0 :                                           ledger_args->spads,
     231           0 :                                           ledger_args->spad_cnt ) == FD_RUNTIME_EXECUTE_SUCCESS );
     232           0 :     txn_cnt += blk_txn_cnt;
     233           0 :     slot_cnt++;
     234             : 
     235           0 :     fd_blockstore_start_read( blockstore );
     236           0 :     fd_hash_t const * expected = fd_blockstore_block_hash_query( blockstore, slot );
     237           0 :     if( FD_UNLIKELY( !expected ) ) FD_LOG_ERR( ( "slot %lu is missing its hash", slot ) );
     238           0 :     else if( FD_UNLIKELY( 0 != memcmp( ledger_args->slot_ctx->slot_bank.poh.hash, expected->hash, 32UL ) ) ) {
     239           0 :       char expected_hash[ FD_BASE58_ENCODED_32_SZ ];
     240           0 :       fd_acct_addr_cstr( expected_hash, expected->hash );
     241           0 :       char poh_hash[ FD_BASE58_ENCODED_32_SZ ];
     242           0 :       fd_acct_addr_cstr( poh_hash, ledger_args->slot_ctx->slot_bank.poh.hash );
     243           0 :       FD_LOG_WARNING(( "PoH hash mismatch! slot=%lu expected=%s, got=%s",
     244           0 :                         slot,
     245           0 :                         expected_hash,
     246           0 :                         poh_hash ));
     247             : 
     248           0 :       if( ledger_args->checkpt_mismatch ) {
     249           0 :         fd_runtime_checkpt( ledger_args->capture_ctx, ledger_args->slot_ctx, ULONG_MAX );
     250           0 :       }
     251           0 :       if( ledger_args->abort_on_mismatch ) {
     252           0 :         fd_blockstore_end_read( blockstore );
     253           0 :         return 1;
     254           0 :       }
     255           0 :     }
     256             : 
     257           0 :     expected = fd_blockstore_bank_hash_query( blockstore, slot );
     258           0 :     if( FD_UNLIKELY( !expected ) ) {
     259           0 :       FD_LOG_ERR(( "slot %lu is missing its bank hash", slot ));
     260           0 :     } else if( FD_UNLIKELY( 0 != memcmp( ledger_args->slot_ctx->slot_bank.banks_hash.hash,
     261           0 :                                          expected->hash,
     262           0 :                                          32UL ) ) ) {
     263             : 
     264           0 :       char expected_hash[ FD_BASE58_ENCODED_32_SZ ];
     265           0 :       fd_acct_addr_cstr( expected_hash, expected->hash );
     266           0 :       char bank_hash[ FD_BASE58_ENCODED_32_SZ ];
     267           0 :       fd_acct_addr_cstr( bank_hash, ledger_args->slot_ctx->slot_bank.banks_hash.hash );
     268             : 
     269           0 :       FD_LOG_WARNING(( "Bank hash mismatch! slot=%lu expected=%s, got=%s",
     270           0 :                         slot,
     271           0 :                         expected_hash,
     272           0 :                         bank_hash ));
     273             : 
     274           0 :       if( ledger_args->checkpt_mismatch ) {
     275           0 :         fd_runtime_checkpt( ledger_args->capture_ctx, ledger_args->slot_ctx, ULONG_MAX );
     276           0 :       }
     277           0 :       if( ledger_args->abort_on_mismatch ) {
     278           0 :         fd_blockstore_end_read( blockstore );
     279           0 :         return 1;
     280           0 :       }
     281           0 :     }
     282           0 :     fd_blockstore_end_read( blockstore );
     283             : 
     284           0 :     prev_slot = slot;
     285             : 
     286           0 :     if( ledger_args->on_demand_block_ingest && slot<ledger_args->end_slot ) {
     287             :       /* TODO: This currently doesn't support switching over on slots that occur
     288             :          on a fork */
     289             :       /* If need to go to next rocksdb, switch over */
     290           0 :       if( FD_UNLIKELY( ledger_args->rocksdb_list_cnt>1UL &&
     291           0 :                        slot+1UL==ledger_args->rocksdb_list_slot[curr_rocksdb_idx] ) ) {
     292           0 :         curr_rocksdb_idx++;
     293           0 :         FD_LOG_WARNING(( "Switching to next rocksdb=%s", ledger_args->rocksdb_list[curr_rocksdb_idx] ));
     294           0 :         fd_rocksdb_root_iter_destroy( &iter );
     295           0 :         fd_rocksdb_destroy( &rocks_db );
     296             : 
     297           0 :         fd_memset( &rocks_db,  0, sizeof(fd_rocksdb_t)           );
     298           0 :         fd_memset( &iter,      0, sizeof(fd_rocksdb_root_iter_t) );
     299           0 :         fd_memset( &slot_meta, 0, sizeof(fd_slot_meta_t)         );
     300             : 
     301           0 :         char * err = fd_rocksdb_init( &rocks_db, ledger_args->rocksdb_list[curr_rocksdb_idx] );
     302           0 :         if( FD_UNLIKELY( err!=NULL ) ) {
     303           0 :           FD_LOG_ERR(( "fd_rocksdb_init at path=%s returned error=%s", ledger_args->rocksdb_list[curr_rocksdb_idx], err ));
     304           0 :         }
     305           0 :         fd_rocksdb_root_iter_new( &iter );
     306           0 :         int ret = fd_rocksdb_root_iter_seek( &iter, &rocks_db, slot+1UL, &slot_meta, ledger_args->slot_ctx->valloc );
     307           0 :         if( ret<0 ) {
     308           0 :           FD_LOG_ERR(( "Failed to seek to slot %lu", slot+1UL ));
     309           0 :         }
     310           0 :       } else {
     311             :         /* Otherwise look for next slot in current rocksdb */
     312           0 :         int ret = fd_rocksdb_root_iter_next( &iter, &slot_meta, ledger_args->slot_ctx->valloc );
     313           0 :         if( ret<0 ) {
     314           0 :           ret = fd_rocksdb_get_meta( &rocks_db, slot+1UL, &slot_meta, ledger_args->slot_ctx->valloc );
     315           0 :           if( ret<0 ) {
     316           0 :             FD_LOG_ERR(( "Failed to get meta for slot %lu", slot+1UL ));
     317           0 :           }
     318           0 :         }
     319           0 :       }
     320           0 :     }
     321           0 :   }
     322             : 
     323           0 :   if( ledger_args->tpool ) {
     324           0 :     fd_tpool_fini( ledger_args->tpool );
     325           0 :   }
     326             : 
     327           0 :   if( ledger_args->on_demand_block_ingest ) {
     328           0 :     fd_rocksdb_root_iter_destroy( &iter );
     329           0 :     fd_rocksdb_destroy( &rocks_db );
     330           0 :   }
     331             : 
     332           0 :   replay_time += fd_log_wallclock();
     333           0 :   double replay_time_s = (double)replay_time * 1e-9;
     334           0 :   double tps           = (double)txn_cnt / replay_time_s;
     335           0 :   double sec_per_slot  = replay_time_s / (double)slot_cnt;
     336           0 :   FD_LOG_NOTICE((
     337           0 :         "replay completed - slots: %lu, elapsed: %6.6f s, txns: %lu, tps: %6.6f, sec/slot: %6.6f",
     338           0 :         slot_cnt,
     339           0 :         replay_time_s,
     340           0 :         txn_cnt,
     341           0 :         tps,
     342           0 :         sec_per_slot ));
     343             : 
     344           0 :   if ( slot_cnt == 0 ) {
     345           0 :     FD_LOG_ERR(( "No slots replayed" ));
     346           0 :   }
     347             : 
     348           0 :   return 0;
     349           0 : }
     350             : 
     351             : /***************************** Helpers ****************************************/
     352           0 : fd_valloc_t allocator_setup( fd_wksp_t * wksp, char const * allocator ) {
     353           0 :   if( strcmp( allocator, "libc" ) == 0 ) {
     354           0 :     return fd_libc_alloc_virtual();
     355           0 :   }
     356             : 
     357           0 :   if( strcmp( allocator, "wksp" ) != 0 ) {
     358           0 :     FD_LOG_ERR( ( "unknown allocator specified" ) );
     359           0 :   }
     360             : 
     361           0 :   FD_TEST( wksp );
     362             : 
     363           0 :   void * alloc_shmem =
     364           0 :       fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), 3UL );
     365           0 :   if( FD_UNLIKELY( !alloc_shmem ) ) { FD_LOG_ERR( ( "fd_alloc too large for workspace" ) ); }
     366           0 :   void * alloc_shalloc = fd_alloc_new( alloc_shmem, 3UL );
     367           0 :   if( FD_UNLIKELY( !alloc_shalloc ) ) { FD_LOG_ERR( ( "fd_allow_new failed" ) ); }
     368           0 :   fd_alloc_t * alloc = fd_alloc_join( alloc_shalloc, 3UL );
     369           0 :   if( FD_UNLIKELY( !alloc ) ) { FD_LOG_ERR( ( "fd_alloc_join failed" ) ); }
     370           0 :   return fd_alloc_virtual( alloc );
     371           0 : }
     372             : 
     373             : void
     374           0 : fd_ledger_main_setup( fd_ledger_args_t * args ) {
     375           0 :   fd_flamenco_boot( NULL, NULL );
     376           0 :   fd_funk_t * funk = args->funk;
     377             : 
     378             :   /* Setup valloc */
     379           0 :   fd_valloc_t valloc = args->slot_ctx->valloc;
     380             : 
     381             :   /* Setup capture context */
     382           0 :   int has_solcap           = args->capture_fpath && args->capture_fpath[0] != '\0';
     383           0 :   int has_checkpt          = args->checkpt_path && args->checkpt_path[0] != '\0';
     384           0 :   int has_checkpt_funk     = args->checkpt_funk && args->checkpt_funk[0] != '\0';
     385           0 :   int has_checkpt_arch     = args->checkpt_archive && args->checkpt_archive[0] != '\0';
     386           0 :   int has_prune            = args->pruned_funk != NULL;
     387           0 :   int has_dump_to_protobuf = args->dump_insn_to_pb || args->dump_txn_to_pb;
     388             : 
     389           0 :   if( has_solcap || has_checkpt || has_checkpt_funk || has_checkpt_arch || has_prune || has_dump_to_protobuf ) {
     390           0 :     FILE * capture_file = NULL;
     391             : 
     392           0 :     void * capture_ctx_mem = fd_valloc_malloc( valloc, FD_CAPTURE_CTX_ALIGN, FD_CAPTURE_CTX_FOOTPRINT );
     393           0 :     FD_TEST( capture_ctx_mem );
     394           0 :     fd_memset( capture_ctx_mem, 0, sizeof( fd_capture_ctx_t ) );
     395           0 :     args->capture_ctx = fd_capture_ctx_new( capture_ctx_mem );
     396             : 
     397           0 :     args->capture_ctx->checkpt_freq = ULONG_MAX;
     398             : 
     399           0 :     if( has_solcap ) {
     400           0 :       capture_file = fopen( args->capture_fpath, "w+" );
     401           0 :       if( FD_UNLIKELY( !capture_file ) ) {
     402           0 :         FD_LOG_ERR(( "fopen(%s) failed (%d-%s)", args->capture_fpath, errno, strerror( errno ) ));
     403           0 :       }
     404           0 :       fd_solcap_writer_init( args->capture_ctx->capture, capture_file );
     405           0 :       args->capture_ctx->capture_txns = args->capture_txns;
     406           0 :     } else {
     407           0 :       args->capture_ctx->capture = NULL;
     408           0 :     }
     409             : 
     410           0 :     if( has_checkpt || has_checkpt_funk || has_checkpt_arch ) {
     411           0 :       args->capture_ctx->checkpt_path = ( has_checkpt ? args->checkpt_path : args->checkpt_funk );
     412           0 :       args->capture_ctx->checkpt_archive = args->checkpt_archive;
     413           0 :       args->capture_ctx->checkpt_freq = args->checkpt_freq;
     414           0 :     }
     415           0 :     if( has_prune ) {
     416           0 :       args->capture_ctx->pruned_funk = args->pruned_funk;
     417           0 :     }
     418           0 :     if( has_dump_to_protobuf ) {
     419           0 :       args->capture_ctx->dump_insn_to_pb       = args->dump_insn_to_pb;
     420           0 :       args->capture_ctx->dump_txn_to_pb        = args->dump_txn_to_pb;
     421           0 :       args->capture_ctx->dump_proto_sig_filter = args->dump_proto_sig_filter;
     422           0 :       args->capture_ctx->dump_proto_output_dir = args->dump_proto_output_dir;
     423           0 :       args->capture_ctx->dump_proto_start_slot = args->dump_proto_start_slot;
     424           0 :     }
     425           0 :   }
     426             : 
     427           0 :   fd_runtime_recover_banks( args->slot_ctx, 0, args->genesis==NULL );
     428             : 
     429             :   /* Finish other runtime setup steps */
     430           0 :   fd_funk_start_write( funk );
     431           0 :   fd_features_restore( args->slot_ctx );
     432           0 :   fd_runtime_update_leaders( args->slot_ctx, args->slot_ctx->slot_bank.slot );
     433           0 :   fd_calculate_epoch_accounts_hash_values( args->slot_ctx );
     434           0 :   fd_bpf_scan_and_create_bpf_program_cache_entry( args->slot_ctx, args->slot_ctx->funk_txn );
     435           0 :   fd_funk_end_write( funk );
     436             : 
     437             :   /* Allocate memory for the account scratch space. In live execution, each of
     438             :      the spad allocations should be tied to its respective execution thread.
     439             :      In the future, the spad should be allocated from its tiles' workspace.
     440             :      It is important that the spads are only allocated on startup for
     441             :      performance reasons to avoid dynamic allocation in the critical path. */
     442             : 
     443           0 :   args->spad_cnt = fd_tpool_worker_cnt( args->tpool );
     444           0 :   for( ulong i=0UL; i<args->spad_cnt; i++ ) {
     445           0 :     ulong       total_mem_sz = fd_spad_footprint( MAX_TX_ACCOUNT_LOCKS * fd_ulong_align_up( FD_ACC_TOT_SZ_MAX, FD_ACCOUNT_REC_ALIGN ) );
     446           0 :     uchar *     mem          = fd_wksp_alloc_laddr( args->wksp, FD_SPAD_ALIGN, total_mem_sz, 999UL );
     447           0 :     fd_spad_t * spad         = fd_spad_join( fd_spad_new( mem, total_mem_sz ) );
     448           0 :     if( FD_UNLIKELY( !spad ) ) {
     449           0 :       FD_LOG_ERR(( "failed to allocate spad" ));
     450           0 :     }
     451           0 :     args->spads[ i ] = spad;
     452           0 :   }
     453             : 
     454           0 : }
     455             : 
     456             : void
     457           0 : fd_ledger_main_teardown( fd_ledger_args_t * args ) {
     458             :   /* Flush solcap file and cleanup */
     459           0 :   if( args->capture_ctx && args->capture_ctx->capture ) {
     460           0 :     fd_solcap_writer_flush( args->capture_ctx->capture );
     461           0 :     fd_solcap_writer_delete( args->capture_ctx->capture );
     462           0 :   }
     463           0 :   fd_exec_epoch_ctx_delete( fd_exec_epoch_ctx_leave( args->epoch_ctx ) );
     464           0 :   fd_exec_slot_ctx_delete( fd_exec_slot_ctx_leave( args->slot_ctx ) );
     465           0 : }
     466             : 
     467             : void
     468             : ingest_rocksdb( fd_alloc_t *      alloc,
     469             :                 char const *      file,
     470             :                 ulong             start_slot,
     471             :                 ulong             end_slot,
     472             :                 fd_blockstore_t * blockstore,
     473             :                 int txn_status,
     474           0 :                 ulong trash_hash ) {
     475             : 
     476           0 :   fd_valloc_t valloc = fd_alloc_virtual( alloc );
     477           0 :   fd_rocksdb_t rocks_db;
     478           0 :   char * err = fd_rocksdb_init( &rocks_db, file );
     479           0 :   if( FD_UNLIKELY( err!=NULL ) ) {
     480           0 :     FD_LOG_ERR(( "fd_rocksdb_init returned %s", err ));
     481           0 :   }
     482             : 
     483           0 :   ulong last_slot = fd_rocksdb_last_slot( &rocks_db, &err );
     484           0 :   if( FD_UNLIKELY( err!=NULL ) ) {
     485           0 :     FD_LOG_ERR(( "fd_rocksdb_last_slot returned %s", err ));
     486           0 :   }
     487             : 
     488           0 :   if( last_slot < start_slot ) {
     489           0 :     FD_LOG_ERR(( "rocksdb blocks are older than snapshot. first=%lu last=%lu wanted=%lu",
     490           0 :                  fd_rocksdb_first_slot(&rocks_db, &err), last_slot, start_slot ));
     491           0 :   }
     492             : 
     493           0 :   FD_LOG_NOTICE(( "ingesting rocksdb from start=%lu to end=%lu", start_slot, end_slot ));
     494             : 
     495           0 :   fd_rocksdb_root_iter_t iter = {0};
     496           0 :   fd_rocksdb_root_iter_new( &iter );
     497             : 
     498           0 :   fd_slot_meta_t slot_meta = {0};
     499           0 :   fd_memset( &slot_meta, 0, sizeof(slot_meta) );
     500             : 
     501           0 :   int ret = fd_rocksdb_root_iter_seek( &iter, &rocks_db, start_slot, &slot_meta, valloc );
     502           0 :   if( ret < 0 ) {
     503           0 :     FD_LOG_ERR(( "fd_rocksdb_root_iter_seek returned %d", ret ));
     504           0 :   }
     505             : 
     506           0 :   uchar trash_hash_buf[32];
     507           0 :   memset( trash_hash_buf, 0xFE, sizeof(trash_hash_buf) );
     508             : 
     509           0 :   ulong blk_cnt = 0;
     510           0 :   do {
     511           0 :     ulong slot = slot_meta.slot;
     512           0 :     if( slot > end_slot ) {
     513           0 :       break;
     514           0 :     }
     515             : 
     516             :     /* Read and deshred block from RocksDB */
     517           0 :     if( blk_cnt % 100 == 0 ) {
     518           0 :       FD_LOG_WARNING(( "imported %lu blocks", blk_cnt ));
     519           0 :     }
     520             : 
     521           0 :     int err = fd_rocksdb_import_block_blockstore( &rocks_db, &slot_meta, blockstore, txn_status,
     522           0 :                                                   (slot == trash_hash) ? trash_hash_buf : NULL );
     523           0 :     if( FD_UNLIKELY( err ) ) {
     524           0 :       FD_LOG_ERR(( "fd_rocksdb_get_block failed" ));
     525           0 :     }
     526             : 
     527           0 :     ++blk_cnt;
     528             : 
     529           0 :     fd_bincode_destroy_ctx_t ctx = { .valloc = valloc };
     530           0 :     fd_slot_meta_destroy( &slot_meta, &ctx );
     531             : 
     532           0 :     ret = fd_rocksdb_root_iter_next( &iter, &slot_meta, valloc );
     533           0 :     if( ret < 0 ) {
     534             :       // FD_LOG_WARNING(("Failed for slot %lu", slot + 1));
     535           0 :       ret = fd_rocksdb_get_meta( &rocks_db, slot + 1, &slot_meta, valloc );
     536           0 :       if( ret < 0 ) {
     537           0 :         break;
     538           0 :       }
     539           0 :     }
     540             :       // FD_LOG_ERR(("fd_rocksdb_root_iter_seek returned %d", ret));
     541           0 :   } while (1);
     542             : 
     543           0 :   fd_rocksdb_root_iter_destroy( &iter );
     544           0 :   fd_rocksdb_destroy( &rocks_db );
     545             : 
     546           0 :   FD_LOG_NOTICE(( "ingested %lu blocks", blk_cnt ));
     547           0 : }
     548             : 
     549             : void
     550           0 : parse_one_off_features( fd_ledger_args_t * args, char const * one_off_features ) {
     551           0 :   if( !one_off_features ) {
     552           0 :     FD_LOG_NOTICE(( "No one-off features passed in" ));
     553           0 :     return;
     554           0 :   }
     555             : 
     556           0 :   char * one_off_features_str = strdup( one_off_features );
     557           0 :   char * token = NULL;
     558           0 :   token = strtok( one_off_features_str, "," );
     559           0 :   while( token ) {
     560           0 :     args->one_off_features[ args->one_off_features_cnt++ ] = token;
     561           0 :     token = strtok( NULL, "," );
     562           0 :   }
     563             : 
     564           0 :   FD_LOG_NOTICE(( "Found %u one off features to include", args->one_off_features_cnt ));
     565             : 
     566             :   /* TODO: Fix the leak here and in parse_rocksdb_list */
     567           0 : }
     568             : 
     569             : void
     570             : parse_rocksdb_list( fd_ledger_args_t * args,
     571             :                     char const *       rocksdb_list,
     572           0 :                     char const *       rocksdb_start_slots ) {
     573             :   /* First parse the paths to the different rocksdb */
     574           0 :   if( FD_UNLIKELY( !rocksdb_list ) ) {
     575           0 :     FD_LOG_NOTICE(( "No rocksdb list passed in" ));
     576           0 :     return;
     577           0 :   }
     578             : 
     579           0 :   char * rocksdb_str = strdup( rocksdb_list );
     580           0 :   char * token       = NULL;
     581           0 :   token = strtok( rocksdb_str, "," );
     582           0 :   while( token ) {
     583           0 :     args->rocksdb_list[ args->rocksdb_list_cnt++ ] = token;
     584           0 :     token = strtok( NULL, "," );
     585           0 :   }
     586             : 
     587             :   /* Now repeat for the start slots assuming there are multiple */
     588           0 :   if( rocksdb_start_slots == NULL && args->rocksdb_list_cnt > 1 ) {
     589           0 :     FD_LOG_ERR(( "Multiple rocksdb dirs passed in but no start slots" ));
     590           0 :   }
     591           0 :   ulong index = 0UL;
     592           0 :   if( rocksdb_start_slots ) {
     593           0 :     char * rocksdb_start_slot_str = strdup( rocksdb_start_slots );
     594           0 :     token = NULL;
     595           0 :     token = strtok( rocksdb_start_slot_str, "," );
     596           0 :     while( token ) {
     597           0 :       args->rocksdb_list_slot[ index++ ] = strtoul( token, NULL, 10 );
     598           0 :       token = strtok( NULL, "," );
     599           0 :     }
     600           0 :   }
     601             : 
     602           0 :   if( index != args->rocksdb_list_cnt - 1UL ) {
     603           0 :     FD_LOG_ERR(( "Number of rocksdb dirs passed in doesn't match number of start slots" ));
     604           0 :   }
     605             : 
     606             : 
     607             :   /* TODO: There is technically a leak here since we don't free the duplicated
     608             :      string but it's not a big deal. */
     609           0 : }
     610             : 
     611             : void
     612           0 : init_scratch( fd_wksp_t * wksp ) {
     613           0 :   #define FD_SCRATCH_TAG (421UL)
     614           0 :   ulong  smax   = 1UL << 33UL; /* 8 GiB */
     615           0 :   ulong  sdepth = 2048UL;      /* 2048 scratch frames */
     616           0 :   void * smem   = fd_wksp_alloc_laddr( wksp, fd_scratch_smem_align(), fd_scratch_smem_footprint( smax   ), FD_SCRATCH_TAG );
     617           0 :   void * fmem   = fd_wksp_alloc_laddr( wksp, fd_scratch_fmem_align(), fd_scratch_fmem_footprint( sdepth ), FD_SCRATCH_TAG );
     618           0 :   #undef FD_SCRATCH_TAG
     619           0 :   FD_TEST( (!!smem) & (!!fmem) );
     620           0 :   fd_scratch_attach( smem, fmem, smax, sdepth );
     621           0 : }
     622             : 
     623             : void
     624           0 : cleanup_scratch( void ) {
     625           0 :   void * fmem = NULL;
     626           0 :   void * smem = fd_scratch_detach( &fmem );
     627           0 :   fd_wksp_free_laddr( smem );
     628           0 :   fd_wksp_free_laddr( fmem );
     629           0 : }
     630             : 
     631             : void
     632           0 : init_funk( fd_ledger_args_t * args ) {
     633           0 :   fd_funk_t * funk;
     634           0 :   if( args->restore_funk ) {
     635           0 :     funk = fd_funk_recover_checkpoint( args->funk_file, 1, args->restore_funk, &args->funk_close_args );
     636           0 :   } else  {
     637           0 :     funk = fd_funk_open_file( args->funk_file, 1, args->hashseed, args->txns_max, args->index_max, args->funk_page_cnt*(1UL<<30), FD_FUNK_OVERWRITE, &args->funk_close_args );
     638           0 :   }
     639           0 :   args->funk = funk;
     640           0 :   args->funk_wksp = fd_funk_wksp( funk );
     641           0 :   FD_LOG_NOTICE(( "funky at global address 0x%016lx with %lu records", fd_wksp_gaddr_fast( args->funk_wksp, funk ),
     642           0 :                                                                        fd_funk_rec_cnt( fd_funk_rec_map( funk, args->funk_wksp ) ) ));
     643           0 : }
     644             : 
     645             : void
     646           0 : cleanup_funk( fd_ledger_args_t * args ) {
     647           0 :   fd_funk_close_file( &args->funk_close_args );
     648           0 : }
     649             : 
     650             : void
     651           0 : init_blockstore( fd_ledger_args_t * args ) {
     652           0 :   fd_wksp_tag_query_info_t info;
     653           0 :   ulong blockstore_tag = FD_BLOCKSTORE_MAGIC;
     654           0 :   void * shmem;
     655           0 :   if( fd_wksp_tag_query( args->wksp, &blockstore_tag, 1, &info, 1 ) > 0 ) {
     656           0 :     shmem = fd_wksp_laddr_fast( args->wksp, info.gaddr_lo );
     657           0 :     args->blockstore = fd_blockstore_join( shmem );
     658           0 :     if( args->blockstore == NULL ) {
     659           0 :       FD_LOG_ERR(( "failed to join a blockstore" ));
     660           0 :     }
     661           0 :     FD_LOG_NOTICE(( "joined blockstore" ));
     662           0 :   } else {
     663           0 :     shmem = fd_wksp_alloc_laddr( args->wksp, fd_blockstore_align(), fd_blockstore_footprint(), blockstore_tag );
     664           0 :     if( shmem == NULL ) {
     665           0 :       FD_LOG_ERR(( "failed to allocate a blockstore" ));
     666           0 :     }
     667           0 :     ulong lg_txn_max = 22UL;
     668           0 :     args->blockstore = fd_blockstore_join( fd_blockstore_new( shmem, 1, args->hashseed, args->shred_max,
     669           0 :                                                               args->slot_history_max, lg_txn_max ) );
     670           0 :     if( args->blockstore == NULL ) {
     671           0 :       fd_wksp_free_laddr( shmem );
     672           0 :       FD_LOG_ERR(( "failed to allocate a blockstore" ));
     673           0 :     }
     674           0 :     FD_LOG_NOTICE(( "allocating a new blockstore" ));
     675           0 :   }
     676           0 : }
     677             : 
     678             : void
     679           0 : checkpt( fd_ledger_args_t * args, fd_exec_slot_ctx_t * slot_ctx ) {
     680           0 :   if( !args->checkpt && !args->checkpt_funk && !args->checkpt_archive && !args->checkpt_status_cache ) {
     681           0 :     FD_LOG_WARNING(( "No checkpt argument specified" ));
     682           0 :   }
     683             : 
     684           0 :   if( args->checkpt_archive ) {
     685           0 :     FD_LOG_NOTICE(( "writing funk archive %s", args->checkpt_archive ));
     686             : 
     687             :     /* Switch to archival format */
     688           0 :     fd_funk_start_write( args->funk );
     689           0 :     int err = fd_runtime_save_slot_bank_archival( slot_ctx );
     690           0 :     if( err ) FD_LOG_ERR(( "funk archive failed: error %d", err ));
     691           0 :     err = fd_runtime_save_epoch_bank_archival( slot_ctx );
     692           0 :     if( err ) FD_LOG_ERR(( "funk archive failed: error %d", err ));
     693           0 :     fd_funk_end_write( args->funk );
     694             : 
     695           0 :     err = fd_funk_archive( args->funk, args->checkpt_archive );
     696           0 :     if( err ) FD_LOG_ERR(( "funk archive failed: error %d", err ));
     697           0 :   }
     698           0 :   if( args->checkpt_funk ) {
     699           0 :     if( args->funk_wksp == NULL ) {
     700           0 :       FD_LOG_ERR(( "funk_wksp is NULL" ));
     701           0 :     }
     702           0 :     FD_LOG_NOTICE(( "writing funk checkpt %s", args->checkpt_funk ));
     703           0 :     unlink( args->checkpt_funk );
     704             : #ifdef FD_FUNK_WKSP_PROTECT
     705             :     fd_wksp_mprotect( args->funk_wksp, 0 );
     706             : #endif
     707           0 :     int err = fd_wksp_checkpt( args->funk_wksp, args->checkpt_funk, 0666, 0, NULL );
     708             : #ifdef FD_FUNK_WKSP_PROTECT
     709             :     fd_wksp_mprotect( args->funk_wksp, 1 );
     710             : #endif
     711           0 :     if( err ) {
     712           0 :       FD_LOG_ERR(( "funk checkpt failed: error %d", err ));
     713           0 :     }
     714           0 :   }
     715           0 :   if( args->checkpt ) {
     716           0 :     FD_LOG_NOTICE(( "writing %s", args->checkpt ));
     717           0 :     unlink( args->checkpt );
     718           0 :     int err = fd_wksp_checkpt( args->wksp, args->checkpt, 0666, 0, NULL );
     719           0 :     if( err ) {
     720           0 :       FD_LOG_ERR(( "checkpt failed: error %d", err ));
     721           0 :     }
     722           0 :   }
     723           0 :   if( args->checkpt_status_cache ) {
     724           0 :     FD_LOG_NOTICE(( "writing %s", args->checkpt_status_cache ));
     725           0 :     unlink( args->checkpt_status_cache );
     726           0 :     int err = fd_wksp_checkpt( args->status_cache_wksp, args->checkpt_status_cache, 0666, 0, NULL );
     727           0 :     if( err ) {
     728           0 :       FD_LOG_ERR(( "status cache checkpt failed: error %d", err ));
     729           0 :     }
     730           0 :   }
     731           0 : }
     732             : 
     733             : void
     734           0 : archive_restore( fd_ledger_args_t * args ) {
     735           0 :   if( args->restore_archive != NULL ) {
     736           0 :     FD_LOG_NOTICE(( "restoring archive %s", args->restore_archive ));
     737           0 :     fd_funk_unarchive( args->funk, args->restore_archive );
     738           0 :   }
     739           0 : }
     740             : 
     741             : void
     742           0 : wksp_restore( fd_ledger_args_t * args ) {
     743           0 :   if( args->restore != NULL ) {
     744           0 :     FD_LOG_NOTICE(( "restoring wksp %s", args->restore ));
     745           0 :     fd_wksp_restore( args->wksp, args->restore, args->hashseed );
     746           0 :   }
     747           0 : }
     748             : 
     749             : /********************* Main Command Functions and Setup ***********************/
     750             : void
     751           0 : minify( fd_ledger_args_t * args ) {
     752             :     /* Example commmand:
     753             :     fd_ledger --cmd minify --rocksdb <LARGE_ROCKSDB> --minified-rocksdb <MINI_ROCKSDB>
     754             :               --start-slot <START_SLOT> --end-slot <END_SLOT> --copy-txn-status 1
     755             :   */
     756           0 :   if( args->rocksdb_list[ 0UL ] == NULL ) {
     757           0 :     FD_LOG_ERR(( "rocksdb path is NULL" ));
     758           0 :   }
     759           0 :   if( args->mini_db_dir == NULL ) {
     760           0 :     FD_LOG_ERR(( "minified rocksdb path is NULL" ));
     761           0 :   }
     762             : 
     763             : 
     764           0 :   fd_rocksdb_t big_rocksdb;
     765           0 :   char * err = fd_rocksdb_init( &big_rocksdb, args->rocksdb_list[ 0UL ] );
     766           0 :   if( FD_UNLIKELY( err!=NULL ) ) {
     767           0 :     FD_LOG_ERR(( "fd_rocksdb_init at path=%s returned error=%s", args->rocksdb_list[ 0UL ], err ));
     768           0 :   }
     769             : 
     770             :   /* If the directory for the minified rocksdb already exists, error out */
     771           0 :   struct stat statbuf;
     772           0 :   if( stat( args->mini_db_dir, &statbuf ) == 0 ) {
     773           0 :     FD_LOG_ERR(( "path for mini_db_dir=%s already exists", args->mini_db_dir ));
     774           0 :   }
     775             : 
     776             :   /* Create a new smaller rocksdb */
     777           0 :   fd_rocksdb_t mini_rocksdb;
     778           0 :   fd_rocksdb_new( &mini_rocksdb, args->mini_db_dir );
     779             : 
     780             :   /* Correctly bound off start and end slot */
     781           0 :   ulong first_slot = fd_rocksdb_first_slot( &big_rocksdb, &err );
     782           0 :   ulong last_slot  = fd_rocksdb_last_slot( &big_rocksdb, &err );
     783           0 :   if( args->start_slot < first_slot ) { args->start_slot = first_slot; }
     784           0 :   if( args->end_slot > last_slot )    { args->end_slot = last_slot; }
     785             : 
     786           0 :   FD_LOG_NOTICE(( "copying over rocks db for range [%lu, %lu]", args->start_slot, args->end_slot ));
     787             : 
     788             :   /* Copy over all slot indexed columns */
     789           0 :   for( ulong cf_idx = 1; cf_idx < FD_ROCKSDB_CF_CNT; ++cf_idx ) {
     790           0 :     fd_rocksdb_copy_over_slot_indexed_range( &big_rocksdb, &mini_rocksdb, cf_idx,
     791           0 :                                               args->start_slot, args->end_slot );
     792           0 :   }
     793           0 :   FD_LOG_NOTICE(("copied over all slot indexed columns"));
     794             : 
     795             :   /* Copy over transactions. This is more complicated because first, a temporary
     796             :       blockstore will be populated. This will be used to look up transactions
     797             :       which can be quickly queried */
     798           0 :   if( args->copy_txn_status ) {
     799           0 :     init_blockstore( args );
     800             :     /* Ingest block range into blockstore */
     801           0 :     ingest_rocksdb( args->alloc, args->rocksdb_list[ 0UL ], args->start_slot,
     802           0 :                     args->end_slot, args->blockstore, 0, ULONG_MAX );
     803             : 
     804           0 :     fd_rocksdb_copy_over_txn_status_range( &big_rocksdb, &mini_rocksdb, args->blockstore,
     805           0 :                                            args->start_slot, args->end_slot );
     806           0 :     FD_LOG_NOTICE(( "copied over all transaction statuses" ));
     807           0 :   } else {
     808           0 :     FD_LOG_NOTICE(( "skipping copying of transaction statuses" ));
     809           0 :   }
     810             : 
     811             :   /* TODO: Currently, the address signatures column family isn't copied as it
     812             :            is indexed on the pubkey. */
     813             : 
     814           0 :   fd_rocksdb_destroy( &big_rocksdb );
     815           0 :   fd_rocksdb_destroy( &mini_rocksdb );
     816           0 : }
     817             : 
     818             : void
     819           0 : ingest( fd_ledger_args_t * args ) {
     820             :   /* Setup funk, blockstore, epoch_ctx, and slot_ctx */
     821           0 :   wksp_restore( args );
     822           0 :   init_funk( args );
     823           0 :   if( !args->funk_only ) {
     824           0 :     init_blockstore( args );
     825           0 :   }
     826             : 
     827           0 :   fd_funk_t * funk = args->funk;
     828             : 
     829           0 :   fd_alloc_t * alloc = fd_alloc_join( fd_wksp_laddr_fast( fd_funk_wksp( funk ), funk->alloc_gaddr ), 0UL );
     830           0 :   if( FD_UNLIKELY( !alloc ) ) FD_LOG_ERR(( "fd_alloc_join(gaddr=%#lx) failed", funk->alloc_gaddr ));
     831             : 
     832           0 :   fd_valloc_t valloc = allocator_setup( args->wksp, args->allocator );
     833           0 :   uchar * epoch_ctx_mem = fd_valloc_malloc( valloc, fd_exec_epoch_ctx_align(), fd_exec_epoch_ctx_footprint( args->vote_acct_max ) );
     834           0 :   fd_memset( epoch_ctx_mem, 0, fd_exec_epoch_ctx_footprint( args->vote_acct_max ) );
     835           0 :   fd_exec_epoch_ctx_t * epoch_ctx = fd_exec_epoch_ctx_join( fd_exec_epoch_ctx_new( epoch_ctx_mem, args->vote_acct_max ) );
     836             : 
     837           0 :   uchar slot_ctx_mem[FD_EXEC_SLOT_CTX_FOOTPRINT] __attribute__((aligned(FD_EXEC_SLOT_CTX_ALIGN)));
     838           0 :   fd_exec_slot_ctx_t * slot_ctx = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( slot_ctx_mem, valloc ) );
     839           0 :   slot_ctx->epoch_ctx = epoch_ctx;
     840           0 :   args->slot_ctx = slot_ctx;
     841             : 
     842           0 :   fd_acc_mgr_t mgr[1];
     843           0 :   slot_ctx->acc_mgr = fd_acc_mgr_new( mgr, funk );
     844           0 :   slot_ctx->blockstore = args->blockstore;
     845             : 
     846           0 :   if( args->status_cache_wksp ) {
     847           0 :     void * status_cache_mem = fd_wksp_alloc_laddr( args->status_cache_wksp, fd_txncache_align(), fd_txncache_footprint(FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS, FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS, MAX_CACHE_TXNS_PER_SLOT), FD_TXNCACHE_MAGIC );
     848           0 :     FD_TEST( status_cache_mem );
     849           0 :     slot_ctx->status_cache  = fd_txncache_join( fd_txncache_new( status_cache_mem, FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS, FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS, MAX_CACHE_TXNS_PER_SLOT ) );
     850           0 :     FD_TEST( slot_ctx->status_cache );
     851           0 :   }
     852             : 
     853           0 :   init_tpool( args );
     854             : 
     855             :   /* Load in snapshot(s) */
     856           0 :   if( args->snapshot ) {
     857           0 :     fd_snapshot_load( args->snapshot, slot_ctx, args->tpool, args->verify_acc_hash, args->check_acc_hash , FD_SNAPSHOT_TYPE_FULL );
     858           0 :     FD_LOG_NOTICE(( "imported %lu records from snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
     859           0 :   }
     860           0 :   if( args->incremental ) {
     861           0 :     fd_snapshot_load( args->incremental, slot_ctx, args->tpool, args->verify_acc_hash, args->check_acc_hash, FD_SNAPSHOT_TYPE_INCREMENTAL );
     862           0 :     FD_LOG_NOTICE(( "imported %lu records from incremental snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
     863           0 :   }
     864             : 
     865           0 :   if( args->genesis ) {
     866           0 :     fd_runtime_read_genesis( slot_ctx, args->genesis, args->snapshot != NULL, NULL );
     867           0 :   }
     868             : 
     869           0 :   if( !args->snapshot && (args->restore_funk != NULL || args->restore != NULL) ) {
     870           0 :     fd_runtime_recover_banks( slot_ctx, 0, 1 );
     871           0 :   }
     872             : 
     873             :   /* At this point the account state has been ingested into funk. Intake rocksdb */
     874           0 :   if( args->start_slot == 0 ) {
     875           0 :     args->start_slot = slot_ctx->slot_bank.slot + 1;
     876           0 :   }
     877           0 :   fd_blockstore_t * blockstore = args->blockstore;
     878           0 :   if( blockstore ) {
     879           0 :     blockstore->min = blockstore->max = blockstore->lps =
     880           0 :       blockstore->hcs = blockstore->smr = slot_ctx->slot_bank.slot;
     881           0 :   }
     882             : 
     883           0 :   if( args->funk_only ) {
     884           0 :     FD_LOG_NOTICE(( "using funk only, skipping blockstore ingest" ));
     885           0 :   } else if( args->shredcap ) {
     886           0 :     FD_LOG_NOTICE(( "using shredcap" ));
     887           0 :     fd_shredcap_populate_blockstore( args->shredcap, blockstore, args->start_slot, args->end_slot );
     888           0 :   } else if( args->rocksdb_list[ 0UL ] ) {
     889           0 :     if( args->end_slot >= slot_ctx->slot_bank.slot + args->slot_history_max ) {
     890           0 :       args->end_slot = slot_ctx->slot_bank.slot + args->slot_history_max - 1;
     891           0 :     }
     892           0 :     ingest_rocksdb( args->alloc, args->rocksdb_list[ 0UL ], args->start_slot, args->end_slot,
     893           0 :                     blockstore, args->copy_txn_status, args->trash_hash );
     894           0 :   }
     895             : 
     896             :   /* Verification */
     897           0 :   for( fd_feature_id_t const * id = fd_feature_iter_init();
     898           0 :                                     !fd_feature_iter_done( id );
     899           0 :                                 id = fd_feature_iter_next( id ) ) {
     900           0 :     ulong activated_at = fd_features_get( &slot_ctx->epoch_ctx->features, id );
     901           0 :     if( activated_at ) {
     902           0 :       FD_LOG_DEBUG(( "feature %s activated at slot %lu", FD_BASE58_ENC_32_ALLOCA( id->id.key ), activated_at ));
     903           0 :     }
     904           0 :   }
     905             : 
     906           0 :   if( args->verify_funk ) {
     907           0 :     FD_LOG_NOTICE(( "verifying funky" ));
     908           0 :     if( fd_funk_verify( funk ) ) {
     909           0 :       FD_LOG_ERR(( "verification failed" ));
     910           0 :     }
     911           0 :   }
     912             : 
     913           0 :   checkpt( args, slot_ctx );
     914             : 
     915           0 :   cleanup_funk( args );
     916             : 
     917           0 :   cleanup_scratch();
     918           0 : }
     919             : 
     920             : int
     921           0 : replay( fd_ledger_args_t * args ) {
     922             :   /* Allows for ingest and direct replay. This can be done with a full checkpoint
     923             :      that contains a blockstore and funk, a checkpoint that just has funk, or directly
     924             :      using a rocksdb and snapshot.
     925             : 
     926             :     On demand block ingest is enabled by default and can be disabled with
     927             :     '--on-demand-block-ingest 0'. The number of blocks retained in a blockstore during
     928             :     on demand block ingest can be set with '--on-demand-block-history <N slots>'
     929             : 
     930             :     In order to replay from a checkpoint, use '--checkpoint <path to checkpoint>'.
     931             : 
     932             :     To use a checkpoint, but to consume blocks on demand use '--funkonly true'.
     933             :     This option MUST be used if the checkpoint was generated during a replay with
     934             :     on demand block ingest.
     935             : 
     936             :     For blocks to contain transaction status information use '--txnstatus true'
     937             : 
     938             :     Example command loading in from on demand checkpoint and replaying with on demand block ingest.
     939             :     It creates a checkpoint every 1000 slots.
     940             :     fd_ledger --funk-restore <CHECKPOINT_TO_LOAD_IN> --cmd replay --page-cnt 20
     941             :               --abort-on-mismatch 1 --tile-cpus 5-21 --allocator wksp
     942             :               --rocksdb dump/rocksdb --checkpt-path dump/checkpoint_new
     943             :               --checkpt-freq 1000 --funk-only 1 --on-demand-block-ingest 1 --funk-page-cnt 350
     944             : 
     945             :     Example command directly loading in a rocksdb and snapshot and replaying.
     946             :     fd_ledger --reset 1 --cmd replay --rocksdb dump/mainnet-257068890/rocksdb --index-max 5000000
     947             :               --end-slot 257068895 --txn-max 100 --page-cnt 16 --verify-acc-hash 1
     948             :               --snapshot dump/mainnet-257068890/snapshot-257068890-uRVtagPzKhYorycp4CRtKdWrYPij6iBxCYYXmqRvdSp.tar.zst
     949             :               --slot-history 5000 --allocator wksp --tile-cpus 5-21 --funk-page-cnt 16
     950             :   */
     951             : 
     952           0 :   wksp_restore( args ); /* Restores checkpointed workspace(s) */
     953             : 
     954           0 :   init_funk( args ); /* Joins or creates funk based on if one exists in the workspace */
     955           0 :   init_blockstore( args ); /* Does the same for the blockstore */
     956             : 
     957           0 :   archive_restore( args ); /* Restores checkpointed workspace(s) */
     958             : 
     959           0 :   fd_funk_t * funk = args->funk;
     960             : 
     961             :   /* Setup slot_ctx */
     962           0 :   fd_valloc_t valloc = allocator_setup( args->wksp, args->allocator );
     963             : 
     964           0 :   void * epoch_ctx_mem = fd_wksp_alloc_laddr( args->wksp, fd_exec_epoch_ctx_align(),
     965           0 :                                               fd_exec_epoch_ctx_footprint( args->vote_acct_max ), FD_EXEC_EPOCH_CTX_MAGIC );
     966           0 :   fd_memset( epoch_ctx_mem, 0, fd_exec_epoch_ctx_footprint( args->vote_acct_max ) );
     967           0 :   void * slot_ctx_mem = fd_wksp_alloc_laddr( args->wksp, FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT, FD_EXEC_SLOT_CTX_MAGIC );
     968           0 :   args->epoch_ctx = fd_exec_epoch_ctx_join( fd_exec_epoch_ctx_new( epoch_ctx_mem, args->vote_acct_max ) );
     969           0 :   fd_exec_epoch_ctx_bank_mem_clear( args->epoch_ctx );
     970             : 
     971           0 :   args->epoch_ctx->epoch_bank.cluster_version[0] = args->cluster_version[0];
     972           0 :   args->epoch_ctx->epoch_bank.cluster_version[1] = args->cluster_version[1];
     973           0 :   args->epoch_ctx->epoch_bank.cluster_version[2] = args->cluster_version[2];
     974             : 
     975           0 :   fd_features_enable_cleaned_up( &args->epoch_ctx->features, args->epoch_ctx->epoch_bank.cluster_version );
     976           0 :   fd_features_enable_one_offs( &args->epoch_ctx->features, args->one_off_features, args->one_off_features_cnt, 0UL );
     977             : 
     978           0 :   args->slot_ctx = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( slot_ctx_mem, valloc ) );
     979           0 :   args->slot_ctx->epoch_ctx = args->epoch_ctx;
     980           0 :   args->slot_ctx->valloc = valloc;
     981           0 :   args->slot_ctx->acc_mgr = fd_acc_mgr_new( args->acc_mgr, funk );
     982           0 :   args->slot_ctx->blockstore = args->blockstore;
     983           0 :   void * status_cache_mem = fd_wksp_alloc_laddr( args->wksp, FD_TXNCACHE_ALIGN, fd_txncache_footprint( FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS, FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS, MAX_CACHE_TXNS_PER_SLOT), FD_TXNCACHE_MAGIC );
     984           0 :   args->slot_ctx->status_cache = fd_txncache_join( fd_txncache_new( status_cache_mem, FD_TXNCACHE_DEFAULT_MAX_ROOTED_SLOTS, FD_TXNCACHE_DEFAULT_MAX_LIVE_SLOTS, MAX_CACHE_TXNS_PER_SLOT ) );
     985           0 :   FD_TEST( args->slot_ctx->status_cache );
     986             : 
     987           0 :   init_tpool( args );
     988             : 
     989             :   /* Check number of records in funk. If rec_cnt == 0, then it can be assumed
     990             :      that you need to load in snapshot(s). */
     991           0 :   ulong rec_cnt = fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) );
     992           0 :   if( !rec_cnt ) {
     993             :     /* Load in snapshot(s) */
     994           0 :     if( args->snapshot ) {
     995           0 :       fd_snapshot_load( args->snapshot, args->slot_ctx, args->tpool, args->verify_acc_hash, args->check_acc_hash, FD_SNAPSHOT_TYPE_FULL );
     996           0 :       FD_LOG_NOTICE(( "imported %lu records from snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
     997           0 :     }
     998           0 :     if( args->incremental ) {
     999           0 :       fd_snapshot_load( args->incremental, args->slot_ctx, args->tpool, args->verify_acc_hash, args->check_acc_hash, FD_SNAPSHOT_TYPE_INCREMENTAL );
    1000           0 :       FD_LOG_NOTICE(( "imported %lu records from snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
    1001           0 :     }
    1002           0 :     if( args->genesis ) {
    1003           0 :       fd_runtime_read_genesis( args->slot_ctx, args->genesis, args->snapshot != NULL, NULL );
    1004           0 :     }
    1005           0 :   } else {
    1006           0 :     FD_LOG_NOTICE(( "found funk with %lu records", rec_cnt ));
    1007           0 :   }
    1008             : 
    1009           0 :   fd_ledger_main_setup( args );
    1010             : 
    1011           0 :   if( !args->on_demand_block_ingest ) {
    1012           0 :     ingest_rocksdb( args->alloc, args->rocksdb_list[ 0UL ], args->start_slot, args->end_slot, args->blockstore, 0, args->trash_hash );
    1013           0 :   }
    1014             : 
    1015           0 :   FD_LOG_WARNING(( "setup done" ));
    1016             : 
    1017           0 :   int ret = runtime_replay( args );
    1018             : 
    1019           0 :   fd_ledger_main_teardown( args );
    1020             : 
    1021           0 :   cleanup_funk( args );
    1022             : 
    1023           0 :   return ret;
    1024           0 : }
    1025             : 
    1026             : void
    1027           0 : prune( fd_ledger_args_t * args ) {
    1028           0 :   if( args->restore || args->restore_funk ) {
    1029           0 :     FD_LOG_NOTICE(("restoring workspace"));
    1030           0 :     fd_wksp_restore( args->funk_wksp == NULL ? args->wksp : args->funk_wksp, args->restore_funk == NULL ? args->restore : args->restore_funk, args->hashseed );
    1031           0 :   }
    1032             : 
    1033             :   /* Setup data structures required for the unpruned workspace & replay ********/
    1034           0 :   init_funk( args );
    1035           0 :   init_blockstore( args );
    1036             : 
    1037           0 :   archive_restore( args );
    1038             : 
    1039           0 :   fd_funk_t * funk = args->funk;
    1040             : 
    1041           0 :   fd_valloc_t valloc = allocator_setup( args->wksp, args->allocator );
    1042             : 
    1043           0 :   void * epoch_ctx_mem = fd_wksp_alloc_laddr( args->wksp, fd_exec_epoch_ctx_align(),
    1044           0 :                                               fd_exec_epoch_ctx_footprint( args->vote_acct_max ), FD_EXEC_EPOCH_CTX_MAGIC );
    1045           0 :   fd_memset( epoch_ctx_mem, 0, fd_exec_epoch_ctx_footprint( args->vote_acct_max ) );
    1046           0 :   void * slot_ctx_mem = fd_wksp_alloc_laddr( args->wksp, FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT, FD_EXEC_SLOT_CTX_MAGIC );
    1047           0 :   args->epoch_ctx = fd_exec_epoch_ctx_join( fd_exec_epoch_ctx_new( epoch_ctx_mem, args->vote_acct_max ) );
    1048           0 :   args->slot_ctx = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( slot_ctx_mem, valloc ) );
    1049           0 :   args->slot_ctx->epoch_ctx = args->epoch_ctx;
    1050           0 :   args->slot_ctx->valloc = valloc;
    1051           0 :   args->slot_ctx->acc_mgr = fd_acc_mgr_new( args->acc_mgr, funk );
    1052           0 :   args->slot_ctx->blockstore = args->blockstore;
    1053             : 
    1054           0 :   ulong rec_cnt = fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) );
    1055           0 :   if( !rec_cnt ) {
    1056             :     /* Load in snapshot(s) */
    1057           0 :     if( args->snapshot ) {
    1058           0 :       fd_snapshot_load( args->snapshot, args->slot_ctx, args->tpool, args->verify_acc_hash, args->check_acc_hash, FD_SNAPSHOT_TYPE_FULL );
    1059           0 :       FD_LOG_NOTICE(( "imported %lu records from snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
    1060           0 :     }
    1061           0 :     if( args->incremental ) {
    1062           0 :       fd_snapshot_load( args->incremental, args->slot_ctx, args->tpool, args->verify_acc_hash, args->check_acc_hash, FD_SNAPSHOT_TYPE_INCREMENTAL );
    1063           0 :       FD_LOG_NOTICE(( "imported %lu records from snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
    1064           0 :     }
    1065           0 :   }
    1066             : 
    1067             :   /* Repeat for the pruned worksapce ******************************************/
    1068             :   /* Create wksp */
    1069           0 :   fd_wksp_t * pruned_wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, args->pages_pruned, 0, "prunedwksp", 0UL );
    1070           0 :   if( pruned_wksp == NULL ) {
    1071           0 :     FD_LOG_ERR(( "failed to create and attach to a pruned_wksp" ));
    1072           0 :   }
    1073             :   /* Create blockstore */
    1074           0 :   fd_blockstore_t * pruned_blockstore;
    1075           0 :   void * shmem = fd_wksp_alloc_laddr( pruned_wksp, fd_blockstore_align(), fd_blockstore_footprint(), FD_BLOCKSTORE_MAGIC );
    1076           0 :   if( shmem == NULL ) {
    1077           0 :     FD_LOG_ERR(( "failed to allocate a blockstore" ));
    1078           0 :   }
    1079           0 :   pruned_blockstore = fd_blockstore_join( fd_blockstore_new( shmem, 1, args->hashseed, args->shred_max,
    1080           0 :                                                              args->slot_history_max, 22 ) );
    1081           0 :   if( pruned_blockstore == NULL ) {
    1082           0 :     fd_wksp_free_laddr( shmem );
    1083           0 :     FD_LOG_ERR(( "failed to allocate a blockstore" ));
    1084           0 :   }
    1085           0 :   FD_LOG_NOTICE(( "pruned blockstore at global address 0x%016lx", fd_wksp_gaddr_fast( pruned_wksp, shmem ) ));
    1086             : 
    1087             :   /* Create funk */
    1088           0 :   fd_funk_t * pruned_funk = NULL;
    1089           0 :   shmem = fd_wksp_alloc_laddr( pruned_wksp, fd_funk_align(), fd_funk_footprint(), 1 );
    1090           0 :   if( shmem == NULL ) {
    1091           0 :     FD_LOG_ERR(( "failed to allocate a funky" ));
    1092           0 :   }
    1093           0 :   pruned_funk = fd_funk_join( fd_funk_new( shmem, 1, args->hashseed,
    1094           0 :                                            args->txns_max, args->index_max_pruned ) );
    1095           0 :   if( pruned_funk == NULL ) {
    1096           0 :     fd_wksp_free_laddr( shmem );
    1097           0 :     FD_LOG_ERR(( "failed to allocate a funky" ));
    1098           0 :   }
    1099           0 :   FD_LOG_NOTICE(( "pruned funky at global address 0x%016lx", fd_wksp_gaddr_fast( pruned_wksp, shmem ) ));
    1100             : 
    1101             :   /* Junk xid for pruning transaction */
    1102           0 :   fd_funk_txn_xid_t prune_xid = {0};
    1103           0 :   fd_memset( &prune_xid, 0x42, sizeof(fd_funk_txn_xid_t) );
    1104           0 :   fd_funk_start_write( pruned_funk );
    1105           0 :   fd_funk_txn_t * prune_txn = fd_funk_txn_prepare( pruned_funk, NULL, &prune_xid, 1 );
    1106           0 :   fd_funk_end_write( pruned_funk );
    1107           0 :   FD_TEST(( !!prune_txn ));
    1108             : 
    1109             :   /* Setup slot/epoch contexts */
    1110           0 :   fd_valloc_t pruned_valloc = allocator_setup( pruned_wksp, args->allocator );
    1111             : 
    1112           0 :   void * epoch_ctx_mem_pruned = fd_wksp_alloc_laddr( pruned_wksp, fd_exec_epoch_ctx_align(),
    1113           0 :                                               fd_exec_epoch_ctx_footprint( args->vote_acct_max ), FD_EXEC_EPOCH_CTX_MAGIC );
    1114           0 :   fd_memset( epoch_ctx_mem_pruned, 0, fd_exec_epoch_ctx_footprint( args->vote_acct_max ) );
    1115           0 :   void * slot_ctx_mem_pruned = fd_wksp_alloc_laddr( pruned_wksp, FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT, FD_EXEC_SLOT_CTX_MAGIC );
    1116           0 :   fd_exec_epoch_ctx_t * epoch_ctx_pruned = fd_exec_epoch_ctx_join( fd_exec_epoch_ctx_new( epoch_ctx_mem_pruned, args->vote_acct_max ) );
    1117           0 :   fd_exec_slot_ctx_t *  slot_ctx_pruned  = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( slot_ctx_mem_pruned, pruned_valloc ) );
    1118           0 :   slot_ctx_pruned->epoch_ctx = epoch_ctx_pruned;
    1119           0 :   slot_ctx_pruned->valloc = pruned_valloc;
    1120           0 :   fd_acc_mgr_t acc_mgr_pruned[1];
    1121           0 :   slot_ctx_pruned->acc_mgr = fd_acc_mgr_new( acc_mgr_pruned, pruned_funk );
    1122           0 :   slot_ctx_pruned->blockstore = pruned_blockstore;
    1123             : 
    1124           0 :   args->pruned_funk = pruned_funk;
    1125             : 
    1126             :   /* Replay through the desired slot range ************************************/
    1127             : 
    1128           0 :   init_tpool( args );
    1129           0 :   fd_ledger_main_setup( args );
    1130           0 :   runtime_replay( args );
    1131             : 
    1132           0 :   FD_LOG_NOTICE(("There are currently %lu records in the pruned funk", fd_funk_rec_cnt( fd_funk_rec_map( pruned_funk, pruned_wksp ) ) ));
    1133             : 
    1134             :   /* Reset the unpruned wksp, reload snapshot *********************************/
    1135             :   /* Reset the wksp */
    1136           0 :   fd_funk_delete( fd_funk_leave( args->funk ) );
    1137           0 :   ulong funk_tag = FD_FUNK_MAGIC;
    1138           0 :   fd_wksp_tag_free( args->wksp, &funk_tag, 1 );
    1139           0 :   fd_wksp_reset( args->wksp,      args->hashseed );
    1140           0 :   fd_wksp_reset( args->funk_wksp, args->hashseed );
    1141             : 
    1142             :   /* Setup funk again */
    1143           0 :   if( args->restore || args->restore_funk ) {
    1144           0 :     FD_LOG_NOTICE(("restoring workspace"));
    1145           0 :     fd_wksp_restore( args->funk_wksp == NULL ? args->wksp : args->funk_wksp, args->restore_funk == NULL ? args->restore : args->restore_funk, args->hashseed );
    1146           0 :   }
    1147           0 :   init_funk( args );
    1148           0 :   init_blockstore( args );
    1149           0 :   init_scratch( args->wksp );
    1150             : 
    1151             :   /* Setup contexts */
    1152           0 :   valloc = allocator_setup( args->wksp, args->allocator );
    1153             : 
    1154           0 :   epoch_ctx_mem = fd_wksp_alloc_laddr( args->wksp, fd_exec_epoch_ctx_align(),
    1155           0 :                                        fd_exec_epoch_ctx_footprint( args->vote_acct_max ), FD_EXEC_EPOCH_CTX_MAGIC );
    1156           0 :   fd_memset( epoch_ctx_mem, 0, fd_exec_epoch_ctx_footprint( args->vote_acct_max ) );
    1157           0 :   slot_ctx_mem = fd_wksp_alloc_laddr( args->wksp, FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT, FD_EXEC_SLOT_CTX_MAGIC );
    1158           0 :   args->epoch_ctx = fd_exec_epoch_ctx_join( fd_exec_epoch_ctx_new( epoch_ctx_mem, args->vote_acct_max ) );
    1159           0 :   args->slot_ctx = fd_exec_slot_ctx_join( fd_exec_slot_ctx_new( slot_ctx_mem, valloc ) );
    1160           0 :   args->slot_ctx->epoch_ctx = args->epoch_ctx;
    1161           0 :   args->slot_ctx->valloc = valloc;
    1162           0 :   fd_acc_mgr_t mgr[1];
    1163           0 :   args->slot_ctx->acc_mgr = fd_acc_mgr_new( mgr, args->funk );
    1164             : 
    1165             :   /* Load in snapshot(s) */
    1166           0 :   if( args->snapshot ) {
    1167           0 :     fd_snapshot_load( args->snapshot, args->slot_ctx, args->tpool, 0, 0, FD_SNAPSHOT_TYPE_FULL );
    1168           0 :     FD_LOG_NOTICE(( "reload: imported %lu records from snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
    1169           0 :   }
    1170           0 :   if( args->incremental ) {
    1171           0 :     fd_snapshot_load( args->incremental, args->slot_ctx, args->tpool, 0, 0, FD_SNAPSHOT_TYPE_INCREMENTAL );
    1172           0 :     FD_LOG_NOTICE(( "reload: imported %lu records from snapshot", fd_funk_rec_cnt( fd_funk_rec_map( funk, fd_funk_wksp( funk ) ) ) ));
    1173           0 :   }
    1174             : 
    1175             :   /* Copy over funk record state **********************************************/
    1176             :   /* After replaying, update all touched accounts to contain the data that is
    1177             :      present before execution begins. Look up the corresponding account in the
    1178             :      unpruned funk and copy over the contents */
    1179           0 :   fd_funk_t * unpruned_funk = args->funk;
    1180           0 :   fd_funk_start_write( pruned_funk   );
    1181           0 :   fd_funk_start_write( unpruned_funk );
    1182           0 :   fd_funk_rec_t * rec_map = fd_funk_rec_map( pruned_funk, fd_funk_wksp( pruned_funk ) );
    1183           0 :   ulong txn_rec_cnt = 0UL;
    1184           0 :   for( const fd_funk_rec_t * rec = fd_funk_txn_rec_head( prune_txn, rec_map );
    1185           0 :        rec; rec = fd_funk_txn_next_rec( pruned_funk, rec ) ) {
    1186             : 
    1187           0 :     const fd_funk_rec_t * original_rec = fd_funk_rec_query_global( unpruned_funk, NULL, rec->pair.key, NULL );
    1188           0 :     if( original_rec != NULL ) {
    1189           0 :       txn_rec_cnt++;
    1190           0 :       fd_funk_rec_t * mod_rec = fd_funk_rec_modify( pruned_funk, rec );
    1191           0 :       mod_rec = fd_funk_val_copy( mod_rec, fd_funk_val_const( original_rec, fd_funk_wksp( unpruned_funk ) ),
    1192           0 :                                   fd_funk_val_sz( original_rec ), fd_funk_val_sz( original_rec ),
    1193           0 :                                   fd_funk_alloc( pruned_funk, pruned_wksp ), pruned_wksp, NULL );
    1194           0 :       FD_TEST(( memcmp( fd_funk_val( original_rec, fd_funk_wksp( unpruned_funk ) ), fd_funk_val_const( rec, pruned_wksp ),
    1195           0 :                         fd_funk_val_sz( original_rec ) ) == 0 ));
    1196           0 :     } else {
    1197           0 :       fd_funk_rec_t * mod_rec = fd_funk_rec_modify( pruned_funk, rec );
    1198           0 :       int res = fd_funk_rec_remove( pruned_funk, mod_rec, 1 );
    1199           0 :       FD_TEST(( res == 0 ));
    1200           0 :     }
    1201           0 :   }
    1202           0 :   FD_LOG_NOTICE(( "Copied over %lu records from transactions", txn_rec_cnt ));
    1203             : 
    1204             :   /* Repeat above steps with all features */
    1205           0 :   ulong features_cnt = 0UL;
    1206           0 :   for( fd_feature_id_t const * id = fd_feature_iter_init();
    1207           0 :         !fd_feature_iter_done( id ); id = fd_feature_iter_next( id ) ) {
    1208           0 :     features_cnt++;
    1209             : 
    1210           0 :     fd_pubkey_t const *   pubkey      = (fd_pubkey_t *) id->id.key;
    1211           0 :     fd_funk_rec_key_t     feature_id  = fd_acc_funk_key( pubkey );
    1212           0 :     fd_funk_rec_t const * feature_rec = fd_funk_rec_query_global( unpruned_funk, NULL, &feature_id, NULL );
    1213           0 :     if( !feature_rec ) {
    1214           0 :       continue;
    1215           0 :     }
    1216           0 :     fd_funk_rec_t * new_feature_rec = fd_funk_rec_write_prepare( pruned_funk, prune_txn, &feature_id,
    1217           0 :                                                                  0, 1, NULL, NULL );
    1218           0 :     FD_TEST(( !!new_feature_rec ));
    1219           0 :     new_feature_rec = fd_funk_val_copy( new_feature_rec, fd_funk_val_const( feature_rec, fd_funk_wksp( unpruned_funk ) ),
    1220           0 :                                         fd_funk_val_sz( feature_rec ), fd_funk_val_sz( feature_rec ),
    1221           0 :                                         fd_funk_alloc( pruned_funk, fd_funk_wksp( pruned_funk ) ), pruned_wksp, NULL );
    1222           0 :     FD_TEST(( !!new_feature_rec ));
    1223           0 :   }
    1224           0 :   FD_LOG_NOTICE(( "Copied over %lu features", features_cnt ));
    1225             : 
    1226             :   /* Do the same with the epoch/slot bank keys and sysvars */
    1227           0 :   fd_runtime_recover_banks( args->slot_ctx, 0, 1 );
    1228             : 
    1229           0 :   fd_funk_rec_key_t id_epoch_bank       = fd_runtime_epoch_bank_key();
    1230           0 :   fd_funk_rec_key_t id_slot_bank        = fd_runtime_slot_bank_key();
    1231           0 :   fd_funk_rec_key_t recent_block_hashes = fd_acc_funk_key( &fd_sysvar_recent_block_hashes_id );
    1232           0 :   fd_funk_rec_key_t clock               = fd_acc_funk_key( &fd_sysvar_clock_id );
    1233           0 :   fd_funk_rec_key_t slot_history        = fd_acc_funk_key( &fd_sysvar_slot_history_id );
    1234           0 :   fd_funk_rec_key_t slot_hashes         = fd_acc_funk_key( &fd_sysvar_slot_hashes_id );
    1235           0 :   fd_funk_rec_key_t epoch_schedule      = fd_acc_funk_key( &fd_sysvar_epoch_schedule_id );
    1236           0 :   fd_funk_rec_key_t epoch_rewards       = fd_acc_funk_key( &fd_sysvar_epoch_rewards_id );
    1237           0 :   fd_funk_rec_key_t sysvar_fees         = fd_acc_funk_key( &fd_sysvar_fees_id );
    1238           0 :   fd_funk_rec_key_t rent                = fd_acc_funk_key( &fd_sysvar_rent_id );
    1239           0 :   fd_funk_rec_key_t stake_history       = fd_acc_funk_key( &fd_sysvar_stake_history_id );
    1240           0 :   fd_funk_rec_key_t owner               = fd_acc_funk_key( &fd_sysvar_owner_id );
    1241           0 :   fd_funk_rec_key_t last_restart_slot   = fd_acc_funk_key( &fd_sysvar_last_restart_slot_id );
    1242           0 :   fd_funk_rec_key_t instructions        = fd_acc_funk_key( &fd_sysvar_instructions_id );
    1243           0 :   fd_funk_rec_key_t incinerator         = fd_acc_funk_key( &fd_sysvar_incinerator_id );
    1244             : 
    1245           0 :   fd_funk_rec_key_t records[15] = { id_epoch_bank, id_slot_bank, recent_block_hashes, clock, slot_history,
    1246           0 :                                     slot_hashes, epoch_schedule, epoch_rewards, sysvar_fees, rent,
    1247           0 :                                     stake_history, owner, last_restart_slot, instructions, incinerator };
    1248           0 :   for( uint i = 0; i < sizeof( records ) / sizeof( fd_funk_rec_key_t ); ++i ) {
    1249           0 :     fd_funk_rec_t const * original_rec = fd_funk_rec_query_global( unpruned_funk, NULL, &records[i], NULL );
    1250           0 :     if( !original_rec ) {
    1251             :       /* Some sysvars aren't touched during execution. Not a problem. */
    1252           0 :       char record[ FD_BASE58_ENCODED_32_SZ ];
    1253           0 :       fd_acct_addr_cstr( record, (uchar*) &records[i] );
    1254           0 :       FD_LOG_DEBUG(( "Record is not in account pubkey=%s at index=%u", record, i ));
    1255           0 :       continue;
    1256           0 :     }
    1257           0 :     fd_funk_rec_t * new_rec = fd_funk_rec_write_prepare( pruned_funk, prune_txn, &records[i], 0, 1, NULL, NULL );
    1258           0 :     FD_TEST(( !!new_rec ));
    1259           0 :     new_rec = fd_funk_val_copy( new_rec, fd_funk_val_const( original_rec, fd_funk_wksp( unpruned_funk) ),
    1260           0 :                                 fd_funk_val_sz( original_rec ), fd_funk_val_sz( original_rec ),
    1261           0 :                                 fd_funk_alloc( pruned_funk, pruned_wksp ), pruned_wksp, NULL );
    1262           0 :     FD_TEST( memcmp( fd_funk_val( original_rec, fd_funk_wksp( unpruned_funk ) ), fd_funk_val_const( new_rec, pruned_wksp ),
    1263           0 :              fd_funk_val_sz( original_rec ) ) == 0 );
    1264           0 :     FD_TEST(( !!new_rec ));
    1265           0 :   }
    1266           0 :   FD_LOG_NOTICE(( "Copied over all sysvars and bank keys" ));
    1267             : 
    1268             :   /* Publish transaction with pruned records to the root of funk */
    1269           0 :   if( fd_funk_txn_publish( pruned_funk, prune_txn, 1 )==0 ) {
    1270           0 :     FD_LOG_ERR(( "failed to publish transaction into pruned funk" ));
    1271           0 :   }
    1272             : 
    1273             :   /* Verify that the pruned records are in the funk */
    1274           0 :   FD_LOG_NOTICE(( "Pruned funk record count is %lu", fd_funk_rec_global_cnt( pruned_funk, pruned_wksp ) ));
    1275             : 
    1276           0 :   fd_funk_leave( unpruned_funk );
    1277             : 
    1278           0 :   if( fd_funk_verify( pruned_funk ) ) {
    1279           0 :     FD_LOG_ERR(( "pruned funk verification failed" ));
    1280           0 :   }
    1281             : 
    1282           0 :   slot_ctx_pruned->funk_txn = NULL;
    1283           0 :   fd_funk_end_write( pruned_funk );
    1284           0 :   fd_funk_end_write( unpruned_funk );
    1285           0 :   args->funk = pruned_funk;
    1286           0 :   args->wksp = pruned_wksp;
    1287           0 :   checkpt( args, slot_ctx_pruned );
    1288             : 
    1289           0 :   cleanup_funk( args );
    1290             : 
    1291           0 :   cleanup_scratch();
    1292           0 : }
    1293             : 
    1294             : /* Parse user arguments and setup shared data structures used across commands */
    1295             : int
    1296           0 : initial_setup( int argc, char ** argv, fd_ledger_args_t * args ) {
    1297           0 :   if( FD_UNLIKELY( argc==1 ) ) {
    1298           0 :     return 1;
    1299           0 :   }
    1300             : 
    1301           0 :   fd_boot( &argc, &argv );
    1302           0 :   fd_flamenco_boot( &argc, &argv );
    1303             : 
    1304           0 :   char const * wksp_name               = fd_env_strip_cmdline_cstr ( &argc, &argv, "--wksp-name",               NULL, NULL      );
    1305           0 :   ulong        funk_page_cnt           = fd_env_strip_cmdline_ulong( &argc, &argv, "--funk-page-cnt",           NULL, 5         );
    1306           0 :   ulong        page_cnt                = fd_env_strip_cmdline_ulong( &argc, &argv, "--page-cnt",                NULL, 5         );
    1307           0 :   int          reset                   = fd_env_strip_cmdline_int  ( &argc, &argv, "--reset",                   NULL, 0         );
    1308           0 :   char const * cmd                     = fd_env_strip_cmdline_cstr ( &argc, &argv, "--cmd",                     NULL, NULL      );
    1309           0 :   ulong        index_max               = fd_env_strip_cmdline_ulong( &argc, &argv, "--index-max",               NULL, 450000000 );
    1310           0 :   ulong        txns_max                = fd_env_strip_cmdline_ulong( &argc, &argv, "--txn-max",                 NULL,      1000 );
    1311           0 :   char const * funk_file               = fd_env_strip_cmdline_cstr ( &argc, &argv, "--funk-file",               NULL, NULL      );
    1312           0 :   int          verify_funk             = fd_env_strip_cmdline_int  ( &argc, &argv, "--verify-funky",            NULL, 0         );
    1313           0 :   char const * snapshot                = fd_env_strip_cmdline_cstr ( &argc, &argv, "--snapshot",                NULL, NULL      );
    1314           0 :   char const * incremental             = fd_env_strip_cmdline_cstr ( &argc, &argv, "--incremental",             NULL, NULL      );
    1315           0 :   char const * genesis                 = fd_env_strip_cmdline_cstr ( &argc, &argv, "--genesis",                 NULL, NULL      );
    1316           0 :   int          copy_txn_status         = fd_env_strip_cmdline_int  ( &argc, &argv, "--copy-txn-status",         NULL, 0         );
    1317           0 :   ulong        slot_history_max        = fd_env_strip_cmdline_ulong( &argc, &argv, "--slot-history",            NULL, FD_BLOCK_MAX );
    1318           0 :   ulong        shred_max               = fd_env_strip_cmdline_ulong( &argc, &argv, "--shred-max",               NULL, 1UL << 17 );
    1319           0 :   ulong        start_slot              = fd_env_strip_cmdline_ulong( &argc, &argv, "--start-slot",              NULL, 0UL       );
    1320           0 :   ulong        end_slot                = fd_env_strip_cmdline_ulong( &argc, &argv, "--end-slot",                NULL, ULONG_MAX );
    1321           0 :   uint         verify_acc_hash         = fd_env_strip_cmdline_uint ( &argc, &argv, "--verify-acc-hash",         NULL, 0         );
    1322           0 :   uint         check_acc_hash          = fd_env_strip_cmdline_uint ( &argc, &argv, "--check-acc-hash",          NULL, 0         );
    1323           0 :   char const * restore                 = fd_env_strip_cmdline_cstr ( &argc, &argv, "--restore",                 NULL, NULL      );
    1324           0 :   char const * restore_funk            = fd_env_strip_cmdline_cstr ( &argc, &argv, "--funk-restore",            NULL, NULL      );
    1325           0 :   char const * restore_archive         = fd_env_strip_cmdline_cstr ( &argc, &argv, "--restore-archive",         NULL, NULL      );
    1326           0 :   char const * shredcap                = fd_env_strip_cmdline_cstr ( &argc, &argv, "--shred-cap",               NULL, NULL      );
    1327           0 :   ulong        trash_hash              = fd_env_strip_cmdline_ulong( &argc, &argv, "--trash-hash",              NULL, ULONG_MAX );
    1328           0 :   char const * mini_db_dir             = fd_env_strip_cmdline_cstr ( &argc, &argv, "--minified-rocksdb",        NULL, NULL      );
    1329           0 :   ulong        index_max_pruned        = fd_env_strip_cmdline_ulong( &argc, &argv, "--pruned-index-max",        NULL, 450000000 );
    1330           0 :   ulong        pages_pruned            = fd_env_strip_cmdline_ulong( &argc, &argv, "--pruned-page-cnt",         NULL, ULONG_MAX );
    1331           0 :   int          funk_only               = fd_env_strip_cmdline_int  ( &argc, &argv, "--funk-only",               NULL, 0         );
    1332           0 :   char const * checkpt                 = fd_env_strip_cmdline_cstr ( &argc, &argv, "--checkpt",                 NULL, NULL      );
    1333           0 :   char const * checkpt_funk            = fd_env_strip_cmdline_cstr ( &argc, &argv, "--checkpt-funk",            NULL, NULL      );
    1334           0 :   char const * checkpt_archive         = fd_env_strip_cmdline_cstr ( &argc, &argv, "--checkpt-archive",         NULL, NULL      );
    1335           0 :   char const * capture_fpath           = fd_env_strip_cmdline_cstr ( &argc, &argv, "--capture-solcap",          NULL, NULL      );
    1336           0 :   int          capture_txns            = fd_env_strip_cmdline_int  ( &argc, &argv, "--capture-txns",            NULL, 1         );
    1337           0 :   char const * checkpt_path            = fd_env_strip_cmdline_cstr ( &argc, &argv, "--checkpt-path",            NULL, NULL      );
    1338           0 :   ulong        checkpt_freq            = fd_env_strip_cmdline_ulong( &argc, &argv, "--checkpt-freq",            NULL, ULONG_MAX );
    1339           0 :   int          checkpt_mismatch        = fd_env_strip_cmdline_int  ( &argc, &argv, "--checkpt-mismatch",        NULL, 0         );
    1340           0 :   char const * allocator               = fd_env_strip_cmdline_cstr ( &argc, &argv, "--allocator",               NULL, "wksp"    );
    1341           0 :   int          abort_on_mismatch       = fd_env_strip_cmdline_int  ( &argc, &argv, "--abort-on-mismatch",       NULL, 1         );
    1342           0 :   int          on_demand_block_ingest  = fd_env_strip_cmdline_int  ( &argc, &argv, "--on-demand-block-ingest",  NULL, 1         );
    1343           0 :   ulong        on_demand_block_history = fd_env_strip_cmdline_ulong( &argc, &argv, "--on-demand-block-history", NULL, 100       );
    1344           0 :   int          dump_insn_to_pb         = fd_env_strip_cmdline_int  ( &argc, &argv, "--dump-insn-to-pb",         NULL, 0         );
    1345           0 :   int          dump_txn_to_pb          = fd_env_strip_cmdline_int  ( &argc, &argv, "--dump-txn-to-pb",          NULL, 0         );
    1346           0 :   ulong        dump_proto_start_slot   = fd_env_strip_cmdline_ulong( &argc, &argv, "--dump-proto-start-slot",   NULL, 0         );
    1347           0 :   char const * dump_proto_sig_filter   = fd_env_strip_cmdline_cstr ( &argc, &argv, "--dump-proto-sig-filter",   NULL, NULL      );
    1348           0 :   char const * dump_proto_output_dir   = fd_env_strip_cmdline_cstr ( &argc, &argv, "--dump-proto-output-dir",   NULL, NULL      );
    1349           0 :   ulong        vote_acct_max           = fd_env_strip_cmdline_ulong( &argc, &argv, "--vote_acct_max",           NULL, 2000000UL );
    1350           0 :   char const * rocksdb_list            = fd_env_strip_cmdline_cstr ( &argc, &argv, "--rocksdb",                 NULL, NULL      );
    1351           0 :   char const * rocksdb_list_starts     = fd_env_strip_cmdline_cstr ( &argc, &argv, "--rocksdb-starts",          NULL, NULL      );
    1352           0 :   char const * cluster_version         = fd_env_strip_cmdline_cstr ( &argc, &argv, "--cluster-version",         NULL, "2.0.0"   );
    1353           0 :   char const * checkpt_status_cache    = fd_env_strip_cmdline_cstr ( &argc, &argv, "--checkpt-status-cache",    NULL, NULL      );
    1354           0 :   char const * one_off_features        = fd_env_strip_cmdline_cstr ( &argc, &argv, "--one-off-features",        NULL, NULL      );
    1355           0 :   char const * lthash                  = fd_env_strip_cmdline_cstr ( &argc, &argv, "--lthash",                  NULL, "false"   );
    1356             : 
    1357             :   // TODO: Add argument validation. Make sure that we aren't including any arguments that aren't parsed for
    1358             : 
    1359           0 :   char hostname[64];
    1360           0 :   gethostname( hostname, sizeof(hostname) );
    1361           0 :   ulong hashseed = fd_hash( 0, hostname, strnlen( hostname, sizeof(hostname) ) );
    1362           0 :   args->hashseed = (uint)hashseed;
    1363             : 
    1364             :   /* Setup workspace */
    1365           0 :   fd_wksp_t * wksp;
    1366           0 :   if( wksp_name == NULL ) {
    1367           0 :     FD_LOG_NOTICE(( "--wksp not specified, using an anonymous local workspace" ));
    1368           0 :     wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, page_cnt, 0, "wksp", 0UL );
    1369           0 :   } else {
    1370           0 :     fd_shmem_info_t shmem_info[1];
    1371           0 :     if( FD_UNLIKELY( fd_shmem_info( wksp_name, 0UL, shmem_info ) ) )
    1372           0 :       FD_LOG_ERR(( "unable to query region \"%s\"\n\tprobably does not exist or bad permissions", wksp_name ));
    1373           0 :     wksp = fd_wksp_attach( wksp_name );
    1374           0 :   }
    1375             : 
    1376           0 :   if( wksp == NULL ) {
    1377           0 :     FD_LOG_ERR(( "failed to attach to workspace %s", wksp_name ));
    1378           0 :   }
    1379           0 :   if( reset ) {
    1380           0 :     fd_wksp_reset( wksp, args->hashseed );
    1381           0 :   }
    1382           0 :   args->wksp = wksp;
    1383             : 
    1384           0 :   init_scratch( wksp );
    1385             : 
    1386           0 :   if( checkpt_status_cache && checkpt_status_cache[0] != '\0' ) {
    1387           0 :     FD_LOG_NOTICE(( "Creating status cache wksp" ));
    1388           0 :     fd_wksp_t * status_cache_wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, 23UL, 0, "status_cache_wksp", 0UL );
    1389           0 :     fd_wksp_reset( status_cache_wksp, args->hashseed );
    1390           0 :     args->status_cache_wksp = status_cache_wksp;
    1391           0 :   } else {
    1392           0 :     args->status_cache_wksp = NULL;
    1393           0 :   }
    1394             : 
    1395             :   /* Setup alloc and valloc */
    1396           0 :   #define FD_ALLOC_TAG (422UL)
    1397           0 :   void * alloc_shmem = fd_wksp_alloc_laddr( wksp, fd_alloc_align(), fd_alloc_footprint(), FD_ALLOC_TAG );
    1398           0 :   if( FD_UNLIKELY( !alloc_shmem ) ) { FD_LOG_ERR( ( "fd_alloc too large for workspace" ) ); }
    1399           0 :   void * alloc_shalloc = fd_alloc_new( alloc_shmem, FD_ALLOC_TAG );
    1400           0 :   if( FD_UNLIKELY( !alloc_shalloc ) ) { FD_LOG_ERR( ( "fd_allow_new failed" ) ); }
    1401           0 :   fd_alloc_t * alloc = fd_alloc_join( alloc_shalloc, FD_ALLOC_TAG );
    1402           0 :   args->alloc = alloc;
    1403           0 :   #undef FD_ALLOC_TAG
    1404             : 
    1405             :   /* Copy over arguments */
    1406           0 :   args->cmd                     = cmd;
    1407           0 :   args->start_slot              = start_slot;
    1408           0 :   args->end_slot                = end_slot;
    1409           0 :   args->checkpt                 = checkpt;
    1410           0 :   args->checkpt_funk            = checkpt_funk;
    1411           0 :   args->checkpt_archive         = checkpt_archive;
    1412           0 :   args->shred_max               = shred_max;
    1413           0 :   args->slot_history_max        = slot_history_max;
    1414           0 :   args->txns_max                = txns_max;
    1415           0 :   args->index_max               = index_max;
    1416           0 :   args->funk_page_cnt           = funk_page_cnt;
    1417           0 :   args->funk_file               = funk_file;
    1418           0 :   args->restore                 = restore;
    1419           0 :   args->restore_funk            = restore_funk;
    1420           0 :   args->restore_archive         = restore_archive;
    1421           0 :   args->mini_db_dir             = mini_db_dir;
    1422           0 :   args->funk_only               = funk_only;
    1423           0 :   args->copy_txn_status         = copy_txn_status;
    1424           0 :   args->snapshot                = snapshot;
    1425           0 :   args->incremental             = incremental;
    1426           0 :   args->genesis                 = genesis;
    1427           0 :   args->shredcap                = shredcap;
    1428           0 :   args->verify_funk             = verify_funk;
    1429           0 :   args->check_acc_hash          = check_acc_hash;
    1430           0 :   args->verify_acc_hash         = verify_acc_hash;
    1431           0 :   args->trash_hash              = trash_hash;
    1432           0 :   args->index_max_pruned        = index_max_pruned;
    1433           0 :   args->pages_pruned            = pages_pruned;
    1434           0 :   args->capture_fpath           = capture_fpath;
    1435           0 :   args->capture_txns            = capture_txns;
    1436           0 :   args->checkpt_path            = checkpt_path;
    1437           0 :   args->checkpt_freq            = checkpt_freq;
    1438           0 :   args->checkpt_mismatch        = checkpt_mismatch;
    1439           0 :   args->allocator               = allocator;
    1440           0 :   args->abort_on_mismatch       = abort_on_mismatch;
    1441           0 :   args->on_demand_block_ingest  = on_demand_block_ingest;
    1442           0 :   args->on_demand_block_history = on_demand_block_history;
    1443           0 :   args->dump_insn_to_pb         = dump_insn_to_pb;
    1444           0 :   args->dump_txn_to_pb          = dump_txn_to_pb;
    1445           0 :   args->dump_proto_start_slot   = dump_proto_start_slot;
    1446           0 :   args->dump_proto_sig_filter   = dump_proto_sig_filter;
    1447           0 :   args->dump_proto_output_dir   = dump_proto_output_dir;
    1448           0 :   args->vote_acct_max           = vote_acct_max;
    1449           0 :   args->rocksdb_list_cnt        = 0UL;
    1450           0 :   args->checkpt_status_cache    = checkpt_status_cache;
    1451           0 :   args->one_off_features_cnt    = 0UL;
    1452           0 :   parse_one_off_features( args, one_off_features );
    1453           0 :   parse_rocksdb_list( args, rocksdb_list, rocksdb_list_starts );
    1454             : 
    1455           0 :   if( FD_UNLIKELY( sscanf( cluster_version, "%u.%u.%u", &args->cluster_version[0], &args->cluster_version[1], &args->cluster_version[2] )!=3 ) ) {
    1456           0 :     FD_LOG_ERR(( "failed to decode cluster version" ));;
    1457           0 :   }
    1458             : 
    1459           0 :   if( args->rocksdb_list_cnt==1UL ) {
    1460           0 :     FD_LOG_NOTICE(( "rocksdb=%s", args->rocksdb_list[0] ));
    1461           0 :   } else {
    1462           0 :     for( ulong i=0UL; i<args->rocksdb_list_cnt; ++i ) {
    1463           0 :       FD_LOG_NOTICE(( "rocksdb_list[ %lu ]=%s slot=%lu", i, args->rocksdb_list[i], args->rocksdb_list_slot[i-1] ));
    1464           0 :     }
    1465           0 :   }
    1466             : 
    1467           0 :   args->lthash           = lthash;
    1468             : 
    1469           0 :   return 0;
    1470           0 : }
    1471             : 
    1472             : int main( int argc, char ** argv ) {
    1473             :   fd_ledger_args_t args = {0};
    1474             :   initial_setup( argc, argv, &args );
    1475             : 
    1476             :   if( args.cmd == NULL ) {
    1477             :     FD_LOG_ERR(( "no command specified" ));
    1478             :   } else if( strcmp( args.cmd, "replay" ) == 0 ) {
    1479             :     return replay( &args );
    1480             :   } else if( strcmp( args.cmd, "ingest" ) == 0 ) {
    1481             :     ingest( &args );
    1482             :   } else if( strcmp( args.cmd, "minify" ) == 0 ) {
    1483             :     minify( &args );
    1484             :   } else if( strcmp( args.cmd, "prune" ) == 0 ) {
    1485             :     prune( &args );
    1486             :   } else {
    1487             :     FD_LOG_ERR(( "unknown command=%s", args.cmd ));
    1488             :   }
    1489             :   return 0;
    1490             : }

Generated by: LCOV version 1.14