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