LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_vote_program.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 1355 1729 78.4 %
Date: 2025-01-08 12:08:44 Functions: 56 65 86.2 %

          Line data    Source code
       1             : #define FD_SCRATCH_USE_HANDHOLDING 1
       2             : #include "fd_vote_program.h"
       3             : #include "../../types/fd_types_yaml.h"
       4             : #include "../fd_account.h"
       5             : #include "../fd_executor.h"
       6             : #include "../fd_pubkey_utils.h"
       7             : #include "../sysvar/fd_sysvar_epoch_schedule.h"
       8             : #include "../sysvar/fd_sysvar_rent.h"
       9             : 
      10             : #include <limits.h>
      11             : #include <math.h>
      12             : #include <stdio.h>
      13             : #include <string.h>
      14             : 
      15             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L35
      16        4680 : #define MAX_LOCKOUT_HISTORY 31UL
      17             : 
      18             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L36
      19         759 : #define INITIAL_LOCKOUT 2UL
      20             : 
      21             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L36
      22             : #define MAX_EPOCH_CREDITS_HISTORY 64UL
      23             : 
      24             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L42
      25           0 : #define DEFAULT_PRIOR_VOTERS_OFFSET 114
      26             : 
      27             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L45
      28           0 : #define VOTE_CREDITS_GRACE_SLOTS 2
      29             : 
      30             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L48
      31           0 : #define VOTE_CREDITS_MAXIMUM_PER_SLOT 16
      32             : 
      33             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L51
      34          66 : #define VOTE_CREDITS_MAXIMUM_PER_SLOT_OLD 8
      35             : 
      36             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/clock.rs#L147
      37             : #define SLOT_DEFAULT 0UL
      38             : 
      39             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/clock.rs#L147
      40             : #define SLOT_MAX ULONG_MAX
      41             : 
      42             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L886
      43           0 : #define VERSION_OFFSET (4UL)
      44             : 
      45             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L887
      46             : #define DEFAULT_PRIOR_VOTERS_END (118)
      47             : 
      48             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L6
      49           0 : #define DEFAULT_PRIOR_VOTERS_OFFSET_1_14_11 (82UL)
      50             : 
      51             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L60
      52             : #define DEFAULT_PRIOR_VOTERS_END_1_14_11 (86UL)
      53             : 
      54             : #define ACCOUNTS_MAX 4 /* Vote instructions take in at most 4 accounts */
      55             : 
      56             : #define DEFAULT_COMPUTE_UNITS 2100UL
      57             : 
      58             : /**********************************************************************/
      59             : /* size_of                                                            */
      60             : /**********************************************************************/
      61             : 
      62             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L82
      63             : static inline ulong
      64        1374 : size_of_versioned( int is_current ) {
      65        1374 :   return fd_ulong_if( is_current, FD_VOTE_STATE_V3_SZ, FD_VOTE_STATE_V2_SZ );
      66        1374 : }
      67             : 
      68             : /**********************************************************************/
      69             : /* impl Lockout                                                       */
      70             : /**********************************************************************/
      71             : 
      72             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L104
      73             : static inline ulong
      74         729 : lockout( fd_vote_lockout_t * self ) {
      75         729 :   return (ulong)pow( INITIAL_LOCKOUT, self->confirmation_count );
      76         729 : }
      77             : 
      78             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L110
      79             : static inline ulong
      80         729 : last_locked_out_slot( fd_vote_lockout_t * self ) {
      81         729 :   return fd_ulong_sat_add( self->slot, lockout( self ) );
      82         729 : }
      83             : 
      84             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L114
      85             : static inline ulong
      86           6 : is_locked_out_at_slot( fd_vote_lockout_t * self, ulong slot ) {
      87           6 :   return last_locked_out_slot( self ) >= slot;
      88           6 : }
      89             : 
      90             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L122
      91             : static void
      92          18 : increase_confirmation_count( fd_vote_lockout_t * self, uint by ) {
      93          18 :   self->confirmation_count = fd_uint_sat_add( self->confirmation_count, by );
      94          18 : }
      95             : 
      96             : /**********************************************************************/
      97             : /* impl From<VoteState> for VoteState1_14_11                          */
      98             : /**********************************************************************/
      99             : 
     100             : /* from_vote_state_1_14_11 converts a "current" vote state object into
     101             :    the older "v1.14.11" version.  This destroys the "current" object in
     102             :    the process.  valloc is the heap allocator to be used, which must be
     103             :    the same as the one used for v1.14.11.
     104             : */
     105             : 
     106             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L67
     107             : static void
     108             : from_vote_state_1_14_11( fd_vote_state_t *         vote_state,
     109             :                          fd_vote_state_1_14_11_t * vote_state_1_14_11, /* out */
     110         348 :                          fd_valloc_t               valloc ) {
     111         348 :   vote_state_1_14_11->node_pubkey           = vote_state->node_pubkey;            /* copy */
     112         348 :   vote_state_1_14_11->authorized_withdrawer = vote_state->authorized_withdrawer;  /* copy */
     113         348 :   vote_state_1_14_11->commission            = vote_state->commission;             /* copy */
     114             : 
     115             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L72
     116         348 :   if( vote_state->votes ) {
     117         327 :     vote_state_1_14_11->votes = deq_fd_vote_lockout_t_alloc( valloc, deq_fd_landed_vote_t_cnt( vote_state->votes ) );
     118         327 :     for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( vote_state->votes );
     119        4551 :          !deq_fd_landed_vote_t_iter_done( vote_state->votes, iter );
     120        4224 :          iter = deq_fd_landed_vote_t_iter_next( vote_state->votes, iter ) ) {
     121        4224 :       fd_landed_vote_t const * landed_vote = deq_fd_landed_vote_t_iter_ele_const( vote_state->votes, iter );
     122        4224 :       deq_fd_vote_lockout_t_push_tail( vote_state_1_14_11->votes, landed_vote->lockout );
     123        4224 :     }
     124         327 :   }
     125             : 
     126         348 :   vote_state_1_14_11->has_root_slot     = vote_state->has_root_slot;      /* copy */
     127         348 :   vote_state_1_14_11->root_slot         = vote_state->root_slot;          /* copy */
     128         348 :   vote_state_1_14_11->authorized_voters = vote_state->authorized_voters;  /* move */
     129         348 :   vote_state_1_14_11->prior_voters      = vote_state->prior_voters;       /* deep copy */
     130         348 :   vote_state_1_14_11->epoch_credits     = vote_state->epoch_credits;      /* move */
     131         348 :   vote_state_1_14_11->last_timestamp    = vote_state->last_timestamp;     /* deep copy */
     132             : 
     133             :   /* Clear moved objects */
     134         348 :   vote_state->authorized_voters.treap = NULL;
     135         348 :   vote_state->authorized_voters.pool  = NULL;
     136         348 :   vote_state->epoch_credits           = NULL;
     137             : 
     138         348 :   fd_bincode_destroy_ctx_t destroy = { .valloc = valloc };
     139         348 :   fd_vote_state_destroy( vote_state, &destroy );
     140         348 : }
     141             : 
     142             : /**********************************************************************/
     143             : /* impl VoteAccount                                                   */
     144             : /**********************************************************************/
     145             : 
     146             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1074
     147             : static int
     148             : get_state( fd_borrowed_account_t const * self,
     149             :            fd_valloc_t                   valloc,
     150       12000 :            fd_vote_state_versioned_t *   versioned /* out */ ) {
     151       12000 :   int rc;
     152             : 
     153       12000 :   fd_bincode_decode_ctx_t decode_ctx;
     154       12000 :   decode_ctx.data    = self->const_data;
     155       12000 :   decode_ctx.dataend = &self->const_data[self->const_meta->dlen];
     156       12000 :   decode_ctx.valloc  = valloc;
     157             : 
     158       12000 :   rc = fd_vote_state_versioned_decode( versioned, &decode_ctx );
     159       12000 :   if( FD_UNLIKELY( rc != FD_BINCODE_SUCCESS ) )
     160        3930 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     161             : 
     162        8070 :   return FD_EXECUTOR_INSTR_SUCCESS;
     163       12000 : }
     164             : 
     165             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L976
     166             : static int
     167             : set_state( ulong                       self_acct_idx,
     168             :            fd_borrowed_account_t *     self,
     169             :            fd_vote_state_versioned_t * state,
     170        1149 :            fd_exec_instr_ctx_t const * ctx ) {
     171             : 
     172             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L977
     173        1149 :   do {
     174        1149 :     int err = 0;
     175        1149 :     if( FD_UNLIKELY( !fd_account_can_data_be_changed( ctx, self_acct_idx, &err ) ) )
     176         303 :       return err;
     177        1149 :   } while(0);
     178             : 
     179         846 :   do {
     180         846 :     int err = fd_instr_borrowed_account_modify_idx( ctx, self_acct_idx, 0UL, &self );
     181         846 :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_instr_borrowed_account_modify_idx failed (%d)", err ));
     182         846 :   } while(0);
     183             : 
     184             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L978
     185         846 :   ulong serialized_size = fd_vote_state_versioned_size( state );
     186         846 :   if( FD_UNLIKELY( serialized_size > self->const_meta->dlen ) )
     187          21 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     188             : 
     189             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L983
     190         825 :   fd_bincode_encode_ctx_t encode =
     191         825 :     { .data    = self->data,
     192         825 :       .dataend = self->data + self->meta->dlen };
     193         825 :   do {
     194         825 :     int err = fd_vote_state_versioned_encode( state, &encode );
     195         825 :     if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_vote_state_versioned_encode failed (%d)", err ));
     196         825 :   } while(0);
     197             : 
     198         825 :   return FD_EXECUTOR_INSTR_SUCCESS;
     199         825 : }
     200             : 
     201             : /**********************************************************************/
     202             : /* impl AuthorizedVoters                                              */
     203             : /**********************************************************************/
     204             : 
     205             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L17
     206             : static void
     207             : authorized_voters_new( ulong                         epoch,
     208             :                        fd_pubkey_t const *           pubkey,
     209             :                        fd_valloc_t                   valloc,
     210        1929 :                        fd_vote_authorized_voters_t * authorized_voters /* out */ ) {
     211        1929 :   authorized_voters->pool  = fd_vote_authorized_voters_pool_alloc ( valloc, FD_VOTE_AUTHORIZED_VOTERS_MIN );
     212        1929 :   authorized_voters->treap = fd_vote_authorized_voters_treap_alloc( valloc, FD_VOTE_AUTHORIZED_VOTERS_MIN );
     213        1929 :   if( 0 == fd_vote_authorized_voters_pool_free( authorized_voters->pool) ) {
     214           0 :     FD_LOG_ERR(( "Authorized_voter pool is empty" ));
     215           0 :   }
     216        1929 :   fd_vote_authorized_voter_t * ele =
     217        1929 :       fd_vote_authorized_voters_pool_ele_acquire( authorized_voters->pool );
     218        1929 :   ele->epoch = epoch;
     219        1929 :   memcpy( &ele->pubkey, pubkey, sizeof( fd_pubkey_t ) );
     220        1929 :   ele->prio = (ulong)&ele->pubkey;
     221        1929 :   fd_vote_authorized_voters_treap_ele_insert(
     222        1929 :       authorized_voters->treap, ele, authorized_voters->pool );
     223        1929 : }
     224             : 
     225             : static inline int
     226        4734 : authorized_voters_is_empty( fd_vote_authorized_voters_t * self ) {
     227        4734 :   return fd_vote_authorized_voters_treap_ele_cnt( self->treap ) == 0;
     228        4734 : }
     229             : 
     230             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L80
     231             : static inline int
     232         402 : authorized_voters_contains( fd_vote_authorized_voters_t * self, ulong epoch ) {
     233         402 :   return !!fd_vote_authorized_voters_treap_ele_query( self->treap, epoch, self->pool );
     234         402 : }
     235             : 
     236             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L72
     237             : static inline fd_vote_authorized_voter_t *
     238         396 : authorized_voters_last( fd_vote_authorized_voters_t * self ) {
     239         396 :   fd_vote_authorized_voters_treap_rev_iter_t iter =
     240         396 :       fd_vote_authorized_voters_treap_rev_iter_init( self->treap, self->pool );
     241         396 :   return fd_vote_authorized_voters_treap_rev_iter_ele( iter, self->pool );
     242         396 : }
     243             : 
     244             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L43
     245             : static void
     246             : authorized_voters_purge_authorized_voters( fd_vote_authorized_voters_t * self,
     247             :                                            ulong                         current_epoch,
     248        3024 :                                            fd_exec_instr_ctx_t const *   ctx /* spad */ ) {
     249             : 
     250        3024 :   FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
     251             : 
     252             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L46
     253        3024 :   ulong *expired_keys = fd_spad_alloc( ctx->txn_ctx->spad, alignof(ulong), fd_vote_authorized_voters_treap_ele_cnt(self->treap) * sizeof(ulong) );
     254        3024 :   ulong key_cnt                                     = 0;
     255        3024 :   for( fd_vote_authorized_voters_treap_fwd_iter_t iter =
     256        3024 :            fd_vote_authorized_voters_treap_fwd_iter_init( self->treap, self->pool );
     257       57363 :        !fd_vote_authorized_voters_treap_fwd_iter_done( iter );
     258       54339 :        iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, self->pool ) ) {
     259       54339 :     fd_vote_authorized_voter_t * ele =
     260       54339 :         fd_vote_authorized_voters_treap_fwd_iter_ele( iter, self->pool );
     261       54339 :     if( ele->epoch < current_epoch ) expired_keys[key_cnt++] = ele->epoch;
     262       54339 :   }
     263             : 
     264             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L52
     265       50040 :   for( ulong i = 0; i < key_cnt; i++ ) {
     266       47016 :     fd_vote_authorized_voter_t * ele =
     267       47016 :         fd_vote_authorized_voters_treap_ele_query( self->treap, expired_keys[i], self->pool );
     268       47016 :     fd_vote_authorized_voters_treap_ele_remove( self->treap, ele, self->pool );
     269       47016 :     fd_vote_authorized_voters_pool_ele_release( self->pool, ele );
     270             :     // fd_vote_authorized_voter_destroy( &self->pool[i], &ctx3 );
     271       47016 :   }
     272             : 
     273             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L60
     274        3024 :   FD_TEST( !authorized_voters_is_empty( self ) );
     275             : 
     276        3024 :   } FD_SPAD_FRAME_END;
     277             : 
     278        3024 : }
     279             : 
     280             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L91
     281             : static fd_vote_authorized_voter_t *
     282             : authorized_voters_get_or_calculate_authorized_voter_for_epoch( fd_vote_authorized_voters_t * self,
     283             :                                                                ulong                         epoch,
     284        3369 :                                                                int * existed ) {
     285        3369 :   *existed                                  = 0;
     286        3369 :   ulong                        latest_epoch = 0;
     287        3369 :   fd_vote_authorized_voter_t * res =
     288        3369 :       fd_vote_authorized_voters_treap_ele_query( self->treap, epoch, self->pool );
     289             :   // "predecessor" would be more big-O optimal here, but mirroring labs logic
     290             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L93
     291        3369 :   if( FD_UNLIKELY( !res ) ) {
     292        3210 :     for( fd_vote_authorized_voters_treap_fwd_iter_t iter =
     293        3210 :              fd_vote_authorized_voters_treap_fwd_iter_init( self->treap, self->pool );
     294       54474 :          !fd_vote_authorized_voters_treap_fwd_iter_done( iter );
     295       51264 :          iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, self->pool ) ) {
     296       51264 :       fd_vote_authorized_voter_t * ele =
     297       51264 :           fd_vote_authorized_voters_treap_fwd_iter_ele( iter, self->pool );
     298       51264 :       if( ele->epoch < epoch && ( latest_epoch == 0 || ele->epoch > latest_epoch ) ) {
     299       46986 :         latest_epoch = ele->epoch;
     300       46986 :         res          = ele;
     301       46986 :       }
     302       51264 :     }
     303        3210 :     *existed = 0;
     304        3210 :     return res;
     305        3210 :   } else {
     306         159 :     *existed = 1;
     307         159 :     return res;
     308         159 :   }
     309           0 :   return res;
     310        3369 : }
     311             : 
     312             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L28
     313             : static fd_vote_authorized_voter_t *
     314             : authorized_voters_get_and_cache_authorized_voter_for_epoch( fd_vote_authorized_voters_t * self,
     315        3369 :                                                             ulong                         epoch ) {
     316        3369 :   int                          existed = 0;
     317             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L29
     318        3369 :   fd_vote_authorized_voter_t * res =
     319        3369 :       authorized_voters_get_or_calculate_authorized_voter_for_epoch( self, epoch, &existed );
     320        3369 :   if( !res ) return NULL;
     321             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L32
     322        3024 :   if( !existed ) {
     323             :     /* insert cannot fail because !existed */
     324        2865 :     if( 0 == fd_vote_authorized_voters_pool_free( self->pool) ) {
     325           0 :       FD_LOG_ERR(( "Authorized_voter pool is empty" ));
     326           0 :     }
     327        2865 :     fd_vote_authorized_voter_t * ele = fd_vote_authorized_voters_pool_ele_acquire( self->pool );
     328        2865 :     ele->epoch                       = epoch;
     329        2865 :     memcpy( &ele->pubkey, &res->pubkey, sizeof( fd_pubkey_t ) );
     330        2865 :     ele->prio = (ulong)&res->pubkey;
     331             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L33
     332        2865 :     fd_vote_authorized_voters_treap_ele_insert( self->treap, ele, self->pool );
     333        2865 :   }
     334        3024 :   return res;
     335        3024 : }
     336             : 
     337             : /**********************************************************************/
     338             : /* impl VoteStateVersions                                             */
     339             : /**********************************************************************/
     340             : 
     341             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L66
     342             : static fd_landed_vote_t *
     343             : landed_votes_from_lockouts( fd_vote_lockout_t * lockouts,
     344        4278 :                             fd_valloc_t         valloc ) {
     345        4278 :   if( !lockouts ) return NULL;
     346             : 
     347             :   /* Allocate MAX_LOCKOUT_HISTORY (sane case) by default.  In case the
     348             :      vote account is corrupt, allocate as many entries are needed. */
     349             : 
     350        4278 :   ulong cnt = deq_fd_vote_lockout_t_cnt( lockouts );
     351        4278 :         cnt = fd_ulong_max( cnt, MAX_LOCKOUT_HISTORY );
     352        4278 :   fd_landed_vote_t * landed_votes = deq_fd_landed_vote_t_alloc( valloc, cnt );
     353             : 
     354        4278 :   for( deq_fd_vote_lockout_t_iter_t iter = deq_fd_vote_lockout_t_iter_init( lockouts );
     355      110877 :        !deq_fd_vote_lockout_t_iter_done( lockouts, iter );
     356      106599 :        iter = deq_fd_vote_lockout_t_iter_next( lockouts, iter ) ) {
     357      106599 :     fd_vote_lockout_t const * ele = deq_fd_vote_lockout_t_iter_ele_const( lockouts, iter );
     358             : 
     359      106599 :     fd_landed_vote_t * elem = deq_fd_landed_vote_t_push_tail_nocopy( landed_votes );
     360      106599 :     fd_landed_vote_new( elem );
     361             : 
     362      106599 :     elem->latency                    = 0;
     363      106599 :     elem->lockout.slot               = ele->slot;
     364      106599 :     elem->lockout.confirmation_count = ele->confirmation_count;
     365      106599 :   }
     366             : 
     367        4278 :   return landed_votes;
     368        4278 : }
     369             : 
     370             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L70
     371             : static inline int
     372        2598 : is_uninitialized( fd_vote_state_versioned_t * self ) {
     373        2598 :   switch( self->discriminant ) {
     374         888 :   case fd_vote_state_versioned_enum_v0_23_5:;
     375             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L73
     376         888 :     fd_pubkey_t pubkey_default = { 0 };
     377         888 :     return 0 ==
     378         888 :            memcmp( &self->inner.v0_23_5.authorized_voter, &pubkey_default, sizeof( fd_pubkey_t ) );
     379         804 :   case fd_vote_state_versioned_enum_v1_14_11:;
     380         804 :     return authorized_voters_is_empty( &self->inner.v1_14_11.authorized_voters );
     381         906 :   case fd_vote_state_versioned_enum_current:
     382         906 :     return authorized_voters_is_empty( &self->inner.current.authorized_voters );
     383           0 :   default:
     384           0 :     FD_LOG_ERR(( "missing handler or invalid vote state version: %u", self->discriminant ));
     385        2598 :   }
     386        2598 : }
     387             : 
     388             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L73
     389             : static void
     390             : convert_to_current( fd_vote_state_versioned_t * self,
     391        7521 :                     fd_valloc_t                 valloc ) {
     392        7521 :   switch( self->discriminant ) {
     393             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L19
     394        1920 :   case fd_vote_state_versioned_enum_v0_23_5: {
     395        1920 :     fd_vote_state_0_23_5_t * state = &self->inner.v0_23_5;
     396        1920 :     fd_vote_authorized_voters_t authorized_voters;
     397             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L21
     398        1920 :     authorized_voters_new(
     399        1920 :         state->authorized_voter_epoch, &state->authorized_voter, valloc, &authorized_voters );
     400             : 
     401             :     /* Temporary to hold current */
     402             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L23
     403        1920 :     fd_vote_state_t current = {
     404        1920 :       .node_pubkey           = state->node_pubkey,            /* copy */
     405        1920 :       .authorized_withdrawer = state->authorized_withdrawer,  /* copy */
     406        1920 :       .commission            = state->commission,             /* copy */
     407        1920 :       .votes                 = landed_votes_from_lockouts( state->votes, valloc ),
     408        1920 :       .has_root_slot         = state->has_root_slot,  /* copy */
     409        1920 :       .root_slot             = state->root_slot,      /* copy */
     410        1920 :       .authorized_voters     = authorized_voters,
     411        1920 :       .prior_voters = (fd_vote_prior_voters_t) {
     412        1920 :         .idx      = 31UL,
     413        1920 :         .is_empty = 1,
     414        1920 :       },
     415        1920 :       .epoch_credits  = state->epoch_credits,   /* move */
     416        1920 :       .last_timestamp = state->last_timestamp,  /* deep copy */
     417        1920 :     };
     418             : 
     419             :     /* Move objects */
     420        1920 :     state->epoch_credits = NULL;
     421             : 
     422             :     /* Deallocate objects owned by old vote state */
     423        1920 :     fd_bincode_destroy_ctx_t destroy = { .valloc = valloc };
     424        1920 :     fd_vote_state_0_23_5_destroy( state, &destroy );
     425             : 
     426             :     /* Emplace new vote state into target */
     427        1920 :     self->discriminant = fd_vote_state_versioned_enum_current;
     428        1920 :     memcpy( &self->inner.current, &current, sizeof(fd_vote_state_t) );
     429             : 
     430        1920 :     break;
     431           0 :   }
     432             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L44
     433        2355 :   case fd_vote_state_versioned_enum_v1_14_11: {
     434        2355 :     fd_vote_state_1_14_11_t * state = &self->inner.v1_14_11;
     435             : 
     436             :     /* Temporary to hold current */
     437        2355 :     fd_vote_state_t current = {
     438        2355 :       .node_pubkey            = state->node_pubkey,            /* copy */
     439        2355 :       .authorized_withdrawer  = state->authorized_withdrawer,  /* copy */
     440        2355 :       .commission             = state->commission,             /* copy */
     441        2355 :       .votes                  = landed_votes_from_lockouts( state->votes, valloc ),
     442        2355 :       .has_root_slot          = state->has_root_slot,          /* copy */
     443        2355 :       .root_slot              = state->root_slot,              /* copy */
     444        2355 :       .authorized_voters      = state->authorized_voters,      /* move */
     445        2355 :       .prior_voters           = state->prior_voters,           /* deep copy */
     446        2355 :       .epoch_credits          = state->epoch_credits,          /* move */
     447        2355 :       .last_timestamp         = state->last_timestamp          /* deep copy */
     448        2355 :     };
     449             : 
     450             :     /* Move objects */
     451        2355 :     state->authorized_voters.treap = NULL;
     452        2355 :     state->authorized_voters.pool  = NULL;
     453        2355 :     state->epoch_credits           = NULL;
     454             : 
     455             :     /* Deallocate objects owned by old vote state */
     456        2355 :     fd_bincode_destroy_ctx_t destroy = { .valloc = valloc };
     457        2355 :     fd_vote_state_1_14_11_destroy( state, &destroy );
     458             : 
     459             :     /* Emplace new vote state into target */
     460        2355 :     self->discriminant = fd_vote_state_versioned_enum_current;
     461        2355 :     memcpy( &self->inner.current, &current, sizeof( fd_vote_state_t ) );
     462             : 
     463        2355 :     break;
     464           0 :   }
     465        3246 :   case fd_vote_state_versioned_enum_current:
     466        3246 :     break;
     467           0 :   default:
     468           0 :     FD_LOG_ERR( ( "unsupported vote state version: %u", self->discriminant ) );
     469        7521 :   }
     470        7521 : }
     471             : 
     472             : /**********************************************************************/
     473             : /* impl VoteState                                                     */
     474             : /**********************************************************************/
     475             : 
     476             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L428
     477             : static void
     478             : vote_state_new( fd_vote_init_t *              vote_init,
     479             :                 fd_sol_sysvar_clock_t const * clock,
     480             :                 fd_valloc_t                   valloc,
     481           9 :                 fd_vote_state_t *             vote_state /* out */ ) {
     482           9 :   vote_state->node_pubkey = vote_init->node_pubkey;
     483           9 :   authorized_voters_new(
     484           9 :       clock->epoch, &vote_init->authorized_voter, valloc, &vote_state->authorized_voters );
     485             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L431
     486           9 :   vote_state->authorized_withdrawer = vote_init->authorized_withdrawer;
     487           9 :   vote_state->commission            = vote_init->commission;
     488             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L434
     489           9 :   vote_state->prior_voters.idx      = 31;
     490           9 :   vote_state->prior_voters.is_empty = 1;
     491           9 : }
     492             : 
     493             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L985
     494             : static inline int
     495             : verify_authorized_signer( fd_pubkey_t const * authorized,
     496        6252 :                           fd_pubkey_t const * signers[static FD_TXN_SIG_MAX] ) {
     497             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L989
     498        6252 :   return fd_instr_signers_contains( signers, authorized ) ?
     499        2703 :     FD_EXECUTOR_INSTR_SUCCESS :
     500        6252 :     FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
     501        6252 : }
     502             : 
     503             : // lambda function: https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L873
     504             : static inline int
     505             : verify( fd_pubkey_t *       epoch_authorized_voter,
     506             :         int                 authorized_withdrawer_signer,
     507         807 :         fd_pubkey_t const * signers[static FD_TXN_SIG_MAX] ) {
     508         807 :   if( authorized_withdrawer_signer )
     509         324 :     return 0;
     510         483 :   else
     511         483 :     return verify_authorized_signer( epoch_authorized_voter, signers );
     512         807 : }
     513             : 
     514             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L845
     515             : static void
     516           9 : pop_expired_votes( fd_vote_state_t * self, ulong next_vote_slot ) {
     517          12 :   while( !deq_fd_landed_vote_t_empty( self->votes ) ) {
     518           6 :     fd_landed_vote_t * vote = deq_fd_landed_vote_t_peek_tail( self->votes );
     519           6 :     if( !( is_locked_out_at_slot( &vote->lockout, next_vote_slot ) ) ) {
     520           3 :       deq_fd_landed_vote_t_pop_tail( self->votes );
     521           3 :     } else {
     522           3 :       break;
     523           3 :     }
     524           6 :   }
     525           9 : }
     526             : 
     527             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L855
     528             : static void
     529           9 : double_lockouts( fd_vote_state_t * self ) {
     530             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L856
     531           9 :   ulong stack_depth = deq_fd_landed_vote_t_cnt( self->votes );
     532           9 :   ulong i           = 0;
     533             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L857
     534           9 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( self->votes );
     535          66 :        !deq_fd_landed_vote_t_iter_done( self->votes, iter );
     536          57 :        iter = deq_fd_landed_vote_t_iter_next( self->votes, iter ) ) {
     537          57 :     fd_landed_vote_t * v = deq_fd_landed_vote_t_iter_ele( self->votes, iter );
     538             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L860
     539          57 :     if( stack_depth >
     540          57 :         fd_ulong_checked_add_expect(
     541          57 :             i,
     542          57 :             (ulong)v->lockout.confirmation_count,
     543          57 :             "`confirmation_count` and tower_size should be bounded by `MAX_LOCKOUT_HISTORY`" ) )
     544          18 :       {
     545             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L864
     546          18 :         increase_confirmation_count( &v->lockout, 1 );
     547          18 :       }
     548          57 :     i++;
     549          57 :   }
     550           9 : }
     551             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L668
     552             : static inline uchar
     553           6 : compute_vote_latency( ulong voted_for_slot, ulong current_slot ) {
     554           6 :   return (uchar)fd_ulong_min( fd_ulong_sat_sub( current_slot, voted_for_slot ), UCHAR_MAX );
     555           6 : }
     556             : 
     557             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L673
     558             : static ulong
     559          33 : credits_for_vote_at_index( fd_vote_state_t * self, ulong index, int timely_vote_credits, int deprecate_unused_legacy_vote_plumbing ) {
     560             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L679
     561          33 :   fd_landed_vote_t * landed_vote = deq_fd_landed_vote_t_peek_index( self->votes, index );
     562          33 :   ulong              latency     = landed_vote == NULL ? 0 : landed_vote->latency;
     563             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L683
     564          33 :   ulong              max_credits = deprecate_unused_legacy_vote_plumbing ?
     565          33 :                                    VOTE_CREDITS_MAXIMUM_PER_SLOT : VOTE_CREDITS_MAXIMUM_PER_SLOT_OLD;
     566             : 
     567             :   // If latency is 0, this means that the Lockout was created and stored from a software version
     568             :   // that did not store vote latencies; in this case, 1 credit is awarded
     569             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L691
     570          33 :   if( FD_UNLIKELY( latency == 0 || (deprecate_unused_legacy_vote_plumbing && !timely_vote_credits) ) ) {
     571          33 :     return 1;
     572          33 :   }
     573             : 
     574           0 :   ulong diff = 0;
     575           0 :   int   cf   = fd_ulong_checked_sub( latency, VOTE_CREDITS_GRACE_SLOTS, &diff );
     576           0 :   if( cf != 0 || diff == 0 ) {
     577             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L697
     578           0 :     return max_credits;
     579           0 :   }
     580             : 
     581           0 :   ulong credits = 0;
     582           0 :   cf = fd_ulong_checked_sub( max_credits, diff, &credits );
     583           0 :   if( cf != 0 || credits == 0 ) {
     584             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L705
     585           0 :     return 1;
     586           0 :   }
     587             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L707
     588           0 :   return credits;
     589           0 : }
     590             : 
     591             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L639
     592             : static void
     593          24 : increment_credits( fd_vote_state_t * self, ulong epoch, ulong credits ) {
     594             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L643
     595          24 :   if( FD_UNLIKELY( deq_fd_vote_epoch_credits_t_empty( self->epoch_credits ) ) ) {
     596             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L644
     597           0 :     deq_fd_vote_epoch_credits_t_push_tail(
     598           0 :         self->epoch_credits,
     599           0 :         ( fd_vote_epoch_credits_t ){ .epoch = epoch, .credits = 0, .prev_credits = 0 } );
     600          24 :   } else if( FD_LIKELY( epoch !=
     601          24 :                         deq_fd_vote_epoch_credits_t_peek_tail( self->epoch_credits )->epoch ) ) {
     602           0 :     fd_vote_epoch_credits_t * last = deq_fd_vote_epoch_credits_t_peek_tail( self->epoch_credits );
     603             : 
     604           0 :     ulong credits      = last->credits;
     605           0 :     ulong prev_credits = last->prev_credits;
     606             : 
     607             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L648
     608           0 :     if( FD_LIKELY( credits != prev_credits ) ) {
     609           0 :       deq_fd_vote_epoch_credits_t_push_tail(
     610           0 :           self->epoch_credits,
     611           0 :           ( fd_vote_epoch_credits_t ){
     612           0 :               .epoch = epoch, .credits = credits, .prev_credits = credits } );
     613           0 :     } else {
     614             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L654
     615           0 :       deq_fd_vote_epoch_credits_t_peek_tail( self->epoch_credits )->epoch = epoch;
     616           0 :     }
     617             : 
     618             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L658
     619           0 :     if( FD_UNLIKELY( deq_fd_vote_epoch_credits_t_cnt( self->epoch_credits ) >
     620           0 :                      MAX_EPOCH_CREDITS_HISTORY ) ) {
     621           0 :       deq_fd_vote_epoch_credits_t_pop_head( self->epoch_credits );
     622           0 :     }
     623           0 :   }
     624             : 
     625             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L663
     626          24 :   deq_fd_vote_epoch_credits_t_peek_tail( self->epoch_credits )->credits = fd_ulong_sat_add(
     627          24 :       deq_fd_vote_epoch_credits_t_peek_tail( self->epoch_credits )->credits, credits );
     628          24 : }
     629             : 
     630             : static inline ulong *
     631             : last_voted_slot( fd_vote_state_t * self );
     632             : 
     633             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L595
     634             : static void
     635             : process_next_vote_slot( fd_vote_state_t * self,
     636             :                         ulong             next_vote_slot,
     637             :                         ulong             epoch,
     638             :                         ulong             current_slot,
     639             :                         int               timely_vote_credits,
     640             :                         int               deprecate_unused_legacy_vote_plumbing
     641             : 
     642          24 :  ) {
     643          24 :   ulong * last_voted_slot_ = last_voted_slot( self );
     644          24 :   if( FD_UNLIKELY( last_voted_slot_ && next_vote_slot <= *last_voted_slot_ ) ) return;
     645             : 
     646           9 :   pop_expired_votes( self, next_vote_slot );
     647             : 
     648           9 :   fd_landed_vote_t landed_vote = { .latency = (timely_vote_credits || !deprecate_unused_legacy_vote_plumbing) ?
     649             :                                    // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L615
     650           3 :                                    compute_vote_latency( next_vote_slot, current_slot ) :
     651             :                                    // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L617
     652           9 :                                    0,
     653           9 :                                    ( fd_vote_lockout_t ){ .slot = next_vote_slot } };
     654             : 
     655             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L623
     656           9 :   if( FD_UNLIKELY( deq_fd_landed_vote_t_cnt( self->votes ) == MAX_LOCKOUT_HISTORY ) ) {
     657           0 :     ulong            credits     = credits_for_vote_at_index( self, 0, timely_vote_credits, deprecate_unused_legacy_vote_plumbing);
     658           0 :     fd_landed_vote_t landed_vote = deq_fd_landed_vote_t_pop_head( self->votes );
     659           0 :     self->has_root_slot = 1;
     660           0 :     self->root_slot     = landed_vote.lockout.slot;
     661             : 
     662           0 :     increment_credits( self, epoch, credits );
     663           0 :   }
     664             : 
     665             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L634
     666           9 :   deq_fd_landed_vote_t_push_tail( self->votes, landed_vote );
     667           9 :   double_lockouts( self );
     668           9 : }
     669             : 
     670             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L828
     671             : static int
     672             : get_and_update_authorized_voter( fd_vote_state_t *           self,
     673             :                                  ulong                       current_epoch,
     674             :                                  fd_pubkey_t **              pubkey /* out */,
     675        3369 :                                  fd_exec_instr_ctx_t const * ctx /* spad */ ) {
     676             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L832
     677        3369 :   fd_vote_authorized_voter_t * authorized_voter =
     678        3369 :       authorized_voters_get_and_cache_authorized_voter_for_epoch( &self->authorized_voters,
     679        3369 :                                                                   current_epoch );
     680             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L835
     681        3369 :   if( FD_UNLIKELY( !authorized_voter ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     682        3024 :   *pubkey = &authorized_voter->pubkey;
     683             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L837
     684        3024 :   authorized_voters_purge_authorized_voters( &self->authorized_voters, current_epoch, ctx );
     685        3024 :   return FD_EXECUTOR_INSTR_SUCCESS;
     686        3369 : }
     687             : 
     688             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L768
     689             : static int
     690             : set_new_authorized_voter( fd_vote_state_t *                          self,
     691             :                           fd_pubkey_t const *                        authorized_pubkey,
     692             :                           ulong                                      current_epoch,
     693             :                           ulong                                      target_epoch,
     694             :                           /* "verify" closure */ int                 authorized_withdrawer_signer,
     695             :                           /* "verify" closure */ fd_pubkey_t const * signers[static FD_TXN_SIG_MAX],
     696         855 :                           fd_exec_instr_ctx_t const *                ctx ) {
     697         855 :   int           rc;
     698         855 :   fd_pubkey_t * epoch_authorized_voter = NULL;
     699             : 
     700             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L778
     701         855 :   rc = get_and_update_authorized_voter( self, current_epoch, &epoch_authorized_voter, ctx );
     702         855 :   if( FD_UNLIKELY( rc ) ) return rc;
     703             : 
     704             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L779
     705         807 :   rc = verify( epoch_authorized_voter, authorized_withdrawer_signer, signers );
     706         807 :   if( FD_UNLIKELY( rc ) ) return rc;
     707             : 
     708             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L786
     709         402 :   if( FD_UNLIKELY( authorized_voters_contains( &self->authorized_voters, target_epoch ) ) ) {
     710           6 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_TOO_SOON_TO_REAUTHORIZE;
     711           6 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     712           6 :   }
     713             : 
     714             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L791
     715         396 :   fd_vote_authorized_voter_t * latest_authorized =
     716         396 :       authorized_voters_last( &self->authorized_voters );
     717             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L794
     718         396 :   if( FD_UNLIKELY( ( !latest_authorized ) ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     719         396 :   ulong         latest_epoch             = latest_authorized->epoch;
     720         396 :   fd_pubkey_t * latest_authorized_pubkey = &latest_authorized->pubkey;
     721             : 
     722             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L799
     723         396 :   if( 0 != memcmp( latest_authorized_pubkey, authorized_pubkey, sizeof( fd_pubkey_t ) ) ) {
     724         273 :     fd_vote_prior_voters_t * prior_voters = &self->prior_voters;
     725             : 
     726             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L801
     727         273 :     ulong epoch_of_last_authorized_switch = 0UL;
     728         273 :     if( (!prior_voters->is_empty) & (prior_voters->idx < 32) ) {
     729          45 :       epoch_of_last_authorized_switch = prior_voters->buf[prior_voters->idx].epoch_end;
     730          45 :     }
     731             : 
     732             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L810
     733         273 :     if( target_epoch <= latest_epoch )
     734         141 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     735             : 
     736             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L815
     737         132 :     prior_voters->idx += 1UL;
     738         132 :     prior_voters->idx %= 32UL;
     739         132 :     prior_voters->buf[prior_voters->idx] =
     740         132 :         ( fd_vote_prior_voter_t ){ .pubkey      = *latest_authorized_pubkey,
     741         132 :                                    .epoch_start = epoch_of_last_authorized_switch,
     742         132 :                                    .epoch_end   = target_epoch };
     743         132 :     prior_voters->is_empty = 0;
     744         132 :   }
     745             : 
     746             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L822
     747         255 :   if( 0 == fd_vote_authorized_voters_pool_free( self->authorized_voters.pool) ) {
     748           0 :     FD_LOG_ERR(( "Authorized_voter pool is empty" ));
     749           0 :   }
     750             : 
     751         255 :   fd_vote_authorized_voter_t * ele =
     752         255 :       fd_vote_authorized_voters_pool_ele_acquire( self->authorized_voters.pool );
     753         255 :   ele->epoch = target_epoch;
     754         255 :   memcpy( &ele->pubkey, authorized_pubkey, sizeof( fd_pubkey_t ) );
     755         255 :   ele->prio = (ulong)&ele->pubkey;
     756         255 :   fd_vote_authorized_voters_treap_ele_insert(
     757         255 :       self->authorized_voters.treap, ele, self->authorized_voters.pool );
     758             : 
     759         255 :   return 0;
     760         255 : }
     761             : 
     762             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L869
     763             : static int
     764             : process_timestamp( fd_vote_state_t *           self,
     765             :                    ulong                       slot,
     766             :                    long                        timestamp,
     767          36 :                    fd_exec_instr_ctx_t const * ctx ) {
     768          36 :   if( FD_UNLIKELY(
     769          36 :           ( slot < self->last_timestamp.slot || timestamp < self->last_timestamp.timestamp ) ||
     770          36 :           ( slot == self->last_timestamp.slot &&
     771          36 :             ( slot != self->last_timestamp.slot || timestamp != self->last_timestamp.timestamp ) &&
     772          36 :             self->last_timestamp.slot != 0 ) ) ) {
     773           9 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_TIMESTAMP_TOO_OLD;
     774           9 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     775           9 :   }
     776          27 :   self->last_timestamp.slot      = slot;
     777          27 :   self->last_timestamp.timestamp = timestamp;
     778             : 
     779          27 :   return 0;
     780          36 : }
     781             : 
     782             : /**********************************************************************/
     783             : /* mod vote_state                                                    */
     784             : /**********************************************************************/
     785             : 
     786             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L166
     787             : __attribute__((warn_unused_result)) static int
     788             : set_vote_account_state( ulong                       vote_acct_idx,
     789             :                         fd_borrowed_account_t *     vote_account,
     790             :                         fd_vote_state_t *           vote_state,
     791        1149 :                         fd_exec_instr_ctx_t const * ctx /* feature_set */ ) {
     792             : 
     793        1149 :   if( FD_FEATURE_ACTIVE( ctx->slot_ctx, vote_state_add_vote_latency ) ) {
     794             :     /* This is a horrible conditional expression in Agave.
     795             :        The terms were broken up into their own variables. */
     796             : 
     797        1149 :     ulong vsz = size_of_versioned( 1 );
     798             : 
     799             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L175
     800        1149 :     int resize_needed      = vote_account->const_meta->dlen < vsz;
     801        1149 :     fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank_const( ctx->epoch_ctx );
     802        1149 :     int resize_rent_exempt = fd_rent_exempt_minimum_balance( &epoch_bank->rent, vsz ) <= vote_account->const_meta->info.lamports;
     803             : 
     804             :     /* The resize operation itself is part of the horrible conditional,
     805             :        but behind a short-circuit operator. */
     806        1149 :     int resize_failed = 0;
     807        1149 :     if( resize_needed && resize_rent_exempt ) {
     808             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L179
     809         894 :       resize_failed =
     810         894 :         fd_account_set_data_length( ctx, vote_acct_idx, vsz ) != FD_EXECUTOR_INSTR_SUCCESS;
     811         894 :     }
     812             : 
     813        1149 :     if( FD_UNLIKELY( resize_needed && ( !resize_rent_exempt || resize_failed ) ) ) {
     814             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L184
     815         348 :       fd_vote_state_versioned_t v1_14_11;
     816         348 :       fd_vote_state_versioned_new_disc( &v1_14_11, fd_vote_state_versioned_enum_v1_14_11 );
     817         348 :       from_vote_state_1_14_11( vote_state, &v1_14_11.inner.v1_14_11, fd_spad_virtual( ctx->txn_ctx->spad ) );
     818         348 :       return set_state( vote_acct_idx, vote_account, &v1_14_11, ctx );
     819         348 :     }
     820             : 
     821             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L189
     822             :     // TODO: This is stupid...  optimize this...
     823         801 :     fd_vote_state_versioned_t new_current = { .discriminant = fd_vote_state_versioned_enum_current,
     824         801 :                                               .inner        = { .current = *vote_state } };
     825         801 :     return set_state( vote_acct_idx, vote_account, &new_current, ctx );
     826        1149 :   } else {
     827             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L192
     828           0 :     fd_vote_state_versioned_t v1_14_11;
     829           0 :     fd_vote_state_versioned_new_disc( &v1_14_11, fd_vote_state_versioned_enum_v1_14_11 );
     830             : 
     831           0 :     from_vote_state_1_14_11( vote_state, &v1_14_11.inner.v1_14_11, fd_spad_virtual( ctx->txn_ctx->spad ) );
     832           0 :     return set_state( vote_acct_idx, vote_account, &v1_14_11, ctx );
     833           0 :   }
     834        1149 : }
     835             : 
     836             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L727
     837             : static inline fd_vote_lockout_t *
     838       50382 : last_lockout( fd_vote_state_t * self ) {
     839       50382 :   if( deq_fd_landed_vote_t_empty( self->votes ) ) return NULL;
     840       36990 :   fd_landed_vote_t * last_vote = deq_fd_landed_vote_t_peek_tail( self->votes );
     841       36990 :   return &last_vote->lockout;
     842       50382 : }
     843             : 
     844             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L731
     845             : static inline ulong *
     846       50382 : last_voted_slot( fd_vote_state_t * self ) {
     847       50382 :   fd_vote_lockout_t * last_lockout_ = last_lockout( self );
     848       50382 :   if( FD_UNLIKELY( !last_lockout_ ) ) return NULL;
     849       36990 :   return &last_lockout_->slot;
     850       50382 : }
     851             : 
     852             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L573
     853             : static uchar
     854         423 : contains_slot( fd_vote_state_t * vote_state, ulong slot ) {
     855             :   /* Logic is copied from slice::binary_search_by() in Rust */
     856         423 :   ulong start = 0UL;
     857         423 :   ulong end   = deq_fd_landed_vote_t_cnt( vote_state->votes );
     858             : 
     859        2241 :   while( start < end ) {
     860        1845 :     ulong mid      = start + ( end - start ) / 2UL;
     861        1845 :     ulong mid_slot = deq_fd_landed_vote_t_peek_index_const( vote_state->votes, mid )->lockout.slot;
     862        1845 :     if( mid_slot == slot ) {
     863          27 :       return 1;
     864        1818 :     } else if( mid_slot < slot ) {
     865         564 :       start = mid + 1UL;
     866        1254 :     } else {
     867        1254 :       end = mid;
     868        1254 :     }
     869        1845 :   }
     870         396 :   return 0;
     871         423 : }
     872             : 
     873             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L201
     874             : static int
     875             : check_and_filter_proposed_vote_state( fd_vote_state_t *           vote_state,
     876             :                                       fd_vote_lockout_t *         proposed_lockouts,
     877             :                                       uchar *                     proposed_has_root,
     878             :                                       ulong *                     proposed_root,
     879             :                                       fd_hash_t const *           proposed_hash,
     880             :                                       fd_slot_hashes_t const *    slot_hashes,
     881         507 :                                       fd_exec_instr_ctx_t const * ctx ) {
     882             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L208
     883         507 :   if( FD_UNLIKELY( deq_fd_vote_lockout_t_empty( proposed_lockouts ) ) ) {
     884          45 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
     885          45 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     886          45 :   }
     887         462 :   fd_landed_vote_t const * last_vote = NULL;
     888         462 :   if( !deq_fd_landed_vote_t_empty( vote_state->votes ) ) {
     889             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L212
     890         393 :     last_vote = deq_fd_landed_vote_t_peek_tail( vote_state->votes );
     891         393 :   }
     892             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L218
     893         462 :   if( FD_LIKELY( last_vote ) ) {
     894         393 :     if( FD_UNLIKELY( deq_fd_vote_lockout_t_peek_tail_const( proposed_lockouts )->slot <=
     895         393 :                      last_vote->lockout.slot ) ) {
     896           9 :       ctx->txn_ctx->custom_err = FD_VOTE_ERROR_VOTE_TOO_OLD;
     897           9 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     898           9 :     }
     899         393 :   }
     900             : 
     901             :   /* must be nonempty, checked above */
     902         453 :   ulong last_vote_state_update_slot = deq_fd_vote_lockout_t_peek_tail_const( proposed_lockouts )->slot;
     903             : 
     904             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L224
     905         453 :   if( FD_UNLIKELY( deq_fd_slot_hash_t_empty( slot_hashes->hashes ) ) ) {
     906          36 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
     907          36 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     908          36 :   }
     909             : 
     910             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L227
     911         417 :   ulong earliest_slot_hash_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes->hashes )->slot;
     912             : 
     913             :   /* Check if the proposed vote is too old to be in the SlotHash history */
     914             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L230
     915         417 :   if( FD_UNLIKELY( last_vote_state_update_slot < earliest_slot_hash_in_history ) ) {
     916          27 :     ctx->txn_ctx->custom_err = FD_VOTE_ERROR_VOTE_TOO_OLD;
     917          27 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     918          27 :   }
     919             : 
     920             :   /* Check if the proposed root is too old */
     921             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L237
     922         390 :   if( *proposed_has_root ) {
     923         246 :     ulong const proposed_root_ = *proposed_root;
     924             :     /* If the new proposed root `R` is less than the earliest slot hash in the history
     925             :        such that we cannot verify whether the slot was actually was on this fork, set
     926             :        the root to the latest vote in the current vote that's less than R. */
     927             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L242
     928         246 :     if( proposed_root_ < earliest_slot_hash_in_history ) {
     929         165 :       *proposed_has_root = vote_state->has_root_slot;
     930         165 :       *proposed_root     = vote_state->root_slot;
     931         165 :       for( deq_fd_landed_vote_t_iter_t iter =
     932         165 :                deq_fd_landed_vote_t_iter_init_rev( vote_state->votes );
     933        1689 :            !deq_fd_landed_vote_t_iter_done_rev( vote_state->votes, iter );
     934        1584 :            iter = deq_fd_landed_vote_t_iter_prev( vote_state->votes, iter ) ) {
     935             :         /* Ensure we're iterating from biggest to smallest vote in the
     936             :            current vote state */
     937        1584 :         fd_landed_vote_t const * vote = deq_fd_landed_vote_t_iter_ele_const( vote_state->votes, iter );
     938             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L248
     939        1584 :         if( vote->lockout.slot <= proposed_root_ ) {
     940          60 :           *proposed_has_root = 1;
     941          60 :           *proposed_root     = vote->lockout.slot;
     942          60 :           break;
     943          60 :         }
     944             : 
     945        1584 :       }
     946         165 :     }
     947         246 :   }
     948             : 
     949         390 :   FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
     950             : 
     951             :     /* Index into the new proposed vote state's slots, starting with the root if it exists then
     952             :        we use this mutable root to fold checking the root slot into the below loop for performance */
     953         390 :     int     has_root_to_check       = *proposed_has_root;
     954             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L259
     955         390 :     ulong   root_to_check           = *proposed_root;
     956         390 :     ulong   proposed_lockouts_index = 0UL;
     957         390 :     ulong   lockouts_len = deq_fd_vote_lockout_t_cnt( proposed_lockouts );
     958             : 
     959             :     /* Index into the slot_hashes, starting at the oldest known slot hash */
     960             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L264
     961         390 :     ulong   slot_hashes_index = deq_fd_slot_hash_t_cnt( slot_hashes->hashes );
     962         390 :     ulong * proposed_lockouts_indexes_to_filter = fd_spad_alloc( ctx->txn_ctx->spad, alignof(ulong), lockouts_len * sizeof(ulong) );
     963         390 :     ulong   filter_index = 0UL;
     964             : 
     965             : 
     966             :     /* Note:
     967             : 
     968             :        1) `vote_state_update.lockouts` is sorted from oldest/smallest vote to newest/largest
     969             :        vote, due to the way votes are applied to the vote state (newest votes
     970             :        pushed to the back).
     971             : 
     972             :        2) Conversely, `slot_hashes` is sorted from newest/largest vote to
     973             :        the oldest/smallest vote
     974             : 
     975             :        Unlike for vote updates, vote state updates here can't only check votes older than the last vote
     976             :        because have to ensure that every slot is actually part of the history, not just the most
     977             :        recent ones */
     978             : 
     979             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L279
     980       29658 :     while( proposed_lockouts_index < lockouts_len && slot_hashes_index > 0 ) {
     981       29556 :       ulong proposed_vote_slot =
     982       29556 :         fd_ulong_if( has_root_to_check,
     983             :           // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L281
     984       29556 :           root_to_check,
     985             :           // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L283
     986       29556 :           deq_fd_vote_lockout_t_peek_index_const( proposed_lockouts,
     987       29556 :             proposed_lockouts_index )
     988       29556 :           ->slot );
     989             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L285
     990       29556 :       if( !has_root_to_check && proposed_lockouts_index > 0UL &&
     991       29556 :         proposed_vote_slot <=
     992        1200 :         deq_fd_vote_lockout_t_peek_index_const(
     993        1200 :           proposed_lockouts,
     994        1200 :             fd_ulong_checked_sub_expect(
     995        1200 :               proposed_lockouts_index,
     996        1200 :                 1,
     997        1200 :                 "`proposed_lockouts_index` is positive when checking `SlotsNotOrdered`" ) )
     998        1200 :         ->slot ) {
     999             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L293
    1000           9 :         ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_NOT_ORDERED;
    1001           9 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1002           9 :       }
    1003             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L295
    1004       29547 :       ulong ancestor_slot =
    1005       29547 :         deq_fd_slot_hash_t_peek_index_const(
    1006       29547 :           slot_hashes->hashes,
    1007       29547 :             fd_ulong_checked_sub_expect(
    1008       29547 :               slot_hashes_index,
    1009       29547 :                 1UL,
    1010       29547 :                 "`slot_hashes_index` is positive when computing `ancestor_slot`" ) )
    1011       29547 :         ->slot;
    1012             :       /* Find if this slot in the proposed vote state exists in the SlotHashes history
    1013             :          to confirm if it was a valid ancestor on this fork */
    1014             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L303
    1015       29547 :       if( proposed_vote_slot < ancestor_slot ) {
    1016         702 :         if( slot_hashes_index == deq_fd_slot_hash_t_cnt( slot_hashes->hashes ) ) {
    1017             :           /* The vote slot does not exist in the SlotHashes history because it's too old,
    1018             :              i.e. older than the oldest slot in the history. */
    1019         423 :           if( proposed_vote_slot >= earliest_slot_hash_in_history ) {
    1020           0 :             ctx->txn_ctx->custom_err = 0;
    1021           0 :             return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1022           0 :           }
    1023             :           // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L310
    1024         423 :           if( !contains_slot( vote_state, proposed_vote_slot ) && !has_root_to_check ) {
    1025             :             /* If the vote slot is both:
    1026             :                1) Too old
    1027             :                2) Doesn't already exist in vote state
    1028             :                Then filter it out */
    1029         327 :             proposed_lockouts_indexes_to_filter[filter_index++] = proposed_lockouts_index;        }
    1030             :           // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L318
    1031         423 :           if( has_root_to_check ) {
    1032          93 :             ulong new_proposed_root = root_to_check;
    1033             :             /* 1. Because `root_to_check.is_some()`, then we know that
    1034             :                we haven't checked the root yet in this loop, so
    1035             :                `proposed_vote_slot` == `new_proposed_root` == `vote_state_update.root` */
    1036          93 :             FD_TEST( new_proposed_root == proposed_vote_slot );
    1037             :             /* 2. We know from the assert earlier in the function that
    1038             :                `proposed_vote_slot < earliest_slot_hash_in_history`,
    1039             :                so from 1. we know that `new_proposed_root < earliest_slot_hash_in_history` */
    1040          93 :             if( new_proposed_root >= earliest_slot_hash_in_history ) {
    1041           0 :               ctx->txn_ctx->custom_err = 0;
    1042           0 :               return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1043           0 :             }
    1044             : 
    1045             :             // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L329
    1046          93 :             has_root_to_check = 0;
    1047          93 :             root_to_check     = ULONG_MAX;
    1048         330 :           } else {
    1049             :             // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L331
    1050         330 :             proposed_lockouts_index = fd_ulong_checked_add_expect(
    1051         330 :               proposed_lockouts_index,
    1052         330 :                 1,
    1053         330 :                 "`proposed_lockouts_index` is bounded by `MAX_LOCKOUT_HISTORY` when "
    1054         330 :                 "`proposed_vote_slot` is too old to be in SlotHashes history" );
    1055         330 :           }
    1056         423 :           continue;
    1057         423 :         } else {
    1058             :           /* If the vote slot is new enough to be in the slot history,
    1059             :              but is not part of the slot history, then it must belong to another fork,
    1060             :              which means this vote state update is invalid. */
    1061             :           // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L340
    1062         279 :           if( has_root_to_check ) {
    1063          87 :             ctx->txn_ctx->custom_err = FD_VOTE_ERR_ROOT_ON_DIFFERENT_FORK;
    1064          87 :             return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1065         192 :           } else {
    1066         192 :             ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
    1067         192 :             return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1068         192 :           }
    1069         279 :         }
    1070       28845 :       } else if( proposed_vote_slot > ancestor_slot ) {
    1071             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L347
    1072             : 
    1073             :         /* Decrement `slot_hashes_index` to find newer slots in the SlotHashes history */
    1074       28029 :         slot_hashes_index = fd_ulong_checked_sub_expect(
    1075       28029 :           slot_hashes_index,
    1076       28029 :             1,
    1077       28029 :             "`slot_hashes_index` is positive when finding newer slots in SlotHashes history" );
    1078       28029 :         continue;
    1079       28029 :       } else {
    1080             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L354
    1081             : 
    1082             :         /* Once the slot in `vote_state_update.lockouts` is found, bump to the next slot
    1083             :            in `vote_state_update.lockouts` and continue. If we were checking the root,
    1084             :            start checking the vote state instead. */
    1085         816 :         if( has_root_to_check ) {
    1086          24 :           has_root_to_check = 0;
    1087          24 :           root_to_check     = ULONG_MAX;
    1088         792 :         } else {
    1089         792 :           proposed_lockouts_index = fd_ulong_checked_add_expect(
    1090         792 :             proposed_lockouts_index,
    1091         792 :               1,
    1092         792 :               "`proposed_lockouts_index` is bounded by `MAX_LOCKOUT_HISTORY` "
    1093         792 :               "when match is found in SlotHashes history" );
    1094         792 :           slot_hashes_index = fd_ulong_checked_sub_expect(
    1095         792 :             slot_hashes_index,
    1096         792 :               1,
    1097         792 :               "`slot_hashes_index` is positive when match is found in SlotHashes history" );
    1098         792 :         }
    1099         816 :       }
    1100       29547 :     }
    1101             : 
    1102             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L372
    1103         102 :     if( proposed_lockouts_index != deq_fd_vote_lockout_t_cnt( proposed_lockouts ) ) {
    1104             :       /* The last vote slot in the update did not exist in SlotHashes */
    1105          39 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
    1106          39 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1107          39 :     }
    1108             : 
    1109             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L401
    1110          63 :     if( memcmp( &deq_fd_slot_hash_t_peek_index_const( slot_hashes->hashes, slot_hashes_index )->hash,
    1111          63 :         proposed_hash,
    1112          63 :         sizeof( fd_hash_t ) ) != 0 ) {
    1113             :       /* This means the newest vote in the slot has a match that
    1114             :          doesn't match the expected hash for that slot on this fork */
    1115           6 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_HASH_MISMATCH;
    1116           6 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1117           6 :     }
    1118             : 
    1119             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L418
    1120             :     /* Filter out the irrelevant votes */
    1121          57 :     proposed_lockouts_index = 0UL;
    1122          57 :     ulong filter_votes_index = deq_fd_vote_lockout_t_cnt( proposed_lockouts );
    1123             : 
    1124             :     /* We need to iterate backwards here because proposed_lockouts_indexes_to_filter[ i ] is a
    1125             :        strictly increasing value. Forward iterating can lead to the proposed lockout indicies to get
    1126             :        shifted leading to popping the wrong proposed lockouts or out of bounds accessing. We need
    1127             :        to be sure of handling underflow in this case. */
    1128             : 
    1129         270 :     for( ulong i=filter_index; i>0UL && filter_votes_index>0UL; i-- ) {
    1130         213 :       proposed_lockouts_index = i - 1UL;
    1131         213 :       if( FD_UNLIKELY(proposed_lockouts_indexes_to_filter[ proposed_lockouts_index ]>=filter_votes_index ) ) {
    1132           0 :         return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
    1133           0 :       }
    1134             : 
    1135         213 :       deq_fd_vote_lockout_t_pop_idx_tail( proposed_lockouts, proposed_lockouts_indexes_to_filter[ proposed_lockouts_index ] );
    1136         213 :       filter_votes_index--;
    1137         213 :     }
    1138         390 :   } FD_SPAD_FRAME_END;
    1139             : 
    1140          57 :   return FD_EXECUTOR_INSTR_SUCCESS;
    1141         390 : }
    1142             : 
    1143             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L440
    1144             : static int
    1145             : check_slots_are_valid( fd_vote_state_t *        vote_state,
    1146             :                        ulong const *            vote_slots,
    1147             :                        fd_hash_t const *        vote_hash,
    1148             :                        fd_slot_hashes_t const * slot_hashes,
    1149         393 :                        fd_exec_instr_ctx_t const * ctx ) {
    1150         393 :   ulong i              = 0;
    1151         393 :   ulong j              = deq_fd_slot_hash_t_cnt( slot_hashes->hashes );
    1152         393 :   ulong vote_slots_len = deq_ulong_cnt( vote_slots );
    1153             : 
    1154             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L462
    1155       50751 :   while( i < vote_slots_len && j > 0 ) {
    1156       50358 :     ulong * last_voted_slot_ = last_voted_slot( vote_state );
    1157       50358 :     if( FD_UNLIKELY( last_voted_slot_ &&
    1158       50358 :                      *deq_ulong_peek_index_const( vote_slots, i ) <= *last_voted_slot_ ) ) {
    1159             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L469
    1160        1707 :       i = fd_ulong_checked_add_expect(
    1161        1707 :           i, 1, "`i` is bounded by `MAX_LOCKOUT_HISTORY` when finding larger slots" );
    1162        1707 :       continue;
    1163        1707 :     }
    1164             : 
    1165             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L476
    1166       48651 :     if( FD_UNLIKELY(
    1167       48651 :             *deq_ulong_peek_index_const( vote_slots, i ) !=
    1168       48651 :             deq_fd_slot_hash_t_peek_index( slot_hashes->hashes,
    1169       48651 :                                            fd_ulong_checked_sub_expect( j, 1, "`j` is positive" ) )
    1170       48651 :                 ->slot ) ) {
    1171       48531 :       j = fd_ulong_checked_sub_expect( j, 1, "`j` is positive when finding newer slots" );
    1172       48531 :       continue;
    1173       48531 :     }
    1174             : 
    1175             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L486
    1176         120 :     i = fd_ulong_checked_add_expect(
    1177         120 :         i, 1, "`i` is bounded by `MAX_LOCKOUT_HISTORY` when hash is found" );
    1178         120 :     j = fd_ulong_checked_sub_expect( j, 1, "`j` is positive when hash is found" );
    1179         120 :   }
    1180             : 
    1181             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L494
    1182         393 :   if( FD_UNLIKELY( j == deq_fd_slot_hash_t_cnt( slot_hashes->hashes ) ) ) {
    1183         108 :     ctx->txn_ctx->custom_err = FD_VOTE_ERROR_VOTE_TOO_OLD;
    1184         108 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1185         108 :   }
    1186         285 :   if( FD_UNLIKELY( i != vote_slots_len ) ) {
    1187         273 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
    1188         273 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1189         273 :   }
    1190             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L514
    1191          12 :   if( FD_UNLIKELY( 0 != memcmp( &deq_fd_slot_hash_t_peek_index( slot_hashes->hashes, j )->hash,
    1192          12 :                                 vote_hash,
    1193          12 :                                 32UL ) ) ) {
    1194           3 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_HASH_MISMATCH;
    1195           3 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1196           3 :   }
    1197           9 :   return 0;
    1198          12 : }
    1199             : 
    1200             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L565
    1201             : static int
    1202             : process_new_vote_state( fd_vote_state_t *           vote_state,
    1203             :                         fd_landed_vote_t *          new_state,
    1204             :                         int                         has_new_root,
    1205             :                         ulong                       new_root,
    1206             :                         int                         has_timestamp,
    1207             :                         long                        timestamp,
    1208             :                         ulong                       epoch,
    1209             :                         ulong                       current_slot,
    1210          57 :                         fd_exec_instr_ctx_t const * ctx /* feature_set */ ) {
    1211          57 :   int rc;
    1212             : 
    1213          57 :   FD_TEST( !deq_fd_landed_vote_t_empty( new_state ) );
    1214             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L575
    1215          57 :   if( FD_UNLIKELY( deq_fd_landed_vote_t_cnt( new_state ) > MAX_LOCKOUT_HISTORY ) ) {
    1216           0 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_TOO_MANY_VOTES;
    1217           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1218          57 :   };
    1219             : 
    1220             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L579
    1221          57 :   if( FD_UNLIKELY( has_new_root && vote_state->has_root_slot ) ) {
    1222             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L581
    1223          24 :     if( FD_UNLIKELY( new_root < vote_state->root_slot ) ) {
    1224           0 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_ROOT_ROLL_BACK;
    1225           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1226           0 :     }
    1227          33 :   } else if( FD_UNLIKELY( !has_new_root && vote_state->has_root_slot ) ) {
    1228             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L586
    1229           6 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_ROOT_ROLL_BACK;
    1230           6 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1231          27 :   } else {
    1232             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L588
    1233             :     /* no-op */
    1234          27 :   }
    1235             : 
    1236          51 :   fd_landed_vote_t * previous_vote = NULL;
    1237          51 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
    1238         822 :        !deq_fd_landed_vote_t_iter_done( new_state, iter );
    1239         774 :        iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
    1240         774 :     fd_landed_vote_t * vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
    1241         774 :     if( FD_LIKELY( vote->lockout.confirmation_count == 0 ) ) {
    1242           0 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_ZERO_CONFIRMATIONS;
    1243           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1244         774 :     } else if( FD_UNLIKELY( vote->lockout.confirmation_count > MAX_LOCKOUT_HISTORY ) ) {
    1245           0 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_CONFIRMATION_TOO_LARGE;
    1246           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1247         774 :     } else if( FD_LIKELY( has_new_root ) ) {
    1248         744 :       if( FD_UNLIKELY( vote->lockout.slot <= new_root && new_root != SLOT_DEFAULT ) ) {
    1249           0 :         ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOT_SMALLER_THAN_ROOT;
    1250           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1251           0 :       }
    1252         744 :     }
    1253             : 
    1254         774 :     if( FD_LIKELY( previous_vote ) ) {
    1255         723 :       if( FD_UNLIKELY( previous_vote->lockout.slot >= vote->lockout.slot ) ) {
    1256           0 :         ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_NOT_ORDERED;
    1257           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1258         723 :       } else if( FD_UNLIKELY( previous_vote->lockout.confirmation_count <=
    1259         723 :                               vote->lockout.confirmation_count ) ) {
    1260           0 :         ctx->txn_ctx->custom_err = FD_VOTE_ERR_CONFIRMATIONS_NOT_ORDERED;
    1261           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1262         723 :       } else if( FD_UNLIKELY( vote->lockout.slot >
    1263         723 :                               last_locked_out_slot( &previous_vote->lockout ) ) ) {
    1264           3 :         ctx->txn_ctx->custom_err = FD_VOTE_ERR_NEW_VOTE_STATE_LOCKOUT_MISMATCH;
    1265           3 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1266           3 :       }
    1267         723 :     }
    1268         771 :     previous_vote = vote;
    1269         771 :   }
    1270             : 
    1271          48 :   ulong current_vote_state_index = 0;
    1272          48 :   ulong new_vote_state_index     = 0;
    1273             : 
    1274             :   /* Accumulate credits earned by newly rooted slots.  The behavior changes with
    1275             :      timely_vote_credits: prior to this feature, there was a bug that counted a new root slot as 1
    1276             :      credit even if it had never been voted on. timely_vote_credits fixes this bug by only awarding
    1277             :      credits for slots actually voted on and finalized. */
    1278             : 
    1279             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L635
    1280          48 :   int   timely_vote_credits = FD_FEATURE_ACTIVE( ctx->slot_ctx, timely_vote_credits );
    1281          48 :   int   deprecate_unused_legacy_vote_plumbing = FD_FEATURE_ACTIVE( ctx->slot_ctx, deprecate_unused_legacy_vote_plumbing );
    1282             : 
    1283             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L641
    1284          48 :   ulong earned_credits      = timely_vote_credits ? 0 : 1;
    1285             : 
    1286          48 :   if( FD_LIKELY( has_new_root ) ) {
    1287          24 :     for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( vote_state->votes );
    1288          81 :          !deq_fd_landed_vote_t_iter_done( vote_state->votes, iter );
    1289          81 :          iter = deq_fd_landed_vote_t_iter_next( vote_state->votes, iter ) ) {
    1290          81 :       fd_landed_vote_t * current_vote = deq_fd_landed_vote_t_iter_ele( vote_state->votes, iter );
    1291             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L647
    1292          81 :       if( FD_UNLIKELY( current_vote->lockout.slot <= new_root ) ) {
    1293             :         // this is safe because we're inside if has_new_root
    1294          57 :         if( FD_LIKELY( timely_vote_credits || ( current_vote->lockout.slot != new_root ) ) ) {
    1295          33 :           earned_credits = fd_ulong_checked_add_expect(
    1296          33 :               credits_for_vote_at_index( vote_state,
    1297          33 :                 current_vote_state_index,
    1298          33 :                 timely_vote_credits,
    1299          33 :                 deprecate_unused_legacy_vote_plumbing
    1300          33 :                 ),
    1301          33 :               earned_credits,
    1302          33 :               "`earned_credits` does not overflow" );
    1303          33 :         }
    1304          57 :         current_vote_state_index = fd_ulong_checked_add_expect(
    1305          57 :             current_vote_state_index,
    1306          57 :             1,
    1307          57 :             "`current_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
    1308          57 :             "when processing new root" );
    1309          57 :         continue;
    1310          57 :       }
    1311          24 :       break;
    1312          81 :     }
    1313          24 :   }
    1314             : 
    1315             :   // For any slots newly added to the new vote state, the vote latency of that slot is not provided by the
    1316             :   // vote instruction contents, but instead is computed from the actual latency of the vote
    1317             :   // instruction. This prevents other validators from manipulating their own vote latencies within their vote states
    1318             :   // and forcing the rest of the cluster to accept these possibly fraudulent latency values.  If the
    1319             :   // timly_vote_credits feature is not enabled then vote latency is set to 0 for new votes.
    1320             :   //
    1321             :   // For any slot that is in both the new state and the current state, the vote latency of the new state is taken
    1322             :   // from the current state.
    1323             :   //
    1324             :   // Thus vote latencies are set here for any newly vote-on slots when a vote instruction is received.
    1325             :   // They are copied into the new vote state after every vote for already voted-on slots.
    1326             :   // And when voted-on slots are rooted, the vote latencies stored in the vote state of all the rooted slots is used
    1327             :   // to compute credits earned.
    1328             :   // All validators compute the same vote latencies because all process the same vote instruction at the
    1329             :   // same slot, and the only time vote latencies are ever computed is at the time that their slot is first voted on;
    1330             :   // after that, the latencies are retained unaltered until the slot is rooted.
    1331             : 
    1332             :   // All the votes in our current vote state that are missing from the new vote state
    1333             :   // must have been expired by later votes. Check that the lockouts match this assumption.
    1334             : 
    1335             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L686
    1336         774 :   while( current_vote_state_index < deq_fd_landed_vote_t_cnt( vote_state->votes ) &&
    1337         774 :          new_vote_state_index < deq_fd_landed_vote_t_cnt( new_state ) ) {
    1338         726 :     fd_landed_vote_t * current_vote =
    1339         726 :         deq_fd_landed_vote_t_peek_index( vote_state->votes, current_vote_state_index );
    1340             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L690
    1341         726 :     fd_landed_vote_t * new_vote =
    1342         726 :         deq_fd_landed_vote_t_peek_index( new_state, new_vote_state_index );
    1343             : 
    1344             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L696
    1345         726 :     if( FD_LIKELY( current_vote->lockout.slot < new_vote->lockout.slot ) ) {
    1346          30 :       ulong last_locked_out_slot =
    1347          30 :           current_vote->lockout.slot +
    1348          30 :           (ulong)pow( INITIAL_LOCKOUT, current_vote->lockout.confirmation_count );
    1349             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L697
    1350          30 :       if( last_locked_out_slot >= new_vote->lockout.slot ) {
    1351             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L698
    1352           0 :         ctx->txn_ctx->custom_err = FD_VOTE_ERR_LOCKOUT_CONFLICT;
    1353           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1354           0 :       }
    1355             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L700
    1356          30 :       current_vote_state_index =
    1357          30 :           fd_ulong_checked_add_expect( current_vote_state_index,
    1358          30 :                                        1,
    1359          30 :                                        "`current_vote_state_index` is bounded by "
    1360          30 :                                        "`MAX_LOCKOUT_HISTORY` when slot is less than proposed" );
    1361             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L704
    1362         696 :     } else if( FD_UNLIKELY( current_vote->lockout.slot == new_vote->lockout.slot ) ) {
    1363             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L707
    1364         687 :       if( new_vote->lockout.confirmation_count < current_vote->lockout.confirmation_count ) {
    1365           0 :         ctx->txn_ctx->custom_err = FD_VOTE_ERR_CONFIRMATION_ROLL_BACK;
    1366           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1367           0 :       }
    1368             : 
    1369             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L712
    1370         687 :       new_vote->latency =
    1371         687 :           deq_fd_landed_vote_t_peek_index( vote_state->votes, current_vote_state_index )->latency;
    1372             : 
    1373             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L714
    1374         687 :       current_vote_state_index =
    1375         687 :           fd_ulong_checked_add_expect( current_vote_state_index,
    1376         687 :                                        1,
    1377         687 :                                        "`current_vote_state_index` is bounded by "
    1378         687 :                                        "`MAX_LOCKOUT_HISTORY` when slot is equal to proposed" );
    1379             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L717
    1380         687 :       new_vote_state_index =
    1381         687 :           fd_ulong_checked_add_expect( new_vote_state_index,
    1382         687 :                                        1,
    1383         687 :                                        "`new_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
    1384         687 :                                        "when slot is equal to proposed" );
    1385         687 :     } else {
    1386             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L722
    1387           9 :       new_vote_state_index =
    1388           9 :           fd_ulong_checked_add_expect( new_vote_state_index,
    1389           9 :                                        1,
    1390           9 :                                        "`new_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
    1391           9 :                                        "when slot is greater than proposed" );
    1392           9 :     }
    1393         726 :   }
    1394             : 
    1395             :   // Comment:
    1396             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L736
    1397          48 :   if( FD_LIKELY( timely_vote_credits ) ) {
    1398             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L737
    1399           3 :     for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
    1400           6 :          !deq_fd_landed_vote_t_iter_done( new_state, iter );
    1401           3 :          iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
    1402           3 :       fd_landed_vote_t * new_vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
    1403             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L738
    1404           3 :       if( FD_UNLIKELY( new_vote->latency == 0 ) ) {
    1405             :         // this is unlikely because as validators upgrade, it should converge to the new vote state
    1406             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L739
    1407           3 :         new_vote->latency = compute_vote_latency( new_vote->lockout.slot, current_slot );
    1408           3 :       }
    1409           3 :     }
    1410           3 :   }
    1411             : 
    1412             :   // doesn't matter what the value of slot if `is_some = 0` i.e. `Option::None`
    1413             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L744
    1414          48 :   int both_none = !vote_state->has_root_slot && !has_new_root;
    1415          48 :   if( ( !both_none && ( vote_state->has_root_slot != has_new_root ||
    1416          24 :                         vote_state->root_slot != new_root ) ) ) {
    1417          24 :     increment_credits( vote_state, epoch, earned_credits );
    1418          24 :   }
    1419             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L750
    1420          48 :   if( FD_LIKELY( has_timestamp ) ) {
    1421             :     /* new_state asserted nonempty at function beginning */
    1422          33 :     if( deq_fd_landed_vote_t_empty( new_state ) ) {
    1423           0 :       FD_LOG_ERR(( "solana panic" ));
    1424             :       // TODO: solana panics ...  unclear what to return
    1425           0 :       ctx->txn_ctx->custom_err = 0;
    1426           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1427           0 :     }
    1428          33 :     ulong last_slot = deq_fd_landed_vote_t_peek_tail( new_state )->lockout.slot;
    1429          33 :     rc              = process_timestamp( vote_state, last_slot, timestamp, ctx );
    1430          33 :     if( FD_UNLIKELY( rc ) ) { return rc; }
    1431          24 :     vote_state->last_timestamp.timestamp = timestamp;
    1432          24 :   }
    1433             : 
    1434             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L754
    1435          39 :   vote_state->has_root_slot = (uchar)has_new_root;
    1436          39 :   vote_state->root_slot     = new_root;
    1437             : 
    1438             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L755
    1439          39 :   deq_fd_landed_vote_t_remove_all( vote_state->votes );
    1440          39 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
    1441         798 :        !deq_fd_landed_vote_t_iter_done( new_state, iter );
    1442         759 :        iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
    1443         759 :     fd_landed_vote_t * landed_vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
    1444         759 :     deq_fd_landed_vote_t_push_tail( vote_state->votes, *landed_vote );
    1445         759 :   }
    1446             : 
    1447          39 :   return FD_EXECUTOR_INSTR_SUCCESS;
    1448          48 : }
    1449             : 
    1450             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L849
    1451             : static int
    1452             : authorize( ulong                         vote_acct_idx,
    1453             :            fd_borrowed_account_t *       vote_account,
    1454             :            fd_pubkey_t const *           authorized,
    1455             :            fd_vote_authorize_t           vote_authorize,
    1456             :            fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1457             :            fd_sol_sysvar_clock_t const * clock,
    1458        1932 :            fd_exec_instr_ctx_t const *   ctx /* feature_set */ ) {
    1459        1932 :   int rc;
    1460             : 
    1461        1932 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    1462             : 
    1463             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L857
    1464        1932 :   fd_vote_state_versioned_t vote_state_versioned;
    1465        1932 :   rc = get_state( vote_account, valloc, &vote_state_versioned );
    1466        1932 :   if( FD_UNLIKELY( rc ) ) return rc;
    1467        1377 :   convert_to_current( &vote_state_versioned, valloc );
    1468        1377 :   fd_vote_state_t * vote_state = &vote_state_versioned.inner.current;
    1469             : 
    1470             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L861
    1471        1377 :   switch( vote_authorize.discriminant ) {
    1472             : 
    1473             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L862
    1474         855 :   case fd_vote_authorize_enum_voter:;
    1475             : 
    1476             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L863
    1477         855 :     int authorized_withdrawer_signer =
    1478         855 :         FD_EXECUTOR_INSTR_SUCCESS ==
    1479         855 :         verify_authorized_signer( &vote_state->authorized_withdrawer, signers );
    1480             : 
    1481             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L866
    1482         855 :     rc = set_new_authorized_voter( vote_state,
    1483         855 :                                    authorized,
    1484         855 :                                    clock->epoch,
    1485         855 :                                    clock->leader_schedule_epoch + 1UL,
    1486         855 :                                    authorized_withdrawer_signer,
    1487         855 :                                    signers,
    1488         855 :                                    ctx );
    1489         855 :     if( FD_UNLIKELY( rc ) ) return rc;
    1490         255 :     break;
    1491             : 
    1492             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L883
    1493         522 :   case fd_vote_authorize_enum_withdrawer:
    1494         522 :     rc = verify_authorized_signer( &vote_state->authorized_withdrawer, signers );
    1495         522 :     if( FD_UNLIKELY( rc ) ) return rc;
    1496         231 :     memcpy( &vote_state->authorized_withdrawer, authorized, sizeof( fd_pubkey_t ) );
    1497         231 :     break;
    1498             : 
    1499             :   // failing exhaustive check is fatal
    1500           0 :   default:
    1501           0 :     __builtin_unreachable();
    1502        1377 :   }
    1503             : 
    1504             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L890
    1505         486 :   return set_vote_account_state( vote_acct_idx, vote_account, vote_state, ctx );
    1506        1377 : }
    1507             : 
    1508             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L894
    1509             : static int
    1510             : update_validator_identity( ulong                       vote_acct_idx,
    1511             :                            fd_borrowed_account_t *     vote_account,
    1512             :                            fd_pubkey_t const *         node_pubkey,
    1513             :                            fd_pubkey_t const *         signers[static FD_TXN_SIG_MAX],
    1514        1320 :                            fd_exec_instr_ctx_t const * ctx /* feature_set */ ) {
    1515        1320 :   int rc;
    1516             : 
    1517        1320 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    1518             : 
    1519             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L900
    1520        1320 :   fd_vote_state_versioned_t vote_state_versioned;
    1521        1320 :   rc = get_state( vote_account, valloc, &vote_state_versioned );
    1522        1320 :   if( FD_UNLIKELY( rc ) ) return rc;
    1523         774 :   convert_to_current( &vote_state_versioned, valloc );
    1524         774 :   fd_vote_state_t * vote_state = &vote_state_versioned.inner.current;
    1525             : 
    1526             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L905
    1527         774 :   rc = verify_authorized_signer( &vote_state->authorized_withdrawer, signers );
    1528         774 :   if( FD_UNLIKELY( rc ) ) return rc;
    1529             : 
    1530             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L908
    1531         390 :   rc = verify_authorized_signer( node_pubkey, signers );
    1532         390 :   if( FD_UNLIKELY( rc ) ) return rc;
    1533             : 
    1534             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L910
    1535         324 :   vote_state->node_pubkey = *node_pubkey;
    1536             : 
    1537             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L912
    1538         324 :   return set_vote_account_state( vote_acct_idx, vote_account, vote_state, ctx );
    1539         390 : }
    1540             : 
    1541             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L971
    1542             : static int
    1543         459 : is_commission_update_allowed( ulong slot, fd_epoch_schedule_t const * epoch_schedule ) {
    1544         459 :   if( FD_LIKELY( epoch_schedule->slots_per_epoch > 0UL ) ) {
    1545         459 :     ulong relative_slot = fd_ulong_sat_sub( slot, epoch_schedule->first_normal_slot );
    1546             :     // TODO underflow and overflow edge cases in addition to div by 0
    1547         459 :     relative_slot %= epoch_schedule->slots_per_epoch;
    1548         459 :     return fd_ulong_sat_mul( relative_slot, 2 ) <= epoch_schedule->slots_per_epoch;
    1549         459 :   } else {
    1550           0 :     return 1;
    1551           0 :   }
    1552         459 : }
    1553             : 
    1554             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L916
    1555             : static int
    1556             : update_commission( ulong                       vote_acct_idx,
    1557             :                    fd_borrowed_account_t *     vote_account,
    1558             :                    uchar                       commission,
    1559             :                    fd_pubkey_t const *         signers[static FD_TXN_SIG_MAX],
    1560             :                    fd_epoch_schedule_t const * epoch_schedule,
    1561             :                    fd_sol_sysvar_clock_t const * clock,
    1562        1401 :                    fd_exec_instr_ctx_t const * ctx /* feature_set */ ) {
    1563        1401 :   int rc;
    1564             : 
    1565        1401 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    1566             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L925
    1567        1401 :   fd_vote_state_versioned_t vote_state_versioned;
    1568        1401 :   fd_vote_state_t * vote_state = NULL;
    1569             : 
    1570             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L927
    1571        1401 :   int enforce_commission_update_rule = 1;
    1572        1401 :   if (FD_FEATURE_ACTIVE( ctx->slot_ctx, allow_commission_decrease_at_any_time )) {
    1573         648 :     rc = get_state( vote_account, valloc, &vote_state_versioned );
    1574         648 :     if ( FD_LIKELY( rc==FD_EXECUTOR_INSTR_SUCCESS ) ) {
    1575          54 :       convert_to_current( &vote_state_versioned, valloc );
    1576          54 :       vote_state = &vote_state_versioned.inner.current;
    1577          54 :       enforce_commission_update_rule = commission > vote_state->commission;
    1578          54 :     }
    1579         648 :   }
    1580             : 
    1581             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L940
    1582        1401 :   if( FD_LIKELY( enforce_commission_update_rule && FD_FEATURE_ACTIVE( ctx->slot_ctx,
    1583        1401 :         commission_updates_only_allowed_in_first_half_of_epoch ) ) ) {
    1584         459 :     if( FD_UNLIKELY( !is_commission_update_allowed( clock->slot, epoch_schedule ) ) ) {
    1585         120 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_COMMISSION_UPDATE_TOO_LATE;
    1586         120 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1587         120 :     }
    1588         459 :   }
    1589             : 
    1590             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L949
    1591        1281 :   if (NULL == vote_state) {
    1592        1233 :     rc = get_state( vote_account, valloc, &vote_state_versioned );
    1593        1233 :     if( FD_UNLIKELY( rc ) ) return rc;
    1594         414 :     convert_to_current( &vote_state_versioned, valloc );
    1595         414 :     vote_state = &vote_state_versioned.inner.current;
    1596         414 :   }
    1597             : 
    1598             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L957
    1599         462 :   rc = verify_authorized_signer( &vote_state->authorized_withdrawer, signers );
    1600         462 :   if( FD_UNLIKELY( rc ) ) return rc;
    1601             : 
    1602             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L959
    1603         216 :   vote_state->commission = commission;
    1604             : 
    1605             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L961
    1606         216 :   return set_vote_account_state( vote_acct_idx, vote_account, vote_state, ctx );
    1607         462 : }
    1608             : 
    1609             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L997
    1610             : static int
    1611             : withdraw(
    1612             :     /* transaction_context */
    1613             :     fd_exec_instr_ctx_t const *   ctx,
    1614             :     ulong                         vote_acct_idx,
    1615             :     fd_borrowed_account_t *       vote_account,
    1616             :     ulong                         lamports,
    1617             :     ulong                         to_account_index,
    1618             :     fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1619             :     fd_rent_t const *             rent_sysvar,
    1620             :     fd_sol_sysvar_clock_t const * clock
    1621             :     /* feature_set */
    1622         903 : ) {
    1623         903 :   int rc;
    1624             : 
    1625         903 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    1626             : 
    1627             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1010
    1628         903 :   fd_vote_state_versioned_t vote_state_versioned;
    1629         903 :   rc = get_state( vote_account, valloc, &vote_state_versioned );
    1630         903 :   if( FD_UNLIKELY( rc ) ) return rc;
    1631         540 :   convert_to_current( &vote_state_versioned, valloc );
    1632         540 :   fd_vote_state_t * vote_state = &vote_state_versioned.inner.current;
    1633             : 
    1634             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1014
    1635         540 :   rc = verify_authorized_signer( &vote_state->authorized_withdrawer, signers );
    1636         540 :   if( FD_UNLIKELY( rc ) ) return rc;
    1637             : 
    1638             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1016
    1639         156 :   if( FD_UNLIKELY( lamports > vote_account->const_meta->info.lamports ) )
    1640          18 :     return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1641         138 :   ulong remaining_balance = vote_account->const_meta->info.lamports - lamports;
    1642             : 
    1643             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1021
    1644         138 :   if( FD_UNLIKELY( remaining_balance == 0 ) ) {
    1645             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1014
    1646          84 :     int reject_active_vote_account_close = 0;
    1647             : 
    1648          84 :     ulong last_epoch_with_credits;
    1649          84 :     if( FD_LIKELY( !deq_fd_vote_epoch_credits_t_empty( vote_state->epoch_credits ) ) ) {
    1650          60 :       last_epoch_with_credits =
    1651          60 :           deq_fd_vote_epoch_credits_t_peek_tail_const( vote_state->epoch_credits )->epoch;
    1652          60 :       ulong current_epoch = clock->epoch;
    1653          60 :       reject_active_vote_account_close =
    1654          60 :           fd_ulong_sat_sub( current_epoch, last_epoch_with_credits ) < 2;
    1655          60 :     }
    1656             : 
    1657             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1034
    1658          84 :     if( FD_UNLIKELY( reject_active_vote_account_close ) ) {
    1659             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1036
    1660          18 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_ACTIVE_VOTE_ACCOUNT_CLOSE;
    1661          18 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1662          66 :     } else {
    1663             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1040
    1664          66 :       fd_vote_state_versioned_t vote_state_versions;
    1665          66 :       fd_vote_state_versioned_new_disc( &vote_state_versions,
    1666          66 :                                         fd_vote_state_versioned_enum_current );
    1667          66 :       vote_state_versions.inner.current.prior_voters.idx      = 31;
    1668          66 :       vote_state_versions.inner.current.prior_voters.is_empty = 1;
    1669          66 :       fd_vote_state_t * default_vote_state                    = &vote_state_versions.inner.current;
    1670          66 :       rc                                                      = 0;
    1671          66 :       rc = set_vote_account_state( vote_acct_idx, vote_account, default_vote_state, ctx );
    1672          66 :       if( FD_UNLIKELY( rc != 0 ) ) return rc;
    1673          66 :     }
    1674          84 :   } else {
    1675             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1043
    1676          54 :     ulong min_rent_exempt_balance =
    1677          54 :         fd_rent_exempt_minimum_balance( rent_sysvar, vote_account->const_meta->dlen );
    1678          54 :     if( remaining_balance < min_rent_exempt_balance ) {
    1679           9 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1680           9 :     }
    1681          54 :   }
    1682             : 
    1683             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1049
    1684          90 :   rc = fd_account_checked_sub_lamports(ctx, vote_acct_idx, lamports);
    1685          90 :   if( FD_UNLIKELY( rc ) ) return rc;
    1686             : 
    1687             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1053
    1688          75 :   rc = fd_account_checked_add_lamports(ctx, to_account_index, lamports);
    1689          75 :   if( FD_UNLIKELY( rc ) ) return rc;
    1690             : 
    1691          27 :   return 0;
    1692          75 : }
    1693             : 
    1694             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L760
    1695             : static int
    1696             : process_vote_unfiltered( fd_vote_state_t *           vote_state,
    1697             :                          ulong *                     vote_slots,
    1698             :                          fd_vote_t const *           vote,
    1699             :                          fd_slot_hashes_t const *    slot_hashes,
    1700             :                          ulong                       epoch,
    1701             :                          ulong                       current_slot,
    1702             :                          int                         timely_vote_credits,
    1703             :                          int                         deprecate_unused_legacy_vote_plumbing,
    1704         393 :                          fd_exec_instr_ctx_t const * ctx ) {
    1705         393 :   int rc;
    1706             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L770
    1707         393 :   rc = check_slots_are_valid( vote_state, vote_slots, &vote->hash, slot_hashes, ctx );
    1708         393 :   if( FD_UNLIKELY( rc ) ) return rc;
    1709           9 :   for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote_slots );
    1710          33 :        !deq_ulong_iter_done( vote_slots, iter );
    1711          24 :        iter = deq_ulong_iter_next( vote_slots, iter ) ) {
    1712          24 :     ulong * ele = deq_ulong_iter_ele( vote_slots, iter );
    1713             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L772
    1714          24 :     process_next_vote_slot( vote_state, *ele, epoch, current_slot, timely_vote_credits, deprecate_unused_legacy_vote_plumbing);
    1715          24 :   }
    1716           9 :   return 0;
    1717         393 : }
    1718             : 
    1719             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L783
    1720             : static int
    1721             : process_vote( fd_vote_state_t *           vote_state,
    1722             :               fd_vote_t const *           vote,
    1723             :               fd_slot_hashes_t const *    slot_hashes,
    1724             :               ulong                       epoch,
    1725             :               ulong                       current_slot,
    1726             :               int                         timely_vote_credits,
    1727             :               int                         deprecate_unused_legacy_vote_plumbing,
    1728         462 :               fd_exec_instr_ctx_t const * ctx ) {
    1729             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L792
    1730         462 :   if( FD_UNLIKELY( deq_ulong_empty( vote->slots ) ) ) {
    1731           9 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
    1732           9 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1733           9 :   }
    1734             : 
    1735             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L795
    1736         453 :   ulong earliest_slot_in_history = 0;
    1737         453 :   if( FD_UNLIKELY( !deq_fd_slot_hash_t_empty( slot_hashes->hashes ) ) ) {
    1738         441 :     earliest_slot_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes->hashes )->slot;
    1739         441 :   }
    1740             : 
    1741         453 :   ulong   vote_slots_cnt = deq_ulong_cnt( vote->slots );
    1742         453 :   uchar * vote_slots_mem = fd_spad_alloc( ctx->txn_ctx->spad, deq_ulong_align(), deq_ulong_footprint( vote_slots_cnt ) );
    1743             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L796
    1744         453 :   ulong * vote_slots     = deq_ulong_join( deq_ulong_new( vote_slots_mem, vote_slots_cnt ) );
    1745         453 :   for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote->slots );
    1746        7821 :        !deq_ulong_iter_done( vote->slots, iter );
    1747        7368 :        iter = deq_ulong_iter_next( vote->slots, iter ) ) {
    1748        7368 :     ulong * ele = deq_ulong_iter_ele( vote->slots, iter );
    1749        7368 :     if( FD_UNLIKELY( *ele >= earliest_slot_in_history ) ) {
    1750        5979 :       vote_slots = deq_ulong_push_tail( vote_slots, *ele );
    1751        5979 :     }
    1752        7368 :   }
    1753             : 
    1754             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L802
    1755         453 :   if( FD_UNLIKELY( deq_ulong_cnt( vote_slots ) == 0 ) ) {
    1756          60 :     ctx->txn_ctx->custom_err = FD_VOTE_ERR_VOTES_TOO_OLD_ALL_FILTERED;
    1757          60 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1758          60 :   }
    1759             : 
    1760             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L805
    1761         393 :   return process_vote_unfiltered(
    1762         393 :       vote_state, vote_slots, vote, slot_hashes, epoch, current_slot,
    1763         393 :         timely_vote_credits, deprecate_unused_legacy_vote_plumbing, ctx );
    1764         453 : }
    1765             : 
    1766             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1060
    1767             : static int
    1768             : initialize_account( ulong                         vote_acct_idx,
    1769             :                     fd_borrowed_account_t *       vote_account,
    1770             :                     fd_vote_init_t *              vote_init,
    1771             :                     fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1772             :                     fd_sol_sysvar_clock_t const * clock,
    1773         225 :                     fd_exec_instr_ctx_t const *   ctx /* feature_set */ ) {
    1774         225 :   int rc;
    1775             : 
    1776         225 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    1777             : 
    1778             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1067
    1779         225 :   ulong data_len = vote_account->const_meta->dlen;
    1780         225 :   if( FD_UNLIKELY( data_len != size_of_versioned( FD_FEATURE_ACTIVE(
    1781         225 :                                    ctx->slot_ctx, vote_state_add_vote_latency ) ) ) ) {
    1782         216 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
    1783         216 :   }
    1784             : 
    1785             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1074
    1786           9 :   fd_vote_state_versioned_t versioned;
    1787           9 :   rc = get_state( vote_account, valloc, &versioned );
    1788           9 :   if( FD_UNLIKELY( rc ) ) return rc;
    1789             : 
    1790             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1076
    1791           9 :   if( FD_UNLIKELY( !is_uninitialized( &versioned ) ) )
    1792           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
    1793             : 
    1794             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1081
    1795           9 :   rc = verify_authorized_signer( &vote_init->node_pubkey, signers );
    1796           9 :   if( FD_UNLIKELY( rc ) ) return rc;
    1797             : 
    1798             :   /*
    1799             :    * N.B. Technically we should destroy() to release memory before
    1800             :    * newing, otherwise the pointers are wiped and memory is leaked.
    1801             :    * We are probably fine for now since we are bump allocating
    1802             :    * everything and the enclosing frame will free everything when
    1803             :    * popped.
    1804             :    */
    1805             :   // reset the object
    1806           9 :   fd_vote_state_versioned_new( &versioned );
    1807             : 
    1808             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1083
    1809           9 :   vote_state_new( vote_init, clock, valloc, &versioned.inner.current );
    1810           9 :   return set_vote_account_state( vote_acct_idx, vote_account, &versioned.inner.current, ctx );
    1811           9 : }
    1812             : 
    1813             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1086
    1814             : static int
    1815             : verify_and_get_vote_state( fd_borrowed_account_t *       vote_account,
    1816             :                            fd_sol_sysvar_clock_t const * clock,
    1817             :                            fd_pubkey_t const *           signers[FD_TXN_SIG_MAX],
    1818             :                            fd_vote_state_t *             vote_state /* out */,
    1819        2994 :                            fd_exec_instr_ctx_t const *   ctx /* spad */ ) {
    1820        2994 :   int                       rc;
    1821        2994 :   fd_vote_state_versioned_t versioned;
    1822             : 
    1823        2994 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    1824             : 
    1825             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1091
    1826        2994 :   rc = get_state( vote_account, valloc, &versioned );
    1827        2994 :   if( FD_UNLIKELY( rc ) ) return rc;
    1828             : 
    1829             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1093
    1830        2589 :   if( FD_UNLIKELY( is_uninitialized( &versioned ) ) )
    1831          75 :     return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
    1832             : 
    1833             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1097
    1834        2514 :   convert_to_current( &versioned, valloc );
    1835        2514 :   memcpy( vote_state, &versioned.inner.current, sizeof( fd_vote_state_t ) );
    1836             : 
    1837             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1098
    1838        2514 :   fd_pubkey_t * authorized_voter = NULL;
    1839        2514 :   rc = get_and_update_authorized_voter( vote_state, clock->epoch, &authorized_voter, ctx );
    1840        2514 :   if( FD_UNLIKELY( rc ) ) return rc;
    1841             : 
    1842             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1099
    1843        2217 :   rc = verify_authorized_signer( authorized_voter, signers );
    1844        2217 :   if( FD_UNLIKELY( rc ) ) return rc;
    1845             : 
    1846         969 :   return FD_EXECUTOR_INSTR_SUCCESS;
    1847        2217 : }
    1848             : 
    1849             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1104
    1850             : static int
    1851             : process_vote_with_account( ulong                         vote_acct_idx,
    1852             :                            fd_borrowed_account_t *       vote_account,
    1853             :                            fd_slot_hashes_t const *      slot_hashes,
    1854             :                            fd_sol_sysvar_clock_t const * clock,
    1855             :                            fd_vote_t *                   vote,
    1856             :                            fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1857        1158 :                            fd_exec_instr_ctx_t const *   ctx ) {
    1858             : 
    1859        1158 :   int             rc;
    1860        1158 :   fd_vote_state_t vote_state;
    1861             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1112
    1862        1158 :   rc = verify_and_get_vote_state( vote_account, clock, signers, &vote_state, ctx );
    1863        1158 :   if( FD_UNLIKELY( rc ) ) return rc;
    1864             : 
    1865             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1114
    1866         462 :   int   timely_vote_credits = FD_FEATURE_ACTIVE( ctx->slot_ctx, timely_vote_credits );
    1867         462 :   int   deprecate_unused_legacy_vote_plumbing = FD_FEATURE_ACTIVE( ctx->slot_ctx, deprecate_unused_legacy_vote_plumbing );
    1868             : 
    1869             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1117
    1870         462 :   rc = process_vote( &vote_state, vote, slot_hashes, clock->epoch, clock->slot, timely_vote_credits, deprecate_unused_legacy_vote_plumbing, ctx );
    1871         462 :   if( FD_UNLIKELY( rc ) ) return rc;
    1872             : 
    1873             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1126
    1874           9 :   if( FD_LIKELY( vote->timestamp ) ) {
    1875           3 :     if( FD_UNLIKELY( deq_ulong_cnt( vote->slots ) == 0 ) ) {
    1876           0 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
    1877           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1878           0 :     }
    1879             : 
    1880           3 :     ulong * max = deq_ulong_peek_head( vote->slots ) ? deq_ulong_peek_head( vote->slots ) : NULL;
    1881             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1127
    1882           3 :     for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote->slots );
    1883          21 :          !deq_ulong_iter_done( vote->slots, iter );
    1884          18 :          iter = deq_ulong_iter_next( vote->slots, iter ) ) {
    1885          18 :       ulong * ele = deq_ulong_iter_ele( vote->slots, iter );
    1886          18 :       *max        = fd_ulong_max( *max, *ele );
    1887          18 :     }
    1888           3 :     if( FD_UNLIKELY( !max ) ) {
    1889           0 :       ctx->txn_ctx->custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
    1890           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1891           0 :     }
    1892             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1131
    1893           3 :     rc = process_timestamp( &vote_state, *max, *vote->timestamp, ctx );
    1894           3 :     if( FD_UNLIKELY( rc ) ) return rc;
    1895           3 :   }
    1896             : 
    1897             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1133
    1898           9 :   return set_vote_account_state( vote_acct_idx, vote_account, &vote_state, ctx );
    1899           9 : }
    1900             : 
    1901             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1156
    1902             : static int
    1903             : do_process_vote_state_update( fd_vote_state_t *           vote_state,
    1904             :                               fd_slot_hashes_t const *    slot_hashes,
    1905             :                               ulong                       epoch,
    1906             :                               ulong                       slot,
    1907             :                               fd_vote_state_update_t *    vote_state_update,
    1908         498 :                               fd_exec_instr_ctx_t const * ctx /* feature_set */ ) {
    1909         498 :   int rc;
    1910             : 
    1911         498 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    1912             : 
    1913             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1164
    1914         498 :   rc = check_and_filter_proposed_vote_state(
    1915         498 :       vote_state,
    1916         498 :       vote_state_update->lockouts, &vote_state_update->has_root, &vote_state_update->root, &vote_state_update->hash,
    1917         498 :       slot_hashes, ctx );
    1918         498 :   if( FD_UNLIKELY( rc ) ) return rc;
    1919             : 
    1920             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1177
    1921          54 :   fd_landed_vote_t * landed_votes = deq_fd_landed_vote_t_alloc( valloc, deq_fd_vote_lockout_t_cnt( vote_state_update->lockouts ) );
    1922          54 :   for( deq_fd_vote_lockout_t_iter_t iter =
    1923          54 :            deq_fd_vote_lockout_t_iter_init( vote_state_update->lockouts );
    1924         828 :        !deq_fd_vote_lockout_t_iter_done( vote_state_update->lockouts, iter );
    1925         774 :        iter = deq_fd_vote_lockout_t_iter_next( vote_state_update->lockouts, iter ) ) {
    1926         774 :     fd_vote_lockout_t * lockout =
    1927         774 :         deq_fd_vote_lockout_t_iter_ele( vote_state_update->lockouts, iter );
    1928         774 :     deq_fd_landed_vote_t_push_tail( landed_votes,
    1929         774 :                                     ( fd_landed_vote_t ){ .latency = 0, .lockout = *lockout } );
    1930         774 :   }
    1931             : 
    1932             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1171
    1933          54 :   return process_new_vote_state( vote_state,
    1934          54 :                                  landed_votes,
    1935          54 :                                  vote_state_update->has_root,
    1936          54 :                                  vote_state_update->root,
    1937          54 :                                  vote_state_update->has_timestamp,
    1938          54 :                                  vote_state_update->timestamp,
    1939          54 :                                  epoch,
    1940          54 :                                  slot,
    1941          54 :                                  ctx );
    1942         498 : }
    1943             : 
    1944             : // ??
    1945             : ulong
    1946           0 : fd_query_pubkey_stake( fd_pubkey_t const * pubkey, fd_vote_accounts_t const * vote_accounts ) {
    1947           0 :   fd_vote_accounts_pair_t_mapnode_t key         = { 0 };
    1948           0 :   key.elem.key                                  = *pubkey;
    1949           0 :   fd_vote_accounts_pair_t_mapnode_t * vote_node = fd_vote_accounts_pair_t_map_find(
    1950           0 :       vote_accounts->vote_accounts_pool, vote_accounts->vote_accounts_root, &key );
    1951           0 :   return vote_node ? vote_node->elem.stake : 0;
    1952           0 : }
    1953             : 
    1954             : static int
    1955             : process_vote_state_update( ulong                         vote_acct_idx,
    1956             :                            fd_borrowed_account_t *       vote_account,
    1957             :                            fd_slot_hashes_t const *      slot_hashes,
    1958             :                            fd_sol_sysvar_clock_t const * clock,
    1959             :                            fd_vote_state_update_t *      vote_state_update,
    1960             :                            fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1961        1809 :                            fd_exec_instr_ctx_t const *   ctx /* feature_set */ ) {
    1962        1809 :   int rc;
    1963             : 
    1964             :   // tie in code for fd_bank_hash_cmp that helps us detect if we have forked from the cluster.
    1965             :   //
    1966             :   // There is no corresponding code in anza
    1967        1809 :   if( !deq_fd_vote_lockout_t_empty( vote_state_update->lockouts ) ) {
    1968        1680 :     fd_vote_lockout_t * lockout = deq_fd_vote_lockout_t_peek_tail( vote_state_update->lockouts );
    1969        1680 :     fd_bank_hash_cmp_t * bank_hash_cmp = ctx->slot_ctx->epoch_ctx->bank_hash_cmp;
    1970        1680 :     if( FD_LIKELY( lockout && bank_hash_cmp ) ) {
    1971           0 :       fd_bank_hash_cmp_lock( bank_hash_cmp );
    1972           0 :       fd_bank_hash_cmp_insert(
    1973           0 :         bank_hash_cmp,
    1974           0 :           lockout->slot,
    1975           0 :           &vote_state_update->hash,
    1976           0 :           0,
    1977           0 :           fd_query_pubkey_stake( vote_account->pubkey,
    1978           0 :             &ctx->epoch_ctx->epoch_bank.stakes.vote_accounts ) );
    1979             : 
    1980           0 :       if( FD_LIKELY( vote_state_update->has_root ) ) {
    1981           0 :         fd_bank_hash_cmp_entry_t * cmp =
    1982           0 :           fd_bank_hash_cmp_map_query( bank_hash_cmp->map, vote_state_update->root, NULL );
    1983           0 :         if( FD_LIKELY( cmp ) ) cmp->rooted = 1;
    1984           0 :       }
    1985             : 
    1986           0 :       fd_bank_hash_cmp_unlock( bank_hash_cmp );
    1987           0 :     }
    1988        1680 :   }
    1989             : 
    1990        1809 :   fd_vote_state_t vote_state;
    1991             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1144
    1992        1809 :   rc = verify_and_get_vote_state( vote_account, clock, signers, &vote_state, ctx );
    1993        1809 :   if( FD_UNLIKELY( rc ) ) return rc;
    1994             : 
    1995             : 
    1996             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1145
    1997         498 :   rc = do_process_vote_state_update(
    1998         498 :       &vote_state, slot_hashes, clock->epoch, clock->slot, vote_state_update, ctx );
    1999         498 :   if( FD_UNLIKELY( rc ) ) {
    2000         459 :     return rc;
    2001         459 :   }
    2002             : 
    2003             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1153
    2004          39 :   rc = set_vote_account_state( vote_acct_idx, vote_account, &vote_state, ctx );
    2005             : 
    2006          39 :   return rc;
    2007         498 : }
    2008             : 
    2009             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1206
    2010             : static int
    2011             : do_process_tower_sync( fd_vote_state_t *           vote_state,
    2012             :                        fd_slot_hashes_t const *    slot_hashes,
    2013             :                        ulong                       epoch,
    2014             :                        ulong                       slot,
    2015             :                        fd_tower_sync_t *           tower_sync,
    2016           9 :                        fd_exec_instr_ctx_t const * ctx /* feature_set */ ) {
    2017             : 
    2018           9 :   do {
    2019             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1214
    2020           9 :     int err = check_and_filter_proposed_vote_state(
    2021           9 :         vote_state,
    2022           9 :         tower_sync->lockouts, &tower_sync->has_root, &tower_sync->root, &tower_sync->hash,
    2023           9 :         slot_hashes, ctx );
    2024           9 :     if( FD_UNLIKELY( err ) ) return err;
    2025           9 :   } while(0);
    2026             : 
    2027           3 :   int err;
    2028           3 :   FD_SPAD_FRAME_BEGIN( ctx->txn_ctx->spad ) {
    2029             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1221
    2030           3 :   err = process_new_vote_state(
    2031           3 :       vote_state,
    2032           3 :       landed_votes_from_lockouts( tower_sync->lockouts, fd_spad_virtual( ctx->txn_ctx->spad ) ),
    2033           3 :       tower_sync->has_root,
    2034           3 :       tower_sync->root,
    2035           3 :       tower_sync->has_timestamp,
    2036           3 :       tower_sync->timestamp,
    2037           3 :       epoch,
    2038           3 :       slot,
    2039           3 :       ctx );
    2040           3 :   } FD_SPAD_FRAME_END;
    2041             : 
    2042           3 :   return err;
    2043           9 : }
    2044             : 
    2045             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1186
    2046             : static int
    2047             : process_tower_sync( ulong                         vote_acct_idx,
    2048             :                     fd_borrowed_account_t *       vote_account,
    2049             :                     fd_slot_hashes_t const *      slot_hashes,
    2050             :                     fd_sol_sysvar_clock_t const * clock,
    2051             :                     fd_tower_sync_t *             tower_sync,
    2052             :                     fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    2053          27 :                     fd_exec_instr_ctx_t const *   ctx /* feature_set */ ) {
    2054             : 
    2055          27 :   if( !deq_fd_vote_lockout_t_empty( tower_sync->lockouts ) ) {
    2056          24 :     fd_vote_lockout_t * lockout = deq_fd_vote_lockout_t_peek_tail( tower_sync->lockouts );
    2057          24 :     fd_bank_hash_cmp_t * bank_hash_cmp = ctx->slot_ctx->epoch_ctx->bank_hash_cmp;
    2058          24 :     if( FD_LIKELY( lockout && bank_hash_cmp ) ) {
    2059           0 :       fd_bank_hash_cmp_lock( bank_hash_cmp );
    2060           0 :       fd_bank_hash_cmp_insert(
    2061           0 :         bank_hash_cmp,
    2062           0 :           lockout->slot,
    2063           0 :           &tower_sync->hash,
    2064           0 :           0,
    2065           0 :           fd_query_pubkey_stake( vote_account->pubkey,
    2066           0 :             &ctx->epoch_ctx->epoch_bank.stakes.vote_accounts ) );
    2067             : 
    2068           0 :       if( FD_LIKELY( tower_sync->has_root ) ) {
    2069           0 :         fd_bank_hash_cmp_entry_t * cmp =
    2070           0 :           fd_bank_hash_cmp_map_query( bank_hash_cmp->map, tower_sync->root, NULL );
    2071           0 :         if( FD_LIKELY( cmp ) ) cmp->rooted = 1;
    2072           0 :       }
    2073             : 
    2074           0 :       fd_bank_hash_cmp_unlock( bank_hash_cmp );
    2075           0 :     }
    2076          24 :   }
    2077             : 
    2078             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1194
    2079          27 :   fd_vote_state_t vote_state;
    2080          27 :   do {
    2081          27 :     int err = verify_and_get_vote_state( vote_account, clock, signers, &vote_state, ctx );
    2082          27 :     if( FD_UNLIKELY( err ) ) return err;
    2083          27 :   } while(0);
    2084             : 
    2085             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1195
    2086           9 :   do {
    2087           9 :     int err = do_process_tower_sync( &vote_state, slot_hashes, clock->epoch, clock->slot, tower_sync, ctx );
    2088           9 :     if( FD_UNLIKELY( err ) ) return err;
    2089           9 :   } while(0);
    2090             : 
    2091             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1203
    2092           0 :   return set_vote_account_state( vote_acct_idx, vote_account, &vote_state, ctx );
    2093           9 : }
    2094             : 
    2095             : /**********************************************************************/
    2096             : /* FD-only encoders / decoders (doesn't map directly to Labs impl)    */
    2097             : /**********************************************************************/
    2098             : 
    2099             : int
    2100             : fd_vote_decode_compact_update( fd_compact_vote_state_update_t * compact_update,
    2101             :                                fd_vote_state_update_t *         vote_update,
    2102         402 :                                fd_exec_instr_ctx_t const *      ctx /* spad */ ) {
    2103             :   // Taken from:
    2104             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L954
    2105         402 :   if( compact_update->root != ULONG_MAX ) {
    2106         225 :     vote_update->has_root = 1;
    2107         225 :     vote_update->root     = compact_update->root;
    2108         225 :   } else {
    2109         177 :     vote_update->has_root = 0;
    2110         177 :     vote_update->root     = ULONG_MAX;
    2111         177 :   }
    2112             : 
    2113         402 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    2114             : 
    2115         402 :   ulong lockouts_len = compact_update->lockouts_len;
    2116         402 :   ulong lockouts_max = fd_ulong_max( lockouts_len, MAX_LOCKOUT_HISTORY );
    2117             : 
    2118         402 :   vote_update->lockouts = deq_fd_vote_lockout_t_alloc( valloc, lockouts_max );
    2119         402 :   ulong slot            = fd_ulong_if( vote_update->has_root, vote_update->root, 0 );
    2120             : 
    2121        4752 :   for( ulong i=0; i < lockouts_len; ++i ) {
    2122        4392 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( vote_update->lockouts );
    2123        4392 :     fd_vote_lockout_new( elem );
    2124             : 
    2125        4392 :     fd_lockout_offset_t * lock_offset = &compact_update->lockouts[i];
    2126             : 
    2127        4392 :     ulong next_slot;
    2128        4392 :     if( FD_UNLIKELY( __builtin_uaddl_overflow( slot, lock_offset->offset, &next_slot ) ) )
    2129          42 :       return 0;
    2130             : 
    2131        4350 :     elem->slot = slot        = next_slot;
    2132        4350 :     elem->confirmation_count = (uint)lock_offset->confirmation_count;
    2133        4350 :   }
    2134             : 
    2135         360 :   vote_update->hash          = compact_update->hash;
    2136         360 :   vote_update->has_timestamp = compact_update->has_timestamp;
    2137         360 :   vote_update->timestamp     = compact_update->timestamp;
    2138             : 
    2139         360 :   return 1;
    2140         402 : }
    2141             : 
    2142             : void
    2143             : fd_vote_record_timestamp_vote( fd_exec_slot_ctx_t * slot_ctx,
    2144             :                                fd_pubkey_t const *  vote_acc,
    2145             :                                long                 timestamp,
    2146           0 :                                fd_valloc_t          valloc ) {
    2147           0 :   fd_vote_record_timestamp_vote_with_slot(
    2148           0 :       slot_ctx, vote_acc, timestamp, slot_ctx->slot_bank.slot, valloc );
    2149           0 : }
    2150             : 
    2151             : void
    2152             : fd_vote_record_timestamp_vote_with_slot( fd_exec_slot_ctx_t * slot_ctx,
    2153             :                                          fd_pubkey_t const *  vote_acc,
    2154             :                                          long                 timestamp,
    2155             :                                          ulong                slot,
    2156           0 :                                          fd_valloc_t          valloc ) {
    2157           0 :   fd_clock_timestamp_vote_t_mapnode_t * root = slot_ctx->slot_bank.timestamp_votes.votes_root;
    2158           0 :   fd_clock_timestamp_vote_t_mapnode_t * pool = slot_ctx->slot_bank.timestamp_votes.votes_pool;
    2159           0 :   if( NULL == pool )
    2160           0 :     pool = slot_ctx->slot_bank.timestamp_votes.votes_pool =
    2161           0 :         fd_clock_timestamp_vote_t_map_alloc( valloc, 15000 );
    2162             : 
    2163           0 :   fd_clock_timestamp_vote_t timestamp_vote = {
    2164           0 :       .pubkey    = *vote_acc,
    2165           0 :       .timestamp = (long)timestamp,
    2166           0 :       .slot      = slot,
    2167           0 :   };
    2168           0 :   fd_clock_timestamp_vote_t_mapnode_t   key = { .elem = timestamp_vote };
    2169           0 :   fd_clock_timestamp_vote_t_mapnode_t * node =
    2170           0 :       fd_clock_timestamp_vote_t_map_find( pool, root, &key );
    2171           0 :   if( NULL != node ) {
    2172           0 :     node->elem = timestamp_vote;
    2173           0 :   } else {
    2174           0 :     node = fd_clock_timestamp_vote_t_map_acquire( pool );
    2175           0 :     FD_TEST( node != NULL );
    2176           0 :     node->elem = timestamp_vote;
    2177           0 :     fd_clock_timestamp_vote_t_map_insert( pool, &root, node );
    2178           0 :     slot_ctx->slot_bank.timestamp_votes.votes_root = root;
    2179           0 :   }
    2180           0 : }
    2181             : 
    2182             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L751
    2183             : int
    2184             : fd_vote_acc_credits( fd_exec_instr_ctx_t const * ctx,
    2185             :                      fd_account_meta_t const *   vote_acc_meta,
    2186             :                      uchar const *               vote_acc_data,
    2187           0 :                      ulong *                     result ) {
    2188           0 :   int rc;
    2189             : 
    2190           0 :   fd_valloc_t valloc = fd_spad_virtual( ctx->txn_ctx->spad );
    2191             : 
    2192           0 :   fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
    2193           0 :   if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2194             : 
    2195             :   /* Read vote account */
    2196           0 :   fd_borrowed_account_t vote_account = {
    2197             :       // FIXME call sites
    2198           0 :       .const_meta = vote_acc_meta,
    2199           0 :       .const_data = vote_acc_data,
    2200           0 :   };
    2201             : 
    2202           0 :   rc = 0;
    2203           0 :   fd_vote_state_versioned_t vote_state_versioned;
    2204           0 :   rc = get_state( &vote_account, valloc, &vote_state_versioned );
    2205           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    2206           0 :   convert_to_current( &vote_state_versioned, valloc );
    2207           0 :   fd_vote_state_t * state = &vote_state_versioned.inner.current;
    2208           0 :   if( deq_fd_vote_epoch_credits_t_empty( state->epoch_credits ) ) {
    2209           0 :     *result = 0;
    2210           0 :   } else {
    2211           0 :     *result = deq_fd_vote_epoch_credits_t_peek_tail_const( state->epoch_credits )->credits;
    2212           0 :   }
    2213             : 
    2214           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
    2215           0 : }
    2216             : 
    2217             : /// returns commission split as (voter_portion, staker_portion, was_split) tuple
    2218             : ///
    2219             : ///  if commission calculation is 100% one way or other, indicate with false for was_split
    2220             : 
    2221             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L543
    2222             : void
    2223             : fd_vote_commission_split( fd_vote_state_versioned_t * vote_state_versioned,
    2224             :                           ulong                       on,
    2225           0 :                           fd_commission_split_t *     result ) {
    2226           0 :   uchar * commission = NULL;
    2227           0 :   switch( vote_state_versioned->discriminant ) {
    2228           0 :   case fd_vote_state_versioned_enum_current:
    2229           0 :     commission = &vote_state_versioned->inner.current.commission;
    2230           0 :     break;
    2231           0 :   case fd_vote_state_versioned_enum_v0_23_5:
    2232           0 :     commission = &vote_state_versioned->inner.v0_23_5.commission;
    2233           0 :     break;
    2234           0 :   case fd_vote_state_versioned_enum_v1_14_11:
    2235           0 :     commission = &vote_state_versioned->inner.v1_14_11.commission;
    2236           0 :     break;
    2237           0 :   default:
    2238           0 :     __builtin_unreachable();
    2239           0 :   }
    2240           0 :   uchar deref_commision = *commission;
    2241           0 :   uint commission_split = fd_uint_min( (uint)deref_commision, 100 );
    2242           0 :   result->is_split      = ( commission_split != 0 && commission_split != 100 );
    2243             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L545
    2244           0 :   if( commission_split == 0 ) {
    2245           0 :     result->voter_portion  = 0;
    2246           0 :     result->staker_portion = on;
    2247           0 :     return;
    2248           0 :   }
    2249             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L546
    2250           0 :   if( commission_split == 100 ) {
    2251           0 :     result->voter_portion  = on;
    2252           0 :     result->staker_portion = 0;
    2253           0 :     return;
    2254           0 :   }
    2255             :   /* Note: order of operations may matter for int division. That's why I didn't make the
    2256             :    * optimization of getting out the common calculations */
    2257             : 
    2258             :   // ... This is copied from the solana comments...
    2259             :   //
    2260             :   // Calculate mine and theirs independently and symmetrically instead
    2261             :   // of using the remainder of the other to treat them strictly
    2262             :   // equally. This is also to cancel the rewarding if either of the
    2263             :   // parties should receive only fractional lamports, resulting in not
    2264             :   // being rewarded at all. Thus, note that we intentionally discard
    2265             :   // any residual fractional lamports.
    2266             : 
    2267             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L548
    2268           0 :   result->voter_portion =
    2269           0 :       (ulong)( (uint128)on * (uint128)commission_split / (uint128)100 );
    2270           0 :   result->staker_portion =
    2271           0 :       (ulong)( (uint128)on * (uint128)( 100 - commission_split ) / (uint128)100 );
    2272           0 : }
    2273             : 
    2274             : /**********************************************************************/
    2275             : /* mod vote_processor                                                 */
    2276             : /**********************************************************************/
    2277             : 
    2278             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L21
    2279             : static int
    2280             : process_authorize_with_seed_instruction(
    2281             :     /* invoke_context */
    2282             :     fd_exec_instr_ctx_t const * ctx,
    2283             :     /* transaction_context */
    2284             :     ulong                   vote_acct_idx,
    2285             :     fd_borrowed_account_t * vote_account,
    2286             :     fd_pubkey_t const *     new_authority,
    2287             :     fd_vote_authorize_t     authorization_type,
    2288             :     fd_pubkey_t const *     current_authority_derived_key_owner,
    2289             :     uchar const *           current_authority_derived_key_seed,
    2290         276 :     ulong                   current_authority_derived_key_seed_len ) {
    2291         276 :   int rc = 0;
    2292             : 
    2293             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L31
    2294         276 :   fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 1, &rc );
    2295         276 :   if( FD_UNLIKELY( !clock ) ) return rc;
    2296             : 
    2297         246 :   fd_pubkey_t * expected_authority_keys[FD_TXN_SIG_MAX] = { 0 };
    2298         246 :   fd_pubkey_t   single_signer                        = { 0 };
    2299             : 
    2300         246 :   if( ctx->instr->acct_cnt < 3 )
    2301           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    2302             : 
    2303             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L33
    2304         246 :   if( fd_instr_acc_is_signer_idx( ctx->instr, 2 ) ) {
    2305             : 
    2306             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L35
    2307         180 :     fd_pubkey_t const * base_pubkey = &ctx->instr->acct_pubkeys[2];
    2308             : 
    2309             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L37
    2310         180 :     expected_authority_keys[0] = &single_signer;
    2311         180 :     rc = fd_pubkey_create_with_seed( ctx,
    2312         180 :                                      base_pubkey->uc,
    2313         180 :                                      (char const *)current_authority_derived_key_seed,
    2314         180 :                                      current_authority_derived_key_seed_len,
    2315         180 :                                      current_authority_derived_key_owner->uc,
    2316         180 :                                      /* insert */ expected_authority_keys[0]->uc );
    2317         180 :     if( FD_UNLIKELY( rc ) ) return rc;
    2318         180 :   }
    2319             : 
    2320             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L43
    2321         234 :   return authorize( vote_acct_idx,
    2322         234 :                     vote_account,
    2323         234 :                     new_authority,
    2324         234 :                     authorization_type,
    2325         234 :                     (fd_pubkey_t const **)expected_authority_keys,
    2326         234 :                     clock,
    2327         234 :                     ctx );
    2328         246 : }
    2329             : 
    2330             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_versions.rs#L90
    2331             : static uint
    2332           0 : vote_state_versions_is_correct_and_initialized( fd_borrowed_account_t * vote_account ) {
    2333             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L885
    2334           0 :   uint data_len_check = vote_account->const_meta->dlen == FD_VOTE_STATE_V3_SZ;
    2335           0 :   uchar test_data[DEFAULT_PRIOR_VOTERS_OFFSET] = {0};
    2336           0 :   uint data_check = memcmp((
    2337           0 :     (uchar*)vote_account->const_data + VERSION_OFFSET), test_data, DEFAULT_PRIOR_VOTERS_OFFSET) != 0;
    2338           0 :   if (data_check && data_len_check) {
    2339           0 :     return 1;
    2340           0 :   }
    2341             : 
    2342             :   // VoteState1_14_11::is_correct_size_and_initialized
    2343             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L58
    2344           0 :   data_len_check = vote_account->const_meta->dlen == FD_VOTE_STATE_V2_SZ;
    2345           0 :   uchar test_data_1_14_11[DEFAULT_PRIOR_VOTERS_OFFSET_1_14_11] = {0};
    2346           0 :   data_check = memcmp(
    2347           0 :     ((uchar*)vote_account->const_data + VERSION_OFFSET), test_data_1_14_11, DEFAULT_PRIOR_VOTERS_OFFSET_1_14_11) != 0;
    2348           0 :   return data_check && data_len_check;
    2349           0 : }
    2350             : 
    2351             : /**********************************************************************/
    2352             : /* Entry point for the Vote Program                                   */
    2353             : /**********************************************************************/
    2354             : 
    2355             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L57
    2356             : int
    2357       23919 : fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) {
    2358             :   /* FD-specific init */
    2359       23919 :   int rc = FD_EXECUTOR_INSTR_SUCCESS;
    2360             : 
    2361             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L57
    2362       23919 :   FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS );
    2363             : 
    2364             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L64
    2365       19407 :   if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) ) {
    2366         366 :     return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    2367         366 :   }
    2368             : 
    2369       19041 :   fd_borrowed_account_t * me = NULL;
    2370       19041 :   rc                         = fd_instr_borrowed_account_view_idx( ctx, 0, &me );
    2371             : 
    2372       19041 :   switch( rc ) {
    2373       19041 :   case FD_ACC_MGR_SUCCESS:
    2374       19041 :     break;
    2375           0 :   case FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT:
    2376             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L637
    2377           0 :     return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    2378           0 :   default:
    2379             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L639
    2380           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED;
    2381       19041 :   }
    2382             : 
    2383             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L65
    2384       19041 :   if( FD_UNLIKELY( 0 != memcmp( &me->const_meta->info.owner,
    2385       19041 :                                 fd_solana_vote_program_id.key,
    2386       19041 :                                 sizeof( fd_pubkey_t ) ) ) ) {
    2387             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L66
    2388        5364 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
    2389        5364 :   }
    2390             : 
    2391             :   /* Replicate vote account changes to bank caches after processing the
    2392             :      transaction's instructions. */
    2393       13677 :   ctx->txn_ctx->dirty_vote_acc = 1;
    2394             : 
    2395             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L69
    2396       13677 :   fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = { 0 };
    2397       13677 :   fd_instr_get_signers( ctx->instr, signers );
    2398             : 
    2399             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L70
    2400       13677 :   if( FD_UNLIKELY( ctx->instr->data==NULL ) ) {
    2401          21 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2402          21 :   }
    2403       13656 :   fd_vote_instruction_t   instruction;
    2404       13656 :   fd_bincode_decode_ctx_t decode = {
    2405       13656 :       .data    = ctx->instr->data,
    2406       13656 :       .dataend = ctx->instr->data + ctx->instr->data_sz,
    2407       13656 :       .valloc  = fd_spad_virtual( ctx->txn_ctx->spad )
    2408       13656 :   };
    2409       13656 :   int decode_result = fd_vote_instruction_decode( &instruction, &decode );
    2410       13656 :   if( decode_result != FD_BINCODE_SUCCESS ||
    2411       13656 :       (ulong)ctx->instr->data + 1232UL < (ulong)decode.data )
    2412        3822 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2413             : 
    2414             :   /* PLEASE PRESERVE SWITCH-CASE ORDERING TO MIRROR LABS IMPL:
    2415             :    */
    2416        9834 :   switch( instruction.discriminant ) {
    2417             : 
    2418             :   /* InitializeAccount
    2419             :    *
    2420             :    * Instruction:
    2421             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L32
    2422             :    *
    2423             :    * Processor:
    2424             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L71
    2425             :    */
    2426         279 :   case fd_vote_instruction_enum_initialize_account: {
    2427             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L72
    2428         279 :     fd_rent_t const * rent = fd_sysvar_from_instr_acct_rent( ctx, 1UL, &rc );
    2429         279 :     if( FD_UNLIKELY( !rent ) ) return rc;
    2430             : 
    2431         252 :     if( FD_UNLIKELY( me->const_meta->info.lamports <
    2432         252 :                      fd_rent_exempt_minimum_balance( rent, me->const_meta->dlen ) ) )
    2433           6 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    2434             : 
    2435             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L76
    2436         246 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 2, &rc );
    2437         246 :     if( !clock ) return rc;
    2438             : 
    2439             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L78
    2440         225 :     rc = initialize_account( 0, me, &instruction.inner.initialize_account, signers, clock, ctx );
    2441             : 
    2442         225 :     break;
    2443         246 :   }
    2444             : 
    2445             :   /* Authorize
    2446             :    *
    2447             :    * Instruction:
    2448             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L40
    2449             :    *
    2450             :    * Processor:
    2451             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L86
    2452             :    *
    2453             :    * Notes:
    2454             :    * - Up to two signers: the vote authority and the authorized withdrawer.
    2455             :    */
    2456        1257 :   case fd_vote_instruction_enum_authorize: {
    2457             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L87
    2458        1257 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 1, &rc );
    2459        1257 :     if( !clock ) return rc;
    2460             : 
    2461             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L89
    2462        1236 :     fd_pubkey_t const * voter_pubkey   = &instruction.inner.authorize.pubkey;
    2463        1236 :     fd_vote_authorize_t vote_authorize = instruction.inner.authorize.vote_authorize;
    2464             : 
    2465        1236 :     rc = authorize( 0, me, voter_pubkey, vote_authorize, signers, clock, ctx );
    2466             : 
    2467        1236 :     break;
    2468        1257 :   }
    2469             : 
    2470             :   /* AuthorizeWithSeed
    2471             :    *
    2472             :    * Instruction:
    2473             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L117
    2474             :    *
    2475             :    * Processor:
    2476             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L98
    2477             :    */
    2478         228 :   case fd_vote_instruction_enum_authorize_with_seed: {
    2479             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L99
    2480         228 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 3 ) ) {
    2481           9 :       rc = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    2482           9 :       break;
    2483           9 :     }
    2484             : 
    2485             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L100
    2486         219 :     fd_vote_authorize_with_seed_args_t * args = &instruction.inner.authorize_with_seed;
    2487             : 
    2488         219 :     rc = process_authorize_with_seed_instruction( ctx,
    2489         219 :                                                   0, me,
    2490         219 :                                                   &args->new_authority,
    2491         219 :                                                   args->authorization_type,
    2492         219 :                                                   &args->current_authority_derived_key_owner,
    2493         219 :                                                   args->current_authority_derived_key_seed,
    2494         219 :                                                   args->current_authority_derived_key_seed_len );
    2495             : 
    2496         219 :     break;
    2497         228 :   }
    2498             : 
    2499             :   /* AuthorizeCheckedWithSeed
    2500             :    *
    2501             :    * Instruction:
    2502             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L131
    2503             :    *
    2504             :    * Processor:
    2505             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L111
    2506             :    */
    2507         114 :   case fd_vote_instruction_enum_authorize_checked_with_seed: {
    2508         114 :     fd_vote_authorize_checked_with_seed_args_t const * args =
    2509         114 :         &instruction.inner.authorize_checked_with_seed;
    2510             : 
    2511             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L112
    2512         114 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 4 ) ) {
    2513           9 :       rc = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    2514           9 :       break;
    2515           9 :     }
    2516             : 
    2517             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L116
    2518         105 :     fd_pubkey_t const * new_authority = &ctx->instr->acct_pubkeys[3];
    2519             : 
    2520         105 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, 3 ) ) ) {
    2521             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L117
    2522          48 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    2523          48 :       break;
    2524          48 :     }
    2525             : 
    2526             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L119
    2527          57 :     rc = process_authorize_with_seed_instruction( ctx,
    2528          57 :                                                   0, me,
    2529          57 :                                                   new_authority,
    2530          57 :                                                   args->authorization_type,
    2531          57 :                                                   &args->current_authority_derived_key_owner,
    2532          57 :                                                   args->current_authority_derived_key_seed,
    2533          57 :                                                   args->current_authority_derived_key_seed_len );
    2534             : 
    2535          57 :     break;
    2536         105 :   }
    2537             : 
    2538             :   /* UpdateValidatorIdentity
    2539             :    *
    2540             :    * Instruction:
    2541             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L65
    2542             :    *
    2543             :    * Processor:
    2544             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L130
    2545             :    */
    2546        1323 :   case fd_vote_instruction_enum_update_validator_identity: {
    2547             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L131
    2548        1323 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) ) {
    2549           3 :       rc = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    2550           3 :       break;
    2551           3 :     }
    2552             : 
    2553             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L132
    2554        1320 :     fd_pubkey_t const * node_pubkey = &ctx->instr->acct_pubkeys[1];
    2555             : 
    2556             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L135
    2557        1320 :     rc = update_validator_identity( 0, me, node_pubkey, signers, ctx );
    2558             : 
    2559        1320 :     break;
    2560        1323 :   }
    2561             : 
    2562             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L142
    2563        1401 :   case fd_vote_instruction_enum_update_commission: {
    2564             : 
    2565             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L149
    2566        1401 :     fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_cache_epoch_schedule( ctx->slot_ctx->sysvar_cache );
    2567        1401 :     if( FD_UNLIKELY( !epoch_schedule ) )
    2568           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2569             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L150
    2570        1401 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
    2571        1401 :     if( FD_UNLIKELY( !clock ) )
    2572           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2573             : 
    2574             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L145
    2575        1401 :     rc = update_commission( 0, me, instruction.inner.update_commission, signers, epoch_schedule, clock, ctx );
    2576             : 
    2577        1401 :     break;
    2578        1401 :   }
    2579             : 
    2580             :   /* Vote
    2581             :    *
    2582             :    * Instruction:
    2583             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L49
    2584             :    */
    2585         666 :   case fd_vote_instruction_enum_vote:;
    2586             :     /* clang-format off */
    2587         666 :     __attribute__((fallthrough));
    2588             :     /* clang-format on */
    2589             : 
    2590             :   /* VoteSwitch
    2591             :    *
    2592             :    * Instruction:
    2593             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L81
    2594             :    *
    2595             :    * Processor:
    2596             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L154
    2597             :    */
    2598        1305 :   case fd_vote_instruction_enum_vote_switch: {
    2599        1305 :     if( FD_FEATURE_ACTIVE( ctx->slot_ctx, deprecate_legacy_vote_ixs ) &&
    2600        1305 :         FD_FEATURE_ACTIVE( ctx->slot_ctx, enable_tower_sync_ix ) ) {
    2601           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2602           0 :     }
    2603             : 
    2604        1305 :     fd_vote_t * vote;
    2605        1305 :     if( instruction.discriminant == fd_vote_instruction_enum_vote ) {
    2606         666 :       vote = &instruction.inner.vote;
    2607         666 :     } else if( instruction.discriminant == fd_vote_instruction_enum_vote_switch ) {
    2608         639 :       vote = &instruction.inner.vote_switch.vote;
    2609         639 :     } else {
    2610           0 :       __builtin_unreachable();
    2611           0 :     }
    2612             : 
    2613             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L155
    2614        1305 :     int err;
    2615        1305 :     fd_slot_hashes_t const * slot_hashes = fd_sysvar_from_instr_acct_slot_hashes( ctx, 1, &err );
    2616        1305 :     if( FD_UNLIKELY( !slot_hashes ) ) return err;
    2617             : 
    2618             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L157
    2619        1170 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 2, &err );
    2620        1170 :     if( FD_UNLIKELY( !clock ) ) return err;
    2621             : 
    2622        1158 :     rc = process_vote_with_account( 0, me, slot_hashes, clock, vote, signers, ctx );
    2623             : 
    2624        1158 :     break;
    2625        1170 :   }
    2626             : 
    2627             :   /* UpdateVoteState
    2628             :    *
    2629             :    * Instruction:
    2630             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L100
    2631             :    */
    2632         831 :   case fd_vote_instruction_enum_update_vote_state:;
    2633             :     /* clang-format off */
    2634         831 :     __attribute__((fallthrough));
    2635             :     /* clang-format on */
    2636             : 
    2637             :   /* UpdateVoteStateSwitch
    2638             :    *
    2639             :    * Instruction:
    2640             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L107
    2641             :    *
    2642             :    * Processor:
    2643             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L169
    2644             :    */
    2645        1566 :   case fd_vote_instruction_enum_update_vote_state_switch: {
    2646        1566 :     if( FD_FEATURE_ACTIVE( ctx->slot_ctx, deprecate_legacy_vote_ixs ) &&
    2647        1566 :         FD_FEATURE_ACTIVE( ctx->slot_ctx, enable_tower_sync_ix ) ) {
    2648           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2649           0 :     }
    2650             : 
    2651        1566 :     fd_vote_state_update_t * vote_state_update;
    2652        1566 :     switch( instruction.discriminant ) {
    2653         831 :     case fd_vote_instruction_enum_update_vote_state:
    2654         831 :       vote_state_update = &instruction.inner.update_vote_state;
    2655         831 :       break;
    2656         735 :     case fd_vote_instruction_enum_update_vote_state_switch:
    2657         735 :       vote_state_update = &instruction.inner.update_vote_state_switch.vote_state_update;
    2658         735 :       break;
    2659           0 :     default:
    2660           0 :       __builtin_unreachable();
    2661        1566 :     }
    2662             : 
    2663             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L171
    2664        1566 :     fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes( ctx->slot_ctx->sysvar_cache );
    2665        1566 :     if( FD_UNLIKELY( !slot_hashes ) )
    2666          60 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2667             : 
    2668             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L172
    2669        1506 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
    2670        1506 :     if( FD_UNLIKELY( !clock ) )
    2671           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2672             : 
    2673             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L173
    2674        1506 :     rc = process_vote_state_update( 0, me, slot_hashes, clock, vote_state_update, signers, ctx );
    2675             : 
    2676        1506 :     break;
    2677        1506 :   }
    2678             : 
    2679             :   /* CompactUpdateVoteState
    2680             :    *
    2681             :    * Instruction:
    2682             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L139
    2683             :    *
    2684             :    * Notes:
    2685             :    * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
    2686             :    * - Feature gated, but live on mainnet.
    2687             :    */
    2688         240 :   case fd_vote_instruction_enum_compact_update_vote_state:;
    2689         240 :     __attribute__((fallthrough));
    2690             : 
    2691             :   /* CompactUpdateVoteStateSwitch
    2692             :    *
    2693             :    * Instruction:
    2694             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L146
    2695             :    *
    2696             :    * Processor:
    2697             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L183
    2698             :    *
    2699             :    * Notes:
    2700             :    * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
    2701             :    * - Feature gated, but live on mainnet.
    2702             :    */
    2703         402 :   case fd_vote_instruction_enum_compact_update_vote_state_switch: {
    2704             :     /* https://github.com/anza-xyz/agave/blob/dc4b9dcbbf859ff48f40d00db824bde063fdafcc/programs/vote/src/vote_processor.rs#L183-L191 */
    2705         402 :     if( FD_FEATURE_ACTIVE( ctx->slot_ctx, deprecate_legacy_vote_ixs ) &&
    2706         402 :         FD_FEATURE_ACTIVE( ctx->slot_ctx, enable_tower_sync_ix ) ) {
    2707           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2708           0 :     }
    2709             : 
    2710         402 :     fd_compact_vote_state_update_t * vote_state_update = NULL;
    2711         402 :     if( instruction.discriminant == fd_vote_instruction_enum_compact_update_vote_state ) {
    2712         240 :       vote_state_update = &instruction.inner.compact_update_vote_state;
    2713         240 :     } else if( instruction.discriminant ==
    2714         162 :                fd_vote_instruction_enum_compact_update_vote_state_switch ) {
    2715         162 :       vote_state_update =
    2716         162 :           &instruction.inner.compact_update_vote_state_switch.compact_vote_state_update;
    2717         162 :     }
    2718             : 
    2719         402 :     fd_vote_state_update_t vote_update;
    2720         402 :     fd_vote_state_update_new( &vote_update );
    2721         402 :     if( FD_UNLIKELY( !fd_vote_decode_compact_update( vote_state_update, &vote_update, ctx ) ) )
    2722          42 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2723             : 
    2724             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L185
    2725         360 :     fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes( ctx->slot_ctx->sysvar_cache );
    2726         360 :     if( FD_UNLIKELY( !slot_hashes ) )
    2727          57 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2728             : 
    2729         303 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
    2730         303 :     if( FD_UNLIKELY( !clock ) )
    2731           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2732             : 
    2733             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L187
    2734         303 :     rc = process_vote_state_update( 0, me, slot_hashes, clock, &vote_update, signers, ctx );
    2735             : 
    2736         303 :     break;
    2737         303 :   }
    2738             : 
    2739             :   /* TowerSync(Switch)
    2740             :    *
    2741             :    * Instruction:
    2742             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L151-L157
    2743             :    *
    2744             :    * Processor:
    2745             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L196-L215
    2746             :    */
    2747             : 
    2748         105 :   case fd_vote_instruction_enum_tower_sync:
    2749         165 :   case fd_vote_instruction_enum_tower_sync_switch: {
    2750         165 :     if( !FD_FEATURE_ACTIVE( ctx->slot_ctx, enable_tower_sync_ix ) ) {
    2751         132 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2752         132 :     }
    2753             : 
    2754          33 :     fd_tower_sync_t * tower_sync = (instruction.discriminant == fd_vote_instruction_enum_tower_sync)
    2755          33 :         ? &instruction.inner.tower_sync
    2756          33 :         : &instruction.inner.tower_sync_switch.tower_sync;
    2757             : 
    2758          33 :     fd_slot_hashes_t const *      slot_hashes = fd_sysvar_cache_slot_hashes( ctx->slot_ctx->sysvar_cache );
    2759          33 :     fd_sol_sysvar_clock_t const * clock       = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
    2760          33 :     if( FD_UNLIKELY( !slot_hashes || !clock ) ) {
    2761           6 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2762           6 :     }
    2763             : 
    2764          27 :     rc = process_tower_sync( 0, me, slot_hashes, clock, tower_sync, signers, ctx );
    2765          27 :     break;
    2766          33 :   }
    2767             : 
    2768             :   /* Withdraw
    2769             :    *
    2770             :    * Instruction:
    2771             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L57
    2772             :    *
    2773             :    * Processor:
    2774             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L216
    2775             :    */
    2776         906 :   case fd_vote_instruction_enum_withdraw: {
    2777         906 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) ) {
    2778           3 :       rc = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    2779           3 :       break;
    2780           3 :     }
    2781         903 :     fd_rent_t const * rent_sysvar = fd_sysvar_cache_rent( ctx->slot_ctx->sysvar_cache );
    2782         903 :     if( FD_UNLIKELY( !rent_sysvar ) )
    2783           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2784         903 :     fd_sol_sysvar_clock_t const * clock_sysvar = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
    2785         903 :     if( FD_UNLIKELY( !clock_sysvar ) )
    2786           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2787             : 
    2788         903 :     rc = withdraw( ctx, 0, me, instruction.inner.withdraw, 1, signers, rent_sysvar, clock_sysvar );
    2789             : 
    2790         903 :     break;
    2791         903 :   }
    2792             : 
    2793             :   /* AuthorizeChecked
    2794             :    *
    2795             :    * Instruction:
    2796             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L93
    2797             :    *
    2798             :    * Processor:
    2799             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L234
    2800             :    *
    2801             :    * Notes:
    2802             :    * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
    2803             :    * - Feature gated, but live on mainnet.
    2804             :    */
    2805         888 :   case fd_vote_instruction_enum_authorize_checked: {
    2806         888 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 4 ) ) {
    2807          18 :       rc = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
    2808          18 :       break;
    2809          18 :     }
    2810             : 
    2811             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L236
    2812         870 :     fd_pubkey_t const * voter_pubkey = &ctx->instr->acct_pubkeys[3];
    2813             : 
    2814             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L239
    2815         870 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, 3 ) ) ) {
    2816         330 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    2817         330 :       break;
    2818         330 :     }
    2819             : 
    2820             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L242
    2821         540 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 1, &rc );
    2822         540 :     if( FD_UNLIKELY( !clock ) ) return rc;
    2823             : 
    2824         462 :     rc = authorize( 0, me, voter_pubkey, instruction.inner.authorize_checked, signers, clock, ctx );
    2825         462 :     break;
    2826         540 :   }
    2827             : 
    2828           0 :   default:
    2829           0 :     FD_LOG_ERR(( "unsupported vote instruction: %u", instruction.discriminant ));
    2830        9834 :   }
    2831             : 
    2832        9237 :   return rc;
    2833        9834 : }
    2834             : 
    2835             : /**********************************************************************/
    2836             : /* Public API                                                         */
    2837             : /**********************************************************************/
    2838             : 
    2839             : int
    2840             : fd_vote_get_state( fd_borrowed_account_t const * self,
    2841             :                    fd_valloc_t                   valloc,
    2842        2961 :                    fd_vote_state_versioned_t *   versioned /* out */ ) {
    2843        2961 :   return get_state( self, valloc, versioned );
    2844        2961 : }
    2845             : 
    2846             : void
    2847             : fd_vote_convert_to_current( fd_vote_state_versioned_t * self,
    2848        1848 :                             fd_valloc_t                 valloc ) {
    2849        1848 :   convert_to_current( self, valloc );
    2850        1848 : }
    2851             : 
    2852             : static void
    2853           0 : remove_vote_account( fd_exec_slot_ctx_t * slot_ctx, fd_borrowed_account_t * vote_account ) {
    2854           0 :   fd_vote_accounts_pair_t_mapnode_t key;
    2855           0 :   fd_memcpy( key.elem.key.uc, vote_account->pubkey->uc, sizeof(fd_pubkey_t) );
    2856             : 
    2857           0 :   fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
    2858           0 :   fd_vote_accounts_t * epoch_vote_accounts = &epoch_bank->stakes.vote_accounts;
    2859           0 :   if (epoch_vote_accounts->vote_accounts_pool == NULL) {
    2860           0 :     FD_LOG_DEBUG(("Vote accounts pool does not exist"));
    2861           0 :     return;
    2862           0 :   }
    2863           0 :   fd_vote_accounts_pair_t_mapnode_t * entry = fd_vote_accounts_pair_t_map_find(epoch_vote_accounts->vote_accounts_pool, epoch_vote_accounts->vote_accounts_root, &key);
    2864           0 :   if (FD_LIKELY( entry )) {
    2865           0 :     fd_vote_accounts_pair_t_map_remove( epoch_vote_accounts->vote_accounts_pool, &epoch_vote_accounts->vote_accounts_root, entry);
    2866           0 :   }
    2867             : 
    2868           0 :   if (slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool == NULL) {
    2869           0 :     FD_LOG_DEBUG(("Vote accounts pool does not exist"));
    2870           0 :     return;
    2871           0 :   }
    2872           0 :   entry = fd_vote_accounts_pair_t_map_find(slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, slot_ctx->slot_bank.vote_account_keys.vote_accounts_root, &key);
    2873           0 :   if (FD_UNLIKELY( entry )) {
    2874           0 :     fd_vote_accounts_pair_t_map_remove( slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, &slot_ctx->slot_bank.vote_account_keys.vote_accounts_root, entry);
    2875           0 :   }
    2876           0 : }
    2877             : 
    2878             : static void
    2879             : upsert_vote_account( fd_exec_slot_ctx_t *    slot_ctx,
    2880             :                      fd_borrowed_account_t * vote_account,
    2881           0 :                      fd_spad_t *             spad ) {
    2882           0 :   FD_SPAD_FRAME_BEGIN( spad ) {
    2883             : 
    2884           0 :     fd_bincode_decode_ctx_t decode = {
    2885           0 :       .data    = vote_account->const_data,
    2886           0 :       .dataend = vote_account->const_data + vote_account->const_meta->dlen,
    2887           0 :       .valloc  = fd_spad_virtual( spad ),
    2888           0 :     };
    2889           0 :     fd_bincode_destroy_ctx_t destroy = {
    2890           0 :       .valloc = fd_spad_virtual( spad ),
    2891           0 :     };
    2892           0 :     fd_vote_state_versioned_t vote_state[1] = {0};
    2893           0 :     if( FD_UNLIKELY( 0!=fd_vote_state_versioned_decode( vote_state, &decode ) ) ) {
    2894           0 :       remove_vote_account( slot_ctx, vote_account );
    2895           0 :       fd_vote_state_versioned_destroy( vote_state, &destroy );
    2896           0 :       return;
    2897           0 :     }
    2898             : 
    2899           0 :     if ( vote_state_versions_is_correct_and_initialized( vote_account ) ) {
    2900           0 :       fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
    2901           0 :       fd_stakes_t * stakes = &epoch_bank->stakes;
    2902             : 
    2903           0 :       fd_vote_accounts_pair_t_mapnode_t key;
    2904           0 :       fd_memcpy(&key.elem.key, vote_account->pubkey->uc, sizeof(fd_pubkey_t));
    2905           0 :       if (stakes->vote_accounts.vote_accounts_pool == NULL) {
    2906           0 :         FD_LOG_DEBUG(("Vote accounts pool does not exist"));
    2907           0 :         fd_vote_state_versioned_destroy( vote_state, &destroy );
    2908           0 :         return;
    2909           0 :       }
    2910           0 :       fd_vote_accounts_pair_t_mapnode_t * entry = fd_vote_accounts_pair_t_map_find( stakes->vote_accounts.vote_accounts_pool, stakes->vote_accounts.vote_accounts_root, &key);
    2911           0 :       if ( FD_UNLIKELY( !entry ) ) {
    2912           0 :         if (slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool == NULL) {
    2913           0 :           FD_LOG_DEBUG(("Vote accounts pool does not exist"));
    2914           0 :           return;
    2915           0 :         }
    2916           0 :         fd_vote_accounts_pair_t_mapnode_t * existing = fd_vote_accounts_pair_t_map_find( slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, slot_ctx->slot_bank.vote_account_keys.vote_accounts_root, &key );
    2917           0 :         if ( !existing ) {
    2918           0 :           fd_vote_accounts_pair_t_mapnode_t * new_node = fd_vote_accounts_pair_t_map_acquire( slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool );
    2919           0 :           if (!new_node) {
    2920           0 :             FD_LOG_ERR(("Map full"));
    2921           0 :           }
    2922             : 
    2923           0 :           fd_vote_block_timestamp_t last_timestamp;
    2924           0 :           fd_pubkey_t node_pubkey;
    2925             : 
    2926           0 :           switch( vote_state->discriminant ) {
    2927           0 :             case fd_vote_state_versioned_enum_current:
    2928           0 :               last_timestamp = vote_state->inner.current.last_timestamp;
    2929           0 :               node_pubkey    = vote_state->inner.current.node_pubkey;
    2930           0 :               break;
    2931           0 :             case fd_vote_state_versioned_enum_v0_23_5:
    2932           0 :               last_timestamp = vote_state->inner.v0_23_5.last_timestamp;
    2933           0 :               node_pubkey    = vote_state->inner.v0_23_5.node_pubkey;
    2934           0 :               break;
    2935           0 :             case fd_vote_state_versioned_enum_v1_14_11:
    2936           0 :               last_timestamp = vote_state->inner.v1_14_11.last_timestamp;
    2937           0 :               node_pubkey    = vote_state->inner.v1_14_11.node_pubkey;
    2938           0 :               break;
    2939           0 :             default:
    2940           0 :               __builtin_unreachable();
    2941           0 :           }
    2942             : 
    2943           0 :           fd_memcpy( &new_node->elem.key, vote_account->pubkey, sizeof(fd_pubkey_t));
    2944           0 :           new_node->elem.value.lamports = vote_account->const_meta->info.lamports;
    2945             : 
    2946           0 :           fd_memcpy(new_node->elem.value.node_pubkey.uc, node_pubkey.uc, sizeof(fd_pubkey_t));
    2947           0 :           new_node->elem.value.last_timestamp_ts   = last_timestamp.timestamp;
    2948           0 :           new_node->elem.value.last_timestamp_slot = last_timestamp.slot;
    2949             : 
    2950           0 :           fd_memcpy( &new_node->elem.value.owner, vote_account->const_meta->info.owner, sizeof(fd_pubkey_t) );
    2951           0 :           new_node->elem.value.executable = (uchar)vote_account->const_meta->info.executable;
    2952           0 :           new_node->elem.value.rent_epoch = vote_account->const_meta->info.rent_epoch;
    2953           0 :           new_node->elem.stake            = 0UL;
    2954           0 :           fd_vote_accounts_pair_t_map_insert( slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, &slot_ctx->slot_bank.vote_account_keys.vote_accounts_root, new_node );
    2955           0 :         } else {
    2956           0 :           existing->elem.value.lamports = vote_account->const_meta->info.lamports;
    2957           0 :         }
    2958           0 :       } else {
    2959           0 :         entry->elem.value.lamports = vote_account->const_meta->info.lamports;
    2960           0 :       }
    2961           0 :     } else {
    2962           0 :       remove_vote_account( slot_ctx, vote_account );
    2963           0 :     }
    2964             : 
    2965           0 :     fd_vote_state_versioned_destroy( vote_state, &destroy );
    2966           0 :   } FD_SPAD_FRAME_END;
    2967           0 : }
    2968             : 
    2969             : void
    2970             : fd_vote_store_account( fd_exec_slot_ctx_t *    slot_ctx,
    2971             :                        fd_borrowed_account_t * vote_account,
    2972           0 :                        fd_spad_t *             spad ) {
    2973           0 :   fd_pubkey_t const * owner = (fd_pubkey_t const *)vote_account->const_meta->info.owner;
    2974             : 
    2975           0 :   if (memcmp(owner->uc, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t)) != 0) {
    2976           0 :       return;
    2977           0 :   }
    2978           0 :   if (vote_account->const_meta->info.lamports == 0) {
    2979           0 :     remove_vote_account( slot_ctx, vote_account );
    2980           0 :   } else {
    2981           0 :     upsert_vote_account( slot_ctx, vote_account, spad );
    2982           0 :   }
    2983           0 : }

Generated by: LCOV version 1.14