LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_vote_program.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 1115 1430 78.0 %
Date: 2026-11-11 12:40:43 Functions: 23 30 76.7 %

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

Generated by: LCOV version 1.14