|
| 1 | +#include "fd_authorized_voters.h" |
| 2 | +#include "fd_vote_state_v3.h" |
| 3 | +#include "fd_vote_state_v4.h" |
| 4 | + |
| 5 | +/**********************************************************************/ |
| 6 | +/* impl AuthorizedVoters */ |
| 7 | +/**********************************************************************/ |
| 8 | + |
| 9 | +// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L17 |
| 10 | +fd_vote_authorized_voters_t * |
| 11 | +fd_authorized_voters_new( ulong epoch, |
| 12 | + fd_pubkey_t const * pubkey, |
| 13 | + uchar * mem ) { |
| 14 | + |
| 15 | + FD_SCRATCH_ALLOC_INIT( l, mem ); |
| 16 | + fd_vote_authorized_voters_t * authorized_voters = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_authorized_voters_align(), sizeof(fd_vote_authorized_voters_t) ); |
| 17 | + void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_authorized_voters_pool_align(), fd_vote_authorized_voters_pool_footprint( FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 18 | + void * treap_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_authorized_voters_treap_align(), fd_vote_authorized_voters_treap_footprint( FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 19 | + |
| 20 | + authorized_voters->pool = fd_vote_authorized_voters_pool_join( fd_vote_authorized_voters_pool_new( pool_mem, FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 21 | + authorized_voters->treap = fd_vote_authorized_voters_treap_join( fd_vote_authorized_voters_treap_new( treap_mem, FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 22 | + if( 0 == fd_vote_authorized_voters_pool_free( authorized_voters->pool ) ) { |
| 23 | + FD_LOG_ERR(( "Authorized_voter pool is empty" )); |
| 24 | + } |
| 25 | + fd_vote_authorized_voter_t * ele = fd_vote_authorized_voters_pool_ele_acquire( authorized_voters->pool ); |
| 26 | + ele->epoch = epoch; |
| 27 | + ele->pubkey = *pubkey; |
| 28 | + ele->prio = (ulong)&ele->pubkey; |
| 29 | + fd_vote_authorized_voters_treap_ele_insert( authorized_voters->treap, ele, authorized_voters->pool ); |
| 30 | + return authorized_voters; |
| 31 | +} |
| 32 | + |
| 33 | +// Helper to create an empty AuthorizedVoters structure (for default/uninitialized states) |
| 34 | +fd_vote_authorized_voters_t * |
| 35 | +fd_authorized_voters_new_empty( uchar * mem ) { |
| 36 | + FD_SCRATCH_ALLOC_INIT( l, mem ); |
| 37 | + fd_vote_authorized_voters_t * authorized_voters = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_authorized_voters_align(), sizeof(fd_vote_authorized_voters_t) ); |
| 38 | + void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_authorized_voters_pool_align(), fd_vote_authorized_voters_pool_footprint( FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 39 | + void * treap_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_authorized_voters_treap_align(), fd_vote_authorized_voters_treap_footprint( FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 40 | + |
| 41 | + authorized_voters->pool = fd_vote_authorized_voters_pool_join( fd_vote_authorized_voters_pool_new( pool_mem, FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 42 | + authorized_voters->treap = fd_vote_authorized_voters_treap_join( fd_vote_authorized_voters_treap_new( treap_mem, FD_VOTE_AUTHORIZED_VOTERS_MIN ) ); |
| 43 | + return authorized_voters; |
| 44 | +} |
| 45 | + |
| 46 | +int |
| 47 | +fd_authorized_voters_is_empty( fd_vote_authorized_voters_t * self ) { |
| 48 | + return fd_vote_authorized_voters_treap_ele_cnt( self->treap ) == 0; |
| 49 | +} |
| 50 | + |
| 51 | +// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L80 |
| 52 | +int |
| 53 | +fd_authorized_voters_contains( fd_vote_authorized_voters_t * self, ulong epoch ) { |
| 54 | + return !!fd_vote_authorized_voters_treap_ele_query( self->treap, epoch, self->pool ); |
| 55 | +} |
| 56 | + |
| 57 | +// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L72 |
| 58 | +fd_vote_authorized_voter_t * |
| 59 | +fd_authorized_voters_last( fd_vote_authorized_voters_t * self ) { |
| 60 | + fd_vote_authorized_voters_treap_rev_iter_t iter = |
| 61 | + fd_vote_authorized_voters_treap_rev_iter_init( self->treap, self->pool ); |
| 62 | + return fd_vote_authorized_voters_treap_rev_iter_ele( iter, self->pool ); |
| 63 | +} |
| 64 | + |
| 65 | +// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L43 |
| 66 | +void |
| 67 | +fd_authorized_voters_purge_authorized_voters( fd_vote_authorized_voters_t * self, |
| 68 | + ulong current_epoch ) { |
| 69 | + |
| 70 | + // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L46 |
| 71 | + ulong expired_keys[ FD_VOTE_AUTHORIZED_VOTERS_MIN ]; |
| 72 | + ulong key_cnt = 0; |
| 73 | + for( fd_vote_authorized_voters_treap_fwd_iter_t iter = |
| 74 | + fd_vote_authorized_voters_treap_fwd_iter_init( self->treap, self->pool ); |
| 75 | + !fd_vote_authorized_voters_treap_fwd_iter_done( iter ); |
| 76 | + iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, self->pool ) ) { |
| 77 | + fd_vote_authorized_voter_t * ele = |
| 78 | + fd_vote_authorized_voters_treap_fwd_iter_ele( iter, self->pool ); |
| 79 | + if( ele->epoch < current_epoch ) expired_keys[key_cnt++] = ele->epoch; |
| 80 | + } |
| 81 | + |
| 82 | + // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L52 |
| 83 | + for( ulong i = 0; i < key_cnt; i++ ) { |
| 84 | + fd_vote_authorized_voter_t * ele = |
| 85 | + fd_vote_authorized_voters_treap_ele_query( self->treap, expired_keys[i], self->pool ); |
| 86 | + fd_vote_authorized_voters_treap_ele_remove( self->treap, ele, self->pool ); |
| 87 | + fd_vote_authorized_voters_pool_ele_release( self->pool, ele ); |
| 88 | + } |
| 89 | + |
| 90 | + // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L60 |
| 91 | + FD_TEST( !fd_authorized_voters_is_empty( self ) ); |
| 92 | + |
| 93 | +} |
| 94 | + |
| 95 | +// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L91 |
| 96 | +fd_vote_authorized_voter_t * |
| 97 | +fd_authorized_voters_get_or_calculate_authorized_voter_for_epoch( fd_vote_authorized_voters_t * self, |
| 98 | + ulong epoch, |
| 99 | + int * existed ) { |
| 100 | + *existed = 0; |
| 101 | + ulong latest_epoch = 0; |
| 102 | + fd_vote_authorized_voter_t * res = |
| 103 | + fd_vote_authorized_voters_treap_ele_query( self->treap, epoch, self->pool ); |
| 104 | + // "predecessor" would be more big-O optimal here, but mirroring labs logic |
| 105 | + // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L93 |
| 106 | + if( FD_UNLIKELY( !res ) ) { |
| 107 | + for( fd_vote_authorized_voters_treap_fwd_iter_t iter = |
| 108 | + fd_vote_authorized_voters_treap_fwd_iter_init( self->treap, self->pool ); |
| 109 | + !fd_vote_authorized_voters_treap_fwd_iter_done( iter ); |
| 110 | + iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, self->pool ) ) { |
| 111 | + fd_vote_authorized_voter_t * ele = |
| 112 | + fd_vote_authorized_voters_treap_fwd_iter_ele( iter, self->pool ); |
| 113 | + if( ele->epoch < epoch && ( latest_epoch == 0 || ele->epoch > latest_epoch ) ) { |
| 114 | + latest_epoch = ele->epoch; |
| 115 | + res = ele; |
| 116 | + } |
| 117 | + } |
| 118 | + *existed = 0; |
| 119 | + return res; |
| 120 | + } else { |
| 121 | + *existed = 1; |
| 122 | + return res; |
| 123 | + } |
| 124 | + return res; |
| 125 | +} |
| 126 | + |
| 127 | +// https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L28 |
| 128 | +fd_vote_authorized_voter_t * |
| 129 | +fd_authorized_voters_get_and_cache_authorized_voter_for_epoch( fd_vote_authorized_voters_t * self, |
| 130 | + ulong epoch ) { |
| 131 | + int existed = 0; |
| 132 | + // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L29 |
| 133 | + fd_vote_authorized_voter_t * res = |
| 134 | + fd_authorized_voters_get_or_calculate_authorized_voter_for_epoch( self, epoch, &existed ); |
| 135 | + if( !res ) return NULL; |
| 136 | + // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L32 |
| 137 | + if( !existed ) { |
| 138 | + /* insert cannot fail because !existed */ |
| 139 | + if( 0 == fd_vote_authorized_voters_pool_free( self->pool) ) { |
| 140 | + FD_LOG_ERR(( "Authorized_voter pool is empty" )); |
| 141 | + } |
| 142 | + fd_vote_authorized_voter_t * ele = fd_vote_authorized_voters_pool_ele_acquire( self->pool ); |
| 143 | + ele->epoch = epoch; |
| 144 | + ele->pubkey = res->pubkey; |
| 145 | + ele->prio = (ulong)&res->pubkey; |
| 146 | + // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/authorized_voters.rs#L33 |
| 147 | + fd_vote_authorized_voters_treap_ele_insert( self->treap, ele, self->pool ); |
| 148 | + } |
| 149 | + return res; |
| 150 | +} |
| 151 | + |
| 152 | +int |
| 153 | +fd_authorized_voters_get_and_update_authorized_voter( fd_vote_state_versioned_t * self, |
| 154 | + ulong current_epoch, |
| 155 | + fd_pubkey_t ** pubkey /* out */ ) { |
| 156 | + switch( self->discriminant ) { |
| 157 | + case fd_vote_state_versioned_enum_current: |
| 158 | + return fd_vote_state_v3_get_and_update_authorized_voter( &self->inner.current, current_epoch, pubkey ); |
| 159 | + case fd_vote_state_versioned_enum_v4: |
| 160 | + return fd_vote_state_v4_get_and_update_authorized_voter( &self->inner.v4, current_epoch, pubkey ); |
| 161 | + default: |
| 162 | + __builtin_unreachable(); |
| 163 | + } |
| 164 | +} |
0 commit comments