LCOV - code coverage report
Current view: top level - flamenco/runtime/program/vote - fd_vote_state_v4.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 28 82 34.1 %
Date: 2026-06-29 05:51:35 Functions: 3 6 50.0 %

          Line data    Source code
       1             : #include "fd_vote_state_v4.h"
       2             : #include "fd_authorized_voters.h"
       3             : #include "fd_vote_state_versioned.h"
       4             : #include "fd_vote_utils.h"
       5             : #include "../fd_vote_program.h"
       6             : #include "../../fd_runtime.h"
       7             : 
       8             : static inline void
       9             : init_authorized_voters( fd_vote_authorized_voters_t * authorized_voters,
      10             :                         ulong                         epoch,
      11           6 :                         fd_pubkey_t const *           authorized_voter ) {
      12           6 :   fd_vote_authorized_voter_t * voter = fd_vote_authorized_voters_pool_ele_acquire( authorized_voters->pool );
      13           6 :   voter->epoch  = epoch;
      14           6 :   voter->pubkey = *authorized_voter;
      15           6 :   voter->prio   = voter->pubkey.uc[0];
      16           6 :   fd_vote_authorized_voters_treap_ele_insert( authorized_voters->treap, voter, authorized_voters->pool );
      17           6 : }
      18             : 
      19             : /* https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/state/vote_state_v4.rs#L80 */
      20             : void
      21             : fd_vote_state_v4_create_new_with_defaults( fd_pubkey_t const *           vote_pubkey,
      22             :                                            fd_vote_init_t const *        vote_init,
      23             :                                            fd_sol_sysvar_clock_t const * clock,
      24           6 :                                            fd_vote_state_versioned_t *   versioned /* out */ ) {
      25           6 :   fd_vote_state_versioned_new( versioned, fd_vote_state_versioned_enum_v4 );
      26             : 
      27           6 :   fd_vote_state_v4_t * vote_state              = &versioned->v4;
      28           6 :   vote_state->node_pubkey                      = vote_init->node_pubkey;
      29           6 :   vote_state->authorized_withdrawer            = vote_init->authorized_withdrawer;
      30           6 :   vote_state->inflation_rewards_commission_bps = (ushort)( vote_init->commission * 100 );
      31           6 :   vote_state->inflation_rewards_collector      = *vote_pubkey;
      32           6 :   vote_state->block_revenue_collector          = vote_init->node_pubkey;
      33           6 :   vote_state->block_revenue_commission_bps     = DEFAULT_BLOCK_REVENUE_COMMISSION_BPS;
      34           6 :   vote_state->has_bls_pubkey_compressed        = 0;
      35             : 
      36           6 :   init_authorized_voters( &vote_state->authorized_voters, clock->epoch, &vote_init->authorized_voter );
      37           6 : }
      38             : 
      39             : /* https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/state/vote_state_v4.rs#L95 */
      40             : void
      41             : fd_vote_state_v4_create_new( fd_vote_init_v2_t const *     vote_init_v2,
      42             :                              fd_sol_sysvar_clock_t const * clock,
      43           0 :                              fd_vote_state_versioned_t *   versioned /* out */ ) {
      44           0 :   fd_vote_state_versioned_new( versioned, fd_vote_state_versioned_enum_v4 );
      45             : 
      46           0 :   fd_vote_state_v4_t * vote_state              = &versioned->v4;
      47           0 :   vote_state->node_pubkey                      = vote_init_v2->node_pubkey;
      48             : 
      49             :   /* Important: BLS pubkey proof of possesion MUST be validated first */
      50           0 :   vote_state->has_bls_pubkey_compressed        = 1;
      51           0 :   memcpy( vote_state->bls_pubkey_compressed, vote_init_v2->authorized_voter_bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ );
      52             : 
      53           0 :   vote_state->authorized_withdrawer            = vote_init_v2->authorized_withdrawer;
      54           0 :   vote_state->inflation_rewards_commission_bps = vote_init_v2->inflation_rewards_commission_bps;
      55           0 :   vote_state->inflation_rewards_collector      = vote_init_v2->inflation_rewards_collector;
      56           0 :   vote_state->block_revenue_commission_bps     = vote_init_v2->block_revenue_commission_bps;
      57           0 :   vote_state->block_revenue_collector          = vote_init_v2->block_revenue_collector;
      58             : 
      59           0 :   init_authorized_voters( &vote_state->authorized_voters, clock->epoch, &vote_init_v2->authorized_voter );
      60           0 : }
      61             : 
      62             : int
      63             : fd_vote_state_v4_set_vote_account_state( fd_exec_instr_ctx_t const * ctx,
      64             :                                          fd_borrowed_account_t *     vote_account,
      65           6 :                                          fd_vote_state_versioned_t * versioned ) {
      66             :   /* This is a horrible conditional expression in Agave.
      67             :      The terms were broken up into their own variables. */
      68             : 
      69             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L582-L586 */
      70           6 :   fd_rent_t const * rent               = &ctx->bank->f.rent;
      71           6 :   int               resize_needed      = fd_borrowed_account_get_data_len( vote_account ) < FD_VOTE_STATE_V4_SZ;
      72           6 :   int               resize_rent_exempt = fd_rent_exempt_minimum_balance( rent, FD_VOTE_STATE_V4_SZ ) <= fd_borrowed_account_get_lamports( vote_account );
      73             : 
      74             :   /* The resize operation itself is part of the horrible conditional,
      75             :      but behind a short-circuit operator. */
      76           6 :   int resize_failed = 0;
      77           6 :   if( resize_needed && resize_rent_exempt ) {
      78             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L584-L586 */
      79           0 :     resize_failed =
      80           0 :       fd_borrowed_account_set_data_length( vote_account, FD_VOTE_STATE_V4_SZ ) != FD_EXECUTOR_INSTR_SUCCESS;
      81           0 :   }
      82             : 
      83           6 :   if( FD_UNLIKELY( resize_needed && ( !resize_rent_exempt || resize_failed ) ) ) {
      84             :     /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L590 */
      85           0 :     return FD_EXECUTOR_INSTR_ERR_ACC_NOT_RENT_EXEMPT;
      86           0 :   }
      87             : 
      88             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L593 */
      89           6 :   return fd_vsv_set_state( vote_account, versioned );
      90           6 : }
      91             : 
      92             : int
      93             : fd_vote_state_v4_get_and_update_authorized_voter( fd_vote_state_v4_t * self,
      94             :                                                   ulong                current_epoch,
      95           0 :                                                   fd_pubkey_t **       pubkey /* out */ ) {
      96             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L327-L330 */
      97           0 :   fd_vote_authorized_voter_t * authorized_voter =
      98           0 :       fd_authorized_voters_get_and_cache_authorized_voter_for_epoch( &self->authorized_voters,
      99           0 :                                                                   current_epoch );
     100           0 :   if( FD_UNLIKELY( !authorized_voter ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
     101           0 :   *pubkey = &authorized_voter->pubkey;
     102             : 
     103             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L331-L332 */
     104           0 :   fd_authorized_voters_purge_authorized_voters( &self->authorized_voters, fd_ulong_sat_sub( current_epoch, 1UL ) );
     105           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     106           0 : }
     107             : 
     108             : int
     109             : fd_vote_state_v4_set_new_authorized_voter( fd_exec_instr_ctx_t * ctx,
     110             :                                            fd_vote_state_v4_t *  self,
     111             :                                            fd_pubkey_t const *   authorized_pubkey,
     112             :                                            ulong                 current_epoch,
     113             :                                            ulong                 target_epoch,
     114             :                                            uchar const *         bls_pubkey,
     115             :                                            int                   authorized_withdrawer_signer,
     116             :                                            fd_pubkey_t const *   signers[ FD_TXN_SIG_MAX ],
     117           0 :                                            ulong                 signers_cnt ) {
     118           0 :   int           rc;
     119           0 :   fd_pubkey_t * epoch_authorized_voter = NULL;
     120             : 
     121             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L462 */
     122           0 :   rc = fd_vote_state_v4_get_and_update_authorized_voter( self, current_epoch, &epoch_authorized_voter );
     123           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     124             : 
     125             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L463 */
     126           0 :   rc = fd_vote_signature_verify( epoch_authorized_voter, authorized_withdrawer_signer, signers, signers_cnt );
     127           0 :   if( FD_UNLIKELY( rc ) ) return rc;
     128             : 
     129             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L470-L472 */
     130           0 :   if( FD_UNLIKELY( fd_authorized_voters_contains( &self->authorized_voters, target_epoch ) ) ) {
     131           0 :     ctx->txn_out->err.custom_err = FD_VOTE_ERR_TOO_SOON_TO_REAUTHORIZE;
     132           0 :     return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
     133           0 :   }
     134             : 
     135             :   /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L474-L475 */
     136           0 :   if( FD_UNLIKELY( !fd_vote_authorized_voters_pool_free( self->authorized_voters.pool ) ) ) {
     137           0 :     FD_LOG_CRIT(( "invariant violation: max authorized voter count of vote account exceeded" ));
     138           0 :   }
     139             : 
     140           0 :   fd_vote_authorized_voter_t * ele =
     141           0 :       fd_vote_authorized_voters_pool_ele_acquire( self->authorized_voters.pool );
     142           0 :   ele->epoch  = target_epoch;
     143           0 :   ele->pubkey = *authorized_pubkey;
     144           0 :   ele->prio   = ele->pubkey.uc[0];
     145           0 :   fd_vote_authorized_voters_treap_ele_insert(
     146           0 :       self->authorized_voters.treap, ele, self->authorized_voters.pool );
     147             : 
     148             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L528-L530 */
     149           0 :   if( FD_LIKELY( bls_pubkey!=NULL ) ) {
     150           0 :     self->has_bls_pubkey_compressed = 1;
     151           0 :     memcpy( self->bls_pubkey_compressed, bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ );
     152           0 :   }
     153             : 
     154           0 :   return 0;
     155           0 : }

Generated by: LCOV version 1.14