Line data Source code
1 : #include "fd_vote_state_v3.h" 2 : #include "fd_vote_codec_tmpl.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 : int 29 : fd_vote_state_v3_set_vote_account_state( fd_exec_instr_ctx_t const * ctx, 30 : fd_borrowed_account_t * vote_account, 31 0 : fd_vote_state_versioned_t * versioned ) { 32 : /* This is a horrible conditional expression in Agave. 33 : The terms were broken up into their own variables. */ 34 0 : fd_vote_state_v3_t * v3_vote_state = &versioned->v3; 35 : 36 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L420-L424 */ 37 0 : fd_rent_t const * rent = &ctx->bank->f.rent; 38 0 : int resize_needed = fd_borrowed_account_get_data_len( vote_account ) < FD_VOTE_STATE_V3_SZ; 39 0 : int resize_rent_exempt = fd_rent_exempt_minimum_balance( rent, FD_VOTE_STATE_V3_SZ ) <= fd_borrowed_account_get_lamports( vote_account ); 40 : 41 : /* The resize operation itself is part of the horrible conditional, 42 : but behind a short-circuit operator. */ 43 0 : int resize_failed = 0; 44 0 : if( resize_needed && resize_rent_exempt ) { 45 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L422-L424 */ 46 0 : resize_failed = 47 0 : fd_borrowed_account_set_data_length( vote_account, FD_VOTE_STATE_V3_SZ ) != FD_EXECUTOR_INSTR_SUCCESS; 48 0 : } 49 : 50 0 : if( FD_UNLIKELY( resize_needed && ( !resize_rent_exempt || resize_failed ) ) ) { 51 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L426-L430 */ 52 0 : fd_vote_state_versioned_t vsv[1]; 53 0 : fd_vote_state_versioned_new( vsv, fd_vote_state_versioned_enum_v1_14_11 ); 54 0 : to_vote_state_1_14_11( v3_vote_state, &vsv->v1_14_11 ); 55 0 : return fd_vsv_set_state( vote_account, vsv ); 56 0 : } 57 : 58 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/handler.rs#L432-L433 */ 59 0 : return fd_vsv_set_state( vote_account, versioned ); 60 0 : } 61 : 62 : int 63 : fd_vote_state_v3_get_and_update_authorized_voter( fd_vote_state_v3_t * self, 64 : ulong current_epoch, 65 0 : fd_pubkey_t ** pubkey /* out */ ) { 66 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L832 67 0 : fd_vote_authorized_voter_t * authorized_voter = fd_authorized_voters_get_and_cache_authorized_voter_for_epoch( 68 0 : &self->authorized_voters, 69 0 : current_epoch 70 0 : ); 71 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L835 72 0 : if( FD_UNLIKELY( !authorized_voter ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA; 73 0 : *pubkey = &authorized_voter->pubkey; 74 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L837 75 0 : fd_authorized_voters_purge_authorized_voters( &self->authorized_voters, current_epoch ); 76 0 : return FD_EXECUTOR_INSTR_SUCCESS; 77 0 : } 78 : 79 : int 80 : fd_vote_state_v3_set_new_authorized_voter( fd_exec_instr_ctx_t * ctx, 81 : fd_vote_state_v3_t * self, 82 : fd_pubkey_t const * authorized_pubkey, 83 : ulong current_epoch, 84 : ulong target_epoch, 85 : uchar const * bls_pubkey, 86 : int authorized_withdrawer_signer, 87 : fd_pubkey_t const * signers[ FD_INSTR_SIGNERS_MAX ], 88 0 : ulong signers_cnt ) { 89 0 : int rc; 90 0 : fd_pubkey_t * epoch_authorized_voter = NULL; 91 : 92 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/handler.rs#L287-L292 */ 93 0 : if( FD_UNLIKELY( bls_pubkey!=NULL ) ) { 94 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA; 95 0 : } 96 : 97 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L778 98 0 : rc = fd_vote_state_v3_get_and_update_authorized_voter( self, current_epoch, &epoch_authorized_voter ); 99 0 : if( FD_UNLIKELY( rc ) ) return rc; 100 : 101 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L779 102 0 : rc = fd_vote_signature_verify( epoch_authorized_voter, authorized_withdrawer_signer, signers, signers_cnt ); 103 0 : if( FD_UNLIKELY( rc ) ) return rc; 104 : 105 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L786 106 0 : if( FD_UNLIKELY( fd_authorized_voters_contains( &self->authorized_voters, target_epoch ) ) ) { 107 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_TOO_SOON_TO_REAUTHORIZE; 108 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; 109 0 : } 110 : 111 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L791 112 0 : fd_vote_authorized_voter_t * latest_authorized = 113 0 : fd_authorized_voters_last( &self->authorized_voters ); 114 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L794 115 0 : if( FD_UNLIKELY( ( !latest_authorized ) ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA; 116 0 : ulong latest_epoch = latest_authorized->epoch; 117 0 : fd_pubkey_t * latest_authorized_pubkey = &latest_authorized->pubkey; 118 : 119 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L799 120 0 : if( !fd_pubkey_eq( latest_authorized_pubkey, authorized_pubkey ) ) { 121 0 : fd_vote_prior_voters_t * prior_voters = &self->prior_voters; 122 : 123 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L801 124 0 : ulong epoch_of_last_authorized_switch = 0UL; 125 0 : if( (!prior_voters->is_empty) & (prior_voters->idx < 32) ) { 126 0 : epoch_of_last_authorized_switch = prior_voters->buf[prior_voters->idx].epoch_end; 127 0 : } 128 : 129 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L810 130 0 : if( target_epoch <= latest_epoch ) 131 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA; 132 : 133 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L815 134 0 : prior_voters->idx += 1UL; 135 0 : prior_voters->idx %= 32UL; 136 0 : prior_voters->buf[prior_voters->idx] = 137 0 : ( fd_vote_prior_voter_t ){ .pubkey = *latest_authorized_pubkey, 138 0 : .epoch_start = epoch_of_last_authorized_switch, 139 0 : .epoch_end = target_epoch }; 140 0 : prior_voters->is_empty = 0; 141 0 : } 142 : 143 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L822 144 0 : if( FD_UNLIKELY( !fd_vote_authorized_voters_pool_free( self->authorized_voters.pool ) ) ) { 145 0 : FD_LOG_CRIT(( "invariant violation: max authorized voter count of vote account exceeded" )); 146 0 : } 147 : 148 0 : fd_vote_authorized_voter_t * ele = 149 0 : fd_vote_authorized_voters_pool_ele_acquire( self->authorized_voters.pool ); 150 0 : ele->epoch = target_epoch; 151 0 : ele->pubkey = *authorized_pubkey; 152 0 : ele->prio = ele->pubkey.uc[0]; 153 0 : fd_vote_authorized_voters_treap_ele_insert( 154 0 : self->authorized_voters.treap, ele, self->authorized_voters.pool ); 155 : 156 0 : return 0; 157 0 : } 158 :