LCOV - code coverage report
Current view: top level - flamenco/runtime/sysvar - fd_sysvar_clock.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 162 214 75.7 %
Date: 2026-05-13 07:19:34 Functions: 7 7 100.0 %

          Line data    Source code
       1             : #include "fd_sysvar_clock.h"
       2             : #include "fd_sysvar_epoch_schedule.h"
       3             : #include "../fd_runtime_stack.h"
       4             : #include "../fd_system_ids.h"
       5             : #include "../program/fd_program_util.h"
       6             : #include "../program/vote/fd_vote_state_versioned.h"
       7             : #include "../program/vote/fd_vote_codec.h"
       8             : #include "../../accdb/fd_accdb_sync.h"
       9             : 
      10             : /* Syvar Clock Possible Values:
      11             :   slot:
      12             :   [0, ULONG_MAX]
      13             : 
      14             :   epoch:
      15             :   [0, slot/432000UL]
      16             : 
      17             :   epoch_start_timestamp:
      18             :   [0, ULONG_MAX]
      19             : 
      20             :   unix_timestamp:
      21             :   This value is bounded by the slot distance from the
      22             :   epoch_start_timestamp.
      23             :   The protocol allows for a maximum drift (either fast or slow) from the
      24             :   start of the epoch's timestamp.  The expected time is called the PoH
      25             :   offset.  This offset is calculated by (epoch_start_timestamp + slots
      26             :   since epoch * slot_duration). The drift is then bounded by the
      27             :   max_allowable_drift_{slow,fast}.  The stake weighted offset can be
      28             :   150% more than the PoH offset and 25% less than the PoH offset.
      29             :   So, the bounds for the unix_timestamp can be calculated by:
      30             :   upper bound = epoch_start_timestamp + (slots since epoch * slot_duration) * 2.5
      31             :   lower bound = epoch_start_timestamp + (slots since epoch * slot_duration) * 0.75
      32             : 
      33             :   leader_schedule_epoch:
      34             :   This is the value of the epoch used for the leader schedule.  It is
      35             :   computed based on the values of the epoch schedule (first_normal_slot,
      36             :   leader_schedule_slot_offset, slots_per_epoch).  It is always equal to
      37             :   ((slot - first_normal_slot) + leader_schedule_slot_offset) / schedule->slots_per_epoch
      38             : */
      39             : 
      40             : /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L14 */
      41        3378 : #define MAX_ALLOWABLE_DRIFT_FAST_PERCENT ( 25U )
      42             : 
      43             : /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L15 */
      44        3378 : #define MAX_ALLOWABLE_DRIFT_SLOW_PERCENT ( 150U )
      45             : 
      46             : /* Do all intermediate calculations at nanosecond precision, to mirror
      47             :    Solana's behavior. */
      48        6780 : #define NS_IN_S ((long)1e9)
      49             : 
      50             : /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2110-L2117 */
      51             : static inline long
      52          18 : unix_timestamp_from_genesis( fd_bank_t * bank ) {
      53             :   /* TODO: genesis_creation_time needs to be a long in the bank. */
      54          18 :   return fd_long_sat_add(
      55          18 :       (long)bank->f.genesis_creation_time,
      56          18 :       (long)( fd_uint128_sat_mul( bank->f.slot, bank->f.ns_per_slot.ud ) / NS_IN_S ) );
      57          18 : }
      58             : 
      59             : fd_sol_sysvar_clock_t *
      60             : fd_sysvar_clock_read( fd_accdb_user_t *         accdb,
      61             :                       fd_funk_txn_xid_t const * xid,
      62        3528 :                       fd_sol_sysvar_clock_t *   clock ) {
      63        3528 :   fd_accdb_ro_t ro[1];
      64        3528 :   if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, ro, xid, &fd_sysvar_clock_id ) ) ) {
      65           0 :     return NULL;
      66           0 :   }
      67             : 
      68             :   /* This check is needed as a quirk of the fuzzer. If a sysvar account
      69             :      exists in the accounts database, but doesn't have any lamports,
      70             :      this means that the account does not exist. This wouldn't happen
      71             :      in a real execution environment. */
      72        3528 :   if( FD_UNLIKELY( fd_accdb_ref_lamports( ro ) == 0UL ||
      73        3528 :                    fd_accdb_ref_data_sz ( ro ) <  sizeof(fd_sol_sysvar_clock_t) ) ) {
      74           0 :     fd_accdb_close_ro( accdb, ro );
      75           0 :     return NULL;
      76           0 :   }
      77             : 
      78        3528 :   fd_memcpy( clock, fd_accdb_ref_data_const( ro ), sizeof(fd_sol_sysvar_clock_t) );
      79        3528 :   fd_accdb_close_ro( accdb, ro );
      80        3528 :   return clock;
      81        3528 : }
      82             : 
      83             : void
      84             : fd_sysvar_clock_init( fd_bank_t *               bank,
      85             :                       fd_accdb_user_t *         accdb,
      86             :                       fd_funk_txn_xid_t const * xid,
      87          18 :                       fd_capture_ctx_t *        capture_ctx ) {
      88          18 :   long timestamp = unix_timestamp_from_genesis( bank );
      89             : 
      90          18 :   fd_sol_sysvar_clock_t clock = {
      91          18 :     .slot                  = bank->f.slot,
      92          18 :     .epoch                 = 0,
      93          18 :     .epoch_start_timestamp = timestamp,
      94          18 :     .leader_schedule_epoch = 1,
      95          18 :     .unix_timestamp        = timestamp,
      96          18 :   };
      97          18 :   fd_sysvar_clock_write( bank, accdb, xid, capture_ctx, &clock );
      98          18 : }
      99             : 
     100             : #define SORT_NAME  sort_stake_ts
     101          12 : #define SORT_KEY_T ts_est_ele_t
     102           6 : #define SORT_BEFORE(a,b) ( (a).timestamp < (b).timestamp )
     103             : #include "../../../util/tmpl/fd_sort.c"
     104             : 
     105             : static void
     106             : accum_vote_stakes_no_vat( fd_accdb_user_t *         accdb,
     107             :                           fd_funk_txn_xid_t const * xid,
     108             :                           fd_bank_t *               bank,
     109             :                           fd_runtime_stack_t *      runtime_stack,
     110             :                           uint128 *                 total_stake_out,
     111        3516 :                           ulong *                   ts_ele_cnt_out ) {
     112             : 
     113        3516 :   ts_est_ele_t * ts_eles = runtime_stack->clock_ts.staked_ts;
     114        3516 :   ulong ts_ele_cnt = 0UL;
     115             : 
     116        3516 :   uint128 total_stake = 0UL;
     117             : 
     118        3516 :   fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
     119        3516 :   ulong                       slot_duration  = bank->f.ns_per_slot.ul[0];
     120        3516 :   ulong                       current_slot   = bank->f.slot;
     121             : 
     122        3516 :   fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
     123        3516 :   ushort             fork_idx    = bank->vote_stakes_fork_id;
     124             : 
     125        3516 :   fd_top_votes_t const * top_votes = fd_bank_top_votes_t_2_query( bank );
     126             : 
     127        3516 :   uchar __attribute__((aligned(FD_VOTE_STAKES_ITER_ALIGN))) iter_mem[ FD_VOTE_STAKES_ITER_FOOTPRINT ];
     128        3516 :   for( fd_vote_stakes_iter_t * iter = fd_vote_stakes_fork_iter_init( vote_stakes, fork_idx, iter_mem );
     129        7032 :         !fd_vote_stakes_fork_iter_done( vote_stakes, fork_idx, iter );
     130        3516 :         fd_vote_stakes_fork_iter_next( vote_stakes, fork_idx, iter ) ) {
     131        3516 :     fd_pubkey_t pubkey;
     132        3516 :     ulong       stake_t_2;
     133        3516 :     fd_vote_stakes_fork_iter_ele( vote_stakes, fork_idx, iter, &pubkey, NULL, &stake_t_2, NULL, NULL, NULL, NULL );
     134        3516 :     if( FD_UNLIKELY( !stake_t_2 ) ) continue;
     135             : 
     136        3516 :     ulong last_vote_slot;
     137        3516 :     long  last_vote_timestamp;
     138        3516 :     int   found = fd_top_votes_query( top_votes, &pubkey, NULL, NULL, &last_vote_slot, &last_vote_timestamp, NULL );
     139        3516 :     if( FD_UNLIKELY( !found ) ) {
     140          12 :       fd_accdb_ro_t ro[1];
     141          12 :       if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, ro, xid, &pubkey ) ) ) {
     142           0 :         continue;
     143           0 :       }
     144          12 :       if( FD_UNLIKELY( !fd_vsv_is_correct_size_owner_and_init( ro->meta ) ) ) {
     145           0 :         fd_accdb_close_ro( accdb, ro );
     146           0 :         continue;
     147           0 :       }
     148          12 :       fd_vote_block_timestamp_t last_vote;
     149          12 :       FD_TEST( !fd_vote_account_last_timestamp( fd_account_data( ro->meta ), ro->meta->dlen, &last_vote ) );
     150          12 :       fd_accdb_close_ro( accdb, ro );
     151          12 :       last_vote_slot      = last_vote.slot;
     152          12 :       last_vote_timestamp = last_vote.timestamp;
     153          12 :     }
     154             : 
     155             :     /* https://github.com/anza-xyz/agave/blob/v3.0.0/runtime/src/bank.rs#L2445 */
     156        3516 :     ulong slot_delta;
     157        3516 :     int err = fd_ulong_checked_sub( current_slot, last_vote_slot, &slot_delta );
     158        3516 :     if( FD_UNLIKELY( err ) ) {
     159             :       /* Don't count vote accounts with a last vote slot that is greater
     160             :           than the current slot. */
     161           0 :       continue;
     162           0 :     }
     163             : 
     164             :     /* Don't count vote accounts that haven't voted in the past 432k
     165             :         slots (length of an epoch).
     166             :         https://github.com/anza-xyz/agave/blob/v3.0.0/runtime/src/bank.rs#L2446-L2447 */
     167        3516 :     if( FD_UNLIKELY( slot_delta>epoch_schedule->slots_per_epoch ) ) {
     168         132 :       continue;
     169         132 :     }
     170             : 
     171             :     /* Calculate the timestamp estimate by taking the last vote
     172             :         timestamp and adding the estimated time since the last vote
     173             :         (delta from last vote slot to current slot * slot duration).
     174             :         https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L44-L45 */
     175        3384 :     ulong offset   = fd_ulong_sat_mul( slot_duration, slot_delta );
     176        3384 :     long  estimate = fd_long_sat_add( last_vote_timestamp, (long)(offset / NS_IN_S) );
     177             : 
     178             :     /* For each timestamp, accumulate the stake from E-2.  If the entry
     179             :         for the timestamp doesn't exist yet, insert it.  Otherwise,
     180             :         update the existing entry.
     181             :         https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L46-L53 */
     182        3384 :     ts_eles[ ts_ele_cnt ] = (ts_est_ele_t){
     183        3384 :       .timestamp = estimate,
     184        3384 :       .stake     = { .ud=stake_t_2 },
     185        3384 :     };
     186        3384 :     ts_ele_cnt++;
     187             : 
     188             :     /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L54 */
     189        3384 :     total_stake += stake_t_2;
     190        3384 :   }
     191        3516 :   fd_vote_stakes_fork_iter_fini( vote_stakes );
     192             : 
     193        3516 :   *total_stake_out = total_stake;
     194        3516 :   *ts_ele_cnt_out  = ts_ele_cnt;
     195        3516 : }
     196             : 
     197             : static void
     198             : accum_vote_stakes_vat( fd_bank_t *          bank,
     199             :                        fd_runtime_stack_t * runtime_stack,
     200             :                        uint128 *            total_stake_out,
     201          12 :                        ulong *              ts_ele_cnt_out ) {
     202             : 
     203          12 :   ts_est_ele_t * ts_eles = runtime_stack->clock_ts.staked_ts;
     204          12 :   ulong ts_ele_cnt = 0UL;
     205             : 
     206          12 :   uint128 total_stake = 0UL;
     207             : 
     208          12 :   fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
     209          12 :   ulong                       slot_duration  = bank->f.ns_per_slot.ul[0];
     210          12 :   ulong                       current_slot   = bank->f.slot;
     211             : 
     212          12 :   fd_top_votes_t const * top_votes = fd_bank_top_votes_t_2_query( bank );
     213             : 
     214          12 :   uchar __attribute__((aligned(FD_TOP_VOTES_ITER_ALIGN))) iter_mem[ FD_TOP_VOTES_ITER_FOOTPRINT ];
     215          12 :   for( fd_top_votes_iter_t * iter = fd_top_votes_iter_init( top_votes, iter_mem );
     216          12 :        !fd_top_votes_iter_done( top_votes, iter );
     217          12 :        fd_top_votes_iter_next( top_votes, iter ) ) {
     218           0 :     fd_pubkey_t pubkey;
     219           0 :     ulong       stake_t_2;
     220           0 :     ulong       last_vote_slot;
     221           0 :     long        last_vote_timestamp;
     222           0 :     int is_valid = fd_top_votes_iter_ele( top_votes, iter, &pubkey, NULL, &stake_t_2, NULL, &last_vote_slot, &last_vote_timestamp );
     223           0 :     if( FD_UNLIKELY( !is_valid ) ) continue;
     224             : 
     225             :     /* https://github.com/anza-xyz/agave/blob/v3.0.0/runtime/src/bank.rs#L2445 */
     226           0 :     ulong slot_delta;
     227           0 :     int err = fd_ulong_checked_sub( current_slot, last_vote_slot, &slot_delta );
     228           0 :     if( FD_UNLIKELY( err ) ) {
     229             :       /* Don't count vote accounts with a last vote slot that is greater
     230             :           than the current slot. */
     231           0 :       continue;
     232           0 :     }
     233             : 
     234             :     /* Don't count vote accounts that haven't voted in the past 432k
     235             :         slots (length of an epoch).
     236             :         https://github.com/anza-xyz/agave/blob/v3.0.0/runtime/src/bank.rs#L2446-L2447 */
     237           0 :     if( FD_UNLIKELY( slot_delta>epoch_schedule->slots_per_epoch ) ) {
     238           0 :       continue;
     239           0 :     }
     240             : 
     241             :     /* Calculate the timestamp estimate by taking the last vote
     242             :         timestamp and adding the estimated time since the last vote
     243             :         (delta from last vote slot to current slot * slot duration).
     244             :         https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L44-L45 */
     245           0 :     ulong offset   = fd_ulong_sat_mul( slot_duration, slot_delta );
     246           0 :     long  estimate = fd_long_sat_add( last_vote_timestamp, (long)(offset / NS_IN_S) );
     247             : 
     248             :     /* For each timestamp, accumulate the stake from E-2.  If the entry
     249             :         for the timestamp doesn't exist yet, insert it.  Otherwise,
     250             :         update the existing entry.
     251             :         https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L46-L53 */
     252           0 :     ts_eles[ ts_ele_cnt ] = (ts_est_ele_t){
     253           0 :       .timestamp = estimate,
     254           0 :       .stake     = { .ud=stake_t_2 },
     255           0 :     };
     256           0 :     ts_ele_cnt++;
     257             : 
     258             :     /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L54 */
     259           0 :     total_stake += stake_t_2;
     260           0 :   }
     261             : 
     262          12 :   *total_stake_out = total_stake;
     263          12 :   *ts_ele_cnt_out  = ts_ele_cnt;
     264          12 : }
     265             : 
     266             : /* get_timestamp_estimate calculates a timestamp estimate.  Does not
     267             :    modify the slot context.  Walks all cached vote accounts (from the
     268             :    "bank") and calculates a unix timestamp estimate. Returns the
     269             :    timestamp estimate.  spad is used for scratch allocations (allocates
     270             :    a treap of size FD_SYSVAR_CLOCK_STAKE_WEIGHTS_MAX). Crashes the
     271             :    process with FD_LOG_ERR on failure (e.g. too many vote accounts).
     272             : 
     273             :   https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2563-L2601 */
     274             : static long
     275             : get_timestamp_estimate( fd_accdb_user_t *         accdb,
     276             :                         fd_funk_txn_xid_t const * xid,
     277             :                         fd_bank_t *               bank,
     278             :                         fd_sol_sysvar_clock_t *   clock,
     279             :                         fd_runtime_stack_t *      runtime_stack,
     280        3528 :                         ulong const *             parent_epoch ) {
     281        3528 :   fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
     282        3528 :   ulong                       slot_duration  = bank->f.ns_per_slot.ul[0];
     283        3528 :   ulong                       current_slot   = bank->f.slot;
     284             : 
     285        3528 :   ts_est_ele_t * ts_eles = runtime_stack->clock_ts.staked_ts;
     286             : 
     287             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L41 */
     288        3528 :   ulong  ts_ele_cnt   = 0UL;
     289        3528 :   uint128 total_stake = 0UL;
     290             : 
     291             :   /* A timestamp estimate is calculated at every slot using the most
     292             :      recent vote states of voting validators. This estimated is based on
     293             :      a stake weighted median using the stake as of the end of epoch E-2
     294             :      if we are currently in epoch E. We do not count vote accounts that
     295             :      have not voted in an epoch's worth of slots (432k). */
     296             : 
     297        3528 :   ulong curr_epoch = fd_slot_to_epoch( epoch_schedule, bank->f.slot, NULL );
     298        3528 :   ulong vat_epoch  = fd_slot_to_epoch( epoch_schedule, bank->f.features.validator_admission_ticket, NULL );
     299             : 
     300        3528 :   if( curr_epoch>=vat_epoch+1UL ) {
     301          12 :     accum_vote_stakes_vat( bank, runtime_stack, &total_stake, &ts_ele_cnt );
     302        3516 :   } else {
     303        3516 :     accum_vote_stakes_no_vat( accdb, xid, bank, runtime_stack, &total_stake, &ts_ele_cnt );
     304        3516 :   }
     305             : 
     306             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L56-L58 */
     307        3528 :   if( FD_UNLIKELY( total_stake==0UL ) ) {
     308         150 :     return 0L;
     309         150 :   }
     310             : 
     311        3378 :   sort_stake_ts_inplace( ts_eles, ts_ele_cnt );
     312             : 
     313             :   /* Populate estimate with the stake-weighted median timestamp.
     314             :      https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L59-L68 */
     315        3378 :   uint128 stake_accumulator = 0;
     316        3378 :   long    estimate          = 0L;
     317        3384 :   for( ulong i=0UL; i<ts_ele_cnt; i++ ) {
     318        3384 :     stake_accumulator = fd_uint128_sat_add( stake_accumulator, ts_eles[i].stake.ud );
     319        3384 :     if( stake_accumulator>(total_stake/2UL) ) {
     320        3378 :       estimate = ts_eles[ i ].timestamp;
     321        3378 :       break;
     322        3378 :     }
     323        3384 :   }
     324             : 
     325        3378 :   int const fix_estimate_into_u64 = FD_FEATURE_ACTIVE_BANK( bank, warp_timestamp_again );
     326             : 
     327             :   /* Bound estimate by `max_allowable_drift` since the start of the
     328             :      epoch.
     329             :      https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L69-L99 */
     330        3378 :   ulong epoch_for_start_slot  = parent_epoch ? *parent_epoch : curr_epoch;
     331        3378 :   ulong epoch_start_slot      = fd_epoch_slot0( epoch_schedule, epoch_for_start_slot );
     332        3378 :   long  epoch_start_timestamp = clock->epoch_start_timestamp;
     333             : 
     334             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L71-L72 */
     335        3378 :   ulong poh_estimate_offset = fd_ulong_sat_mul( slot_duration, fd_ulong_sat_sub( current_slot, epoch_start_slot ) );
     336             : 
     337             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L73-L77 */
     338        3378 :   ulong estimate_offset;
     339        3378 :   if( fix_estimate_into_u64 ) {
     340           0 :     estimate_offset = fd_ulong_sat_mul( NS_IN_S, fd_ulong_sat_sub( (ulong)estimate, (ulong)epoch_start_timestamp ) );
     341        3378 :   } else {
     342        3378 :     estimate_offset = fd_ulong_sat_mul( NS_IN_S, (ulong)fd_long_sat_sub( estimate, epoch_start_timestamp ) );
     343        3378 :   }
     344             : 
     345             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L78-L81 */
     346        3378 :   ulong max_allowable_drift_fast = fd_ulong_sat_mul( poh_estimate_offset, MAX_ALLOWABLE_DRIFT_FAST_PERCENT ) / 100UL;
     347        3378 :   ulong max_allowable_drift_slow = fd_ulong_sat_mul( poh_estimate_offset, MAX_ALLOWABLE_DRIFT_SLOW_PERCENT ) / 100UL;
     348             : 
     349             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/stake_weighted_timestamp.rs#L82-L98 */
     350        3378 :   if( estimate_offset>poh_estimate_offset && fd_ulong_sat_sub( estimate_offset, poh_estimate_offset )>max_allowable_drift_slow ) {
     351           0 :     estimate = fd_long_sat_add(
     352           0 :         epoch_start_timestamp,
     353           0 :         fd_long_sat_add( (long)poh_estimate_offset / NS_IN_S, (long)max_allowable_drift_slow / NS_IN_S ) );
     354        3378 :   } else if( estimate_offset<poh_estimate_offset && fd_ulong_sat_sub( poh_estimate_offset, estimate_offset )>max_allowable_drift_fast ) {
     355           0 :     estimate = fd_long_sat_sub(
     356           0 :         fd_long_sat_add( epoch_start_timestamp, (long)poh_estimate_offset / NS_IN_S ),
     357           0 :         (long)max_allowable_drift_fast / NS_IN_S );
     358           0 :   }
     359             : 
     360        3378 :   return estimate;
     361        3528 : }
     362             : 
     363             : /* TODO: This function should be called from genesis bootup as well with
     364             :    parent_epoch = NULL
     365             :    https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2158-L2215 */
     366             : void
     367             : fd_sysvar_clock_update( fd_bank_t *               bank,
     368             :                         fd_accdb_user_t *         accdb,
     369             :                         fd_funk_txn_xid_t const * xid,
     370             :                         fd_capture_ctx_t *        capture_ctx,
     371             :                         fd_runtime_stack_t *      runtime_stack,
     372        3528 :                         ulong const *             parent_epoch ) {
     373        3528 :   fd_sol_sysvar_clock_t clock_[1];
     374        3528 :   fd_sol_sysvar_clock_t * clock = fd_sysvar_clock_read( accdb, xid, clock_ );
     375        3528 :   if( FD_UNLIKELY( !clock ) ) FD_LOG_ERR(( "fd_sysvar_clock_read failed" ));
     376             : 
     377        3528 :   fd_epoch_schedule_t const * epoch_schedule = &bank->f.epoch_schedule;
     378        3528 :   ulong                       current_slot   = bank->f.slot;
     379        3528 :   ulong                       current_epoch  = fd_slot_to_epoch( epoch_schedule, current_slot, NULL );
     380             : 
     381             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2159 */
     382        3528 :   long unix_timestamp = clock->unix_timestamp;
     383             : 
     384             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2175 */
     385        3528 :   long ancestor_timestamp = clock->unix_timestamp;
     386             : 
     387             :   /* TODO: Are we handling slot 0 correctly?
     388             :      https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2176-L2183 */
     389        3528 :   long timestamp_estimate = get_timestamp_estimate( accdb, xid, bank, clock, runtime_stack, parent_epoch );
     390             : 
     391             :   /* If the timestamp was successfully calculated, use it. It not keep the old one. */
     392        3528 :   if( FD_LIKELY( timestamp_estimate!=0L ) ) {
     393           0 :     unix_timestamp = timestamp_estimate;
     394             : 
     395             :     /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2180-L2182 */
     396           0 :     if( timestamp_estimate<ancestor_timestamp ) {
     397           0 :       unix_timestamp = ancestor_timestamp;
     398           0 :     }
     399           0 :   }
     400             : 
     401             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2191-L2197 */
     402        3528 :   long epoch_start_timestamp = (parent_epoch!=NULL && *parent_epoch!=current_epoch) ?
     403         129 :       unix_timestamp :
     404        3528 :       clock->epoch_start_timestamp;
     405             : 
     406             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2198-L2201 */
     407        3528 :   if( FD_UNLIKELY( current_slot==0UL ) ) {
     408           0 :     long timestamp_from_genesis = unix_timestamp_from_genesis( bank );
     409           0 :     unix_timestamp              = timestamp_from_genesis;
     410           0 :     epoch_start_timestamp       = timestamp_from_genesis;
     411           0 :   }
     412             : 
     413             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2202-L2208 */
     414        3528 :   *clock = (fd_sol_sysvar_clock_t){
     415        3528 :     .slot                  = current_slot,
     416        3528 :     .epoch_start_timestamp = epoch_start_timestamp,
     417        3528 :     .epoch                 = current_epoch,
     418        3528 :     .leader_schedule_epoch = fd_slot_to_leader_schedule_epoch( epoch_schedule, current_slot ),
     419        3528 :     .unix_timestamp        = unix_timestamp,
     420        3528 :   };
     421             : 
     422             :   /* https://github.com/anza-xyz/agave/blob/v2.3.7/runtime/src/bank.rs#L2209-L2214 */
     423        3528 :   fd_sysvar_clock_write( bank, accdb, xid, capture_ctx, clock );
     424        3528 : }

Generated by: LCOV version 1.14