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