LCOV - code coverage report
Current view: top level - flamenco/snapshot - fd_snapshot.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 226 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 14 0.0 %

          Line data    Source code
       1             : #include "fd_snapshot.h"
       2             : #include "fd_snapshot_loader.h"
       3             : #include "fd_snapshot_restore.h"
       4             : #include "../runtime/fd_acc_mgr.h"
       5             : #include "../runtime/fd_hashes.h"
       6             : #include "../runtime/fd_runtime_init.h"
       7             : #include "../runtime/fd_system_ids.h"
       8             : #include "../runtime/context/fd_exec_epoch_ctx.h"
       9             : #include "../runtime/context/fd_exec_slot_ctx.h"
      10             : #include "../rewards/fd_rewards.h"
      11             : #include "../runtime/fd_runtime.h"
      12             : 
      13             : #include <assert.h>
      14             : #include <errno.h>
      15             : 
      16             : /* FIXME: don't hardcode this param */
      17           0 : #define ZSTD_WINDOW_SZ (33554432UL)
      18             : 
      19             : struct fd_snapshot_load_ctx {
      20             :   /* User-defined parameters. */
      21             :   const char *           snapshot_file;
      22             :   fd_exec_slot_ctx_t *   slot_ctx;
      23             :   fd_tpool_t *           tpool;
      24             :   uint                   verify_hash;
      25             :   uint                   check_hash;
      26             :   int                    snapshot_type;
      27             : 
      28             :   /* Internal state. */
      29             :   fd_funk_txn_t *        par_txn;
      30             :   fd_funk_txn_t *        child_txn;
      31             : 
      32             :   fd_snapshot_loader_t *  loader;
      33             :   fd_snapshot_restore_t * restore;
      34             : 
      35             :   fd_spad_t *             runtime_spad;
      36             : };
      37             : typedef struct fd_snapshot_load_ctx fd_snapshot_load_ctx_t;
      38             : 
      39             : static void
      40           0 : fd_hashes_load( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
      41           0 :   FD_TXN_ACCOUNT_DECL( block_hashes_rec );
      42           0 :   int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, &fd_sysvar_recent_block_hashes_id, block_hashes_rec );
      43             : 
      44           0 :   if( err != FD_ACC_MGR_SUCCESS ) {
      45           0 :     FD_LOG_ERR(( "missing recent block hashes account" ));
      46           0 :   }
      47             : 
      48             :   /* FIXME: Do not hardcode the number of vote accounts */
      49             : 
      50           0 :   slot_ctx->slot_bank.stake_account_keys.account_keys_root = NULL;
      51           0 :   uchar * pool_mem = fd_spad_alloc( runtime_spad, fd_account_keys_pair_t_map_align(), fd_account_keys_pair_t_map_footprint( 100000UL ) );
      52             : 
      53           0 :   slot_ctx->slot_bank.stake_account_keys.account_keys_pool = fd_account_keys_pair_t_map_join( fd_account_keys_pair_t_map_new( pool_mem, 100000UL ) );
      54             : 
      55           0 :   slot_ctx->slot_bank.vote_account_keys.account_keys_root = NULL;
      56           0 :   pool_mem = fd_spad_alloc( runtime_spad, fd_account_keys_pair_t_map_align(), fd_account_keys_pair_t_map_footprint( 100000UL ) );
      57           0 :   slot_ctx->slot_bank.vote_account_keys.account_keys_pool = fd_account_keys_pair_t_map_join( fd_account_keys_pair_t_map_new( pool_mem, 100000UL ) );
      58             : 
      59           0 :   slot_ctx->slot_bank.collected_execution_fees = 0UL;
      60           0 :   slot_ctx->slot_bank.collected_priority_fees  = 0UL;
      61           0 :   slot_ctx->slot_bank.collected_rent           = 0UL;
      62             : 
      63           0 :   fd_runtime_save_slot_bank( slot_ctx );
      64           0 :   fd_runtime_save_epoch_bank( slot_ctx );
      65           0 : }
      66             : 
      67             : static int
      68             : restore_manifest( void *                 ctx,
      69             :                   fd_solana_manifest_t * manifest,
      70           0 :                   fd_spad_t *            spad ) {
      71           0 :   return (!!fd_exec_slot_ctx_recover( ctx, manifest, spad ) ? 0 : EINVAL);
      72           0 : }
      73             : 
      74             : static int
      75             : restore_status_cache( void *                  ctx,
      76             :                       fd_bank_slot_deltas_t * slot_deltas,
      77           0 :                       fd_spad_t *             spad ) {
      78           0 :   return (!!fd_exec_slot_ctx_recover_status_cache( ctx, slot_deltas, spad ) ? 0 : EINVAL);
      79           0 : }
      80             : 
      81             : static int
      82             : restore_rent_fresh_account( fd_exec_slot_ctx_t * slot_ctx,
      83           0 :                             fd_pubkey_t const  * pubkey ) {
      84           0 :   fd_runtime_register_new_fresh_account( slot_ctx, pubkey );
      85           0 :   return 0;
      86           0 : }
      87             : 
      88             : ulong
      89           0 : fd_snapshot_load_ctx_align( void ) {
      90           0 :   return alignof(fd_snapshot_load_ctx_t);
      91           0 : }
      92             : 
      93             : ulong
      94           0 : fd_snapshot_load_ctx_footprint( void ) {
      95           0 :   return sizeof(fd_snapshot_load_ctx_t);
      96           0 : }
      97             : 
      98             : fd_snapshot_load_ctx_t *
      99             : fd_snapshot_load_new( uchar *                mem,
     100             :                       const char *           snapshot_file,
     101             :                       fd_exec_slot_ctx_t *   slot_ctx,
     102             :                       fd_tpool_t *           tpool,
     103             :                       uint                   verify_hash,
     104             :                       uint                   check_hash,
     105             :                       int                    snapshot_type,
     106             :                       fd_spad_t * *          exec_spads,
     107             :                       ulong                  exec_spad_cnt,
     108           0 :                       fd_spad_t *            runtime_spad ) {
     109             : 
     110           0 :   (void)exec_spads;
     111           0 :   (void)exec_spad_cnt;
     112             : 
     113           0 :   fd_snapshot_load_ctx_t * ctx = (fd_snapshot_load_ctx_t *)mem;
     114           0 :   ctx->snapshot_file = snapshot_file;
     115           0 :   ctx->slot_ctx      = slot_ctx;
     116           0 :   ctx->tpool         = tpool;
     117           0 :   ctx->verify_hash   = verify_hash;
     118           0 :   ctx->check_hash    = check_hash;
     119           0 :   ctx->snapshot_type = snapshot_type;
     120           0 :   ctx->runtime_spad  = runtime_spad;
     121           0 :   return ctx;
     122           0 : }
     123             : 
     124             : void
     125           0 : fd_snapshot_load_init( fd_snapshot_load_ctx_t * ctx ) {
     126           0 :   switch( ctx->snapshot_type ) {
     127           0 :     case FD_SNAPSHOT_TYPE_UNSPECIFIED:
     128           0 :       FD_LOG_ERR(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_UNSPECIFIED)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
     129           0 :       break;
     130           0 :     case FD_SNAPSHOT_TYPE_FULL:
     131           0 :       FD_LOG_NOTICE(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_FULL)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
     132           0 :       break;
     133           0 :     case FD_SNAPSHOT_TYPE_INCREMENTAL:
     134           0 :       FD_LOG_NOTICE(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, FD_SNAPSHOT_TYPE_INCREMENTAL)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
     135           0 :       break;
     136           0 :     default:
     137           0 :       FD_LOG_ERR(("fd_snapshot_load(\"%s\", verify-hash=%s, check-hash=%s, huh?)", ctx->snapshot_file, ctx->verify_hash ? "true" : "false", ctx->check_hash ? "true" : "false"));
     138           0 :       break;
     139           0 :   }
     140             : 
     141           0 :   fd_funk_start_write( ctx->slot_ctx->acc_mgr->funk );
     142             : 
     143           0 :   ctx->par_txn   = ctx->slot_ctx->funk_txn;
     144           0 :   ctx->child_txn = ctx->slot_ctx->funk_txn;
     145           0 :   if( ctx->verify_hash && FD_FEATURE_ACTIVE( ctx->slot_ctx->slot_bank.slot, ctx->slot_ctx->epoch_ctx->features, incremental_snapshot_only_incremental_hash_calculation ) ) {
     146           0 :     fd_funk_txn_xid_t xid;
     147           0 :     memset( &xid, 0xc3, sizeof(xid) );
     148           0 :     ctx->child_txn = fd_funk_txn_prepare( ctx->slot_ctx->acc_mgr->funk, ctx->child_txn, &xid, 0 );
     149           0 :     ctx->slot_ctx->funk_txn = ctx->child_txn;
     150           0 :     }
     151           0 : }
     152             : 
     153             : void
     154             : fd_snapshot_load_manifest_and_status_cache( fd_snapshot_load_ctx_t * ctx,
     155             :                                             ulong *                  base_slot_override,
     156           0 :                                             int                      restore_manifest_flags ) {
     157             : 
     158           0 :   size_t slen = strlen( ctx->snapshot_file );
     159           0 :   char * snapshot_cstr = fd_spad_alloc( ctx->runtime_spad, 8UL, slen + 1 );
     160           0 :   fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( snapshot_cstr ), ctx->snapshot_file, slen ) );
     161             : 
     162           0 :   fd_snapshot_src_t src[1];
     163           0 :   if( FD_UNLIKELY( !fd_snapshot_src_parse( src, snapshot_cstr ) ) ) {
     164           0 :     FD_LOG_ERR(( "Failed to load snapshot" ));
     165           0 :   }
     166             : 
     167           0 :   fd_exec_epoch_ctx_bank_mem_clear( ctx->slot_ctx->epoch_ctx );
     168             : 
     169           0 :   fd_acc_mgr_t *  acc_mgr  = ctx->slot_ctx->acc_mgr;
     170           0 :   fd_funk_txn_t * funk_txn = ctx->slot_ctx->funk_txn;
     171             : 
     172           0 :   void * restore_mem = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_restore_align(), fd_snapshot_restore_footprint() );
     173           0 :   void * loader_mem  = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_loader_align(),  fd_snapshot_loader_footprint( ZSTD_WINDOW_SZ ) );
     174             : 
     175           0 :   ctx->restore = fd_snapshot_restore_new( restore_mem,
     176           0 :                                           acc_mgr,
     177           0 :                                           funk_txn,
     178           0 :                                           ctx->runtime_spad,
     179           0 :                                           ctx->slot_ctx,
     180           0 :                                           (restore_manifest_flags & FD_SNAPSHOT_RESTORE_MANIFEST) ? restore_manifest : NULL,
     181           0 :                                           (restore_manifest_flags & FD_SNAPSHOT_RESTORE_STATUS_CACHE) ? restore_status_cache : NULL,
     182           0 :                                           restore_rent_fresh_account );
     183             : 
     184           0 :   ctx->loader  = fd_snapshot_loader_new ( loader_mem, ZSTD_WINDOW_SZ );
     185             : 
     186           0 :   if( FD_UNLIKELY( !ctx->restore || !ctx->loader ) ) {
     187           0 :     FD_LOG_ERR(( "Failed to load snapshot" ));
     188           0 :   }
     189             : 
     190           0 :   if( FD_UNLIKELY( !fd_snapshot_loader_init( ctx->loader,
     191           0 :                                             ctx->restore,
     192           0 :                                                     src,
     193           0 :                                                     base_slot_override ? *base_slot_override : ctx->slot_ctx->slot_bank.slot,
     194           0 :                                                     1 ) ) ) {
     195           0 :     FD_LOG_ERR(( "Failed to init snapshot loader" ));
     196           0 :   }
     197             : 
     198             :   /* First load in the manifest. */
     199           0 :   for(;;) {
     200           0 :     int err = fd_snapshot_loader_advance( ctx->loader );
     201           0 :     if( err==MANIFEST_DONE ) break; /* We have finished loading in the manifest. */
     202           0 :     if( FD_LIKELY( !err ) ) continue; /* Keep going. */
     203             : 
     204             :     /* If we have reached the end of the snapshot(err==-1), throw an error because
     205             :        this is not expected. */
     206           0 :     FD_LOG_ERR(( "Failed to load snapshot (%d-%s)", err, fd_io_strerror( err ) ));
     207           0 :   }
     208             : 
     209           0 : }
     210             : 
     211             : void
     212           0 : fd_snapshot_load_accounts( fd_snapshot_load_ctx_t * ctx ) {
     213             : 
     214             :   /* Now, that the manifest is done being read in. Read in the rest of the accounts. */
     215           0 :   for(;;) {
     216           0 :     int err = fd_snapshot_loader_advance( ctx->loader );
     217           0 :     if( err==-1 ) break; /* We have finished loading in the snapshot. */
     218           0 :     if( FD_LIKELY( err==0 ) ) continue; /* Keep going. */
     219             : 
     220           0 :     FD_LOG_ERR(( "Failed to load snapshot (%d-%s)", err, fd_io_strerror( err ) ));
     221           0 :   }
     222             : 
     223           0 :   fd_snapshot_name_t const * name = fd_snapshot_loader_get_name( ctx->loader );
     224           0 :   if( FD_UNLIKELY( !name ) ) FD_LOG_ERR(( "name is NULL" ));
     225             : 
     226           0 :   FD_LOG_NOTICE(( "Done loading accounts" ));
     227             : 
     228           0 :   FD_LOG_NOTICE(( "Finished reading snapshot %s", ctx->snapshot_file ));
     229           0 : }
     230             : 
     231             : void
     232           0 : fd_snapshot_load_fini( fd_snapshot_load_ctx_t * ctx ) {
     233             : 
     234           0 :   fd_snapshot_name_t const * name  = fd_snapshot_loader_get_name( ctx->loader );
     235           0 :   fd_hash_t          const * fhash = &name->fhash;
     236             : 
     237           0 :   if( name->type != ctx->snapshot_type ) {
     238           0 :     FD_LOG_ERR(( "snapshot %s is wrong type", ctx->snapshot_file ));
     239           0 :   }
     240             : 
     241             :   // In order to calculate the snapshot hash, we need to know what features are active...
     242           0 :   fd_features_restore( ctx->slot_ctx, ctx->runtime_spad );
     243           0 :   fd_calculate_epoch_accounts_hash_values( ctx->slot_ctx );
     244             : 
     245             :   // https://github.com/anza-xyz/agave/blob/766cd682423b8049ddeac3c0ec6cebe0a1356e9e/runtime/src/bank.rs#L1831
     246           0 :   if( FD_FEATURE_ACTIVE( ctx->slot_ctx->slot_bank.slot, ctx->slot_ctx->epoch_ctx->features, accounts_lt_hash ) ) {
     247           0 :     ulong *p = (ulong *) ctx->slot_ctx->slot_bank.lthash.lthash;
     248           0 :     ulong *e = (ulong *) &ctx->slot_ctx->slot_bank.lthash.lthash[sizeof(ctx->slot_ctx->slot_bank.lthash.lthash)];
     249           0 :     while (p < e) {
     250           0 :       if ( 0 != *(p++) )
     251           0 :         break;
     252           0 :     }
     253           0 :     if (p >= e)
     254           0 :       FD_LOG_ERR(( "snapshot must have an accounts lt hash if the feature is enabled" ));
     255           0 :   }
     256             : 
     257           0 :   if( ctx->verify_hash ) {
     258           0 :     if( ctx->snapshot_type==FD_SNAPSHOT_TYPE_FULL ) {
     259           0 :       fd_hash_t accounts_hash;
     260           0 :       FD_SPAD_FRAME_BEGIN( ctx->runtime_spad ) {
     261           0 :         fd_snapshot_hash( ctx->slot_ctx, ctx->tpool, &accounts_hash, ctx->check_hash, ctx->runtime_spad );
     262           0 :       } FD_SPAD_FRAME_END;
     263             : 
     264           0 :       if( memcmp( fhash->uc, accounts_hash.uc, sizeof(fd_hash_t) ) ) {
     265           0 :         FD_LOG_ERR(( "snapshot accounts_hash (calculated) %s != (expected) %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ), FD_BASE58_ENC_32_ALLOCA( fhash->uc ) ));
     266           0 :       } else {
     267           0 :         FD_LOG_NOTICE(( "snapshot accounts_hash %s verified successfully", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ) ));
     268           0 :       }
     269           0 :     } else if( ctx->snapshot_type == FD_SNAPSHOT_TYPE_INCREMENTAL ) {
     270           0 :       fd_hash_t accounts_hash;
     271             : 
     272           0 :       if( FD_FEATURE_ACTIVE( ctx->slot_ctx->slot_bank.slot, ctx->slot_ctx->epoch_ctx->features, incremental_snapshot_only_incremental_hash_calculation ) ) {
     273           0 :         FD_LOG_NOTICE(( "hashing incremental snapshot with only deltas" ));
     274           0 :         fd_snapshot_inc_hash( ctx->slot_ctx, &accounts_hash, ctx->child_txn, ctx->check_hash, ctx->runtime_spad );
     275           0 :       } else {
     276           0 :         FD_LOG_NOTICE(( "hashing incremental snapshot with all accounts" ));
     277           0 :         fd_snapshot_hash( ctx->slot_ctx, ctx->tpool, &accounts_hash, ctx->check_hash, ctx->runtime_spad );
     278           0 :       }
     279             : 
     280           0 :       if( memcmp( fhash->uc, accounts_hash.uc, sizeof(fd_hash_t) ) ) {
     281           0 :         FD_LOG_ERR(( "incremental accounts_hash %s != %s", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ), FD_BASE58_ENC_32_ALLOCA( fhash->uc ) ));
     282           0 :       } else {
     283           0 :         FD_LOG_NOTICE(( "incremental accounts_hash %s verified successfully", FD_BASE58_ENC_32_ALLOCA( accounts_hash.hash ) ));
     284           0 :       }
     285           0 :     } else {
     286           0 :       FD_LOG_ERR(( "invalid snapshot type %d", ctx->snapshot_type ));
     287           0 :     }
     288           0 :   }
     289             : 
     290           0 :   if( ctx->child_txn != ctx->par_txn ) {
     291           0 :     fd_funk_txn_publish( ctx->slot_ctx->acc_mgr->funk, ctx->child_txn, 0 );
     292           0 :     ctx->slot_ctx->funk_txn = ctx->par_txn;
     293           0 :   }
     294             : 
     295           0 :   fd_hashes_load( ctx->slot_ctx, ctx->runtime_spad );
     296             : 
     297             :   /* We don't need to free any of the loader memory since it is allocated
     298             :      from a spad. */
     299             : 
     300           0 :   fd_funk_end_write( ctx->slot_ctx->acc_mgr->funk );
     301           0 : }
     302             : 
     303             : void
     304             : fd_snapshot_load_all( const char *         source_cstr,
     305             :                       fd_exec_slot_ctx_t * slot_ctx,
     306             :                       ulong *              base_slot_override,
     307             :                       fd_tpool_t *         tpool,
     308             :                       uint                 verify_hash,
     309             :                       uint                 check_hash,
     310             :                       int                  snapshot_type,
     311             :                       fd_spad_t * *        exec_spads,
     312             :                       ulong                exec_spad_cnt,
     313           0 :                       fd_spad_t *          runtime_spad ) {
     314             : 
     315           0 :   uchar *                  mem = fd_spad_alloc( runtime_spad, fd_snapshot_load_ctx_align(), fd_snapshot_load_ctx_footprint() );
     316           0 :   fd_snapshot_load_ctx_t * ctx = fd_snapshot_load_new( mem,
     317           0 :                                                        source_cstr,
     318           0 :                                                        slot_ctx,
     319           0 :                                                        tpool,
     320           0 :                                                        verify_hash,
     321           0 :                                                        check_hash,
     322           0 :                                                        snapshot_type,
     323           0 :                                                        exec_spads,
     324           0 :                                                        exec_spad_cnt,
     325           0 :                                                        runtime_spad );
     326             : 
     327           0 :   fd_snapshot_load_init( ctx );
     328           0 :   fd_runtime_update_slots_per_epoch( slot_ctx, 432000UL, runtime_spad );
     329           0 :   fd_snapshot_load_manifest_and_status_cache( ctx, base_slot_override,
     330           0 :     FD_SNAPSHOT_RESTORE_STATUS_CACHE | FD_SNAPSHOT_RESTORE_MANIFEST );
     331           0 :   fd_snapshot_load_accounts( ctx );
     332           0 :   fd_snapshot_load_fini( ctx );
     333             : 
     334           0 : }
     335             : 
     336             : void
     337           0 : fd_snapshot_load_prefetch_manifest( fd_snapshot_load_ctx_t * ctx ) {
     338             : 
     339           0 :   fd_funk_start_write( ctx->slot_ctx->acc_mgr->funk );
     340             : 
     341           0 :   size_t slen = strlen( ctx->snapshot_file );
     342           0 :   char * snapshot_cstr = fd_spad_alloc( ctx->runtime_spad, 8UL, slen + 1 );
     343           0 :   fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( snapshot_cstr ), ctx->snapshot_file, slen ) );
     344             : 
     345           0 :   fd_snapshot_src_t src[1];
     346           0 :   if( FD_UNLIKELY( !fd_snapshot_src_parse( src, snapshot_cstr ) ) ) {
     347           0 :     FD_LOG_ERR(( "Failed to load snapshot" ));
     348           0 :   }
     349             : 
     350           0 :   fd_acc_mgr_t *  acc_mgr  = ctx->slot_ctx->acc_mgr;
     351           0 :   fd_funk_txn_t * funk_txn = ctx->slot_ctx->funk_txn;
     352             : 
     353           0 :   void * restore_mem = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_restore_align(), fd_snapshot_restore_footprint() );
     354           0 :   void * loader_mem  = fd_spad_alloc( ctx->runtime_spad, fd_snapshot_loader_align(),  fd_snapshot_loader_footprint( ZSTD_WINDOW_SZ ) );
     355             : 
     356           0 :   ctx->restore = fd_snapshot_restore_new( restore_mem, acc_mgr, funk_txn, ctx->runtime_spad, ctx->slot_ctx, restore_manifest, restore_status_cache, restore_rent_fresh_account );
     357           0 :   ctx->loader  = fd_snapshot_loader_new( loader_mem, ZSTD_WINDOW_SZ );
     358             : 
     359           0 :   if( FD_UNLIKELY( !fd_snapshot_loader_init( ctx->loader, ctx->restore, src, ctx->slot_ctx->slot_bank.slot, 0 ) ) ) {
     360           0 :     FD_LOG_ERR(( "Failed to init snapshot loader" ));
     361           0 :   }
     362             : 
     363             :   /* First load in the manifest. */
     364           0 :   for(;;) {
     365           0 :     int err = fd_snapshot_loader_advance( ctx->loader );
     366           0 :     if( err==MANIFEST_DONE ) break; /* We have finished loading in the manifest. */
     367           0 :     if( FD_LIKELY( !err ) ) continue; /* Keep going. */
     368             : 
     369             :     /* If we have reached the end of the snapshot(err==-1), throw an error because
     370             :        this is not expected. */
     371           0 :     FD_LOG_ERR(( "Failed to load snapshot (%d-%s)", err, fd_io_strerror( err ) ));
     372           0 :   }
     373             : 
     374           0 :   fd_funk_end_write( ctx->slot_ctx->acc_mgr->funk );
     375           0 : }
     376             : 
     377             : ulong
     378           0 : fd_snapshot_get_slot( fd_snapshot_load_ctx_t * ctx ) {
     379           0 :   return fd_snapshot_restore_get_slot( ctx->restore );
     380           0 : }

Generated by: LCOV version 1.14