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 115 0.0 %
Date: 2026-01-28 05:27:31 Functions: 0 6 0.0 %

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

Generated by: LCOV version 1.14