LCOV - code coverage report
Current view: top level - flamenco/runtime/program/vote - fd_vote_state_versioned.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 338 619 54.6 %
Date: 2026-11-11 12:40:43 Functions: 34 41 82.9 %

          Line data    Source code
       1             : #include "fd_vote_state_versioned.h"
       2             : #include "fd_vote_codec_tmpl.h"
       3             : #include "fd_vote_utils.h"
       4             : #include "fd_vote_state_v3.h"
       5             : #include "fd_vote_state_v4.h"
       6             : #include "fd_vote_state_v5.h"
       7             : #include "fd_authorized_voters.h"
       8             : #include "../fd_vote_program.h"
       9             : #include "../../fd_runtime.h"
      10             : #include "../../fd_system_ids.h"
      11             : 
      12             : /* https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L42 */
      13             : #define DEFAULT_PRIOR_VOTERS_OFFSET 114
      14             : 
      15             : /* https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L886 */
      16             : #define VERSION_OFFSET (4UL)
      17             : 
      18             : /* https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L887 */
      19             : #define DEFAULT_PRIOR_VOTERS_END (118)
      20             : 
      21             : /* https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L6 */
      22             : #define DEFAULT_PRIOR_VOTERS_OFFSET_1_14_11 (82UL)
      23             : 
      24             : /* https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L60 */
      25             : #define DEFAULT_PRIOR_VOTERS_END_1_14_11 (86UL)
      26             : 
      27             : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L780-L785 */
      28             : static inline fd_vote_lockout_t *
      29       34589 : last_lockout( fd_vote_state_versioned_t * self ) {
      30       34589 :   fd_landed_vote_t * votes = NULL;
      31       34589 :   switch( self->kind ) {
      32           0 :     case fd_vote_state_versioned_enum_v3:
      33           0 :       votes = self->v3.votes;
      34           0 :       break;
      35       34592 :     case fd_vote_state_versioned_enum_v4:
      36       34592 :       votes = self->v4.votes;
      37       34592 :       break;
      38           0 :     default:
      39           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
      40       34589 :   }
      41             : 
      42       34592 :   if( deq_fd_landed_vote_t_empty( votes ) ) return NULL;
      43       33834 :   fd_landed_vote_t * last_vote = deq_fd_landed_vote_t_peek_tail( votes );
      44       33834 :   return &last_vote->lockout;
      45       34592 : }
      46             : 
      47             : /**********************************************************************/
      48             : /* Getters                                                            */
      49             : /**********************************************************************/
      50             : 
      51             : int
      52             : fd_vsv_get_state( fd_acc_t const *            acc,
      53        4013 :                   fd_vote_state_versioned_t * versioned ) {
      54        4013 :   if( FD_UNLIKELY( !fd_vote_state_versioned_deserialize( versioned, acc->data, acc->data_len ) ) ) {
      55         528 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      56         528 :   }
      57             : 
      58        3485 :   return FD_EXECUTOR_INSTR_SUCCESS;
      59        4013 : }
      60             : 
      61             : int
      62             : fd_vsv_deserialize( fd_acc_t const *            acc,
      63        3850 :                     fd_vote_state_versioned_t * versioned ) {
      64        3850 :   int rc = fd_vsv_get_state( acc, versioned );
      65        3850 :   if( FD_UNLIKELY( rc ) ) return rc;
      66             : 
      67        3322 :   if( FD_UNLIKELY( versioned->kind==fd_vote_state_versioned_enum_uninitialized ) ) {
      68         658 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      69         658 :   }
      70             : 
      71        2664 :   return FD_EXECUTOR_INSTR_SUCCESS;
      72        3322 : }
      73             : 
      74             : fd_pubkey_t const *
      75        1220 : fd_vsv_get_authorized_withdrawer( fd_vote_state_versioned_t * self ) {
      76        1220 :   switch( self->kind ) {
      77           0 :     case fd_vote_state_versioned_enum_v1_14_11:
      78           0 :       return &self->v1_14_11.authorized_withdrawer;
      79           0 :     case fd_vote_state_versioned_enum_v3:
      80           0 :       return &self->v3.authorized_withdrawer;
      81        1220 :     case fd_vote_state_versioned_enum_v4:
      82        1220 :       return &self->v4.authorized_withdrawer;
      83           0 :     case fd_vote_state_versioned_enum_v5:
      84           0 :       return &self->v5.authorized_withdrawer;
      85           0 :     default:
      86           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
      87        1220 :   }
      88        1220 : }
      89             : 
      90             : static ushort
      91             : v5_latest_commission_bps( fd_vote_state_v5_t const * v5,
      92           0 :                           uint                       kind ) {
      93           0 :   fd_vote_state_v5_commission_t c;
      94           0 :   fd_vote_state_v5_commission_get( v5, kind, &c );
      95           0 :   return fd_vote_state_v5_commission_latest( &c );
      96           0 : }
      97             : 
      98             : static void
      99             : v5_schedule_commission( fd_vote_state_v5_t * v5,
     100             :                         uint                 kind,
     101             :                         ulong                current_epoch,
     102           0 :                         ushort               bps ) {
     103           0 :   fd_vote_state_v5_commission_t c;
     104           0 :   fd_vote_state_v5_commission_get( v5, kind, &c );
     105           0 :   fd_vote_state_v5_commission_schedule( &c, current_epoch+2UL, bps );
     106           0 :   fd_vote_state_v5_commission_set( v5, kind, &c );
     107           0 : }
     108             : 
     109             : uchar
     110           0 : fd_vsv_get_commission( fd_vote_state_versioned_t * self ) {
     111           0 :   switch( self->kind ) {
     112           0 :     case fd_vote_state_versioned_enum_v3:
     113           0 :       return self->v3.commission;
     114           0 :     case fd_vote_state_versioned_enum_v4:
     115           0 :       return (uchar)fd_ushort_min( (ushort)UCHAR_MAX, (ushort)( self->v4.inflation_rewards_commission_bps/100 ) );
     116           0 :     case fd_vote_state_versioned_enum_v5:
     117           0 :       return (uchar)fd_ushort_min( (ushort)UCHAR_MAX, (ushort)( v5_latest_commission_bps( &self->v5, fd_commission_kind_enum_inflation_rewards )/100 ) );
     118           0 :     default:
     119           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     120           0 :   }
     121           0 : }
     122             : 
     123             : fd_vote_epoch_credits_t const *
     124           9 : fd_vsv_get_epoch_credits( fd_vote_state_versioned_t * self ) {
     125           9 :   return fd_vsv_get_epoch_credits_mutable( self );
     126           9 : }
     127             : 
     128             : fd_vote_epoch_credits_t const *
     129           9 : fd_vsv_get_last_epoch_credits( fd_vote_state_versioned_t * self ) {
     130           9 :   if( self->kind==fd_vote_state_versioned_enum_v5 ) {
     131           0 :     ulong cnt = self->v5.accumulated_lamports_len;
     132           0 :     return cnt ? &self->v5.accumulated_lamports[ cnt-1UL ] : NULL;
     133           0 :   }
     134           9 :   fd_vote_epoch_credits_t const * epoch_credits = fd_vsv_get_epoch_credits( self );
     135           9 :   if( deq_fd_vote_epoch_credits_t_empty( epoch_credits ) ) return NULL;
     136           6 :   return deq_fd_vote_epoch_credits_t_peek_tail_const( epoch_credits );
     137           9 : }
     138             : 
     139             : fd_landed_vote_t const *
     140         377 : fd_vsv_get_votes( fd_vote_state_versioned_t * self ) {
     141         377 :   return fd_vsv_get_votes_mutable( self );
     142         377 : }
     143             : 
     144             : ulong const *
     145       34588 : fd_vsv_get_last_voted_slot( fd_vote_state_versioned_t * self ) {
     146       34588 :   fd_vote_lockout_t * last_lockout_ = last_lockout( self );
     147       34588 :   if( FD_UNLIKELY( !last_lockout_ ) ) return NULL;
     148       33830 :   return &last_lockout_->slot;
     149       34588 : }
     150             : 
     151             : ulong const *
     152         719 : fd_vsv_get_root_slot( fd_vote_state_versioned_t * self ) {
     153         719 :   switch( self->kind ) {
     154           0 :     case fd_vote_state_versioned_enum_v3:
     155           0 :       if( !self->v3.has_root_slot ) return NULL;
     156           0 :       return &self->v3.root_slot;
     157         719 :     case fd_vote_state_versioned_enum_v4:
     158         719 :       if( !self->v4.has_root_slot ) return NULL;
     159         341 :       return &self->v4.root_slot;
     160           0 :     default:
     161           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     162         719 :   }
     163         719 : }
     164             : 
     165             : fd_vote_block_timestamp_t const *
     166         234 : fd_vsv_get_last_timestamp( fd_vote_state_versioned_t * self ) {
     167         234 :   switch( self->kind ) {
     168           0 :     case fd_vote_state_versioned_enum_v3:
     169           0 :       return &self->v3.last_timestamp;
     170         234 :     case fd_vote_state_versioned_enum_v4:
     171         234 :       return &self->v4.last_timestamp;
     172           0 :     default:
     173           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     174         234 :   }
     175         234 : }
     176             : 
     177             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L938 */
     178             : int
     179         238 : fd_vsv_has_bls_pubkey( fd_vote_state_versioned_t * self ) {
     180         238 :   switch( self->kind ) {
     181           0 :     case fd_vote_state_versioned_enum_uninitialized:
     182           0 :       return 0;
     183           0 :     case fd_vote_state_versioned_enum_v1_14_11:
     184           0 :       return 0;
     185           0 :     case fd_vote_state_versioned_enum_v3:
     186             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L483 */
     187           0 :       return 0;
     188         238 :     case fd_vote_state_versioned_enum_v4:
     189             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L676 */
     190         238 :       return !!self->v4.has_bls_pubkey_compressed;
     191           0 :     case fd_vote_state_versioned_enum_v5:
     192           0 :       return 1;
     193           0 :     default:
     194           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     195         238 :   }
     196         238 : }
     197             : 
     198             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L823-L828 */
     199             : ulong
     200         178 : fd_vsv_get_pending_delegator_rewards( fd_vote_state_versioned_t * self ) {
     201         178 :   switch( self->kind ) {
     202           0 :     case fd_vote_state_versioned_enum_v3:
     203           0 :       return 0UL;
     204         178 :     case fd_vote_state_versioned_enum_v4:
     205         178 :       return self->v4.pending_delegator_rewards;
     206           0 :     case fd_vote_state_versioned_enum_v5:
     207           0 :       return self->v5.pending_delegator_rewards;
     208           0 :     default:
     209           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     210         178 :   }
     211         178 : }
     212             : 
     213             : /**********************************************************************/
     214             : /* Mutable getters                                                    */
     215             : /**********************************************************************/
     216             : 
     217             : fd_vote_epoch_credits_t *
     218        7311 : fd_vsv_get_epoch_credits_mutable( fd_vote_state_versioned_t * self ) {
     219        7311 :   switch( self->kind ) {
     220           0 :     case fd_vote_state_versioned_enum_v3:
     221           0 :       return self->v3.epoch_credits;
     222        7310 :     case fd_vote_state_versioned_enum_v4:
     223        7310 :       return self->v4.epoch_credits;
     224           0 :     default:
     225           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     226        7311 :   }
     227        7311 : }
     228             : 
     229             : fd_landed_vote_t *
     230       48797 : fd_vsv_get_votes_mutable( fd_vote_state_versioned_t * self ) {
     231       48797 :   switch( self->kind ) {
     232           0 :     case fd_vote_state_versioned_enum_v3:
     233           0 :       return self->v3.votes;
     234       48798 :     case fd_vote_state_versioned_enum_v4:
     235       48798 :       return self->v4.votes;
     236           0 :     default:
     237           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     238       48797 :   }
     239       48797 : }
     240             : 
     241             : /**********************************************************************/
     242             : /* Setters                                                            */
     243             : /**********************************************************************/
     244             : 
     245             : int
     246             : fd_vsv_set_state( fd_borrowed_account_t *     self,
     247        1086 :                   fd_vote_state_versioned_t * state ) {
     248             :   /* https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L974 */
     249        1086 :   uchar * data = NULL;
     250        1086 :   ulong   dlen = 0UL;
     251        1086 :   int err = fd_borrowed_account_get_data_mut( self, &data, &dlen );
     252        1086 :   if( FD_UNLIKELY( err ) ) {
     253           0 :     return err;
     254           0 :   }
     255             : 
     256             :   /* Note that although the serialization method already performs bounds
     257             :      checks, the account data buffer should remain unmodified if the
     258             :      serialization would fail.
     259             :      https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L978 */
     260        1086 :   ulong serialized_size = fd_vote_state_versioned_serialized_size( state );
     261        1086 :   if( FD_UNLIKELY( serialized_size>dlen ) ) {
     262           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
     263           0 :   }
     264             : 
     265             :   /* https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/src/transaction_context.rs#L983 */
     266        1086 :   if( FD_UNLIKELY( fd_vote_state_versioned_serialize( state, data, dlen ) ) ) {
     267           0 :     FD_LOG_CRIT(( "invariant violation: fd_vote_state_versioned_serialize failed" ));
     268           0 :   }
     269             : 
     270        1086 :   return FD_EXECUTOR_INSTR_SUCCESS;
     271        1086 : }
     272             : 
     273             : int
     274             : fd_vsv_set_vote_account_state( fd_exec_instr_ctx_t const * ctx,
     275             :                                fd_borrowed_account_t *     vote_account,
     276         931 :                                fd_vote_state_versioned_t * versioned ) {
     277         931 :   switch( versioned->kind ) {
     278           0 :     case fd_vote_state_versioned_enum_v3:
     279           0 :       return fd_vote_state_v3_set_vote_account_state( ctx, vote_account, versioned );
     280         931 :     case fd_vote_state_versioned_enum_v4:
     281         931 :       return fd_vote_state_v4_set_vote_account_state( ctx, vote_account, versioned );
     282           0 :     case fd_vote_state_versioned_enum_v5:
     283           0 :       return fd_vsv_set_state( vote_account, versioned );
     284           0 :     default:
     285           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", versioned->kind ));
     286         931 :   }
     287         931 : }
     288             : 
     289             : void
     290             : fd_vsv_set_authorized_withdrawer( fd_vote_state_versioned_t * self,
     291         130 :                                   fd_pubkey_t const *         authorized_withdrawer ) {
     292         130 :   switch( self->kind ) {
     293           0 :     case fd_vote_state_versioned_enum_v3: {
     294           0 :       self->v3.authorized_withdrawer = *authorized_withdrawer;
     295           0 :       break;
     296           0 :     }
     297         130 :     case fd_vote_state_versioned_enum_v4: {
     298         130 :       self->v4.authorized_withdrawer = *authorized_withdrawer;
     299         130 :       break;
     300           0 :     }
     301           0 :     case fd_vote_state_versioned_enum_v5: {
     302           0 :       self->v5.authorized_withdrawer = *authorized_withdrawer;
     303           0 :       break;
     304           0 :     }
     305           0 :     default:
     306           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     307         130 :   }
     308         130 : }
     309             : 
     310             : int
     311             : fd_vsv_set_new_authorized_voter( fd_exec_instr_ctx_t *       ctx,
     312             :                                  fd_vote_state_versioned_t * self,
     313             :                                  fd_pubkey_t const *         authorized_pubkey,
     314             :                                  ulong                       current_epoch,
     315             :                                  ulong                       target_epoch,
     316             :                                  uchar const *               bls_pubkey,
     317             :                                  int                         authorized_withdrawer_signer,
     318             :                                  fd_pubkey_t const *         signers[ FD_INSTR_SIGNERS_MAX ],
     319         215 :                                  ulong                       signers_cnt ) {
     320         215 :   switch( self->kind ) {
     321           0 :     case fd_vote_state_versioned_enum_v3:
     322           0 :       return fd_vote_state_v3_set_new_authorized_voter(
     323           0 :           ctx,
     324           0 :           &self->v3,
     325           0 :           authorized_pubkey,
     326           0 :           current_epoch,
     327           0 :           target_epoch,
     328           0 :           bls_pubkey,
     329           0 :           authorized_withdrawer_signer,
     330           0 :           signers,
     331           0 :           signers_cnt
     332           0 :       );
     333         215 :     case fd_vote_state_versioned_enum_v4:
     334         215 :       return fd_vote_state_v4_set_new_authorized_voter(
     335         215 :           ctx,
     336         215 :           &self->v4,
     337         215 :           authorized_pubkey,
     338         215 :           current_epoch,
     339         215 :           target_epoch,
     340         215 :           bls_pubkey,
     341         215 :           authorized_withdrawer_signer,
     342         215 :           signers,
     343         215 :           signers_cnt
     344         215 :       );
     345           0 :     case fd_vote_state_versioned_enum_v5:
     346           0 :       return fd_vote_state_v5_set_new_authorized_voter(
     347           0 :           ctx,
     348           0 :           &self->v5,
     349           0 :           authorized_pubkey,
     350           0 :           current_epoch,
     351           0 :           target_epoch,
     352           0 :           bls_pubkey,
     353           0 :           authorized_withdrawer_signer,
     354           0 :           signers,
     355           0 :           signers_cnt
     356           0 :       );
     357           0 :     default:
     358           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     359         215 :   }
     360         215 : }
     361             : 
     362             : void
     363             : fd_vsv_set_node_pubkey( fd_vote_state_versioned_t * self,
     364         175 :                         fd_pubkey_t const *         node_pubkey ) {
     365         175 :   switch( self->kind ) {
     366           0 :     case fd_vote_state_versioned_enum_v3:
     367           0 :       self->v3.node_pubkey = *node_pubkey;
     368           0 :       break;
     369         175 :     case fd_vote_state_versioned_enum_v4:
     370         175 :       self->v4.node_pubkey = *node_pubkey;
     371         175 :       break;
     372           0 :     case fd_vote_state_versioned_enum_v5:
     373           0 :       self->v5.node_pubkey = *node_pubkey;
     374           0 :       break;
     375           0 :     default:
     376           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     377         175 :   }
     378         175 : }
     379             : 
     380             : void
     381             : fd_vsv_set_block_revenue_collector( fd_vote_state_versioned_t * self,
     382         175 :                                     fd_pubkey_t const *         block_revenue_collector ) {
     383         175 :   switch( self->kind ) {
     384         175 :     case fd_vote_state_versioned_enum_v4:
     385         175 :       self->v4.block_revenue_collector = *block_revenue_collector;
     386         175 :       break;
     387           0 :     case fd_vote_state_versioned_enum_v5:
     388           0 :       self->v5.block_revenue_collector = *block_revenue_collector;
     389           0 :       break;
     390           0 :     case fd_vote_state_versioned_enum_v3:
     391             :       /* No-op for v3 */
     392           0 :       break;
     393           0 :     default:
     394           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     395         175 :   }
     396         175 : }
     397             : 
     398             : void
     399             : fd_vsv_set_inflation_rewards_collector( fd_vote_state_versioned_t * self,
     400           0 :                                         fd_pubkey_t const *         inflation_rewards_collector ) {
     401           0 :   switch( self->kind ) {
     402           0 :     case fd_vote_state_versioned_enum_v4:
     403           0 :       self->v4.inflation_rewards_collector = *inflation_rewards_collector;
     404           0 :       break;
     405           0 :     case fd_vote_state_versioned_enum_v5:
     406           0 :       self->v5.inflation_rewards_collector = *inflation_rewards_collector;
     407           0 :       break;
     408           0 :     case fd_vote_state_versioned_enum_v3:
     409             :       /* No-op for v3 */
     410           0 :       break;
     411           0 :     default:
     412           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     413           0 :   }
     414           0 : }
     415             : 
     416             : void
     417             : fd_vsv_set_commission( fd_vote_state_versioned_t * self,
     418             :                        uchar                       commission,
     419         179 :                        ulong                       current_epoch ) {
     420         179 :   switch( self->kind ) {
     421           0 :     case fd_vote_state_versioned_enum_v3:
     422           0 :       self->v3.commission = commission;
     423           0 :       break;
     424         179 :     case fd_vote_state_versioned_enum_v4:
     425         179 :       self->v4.inflation_rewards_commission_bps = (ushort)( commission*100 );
     426         179 :       break;
     427           0 :     case fd_vote_state_versioned_enum_v5:
     428           0 :       v5_schedule_commission( &self->v5, fd_commission_kind_enum_inflation_rewards, current_epoch, (ushort)( commission*100 ) );
     429           0 :       break;
     430           0 :     default:
     431           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     432         179 :   }
     433         179 : }
     434             : 
     435             : void
     436             : fd_vsv_set_inflation_rewards_commission_bps( fd_vote_state_versioned_t * self,
     437             :                                              ushort                      commission_bps,
     438           0 :                                              ulong                       current_epoch ) {
     439           0 :   switch( self->kind ) {
     440           0 :     case fd_vote_state_versioned_enum_v4:
     441           0 :       self->v4.inflation_rewards_commission_bps = commission_bps;
     442           0 :       break;
     443           0 :     case fd_vote_state_versioned_enum_v5:
     444           0 :       v5_schedule_commission( &self->v5, fd_commission_kind_enum_inflation_rewards, current_epoch, commission_bps );
     445           0 :       break;
     446           0 :     case fd_vote_state_versioned_enum_v3:
     447             :       /* No-op for v3 */
     448           0 :       break;
     449           0 :     default:
     450           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     451           0 :   }
     452           0 : }
     453             : 
     454             : void
     455             : fd_vsv_set_block_revenue_commission_bps( fd_vote_state_versioned_t * self,
     456             :                                          ushort                      commission_bps,
     457           0 :                                          ulong                       current_epoch ) {
     458           0 :   switch( self->kind ) {
     459           0 :     case fd_vote_state_versioned_enum_v4:
     460           0 :       self->v4.block_revenue_commission_bps = commission_bps;
     461           0 :       break;
     462           0 :     case fd_vote_state_versioned_enum_v5:
     463           0 :       v5_schedule_commission( &self->v5, fd_commission_kind_enum_block_revenue, current_epoch, commission_bps );
     464           0 :       break;
     465           0 :     case fd_vote_state_versioned_enum_v3:
     466             :       /* No-op for v3 */
     467           0 :       break;
     468           0 :     default:
     469           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     470           0 :   }
     471           0 : }
     472             : 
     473             : void
     474        7373 : fd_vsv_set_root_slot( fd_vote_state_versioned_t * self, ulong * root_slot ) {
     475        7373 :   switch( self->kind ) {
     476           0 :     case fd_vote_state_versioned_enum_v3:
     477           0 :       self->v3.has_root_slot = (root_slot!=NULL);
     478           0 :       if( FD_LIKELY( root_slot ) ) {
     479           0 :         self->v3.root_slot = *root_slot;
     480           0 :       }
     481           0 :       break;
     482        7373 :     case fd_vote_state_versioned_enum_v4:
     483        7373 :       self->v4.has_root_slot = (root_slot!=NULL);
     484        7373 :       if( FD_LIKELY( root_slot ) ) {
     485        7289 :         self->v4.root_slot = *root_slot;
     486        7289 :       }
     487        7373 :       break;
     488           0 :     default:
     489           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     490        7373 :   }
     491        7373 : }
     492             : 
     493             : void
     494             : fd_vsv_set_last_timestamp( fd_vote_state_versioned_t *       self,
     495          86 :                            fd_vote_block_timestamp_t const * last_timestamp ) {
     496          86 :   switch( self->kind ) {
     497           0 :     case fd_vote_state_versioned_enum_v3:
     498           0 :       self->v3.last_timestamp = *last_timestamp;
     499           0 :       break;
     500          86 :     case fd_vote_state_versioned_enum_v4:
     501          86 :       self->v4.last_timestamp = *last_timestamp;
     502          86 :       break;
     503           0 :     default:
     504           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     505          86 :   }
     506          86 : }
     507             : 
     508             : /**********************************************************************/
     509             : /* General functions                                                  */
     510             : /**********************************************************************/
     511             : 
     512             : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L855
     513             : static void
     514       16044 : double_lockouts( fd_vote_state_versioned_t * self ) {
     515       16044 :   fd_landed_vote_t * votes = fd_vsv_get_votes_mutable( self );
     516             : 
     517             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L856
     518       16044 :   ulong stack_depth = deq_fd_landed_vote_t_cnt( votes );
     519       16044 :   ulong i           = 0;
     520             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L857
     521       16044 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( votes );
     522      373575 :        !deq_fd_landed_vote_t_iter_done( votes, iter );
     523      357531 :        iter = deq_fd_landed_vote_t_iter_next( votes, iter ) ) {
     524      357531 :     fd_landed_vote_t * v = deq_fd_landed_vote_t_iter_ele( votes, iter );
     525             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L860
     526      357531 :     if( stack_depth >
     527      357531 :         fd_ulong_checked_add_expect(
     528      357531 :             i,
     529      357531 :             (ulong)v->lockout.confirmation_count,
     530      357531 :             "`confirmation_count` and tower_size should be bounded by `MAX_LOCKOUT_HISTORY`" ) )
     531      357811 :       {
     532             :         // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L864
     533      357811 :         fd_vote_lockout_increase_confirmation_count( &v->lockout, 1 );
     534      357811 :       }
     535      357531 :     i++;
     536      357531 :   }
     537       16044 : }
     538             : 
     539             : void
     540             : fd_vsv_increment_credits( fd_vote_state_versioned_t * self,
     541             :                           ulong                       epoch,
     542        7302 :                           ulong                       credits ) {
     543        7302 :   fd_vote_epoch_credits_t * epoch_credits = fd_vsv_get_epoch_credits_mutable( self );
     544             : 
     545             :   /* https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v3.0.0/vote-interface/src/state/vote_state_v3.rs#L286-L305 */
     546        7302 :   if( FD_UNLIKELY( deq_fd_vote_epoch_credits_t_empty( epoch_credits ) ) ) {
     547             :     /* https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v3.0.0/vote-interface/src/state/vote_state_v3.rs#L286-L288 */
     548           2 :     deq_fd_vote_epoch_credits_t_push_tail_wrap(
     549           2 :         epoch_credits,
     550           2 :         ( fd_vote_epoch_credits_t ){ .epoch = epoch, .credits = 0, .prev_credits = 0 } );
     551        7300 :   } else if( FD_LIKELY( epoch !=
     552        7300 :                         deq_fd_vote_epoch_credits_t_peek_tail( epoch_credits )->epoch ) ) {
     553             :     /* https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v3.0.0/vote-interface/src/state/vote_state_v3.rs#L290 */
     554         297 :     fd_vote_epoch_credits_t * last = deq_fd_vote_epoch_credits_t_peek_tail( epoch_credits );
     555             : 
     556         297 :     ulong credits      = last->credits;
     557         297 :     ulong prev_credits = last->prev_credits;
     558             : 
     559             :     /* https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v3.0.0/vote-interface/src/state/vote_state_v3.rs#L292-L299 */
     560         297 :     if( FD_LIKELY( credits!=prev_credits ) ) {
     561         294 :       if( FD_UNLIKELY( deq_fd_vote_epoch_credits_t_cnt( epoch_credits )>=MAX_EPOCH_CREDITS_HISTORY ) ) {
     562             :         /* Although Agave performs a `.remove(0)` AFTER the call to
     563             :           `.push()`, there is an edge case where the epoch credits is
     564             :           full, making the call to `_push_tail()` unsafe. Since Agave's
     565             :           structures are dynamically allocated, it is safe for them to
     566             :           simply call `.push()` and then popping afterwards. We have to
     567             :           reverse the order of operations to maintain correct behavior
     568             :           and avoid overflowing the deque.
     569             :           https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v3.0.0/vote-interface/src/state/vote_state_v3.rs#L303 */
     570           3 :         deq_fd_vote_epoch_credits_t_pop_head( epoch_credits );
     571           3 :       }
     572             : 
     573             :       /* This will not fail because we already popped if we're at
     574             :          capacity, since the epoch_credits deque is allocated with a
     575             :          minimum capacity of MAX_EPOCH_CREDITS_HISTORY. */
     576         294 :       deq_fd_vote_epoch_credits_t_push_tail(
     577         294 :           epoch_credits,
     578         294 :           ( fd_vote_epoch_credits_t ){
     579         294 :               .epoch = epoch, .credits = credits, .prev_credits = credits } );
     580         294 :     } else {
     581             :       /* https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v3.0.0/vote-interface/src/state/vote_state_v3.rs#L297-L298 */
     582           3 :       deq_fd_vote_epoch_credits_t_peek_tail( epoch_credits )->epoch = epoch;
     583             : 
     584             :       /* Here we can perform the same deque size check and pop if
     585             :          we're beyond the maximum epoch credits len. */
     586           3 :       if( FD_UNLIKELY( deq_fd_vote_epoch_credits_t_cnt( epoch_credits )>MAX_EPOCH_CREDITS_HISTORY ) ) {
     587           0 :         deq_fd_vote_epoch_credits_t_pop_head( epoch_credits );
     588           0 :       }
     589           3 :     }
     590         297 :   }
     591             : 
     592             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L663
     593        7302 :   deq_fd_vote_epoch_credits_t_peek_tail( epoch_credits )->credits = fd_ulong_sat_add(
     594        7302 :       deq_fd_vote_epoch_credits_t_peek_tail( epoch_credits )->credits, credits );
     595        7302 : }
     596             : 
     597             : int
     598             : fd_vsv_process_timestamp( fd_exec_instr_ctx_t *       ctx,
     599             :                           fd_vote_state_versioned_t * self,
     600             :                           ulong                       slot,
     601         234 :                           long                        timestamp ) {
     602             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L160 */
     603         234 :   fd_vote_block_timestamp_t const * last_timestamp = fd_vsv_get_last_timestamp( self );
     604         234 :   if( FD_UNLIKELY(
     605         234 :           ( slot<last_timestamp->slot || timestamp<last_timestamp->timestamp ) ||
     606         234 :           ( slot==last_timestamp->slot &&
     607         234 :             ( slot!=last_timestamp->slot || timestamp!=last_timestamp->timestamp ) &&
     608         234 :             last_timestamp->slot!=0UL ) ) ) {
     609         148 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_TIMESTAMP_TOO_OLD;
     610         148 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     611         148 :   }
     612             : 
     613             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L168 */
     614          86 :   fd_vote_block_timestamp_t new_timestamp = {
     615          86 :     .slot = slot,
     616          86 :     .timestamp = timestamp,
     617          86 :   };
     618          86 :   fd_vsv_set_last_timestamp( self, &new_timestamp );
     619          86 :   return FD_EXECUTOR_INSTR_SUCCESS;
     620         234 : }
     621             : 
     622             : void
     623       16053 : fd_vsv_pop_expired_votes( fd_vote_state_versioned_t * self, ulong next_vote_slot ) {
     624       16053 :   fd_landed_vote_t * votes = fd_vsv_get_votes_mutable( self );
     625             : 
     626       20906 :   while( !deq_fd_landed_vote_t_empty( votes ) ) {
     627       20585 :     fd_landed_vote_t * vote = deq_fd_landed_vote_t_peek_tail( votes );
     628       20585 :     if( !( fd_vote_lockout_is_locked_out_at_slot( &vote->lockout, next_vote_slot ) ) ) {
     629        4853 :       deq_fd_landed_vote_t_pop_tail( votes );
     630       15732 :     } else {
     631       15732 :       break;
     632       15732 :     }
     633       20585 :   }
     634       16053 : }
     635             : 
     636             : void
     637             : fd_vsv_process_next_vote_slot( fd_vote_state_versioned_t * self,
     638             :                                ulong                       next_vote_slot,
     639             :                                ulong                       epoch,
     640       16052 :                                ulong                       current_slot ) {
     641       16052 :   ulong const * last_voted_slot_ = fd_vsv_get_last_voted_slot( self );
     642       16052 :   if( FD_UNLIKELY( last_voted_slot_ && next_vote_slot <= *last_voted_slot_ ) ) return;
     643             : 
     644       16052 :   fd_vsv_pop_expired_votes( self, next_vote_slot );
     645             : 
     646       16052 :   fd_landed_vote_t * votes = fd_vsv_get_votes_mutable( self );
     647             : 
     648       16052 :   fd_landed_vote_t landed_vote = {
     649       16052 :     .latency = fd_vote_compute_vote_latency( next_vote_slot, current_slot ),
     650       16052 :     .lockout = ( fd_vote_lockout_t ){ .slot = next_vote_slot }
     651       16052 :   };
     652             : 
     653             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L623
     654       16052 :   if( FD_UNLIKELY( deq_fd_landed_vote_t_cnt( votes ) == MAX_LOCKOUT_HISTORY ) ) {
     655        7251 :     ulong            credits     = fd_vote_credits_for_vote_at_index( votes, 0 );
     656        7251 :     fd_landed_vote_t landed_vote = deq_fd_landed_vote_t_pop_head( votes );
     657        7251 :     fd_vsv_set_root_slot( self, &landed_vote.lockout.slot );
     658             : 
     659        7251 :     fd_vsv_increment_credits( self, epoch, credits );
     660        7251 :   }
     661             : 
     662             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L634
     663       16052 :   deq_fd_landed_vote_t_push_tail_wrap( votes, landed_vote );
     664       16052 :   double_lockouts( self );
     665       16052 : }
     666             : 
     667             : int
     668             : fd_vsv_try_convert_to_v4( fd_vote_state_versioned_t * self,
     669        2600 :                           fd_pubkey_t const *         vote_pubkey ) {
     670        2600 :   switch( self->kind ) {
     671             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L971-L974 */
     672           0 :     case fd_vote_state_versioned_enum_uninitialized: {
     673           0 :       return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
     674           0 :     }
     675             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L975-L989 */
     676         102 :     case fd_vote_state_versioned_enum_v1_14_11: {
     677         102 :       fd_vote_state_1_14_11_t * state = &self->v1_14_11;
     678             : 
     679             :       /* Temporary to hold v4. Note that since v1_14_11 and v3/v4 use
     680             :          the same underlying types for votes, we can just directly set
     681             :          it and avoid an intermediate call to
     682             :          fd_vote_lockout_landed_votes_from_lockouts. */
     683         102 :       fd_vote_state_v4_t v4 = {
     684         102 :         .node_pubkey                      = state->node_pubkey,
     685         102 :         .authorized_withdrawer            = state->authorized_withdrawer,
     686         102 :         .inflation_rewards_collector      = *vote_pubkey,
     687         102 :         .block_revenue_collector          = state->node_pubkey,
     688         102 :         .inflation_rewards_commission_bps = fd_ushort_sat_mul( state->commission, 100 ),
     689         102 :         .block_revenue_commission_bps     = FD_VOTE_DEFAULT_BLOCK_REVENUE_COMMISSION_BPS,
     690         102 :         .pending_delegator_rewards        = 0,
     691         102 :         .has_bls_pubkey_compressed        = 0,
     692         102 :         .votes                            = state->votes,
     693         102 :         .has_root_slot                    = state->has_root_slot,
     694         102 :         .root_slot                        = state->root_slot,
     695         102 :         .authorized_voters                = state->authorized_voters,
     696         102 :         .epoch_credits                    = state->epoch_credits,
     697         102 :         .last_timestamp                   = state->last_timestamp
     698         102 :       };
     699             : 
     700             :       /* Emplace new vote state into target */
     701         102 :       self->kind = fd_vote_state_versioned_enum_v4;
     702         102 :       self->v4   = v4;
     703             : 
     704         102 :       return FD_EXECUTOR_INSTR_SUCCESS;
     705           0 :     }
     706             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L990-L1004 */
     707        1244 :     case fd_vote_state_versioned_enum_v3: {
     708        1244 :       fd_vote_state_v3_t * state = &self->v3;
     709        1244 :       fd_vote_state_v4_t v4 = {
     710        1244 :         .node_pubkey                      = state->node_pubkey,
     711        1244 :         .authorized_withdrawer            = state->authorized_withdrawer,
     712        1244 :         .inflation_rewards_collector      = *vote_pubkey,
     713        1244 :         .block_revenue_collector          = state->node_pubkey,
     714        1244 :         .inflation_rewards_commission_bps = fd_ushort_sat_mul( state->commission, 100 ),
     715        1244 :         .block_revenue_commission_bps     = FD_VOTE_DEFAULT_BLOCK_REVENUE_COMMISSION_BPS,
     716        1244 :         .pending_delegator_rewards        = 0,
     717        1244 :         .has_bls_pubkey_compressed        = 0,
     718        1244 :         .votes                            = state->votes,
     719        1244 :         .has_root_slot                    = state->has_root_slot,
     720        1244 :         .root_slot                        = state->root_slot,
     721        1244 :         .authorized_voters                = state->authorized_voters,
     722        1244 :         .epoch_credits                    = state->epoch_credits,
     723        1244 :         .last_timestamp                   = state->last_timestamp
     724        1244 :       };
     725             : 
     726             :       /* Emplace new vote state into target */
     727        1244 :       self->kind = fd_vote_state_versioned_enum_v4;
     728        1244 :       self->v4   = v4;
     729             : 
     730        1244 :       return FD_EXECUTOR_INSTR_SUCCESS;
     731           0 :     }
     732             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L1005 */
     733        1257 :     case fd_vote_state_versioned_enum_v4:
     734        1257 :       return FD_EXECUTOR_INSTR_SUCCESS;
     735             :     /* V5 can't be converted back to V4 */
     736           0 :     case fd_vote_state_versioned_enum_v5:
     737           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     738           0 :     default:
     739           0 :       FD_LOG_CRIT(( "unsupported vote state version: %u", self->kind ));
     740        2600 :   }
     741        2600 : }
     742             : 
     743             : int
     744        1361 : fd_vsv_has_tower_votes( fd_vote_state_versioned_t const * self ) {
     745        1361 :   return self->kind!=fd_vote_state_versioned_enum_v5;
     746        1361 : }
     747             : 
     748             : int
     749             : fd_vsv_try_convert_to_v5( fd_vote_state_versioned_t * self,
     750           0 :                           ulong                       current_epoch ) {
     751           0 :   switch( self->kind ) {
     752           0 :     case fd_vote_state_versioned_enum_v5:
     753           0 :       return FD_EXECUTOR_INSTR_SUCCESS;
     754           0 :     case fd_vote_state_versioned_enum_v4: {
     755           0 :       fd_vote_state_v4_t * state   = &self->v4;
     756           0 :       ulong                av_cnt  = fd_vote_authorized_voters_treap_ele_cnt( state->authorized_voters.treap );
     757           0 :       ulong                ec_cnt  = deq_fd_vote_epoch_credits_t_cnt( state->epoch_credits );
     758           0 :       ulong                ec_skip = fd_ulong_sat_sub( ec_cnt, FD_VOTE_STATE_V5_ACCUMULATED_LAMPORTS_MAX );
     759           0 :       if( FD_UNLIKELY( !state->has_bls_pubkey_compressed ||
     760           0 :                        av_cnt>MAX_AUTHORIZED_VOTERS ) ) {
     761           0 :         return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     762           0 :       }
     763             : 
     764           0 :       fd_vote_state_v5_t v5 = {
     765           0 :         .node_pubkey                                 = state->node_pubkey,
     766           0 :         .authorized_withdrawer                       = state->authorized_withdrawer,
     767           0 :         .inflation_rewards_collector                 = state->inflation_rewards_collector,
     768           0 :         .block_revenue_collector                     = state->block_revenue_collector,
     769           0 :         .inflation_rewards_commission_bps_len        = 1,
     770           0 :         .block_revenue_commission_bps_len            = 1,
     771           0 :         .pending_delegator_rewards                   = state->pending_delegator_rewards,
     772           0 :         .inflation_rewards_commission_bps_epochs     = { current_epoch+2UL },
     773           0 :         .inflation_rewards_commission_bps            = { state->inflation_rewards_commission_bps },
     774           0 :         .block_revenue_commission_bps_epochs         = { current_epoch+2UL },
     775           0 :         .block_revenue_commission_bps                = { state->block_revenue_commission_bps },
     776           0 :         .latest_vote                                 = deq_fd_landed_vote_t_empty( state->votes ) ? ULONG_MAX : deq_fd_landed_vote_t_peek_tail_const( state->votes )->lockout.slot,
     777           0 :         .root_slot                                   = state->has_root_slot ? state->root_slot : ULONG_MAX,
     778           0 :         .authorized_voters_len                       = (uint)av_cnt,
     779           0 :         .accumulated_lamports_len                    = (uint)( ec_cnt-ec_skip ),
     780           0 :         .last_timestamp                              = state->last_timestamp,
     781           0 :         .rank_epoch                                  = ULONG_MAX,
     782           0 :         .rank                                        = USHORT_MAX
     783           0 :       };
     784           0 :       fd_memcpy( v5.bls_pubkey_compressed, state->bls_pubkey_compressed, FD_BLS_PUBKEY_COMPRESSED_SZ );
     785             : 
     786           0 :       ulong i = 0UL;
     787           0 :       for( fd_vote_authorized_voters_treap_fwd_iter_t iter = fd_vote_authorized_voters_treap_fwd_iter_init( state->authorized_voters.treap, state->authorized_voters.pool );
     788           0 :            !fd_vote_authorized_voters_treap_fwd_iter_done( iter );
     789           0 :            iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, state->authorized_voters.pool ) ) {
     790           0 :         fd_vote_authorized_voter_t const * voter = fd_vote_authorized_voters_treap_fwd_iter_ele_const( iter, state->authorized_voters.pool );
     791           0 :         v5.authorized_voters[ i++ ] = (fd_vote_state_v5_authorized_voter_t){ .epoch=voter->epoch, .pubkey=voter->pubkey };
     792           0 :       }
     793             : 
     794           0 :       i = 0UL;
     795           0 :       for( deq_fd_vote_epoch_credits_t_iter_t iter = deq_fd_vote_epoch_credits_t_iter_init( state->epoch_credits );
     796           0 :            !deq_fd_vote_epoch_credits_t_iter_done( state->epoch_credits, iter );
     797           0 :            iter = deq_fd_vote_epoch_credits_t_iter_next( state->epoch_credits, iter ) ) {
     798           0 :         if( i>=ec_skip ) v5.accumulated_lamports[ i-ec_skip ] = *deq_fd_vote_epoch_credits_t_iter_ele_const( state->epoch_credits, iter );
     799           0 :         i++;
     800           0 :       }
     801             : 
     802           0 :       self->kind = fd_vote_state_versioned_enum_v5;
     803           0 :       self->v5   = v5;
     804           0 :       return FD_EXECUTOR_INSTR_SUCCESS;
     805           0 :     }
     806           0 :     default:
     807           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     808           0 :   }
     809           0 : }
     810             : 
     811             : int
     812             : fd_vsv_deinitialize_vote_account_state( fd_exec_instr_ctx_t *   ctx,
     813             :                                         fd_borrowed_account_t * vote_account,
     814           9 :                                         int                     target_version ) {
     815             :   /* V4 clears the entire account data on deinitialize.
     816             :      https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_state/handler.rs#L366-L377 */
     817           9 :   (void)ctx;
     818           9 :   (void)target_version;
     819           9 :   uchar * data;
     820           9 :   ulong   dlen;
     821           9 :   int rc = fd_borrowed_account_get_data_mut( vote_account, &data, &dlen );
     822           9 :   if( FD_UNLIKELY( rc ) ) return rc;
     823           8 :   fd_memset( data, 0, dlen );
     824           8 :   return FD_EXECUTOR_INSTR_SUCCESS;
     825           9 : }
     826             : 
     827             : int
     828        2838 : fd_vsv_is_uninitialized( fd_vote_state_versioned_t * self ) {
     829        2838 :   switch( self->kind ) {
     830         167 :     case fd_vote_state_versioned_enum_uninitialized:
     831         167 :       return 1;
     832         145 :     case fd_vote_state_versioned_enum_v1_14_11:
     833         145 :       return fd_authorized_voters_is_empty( &self->v1_14_11.authorized_voters );
     834        1270 :     case fd_vote_state_versioned_enum_v3:
     835        1270 :       return fd_authorized_voters_is_empty( &self->v3.authorized_voters );
     836        1257 :     case fd_vote_state_versioned_enum_v4:
     837        1257 :     case fd_vote_state_versioned_enum_v5:
     838        1257 :       return 0; // v4 vote states are always initialized
     839           0 :     default:
     840           0 :       FD_LOG_CRIT(( "unsupported vote state versioned kind: %u", self->kind ));
     841        2838 :   }
     842        2838 : }
     843             : 
     844             : int
     845             : fd_vsv_is_correct_size_and_initialized( uchar const * data,
     846        1221 :                                         ulong         data_len ) {
     847             :   /* VoteStateV4::is_correct_size_and_initialized
     848             :      https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v4.0.4/vote-interface/src/state/vote_state_v4.rs#L207-L210 */
     849        1221 :   if( FD_LIKELY( data_len==FD_VOTE_STATE_V4_SZ && FD_LOAD( uint, data )==fd_vote_state_versioned_enum_v4 ) ) {
     850        1221 :     return 1;
     851        1221 :   }
     852             : 
     853           0 :   if( FD_LIKELY( data_len==FD_VOTE_STATE_V5_SZ && FD_LOAD( uint, data )==fd_vote_state_versioned_enum_v5 ) ) {
     854           0 :     return 1;
     855           0 :   }
     856             : 
     857             :   /* VoteStateV3::is_correct_size_and_initialized
     858             :      https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v4.0.4/vote-interface/src/state/vote_state_v3.rs#L509-L514 */
     859           0 :   if( FD_LIKELY( data_len==FD_VOTE_STATE_V3_SZ &&
     860           0 :                  !fd_mem_iszero( data+VERSION_OFFSET, DEFAULT_PRIOR_VOTERS_OFFSET ) ) ) {
     861           0 :     return 1;
     862           0 :   }
     863             : 
     864             :   /* VoteState1_14_11::is_correct_size_and_initialized
     865             :      https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v4.0.4/vote-interface/src/state/vote_state_1_14_11.rs#L63-L69 */
     866           0 :   if( FD_LIKELY( data_len==FD_VOTE_STATE_V2_SZ &&
     867           0 :                  !fd_mem_iszero( data+VERSION_OFFSET, DEFAULT_PRIOR_VOTERS_OFFSET_1_14_11 ) ) ) {
     868           0 :     return 1;
     869           0 :   }
     870             : 
     871           0 :   return 0;
     872           0 : }
     873             : 
     874             : int
     875             : fd_vsv_is_correct_size_owner_and_init( uchar const * owner,
     876             :                                        uchar const * data,
     877        1233 :                                        ulong         data_len ) {
     878        1233 :   if( FD_UNLIKELY( memcmp( owner, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     879          12 :     return 0;
     880          12 :   }
     881             : 
     882        1221 :   return fd_vsv_is_correct_size_and_initialized( data, data_len );
     883        1233 : }

Generated by: LCOV version 1.14