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

          Line data    Source code
       1             : #define FD_SCRATCH_USE_HANDHOLDING 1
       2             : #include "../fd_flamenco.h"
       3             : #include "../../ballet/base58/fd_base58.h"
       4             : #include "../types/fd_types.h"
       5             : #include "../leaders/fd_leaders.h"
       6             : #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h"
       7             : #include "fd_stakes.h"
       8             : 
       9             : #include <errno.h>
      10             : #include <stdio.h>
      11             : #include <stdlib.h>
      12             : #include <sys/stat.h>
      13             : 
      14             : static int
      15           0 : usage( void ) {
      16           0 :   fprintf( stderr,
      17           0 :     "usage: fd_stakes_from_snapshot {nodes/leaders} {FILE}\n"
      18           0 :     "\n"
      19           0 :     "Derive epoch stake information from snapshot.\n"
      20           0 :     "\n"
      21           0 :     "Mode:\n"
      22           0 :     "  epochs     Print available epochs\n"
      23           0 :     "  nodes      Dump active stake per node identity\n"
      24           0 :     "             CSV format: {pubkey},{stake}\n"
      25           0 :     "  leaders    Dump leader schedule\n"
      26           0 :     "             CSV format: {slot},{pubkey}\n"
      27           0 :     "\n"
      28           0 :     "FILE is the file path to a .tar.zst snapshot or a raw\n"
      29           0 :     "  bincode snapshot manifest\n"
      30           0 :     "\n"
      31           0 :     "Options:\n"
      32           0 :     "\n"
      33           0 :     "  --page-sz      {gigantic|huge|normal}    Page size\n"
      34           0 :     "  --page-cnt     2                         Page count\n"
      35           0 :     "  --scratch-mb   1024                      Scratch mem MiB\n"
      36           0 :     "  --epoch        <ulong>                   Epoch number\n" );
      37           0 :   return 0;
      38           0 : }
      39             : 
      40             : #define ACTION_NODES   (0)
      41             : #define ACTION_LEADERS (1)
      42             : #define ACTION_EPOCHS  (2)
      43             : 
      44             : /* _find_epoch looks for epoch stakes for the requested epoch.
      45             :    On failure, logs error and aborts application. */
      46             : 
      47             : static fd_epoch_stakes_t const *
      48             : _find_epoch( fd_solana_manifest_t const * manifest,
      49           0 :              ulong                        epoch ) {
      50             : 
      51             : 
      52           0 :   if( FD_UNLIKELY( epoch==ULONG_MAX ) ) {
      53           0 :     fprintf( stderr, "error: missing --epoch\n" );
      54           0 :     usage();
      55           0 :     exit(1);
      56           0 :   }
      57             : 
      58           0 :   fd_epoch_stakes_t const * stakes = NULL;
      59           0 :   fd_epoch_epoch_stakes_pair_t const * epochs = manifest->bank.epoch_stakes;
      60           0 :   for( ulong i=0; i < manifest->bank.epoch_stakes_len; i++ ) {
      61           0 :     if( epochs[ i ].key==epoch ) {
      62           0 :       stakes = &epochs[i].value;
      63           0 :       break;
      64           0 :     }
      65           0 :   }
      66           0 :   if( FD_UNLIKELY( !stakes ) )
      67           0 :     FD_LOG_ERR(( "Snapshot missing EpochStakes for epoch %lu", epoch ));
      68             : 
      69           0 :   return stakes;
      70           0 : }
      71             : 
      72             : static fd_stake_weight_t *
      73             : _get_stake_weights( fd_solana_manifest_t const * manifest,
      74             :                     ulong                        epoch,
      75           0 :                     ulong *                      out_cnt ) {
      76             : 
      77           0 :   fd_epoch_stakes_t  const * stakes = _find_epoch( manifest, epoch );
      78           0 :   fd_vote_accounts_t const * vaccs = &stakes->stakes.vote_accounts;
      79             : 
      80           0 :   ulong vote_acc_cnt = fd_vote_accounts_pair_t_map_size( vaccs->vote_accounts_pool, vaccs->vote_accounts_root );
      81           0 :   FD_LOG_NOTICE(( "vote_acc_cnt=%lu", vote_acc_cnt ));
      82           0 :   fd_stake_weight_t * weights = fd_scratch_alloc( alignof(fd_stake_weight_t), vote_acc_cnt * sizeof(fd_stake_weight_t) );
      83           0 :   if( FD_UNLIKELY( !weights ) ) FD_LOG_ERR(( "fd_scratch_alloc() failed" ));
      84             : 
      85           0 :   ulong weight_cnt = fd_stake_weights_by_node( vaccs, weights );
      86           0 :   if( FD_UNLIKELY( weight_cnt==ULONG_MAX ) ) FD_LOG_ERR(( "fd_stake_weights_by_node() failed" ));
      87             : 
      88           0 :   *out_cnt = weight_cnt;
      89           0 :   return weights;
      90           0 : }
      91             : 
      92             : static int
      93           0 : action_epochs( fd_solana_manifest_t const * manifest ) {
      94           0 :   fd_epoch_epoch_stakes_pair_t const * epochs = manifest->bank.epoch_stakes;
      95           0 :   for( ulong i=0; i < manifest->bank.epoch_stakes_len; i++ )
      96           0 :     printf( "%lu\n", epochs[ i ].key );
      97           0 :   return 0;
      98           0 : }
      99             : 
     100             : static int
     101             : action_nodes( fd_solana_manifest_t const * manifest,
     102           0 :               ulong                        epoch ) {
     103             : 
     104           0 :   ulong               weight_cnt;
     105           0 :   fd_stake_weight_t * weights = _get_stake_weights( manifest, epoch, &weight_cnt );
     106             : 
     107           0 :   for( ulong i=0UL; i<weight_cnt; i++ ) {
     108           0 :     fd_stake_weight_t const * w = weights + i;
     109           0 :     char keyB58[ FD_BASE58_ENCODED_32_SZ ];
     110           0 :     fd_base58_encode_32( w->key.key, NULL,  keyB58 );
     111           0 :     printf( "%s,%lu\n", keyB58, w->stake );
     112           0 :   }
     113             : 
     114           0 :   return 0;
     115           0 : }
     116             : 
     117             : static int
     118             : action_leaders( fd_solana_manifest_t const * manifest,
     119           0 :                 ulong                        epoch ) {
     120             : 
     121           0 :   ulong               weight_cnt;
     122           0 :   fd_stake_weight_t * weights = _get_stake_weights( manifest, epoch, &weight_cnt );
     123             : 
     124           0 :   fd_epoch_schedule_t const * sched = &manifest->bank.epoch_schedule;
     125           0 :   ulong slot0     = fd_epoch_slot0   ( sched, epoch );
     126           0 :   ulong slot_cnt  = fd_epoch_slot_cnt( sched, epoch );
     127           0 :   ulong sched_cnt = slot_cnt/FD_EPOCH_SLOTS_PER_ROTATION;
     128             : 
     129           0 :   void * leaders_mem = fd_scratch_alloc( fd_epoch_leaders_align(), fd_epoch_leaders_footprint( weight_cnt, sched_cnt ) );
     130           0 :          leaders_mem = fd_epoch_leaders_new( leaders_mem, epoch, slot0, slot_cnt, weight_cnt, weights, 0UL );
     131           0 :   fd_epoch_leaders_t * leaders = fd_epoch_leaders_join( leaders_mem );
     132           0 :   FD_TEST( leaders );
     133             : 
     134           0 :   ulong slot = slot0;
     135           0 :   for( ulong i=0; i<sched_cnt; i++ ) {
     136           0 :     fd_pubkey_t const * leader = fd_epoch_leaders_get( leaders, slot );
     137           0 :     char keyB58[ FD_BASE58_ENCODED_32_SZ ];
     138           0 :     fd_base58_encode_32( leader->key, NULL, keyB58 );
     139           0 :     for( ulong j=0; j<FD_EPOCH_SLOTS_PER_ROTATION; j++ ) {
     140           0 :       printf( "%lu,%s\n", slot, keyB58 );
     141           0 :       slot++;
     142           0 :     }
     143           0 :   }
     144             : 
     145           0 :   return 0;
     146           0 : }
     147             : 
     148             : /* _is_zstd returns 1 if given file handle points to the beginning of a
     149             :     zstd stream, otherwise zero. */
     150             : 
     151             : static int
     152           0 : _is_zstd( FILE * file ) {
     153           0 :   uint magic;
     154           0 :   ulong n = fread( &magic, 1UL, 4UL, file );
     155           0 :   if( FD_UNLIKELY( feof( file ) ) ) {
     156           0 :     clearerr( file );
     157           0 :     fseek( file, -(long)n, SEEK_CUR );
     158           0 :     return 0;
     159           0 :   }
     160           0 :   int err = ferror( file );
     161           0 :   if( FD_UNLIKELY( err ) )
     162           0 :     FD_LOG_ERR(( "fread() failed (%d-%s)", err, strerror( err ) ));
     163           0 :   fseek( file, -4L, SEEK_CUR );
     164           0 :   return ( magic==0xFD2FB528UL );
     165           0 : }
     166             : 
     167             : /* TODO older Solana snapshots are gzip, add support */
     168             : 
     169             : int
     170             : main( int     argc,
     171             :       char ** argv ) {
     172             :   fd_boot( &argc, &argv );
     173             :   fd_flamenco_boot( &argc, &argv );
     174             : 
     175             :   for( int i=1; i<argc; i++ )
     176             :     if( 0==strcmp( argv[i], "--help" ) ) return usage();
     177             : 
     178             :   char const * _page_sz   = fd_env_strip_cmdline_cstr ( &argc, &argv, "--page-sz",    NULL, "gigantic" );
     179             :   ulong        page_cnt   = fd_env_strip_cmdline_ulong( &argc, &argv, "--page-cnt",   NULL, 2UL        );
     180             :   ulong        scratch_mb = fd_env_strip_cmdline_ulong( &argc, &argv, "--scratch-mb", NULL, 1024UL     );
     181             :   ulong        epoch      = fd_env_strip_cmdline_ulong( &argc, &argv, "--epoch",      NULL, ULONG_MAX  );
     182             : 
     183             :   ulong page_sz = fd_cstr_to_shmem_page_sz( _page_sz );
     184             :   if( FD_UNLIKELY( !page_sz ) ) FD_LOG_ERR(( "unsupported --page-sz" ));
     185             : 
     186             :   if( FD_UNLIKELY( argc!=3 ) ) {
     187             :     fprintf( stderr, "error: missing arguments\n" );
     188             :     return usage();
     189             :   }
     190             : 
     191             :   char const * mode     = argv[1];
     192             :   char const * filepath = argv[2];
     193             : 
     194             :   int action;
     195             :   /**/ if( 0==strcmp( mode, "epochs"  ) ) action = ACTION_EPOCHS;
     196             :   else if( 0==strcmp( mode, "nodes"   ) ) action = ACTION_NODES;
     197             :   else if( 0==strcmp( mode, "leaders" ) ) action = ACTION_LEADERS;
     198             :   else {
     199             :     fprintf( stderr, "error: invalid mode \"%s\"\n", mode );
     200             :     return usage();
     201             :   }
     202             : 
     203             :   /* Create workspace and scratch allocator */
     204             : 
     205             :   fd_wksp_t * wksp = fd_wksp_new_anonymous( page_sz, page_cnt, fd_log_cpu_id(), "wksp", 0UL );
     206             :   if( FD_UNLIKELY( !wksp ) ) FD_LOG_ERR(( "fd_wksp_new_anonymous() failed" ));
     207             : 
     208             :   ulong  smax = scratch_mb << 20;
     209             :   void * smem = fd_wksp_alloc_laddr( wksp, fd_scratch_smem_align(), smax, 1UL );
     210             :   if( FD_UNLIKELY( !smem ) ) FD_LOG_ERR(( "Failed to alloc scratch mem" ));
     211             :   ulong  scratch_depth = 4UL;
     212             :   void * fmem = fd_wksp_alloc_laddr( wksp, fd_scratch_fmem_align(), fd_scratch_fmem_footprint( scratch_depth ), 2UL );
     213             :   if( FD_UNLIKELY( !fmem ) ) FD_LOG_ERR(( "Failed to alloc scratch frames" ));
     214             : 
     215             :   fd_scratch_attach( smem, fmem, smax, scratch_depth );
     216             :   fd_scratch_push();
     217             :   fd_valloc_t scratch_valloc = fd_scratch_virtual();
     218             : 
     219             :   /* Open file */
     220             : 
     221             :   FD_LOG_INFO(( "Reading snapshot %s", filepath ));
     222             :   FILE * file = fopen( filepath, "rb" );
     223             :   if( FD_UNLIKELY( !file ) ) FD_LOG_ERR(( "fopen(%s) failed (%d-%s)", filepath, errno, strerror( errno ) ));
     224             : 
     225             :   /* Read manifest bytes */
     226             : 
     227             :   void * manifest_bin;
     228             :   ulong  manifest_binsz;
     229             :   if( _is_zstd( file ) ) {
     230             :     FD_LOG_NOTICE(( "Detected .tar.zst stream" ));
     231             :     FD_LOG_ERR(( "TODO" ));
     232             :   } else {
     233             :     FD_LOG_NOTICE(( "Assuming raw bincode file" ));
     234             : 
     235             :     /* Allocate buffer suitable for storing file */
     236             : 
     237             :     struct stat stat;
     238             :     int err = fstat( fileno( file ), &stat );
     239             :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fstat() failed (%d-%s)", errno, strerror( errno ) ));
     240             :     manifest_binsz = (ulong)stat.st_size;
     241             : 
     242             :     manifest_bin = fd_wksp_alloc_laddr( wksp, 1UL, manifest_binsz, 3UL );
     243             :     if( FD_UNLIKELY( !manifest_bin ) ) FD_LOG_ERR(( "failed to allocate metadata buffer" ));
     244             : 
     245             :     /* Read file into buffer */
     246             : 
     247             :     ulong n = fread( manifest_bin, manifest_binsz, 1UL, file );
     248             :     if( FD_UNLIKELY( n!=1UL ) ) FD_LOG_ERR(( "fread() failed (eof=%d)", feof( file ) ));
     249             :     FD_LOG_NOTICE(( "Read manifest (%.3f MiB)", (double)manifest_binsz/(1UL<<20) ));
     250             :   }
     251             : 
     252             :   /* Deserialize manifest */
     253             : 
     254             :   long dt = -fd_log_wallclock();
     255             :   fd_solana_manifest_t manifest;
     256             : 
     257             :   fd_bincode_decode_ctx_t decode = {
     258             :     .valloc  = scratch_valloc,
     259             :     .data    = manifest_bin,
     260             :     .dataend = (void *)( (ulong)manifest_bin + manifest_binsz ),
     261             :   };
     262             :   if( FD_UNLIKELY( FD_BINCODE_SUCCESS!=
     263             :                    fd_solana_manifest_decode( &manifest, &decode ) ) )
     264             :     FD_LOG_ERR(( "Failed to deserialize manifest" ));
     265             : 
     266             :   fd_wksp_free_laddr( manifest_bin ); manifest_bin = NULL;
     267             :   dt += fd_log_wallclock();
     268             :   FD_LOG_NOTICE(( "Deserialized manifest (took %.3fs)", (double)dt/1e9 ));
     269             : 
     270             :   /* Action */
     271             : 
     272             :   int res;
     273             :   fd_scratch_push();
     274             :   switch( action ) {
     275             :   case ACTION_LEADERS:
     276             :     res = action_leaders( &manifest, epoch );
     277             :     break;
     278             :   case ACTION_NODES:
     279             :     res = action_nodes( &manifest, epoch );
     280             :     break;
     281             :   case ACTION_EPOCHS:
     282             :     res = action_epochs( &manifest );
     283             :     break;
     284             :   default:
     285             :     __builtin_unreachable();
     286             :   }
     287             :   fd_scratch_pop();
     288             : 
     289             :   /* Cleanup */
     290             : 
     291             :   fd_scratch_pop();
     292             :   FD_TEST( fd_scratch_frame_used()==0UL );
     293             :   fd_wksp_free_laddr( fd_scratch_detach( NULL ) );
     294             :   fd_wksp_free_laddr( fmem                      );
     295             :   fclose( file );
     296             :   fd_wksp_detach( wksp );
     297             :   fd_flamenco_halt();
     298             :   fd_halt();
     299             :   return res;
     300             : }

Generated by: LCOV version 1.14