LCOV - code coverage report
Current view: top level - flamenco/runtime/program/vote - fd_vote_state_v3.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 110 0.0 %
Date: 2026-06-29 05:51:35 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #include "fd_vote_state_v3.h"
       2             : #include "fd_vote_codec.h"
       3             : #include "fd_authorized_voters.h"
       4             : #include "fd_vote_utils.h"
       5             : #include "fd_vote_state_versioned.h"
       6             : #include "../fd_vote_program.h"
       7             : #include "../../fd_runtime.h"
       8             : 
       9             : /* to_vote_state_1_14_11 converts a "v3" vote state object into the
      10             :    older "v1.14.11" version.  This destroys the "v3" object in the
      11             :    process.
      12             :    https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/vote_state_1_14_11.rs#L67 */
      13             : static void
      14             : to_vote_state_1_14_11( fd_vote_state_v3_t *      vote_state,
      15           0 :                        fd_vote_state_1_14_11_t * vote_state_1_14_11 /* out */ ) {
      16           0 :   vote_state_1_14_11->node_pubkey           = vote_state->node_pubkey;
      17           0 :   vote_state_1_14_11->authorized_withdrawer = vote_state->authorized_withdrawer;
      18           0 :   vote_state_1_14_11->commission            = vote_state->commission;
      19           0 :   vote_state_1_14_11->votes                 = vote_state->votes;
      20           0 :   vote_state_1_14_11->has_root_slot         = vote_state->has_root_slot;
      21           0 :   vote_state_1_14_11->root_slot             = vote_state->root_slot;
      22           0 :   vote_state_1_14_11->authorized_voters     = vote_state->authorized_voters;
      23           0 :   vote_state_1_14_11->prior_voters          = vote_state->prior_voters;
      24           0 :   vote_state_1_14_11->epoch_credits         = vote_state->epoch_credits;
      25           0 :   vote_state_1_14_11->last_timestamp        = vote_state->last_timestamp;
      26           0 : }
      27             : 
      28             : void
      29             : fd_vote_program_v3_create_new( fd_vote_init_t * const        vote_init,
      30             :                                fd_sol_sysvar_clock_t const * clock,
      31           0 :                                fd_vote_state_versioned_t *   versioned /* out */ ) {
      32           0 :   fd_vote_state_versioned_new( versioned, fd_vote_state_versioned_enum_v3 );
      33             : 
      34           0 :   fd_vote_state_v3_t * vote_state   = &versioned->v3;
      35           0 :   vote_state->node_pubkey           = vote_init->node_pubkey;
      36           0 :   vote_state->authorized_withdrawer = vote_init->authorized_withdrawer;
      37           0 :   vote_state->commission            = vote_init->commission;
      38           0 :   vote_state->prior_voters.idx      = 31;
      39           0 :   vote_state->prior_voters.is_empty = 1;
      40             : 
      41             :   /* Insert the authorized voter */
      42           0 :   fd_vote_authorized_voter_t * voter = fd_vote_authorized_voters_pool_ele_acquire( vote_state->authorized_voters.pool );
      43           0 :   voter->epoch  = clock->epoch;
      44           0 :   voter->pubkey = vote_init->authorized_voter;
      45           0 :   voter->prio   = voter->pubkey.uc[0];
      46           0 :   fd_vote_authorized_voters_treap_ele_insert( vote_state->authorized_voters.treap, voter, vote_state->authorized_voters.pool );
      47           0 : }
      48             : 
      49             : int
      50             : fd_vote_state_v3_set_vote_account_state( fd_exec_instr_ctx_t const * ctx,
      51             :                                          fd_borrowed_account_t *     vote_account,
      52           0 :                                          fd_vote_state_versioned_t * versioned ) {
      53             :   /* This is a horrible conditional expression in Agave.
      54             :      The terms were broken up into their own variables. */
      55           0 :   fd_vote_state_v3_t * v3_vote_state = &versioned->v3;
      56             : 
      57             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L420-L424 */
      58           0 :   fd_rent_t const * rent               = &ctx->bank->f.rent;
      59           0 :   int               resize_needed      = fd_borrowed_account_get_data_len( vote_account ) < FD_VOTE_STATE_V3_SZ;
      60           0 :   int               resize_rent_exempt = fd_rent_exempt_minimum_balance( rent, FD_VOTE_STATE_V3_SZ ) <= fd_borrowed_account_get_lamports( vote_account );
      61             : 
      62             :   /* The resize operation itself is part of the horrible conditional,
      63             :      but behind a short-circuit operator. */
      64           0 :   int resize_failed = 0;
      65           0 :   if( resize_needed && resize_rent_exempt ) {
      66             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L422-L424 */
      67           0 :     resize_failed =
      68           0 :       fd_borrowed_account_set_data_length( vote_account, FD_VOTE_STATE_V3_SZ ) != FD_EXECUTOR_INSTR_SUCCESS;
      69           0 :   }
      70             : 
      71           0 :   if( FD_UNLIKELY( resize_needed && ( !resize_rent_exempt || resize_failed ) ) ) {
      72             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L426-L430 */
      73           0 :     fd_vote_state_versioned_t vsv[1];
      74           0 :     fd_vote_state_versioned_new( vsv, fd_vote_state_versioned_enum_v1_14_11 );
      75           0 :     to_vote_state_1_14_11( v3_vote_state, &vsv->v1_14_11 );
      76           0 :     return fd_vsv_set_state( vote_account, vsv );
      77           0 :   }
      78             : 
      79             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L432-L433 */
      80           0 :   return fd_vsv_set_state( vote_account, versioned );
      81           0 : }
      82             : 
      83             : int
      84             : fd_vote_state_v3_deserialize( fd_borrowed_account_t const * vote_account,
      85           0 :                               fd_vote_state_versioned_t *   versioned ) {
      86             :   /* deserialize_into_ptr is essentially a call to get_state +
      87             :      try_convert_to_v3. It's written a little more verbosely in Agave
      88             :      as they try to optimize the decoding steps.
      89             :      https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v4.0.4/vote-interface/src/state/vote_state_v3.rs#L162-L202 */
      90           0 :   int rc = fd_vsv_get_state( vote_account->acc, versioned );
      91           0 :   if( FD_UNLIKELY( rc ) ) return rc;
      92             : 
      93             :   /* Unlike vote states v4 decoding, vote state v3 decoding will only
      94             :      pass for v1_14_11 and v3 vote states.
      95             :      https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/state/vote_state_v3.rs#L157-L164 */
      96           0 :   if( FD_UNLIKELY( versioned->kind!=fd_vote_state_versioned_enum_v1_14_11 &&
      97           0 :                    versioned->kind!=fd_vote_state_versioned_enum_v3 ) ) {
      98           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
      99           0 :   }
     100             : 
     101           0 :   return fd_vsv_try_convert_to_v3( versioned );
     102           0 : }
     103             : 
     104             : int
     105             : fd_vote_state_v3_get_and_update_authorized_voter( fd_vote_state_v3_t * self,
     106             :                                                   ulong                current_epoch,
     107           0 :                                                   fd_pubkey_t **       pubkey /* out */ ) {
     108             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L832
     109           0 :   fd_vote_authorized_voter_t * authorized_voter = fd_authorized_voters_get_and_cache_authorized_voter_for_epoch(
     110           0 :       &self->authorized_voters,
     111           0 :       current_epoch
     112           0 :   );
     113             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L835
     114           0 :   if( FD_UNLIKELY( !authorized_voter ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     115           0 :   *pubkey = &authorized_voter->pubkey;
     116             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L837
     117           0 :   fd_authorized_voters_purge_authorized_voters( &self->authorized_voters, current_epoch );
     118           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     119           0 : }
     120             : 
     121             : int
     122             : fd_vote_state_v3_set_new_authorized_voter( fd_exec_instr_ctx_t * ctx,
     123             :                                            fd_vote_state_v3_t *  self,
     124             :                                            fd_pubkey_t const *   authorized_pubkey,
     125             :                                            ulong                 current_epoch,
     126             :                                            ulong                 target_epoch,
     127             :                                            uchar const *         bls_pubkey,
     128             :                                            int                   authorized_withdrawer_signer,
     129             :                                            fd_pubkey_t const *   signers[ FD_TXN_SIG_MAX ],
     130           0 :                                            ulong                 signers_cnt ) {
     131           0 :   int           rc;
     132           0 :   fd_pubkey_t * epoch_authorized_voter = NULL;
     133             : 
     134             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L287-L292 */
     135           0 :   if( FD_UNLIKELY( bls_pubkey!=NULL ) ) {
     136           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     137           0 :   }
     138             : 
     139             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L778
     140           0 :   rc = fd_vote_state_v3_get_and_update_authorized_voter( self, current_epoch, &epoch_authorized_voter );
     141           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     142             : 
     143             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L779
     144           0 :   rc = fd_vote_signature_verify( epoch_authorized_voter, authorized_withdrawer_signer, signers, signers_cnt );
     145           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     146             : 
     147             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L786
     148           0 :   if( FD_UNLIKELY( fd_authorized_voters_contains( &self->authorized_voters, target_epoch ) ) ) {
     149           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_TOO_SOON_TO_REAUTHORIZE;
     150           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     151           0 :   }
     152             : 
     153             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L791
     154           0 :   fd_vote_authorized_voter_t * latest_authorized =
     155           0 :       fd_authorized_voters_last( &self->authorized_voters );
     156             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L794
     157           0 :   if( FD_UNLIKELY( ( !latest_authorized ) ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     158           0 :   ulong         latest_epoch             = latest_authorized->epoch;
     159           0 :   fd_pubkey_t * latest_authorized_pubkey = &latest_authorized->pubkey;
     160             : 
     161             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L799
     162           0 :   if( !fd_pubkey_eq( latest_authorized_pubkey, authorized_pubkey ) ) {
     163           0 :     fd_vote_prior_voters_t * prior_voters = &self->prior_voters;
     164             : 
     165             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L801
     166           0 :     ulong epoch_of_last_authorized_switch = 0UL;
     167           0 :     if( (!prior_voters->is_empty) & (prior_voters->idx < 32) ) {
     168           0 :       epoch_of_last_authorized_switch = prior_voters->buf[prior_voters->idx].epoch_end;
     169           0 :     }
     170             : 
     171             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L810
     172           0 :     if( target_epoch <= latest_epoch )
     173           0 :       return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     174             : 
     175             :     // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L815
     176           0 :     prior_voters->idx += 1UL;
     177           0 :     prior_voters->idx %= 32UL;
     178           0 :     prior_voters->buf[prior_voters->idx] =
     179           0 :         ( fd_vote_prior_voter_t ){ .pubkey      = *latest_authorized_pubkey,
     180           0 :                                    .epoch_start = epoch_of_last_authorized_switch,
     181           0 :                                    .epoch_end   = target_epoch };
     182           0 :     prior_voters->is_empty = 0;
     183           0 :   }
     184             : 
     185             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L822
     186           0 :   if( FD_UNLIKELY( !fd_vote_authorized_voters_pool_free( self->authorized_voters.pool ) ) ) {
     187           0 :     FD_LOG_CRIT(( "invariant violation: max authorized voter count of vote account exceeded" ));
     188           0 :   }
     189             : 
     190           0 :   fd_vote_authorized_voter_t * ele =
     191           0 :       fd_vote_authorized_voters_pool_ele_acquire( self->authorized_voters.pool );
     192           0 :   ele->epoch  = target_epoch;
     193           0 :   ele->pubkey = *authorized_pubkey;
     194           0 :   ele->prio   = ele->pubkey.uc[0];
     195           0 :   fd_vote_authorized_voters_treap_ele_insert(
     196           0 :       self->authorized_voters.treap, ele, self->authorized_voters.pool );
     197             : 
     198           0 :   return 0;
     199           0 : }
     200             : 

Generated by: LCOV version 1.14