Line data Source code
1 : #include "fd_vote_utils.h" 2 : #include "fd_vote_codec.h" 3 : #include "../fd_vote_program.h" 4 : #include "../fd_program_util.h" 5 : 6 : /**********************************************************************/ 7 : /* Lockout utilities */ 8 : /**********************************************************************/ 9 : 10 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L104 11 : ulong 12 0 : fd_vote_lockout_get_lockout( fd_vote_lockout_t * self ) { 13 : /* Confirmation count can never be greater than MAX_LOCKOUT_HISTORY, preventing overflow. 14 : Although Agave does not consider overflow, we do for fuzzing conformance. */ 15 0 : ulong confirmation_count = fd_ulong_min( self->confirmation_count, MAX_LOCKOUT_HISTORY ); 16 0 : return 1UL<<confirmation_count; 17 0 : } 18 : 19 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L110 20 : ulong 21 0 : fd_vote_lockout_last_locked_out_slot( fd_vote_lockout_t * self ) { 22 0 : return fd_ulong_sat_add( self->slot, fd_vote_lockout_get_lockout( self ) ); 23 0 : } 24 : 25 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L114 26 : ulong 27 0 : fd_vote_lockout_is_locked_out_at_slot( fd_vote_lockout_t * self, ulong slot ) { 28 0 : return fd_vote_lockout_last_locked_out_slot( self ) >= slot; 29 0 : } 30 : 31 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L122 32 : void 33 0 : fd_vote_lockout_increase_confirmation_count( fd_vote_lockout_t * self, uint by ) { 34 0 : self->confirmation_count = fd_uint_sat_add( self->confirmation_count, by ); 35 0 : } 36 : 37 : fd_landed_vote_t * 38 : fd_vote_lockout_landed_votes_from_lockouts( fd_vote_lockout_t * lockouts, 39 0 : uchar * mem ) { 40 0 : if( !lockouts ) return NULL; 41 : 42 0 : ulong cnt = deq_fd_vote_lockout_t_cnt( lockouts ); 43 0 : cnt = fd_ulong_max( cnt, MAX_LOCKOUT_HISTORY ); 44 : 45 0 : fd_landed_vote_t * landed_votes = deq_fd_landed_vote_t_join( deq_fd_landed_vote_t_new( mem, cnt ) ); 46 0 : if( FD_UNLIKELY( !landed_votes ) ) { 47 0 : FD_LOG_CRIT(( "failed to join landed votes" )); 48 0 : } 49 : 50 0 : for( deq_fd_vote_lockout_t_iter_t iter = deq_fd_vote_lockout_t_iter_init( lockouts ); 51 0 : !deq_fd_vote_lockout_t_iter_done( lockouts, iter ); 52 0 : iter = deq_fd_vote_lockout_t_iter_next( lockouts, iter ) ) { 53 0 : fd_vote_lockout_t const * ele = deq_fd_vote_lockout_t_iter_ele_const( lockouts, iter ); 54 : 55 0 : fd_landed_vote_t * elem = deq_fd_landed_vote_t_push_tail_nocopy( landed_votes ); 56 : 57 0 : elem->latency = 0; 58 0 : elem->lockout.slot = ele->slot; 59 0 : elem->lockout.confirmation_count = ele->confirmation_count; 60 0 : } 61 : 62 0 : return landed_votes; 63 0 : } 64 : 65 : /**********************************************************************/ 66 : /* Vote state utilities */ 67 : /**********************************************************************/ 68 : 69 : int 70 : fd_vote_verify_authorized_signer( fd_pubkey_t const * authorized, 71 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX], 72 6 : ulong signers_cnt ) { 73 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L989 74 6 : return fd_signers_contains( signers, signers_cnt, authorized ) ? 75 6 : FD_EXECUTOR_INSTR_SUCCESS : 76 6 : FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE; 77 6 : } 78 : 79 : int 80 : fd_vote_signature_verify( fd_pubkey_t * epoch_authorized_voter, 81 : int authorized_withdrawer_signer, 82 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX], 83 0 : ulong signers_cnt ) { 84 0 : return authorized_withdrawer_signer ? 0 : fd_vote_verify_authorized_signer( epoch_authorized_voter, signers, signers_cnt ); 85 0 : } 86 : 87 : uchar 88 : fd_vote_compute_vote_latency( ulong voted_for_slot, 89 0 : ulong current_slot ) { 90 0 : return (uchar)fd_ulong_min( fd_ulong_sat_sub( current_slot, voted_for_slot ), UCHAR_MAX ); 91 0 : } 92 : 93 : ulong 94 : fd_vote_credits_for_vote_at_index( fd_landed_vote_t const * votes, 95 0 : ulong index ) { 96 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L679 97 0 : fd_landed_vote_t const * landed_vote = deq_fd_landed_vote_t_peek_index_const( votes, index ); 98 0 : ulong latency = landed_vote == NULL ? 0 : landed_vote->latency; 99 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L683 100 0 : ulong max_credits = VOTE_CREDITS_MAXIMUM_PER_SLOT; 101 : 102 : /* If latency is 0, this means that the Lockout was created and stored 103 : from a software version that did not store vote latencies; in this 104 : case, 1 credit is awarded. 105 : https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L691 */ 106 0 : if( FD_UNLIKELY( latency==0UL ) ) { 107 0 : return 1; 108 0 : } 109 : 110 0 : ulong diff = 0; 111 0 : int cf = fd_ulong_checked_sub( latency, VOTE_CREDITS_GRACE_SLOTS, &diff ); 112 0 : if( cf || diff==0UL ) { 113 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L697 114 0 : return max_credits; 115 0 : } 116 : 117 0 : ulong credits = 0; 118 0 : cf = fd_ulong_checked_sub( max_credits, diff, &credits ); 119 0 : if( cf != 0 || credits == 0 ) { 120 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L705 121 0 : return 1; 122 0 : } 123 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L707 124 0 : return credits; 125 0 : } 126 : 127 : int 128 : fd_vote_contains_slot( fd_landed_vote_t const * votes, 129 0 : ulong slot ) { 130 : /* Logic is copied from slice::binary_search_by() in Rust. While not fully optimized, 131 : it aims to achieve fuzzing conformance for both sorted and unsorted inputs. */ 132 0 : ulong size = deq_fd_landed_vote_t_cnt( votes ); 133 0 : if( FD_UNLIKELY( size==0UL ) ) return 0; 134 : 135 0 : ulong base = 0UL; 136 0 : while( size>1UL ) { 137 0 : ulong half = size / 2UL; 138 0 : ulong mid = base + half; 139 0 : ulong mid_slot = deq_fd_landed_vote_t_peek_index_const( votes, mid )->lockout.slot; 140 0 : base = (slot<mid_slot) ? base : mid; 141 0 : size -= half; 142 0 : } 143 : 144 0 : return deq_fd_landed_vote_t_peek_index_const( votes, base )->lockout.slot==slot; 145 0 : }