LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_vote_program.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 112 1419 7.9 %
Date: 2026-03-16 06:26:59 Functions: 4 28 14.3 %

          Line data    Source code
       1             : #include "fd_vote_program.h"
       2             : #include "../fd_runtime.h"
       3             : #include "../fd_borrowed_account.h"
       4             : #include "../fd_executor.h"
       5             : #include "../fd_pubkey_utils.h"
       6             : #include "../sysvar/fd_sysvar_rent.h"
       7             : #include "../sysvar/fd_sysvar.h"
       8             : #include "../fd_system_ids.h"
       9             : #include "vote/fd_authorized_voters.h"
      10             : #include "vote/fd_vote_common.h"
      11             : #include "vote/fd_vote_lockout.h"
      12             : #include "vote/fd_vote_state_versioned.h"
      13             : #include "vote/fd_vote_state_v3.h"
      14             : #include "vote/fd_vote_state_v4.h"
      15             : #include "../../../ballet/bls/fd_bls12_381.h"
      16             : 
      17             : #include <limits.h>
      18             : #include <math.h>
      19             : #include <stdio.h>
      20             : #include <string.h>
      21             : 
      22             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L36
      23           0 : #define INITIAL_LOCKOUT 2UL
      24             : 
      25             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L51
      26             : #define VOTE_CREDITS_MAXIMUM_PER_SLOT_OLD 8
      27             : 
      28             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/clock.rs#L147
      29             : #define SLOT_DEFAULT 0UL
      30             : 
      31             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/clock.rs#L147
      32             : #define SLOT_MAX ULONG_MAX
      33             : 
      34             : #define ACCOUNTS_MAX 4 /* Vote instructions take in at most 4 accounts */
      35             : 
      36             : #define DEFAULT_COMPUTE_UNITS 2100UL
      37             : #define COMPUTE_UNITS_POP    34500UL
      38             : 
      39             : /**********************************************************************/
      40             : /* VoteStateHandler                                                   */
      41             : /**********************************************************************/
      42             : 
      43             : /* This is a temporary method in Agave (until the vote state v4 feature
      44             :    is cleaned up) to check the vote state and, in some cases, check
      45             :    if the vote account is uninitialized or not. Initializes a v3 or v4
      46             :    vote account depending on the target version.
      47             :    https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L45-L77 */
      48             : static int
      49             : get_vote_state_handler_checked( fd_borrowed_account_t const * vote_account,
      50             :                                 int                           target_version,
      51             :                                 uchar                         check_initialized,
      52             :                                 uchar *                       vote_state_mem,
      53           0 :                                 uchar *                       landed_votes_mem ) {
      54           0 :   int rc;
      55           0 :   switch( target_version ) {
      56             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L50-L62 */
      57           0 :     case VOTE_STATE_TARGET_VERSION_V3: {
      58           0 :       rc = fd_vote_state_v3_deserialize( vote_account, vote_state_mem, landed_votes_mem );
      59           0 :       if( FD_UNLIKELY( rc ) ) return rc;
      60             : 
      61           0 :       fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)vote_state_mem;
      62           0 :       if( FD_UNLIKELY( check_initialized && fd_vsv_is_uninitialized( versioned ) ) ) {
      63           0 :         return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
      64           0 :       }
      65             : 
      66           0 :       return FD_EXECUTOR_INSTR_SUCCESS;
      67           0 :     }
      68             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L63-L75 */
      69           0 :     case VOTE_STATE_TARGET_VERSION_V4: {
      70           0 :       rc = fd_vsv_deserialize( vote_account->meta, vote_state_mem );
      71           0 :       if( FD_UNLIKELY( rc ) ) return rc;
      72             : 
      73           0 :       fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)vote_state_mem;
      74           0 :       if( FD_UNLIKELY( fd_vsv_is_uninitialized( versioned ) ) ) {
      75           0 :         return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
      76           0 :       }
      77             : 
      78           0 :       rc = fd_vsv_try_convert_to_v4( versioned, vote_account->pubkey, landed_votes_mem );
      79           0 :       if( FD_UNLIKELY( rc ) ) return rc;
      80             : 
      81           0 :       return FD_EXECUTOR_INSTR_SUCCESS;
      82           0 :     }
      83           0 :     default:
      84           0 :       FD_LOG_CRIT(( "unsupported version: %d", target_version ));
      85           0 :   }
      86           0 : }
      87             : 
      88             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L888-L902 */
      89             : static int
      90             : check_vote_account_length( fd_borrowed_account_t const * vote_account,
      91           6 :                            int                           target_version ) {
      92           6 :   ulong length = fd_borrowed_account_get_data_len( vote_account );
      93           6 :   ulong expected;
      94           6 :   switch( target_version ) {
      95           3 :     case VOTE_STATE_TARGET_VERSION_V3:
      96           3 :       expected = FD_VOTE_STATE_V3_SZ;
      97           3 :       break;
      98           3 :     case VOTE_STATE_TARGET_VERSION_V4:
      99           3 :       expected = FD_VOTE_STATE_V4_SZ;
     100           3 :       break;
     101           0 :     default:
     102           0 :       FD_LOG_CRIT(( "unsupported version: %d", target_version ));
     103           6 :   }
     104           6 :   if( FD_UNLIKELY( length!=expected ) ) {
     105           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     106           0 :   }
     107           6 :   return FD_EXECUTOR_INSTR_SUCCESS;
     108           6 : }
     109             : 
     110             : /* The versioned parameter must point to a buffer that is aligned to
     111             :    FD_VOTE_STATE_VERSIONED_ALIGN and is at least
     112             :    FD_VOTE_STATE_VERSIONED_FOOTPRINT bytes in size.
     113             :    https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L855-L870 */
     114             : static int
     115             : init_vote_account_state( fd_exec_instr_ctx_t *         ctx,
     116             :                          fd_borrowed_account_t *       vote_account,
     117             :                          fd_vote_state_versioned_t *   versioned,
     118             :                          int                           target_version,
     119             :                          fd_vote_init_t *              vote_init,
     120           6 :                          fd_sol_sysvar_clock_t const * clock ) {
     121             :   /* Reset the object */
     122           6 :   fd_vote_state_versioned_new( versioned );
     123             : 
     124           6 :   switch( target_version ) {
     125           3 :     case VOTE_STATE_TARGET_VERSION_V3:
     126           3 :       fd_vote_program_v3_create_new(
     127           3 :           vote_init,
     128           3 :           clock,
     129           3 :           ctx->runtime->vote_program.init_account.authorized_voters_mem,
     130           3 :           versioned
     131           3 :       );
     132           3 :       return fd_vote_state_v3_set_vote_account_state(
     133           3 :           ctx,
     134           3 :           vote_account,
     135           3 :           versioned,
     136           3 :           ctx->runtime->vote_program.init_account.vote_lockout_mem
     137           3 :       );
     138           3 :     case VOTE_STATE_TARGET_VERSION_V4:
     139           3 :       fd_vote_state_v4_create_new_with_defaults(
     140           3 :           vote_account->pubkey,
     141           3 :           vote_init,
     142           3 :           clock,
     143           3 :           ctx->runtime->vote_program.init_account.authorized_voters_mem,
     144           3 :           versioned
     145           3 :       );
     146           3 :       return fd_vote_state_v4_set_vote_account_state( ctx, vote_account, versioned );
     147           0 :     default:
     148           0 :       FD_LOG_CRIT(( "unsupported version: %d", target_version ));
     149           6 :   }
     150           6 : }
     151             : 
     152             : /* The versioned parameter must point to a buffer that is aligned to
     153             :    https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L965-L983 */
     154             : static int
     155             : init_vote_account_state_v2( fd_exec_instr_ctx_t *         ctx,
     156             :                             fd_borrowed_account_t *       vote_account,
     157             :                             fd_vote_state_versioned_t *   versioned,
     158             :                             int                           target_version,
     159             :                             fd_vote_init_v2_t *           vote_init_v2,
     160           0 :                             fd_sol_sysvar_clock_t const * clock ) {
     161             :   /* Reset the object */
     162           0 :   fd_vote_state_versioned_new( versioned );
     163             : 
     164           0 :   switch( target_version ) {
     165           0 :     case VOTE_STATE_TARGET_VERSION_V3:
     166           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     167             : 
     168           0 :     case VOTE_STATE_TARGET_VERSION_V4:
     169           0 :       fd_vote_state_v4_create_new(
     170           0 :           vote_init_v2,
     171           0 :           clock,
     172           0 :           ctx->runtime->vote_program.init_account.authorized_voters_mem,
     173           0 :           versioned
     174           0 :       );
     175           0 :       return fd_vote_state_v4_set_vote_account_state( ctx, vote_account, versioned );
     176           0 :     default:
     177           0 :       FD_LOG_CRIT(( "unsupported version: %d", target_version ));
     178           0 :   }
     179           0 : }
     180             : 
     181             : /**********************************************************************/
     182             : /* mod vote_state                                                    */
     183             : /**********************************************************************/
     184             : 
     185             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L82-L324 */
     186             : static int
     187             : check_and_filter_proposed_vote_state( fd_exec_instr_ctx_t *       ctx,
     188             :                                       fd_vote_state_versioned_t * versioned,
     189             :                                       fd_vote_lockout_t *         proposed_lockouts,
     190             :                                       uchar *                     proposed_has_root,
     191             :                                       ulong *                     proposed_root,
     192             :                                       fd_hash_t const *           proposed_hash,
     193           0 :                                       fd_slot_hash_t const *      slot_hashes /* deque */ ) {
     194           0 :   fd_landed_vote_t const * votes         = fd_vsv_get_votes( versioned );
     195           0 :   ulong const *            root_slot     = fd_vsv_get_root_slot( versioned );
     196           0 :   uchar                    has_root_slot = !!(root_slot!=NULL);
     197             : 
     198             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L208
     199           0 :   if( FD_UNLIKELY( deq_fd_vote_lockout_t_empty( proposed_lockouts ) ) ) {
     200           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
     201           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     202           0 :   }
     203           0 :   fd_landed_vote_t const * last_vote = NULL;
     204           0 :   if( !deq_fd_landed_vote_t_empty( votes ) ) {
     205             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L212
     206           0 :     last_vote = deq_fd_landed_vote_t_peek_tail_const( votes );
     207           0 :   }
     208             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L218
     209           0 :   if( FD_LIKELY( last_vote ) ) {
     210           0 :     if( FD_UNLIKELY( deq_fd_vote_lockout_t_peek_tail_const( proposed_lockouts )->slot <=
     211           0 :                      last_vote->lockout.slot ) ) {
     212           0 :       ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTE_TOO_OLD;
     213           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     214           0 :     }
     215           0 :   }
     216             : 
     217             :   /* must be nonempty, checked above */
     218           0 :   ulong last_vote_state_update_slot = deq_fd_vote_lockout_t_peek_tail_const( proposed_lockouts )->slot;
     219             : 
     220             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L224
     221           0 :   if( FD_UNLIKELY( deq_fd_slot_hash_t_empty( slot_hashes ) ) ) {
     222           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
     223           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     224           0 :   }
     225             : 
     226             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L227
     227           0 :   ulong earliest_slot_hash_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes )->slot;
     228             : 
     229             :   /* Check if the proposed vote is too old to be in the SlotHash history */
     230             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L230
     231           0 :   if( FD_UNLIKELY( last_vote_state_update_slot < earliest_slot_hash_in_history ) ) {
     232           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTE_TOO_OLD;
     233           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     234           0 :   }
     235             : 
     236             :   /* Check if the proposed root is too old */
     237             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L237
     238           0 :   if( *proposed_has_root ) {
     239           0 :     ulong const proposed_root_ = *proposed_root;
     240             :     /* If the new proposed root `R` is less than the earliest slot hash in the history
     241             :        such that we cannot verify whether the slot was actually was on this fork, set
     242             :        the root to the latest vote in the current vote that's less than R. */
     243             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L242
     244           0 :     if( proposed_root_ < earliest_slot_hash_in_history ) {
     245           0 :       *proposed_has_root = has_root_slot;
     246           0 :       if( has_root_slot ) {
     247           0 :         *proposed_root   = *root_slot;
     248           0 :       }
     249           0 :       for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init_rev( votes );
     250           0 :                                              !deq_fd_landed_vote_t_iter_done_rev( votes, iter );
     251           0 :                                        iter = deq_fd_landed_vote_t_iter_prev( votes, iter ) ) {
     252             :         /* Ensure we're iterating from biggest to smallest vote in the
     253             :            current vote state */
     254           0 :         fd_landed_vote_t const * vote = deq_fd_landed_vote_t_iter_ele_const( votes, iter );
     255             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L248
     256           0 :         if( vote->lockout.slot <= proposed_root_ ) {
     257           0 :           *proposed_has_root = 1;
     258           0 :           *proposed_root     = vote->lockout.slot;
     259           0 :           break;
     260           0 :         }
     261           0 :       }
     262           0 :     }
     263           0 :   }
     264             : 
     265             :   /* Index into the new proposed vote state's slots, starting with the root if it exists then
     266             :      we use this mutable root to fold checking the root slot into the below loop for performance */
     267           0 :   int   has_root_to_check       = *proposed_has_root;
     268             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L259
     269           0 :   ulong root_to_check           = *proposed_root;
     270           0 :   ulong proposed_lockouts_index = 0UL;
     271           0 :   ulong lockouts_len = deq_fd_vote_lockout_t_cnt( proposed_lockouts );
     272             : 
     273             :   /* Index into the slot_hashes, starting at the oldest known slot hash */
     274             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L264
     275           0 :   ulong slot_hashes_index = deq_fd_slot_hash_t_cnt( slot_hashes );
     276             : 
     277             :   /* proposed_lockouts_indexes_to_filter's size is bounded by the length
     278             :      of the proposed lockouts provided in the instruction data, which is
     279             :      capped at roughly 10KB / sizeof(ulong). */
     280           0 :   ulong proposed_lockouts_indexes_to_filter[ FD_INSTR_DATA_MAX/sizeof(ulong) ];
     281           0 :   ulong filter_index = 0UL;
     282             : 
     283             :   /* Note:
     284             : 
     285             :     1) `vote_state_update.lockouts` is sorted from oldest/smallest vote to newest/largest
     286             :     vote, due to the way votes are applied to the vote state (newest votes
     287             :     pushed to the back).
     288             : 
     289             :     2) Conversely, `slot_hashes` is sorted from newest/largest vote to
     290             :     the oldest/smallest vote.
     291             : 
     292             :     Unlike for vote updates, vote state updates here can't only check votes older than the last vote
     293             :     because have to ensure that every slot is actually part of the history, not just the most
     294             :     recent ones */
     295             : 
     296             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L279
     297           0 :   while( proposed_lockouts_index < lockouts_len && slot_hashes_index > 0 ) {
     298           0 :     ulong proposed_vote_slot =
     299           0 :       fd_ulong_if( has_root_to_check,
     300             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L281
     301           0 :         root_to_check,
     302             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L283
     303           0 :         deq_fd_vote_lockout_t_peek_index_const( proposed_lockouts,
     304           0 :           proposed_lockouts_index )
     305           0 :         ->slot );
     306             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L285
     307           0 :     if( !has_root_to_check && proposed_lockouts_index > 0UL &&
     308           0 :       proposed_vote_slot <=
     309           0 :       deq_fd_vote_lockout_t_peek_index_const(
     310           0 :         proposed_lockouts,
     311           0 :           fd_ulong_checked_sub_expect(
     312           0 :             proposed_lockouts_index,
     313           0 :               1,
     314           0 :               "`proposed_lockouts_index` is positive when checking `SlotsNotOrdered`" ) )
     315           0 :       ->slot ) {
     316             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L293
     317           0 :       ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_NOT_ORDERED;
     318           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     319           0 :     }
     320             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L295
     321           0 :     ulong ancestor_slot =
     322           0 :       deq_fd_slot_hash_t_peek_index_const(
     323           0 :         slot_hashes,
     324           0 :           fd_ulong_checked_sub_expect(
     325           0 :             slot_hashes_index,
     326           0 :               1UL,
     327           0 :               "`slot_hashes_index` is positive when computing `ancestor_slot`" ) )
     328           0 :       ->slot;
     329             :     /* Find if this slot in the proposed vote state exists in the SlotHashes history
     330             :        to confirm if it was a valid ancestor on this fork */
     331             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L303
     332           0 :     if( proposed_vote_slot < ancestor_slot ) {
     333           0 :       if( slot_hashes_index == deq_fd_slot_hash_t_cnt( slot_hashes ) ) {
     334             :         /* The vote slot does not exist in the SlotHashes history because it's too old,
     335             :            i.e. older than the oldest slot in the history. */
     336           0 :         if( proposed_vote_slot >= earliest_slot_hash_in_history ) {
     337           0 :           ctx->txn_out->err.custom_err = 0;
     338           0 :           return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     339           0 :         }
     340             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L310
     341           0 :         if( !fd_vote_contains_slot( votes, proposed_vote_slot ) && !has_root_to_check ) {
     342             :           /* If the vote slot is both:
     343             :              1) Too old
     344             :              2) Doesn't already exist in vote state
     345             :              Then filter it out */
     346           0 :           proposed_lockouts_indexes_to_filter[filter_index++] = proposed_lockouts_index;        }
     347             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L318
     348           0 :         if( has_root_to_check ) {
     349           0 :           ulong new_proposed_root = root_to_check;
     350             :           /* 1. Because `root_to_check.is_some()`, then we know that
     351             :              we haven't checked the root yet in this loop, so
     352             :              `proposed_vote_slot` == `new_proposed_root` == `vote_state_update.root` */
     353           0 :           FD_TEST( new_proposed_root == proposed_vote_slot );
     354             :           /* 2. We know from the assert earlier in the function that
     355             :              `proposed_vote_slot < earliest_slot_hash_in_history`,
     356             :              so from 1. we know that `new_proposed_root < earliest_slot_hash_in_history` */
     357           0 :           if( new_proposed_root >= earliest_slot_hash_in_history ) {
     358           0 :             ctx->txn_out->err.custom_err = 0;
     359           0 :             return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     360           0 :           }
     361             : 
     362             :           // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L329
     363           0 :           has_root_to_check = 0;
     364           0 :           root_to_check     = ULONG_MAX;
     365           0 :         } else {
     366             :           // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L331
     367           0 :           proposed_lockouts_index = fd_ulong_checked_add_expect(
     368           0 :             proposed_lockouts_index,
     369           0 :               1,
     370           0 :               "`proposed_lockouts_index` is bounded by `MAX_LOCKOUT_HISTORY` when "
     371           0 :               "`proposed_vote_slot` is too old to be in SlotHashes history" );
     372           0 :         }
     373           0 :         continue;
     374           0 :       } else {
     375             :         /* If the vote slot is new enough to be in the slot history,
     376             :            but is not part of the slot history, then it must belong to another fork,
     377             :            which means this vote state update is invalid. */
     378             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L340
     379           0 :         if( has_root_to_check ) {
     380           0 :           ctx->txn_out->err.custom_err = FD_VOTE_ERR_ROOT_ON_DIFFERENT_FORK;
     381           0 :           return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     382           0 :         } else {
     383           0 :           ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
     384           0 :           return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     385           0 :         }
     386           0 :       }
     387           0 :     } else if( proposed_vote_slot > ancestor_slot ) {
     388             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L347
     389             : 
     390             :       /* Decrement `slot_hashes_index` to find newer slots in the SlotHashes history */
     391           0 :       slot_hashes_index = fd_ulong_checked_sub_expect(
     392           0 :         slot_hashes_index,
     393           0 :           1,
     394           0 :           "`slot_hashes_index` is positive when finding newer slots in SlotHashes history" );
     395           0 :       continue;
     396           0 :     } else {
     397             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L354
     398             : 
     399             :       /* Once the slot in `vote_state_update.lockouts` is found, bump to the next slot
     400             :          in `vote_state_update.lockouts` and continue. If we were checking the root,
     401             :          start checking the vote state instead. */
     402           0 :       if( has_root_to_check ) {
     403           0 :         has_root_to_check = 0;
     404           0 :         root_to_check     = ULONG_MAX;
     405           0 :       } else {
     406           0 :         proposed_lockouts_index = fd_ulong_checked_add_expect(
     407           0 :           proposed_lockouts_index,
     408           0 :             1,
     409           0 :             "`proposed_lockouts_index` is bounded by `MAX_LOCKOUT_HISTORY` "
     410           0 :             "when match is found in SlotHashes history" );
     411           0 :         slot_hashes_index = fd_ulong_checked_sub_expect(
     412           0 :           slot_hashes_index,
     413           0 :             1,
     414           0 :             "`slot_hashes_index` is positive when match is found in SlotHashes history" );
     415           0 :       }
     416           0 :     }
     417           0 :   }
     418             : 
     419             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L372
     420           0 :   if( proposed_lockouts_index != deq_fd_vote_lockout_t_cnt( proposed_lockouts ) ) {
     421             :     /* The last vote slot in the update did not exist in SlotHashes */
     422           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
     423           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     424           0 :   }
     425             : 
     426             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L401
     427           0 :   if( memcmp( &deq_fd_slot_hash_t_peek_index_const( slot_hashes, slot_hashes_index )->hash,
     428           0 :       proposed_hash,
     429           0 :       sizeof( fd_hash_t ) ) != 0 ) {
     430             :     /* This means the newest vote in the slot has a match that
     431             :        doesn't match the expected hash for that slot on this fork */
     432           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_HASH_MISMATCH;
     433           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     434           0 :   }
     435             : 
     436             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L418
     437             :   /* Filter out the irrelevant votes */
     438           0 :   proposed_lockouts_index = 0UL;
     439           0 :   ulong filter_votes_index = deq_fd_vote_lockout_t_cnt( proposed_lockouts );
     440             : 
     441             :   /* We need to iterate backwards here because proposed_lockouts_indexes_to_filter[ i ] is a
     442             :      strictly increasing value. Forward iterating can lead to the proposed lockout indicies to get
     443             :      shifted leading to popping the wrong proposed lockouts or out of bounds accessing. We need
     444             :      to be sure of handling underflow in this case. */
     445             : 
     446           0 :   for( ulong i=filter_index; i>0UL && filter_votes_index>0UL; i-- ) {
     447           0 :     proposed_lockouts_index = i - 1UL;
     448           0 :     if( FD_UNLIKELY( proposed_lockouts_indexes_to_filter[ proposed_lockouts_index ]>=filter_votes_index ) ) {
     449           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
     450           0 :     }
     451             : 
     452           0 :     deq_fd_vote_lockout_t_pop_idx_tail( proposed_lockouts, proposed_lockouts_indexes_to_filter[ proposed_lockouts_index ] );
     453           0 :     filter_votes_index--;
     454           0 :   }
     455             : 
     456           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     457           0 : }
     458             : 
     459             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L440
     460             : static int
     461             : check_slots_are_valid( fd_exec_instr_ctx_t *       ctx,
     462             :                        fd_vote_state_versioned_t * versioned,
     463             :                        ulong const *               vote_slots,
     464             :                        fd_hash_t const *           vote_hash,
     465           0 :                        fd_slot_hash_t const *      slot_hashes /* deque */ ) {
     466           0 :   ulong i              = 0;
     467           0 :   ulong j              = deq_fd_slot_hash_t_cnt( slot_hashes );
     468           0 :   ulong vote_slots_len = deq_ulong_cnt( vote_slots );
     469             : 
     470             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L462
     471           0 :   while( i < vote_slots_len && j > 0 ) {
     472           0 :     ulong const * last_voted_slot_ = fd_vsv_get_last_voted_slot( versioned );
     473           0 :     if( FD_UNLIKELY( last_voted_slot_ &&
     474           0 :                      *deq_ulong_peek_index_const( vote_slots, i ) <= *last_voted_slot_ ) ) {
     475             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L469
     476           0 :       i = fd_ulong_checked_add_expect(
     477           0 :           i, 1, "`i` is bounded by `MAX_LOCKOUT_HISTORY` when finding larger slots" );
     478           0 :       continue;
     479           0 :     }
     480             : 
     481             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L476
     482           0 :     if( FD_UNLIKELY(
     483           0 :             *deq_ulong_peek_index_const( vote_slots, i ) !=
     484           0 :             deq_fd_slot_hash_t_peek_index_const( slot_hashes,
     485           0 :               fd_ulong_checked_sub_expect( j, 1, "`j` is positive" ) )
     486           0 :                 ->slot ) ) {
     487           0 :       j = fd_ulong_checked_sub_expect( j, 1, "`j` is positive when finding newer slots" );
     488           0 :       continue;
     489           0 :     }
     490             : 
     491             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L486
     492           0 :     i = fd_ulong_checked_add_expect(
     493           0 :         i, 1, "`i` is bounded by `MAX_LOCKOUT_HISTORY` when hash is found" );
     494           0 :     j = fd_ulong_checked_sub_expect( j, 1, "`j` is positive when hash is found" );
     495           0 :   }
     496             : 
     497             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L494
     498           0 :   if( FD_UNLIKELY( j == deq_fd_slot_hash_t_cnt( slot_hashes ) ) ) {
     499           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTE_TOO_OLD;
     500           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     501           0 :   }
     502           0 :   if( FD_UNLIKELY( i != vote_slots_len ) ) {
     503           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
     504           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     505           0 :   }
     506             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L514
     507           0 :   if( FD_UNLIKELY( 0 != memcmp( &deq_fd_slot_hash_t_peek_index_const( slot_hashes, j )->hash,
     508           0 :                                 vote_hash,
     509           0 :                                 32UL ) ) ) {
     510           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_HASH_MISMATCH;
     511           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     512           0 :   }
     513           0 :   return 0;
     514           0 : }
     515             : 
     516             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L565
     517             : static int
     518             : process_new_vote_state( fd_exec_instr_ctx_t *       ctx,
     519             :                         fd_vote_state_versioned_t * versioned,
     520             :                         fd_landed_vote_t *          new_state,
     521             :                         int                         has_new_root,
     522             :                         ulong                       new_root,
     523             :                         int                         has_timestamp,
     524             :                         long                        timestamp,
     525             :                         ulong                       epoch,
     526           0 :                         ulong                       current_slot ) {
     527           0 :   int rc;
     528           0 :   fd_landed_vote_t * votes         = fd_vsv_get_votes_mutable( versioned );
     529           0 :   ulong const *      root_slot     = fd_vsv_get_root_slot( versioned );
     530           0 :   uchar              has_root_slot = !!(root_slot!=NULL);
     531             : 
     532           0 :   FD_TEST( !deq_fd_landed_vote_t_empty( new_state ) );
     533             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L575
     534           0 :   if( FD_UNLIKELY( deq_fd_landed_vote_t_cnt( new_state ) > MAX_LOCKOUT_HISTORY ) ) {
     535           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_TOO_MANY_VOTES;
     536           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     537           0 :   };
     538             : 
     539             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L579
     540           0 :   if( FD_UNLIKELY( has_new_root && has_root_slot ) ) {
     541             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L581
     542           0 :     if( FD_UNLIKELY( new_root<*root_slot ) ) {
     543           0 :       ctx->txn_out->err.custom_err = FD_VOTE_ERR_ROOT_ROLL_BACK;
     544           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     545           0 :     }
     546           0 :   } else if( FD_UNLIKELY( !has_new_root && has_root_slot ) ) {
     547             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L586
     548           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_ROOT_ROLL_BACK;
     549           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     550           0 :   } else {
     551             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L588
     552             :     /* no-op */
     553           0 :   }
     554             : 
     555           0 :   fd_landed_vote_t * previous_vote = NULL;
     556           0 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
     557           0 :        !deq_fd_landed_vote_t_iter_done( new_state, iter );
     558           0 :        iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
     559           0 :     fd_landed_vote_t * vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
     560           0 :     if( FD_LIKELY( vote->lockout.confirmation_count == 0 ) ) {
     561           0 :       ctx->txn_out->err.custom_err = FD_VOTE_ERR_ZERO_CONFIRMATIONS;
     562           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     563           0 :     } else if( FD_UNLIKELY( vote->lockout.confirmation_count > MAX_LOCKOUT_HISTORY ) ) {
     564           0 :       ctx->txn_out->err.custom_err = FD_VOTE_ERR_CONFIRMATION_TOO_LARGE;
     565           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     566           0 :     } else if( FD_LIKELY( has_new_root ) ) {
     567           0 :       if( FD_UNLIKELY( vote->lockout.slot <= new_root && new_root != SLOT_DEFAULT ) ) {
     568           0 :         ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOT_SMALLER_THAN_ROOT;
     569           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     570           0 :       }
     571           0 :     }
     572             : 
     573           0 :     if( FD_LIKELY( previous_vote ) ) {
     574           0 :       if( FD_UNLIKELY( previous_vote->lockout.slot >= vote->lockout.slot ) ) {
     575           0 :         ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_NOT_ORDERED;
     576           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     577           0 :       } else if( FD_UNLIKELY( previous_vote->lockout.confirmation_count <=
     578           0 :                               vote->lockout.confirmation_count ) ) {
     579           0 :         ctx->txn_out->err.custom_err = FD_VOTE_ERR_CONFIRMATIONS_NOT_ORDERED;
     580           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     581           0 :       } else if( FD_UNLIKELY( vote->lockout.slot >
     582           0 :                               fd_vote_lockout_last_locked_out_slot( &previous_vote->lockout ) ) ) {
     583           0 :         ctx->txn_out->err.custom_err = FD_VOTE_ERR_NEW_VOTE_STATE_LOCKOUT_MISMATCH;
     584           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     585           0 :       }
     586           0 :     }
     587           0 :     previous_vote = vote;
     588           0 :   }
     589             : 
     590           0 :   ulong current_vote_state_index = 0;
     591           0 :   ulong new_vote_state_index     = 0;
     592             : 
     593             :   /* Accumulate credits earned by newly rooted slots.  The behavior changes with
     594             :      timely_vote_credits: prior to this feature, there was a bug that counted a new root slot as 1
     595             :      credit even if it had never been voted on. timely_vote_credits fixes this bug by only awarding
     596             :      credits for slots actually voted on and finalized. */
     597             : 
     598             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L635
     599             : 
     600             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L641
     601           0 :   ulong earned_credits      = 0;
     602             : 
     603           0 :   if( FD_LIKELY( has_new_root ) ) {
     604           0 :     for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( votes );
     605           0 :                                            !deq_fd_landed_vote_t_iter_done( votes, iter );
     606           0 :                                      iter = deq_fd_landed_vote_t_iter_next( votes, iter ) ) {
     607           0 :       fd_landed_vote_t const * current_vote = deq_fd_landed_vote_t_iter_ele_const( votes, iter );
     608             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L647
     609           0 :       if( FD_UNLIKELY( current_vote->lockout.slot <= new_root ) ) {
     610             :         // this is safe because we're inside if has_new_root
     611           0 :         earned_credits = fd_ulong_checked_add_expect(
     612           0 :             fd_vote_credits_for_vote_at_index(
     613           0 :                 votes,
     614           0 :                 current_vote_state_index
     615           0 :             ),
     616           0 :             earned_credits,
     617           0 :             "`earned_credits` does not overflow" );
     618           0 :         current_vote_state_index = fd_ulong_checked_add_expect(
     619           0 :             current_vote_state_index,
     620           0 :             1,
     621           0 :             "`current_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
     622           0 :             "when processing new root" );
     623           0 :         continue;
     624           0 :       }
     625           0 :       break;
     626           0 :     }
     627           0 :   }
     628             : 
     629             :   // For any slots newly added to the new vote state, the vote latency of that slot is not provided by the
     630             :   // vote instruction contents, but instead is computed from the actual latency of the vote
     631             :   // instruction. This prevents other validators from manipulating their own vote latencies within their vote states
     632             :   // and forcing the rest of the cluster to accept these possibly fraudulent latency values.  If the
     633             :   // timly_vote_credits feature is not enabled then vote latency is set to 0 for new votes.
     634             :   //
     635             :   // For any slot that is in both the new state and the current state, the vote latency of the new state is taken
     636             :   // from the current state.
     637             :   //
     638             :   // Thus vote latencies are set here for any newly vote-on slots when a vote instruction is received.
     639             :   // They are copied into the new vote state after every vote for already voted-on slots.
     640             :   // And when voted-on slots are rooted, the vote latencies stored in the vote state of all the rooted slots is used
     641             :   // to compute credits earned.
     642             :   // All validators compute the same vote latencies because all process the same vote instruction at the
     643             :   // same slot, and the only time vote latencies are ever computed is at the time that their slot is first voted on;
     644             :   // after that, the latencies are retained unaltered until the slot is rooted.
     645             : 
     646             :   // All the votes in our current vote state that are missing from the new vote state
     647             :   // must have been expired by later votes. Check that the lockouts match this assumption.
     648             : 
     649             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L686
     650           0 :   while( current_vote_state_index < deq_fd_landed_vote_t_cnt( votes ) &&
     651           0 :          new_vote_state_index < deq_fd_landed_vote_t_cnt( new_state ) ) {
     652           0 :     fd_landed_vote_t const * current_vote = deq_fd_landed_vote_t_peek_index_const( votes, current_vote_state_index );
     653             : 
     654             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L690
     655           0 :     fd_landed_vote_t * new_vote =
     656           0 :         deq_fd_landed_vote_t_peek_index( new_state, new_vote_state_index );
     657             : 
     658             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L696
     659           0 :     if( FD_LIKELY( current_vote->lockout.slot < new_vote->lockout.slot ) ) {
     660             :       /* The agave implementation of calculating the last locked out
     661             :          slot does not calculate a min between the current vote's
     662             :          confirmation count and max lockout history. The reason we do
     663             :          this is to make sure that the fuzzers continue working:
     664             :          the max lockout history can not be > MAX_LOCKOUT_HISTORY. */
     665           0 :       ulong confirmation_count   = fd_ulong_min( current_vote->lockout.confirmation_count, MAX_LOCKOUT_HISTORY );
     666           0 :       ulong last_locked_out_slot = fd_ulong_sat_add( current_vote->lockout.slot,
     667           0 :                                                      (ulong)pow( INITIAL_LOCKOUT, (double)confirmation_count ) );
     668             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L697
     669           0 :       if( last_locked_out_slot >= new_vote->lockout.slot ) {
     670             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L698
     671           0 :         ctx->txn_out->err.custom_err = FD_VOTE_ERR_LOCKOUT_CONFLICT;
     672           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     673           0 :       }
     674             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L700
     675           0 :       current_vote_state_index =
     676           0 :           fd_ulong_checked_add_expect( current_vote_state_index,
     677           0 :                                        1,
     678           0 :                                        "`current_vote_state_index` is bounded by "
     679           0 :                                        "`MAX_LOCKOUT_HISTORY` when slot is less than proposed" );
     680             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L704
     681           0 :     } else if( FD_UNLIKELY( current_vote->lockout.slot == new_vote->lockout.slot ) ) {
     682             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L707
     683           0 :       if( new_vote->lockout.confirmation_count < current_vote->lockout.confirmation_count ) {
     684           0 :         ctx->txn_out->err.custom_err = FD_VOTE_ERR_CONFIRMATION_ROLL_BACK;
     685           0 :         return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     686           0 :       }
     687             : 
     688             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L712
     689           0 :       new_vote->latency = deq_fd_landed_vote_t_peek_index_const( votes, current_vote_state_index )->latency;
     690             : 
     691             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L714
     692           0 :       current_vote_state_index =
     693           0 :           fd_ulong_checked_add_expect( current_vote_state_index,
     694           0 :                                        1,
     695           0 :                                        "`current_vote_state_index` is bounded by "
     696           0 :                                        "`MAX_LOCKOUT_HISTORY` when slot is equal to proposed" );
     697             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L717
     698           0 :       new_vote_state_index =
     699           0 :           fd_ulong_checked_add_expect( new_vote_state_index,
     700           0 :                                        1,
     701           0 :                                        "`new_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
     702           0 :                                        "when slot is equal to proposed" );
     703           0 :     } else {
     704             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L722
     705           0 :       new_vote_state_index =
     706           0 :           fd_ulong_checked_add_expect( new_vote_state_index,
     707           0 :                                        1,
     708           0 :                                        "`new_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
     709           0 :                                        "when slot is greater than proposed" );
     710           0 :     }
     711           0 :   }
     712             : 
     713             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L737
     714           0 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
     715           0 :         !deq_fd_landed_vote_t_iter_done( new_state, iter );
     716           0 :         iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
     717           0 :     fd_landed_vote_t * new_vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
     718             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L738
     719           0 :     if( FD_UNLIKELY( new_vote->latency == 0 ) ) {
     720             :       // this is unlikely because as validators upgrade, it should converge to the new vote state
     721             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L739
     722           0 :       new_vote->latency = fd_vote_compute_vote_latency( new_vote->lockout.slot, current_slot );
     723           0 :     }
     724           0 :   }
     725             : 
     726             :   // doesn't matter what the value of slot if `is_some = 0` i.e. `Option::None`
     727             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L744
     728           0 :   int both_none = !has_root_slot && !has_new_root;
     729           0 :   if( ( !both_none && ( has_root_slot!=has_new_root ||
     730           0 :                         *root_slot!=new_root ) ) ) {
     731           0 :     fd_vsv_increment_credits( versioned, epoch, earned_credits );
     732           0 :   }
     733             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L750
     734           0 :   if( FD_LIKELY( has_timestamp ) ) {
     735             :     /* new_state asserted nonempty at function beginning */
     736           0 :     if( FD_UNLIKELY( deq_fd_landed_vote_t_empty( new_state ) ) ) {
     737           0 :       FD_LOG_CRIT(( "invariant violation: landed votes is empty" ));
     738           0 :     }
     739           0 :     ulong last_slot = deq_fd_landed_vote_t_peek_tail( new_state )->lockout.slot;
     740           0 :     rc              = fd_vsv_process_timestamp( ctx, versioned, last_slot, timestamp );
     741           0 :     if( FD_UNLIKELY( rc ) ) { return rc; }
     742           0 :   }
     743             : 
     744             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L754
     745           0 :   fd_vsv_set_root_slot( versioned, has_new_root ? &new_root : NULL );
     746             : 
     747             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L755
     748           0 :   deq_fd_landed_vote_t_remove_all( votes );
     749           0 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
     750           0 :        !deq_fd_landed_vote_t_iter_done( new_state, iter );
     751           0 :        iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
     752           0 :     fd_landed_vote_t * landed_vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
     753           0 :     deq_fd_landed_vote_t_push_tail_wrap( votes, *landed_vote );
     754           0 :   }
     755             : 
     756           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     757           0 : }
     758             : 
     759             : __attribute__((weak)) int
     760             : fd_bls12_381_proof_of_possession_verify( uchar const msg[],
     761             :                                          ulong       msg_sz,
     762             :                                          uchar const proof[ 96 ],
     763           0 :                                          uchar const public_key[ 48 ] ) {
     764           0 :   (void)msg; (void)msg_sz; (void)proof; (void)public_key;
     765           0 :   FD_LOG_ERR(( "This build does not include BLST, which is required to run a validator.\n"
     766           0 :                "To install BLST, re-run ./deps.sh, make distclean, and make -j" ));
     767           0 : }
     768             : 
     769             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1059-L1108 */
     770             : #define FD_VOTE_BLS_MSG_SZ ( 9 + 32 + 48 )
     771             : static int
     772             : fd_vote_verify_bls_proof_of_possession( fd_exec_instr_ctx_t * ctx,
     773             :                                         uchar const           vote_account_pubkey[ 32 ],
     774             :                                         uchar const           bls_pubkey[ 48 ],
     775           0 :                                         uchar const           bls_proof[ 96 ] ) {
     776             :   /* Consume CUs for proof of possession */
     777           0 :   FD_EXEC_CU_UPDATE( ctx, COMPUTE_UNITS_POP );
     778             : 
     779             :   /* Build message */
     780           0 :   uchar msg[ FD_VOTE_BLS_MSG_SZ ];
     781           0 :   memcpy( msg, "ALPENGLOW", 9 );
     782           0 :   memcpy( msg+9, vote_account_pubkey, 32 );
     783           0 :   memcpy( msg+9+32, bls_pubkey, 48 );
     784             : 
     785             :   /* Verify */
     786           0 :   if( FD_UNLIKELY( fd_bls12_381_proof_of_possession_verify(
     787           0 :     msg,
     788           0 :     FD_VOTE_BLS_MSG_SZ,
     789           0 :     bls_proof,
     790           0 :     bls_pubkey
     791           0 :   )!=FD_BLS_SUCCESS ) ) {
     792           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     793           0 :   }
     794           0 :   return 0;
     795           0 : }
     796             : #undef FD_VOTE_BLS_MSG_SZ
     797             : 
     798             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L716-L759 */
     799             : static int
     800             : authorize( fd_exec_instr_ctx_t *         ctx,
     801             :            fd_borrowed_account_t *       vote_account,
     802             :            int                           target_version,
     803             :            fd_pubkey_t const *           authorized,
     804             :            fd_vote_authorize_t           vote_authorize,
     805             :            fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
     806             :            ulong                         signers_cnt,
     807             :            fd_sol_sysvar_clock_t const * clock,
     808           0 :            int                           is_vote_authorize_with_bls_enabled ) {
     809             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L724-L727 */
     810           0 :   int rc = get_vote_state_handler_checked(
     811           0 :       vote_account,
     812           0 :       target_version,
     813           0 :       0,
     814           0 :       ctx->runtime->vote_program.authorize.vote_state_mem,
     815           0 :       ctx->runtime->vote_program.authorize.landed_votes_mem
     816           0 :   );
     817           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     818             : 
     819             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L729-L756 */
     820           0 :   fd_vote_state_versioned_t * vote_state_versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.authorize.vote_state_mem;
     821           0 :   switch( vote_authorize.discriminant ) {
     822             : 
     823             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L730-L750 */
     824           0 :     case fd_vote_authorize_enum_voter: {
     825             : 
     826             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L741-L743 */
     827           0 :       if( FD_UNLIKELY( is_vote_authorize_with_bls_enabled && fd_vsv_has_bls_pubkey( vote_state_versioned ) ) ) {
     828           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     829           0 :       }
     830             : 
     831             :       /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L731-L732 */
     832           0 :       int authorized_withdrawer_signer = !fd_vote_verify_authorized_signer(
     833           0 :           fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
     834           0 :           signers,
     835           0 :           signers_cnt
     836           0 :       );
     837             : 
     838             :       /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L737-L740 */
     839           0 :       ulong target_epoch;
     840           0 :       rc = fd_ulong_checked_add( clock->leader_schedule_epoch, 1UL, &target_epoch );
     841           0 :       if( FD_UNLIKELY( rc!=FD_EXECUTOR_INSTR_SUCCESS ) ) {
     842           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     843           0 :       }
     844             : 
     845             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L747 */
     846           0 :       rc = fd_vsv_set_new_authorized_voter(
     847           0 :           ctx,
     848           0 :           vote_state_versioned,
     849           0 :           authorized,
     850           0 :           clock->epoch,
     851           0 :           target_epoch,
     852           0 :           NULL, /* no BLS pubkey */
     853           0 :           authorized_withdrawer_signer,
     854           0 :           signers,
     855           0 :           signers_cnt
     856           0 :       );
     857           0 :       if( FD_UNLIKELY( rc ) ) return rc;
     858           0 :       break;
     859           0 :     }
     860             : 
     861             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L751-L756 */
     862           0 :     case fd_vote_authorize_enum_withdrawer: {
     863           0 :       rc = fd_vote_verify_authorized_signer(
     864           0 :           fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
     865           0 :           signers,
     866           0 :           signers_cnt
     867           0 :       );
     868           0 :       if( FD_UNLIKELY( rc ) ) return rc;
     869           0 :       fd_vsv_set_authorized_withdrawer( vote_state_versioned, authorized );
     870           0 :       break;
     871           0 :     }
     872             : 
     873             :     /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L770 */
     874           0 :     case fd_vote_authorize_enum_voter_with_bls: {
     875             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L771-L773 */
     876           0 :       if( FD_UNLIKELY( !is_vote_authorize_with_bls_enabled ) ) {
     877           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
     878           0 :       }
     879             : 
     880             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L774-L775 */
     881           0 :       int authorized_withdrawer_signer = !fd_vote_verify_authorized_signer(
     882           0 :           fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
     883           0 :           signers,
     884           0 :           signers_cnt
     885           0 :       );
     886             : 
     887             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L777-L782 */
     888           0 :       rc = fd_vote_verify_bls_proof_of_possession(
     889           0 :         ctx,
     890           0 :         vote_account->pubkey->uc,
     891           0 :         vote_authorize.inner.voter_with_bls.bls_pubkey.buf,
     892           0 :         vote_authorize.inner.voter_with_bls.bls_proof_of_possession.buf
     893           0 :       );
     894           0 :       if( FD_UNLIKELY( rc ) ) {
     895           0 :         return rc;
     896           0 :       }
     897             : 
     898             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L787-L790 */
     899           0 :       ulong target_epoch;
     900           0 :       rc = fd_ulong_checked_add( clock->leader_schedule_epoch, 1UL, &target_epoch );
     901           0 :       if( FD_UNLIKELY( rc!=FD_EXECUTOR_INSTR_SUCCESS ) ) {
     902           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     903           0 :       }
     904             : 
     905             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L784 */
     906           0 :       rc = fd_vsv_set_new_authorized_voter(
     907           0 :           ctx,
     908           0 :           vote_state_versioned,
     909           0 :           authorized,
     910           0 :           clock->epoch,
     911           0 :           target_epoch,
     912           0 :           &vote_authorize.inner.voter_with_bls.bls_pubkey,
     913           0 :           authorized_withdrawer_signer,
     914           0 :           signers,
     915           0 :           signers_cnt
     916           0 :       );
     917           0 :       if( FD_UNLIKELY( rc ) ) return rc;
     918             : 
     919           0 :       break;
     920           0 :     }
     921             : 
     922           0 :     default:
     923           0 :       FD_LOG_CRIT(( "unsupported vote_authorize discriminant: %u", vote_authorize.discriminant ));
     924           0 :   }
     925             : 
     926             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L758 */
     927           0 :   return fd_vsv_set_vote_account_state(
     928           0 :       ctx,
     929           0 :       vote_account,
     930           0 :       vote_state_versioned,
     931           0 :       ctx->runtime->vote_program.authorize.vote_lockout_mem
     932           0 :   );
     933           0 : }
     934             : 
     935             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L808-L835 */
     936             : static int
     937             : update_validator_identity( fd_exec_instr_ctx_t *   ctx,
     938             :                            int                     target_version,
     939             :                            fd_borrowed_account_t * vote_account,
     940             :                            fd_pubkey_t const *     node_pubkey,
     941             :                            fd_pubkey_t const *     signers[static FD_TXN_SIG_MAX],
     942             :                            ulong                   signers_cnt,
     943           0 :                            int                     custom_commission_collector_enabled ) {
     944             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L768-L771 */
     945           0 :   int rc = get_vote_state_handler_checked(
     946           0 :       vote_account,
     947           0 :       target_version,
     948           0 :       0,
     949           0 :       ctx->runtime->vote_program.update_validator_identity.vote_state_mem,
     950           0 :       ctx->runtime->vote_program.update_validator_identity.landed_votes_mem
     951           0 :   );
     952           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     953             : 
     954           0 :   fd_vote_state_versioned_t * vote_state_versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.update_validator_identity.vote_state_mem;
     955             : 
     956             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L774 */
     957           0 :   rc = fd_vote_verify_authorized_signer(
     958           0 :       fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
     959           0 :       signers,
     960           0 :       signers_cnt
     961           0 :   );
     962           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     963             : 
     964             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L777 */
     965           0 :   rc = fd_vote_verify_authorized_signer( node_pubkey, signers, signers_cnt );
     966           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     967             : 
     968             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L826 */
     969           0 :   fd_vsv_set_node_pubkey( vote_state_versioned, node_pubkey );
     970             : 
     971             :   /* Before SIMD-0232, block_revenue_collector is always synced with node_pubkey.
     972             :      After SIMD-0232, the collector can be set independently.
     973             :      https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L828-L832 */
     974           0 :   if( !custom_commission_collector_enabled ) {
     975           0 :     fd_vsv_set_block_revenue_collector( vote_state_versioned, node_pubkey );
     976           0 :   }
     977             : 
     978             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L834 */
     979           0 :   return fd_vsv_set_vote_account_state(
     980           0 :       ctx,
     981           0 :       vote_account,
     982           0 :       vote_state_versioned,
     983           0 :       ctx->runtime->vote_program.update_validator_identity.vote_lockout_mem
     984           0 :   );
     985           0 : }
     986             : 
     987             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L971
     988             : static int
     989           0 : is_commission_update_allowed( ulong slot, fd_epoch_schedule_t const * epoch_schedule ) {
     990           0 :   if( FD_LIKELY( epoch_schedule->slots_per_epoch > 0UL ) ) {
     991           0 :     ulong relative_slot = fd_ulong_sat_sub( slot, epoch_schedule->first_normal_slot );
     992             :     // TODO underflow and overflow edge cases in addition to div by 0
     993           0 :     relative_slot %= epoch_schedule->slots_per_epoch;
     994           0 :     return fd_ulong_sat_mul( relative_slot, 2 ) <= epoch_schedule->slots_per_epoch;
     995           0 :   } else {
     996           0 :     return 1;
     997           0 :   }
     998           0 : }
     999             : 
    1000             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L838-L869 */
    1001             : static int
    1002             : update_commission( fd_exec_instr_ctx_t *         ctx,
    1003             :                    int                           target_version,
    1004             :                    fd_borrowed_account_t *       vote_account,
    1005             :                    uchar                         commission,
    1006             :                    fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1007             :                    ulong                         signers_cnt,
    1008             :                    fd_epoch_schedule_t const *   epoch_schedule,
    1009             :                    fd_sol_sysvar_clock_t const * clock,
    1010           0 :                    int                           disable_commission_update_rule ) {
    1011             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L796-L799 */
    1012           0 :   int rc         = 0;
    1013           0 :   int get_vsv_rc = get_vote_state_handler_checked(
    1014           0 :       vote_account,
    1015           0 :       target_version,
    1016           0 :       false,
    1017           0 :       ctx->runtime->vote_program.update_commission.vote_state_mem,
    1018           0 :       ctx->runtime->vote_program.update_commission.landed_votes_mem
    1019           0 :   );
    1020             : 
    1021             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L851-L855 */
    1022           0 :   fd_vote_state_versioned_t * vote_state_versioned           = NULL;
    1023           0 :   int                         enforce_commission_update_rule = !disable_commission_update_rule;
    1024           0 :   if( FD_LIKELY( get_vsv_rc==FD_EXECUTOR_INSTR_SUCCESS ) ) {
    1025           0 :     vote_state_versioned           = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.update_commission.vote_state_mem;
    1026           0 :     enforce_commission_update_rule = (!disable_commission_update_rule) && (commission>fd_vsv_get_commission( vote_state_versioned ));
    1027           0 :   }
    1028             : 
    1029             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L806-L808 */
    1030           0 :   if( FD_UNLIKELY( enforce_commission_update_rule && !is_commission_update_allowed( clock->slot, epoch_schedule ) ) ) {
    1031           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_COMMISSION_UPDATE_TOO_LATE;
    1032           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1033           0 :   }
    1034             : 
    1035             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L810 */
    1036           0 :   if( FD_UNLIKELY( get_vsv_rc ) ) return get_vsv_rc;
    1037             : 
    1038             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L813 */
    1039           0 :   rc = fd_vote_verify_authorized_signer(
    1040           0 :       fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
    1041           0 :       signers,
    1042           0 :       signers_cnt
    1043           0 :   );
    1044           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1045             : 
    1046             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L815 */
    1047           0 :   fd_vsv_set_commission( vote_state_versioned, commission );
    1048             : 
    1049             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L817 */
    1050           0 :   return fd_vsv_set_vote_account_state(
    1051           0 :       ctx,
    1052           0 :       vote_account,
    1053           0 :       vote_state_versioned,
    1054           0 :       ctx->runtime->vote_program.update_commission.vote_lockout_mem
    1055           0 :   );
    1056           0 : }
    1057             : 
    1058             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L848C8-L903 */
    1059             : static int
    1060             : withdraw( fd_exec_instr_ctx_t *         ctx,
    1061             :           fd_borrowed_account_t *       vote_account,
    1062             :           int                           target_version,
    1063             :           ulong                         lamports,
    1064             :           ushort                        to_account_index,
    1065             :           fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1066             :           ulong                         signers_cnt,
    1067             :           fd_rent_t const *             rent_sysvar,
    1068           0 :           fd_sol_sysvar_clock_t const * clock ) {
    1069             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L860-L863 */
    1070           0 :   int rc = get_vote_state_handler_checked(
    1071           0 :       vote_account,
    1072           0 :       target_version,
    1073           0 :       0,
    1074           0 :       ctx->runtime->vote_program.withdraw.vote_state_mem,
    1075           0 :       ctx->runtime->vote_program.withdraw.landed_votes_mem
    1076           0 :   );
    1077           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1078             : 
    1079           0 :   fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.withdraw.vote_state_mem;
    1080             : 
    1081             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L865 */
    1082           0 :   rc = fd_vote_verify_authorized_signer(
    1083           0 :       fd_vsv_get_authorized_withdrawer( versioned ),
    1084           0 :       signers,
    1085           0 :       signers_cnt
    1086           0 :   );
    1087           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1088             : 
    1089             :   /* Always zero until SIMD-0123 is activated.
    1090             :      https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1136 */
    1091           0 :   ulong pending_delegator_rewards = fd_vsv_get_pending_delegator_rewards( versioned );
    1092             : 
    1093             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L867-L870 */
    1094           0 :   ulong vote_account_lamports = fd_borrowed_account_get_lamports( vote_account );
    1095           0 :   if( FD_UNLIKELY( lamports>vote_account_lamports ) ) {
    1096           0 :     return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1097           0 :   }
    1098           0 :   ulong remaining_balance = vote_account_lamports-lamports;
    1099             : 
    1100             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L872-L896 */
    1101           0 :   if( FD_UNLIKELY( remaining_balance==0UL ) ) {
    1102             :     /* SIMD-0123: vote account cannot be closed if pending_delegator_rewards > 0.
    1103             :        https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1139-L1143 */
    1104           0 :     if( FD_UNLIKELY( pending_delegator_rewards > 0 ) ) {
    1105           0 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1106           0 :     }
    1107             : 
    1108             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L873-L883 */
    1109           0 :     fd_vote_epoch_credits_t const * epoch_credits = fd_vsv_get_epoch_credits( versioned );
    1110           0 :     ulong                           last_epoch_with_credits;
    1111           0 :     int                             reject_active_vote_account_close = 0;
    1112           0 :     if( FD_LIKELY( !deq_fd_vote_epoch_credits_t_empty( epoch_credits ) ) ) {
    1113           0 :       ulong current_epoch              = clock->epoch;
    1114           0 :       last_epoch_with_credits          = deq_fd_vote_epoch_credits_t_peek_tail_const( epoch_credits )->epoch;
    1115           0 :       reject_active_vote_account_close = fd_ulong_sat_sub( current_epoch, last_epoch_with_credits )<2UL;
    1116           0 :     }
    1117             : 
    1118             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L885-L890 */
    1119           0 :     if( FD_UNLIKELY( reject_active_vote_account_close ) ) {
    1120           0 :       ctx->txn_out->err.custom_err = FD_VOTE_ERR_ACTIVE_VOTE_ACCOUNT_CLOSE;
    1121           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1122           0 :     } else {
    1123           0 :       rc = fd_vsv_deinitialize_vote_account_state(
    1124           0 :           ctx,
    1125           0 :           vote_account,
    1126           0 :           target_version,
    1127           0 :           ctx->runtime->vote_program.withdraw.vote_lockout_mem
    1128           0 :       );
    1129           0 :       if( FD_UNLIKELY( rc ) ) return rc;
    1130           0 :     }
    1131           0 :   } else {
    1132             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L892-L895 */
    1133           0 :     ulong min_rent_exempt_balance = fd_rent_exempt_minimum_balance( rent_sysvar, fd_borrowed_account_get_data_len( vote_account ) );
    1134             : 
    1135             :     /* SIMD-0123: withdrawable balance when pending_delegator_rewards > 0
    1136             :        is lamports - pending_delegator_rewards - rent_exempt_minimum.
    1137             :        https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1164-L1169 */
    1138           0 :     ulong min_balance;
    1139           0 :     if( FD_UNLIKELY( fd_ulong_checked_add( min_rent_exempt_balance, pending_delegator_rewards, &min_balance ) ) ) {
    1140           0 :       return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
    1141           0 :     }
    1142             : 
    1143           0 :     if( FD_UNLIKELY( remaining_balance<min_balance ) ) {
    1144           0 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1145           0 :     }
    1146           0 :   }
    1147             : 
    1148             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L898 */
    1149           0 :   rc = fd_borrowed_account_checked_sub_lamports( vote_account, lamports );
    1150           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1151             : 
    1152             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L899 */
    1153           0 :   fd_borrowed_account_drop( vote_account );
    1154             : 
    1155             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L900 */
    1156           0 :   fd_guarded_borrowed_account_t to = {0};
    1157           0 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, to_account_index, &to );
    1158             : 
    1159             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L901 */
    1160           0 :   rc = fd_borrowed_account_checked_add_lamports( &to, lamports );
    1161           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1162             : 
    1163           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
    1164           0 : }
    1165             : 
    1166             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L638-L651 */
    1167             : static int
    1168             : process_vote_unfiltered( fd_exec_instr_ctx_t *       ctx,
    1169             :                          fd_vote_state_versioned_t * versioned,
    1170             :                          ulong *                     vote_slots,
    1171             :                          fd_vote_t const *           vote,
    1172             :                          fd_slot_hash_t const *      slot_hashes, /* deque */
    1173             :                          ulong                       epoch,
    1174           0 :                          ulong                       current_slot ) {
    1175           0 :   int rc;
    1176             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L770
    1177           0 :   rc = check_slots_are_valid( ctx, versioned, vote_slots, &vote->hash, slot_hashes );
    1178           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1179           0 :   for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote_slots );
    1180           0 :        !deq_ulong_iter_done( vote_slots, iter );
    1181           0 :        iter = deq_ulong_iter_next( vote_slots, iter ) ) {
    1182           0 :     ulong * ele = deq_ulong_iter_ele( vote_slots, iter );
    1183             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L772
    1184           0 :     fd_vsv_process_next_vote_slot( versioned, *ele, epoch, current_slot );
    1185           0 :   }
    1186           0 :   return 0;
    1187           0 : }
    1188             : 
    1189             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L783
    1190             : static int
    1191             : process_vote( fd_exec_instr_ctx_t *       ctx,
    1192             :               fd_vote_state_versioned_t * versioned,
    1193             :               fd_vote_t const *           vote,
    1194             :               fd_slot_hash_t const *      slot_hashes, /* deque */
    1195             :               ulong                       epoch,
    1196           0 :               ulong                       current_slot ) {
    1197             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L792
    1198           0 :   if( FD_UNLIKELY( deq_ulong_empty( vote->slots ) ) ) {
    1199           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
    1200           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1201           0 :   }
    1202             : 
    1203             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L795
    1204           0 :   ulong earliest_slot_in_history = 0;
    1205           0 :   if( FD_UNLIKELY( !deq_fd_slot_hash_t_empty( slot_hashes ) ) ) {
    1206           0 :     earliest_slot_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes )->slot;
    1207           0 :   }
    1208             : 
    1209             :   /* We know that the size of the vote_slots is bounded by the number of
    1210             :      slots that can fit inside of an instruction.  A very loose bound is
    1211             :      assuming that the entire transaction is just filled with a vote
    1212             :      slot deque (1232 bytes per transaction/8 bytes per slot) == 154
    1213             :      slots.  The footprint of a deque is as follows:
    1214             :      fd_ulong_align_up( fd_ulong_align_up( 32UL, alignof(DEQUE_T) ) + sizeof(DEQUE_T)*max, alignof(DEQUE_(private_t)) );
    1215             :      So, the footprint in our case is:
    1216             :      fd_ulong_align_up( fd_ulong_align_up( 32UL, alignof(ulong) ) + sizeof(ulong)*154, alignof(DEQUE_(private_t)) );
    1217             :      Which is equal to
    1218             :      fd_ulong_align_up( 32UL + 154 * 8UL, 8UL ) = 1264UL; */
    1219           0 :   #define VOTE_SLOTS_MAX             (FD_TXN_MTU/sizeof(ulong))
    1220           0 :   #define VOTE_SLOTS_DEQUE_FOOTPRINT (1264UL )
    1221           0 :   #define VOTE_SLOTS_DEQUE_ALIGN     (8UL)
    1222           0 :   FD_TEST( deq_ulong_footprint( VOTE_SLOTS_MAX ) == VOTE_SLOTS_DEQUE_FOOTPRINT );
    1223           0 :   FD_TEST( deq_ulong_align()                     == 8UL );
    1224           0 :   FD_TEST( deq_ulong_cnt( vote->slots )          <= VOTE_SLOTS_MAX );
    1225           0 :   uchar * vote_slots_mem[ VOTE_SLOTS_DEQUE_FOOTPRINT ] __attribute__((aligned(VOTE_SLOTS_DEQUE_ALIGN)));
    1226             : 
    1227             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L796
    1228           0 :   ulong * vote_slots = deq_ulong_join( deq_ulong_new( vote_slots_mem, deq_ulong_cnt( vote->slots ) ) );
    1229           0 :   for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote->slots );
    1230           0 :        !deq_ulong_iter_done( vote->slots, iter );
    1231           0 :        iter = deq_ulong_iter_next( vote->slots, iter ) ) {
    1232           0 :     ulong * ele = deq_ulong_iter_ele( vote->slots, iter );
    1233           0 :     if( FD_UNLIKELY( *ele >= earliest_slot_in_history ) ) {
    1234           0 :       vote_slots = deq_ulong_push_tail_wrap( vote_slots, *ele );
    1235           0 :     }
    1236           0 :   }
    1237             : 
    1238             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L802
    1239           0 :   if( FD_UNLIKELY( deq_ulong_cnt( vote_slots ) == 0 ) ) {
    1240           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTES_TOO_OLD_ALL_FILTERED;
    1241           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1242           0 :   }
    1243             : 
    1244             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L805
    1245           0 :   return process_vote_unfiltered(
    1246           0 :       ctx,
    1247           0 :       versioned,
    1248           0 :       vote_slots,
    1249           0 :       vote,
    1250           0 :       slot_hashes,
    1251           0 :       epoch,
    1252           0 :       current_slot
    1253           0 :   );
    1254           0 : }
    1255             : 
    1256             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L905-L926 */
    1257             : static int
    1258             : initialize_account( fd_exec_instr_ctx_t *         ctx,
    1259             :                     fd_borrowed_account_t *       vote_account,
    1260             :                     int                           target_version,
    1261             :                     fd_vote_init_t *              vote_init,
    1262             :                     fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1263             :                     ulong                         signers_cnt,
    1264           6 :                     fd_sol_sysvar_clock_t const * clock ) {
    1265           6 :   int rc;
    1266             : 
    1267             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L915 */
    1268           6 :   rc = check_vote_account_length( vote_account, target_version );
    1269           6 :   if( FD_UNLIKELY( rc ) ) return rc;
    1270             : 
    1271             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L916 */
    1272           6 :   rc = fd_vsv_get_state( vote_account->meta, ctx->runtime->vote_program.init_account.vote_state_mem );
    1273           6 :   if( FD_UNLIKELY( rc ) ) return rc;
    1274           6 :   fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.init_account.vote_state_mem;
    1275             : 
    1276             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L918-L920 */
    1277           6 :   if( FD_UNLIKELY( !fd_vsv_is_uninitialized( versioned ) ) ) {
    1278           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
    1279           0 :   }
    1280             : 
    1281             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L923 */
    1282           6 :   rc = fd_vote_verify_authorized_signer( &vote_init->node_pubkey, signers, signers_cnt );
    1283           6 :   if( FD_UNLIKELY( rc ) ) {
    1284           0 :     return rc;
    1285           0 :   }
    1286             : 
    1287             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L925 */
    1288           6 :   return init_vote_account_state( ctx, vote_account, versioned, target_version, vote_init, clock );
    1289           6 : }
    1290             : 
    1291             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1182-L1216
    1292             :    Note: this is very similar to initialize_account() but also does verify_bls_proof_of_possession() */
    1293             : static int
    1294             : initialize_account_v2( fd_exec_instr_ctx_t *         ctx,
    1295             :                        fd_borrowed_account_t *       vote_account,
    1296             :                        int                           target_version,
    1297             :                        fd_vote_init_v2_t *           vote_init_v2,
    1298             :                        fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1299             :                        ulong                         signers_cnt,
    1300           0 :                        fd_sol_sysvar_clock_t const * clock ) {
    1301           0 :   int rc;
    1302             : 
    1303             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1198 */
    1304           0 :   rc = check_vote_account_length( vote_account, target_version );
    1305           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1306             : 
    1307           0 :   rc = fd_vsv_get_state( vote_account->meta, ctx->runtime->vote_program.init_account.vote_state_mem );
    1308           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1309           0 :   fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.init_account.vote_state_mem;
    1310             : 
    1311           0 :   if( FD_UNLIKELY( !fd_vsv_is_uninitialized( versioned ) ) ) {
    1312           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
    1313           0 :   }
    1314             : 
    1315           0 :   rc = fd_vote_verify_authorized_signer( &vote_init_v2->node_pubkey, signers, signers_cnt );
    1316           0 :   if( FD_UNLIKELY( rc ) ) {
    1317           0 :     return rc;
    1318           0 :   }
    1319             : 
    1320             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1208-L1213 */
    1321           0 :   rc = fd_vote_verify_bls_proof_of_possession(
    1322           0 :     ctx,
    1323           0 :     vote_account->pubkey->uc,
    1324           0 :     vote_init_v2->authorized_voter_bls_pubkey.buf,
    1325           0 :     vote_init_v2->authorized_voter_bls_proof_of_possession.buf
    1326           0 :   );
    1327           0 :   if( FD_UNLIKELY( rc ) ) {
    1328           0 :     return rc;
    1329           0 :   }
    1330             : 
    1331             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1215 */
    1332           0 :   return init_vote_account_state_v2( ctx, vote_account, versioned, target_version, vote_init_v2, clock );
    1333           0 : }
    1334             : 
    1335             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L928-L953 */
    1336             : static int
    1337             : process_vote_with_account( fd_exec_instr_ctx_t *         ctx,
    1338             :                            fd_borrowed_account_t *       vote_account,
    1339             :                            int                           target_version,
    1340             :                            fd_slot_hash_t const *        slot_hashes, /* deque */
    1341             :                            fd_sol_sysvar_clock_t const * clock,
    1342             :                            fd_vote_t *                   vote,
    1343             :                            fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1344           0 :                            ulong                         signers_cnt ) {
    1345             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L936-L939 */
    1346           0 :   int rc = get_vote_state_handler_checked(
    1347           0 :       vote_account,
    1348           0 :       target_version,
    1349           0 :       1,
    1350           0 :       ctx->runtime->vote_program.process_vote.vote_state_mem,
    1351           0 :       ctx->runtime->vote_program.process_vote.landed_votes_mem
    1352           0 :   );
    1353           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1354             : 
    1355           0 :   fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.process_vote.vote_state_mem;
    1356             : 
    1357             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L941 */
    1358           0 :   fd_pubkey_t * authorized_voter = NULL;
    1359           0 :   rc = fd_authorized_voters_get_and_update_authorized_voter( versioned, clock->epoch, &authorized_voter );
    1360           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1361             : 
    1362             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L942 */
    1363           0 :   rc = fd_vote_verify_authorized_signer( authorized_voter, signers, signers_cnt );
    1364           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1365             : 
    1366             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L944 */
    1367           0 :   rc = process_vote( ctx, versioned, vote, slot_hashes, clock->epoch, clock->slot );
    1368           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1369             : 
    1370             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L945-L951 */
    1371           0 :   if( FD_LIKELY( vote->has_timestamp ) ) {
    1372             :     /* Calling max() on an empty iterator returns None */
    1373           0 :     if( FD_UNLIKELY( deq_ulong_cnt( vote->slots )==0 ) ) {
    1374           0 :       ctx->txn_out->err.custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
    1375           0 :       return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
    1376           0 :     }
    1377             : 
    1378             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L948 */
    1379           0 :     ulong max = 0UL;
    1380           0 :     for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote->slots );
    1381           0 :                                 !deq_ulong_iter_done( vote->slots, iter );
    1382           0 :                           iter = deq_ulong_iter_next( vote->slots, iter ) ) {
    1383           0 :       ulong * ele = deq_ulong_iter_ele( vote->slots, iter );
    1384           0 :       max         = fd_ulong_max( max, *ele );
    1385           0 :     }
    1386             : 
    1387             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L950 */
    1388           0 :     rc = fd_vsv_process_timestamp( ctx, versioned, max, vote->timestamp );
    1389           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    1390           0 :   }
    1391             : 
    1392             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L952 */
    1393           0 :   return fd_vsv_set_vote_account_state(
    1394           0 :       ctx,
    1395           0 :       vote_account,
    1396           0 :       versioned,
    1397           0 :       ctx->runtime->vote_program.process_vote.vote_lockout_mem
    1398           0 :   );
    1399           0 : }
    1400             : 
    1401             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1156
    1402             : static int
    1403             : do_process_vote_state_update( fd_exec_instr_ctx_t *       ctx,
    1404             :                               fd_vote_state_versioned_t * versioned,
    1405             :                               fd_slot_hash_t const *      slot_hashes, /* deque */
    1406             :                               ulong                       epoch,
    1407             :                               ulong                       slot,
    1408           0 :                               fd_vote_state_update_t *    vote_state_update ) {
    1409           0 :   int rc;
    1410             : 
    1411             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1164
    1412           0 :   rc = check_and_filter_proposed_vote_state(
    1413           0 :       ctx,
    1414           0 :       versioned,
    1415           0 :       vote_state_update->lockouts,
    1416           0 :       &vote_state_update->has_root,
    1417           0 :       &vote_state_update->root,
    1418           0 :       &vote_state_update->hash,
    1419           0 :       slot_hashes
    1420           0 :   );
    1421           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1422             : 
    1423             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1177
    1424           0 :   fd_landed_vote_t * landed_votes = deq_fd_landed_vote_t_join( deq_fd_landed_vote_t_new( ctx->runtime->vote_program.process_vote.vs_update_landed_votes_mem, deq_fd_vote_lockout_t_cnt( vote_state_update->lockouts ) ) );
    1425           0 :   for( deq_fd_vote_lockout_t_iter_t iter =
    1426           0 :            deq_fd_vote_lockout_t_iter_init( vote_state_update->lockouts );
    1427           0 :        !deq_fd_vote_lockout_t_iter_done( vote_state_update->lockouts, iter );
    1428           0 :        iter = deq_fd_vote_lockout_t_iter_next( vote_state_update->lockouts, iter ) ) {
    1429           0 :     fd_vote_lockout_t * lockout =
    1430           0 :         deq_fd_vote_lockout_t_iter_ele( vote_state_update->lockouts, iter );
    1431           0 :     deq_fd_landed_vote_t_push_tail_wrap( landed_votes,
    1432           0 :                                     ( fd_landed_vote_t ){ .latency = 0, .lockout = *lockout } );
    1433           0 :   }
    1434             : 
    1435             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1171
    1436           0 :   return process_new_vote_state(
    1437           0 :       ctx,
    1438           0 :       versioned,
    1439           0 :       landed_votes,
    1440           0 :       vote_state_update->has_root,
    1441           0 :       vote_state_update->root,
    1442           0 :       vote_state_update->has_timestamp,
    1443           0 :       vote_state_update->timestamp,
    1444           0 :       epoch,
    1445           0 :       slot
    1446           0 :   );
    1447           0 : }
    1448             : 
    1449             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L955-L979 */
    1450             : static int
    1451             : process_vote_state_update( fd_exec_instr_ctx_t *         ctx,
    1452             :                            fd_borrowed_account_t *       vote_account,
    1453             :                            int                           target_version,
    1454             :                            fd_slot_hash_t const *        slot_hashes,
    1455             :                            fd_sol_sysvar_clock_t const * clock,
    1456             :                            fd_vote_state_update_t *      vote_state_update,
    1457             :                            fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1458           0 :                            ulong                         signers_cnt ) {
    1459             : 
    1460             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L963-L966 */
    1461           0 :   int rc = get_vote_state_handler_checked(
    1462           0 :       vote_account,
    1463           0 :       target_version,
    1464           0 :       1,
    1465           0 :       ctx->runtime->vote_program.process_vote.vote_state_mem,
    1466           0 :       ctx->runtime->vote_program.process_vote.landed_votes_mem
    1467           0 :   );
    1468           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1469             : 
    1470           0 :   fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.process_vote.vote_state_mem;
    1471             : 
    1472             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L968 */
    1473           0 :   fd_pubkey_t * authorized_voter = NULL;
    1474           0 :   rc = fd_authorized_voters_get_and_update_authorized_voter( versioned, clock->epoch, &authorized_voter );
    1475           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1476             : 
    1477             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L969 */
    1478           0 :   rc = fd_vote_verify_authorized_signer( authorized_voter, signers, signers_cnt );
    1479           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1480             : 
    1481             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L971-L977 */
    1482           0 :   rc = do_process_vote_state_update(
    1483           0 :       ctx,
    1484           0 :       versioned,
    1485           0 :       slot_hashes,
    1486           0 :       clock->epoch,
    1487           0 :       clock->slot,
    1488           0 :       vote_state_update
    1489           0 :   );
    1490           0 :   if( FD_UNLIKELY( rc ) ) {
    1491           0 :     return rc;
    1492           0 :   }
    1493             : 
    1494             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L978 */
    1495           0 :   return fd_vsv_set_vote_account_state(
    1496           0 :       ctx,
    1497           0 :       vote_account,
    1498           0 :       versioned,
    1499           0 :       ctx->runtime->vote_program.process_vote.vote_lockout_mem
    1500           0 :   );
    1501           0 : }
    1502             : 
    1503             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1035-L1061 */
    1504             : static int
    1505             : do_process_tower_sync( fd_exec_instr_ctx_t *       ctx,
    1506             :                        fd_vote_state_versioned_t * versioned,
    1507             :                        fd_slot_hash_t const *      slot_hashes, /* deque */
    1508             :                        ulong                       epoch,
    1509             :                        ulong                       slot,
    1510           0 :                        fd_tower_sync_t *           tower_sync ) {
    1511             : 
    1512             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1042-L1048 */
    1513           0 :   int rc = check_and_filter_proposed_vote_state(
    1514           0 :       ctx,
    1515           0 :       versioned,
    1516           0 :       tower_sync->lockouts,
    1517           0 :       &tower_sync->has_root,
    1518           0 :       &tower_sync->root,
    1519           0 :       &tower_sync->hash,
    1520           0 :       slot_hashes
    1521           0 :   );
    1522           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1523             : 
    1524             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1049-L1060 */
    1525           0 :   return process_new_vote_state(
    1526           0 :       ctx,
    1527           0 :       versioned,
    1528           0 :       fd_vote_lockout_landed_votes_from_lockouts( tower_sync->lockouts, ctx->runtime->vote_program.tower_sync.tower_sync_landed_votes_mem ),
    1529           0 :       tower_sync->has_root,
    1530           0 :       tower_sync->root,
    1531           0 :       tower_sync->has_timestamp,
    1532           0 :       tower_sync->timestamp,
    1533           0 :       epoch,
    1534           0 :       slot
    1535           0 :   );
    1536           0 : }
    1537             : 
    1538             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1009-L1033 */
    1539             : static int
    1540             : process_tower_sync( fd_exec_instr_ctx_t *         ctx,
    1541             :                     fd_borrowed_account_t *       vote_account,
    1542             :                     int                           target_version,
    1543             :                     fd_slot_hash_t const *        slot_hashes, /* deque */
    1544             :                     fd_sol_sysvar_clock_t const * clock,
    1545             :                     fd_tower_sync_t *             tower_sync,
    1546             :                     fd_pubkey_t const *           signers[static FD_TXN_SIG_MAX],
    1547           0 :                     ulong                         signers_cnt ) {
    1548             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1017-L1020 */
    1549           0 :   int rc = get_vote_state_handler_checked(
    1550           0 :      vote_account,
    1551           0 :      target_version,
    1552           0 :      1,
    1553           0 :      ctx->runtime->vote_program.tower_sync.vote_state_mem,
    1554           0 :      ctx->runtime->vote_program.tower_sync.vote_state_landed_votes_mem
    1555           0 :   );
    1556           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1557             : 
    1558           0 :   fd_vote_state_versioned_t * versioned = (fd_vote_state_versioned_t *)ctx->runtime->vote_program.tower_sync.vote_state_mem;
    1559             : 
    1560             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1022 */
    1561           0 :   fd_pubkey_t * authorized_voter = NULL;
    1562           0 :   rc = fd_authorized_voters_get_and_update_authorized_voter( versioned, clock->epoch, &authorized_voter );
    1563           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1564             : 
    1565             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1023 */
    1566           0 :   rc = fd_vote_verify_authorized_signer( authorized_voter, signers, signers_cnt );
    1567           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1568             : 
    1569             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1025-L1031 */
    1570           0 :   rc = do_process_tower_sync(
    1571           0 :       ctx,
    1572           0 :       versioned,
    1573           0 :       slot_hashes,
    1574           0 :       clock->epoch,
    1575           0 :       clock->slot,
    1576           0 :       tower_sync
    1577           0 :   );
    1578           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1579             : 
    1580             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1032 */
    1581           0 :   return fd_vsv_set_vote_account_state(
    1582           0 :       ctx,
    1583           0 :       vote_account,
    1584           0 :       versioned,
    1585           0 :       ctx->runtime->vote_program.tower_sync.vote_lockout_mem
    1586           0 :   );
    1587           0 : }
    1588             : 
    1589             : /**********************************************************************/
    1590             : /* FD-only encoders / decoders (doesn't map directly to Labs impl)    */
    1591             : /**********************************************************************/
    1592             : 
    1593             : int
    1594             : fd_vote_decode_compact_update( fd_compact_vote_state_update_t * compact_update,
    1595             :                                fd_vote_state_update_t *         vote_update,
    1596           0 :                                fd_exec_instr_ctx_t const *      ctx ) {
    1597             :   // Taken from:
    1598             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L954
    1599           0 :   if( compact_update->root != ULONG_MAX ) {
    1600           0 :     vote_update->has_root = 1;
    1601           0 :     vote_update->root     = compact_update->root;
    1602           0 :   } else {
    1603           0 :     vote_update->has_root = 0;
    1604           0 :     vote_update->root     = ULONG_MAX;
    1605           0 :   }
    1606             : 
    1607           0 :   ulong lockouts_len = compact_update->lockouts_len;
    1608           0 :   ulong lockouts_max = fd_ulong_max( lockouts_len, MAX_LOCKOUT_HISTORY );
    1609             : 
    1610           0 :   vote_update->lockouts = deq_fd_vote_lockout_t_join( deq_fd_vote_lockout_t_new( ctx->runtime->vote_program.process_vote.compact_vs_lockout_mem, lockouts_max ) );
    1611           0 :   ulong slot            = fd_ulong_if( vote_update->has_root, vote_update->root, 0 );
    1612             : 
    1613           0 :   for( ulong i=0; i < lockouts_len; ++i ) {
    1614           0 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( vote_update->lockouts );
    1615           0 :     fd_vote_lockout_new( elem );
    1616             : 
    1617           0 :     fd_lockout_offset_t * lock_offset = &compact_update->lockouts[i];
    1618             : 
    1619           0 :     ulong next_slot;
    1620           0 :     if( FD_UNLIKELY( __builtin_uaddl_overflow( slot, lock_offset->offset, &next_slot ) ) )
    1621           0 :       return 0;
    1622             : 
    1623           0 :     elem->slot = slot        = next_slot;
    1624           0 :     elem->confirmation_count = (uint)lock_offset->confirmation_count;
    1625           0 :   }
    1626             : 
    1627           0 :   vote_update->hash          = compact_update->hash;
    1628           0 :   vote_update->has_timestamp = compact_update->has_timestamp;
    1629           0 :   vote_update->timestamp     = compact_update->timestamp;
    1630             : 
    1631           0 :   return 1;
    1632           0 : }
    1633             : 
    1634             : /**********************************************************************/
    1635             : /* mod vote_processor                                                 */
    1636             : /**********************************************************************/
    1637             : 
    1638             : /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L21-L51 */
    1639             : static int
    1640             : process_authorize_with_seed_instruction( /* invoke_context */
    1641             :                                          fd_exec_instr_ctx_t *   ctx,
    1642             :                                          int                     target_version,
    1643             :                                          fd_borrowed_account_t * vote_account,
    1644             :                                          fd_pubkey_t const *     new_authority,
    1645             :                                          fd_vote_authorize_t     authorization_type,
    1646             :                                          fd_pubkey_t const *     current_authority_derived_key_owner,
    1647             :                                          uchar const *           current_authority_derived_key_seed,
    1648             :                                          ulong                   current_authority_derived_key_seed_len,
    1649           0 :                                          int                     is_vote_authorize_with_bls_enabled ) {
    1650           0 :   int rc = 0;
    1651             : 
    1652             :   /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L31 */
    1653           0 :   rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id );
    1654           0 :   if( FD_UNLIKELY( rc ) ) return rc;
    1655             : 
    1656           0 :   fd_sol_sysvar_clock_t clock_;
    1657           0 :   fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    1658           0 :   if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1659             : 
    1660           0 :   fd_pubkey_t * expected_authority_keys[FD_TXN_SIG_MAX] = { 0 };
    1661           0 :   ulong         expected_authority_keys_cnt             = 0UL;
    1662           0 :   fd_pubkey_t   single_signer                           = { 0 };
    1663             : 
    1664             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L30-L42 */
    1665           0 :   if( fd_instr_acc_is_signer_idx( ctx->instr, 2, &rc ) ) {
    1666             : 
    1667             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L31 */
    1668           0 :     fd_pubkey_t const * base_pubkey = NULL;
    1669           0 :     rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 2UL, &base_pubkey );
    1670           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    1671             : 
    1672             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L34-L40 */
    1673           0 :     expected_authority_keys[0] = &single_signer;
    1674           0 :     rc = fd_pubkey_create_with_seed( ctx,
    1675           0 :                                      base_pubkey->uc,
    1676           0 :                                      (char const *)current_authority_derived_key_seed,
    1677           0 :                                      current_authority_derived_key_seed_len,
    1678           0 :                                      current_authority_derived_key_owner->uc,
    1679           0 :                                      /* insert */ expected_authority_keys[0]->uc );
    1680           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    1681           0 :     expected_authority_keys_cnt = 1UL;
    1682           0 :   }
    1683             : 
    1684             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L43-L50 */
    1685           0 :   return authorize(
    1686           0 :       ctx,
    1687           0 :       vote_account,
    1688           0 :       target_version,
    1689           0 :       new_authority,
    1690           0 :       authorization_type,
    1691           0 :       (fd_pubkey_t const **)expected_authority_keys,
    1692           0 :       expected_authority_keys_cnt,
    1693           0 :       clock,
    1694           0 :       is_vote_authorize_with_bls_enabled
    1695           0 :   );
    1696           0 : }
    1697             : 
    1698             : /**********************************************************************/
    1699             : /* Entry point for the Vote Program                                   */
    1700             : /**********************************************************************/
    1701             : 
    1702             : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L57
    1703             : int
    1704          12 : fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) {
    1705             :   /* FD-specific init */
    1706          12 :   int rc = FD_EXECUTOR_INSTR_SUCCESS;
    1707             : 
    1708             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L57
    1709          12 :   FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS );
    1710             : 
    1711             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L64-L67 */
    1712          12 :   fd_guarded_borrowed_account_t me = {0};
    1713          12 :   FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 0, &me );
    1714          12 :   if( FD_UNLIKELY( !fd_pubkey_eq( fd_borrowed_account_get_owner( &me ), &fd_solana_vote_program_id ) ) ) {
    1715           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
    1716           0 :   }
    1717             : 
    1718             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L69-L74 */
    1719          12 :   int target_version = FD_FEATURE_ACTIVE_BANK( ctx->bank, vote_state_v4 ) ? VOTE_STATE_TARGET_VERSION_V4 : VOTE_STATE_TARGET_VERSION_V3;
    1720             : 
    1721             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L69
    1722          12 :   fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = { 0 };
    1723          12 :   ulong               signers_cnt             = 0UL;
    1724          12 :   fd_exec_instr_ctx_get_signers( ctx, signers, &signers_cnt );
    1725             : 
    1726             :   /* Some of these features are not implemented yet. As such, they are
    1727             :      not in feature_map.json.
    1728             : 
    1729             :      TODO: don't hardcode these when the features are implemented. */
    1730          12 :   int vote_state_v4                         = FD_FEATURE_ACTIVE_BANK( ctx->bank, vote_state_v4 );
    1731          12 :   int bls_pubkey_management_in_vote_account = FD_FEATURE_ACTIVE_BANK( ctx->bank, bls_pubkey_management_in_vote_account );
    1732          12 :   int delay_commission_updates              = 0;
    1733          12 :   int commission_rate_in_basis_points       = 0;
    1734          12 :   int custom_commission_collector           = 0;
    1735          12 :   int block_revenue_sharing                 = 0;
    1736          12 :   int vote_account_initialize_v2            = 0;
    1737             : 
    1738             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L73-L76 */
    1739          12 :   int is_vote_authorize_with_bls_enabled =
    1740          12 :       vote_state_v4 &&
    1741          12 :       bls_pubkey_management_in_vote_account;
    1742             : 
    1743             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L63-L71 */
    1744          12 :   int is_init_account_v2_enabled =
    1745          12 :       vote_state_v4 &&
    1746          12 :       bls_pubkey_management_in_vote_account &&
    1747          12 :       commission_rate_in_basis_points &&
    1748          12 :       custom_commission_collector &&
    1749          12 :       block_revenue_sharing &&
    1750          12 :       vote_account_initialize_v2;
    1751             : 
    1752          12 :   uchar __attribute__((aligned(alignof(fd_vote_instruction_t)))) vote_instruction_mem[ FD_VOTE_INSTRUCTION_FOOTPRINT ];
    1753          12 :   fd_vote_instruction_t * instruction = fd_bincode_decode_static_limited_deserialize(
    1754          12 :       vote_instruction,
    1755          12 :       vote_instruction_mem,
    1756          12 :       ctx->instr->data,
    1757          12 :       ctx->instr->data_sz,
    1758          12 :       FD_TXN_MTU );
    1759          12 :   if( FD_UNLIKELY( !instruction ) ) {
    1760           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    1761           0 :   }
    1762             : 
    1763             :   /* PLEASE PRESERVE SWITCH-CASE ORDERING TO MIRROR LABS IMPL:
    1764             :    */
    1765          12 :   switch( instruction->discriminant ) {
    1766             : 
    1767             :   /* InitializeAccount
    1768             :    *
    1769             :    * Instruction:
    1770             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L32
    1771             :    *
    1772             :    * Processor:
    1773             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L71
    1774             :    */
    1775           6 :   case fd_vote_instruction_enum_initialize_account: {
    1776             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L72
    1777           6 :     rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_rent_id );
    1778           6 :     if( FD_UNLIKELY( rc ) ) return rc;
    1779           6 :     fd_rent_t rent_;
    1780           6 :     fd_rent_t const * rent = fd_sysvar_cache_rent_read( ctx->sysvar_cache, &rent_ );
    1781           6 :     if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1782             : 
    1783           6 :     if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &me ) <
    1784           6 :                      fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( &me ) ) ) )
    1785           0 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    1786             : 
    1787             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L76
    1788           6 :     rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id );
    1789           6 :     if( FD_UNLIKELY( rc ) ) return rc;
    1790           6 :     fd_sol_sysvar_clock_t clock_;
    1791           6 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    1792           6 :     if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1793             : 
    1794             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L78
    1795           6 :     rc = initialize_account( ctx, &me, target_version, &instruction->inner.initialize_account, signers, signers_cnt, clock );
    1796             : 
    1797           6 :     break;
    1798           6 :   }
    1799             : 
    1800             :   /* Authorize
    1801             :    *
    1802             :    * Instruction:
    1803             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L40
    1804             :    *
    1805             :    * Processor:
    1806             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L86
    1807             :    *
    1808             :    * Notes:
    1809             :    * - Up to two signers: the vote authority and the authorized withdrawer.
    1810             :    */
    1811           0 :   case fd_vote_instruction_enum_authorize: {
    1812           0 :     fd_pubkey_t const * voter_pubkey   = &instruction->inner.authorize.pubkey;
    1813           0 :     fd_vote_authorize_t vote_authorize = instruction->inner.authorize.vote_authorize;
    1814             : 
    1815             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L87
    1816           0 :     rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id );
    1817           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    1818           0 :     fd_sol_sysvar_clock_t clock_;
    1819           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    1820           0 :     if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1821             : 
    1822           0 :     rc = authorize( ctx, &me, target_version, voter_pubkey, vote_authorize, signers, signers_cnt, clock, is_vote_authorize_with_bls_enabled );
    1823             : 
    1824           0 :     break;
    1825           0 :   }
    1826             : 
    1827             :   /* AuthorizeWithSeed
    1828             :    *
    1829             :    * Instruction:
    1830             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L117
    1831             :    *
    1832             :    * Processor:
    1833             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L98
    1834             :    */
    1835           0 :   case fd_vote_instruction_enum_authorize_with_seed: {
    1836           0 :     fd_vote_authorize_with_seed_args_t * args = &instruction->inner.authorize_with_seed;
    1837             : 
    1838             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L99
    1839           0 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 3 ) ) {
    1840           0 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    1841           0 :       break;
    1842           0 :     }
    1843             : 
    1844           0 :     rc = process_authorize_with_seed_instruction(
    1845           0 :         ctx,
    1846           0 :         target_version,
    1847           0 :         &me,
    1848           0 :         &args->new_authority,
    1849           0 :         args->authorization_type,
    1850           0 :         &args->current_authority_derived_key_owner,
    1851           0 :         args->current_authority_derived_key_seed,
    1852           0 :         args->current_authority_derived_key_seed_len,
    1853           0 :         is_vote_authorize_with_bls_enabled
    1854           0 :     );
    1855             : 
    1856           0 :     break;
    1857           0 :   }
    1858             : 
    1859             :   /* AuthorizeCheckedWithSeed
    1860             :    *
    1861             :    * Instruction:
    1862             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L131
    1863             :    *
    1864             :    * Processor:
    1865             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L111
    1866             :    */
    1867           0 :   case fd_vote_instruction_enum_authorize_checked_with_seed: {
    1868           0 :     fd_vote_authorize_checked_with_seed_args_t const * args = &instruction->inner.authorize_checked_with_seed;
    1869             : 
    1870             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L112
    1871           0 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 4 ) ) {
    1872           0 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    1873           0 :       break;
    1874           0 :     }
    1875             : 
    1876             :     // https://github.com/anza-xyz/agave/blob/v2.1.14/programs/vote/src/vote_processor.rs#L99-L100
    1877           0 :     fd_pubkey_t const * new_authority = NULL;
    1878           0 :     rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 3UL, &new_authority );
    1879           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    1880             : 
    1881             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L116
    1882           0 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, 3, &rc ) ) ) {
    1883             :       /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    1884           0 :       if( FD_UNLIKELY( !!rc ) ) break;
    1885             :       // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L117
    1886           0 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    1887           0 :       break;
    1888           0 :     }
    1889             : 
    1890             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L119
    1891           0 :     rc = process_authorize_with_seed_instruction(
    1892           0 :         ctx,
    1893           0 :         target_version,
    1894           0 :         &me,
    1895           0 :         new_authority,
    1896           0 :         args->authorization_type,
    1897           0 :         &args->current_authority_derived_key_owner,
    1898           0 :         args->current_authority_derived_key_seed,
    1899           0 :         args->current_authority_derived_key_seed_len,
    1900           0 :         is_vote_authorize_with_bls_enabled );
    1901             : 
    1902           0 :     break;
    1903           0 :   }
    1904             : 
    1905             :   /* UpdateValidatorIdentity
    1906             :    *
    1907             :    * Instruction:
    1908             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L65
    1909             :    *
    1910             :    * Processor:
    1911             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L130
    1912             :    */
    1913           0 :   case fd_vote_instruction_enum_update_validator_identity: {
    1914             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L131
    1915           0 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) ) {
    1916           0 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    1917           0 :       break;
    1918           0 :     }
    1919             : 
    1920             :     // https://github.com/anza-xyz/agave/blob/v2.1.14/programs/vote/src/vote_processor.rs#L118-L120
    1921           0 :     fd_pubkey_t const * node_pubkey = NULL;
    1922           0 :     rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 1UL, &node_pubkey );
    1923           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    1924             : 
    1925             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L135
    1926           0 :     rc = update_validator_identity( ctx, target_version, &me, node_pubkey, signers, signers_cnt, custom_commission_collector );
    1927             : 
    1928           0 :     break;
    1929           0 :   }
    1930             : 
    1931             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L142
    1932           0 :   case fd_vote_instruction_enum_update_commission: {
    1933             : 
    1934             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L149
    1935           0 :     fd_epoch_schedule_t epoch_schedule_;
    1936           0 :     fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_cache_epoch_schedule_read( ctx->sysvar_cache, &epoch_schedule_ );
    1937           0 :     if( FD_UNLIKELY( !epoch_schedule ) ) {
    1938           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1939           0 :     }
    1940             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L150
    1941             : 
    1942           0 :     fd_sol_sysvar_clock_t clock_;
    1943           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    1944           0 :     if( FD_UNLIKELY( !clock ) ) {
    1945           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    1946           0 :     }
    1947             : 
    1948             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L145
    1949           0 :     rc = update_commission(
    1950           0 :         ctx,
    1951           0 :         target_version,
    1952           0 :         &me,
    1953           0 :         instruction->inner.update_commission,
    1954           0 :         signers,
    1955           0 :         signers_cnt,
    1956           0 :         epoch_schedule,
    1957           0 :         clock,
    1958           0 :         delay_commission_updates
    1959           0 :     );
    1960             : 
    1961           0 :     break;
    1962           0 :   }
    1963             : 
    1964             :   /* Vote
    1965             :    *
    1966             :    * Instruction:
    1967             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L49
    1968             :    */
    1969           0 :   case fd_vote_instruction_enum_vote:;
    1970             :     /* clang-format off */
    1971           0 :     __attribute__((fallthrough));
    1972             :     /* clang-format on */
    1973             : 
    1974             :   /* VoteSwitch
    1975             :    *
    1976             :    * Instruction:
    1977             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L81
    1978             :    *
    1979             :    * Processor:
    1980             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L154
    1981             :    */
    1982           0 :   case fd_vote_instruction_enum_vote_switch: {
    1983           0 :     if( FD_FEATURE_ACTIVE_BANK( ctx->bank, deprecate_legacy_vote_ixs ) ) {
    1984           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    1985           0 :     }
    1986             : 
    1987           0 :     fd_vote_t * vote;
    1988           0 :     if( instruction->discriminant == fd_vote_instruction_enum_vote ) {
    1989           0 :       vote = &instruction->inner.vote;
    1990           0 :     } else if( instruction->discriminant == fd_vote_instruction_enum_vote_switch ) {
    1991           0 :       vote = &instruction->inner.vote_switch.vote;
    1992           0 :     } else {
    1993           0 :       FD_LOG_CRIT(( "unsupported instruction discriminant: %u", instruction->discriminant ));
    1994           0 :     }
    1995             : 
    1996             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L155
    1997           0 :     int err;
    1998           0 :     err = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_slot_hashes_id );
    1999           0 :     if( FD_UNLIKELY( err ) ) return err;
    2000             : 
    2001           0 :     if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
    2002           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2003           0 :     }
    2004             : 
    2005             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L157
    2006           0 :     err = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id );
    2007           0 :     if( FD_UNLIKELY( err ) ) return err;
    2008           0 :     fd_sol_sysvar_clock_t clock_;
    2009           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    2010           0 :     if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2011             : 
    2012           0 :     fd_slot_hash_t const * slot_hashes = fd_sysvar_cache_slot_hashes_join_const( ctx->sysvar_cache ); /* guaranteed to succeed */
    2013           0 :     rc = process_vote_with_account(
    2014           0 :         ctx,
    2015           0 :         &me,
    2016           0 :         target_version,
    2017           0 :         slot_hashes,
    2018           0 :         clock,
    2019           0 :         vote,
    2020           0 :         signers,
    2021           0 :         signers_cnt
    2022           0 :     );
    2023           0 :     fd_sysvar_cache_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes );
    2024             : 
    2025           0 :     break;
    2026           0 :   }
    2027             : 
    2028             :   /* UpdateVoteState
    2029             :    *
    2030             :    * Instruction:
    2031             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L100
    2032             :    */
    2033           0 :   case fd_vote_instruction_enum_update_vote_state:;
    2034             :     /* clang-format off */
    2035           0 :     __attribute__((fallthrough));
    2036             :     /* clang-format on */
    2037             : 
    2038             :   /* UpdateVoteStateSwitch
    2039             :    *
    2040             :    * Instruction:
    2041             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L107
    2042             :    *
    2043             :    * Processor:
    2044             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L169
    2045             :    */
    2046           0 :   case fd_vote_instruction_enum_update_vote_state_switch: {
    2047           0 :     if( FD_FEATURE_ACTIVE_BANK( ctx->bank, deprecate_legacy_vote_ixs ) ) {
    2048           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2049           0 :     }
    2050             : 
    2051           0 :     fd_vote_state_update_t * vote_state_update;
    2052           0 :     switch( instruction->discriminant ) {
    2053           0 :     case fd_vote_instruction_enum_update_vote_state:
    2054           0 :       vote_state_update = &instruction->inner.update_vote_state;
    2055           0 :       break;
    2056           0 :     case fd_vote_instruction_enum_update_vote_state_switch:
    2057           0 :       vote_state_update = &instruction->inner.update_vote_state_switch.vote_state_update;
    2058           0 :       break;
    2059           0 :     default:
    2060           0 :       FD_LOG_CRIT(( "unsupported instruction discriminant: %u", instruction->discriminant ));
    2061           0 :     }
    2062             : 
    2063             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L171
    2064           0 :     if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
    2065           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2066           0 :     }
    2067             : 
    2068             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L172
    2069           0 :     fd_sol_sysvar_clock_t clock_;
    2070           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    2071           0 :     if( FD_UNLIKELY( !clock ) )
    2072           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2073             : 
    2074             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L173
    2075           0 :     fd_slot_hash_t const * slot_hashes = fd_sysvar_cache_slot_hashes_join_const( ctx->sysvar_cache );
    2076           0 :     rc = process_vote_state_update(
    2077           0 :         ctx,
    2078           0 :         &me,
    2079           0 :         target_version,
    2080           0 :         slot_hashes,
    2081           0 :         clock,
    2082           0 :         vote_state_update,
    2083           0 :         signers,
    2084           0 :         signers_cnt
    2085           0 :     );
    2086           0 :     fd_sysvar_cache_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes );
    2087             : 
    2088           0 :     break;
    2089           0 :   }
    2090             : 
    2091             :   /* CompactUpdateVoteState
    2092             :    *
    2093             :    * Instruction:
    2094             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L139
    2095             :    *
    2096             :    * Notes:
    2097             :    * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
    2098             :    * - Feature gated, but live on mainnet.
    2099             :    */
    2100           0 :   case fd_vote_instruction_enum_compact_update_vote_state:;
    2101           0 :     __attribute__((fallthrough));
    2102             : 
    2103             :   /* CompactUpdateVoteStateSwitch
    2104             :    *
    2105             :    * Instruction:
    2106             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L146
    2107             :    *
    2108             :    * Processor:
    2109             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L183
    2110             :    *
    2111             :    * Notes:
    2112             :    * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
    2113             :    * - Feature gated, but live on mainnet.
    2114             :    */
    2115           0 :   case fd_vote_instruction_enum_compact_update_vote_state_switch: {
    2116             :     /* https://github.com/anza-xyz/agave/blob/dc4b9dcbbf859ff48f40d00db824bde063fdafcc/programs/vote/src/vote_processor.rs#L183-L191 */
    2117           0 :     if( FD_FEATURE_ACTIVE_BANK( ctx->bank, deprecate_legacy_vote_ixs ) ) {
    2118           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2119           0 :     }
    2120             : 
    2121           0 :     fd_compact_vote_state_update_t * vote_state_update = NULL;
    2122           0 :     if( instruction->discriminant == fd_vote_instruction_enum_compact_update_vote_state ) {
    2123           0 :       vote_state_update = &instruction->inner.compact_update_vote_state;
    2124           0 :     } else if( instruction->discriminant ==
    2125           0 :                fd_vote_instruction_enum_compact_update_vote_state_switch ) {
    2126           0 :       vote_state_update =
    2127           0 :           &instruction->inner.compact_update_vote_state_switch.compact_vote_state_update;
    2128           0 :     }
    2129             : 
    2130           0 :     fd_vote_state_update_t vote_update;
    2131           0 :     fd_vote_state_update_new( &vote_update );
    2132           0 :     if( FD_UNLIKELY( !fd_vote_decode_compact_update( vote_state_update, &vote_update, ctx ) ) )
    2133           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2134             : 
    2135             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L185
    2136           0 :     if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
    2137           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2138           0 :     }
    2139             : 
    2140           0 :     fd_sol_sysvar_clock_t clock_;
    2141           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    2142           0 :     if( FD_UNLIKELY( !clock ) )
    2143           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2144             : 
    2145             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L187
    2146           0 :     fd_slot_hash_t const * slot_hashes = fd_sysvar_cache_slot_hashes_join_const( ctx->sysvar_cache ); /* guaranteed to succeed */
    2147           0 :     rc = process_vote_state_update(
    2148           0 :         ctx,
    2149           0 :         &me,
    2150           0 :         target_version,
    2151           0 :         slot_hashes,
    2152           0 :         clock,
    2153           0 :         &vote_update,
    2154           0 :         signers,
    2155           0 :         signers_cnt
    2156           0 :     );
    2157           0 :     fd_sysvar_cache_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes );
    2158             : 
    2159           0 :     break;
    2160           0 :   }
    2161             : 
    2162             :   /* TowerSync(Switch)
    2163             :    *
    2164             :    * Instruction:
    2165             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L151-L157
    2166             :    *
    2167             :    * Processor:
    2168             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L196-L215
    2169             :    */
    2170             : 
    2171           0 :   case fd_vote_instruction_enum_tower_sync:
    2172           0 :   case fd_vote_instruction_enum_tower_sync_switch: {
    2173           0 :     fd_tower_sync_t * tower_sync = (instruction->discriminant == fd_vote_instruction_enum_tower_sync)
    2174           0 :         ? &instruction->inner.tower_sync
    2175           0 :         : &instruction->inner.tower_sync_switch.tower_sync;
    2176             : 
    2177           0 :     if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
    2178           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2179           0 :     }
    2180             : 
    2181           0 :     fd_sol_sysvar_clock_t clock_;
    2182           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    2183           0 :     if( FD_UNLIKELY( !clock ) ) {
    2184           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2185           0 :     }
    2186             : 
    2187           0 :     fd_slot_hash_t const * slot_hashes = fd_sysvar_cache_slot_hashes_join_const( ctx->sysvar_cache );
    2188           0 :     FD_TEST( slot_hashes );
    2189           0 :     rc = process_tower_sync(
    2190           0 :         ctx,
    2191           0 :         &me,
    2192           0 :         target_version,
    2193           0 :         slot_hashes,
    2194           0 :         clock,
    2195           0 :         tower_sync,
    2196           0 :         signers,
    2197           0 :         signers_cnt
    2198           0 :     );
    2199           0 :     fd_sysvar_cache_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes );
    2200             : 
    2201           0 :     break;
    2202           0 :   }
    2203             : 
    2204             :   /* Withdraw
    2205             :    *
    2206             :    * Instruction:
    2207             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L57
    2208             :    *
    2209             :    * Processor:
    2210             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L216
    2211             :    */
    2212           0 :   case fd_vote_instruction_enum_withdraw: {
    2213           0 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) ) {
    2214           0 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    2215           0 :       break;
    2216           0 :     }
    2217           0 :     fd_rent_t rent_;
    2218           0 :     fd_rent_t const * rent_sysvar = fd_sysvar_cache_rent_read( ctx->sysvar_cache, &rent_ );
    2219           0 :     if( FD_UNLIKELY( !rent_sysvar ) )
    2220           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2221           0 :     fd_sol_sysvar_clock_t clock_;
    2222           0 :     fd_sol_sysvar_clock_t const * clock_sysvar = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    2223           0 :     if( FD_UNLIKELY( !clock_sysvar ) )
    2224           0 :       return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2225             : 
    2226           0 :     rc = withdraw(
    2227           0 :         ctx,
    2228           0 :         &me,
    2229           0 :         target_version,
    2230           0 :         instruction->inner.withdraw,
    2231           0 :         1UL,
    2232           0 :         signers,
    2233           0 :         signers_cnt,
    2234           0 :         rent_sysvar,
    2235           0 :         clock_sysvar
    2236           0 :     );
    2237             : 
    2238           0 :     break;
    2239           0 :   }
    2240             : 
    2241             :   /* AuthorizeChecked
    2242             :    *
    2243             :    * Instruction:
    2244             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L93
    2245             :    *
    2246             :    * Processor:
    2247             :    * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L234
    2248             :    *
    2249             :    * Notes:
    2250             :    * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
    2251             :    * - Feature gated, but live on mainnet.
    2252             :    */
    2253           0 :   case fd_vote_instruction_enum_authorize_checked: {
    2254           0 :     if( FD_UNLIKELY( ctx->instr->acct_cnt < 4 ) ) {
    2255           0 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
    2256           0 :       break;
    2257           0 :     }
    2258             : 
    2259             :     // https://github.com/anza-xyz/agave/blob/v2.1.14/programs/vote/src/vote_processor.rs#L243-L245
    2260           0 :     fd_pubkey_t const * voter_pubkey = NULL;
    2261           0 :     rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 3UL, &voter_pubkey );
    2262           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    2263             : 
    2264             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L239
    2265           0 :     if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, 3, &rc ) ) ) {
    2266             :       /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
    2267           0 :       if( FD_UNLIKELY( !!rc ) ) break;
    2268             : 
    2269           0 :       rc = FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
    2270           0 :       break;
    2271           0 :     }
    2272             : 
    2273             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L242
    2274           0 :     rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id );
    2275           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    2276           0 :     fd_sol_sysvar_clock_t clock_;
    2277           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    2278           0 :     if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2279             : 
    2280           0 :     rc = authorize(
    2281           0 :         ctx,
    2282           0 :         &me,
    2283           0 :         target_version,
    2284           0 :         voter_pubkey,
    2285           0 :         instruction->inner.authorize_checked,
    2286           0 :         signers,
    2287           0 :         signers_cnt,
    2288           0 :         clock,
    2289           0 :         is_vote_authorize_with_bls_enabled
    2290           0 :     );
    2291           0 :     break;
    2292           0 :   }
    2293             : 
    2294             :   /* InitializeAccountV2
    2295             :    *
    2296             :    * Instruction:
    2297             :    * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L195-L200
    2298             :    *
    2299             :    * Processor:
    2300             :    * https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L307-L324
    2301             :    *
    2302             :    * Notes:
    2303             :    * - The code is identical to InitializeAccount, except calling the actual initialize_account_v2
    2304             :    * - Feature gated.
    2305             :    */
    2306           6 :   case fd_vote_instruction_enum_initialize_account_v2: {
    2307             :     /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L308-L310 */
    2308           6 :     if( FD_UNLIKELY( !is_init_account_v2_enabled ) ) {
    2309           6 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2310           6 :     }
    2311             : 
    2312           0 :     rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_rent_id );
    2313           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    2314           0 :     fd_rent_t rent_;
    2315           0 :     fd_rent_t const * rent = fd_sysvar_cache_rent_read( ctx->sysvar_cache, &rent_ );
    2316           0 :     if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2317             : 
    2318           0 :     if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &me ) <
    2319           0 :                      fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( &me ) ) ) )
    2320           0 :       return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
    2321             : 
    2322           0 :     rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id );
    2323           0 :     if( FD_UNLIKELY( rc ) ) return rc;
    2324           0 :     fd_sol_sysvar_clock_t clock_;
    2325           0 :     fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
    2326           0 :     if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
    2327             : 
    2328           0 :     rc = initialize_account_v2( ctx, &me, target_version, &instruction->inner.initialize_account_v2, signers, signers_cnt, clock );
    2329             : 
    2330           0 :     break;
    2331           0 :   }
    2332             : 
    2333             :   /* UpdateCommissionBps (commission_rate_in_basis_points feature)
    2334             :    *
    2335             :    * Instruction:
    2336             :    * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L212-L221
    2337             :    *
    2338             :    * Processor:
    2339             :    * https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L325-L347
    2340             :    *
    2341             :    * Notes:
    2342             :    * - Unimplemented
    2343             :    */
    2344           0 :   case fd_vote_instruction_enum_update_commission_bps: {
    2345           0 :     if( FD_UNLIKELY( !commission_rate_in_basis_points
    2346           0 :                   || !delay_commission_updates
    2347           0 :                   || target_version!=VOTE_STATE_TARGET_VERSION_V4 ) ) {
    2348           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2349           0 :     }
    2350             : 
    2351             :     /* TODO: fill in when implementing commission_rate_in_basis_points */
    2352           0 :     FD_LOG_CRIT(( "unimplemented: update_commission_bps" ));
    2353           0 :   }
    2354             : 
    2355             :   /* UpdateCommissionCollector
    2356             :    *
    2357             :    * Instruction:
    2358             :    * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L202-L210
    2359             :    *
    2360             :    * Processor:
    2361             :    * https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L348-L376
    2362             :    *
    2363             :    * Notes:
    2364             :    * - Unimplemented (gated on custom_commission_collector)
    2365             :    */
    2366           0 :   case fd_vote_instruction_enum_update_commission_collector: {
    2367           0 :     if( FD_UNLIKELY( !(custom_commission_collector
    2368           0 :                     && target_version==VOTE_STATE_TARGET_VERSION_V4) ) ) {
    2369           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2370           0 :     }
    2371             : 
    2372             :     /* TODO: fill in when implementing custom_commission_collector */
    2373           0 :     FD_LOG_CRIT(( "unimplemented: update_commission_collector" ));
    2374           0 :   }
    2375             : 
    2376             :   /* DepositDelegatorRewards
    2377             :    *
    2378             :    * Instruction:
    2379             :    * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L223-L228
    2380             :    *
    2381             :    * Processor:
    2382             :    * https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L377-L395
    2383             :    *
    2384             :    * Notes:
    2385             :    * - Unimplemented (gated on block_revenue_sharing)
    2386             :    */
    2387           0 :   case fd_vote_instruction_enum_deposit_delegator_rewards: {
    2388           0 :     if( FD_UNLIKELY( !commission_rate_in_basis_points
    2389           0 :                   || !custom_commission_collector
    2390           0 :                   || !block_revenue_sharing
    2391           0 :                   || target_version!=VOTE_STATE_TARGET_VERSION_V4 ) ) {
    2392           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
    2393           0 :     }
    2394             : 
    2395             :     /* TODO: fill in when implementing block_revenue_sharing */
    2396           0 :     FD_LOG_CRIT(( "unimplemented: deposit_delegator_rewards" ));
    2397           0 :   }
    2398             : 
    2399           0 :   default:
    2400           0 :     FD_LOG_CRIT(( "unsupported vote instruction: %u", instruction->discriminant ));
    2401          12 :   }
    2402             : 
    2403           6 :   return rc;
    2404          12 : }
    2405             : 
    2406             : /**********************************************************************/
    2407             : /* Public API                                                         */
    2408             : /**********************************************************************/
    2409             : 
    2410             : /* TODO: Old code, remove whenever stake program gets cleaned up */
    2411             : void
    2412             : fd_vote_convert_to_current( fd_vote_state_versioned_t * self,
    2413           0 :                             uchar *                     landed_votes_mem ) {
    2414           0 :   fd_vsv_try_convert_to_v3( self, landed_votes_mem );
    2415           0 : }
    2416             : 
    2417             : fd_vote_state_versioned_t *
    2418             : fd_vote_get_state( fd_account_meta_t const * self,
    2419           0 :                    uchar *                   mem ) {
    2420           0 :   int err = fd_vsv_get_state( self, mem );
    2421           0 :   return err ? NULL : (fd_vote_state_versioned_t *)mem;
    2422           0 : }

Generated by: LCOV version 1.14