LCOV - code coverage report
Current view: top level - discof/genesis - fd_genesi_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 166 0.0 %
Date: 2025-10-13 04:42:14 Functions: 0 10 0.0 %

          Line data    Source code
       1             : #include "../../disco/topo/fd_topo.h"
       2             : #include "../../funk/fd_funk.h"
       3             : #include "../../flamenco/types/fd_types.h"
       4             : #include "../../ballet/lthash/fd_lthash.h"
       5             : #include "../../ballet/sha256/fd_sha256.h"
       6             : #include "../../flamenco/runtime/fd_acc_mgr.h"
       7             : #include "../../flamenco/runtime/fd_hashes.h"
       8             : 
       9             : #include <errno.h>
      10             : #include <fcntl.h>
      11             : #include <sys/stat.h>
      12             : #include <unistd.h>
      13             : 
      14             : #include "generated/fd_genesi_tile_seccomp.h"
      15             : struct fd_genesi_tile {
      16             :   int fd;
      17             : 
      18             :   fd_funk_t funk[1];
      19             : 
      20             :   ushort shred_version;
      21             :   uchar  genesis_hash[ 32UL ];
      22             : 
      23             :   fd_lthash_value_t lthash[1];
      24             : 
      25             :   int bootstrap;
      26             :   int shutdown;
      27             : 
      28             :   ulong genesis_sz;
      29             :   uchar genesis[ 10UL*1024UL*1024UL ] __attribute__((aligned(alignof(fd_genesis_solana_global_t)))); /* 10 MiB buffer for decoded genesis */
      30             :   uchar buffer[ 10UL*1024UL*1024UL ]; /* 10 MiB buffer for reading genesis file */
      31             : 
      32             :   fd_wksp_t * out_mem;
      33             :   ulong       out_chunk0;
      34             :   ulong       out_wmark;
      35             :   ulong       out_chunk;
      36             : };
      37             : 
      38             : typedef struct fd_genesi_tile fd_genesi_tile_t;
      39             : 
      40             : FD_FN_CONST static inline ulong
      41           0 : scratch_align( void ) {
      42           0 :   return alignof( fd_genesi_tile_t );
      43           0 : }
      44             : 
      45             : FD_FN_PURE static inline ulong
      46           0 : scratch_footprint( fd_topo_tile_t const * tile ) {
      47           0 :   (void)tile;
      48             : 
      49           0 :   ulong l = FD_LAYOUT_INIT;
      50           0 :   l = FD_LAYOUT_APPEND( l, alignof( fd_genesi_tile_t ), sizeof( fd_genesi_tile_t ) );
      51           0 :   return FD_LAYOUT_FINI( l, scratch_align() );
      52           0 : }
      53             : 
      54             : static inline int
      55           0 : should_shutdown( fd_genesi_tile_t * ctx ) {
      56           0 :   return ctx->shutdown;
      57           0 : }
      58             : 
      59             : static void
      60           0 : initialize_accdb( fd_genesi_tile_t * ctx ) {
      61             :   /* Change 'last published' XID to 0 */
      62           0 :   fd_funk_txn_xid_t root_xid; fd_funk_txn_xid_set_root( &root_xid );
      63           0 :   fd_funk_txn_xid_t target_xid = { .ul = { 0UL, 0UL } };
      64           0 :   fd_funk_txn_prepare( ctx->funk, &root_xid, &target_xid );
      65           0 :   fd_funk_txn_publish( ctx->funk, &target_xid );
      66             : 
      67           0 :   fd_genesis_solana_global_t * genesis = fd_type_pun( ctx->genesis );
      68             : 
      69           0 :   fd_pubkey_account_pair_global_t const * accounts = fd_genesis_solana_accounts_join( genesis );
      70             : 
      71           0 :   for( ulong i=0UL; i<genesis->accounts_len; i++ ) {
      72           0 :     fd_pubkey_account_pair_global_t const * account = &accounts[ i ];
      73             : 
      74           0 :     fd_funk_rec_prepare_t prepare;
      75             : 
      76           0 :     FD_TXN_ACCOUNT_DECL( rec );
      77           0 :     int err = fd_txn_account_init_from_funk_mutable( rec,
      78           0 :                                                      &account->key,
      79           0 :                                                      ctx->funk,
      80           0 :                                                      &target_xid,
      81           0 :                                                      1, /* do_create */
      82           0 :                                                      account->account.data_len,
      83           0 :                                                      &prepare );
      84           0 :     FD_TEST( !err );
      85             : 
      86           0 :     fd_txn_account_set_data( rec, fd_solana_account_data_join( &account->account ), account->account.data_len );
      87           0 :     fd_txn_account_set_lamports( rec, account->account.lamports );
      88           0 :     fd_txn_account_set_executable( rec, account->account.executable );
      89           0 :     fd_txn_account_set_owner( rec, &account->account.owner );
      90           0 :     fd_txn_account_mutable_fini( rec, ctx->funk, &prepare );
      91             : 
      92           0 :     fd_lthash_value_t new_hash[1];
      93           0 :     fd_hashes_account_lthash( rec->pubkey, fd_txn_account_get_meta( rec ), fd_txn_account_get_data( rec ), new_hash );
      94           0 :     fd_lthash_add( ctx->lthash, new_hash );
      95           0 :   }
      96           0 : }
      97             : 
      98             : static void
      99             : after_credit( fd_genesi_tile_t *  ctx,
     100             :               fd_stem_context_t * stem,
     101             :               int *               opt_poll_in,
     102           0 :               int *               charge_busy ) {
     103           0 :   (void)opt_poll_in;
     104             : 
     105           0 :   if( FD_UNLIKELY( ctx->shutdown ) ) return;
     106             : 
     107           0 :   *charge_busy = 1;
     108             : 
     109           0 :   initialize_accdb( ctx );
     110             : 
     111           0 :   uchar * dst = fd_chunk_to_laddr( ctx->out_mem, ctx->out_chunk );
     112           0 :   fd_memcpy( dst, &ctx->lthash->bytes, sizeof(fd_lthash_value_t) );
     113           0 :   fd_memcpy( dst+sizeof(fd_lthash_value_t), &ctx->genesis_hash, sizeof(fd_hash_t) );
     114           0 :   fd_memcpy( dst+sizeof(fd_lthash_value_t)+sizeof(fd_hash_t), ctx->genesis, ctx->genesis_sz );
     115             : 
     116           0 :   fd_stem_publish( stem, 0UL, ctx->shred_version, ctx->out_chunk, 0UL, 0UL, 0UL, 0UL );
     117           0 :   ctx->out_chunk = fd_dcache_compact_next( ctx->out_chunk, ctx->genesis_sz+sizeof(fd_hash_t)+sizeof(fd_lthash_value_t), ctx->out_chunk0, ctx->out_wmark );
     118             : 
     119           0 :   ctx->shutdown = 1;
     120           0 : }
     121             : 
     122             : static void
     123             : process_local_genesis( fd_genesi_tile_t * ctx,
     124             :                        char const *       genesis_path,
     125           0 :                        ushort             expected_shred_version ) {
     126           0 :   struct stat st;
     127           0 :   int err = fstat( ctx->fd, &st );
     128           0 :   if( FD_UNLIKELY( -1==err ) ) FD_LOG_ERR(( "stat() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     129             : 
     130           0 :   ulong size = (ulong)st.st_size;
     131             : 
     132           0 :   if( FD_UNLIKELY( size>sizeof(ctx->buffer) ) ) FD_LOG_ERR(( "genesis file `%s` too large (%lu bytes, max %lu)", genesis_path, size, (ulong)sizeof(ctx->buffer) ));
     133             : 
     134           0 :   ulong bytes_read = 0UL;
     135           0 :   while( bytes_read<size ) {
     136           0 :     long result = read( ctx->fd, ctx->buffer+bytes_read, size-bytes_read );
     137           0 :     if( FD_UNLIKELY( -1==result ) ) FD_LOG_ERR(( "read() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     138           0 :     if( FD_UNLIKELY( !result ) )  FD_LOG_ERR(( "read() returned 0 before reading full file" ));
     139           0 :     bytes_read += (ulong)result;
     140           0 :   }
     141             : 
     142           0 :   FD_TEST( bytes_read==size );
     143             : 
     144           0 :   if( FD_UNLIKELY( -1==close( ctx->fd ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     145             : 
     146           0 :   fd_bincode_decode_ctx_t decode_ctx = {
     147           0 :     .data    = ctx->buffer,
     148           0 :     .dataend = ctx->buffer+size,
     149           0 :   };
     150             : 
     151           0 :   ctx->genesis_sz = 0UL;
     152           0 :   err = fd_genesis_solana_decode_footprint( &decode_ctx, &ctx->genesis_sz );
     153           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) FD_LOG_ERR(( "malformed genesis file at `%s`", genesis_path ));
     154           0 :   if( FD_UNLIKELY( ctx->genesis_sz>sizeof(ctx->genesis) ) ) FD_LOG_ERR(( "genesis file at `%s` decode footprint too large (%lu bytes, max %lu)", genesis_path, ctx->genesis_sz, sizeof(ctx->genesis) ));
     155             : 
     156           0 :   fd_genesis_solana_global_t * genesis = fd_genesis_solana_decode_global( ctx->genesis, &decode_ctx );
     157           0 :   FD_TEST( genesis );
     158             : 
     159           0 :   union {
     160           0 :     uchar  c[ 32 ];
     161           0 :     ushort s[ 16 ];
     162           0 :   } hash;
     163           0 :   fd_sha256_hash( ctx->buffer, size, hash.c );
     164             : 
     165           0 :   fd_memcpy( ctx->genesis_hash, hash.c, 32UL );
     166             : 
     167           0 :   ushort xor = 0;
     168           0 :   for( ulong i=0UL; i<16UL; i++ ) xor ^= hash.s[ i ];
     169             : 
     170           0 :   xor = fd_ushort_bswap( xor );
     171           0 :   xor = fd_ushort_if( xor<USHORT_MAX, (ushort)(xor + 1), USHORT_MAX );
     172             : 
     173           0 :   ctx->shred_version = xor;
     174           0 :   FD_TEST( ctx->shred_version );
     175             : 
     176           0 :   if( FD_UNLIKELY( ctx->bootstrap && expected_shred_version && expected_shred_version!=ctx->shred_version ) ) {
     177           0 :     FD_LOG_ERR(( "This node is bootstrapping the cluster as it has no gossip entrypoints provided, but "
     178           0 :                  "a [consensus.expected_shred_version] of %hu is provided which does not match the shred "
     179           0 :                  "version of %hu computed from the genesis.bin file at `%s`",
     180           0 :                  expected_shred_version, ctx->shred_version, genesis_path ));
     181           0 :   }
     182           0 : }
     183             : 
     184             : static void
     185             : privileged_init( fd_topo_t *      topo,
     186           0 :                  fd_topo_tile_t * tile ) {
     187           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     188             : 
     189           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     190           0 :   fd_genesi_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_genesi_tile_t ), sizeof( fd_genesi_tile_t ) );
     191             : 
     192           0 :   ctx->fd = open( tile->genesi.genesis_path, O_RDONLY|O_CLOEXEC );
     193           0 :   if( FD_UNLIKELY( -1==ctx->fd ) ) {
     194           0 :     if( FD_LIKELY( errno==ENOENT  ) ) {
     195           0 :       if( FD_UNLIKELY( !tile->genesi.entrypoints_cnt ) ) {
     196           0 :         FD_LOG_ERR(( "This node is bootstrapping the cluster as it has no gossip entrypoints provided, but "
     197           0 :                      "the genesis.bin file at `%s` does not exist.  Please provide a valid genesis.bin "
     198           0 :                      "file by running genesis, or join an existing cluster.",
     199           0 :                      tile->genesi.genesis_path ));
     200           0 :       } else {
     201           0 :         if( FD_UNLIKELY( !tile->genesi.allow_download ) ) {
     202           0 :           FD_LOG_ERR(( "There is no genesis.bin file at `%s` and automatic downloading is disabled as "
     203           0 :                        "genesis_download is false in your configuration file.  Please either provide a valid "
     204           0 :                        "genesis.bin file locally, or allow donwloading from a gossip entrypoint.",
     205           0 :                        tile->genesi.genesis_path ));
     206           0 :         } else {
     207           0 :           FD_LOG_WARNING(( "UNIMPLEMENTED: automatic downloading of genesis.bin from gossip entrypoints is not yet implemented. "
     208           0 :                            "expected_genesis_hash and shred_version will not be verified." ));
     209           0 :         }
     210           0 :       }
     211           0 :     } else {
     212           0 :       FD_LOG_ERR(( "could not open genesis.bin file at `%s` (%i-%s)", tile->genesi.genesis_path, errno, fd_io_strerror( errno ) ));
     213           0 :     }
     214           0 :   }
     215           0 : }
     216             : 
     217             : static void
     218             : unprivileged_init( fd_topo_t *      topo,
     219           0 :                    fd_topo_tile_t * tile ) {
     220           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     221             : 
     222           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     223           0 :   fd_genesi_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_genesi_tile_t ), sizeof( fd_genesi_tile_t ) );
     224             : 
     225           0 :   FD_TEST( fd_funk_join( ctx->funk, fd_topo_obj_laddr( topo, tile->genesi.funk_obj_id ) ) );
     226             : 
     227           0 :   fd_lthash_zero( ctx->lthash );
     228             : 
     229           0 :   ctx->shutdown = !!tile->genesi.entrypoints_cnt;
     230           0 :   ctx->bootstrap = !!tile->genesi.entrypoints_cnt;
     231           0 :   if( FD_LIKELY( -1!=ctx->fd ) ) process_local_genesis( ctx, tile->genesi.genesis_path, tile->genesi.expected_shred_version );
     232             : 
     233           0 :   ctx->out_mem    = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp;
     234           0 :   ctx->out_chunk0 = fd_dcache_compact_chunk0( ctx->out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache );
     235           0 :   ctx->out_wmark  = fd_dcache_compact_wmark ( ctx->out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache, topo->links[ tile->out_link_id[ 0 ] ].mtu );
     236           0 :   ctx->out_chunk  = ctx->out_chunk0;
     237             : 
     238           0 :   ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
     239           0 :   if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
     240           0 :     FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
     241           0 : }
     242             : 
     243             : static ulong
     244             : populate_allowed_seccomp( fd_topo_t const *      topo,
     245             :                           fd_topo_tile_t const * tile,
     246             :                           ulong                  out_cnt,
     247           0 :                           struct sock_filter *   out ) {
     248             : 
     249           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     250             : 
     251           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     252           0 :   fd_genesi_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_genesi_tile_t ), sizeof( fd_genesi_tile_t ) );
     253             : 
     254           0 :   populate_sock_filter_policy_fd_genesi_tile( out_cnt, out, (uint)fd_log_private_logfile_fd(), (uint)ctx->fd );
     255           0 :   return sock_filter_policy_fd_genesi_tile_instr_cnt;
     256           0 : }
     257             : 
     258             : static ulong
     259             : populate_allowed_fds( fd_topo_t const *      topo,
     260             :                       fd_topo_tile_t const * tile,
     261             :                       ulong                  out_fds_cnt,
     262           0 :                       int *                  out_fds ) {
     263           0 :   void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
     264             : 
     265           0 :   FD_SCRATCH_ALLOC_INIT( l, scratch );
     266           0 :   fd_genesi_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_genesi_tile_t ), sizeof( fd_genesi_tile_t ) );
     267             : 
     268           0 :   if( FD_UNLIKELY( out_fds_cnt<3UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
     269             : 
     270           0 :   ulong out_cnt = 0UL;
     271           0 :   out_fds[ out_cnt++ ] = 2; /* stderr */
     272           0 :   if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
     273           0 :     out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
     274           0 :   if( FD_LIKELY( ctx->fd!=-1 ) ) out_fds[ out_cnt++ ] = ctx->fd;
     275           0 :   return out_cnt;
     276           0 : }
     277             : 
     278           0 : #define STEM_BURST (1UL)
     279             : 
     280           0 : #define STEM_CALLBACK_CONTEXT_TYPE  fd_genesi_tile_t
     281           0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_genesi_tile_t)
     282             : 
     283           0 : #define STEM_CALLBACK_AFTER_CREDIT    after_credit
     284             : #define STEM_CALLBACK_SHOULD_SHUTDOWN should_shutdown
     285             : 
     286             : #include "../../disco/stem/fd_stem.c"
     287             : 
     288             : fd_topo_run_tile_t fd_tile_genesi = {
     289             :   .name                     = "genesi",
     290             :   .populate_allowed_seccomp = populate_allowed_seccomp,
     291             :   .populate_allowed_fds     = populate_allowed_fds,
     292             :   .scratch_align            = scratch_align,
     293             :   .scratch_footprint        = scratch_footprint,
     294             :   .privileged_init          = privileged_init,
     295             :   .unprivileged_init        = unprivileged_init,
     296             :   .run                      = stem_run,
     297             : };

Generated by: LCOV version 1.14