LCOV - code coverage report
Current view: top level - flamenco/runtime/program/vote - fd_authorized_voters.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 93 109 85.3 %
Date: 2026-03-19 18:19:27 Functions: 8 9 88.9 %

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

Generated by: LCOV version 1.14