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 : }