LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_vote_program.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 1753 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 64 0.0 %

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

Generated by: LCOV version 1.14