LCOV - code coverage report
Current view: top level - flamenco/runtime/sysvar - fd_sysvar_epoch_schedule.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 89 108 82.4 %
Date: 2024-11-13 11:58:15 Functions: 8 8 100.0 %

          Line data    Source code
       1             : #include "fd_sysvar_epoch_schedule.h"
       2             : #include "fd_sysvar.h"
       3             : #include "../fd_system_ids.h"
       4             : #include "../context/fd_exec_epoch_ctx.h"
       5             : #include "../context/fd_exec_slot_ctx.h"
       6             : 
       7             : fd_epoch_schedule_t *
       8             : fd_epoch_schedule_derive( fd_epoch_schedule_t * schedule,
       9             :                           ulong                 epoch_len,
      10             :                           ulong                 leader_schedule_slot_offset,
      11       12102 :                           int                   warmup ) {
      12             : 
      13       12102 :   if( FD_UNLIKELY( epoch_len < FD_EPOCH_LEN_MIN ) ) {
      14           0 :     FD_LOG_WARNING(( "epoch_len too small" ));
      15           0 :     return NULL;
      16           0 :   }
      17             : 
      18       12102 :   *schedule = (fd_epoch_schedule_t) {
      19       12102 :     .slots_per_epoch             = epoch_len,
      20       12102 :     .leader_schedule_slot_offset = leader_schedule_slot_offset,
      21       12102 :     .warmup                      = !!warmup
      22       12102 :   };
      23             : 
      24       12102 :   if( warmup ) {
      25        6051 :     ulong ceil_log2_epoch   = (ulong)fd_ulong_find_msb( epoch_len-1UL ) + 1UL;
      26        6051 :     ulong ceil_log2_len_min = (ulong)fd_ulong_find_msb( FD_EPOCH_LEN_MIN );
      27             : 
      28        6051 :     schedule->first_normal_epoch = fd_ulong_sat_sub( ceil_log2_epoch, ceil_log2_len_min );
      29        6051 :     schedule->first_normal_slot  = (1UL << ceil_log2_epoch) - FD_EPOCH_LEN_MIN;
      30        6051 :   }
      31             : 
      32       12102 :   return schedule;
      33       12102 : }
      34             : 
      35             : static void
      36             : write_epoch_schedule( fd_exec_slot_ctx_t  * slot_ctx,
      37       11370 :                       fd_epoch_schedule_t * epoch_schedule ) {
      38       11370 :   ulong sz  = fd_epoch_schedule_size( epoch_schedule );
      39       11370 :   FD_LOG_INFO(("Writing epoch schedule size %lu", sz));
      40             :   /* TODO remove alloca */
      41       11370 :   uchar enc[ sz ];
      42       11370 :   memset( enc, 0, sz );
      43       11370 :   fd_bincode_encode_ctx_t ctx;
      44       11370 :   ctx.data = enc;
      45       11370 :   ctx.dataend = enc + sz;
      46       11370 :   if ( fd_epoch_schedule_encode( epoch_schedule, &ctx ) )
      47           0 :     FD_LOG_ERR(("fd_epoch_schedule_encode failed"));
      48             : 
      49       11370 :   fd_sysvar_set( slot_ctx, fd_sysvar_owner_id.key, &fd_sysvar_epoch_schedule_id, enc, sz, slot_ctx->slot_bank.slot );
      50       11370 : }
      51             : 
      52             : fd_epoch_schedule_t *
      53             : fd_sysvar_epoch_schedule_read( fd_epoch_schedule_t *      result,
      54           6 :                                fd_exec_slot_ctx_t const * slot_ctx ) {
      55           6 :   fd_epoch_schedule_t const * ret = fd_sysvar_cache_epoch_schedule( slot_ctx->sysvar_cache );
      56           6 :   if( FD_UNLIKELY( NULL != ret ) ) {
      57           6 :     fd_memcpy(result, ret, sizeof(fd_epoch_schedule_t));
      58           6 :     return result;
      59           6 :   }
      60             : 
      61           0 :   FD_BORROWED_ACCOUNT_DECL(acc);
      62           0 :   int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, &fd_sysvar_epoch_schedule_id, acc );
      63           0 :   if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) )
      64           0 :     return NULL;
      65             : 
      66           0 :   fd_bincode_decode_ctx_t decode =
      67           0 :     { .data    = acc->const_data,
      68           0 :       .dataend = acc->const_data + acc->const_meta->dlen,
      69           0 :       .valloc  = {0}  /* valloc not required */ };
      70             : 
      71           0 :   if( FD_UNLIKELY( fd_epoch_schedule_decode( result, &decode )!=FD_BINCODE_SUCCESS ) )
      72           0 :     return NULL;
      73           0 :   return result;
      74           0 : }
      75             : 
      76             : void
      77       11370 : fd_sysvar_epoch_schedule_init( fd_exec_slot_ctx_t * slot_ctx ) {
      78       11370 :   fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
      79       11370 :   write_epoch_schedule( slot_ctx, &epoch_bank->epoch_schedule );
      80       11370 : }
      81             : 
      82             : /* https://github.com/solana-labs/solana/blob/88aeaa82a856fc807234e7da0b31b89f2dc0e091/sdk/program/src/epoch_schedule.rs#L105 */
      83             : 
      84             : ulong
      85             : fd_epoch_slot_cnt( fd_epoch_schedule_t const * schedule,
      86         456 :                    ulong                       epoch ) {
      87             : 
      88         456 :   if( FD_UNLIKELY( epoch < schedule->first_normal_epoch ) ) {
      89         426 :     ulong exp = fd_ulong_sat_add( epoch, (ulong)fd_ulong_find_lsb( FD_EPOCH_LEN_MIN ) );
      90         426 :     return ( exp<64UL ? 1UL<<exp : ULONG_MAX ); // saturating_pow
      91         426 :   }
      92             : 
      93          30 :   return schedule->slots_per_epoch;
      94         456 : }
      95             : 
      96             : /* https://github.com/solana-labs/solana/blob/88aeaa82a856fc807234e7da0b31b89f2dc0e091/sdk/program/src/epoch_schedule.rs#L170 */
      97             : 
      98             : ulong
      99             : fd_epoch_slot0( fd_epoch_schedule_t const * schedule,
     100         126 :                 ulong                       epoch ) {
     101         126 :   if( FD_UNLIKELY( epoch < schedule->first_normal_epoch ) ) {
     102         108 :     ulong power = fd_ulong_if( epoch<64UL, 1UL<<epoch, ULONG_MAX );
     103         108 :     return fd_ulong_sat_mul( power-1UL, FD_EPOCH_LEN_MIN );
     104         108 :   }
     105             : 
     106          18 :   return fd_ulong_sat_add(
     107          18 :           fd_ulong_sat_mul(
     108          18 :             fd_ulong_sat_sub(
     109          18 :               epoch,
     110          18 :               schedule->first_normal_epoch),
     111          18 :             schedule->slots_per_epoch),
     112          18 :           schedule->first_normal_slot);
     113         126 : }
     114             : 
     115             : /* https://github.com/solana-labs/solana/blob/88aeaa82a856fc807234e7da0b31b89f2dc0e091/sdk/program/src/epoch_schedule.rs#L140 */
     116             : 
     117             : ulong
     118             : fd_slot_to_epoch( fd_epoch_schedule_t const * schedule,
     119             :                   ulong                       slot,
     120       65190 :                   ulong *                     out_offset_opt ) {
     121             : 
     122       65190 :   if( FD_UNLIKELY( schedule->slots_per_epoch == 0UL ) ) {
     123           0 :     FD_LOG_WARNING(( "zero slots_per_epoch" ));
     124           0 :     return 0UL;
     125           0 :   }
     126             : 
     127       65190 :   ulong epoch;
     128       65190 :   ulong offset;
     129             : 
     130       65190 :   if( FD_UNLIKELY( slot < schedule->first_normal_slot ) ) {
     131             :     /* step0 = ceil(log2(FD_EPOCH_LEN_MIN))
     132             :        step1 = ceil(log2(FD_EPOCH_LEN_MIN + slot + 1))
     133             :        epoch = step1 - step0 - 1 */
     134             : 
     135       32652 :     ulong s0 = FD_EPOCH_LEN_MIN + slot + 1UL;
     136             :     /* Invariant: s0 > 1UL */
     137             :     /* Invariant: s0 > FD_EPOCH_LEN_MIN */
     138             : 
     139             :     /* Find lowest exp where (2^exp) >= s0
     140             :        (Only valid for s0 > 1UL and FD_EPOCH_LEN_MIN > 1UL) */
     141       32652 :     int   exp       = fd_ulong_find_msb( s0-1UL ) + 1;
     142       32652 :     int   min_exp   = fd_ulong_find_msb( FD_EPOCH_LEN_MIN );
     143       32652 :           epoch     = (ulong)( exp - min_exp - 1 );
     144       32652 :     ulong epoch_len = 1UL<<( epoch + (ulong)fd_uint_find_lsb( FD_EPOCH_LEN_MIN ) );
     145       32652 :           offset    = slot - ( epoch_len - FD_EPOCH_LEN_MIN );
     146       32652 :   } else {
     147             :     // FD_LOG_WARNING(("First %lu slots per epoch %lu", schedule->first_normal_slot, schedule->slots_per_epoch));
     148       32538 :     ulong n_slot  = slot - schedule->first_normal_slot;
     149       32538 :     ulong n_epoch = n_slot / schedule->slots_per_epoch;
     150       32538 :           epoch   = schedule->first_normal_epoch + n_epoch;
     151       32538 :           offset  = n_slot % schedule->slots_per_epoch;
     152       32538 :   }
     153             : 
     154       65190 :   ulong   dummy_out;
     155       65190 :   ulong * out_offset = out_offset_opt ? out_offset_opt : &dummy_out;
     156             : 
     157       65190 :   *out_offset = offset;
     158       65190 :   return epoch;
     159       65190 : }
     160             : 
     161             : /* https://github.com/firedancer-io/solana/blob/dab3da8e7b667d7527565bddbdbecf7ec1fb868e/sdk/program/src/epoch_schedule.rs#L114 */
     162             : 
     163             : ulong
     164             : fd_slot_to_leader_schedule_epoch( fd_epoch_schedule_t const * schedule,
     165        5292 :                                   ulong                       slot ) {
     166             : 
     167        5292 :   if( slot < schedule->first_normal_slot )
     168          15 :     return fd_slot_to_epoch( schedule, slot, NULL ) + 1UL;
     169             : 
     170             :   /* These variable names ... sigh */
     171             : 
     172        5277 :   ulong new_slots_since_first_normal_slot =
     173        5277 :     slot - schedule->first_normal_slot;
     174        5277 :   ulong new_first_normal_leader_schedule_slot =
     175        5277 :     new_slots_since_first_normal_slot + schedule->leader_schedule_slot_offset;
     176        5277 :   ulong new_epochs_since_first_normal_leader_schedule =
     177        5277 :     new_first_normal_leader_schedule_slot / schedule->slots_per_epoch;
     178             : 
     179        5277 :   return schedule->first_normal_epoch + new_epochs_since_first_normal_leader_schedule;
     180        5292 : }

Generated by: LCOV version 1.14