LCOV - code coverage report
Current view: top level - flamenco/runtime/program/vote - fd_vote_codec.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 487 821 59.3 %
Date: 2026-09-17 04:28:31 Functions: 27 34 79.4 %

          Line data    Source code
       1             : #include "fd_vote_codec_tmpl.h"
       2             : #include "../../../../ballet/utf8/fd_utf8.h"
       3             : #include "../../../../ballet/txn/fd_compact_u16.h"
       4             : #include "../../../../ballet/txn/fd_txn.h"
       5             : 
       6             : /**********************************************************************/
       7             : /* Unified bincode (de)serialization macros.                          */
       8             : /* All macros operate on a cursor (uchar const ** data, ulong * sz).  */
       9             : /* CHECK returns 1 on failure (non-zero == error).                    */
      10             : /**********************************************************************/
      11             : 
      12      116622 : #define CHECK( cond ) do {               \
      13      116622 :   if( FD_UNLIKELY( !(cond) ) ) return 1; \
      14      116622 : } while( 0 )
      15             : 
      16         690 : #define CHECK_RET_NULL( cond ) do {          \
      17         690 :   if( FD_UNLIKELY( !(cond) ) ) return NULL;  \
      18         690 : } while( 0 )
      19             : 
      20        2241 : #define CHECK_U64_MUL_OVERFLOW( a, b ) do {                \
      21        2241 :   ulong _dummy;                                            \
      22        2241 :   CHECK( !__builtin_umull_overflow( (a), (b), &_dummy ) ); \
      23        2241 : } while( 0 )
      24             : 
      25             : /**********************************************************************/
      26             : /* Read macros                                                        */
      27             : /**********************************************************************/
      28             : 
      29        1401 : #define READ_BYTES( dst, n, data, sz ) do { \
      30        1401 :   CHECK( (n)<=(*(sz)) );                    \
      31        1401 :   fd_memcpy( (dst), *(data), (n) );         \
      32        1392 :   *(data) += (n);                           \
      33        1392 :   *(sz) -= (n);                             \
      34        1392 : } while( 0 )
      35             : 
      36        2931 : #define SKIP_BYTES( n, data, sz ) do { \
      37        2931 :   CHECK( (n)<=(*(sz)) );               \
      38        2931 :   *(data) += (n);                      \
      39        2931 :   *(sz) -= (n);                        \
      40        2931 : } while( 0 )
      41             : 
      42        1923 : #define READ_U8( dst, data, sz ) do { \
      43        1923 :   CHECK( 1UL<=(*(sz)) );              \
      44        1923 :   (dst) = FD_LOAD( uchar, *(data) );  \
      45        1923 :   *(data) += 1UL;                     \
      46        1923 :   *(sz) -= 1UL;                       \
      47        1923 : } while( 0 )
      48             : 
      49         405 : #define READ_U16( dst, data, sz ) do {  \
      50         405 :   CHECK( 2UL<=(*(sz)) );                \
      51         405 :   (dst) = FD_LOAD( ushort, *(data) );   \
      52         405 :   *(data) += 2UL;                       \
      53         405 :   *(sz) -= 2UL;                         \
      54         405 : } while( 0 )
      55             : 
      56        1797 : #define READ_U32( dst, data, sz ) do { \
      57        1797 :   CHECK( 4UL<=(*(sz)) );               \
      58        1797 :   (dst) = FD_LOAD( uint, *(data) );    \
      59        1797 :   *(data) += 4UL;                      \
      60        1797 :   *(sz) -= 4UL;                        \
      61        1797 : } while( 0 )
      62             : 
      63        3270 : #define READ_U64( dst, data, sz ) do {  \
      64        3270 :   CHECK( 8UL<=(*(sz)) );                \
      65        3270 :   (dst) = FD_LOAD( ulong, *(data) );    \
      66        3270 :   *(data) += 8UL;                       \
      67        3270 :   *(sz) -= 8UL;                         \
      68        3270 : } while( 0 )
      69             : 
      70           0 : #define READ_I64( dst, data, sz ) do { \
      71           0 :   CHECK( 8UL<=(*(sz)) );               \
      72           0 :   (dst) = FD_LOAD( long, *(data) );    \
      73           0 :   *(data) += 8UL;                      \
      74           0 :   *(sz) -= 8UL;                        \
      75           0 : } while( 0 )
      76             : 
      77             : #define READ_HASH( dst, data, sz ) \
      78        1032 :   READ_BYTES( (dst).uc, 32UL, data, sz )
      79             : 
      80        1032 : #define READ_PUBKEY READ_HASH
      81             : 
      82         402 : #define READ_BOOL( dst, data, sz ) do { \
      83         402 :   READ_U8( dst, data, sz );             \
      84         402 :   CHECK( (dst)==0 || (dst)==1 );        \
      85         402 : } while( 0 )
      86             : 
      87         396 : #define READ_OPTION READ_BOOL
      88             : 
      89          78 : #define READ_ENUM( dst, n, data, sz ) do { \
      90          78 :   CHECK( 4UL<=(*(sz)) );                   \
      91          78 :   (dst) = FD_LOAD( uint, *(data) );        \
      92          78 :   CHECK( (dst)<(n) );                      \
      93          78 :   *(data) += 4UL;                          \
      94          78 :   *(sz) -= 4UL;                            \
      95          78 : } while( 0 )
      96             : 
      97             : /* Varint decoder for u64 (LEB128). */
      98           0 : #define READ_U64_VARINT( dst, data, sz ) do {                                  \
      99           0 :   ulong _val = 0UL;                                                            \
     100           0 :   uint  _shift = 0U;                                                           \
     101           0 :   for(;;) {                                                                    \
     102           0 :     CHECK( 1UL<=(*(sz)) );                                                     \
     103           0 :     uchar _byte = FD_LOAD( uchar, *(data) );                                   \
     104           0 :     *(data) += 1UL;                                                            \
     105           0 :     *(sz) -= 1UL;                                                              \
     106           0 :     _val |= (ulong)(_byte & 0x7F) << _shift;                                   \
     107           0 :     if( FD_LIKELY( !(_byte & 0x80) ) ) {                                       \
     108           0 :       CHECK( (_val>>_shift)==(ulong)_byte );     /* last byte not truncated */ \
     109           0 :       CHECK( _byte || !_shift );                 /* no trailing zero bytes */  \
     110           0 :       (dst) = _val;                                                            \
     111           0 :       break;                                                                   \
     112           0 :     }                                                                          \
     113           0 :     _shift += 7U;                                                              \
     114           0 :     CHECK( _shift<64U );                                                       \
     115           0 :   }                                                                            \
     116           0 : } while( 0 )
     117             : 
     118           0 : #define READ_COMPACT_U16( dst, data, sz ) do {      \
     119           0 :   ulong _n = fd_cu16_dec( *(data), *(sz), &(dst) ); \
     120           0 :   CHECK( _n );                                      \
     121           0 :   *(data) += _n;                                    \
     122           0 :   *(sz)   -= _n;                                    \
     123           0 : } while( 0 )
     124             : 
     125             : /**********************************************************************/
     126             : /* Write macros                                                       */
     127             : /**********************************************************************/
     128             : 
     129       29394 : #define WRITE_BYTES( src, n, out, out_sz ) do { \
     130       29394 :   CHECK( (n)<=(*(out_sz)) );                    \
     131       29394 :   fd_memcpy( *(out), (src), (n) );              \
     132       29394 :   *(out) += (n);                                \
     133       29394 :   *(out_sz) -= (n);                             \
     134       29394 : } while( 0 )
     135             : 
     136        8415 : #define WRITE_U8( val, out, out_sz ) do { \
     137        8415 :   CHECK( 1UL<=(*(out_sz)) );              \
     138        8415 :   FD_STORE( uchar, *(out), (val) );       \
     139        8415 :   *(out) += 1UL;                          \
     140        8415 :   *(out_sz) -= 1UL;                       \
     141        8415 : } while( 0 )
     142             : 
     143        8400 : #define WRITE_U16( val, out, out_sz ) do { \
     144        8400 :   CHECK( 2UL<=(*(out_sz)) );               \
     145        8400 :   FD_STORE( ushort, *(out), (val) );       \
     146        8400 :   *(out) += 2UL;                           \
     147        8400 :   *(out_sz) -= 2UL;                        \
     148        8400 : } while( 0 )
     149             : 
     150        4215 : #define WRITE_U32( val, out, out_sz ) do { \
     151        4215 :   CHECK( 4UL<=(*(out_sz)) );               \
     152        4215 :   FD_STORE( uint, *(out), (val) );         \
     153        4215 :   *(out) += 4UL;                           \
     154        4215 :   *(out_sz) -= 4UL;                        \
     155        4215 : } while( 0 )
     156             : 
     157       21021 : #define WRITE_U64( val, out, out_sz ) do { \
     158       21021 :   CHECK( 8UL<=(*(out_sz)) );               \
     159       21021 :   FD_STORE( ulong, *(out), (val) );        \
     160       21021 :   *(out) += 8UL;                           \
     161       21021 :   *(out_sz) -= 8UL;                        \
     162       21021 : } while( 0 )
     163             : 
     164             : #define WRITE_I64( val, out, out_sz ) do { \
     165             :   CHECK( 8UL<=(*(out_sz)) );               \
     166             :   FD_STORE( long, *(out), (val) );         \
     167             :   *(out) += 8UL;                           \
     168             :   *(out_sz) -= 8UL;                        \
     169             : } while( 0 )
     170             : 
     171             : #define WRITE_PUBKEY( src, out, out_sz ) \
     172       21000 :   WRITE_BYTES( (src).uc, 32UL, out, out_sz )
     173             : 
     174             : #define WRITE_BOOL( val, out, out_sz ) \
     175        8400 :   WRITE_U8( (uchar)!!(val), out, out_sz )
     176             : 
     177        4200 : #define WRITE_OPTION WRITE_BOOL
     178             : 
     179             : /**********************************************************************/
     180             : /* Vote account state -- deserialization helpers                       */
     181             : /* Each returns 0 on success, 1 on failure.                           */
     182             : /**********************************************************************/
     183             : 
     184             : /* Votes (is_v1_14_11=1 for v1_14_11 Vec<Lockout>, 0 for v3/v4
     185             :    Vec<LandedVote>) */
     186             : static int
     187             : deser_votes( fd_landed_vote_t * votes,
     188             :              int                is_v1_14_11,
     189             :              uchar const **     ptr,
     190         201 :              ulong *            rem ) {
     191         201 :   ulong votes_len;
     192         201 :   READ_U64( votes_len, ptr, rem );
     193         201 :   CHECK( votes_len<=MAX_LOCKOUT_HISTORY );
     194             : 
     195         222 :   for( ulong i=0UL; i<votes_len; i++ ) {
     196          21 :     fd_landed_vote_t * elem = deq_fd_landed_vote_t_push_tail_nocopy( votes );
     197          21 :     if( is_v1_14_11 ) {
     198           0 :       elem->latency = 0; /* Unused field for v1_14_11 */
     199          21 :     } else {
     200          21 :       READ_U8( elem->latency, ptr, rem );
     201          21 :     }
     202          21 :     READ_U64( elem->lockout.slot, ptr, rem );
     203          21 :     READ_U32( elem->lockout.confirmation_count, ptr, rem );
     204          21 :   }
     205         201 :   return 0;
     206         201 : }
     207             : 
     208             : /* Root slot (Option<u64>) */
     209             : static int
     210             : deser_root_slot( uchar *         has_root_slot,
     211             :                  ulong *         root_slot,
     212             :                  uchar const **  ptr,
     213         201 :                  ulong *         rem ) {
     214         201 :   uchar opt;
     215         201 :   READ_OPTION( opt, ptr, rem );
     216         201 :   *has_root_slot = opt;
     217         201 :   if( opt ) {
     218           6 :     READ_U64( *root_slot, ptr, rem );
     219           6 :   }
     220         201 :   return 0;
     221         201 : }
     222             : 
     223             : /* Authorized voters (BTreeMap<u64, Pubkey>) */
     224             : static int
     225             : deser_authorized_voters( fd_vote_authorized_voter_t *        pool,
     226             :                          fd_vote_authorized_voters_treap_t * treap,
     227             :                          uchar const **                      ptr,
     228         201 :                          ulong *                             rem ) {
     229         201 :   ulong authorized_voters_len;
     230         201 :   READ_U64( authorized_voters_len, ptr, rem );
     231         201 :   CHECK( authorized_voters_len<=MAX_AUTHORIZED_VOTERS );
     232         399 :   for( ulong i=0UL; i<authorized_voters_len; i++ ) {
     233         198 :     fd_vote_authorized_voter_t * voter = fd_vote_authorized_voters_pool_ele_acquire( pool );
     234         198 :     READ_U64( voter->epoch, ptr, rem );
     235         198 :     READ_PUBKEY( voter->pubkey, ptr, rem );
     236         198 :     voter->prio = voter->pubkey.uc[0];
     237             : 
     238             :     /* Check for existing entries, overwrite if exists */
     239         198 :     fd_vote_authorized_voter_t * existing_voter = fd_vote_authorized_voters_treap_ele_query( treap, voter->epoch, pool );
     240         198 :     if( FD_UNLIKELY( existing_voter ) ) {
     241           0 :       fd_vote_authorized_voters_treap_ele_remove( treap, existing_voter, pool );
     242           0 :       fd_vote_authorized_voters_pool_ele_release( pool, existing_voter );
     243           0 :     }
     244             : 
     245         198 :     fd_vote_authorized_voters_treap_ele_insert( treap, voter, pool );
     246         198 :   }
     247         201 :   return 0;
     248         201 : }
     249             : 
     250             : /* Prior voters (fixed-size circular buffer of 32 entries)
     251             :    We can directly memcpy the entire buffer because the wire
     252             :    format is identical to the in-memory representation of the
     253             :    array. */
     254             : static int
     255             : deser_prior_voters( fd_vote_prior_voters_t * prior_voters,
     256             :                     uchar const **           ptr,
     257           6 :                     ulong *                  rem ) {
     258           6 :   READ_BYTES( prior_voters->buf, PRIOR_VOTERS_MAX*sizeof(fd_vote_prior_voter_t), ptr, rem );
     259           6 :   READ_U64( prior_voters->idx, ptr, rem );
     260           6 :   READ_BOOL( prior_voters->is_empty, ptr, rem );
     261           6 :   return 0;
     262           6 : }
     263             : 
     264             : /* Epoch credits (Vec<EpochCredits>) */
     265             : static int
     266             : deser_epoch_credits( fd_vote_epoch_credits_t * epoch_credits,
     267             :                      uchar const **            ptr,
     268         201 :                      ulong *                   rem ) {
     269         201 :   ulong epoch_credits_len;
     270         201 :   READ_U64( epoch_credits_len, ptr, rem );
     271         201 :   CHECK( epoch_credits_len<=MAX_EPOCH_CREDITS_HISTORY );
     272         225 :   for( ulong i=0UL; i<epoch_credits_len; i++ ) {
     273          24 :     fd_vote_epoch_credits_t * elem = deq_fd_vote_epoch_credits_t_push_tail_nocopy( epoch_credits );
     274          24 :     READ_BYTES( elem, sizeof(fd_vote_epoch_credits_t), ptr, rem );
     275          24 :   }
     276         201 :   return 0;
     277         201 : }
     278             : 
     279             : /**********************************************************************/
     280             : /* Vote account state -- serialization helpers                        */
     281             : /* Each returns 0 on success, 1 on failure.                           */
     282             : /**********************************************************************/
     283             : 
     284             : /* Votes (is_v1_14_11=1 for v1_14_11 Vec<Lockout>, 0 for v3/v4
     285             :    Vec<LandedVote>) */
     286             : static int
     287             : ser_votes( fd_landed_vote_t const * votes,
     288             :            int                      is_v1_14_11,
     289             :            uchar **                 out,
     290        4200 :            ulong *                  out_sz ) {
     291        4200 :   if( FD_UNLIKELY( votes==NULL ) ) {
     292           0 :     WRITE_U64( 0UL, out, out_sz );
     293           0 :     return 0;
     294           0 :   }
     295             : 
     296        4200 :   ulong votes_len = deq_fd_landed_vote_t_cnt( votes );
     297        4200 :   WRITE_U64( votes_len, out, out_sz );
     298             : 
     299        4200 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( votes );
     300        4215 :        !deq_fd_landed_vote_t_iter_done( votes, iter );
     301        4200 :        iter = deq_fd_landed_vote_t_iter_next( votes, iter ) ) {
     302          15 :     fd_landed_vote_t const * elem = deq_fd_landed_vote_t_iter_ele_const( votes, iter );
     303          15 :     if( !is_v1_14_11 ) {
     304          15 :       WRITE_U8( elem->latency, out, out_sz );
     305          15 :     }
     306          15 :     WRITE_U64( elem->lockout.slot, out, out_sz );
     307          15 :     WRITE_U32( elem->lockout.confirmation_count, out, out_sz );
     308          15 :   }
     309        4200 :   return 0;
     310        4200 : }
     311             : 
     312             : /* Root slot (Option<u64>) */
     313             : static int
     314             : ser_root_slot( uchar    has_root_slot,
     315             :                ulong    root_slot,
     316             :                uchar ** out,
     317        4200 :                ulong *  out_sz ) {
     318        4200 :   WRITE_BOOL( has_root_slot, out, out_sz );
     319        4200 :   if( has_root_slot ) {
     320           6 :     WRITE_U64( root_slot, out, out_sz );
     321           6 :   }
     322        4200 :   return 0;
     323        4200 : }
     324             : 
     325             : /* Authorized voters (BTreeMap<u64, Pubkey>) */
     326             : static int
     327             : ser_authorized_voters( fd_vote_authorized_voter_t const *        pool,
     328             :                        fd_vote_authorized_voters_treap_t const * treap,
     329             :                        uchar **                                  out,
     330        4200 :                        ulong *                                   out_sz ) {
     331        4200 :   if( FD_UNLIKELY( treap==NULL ) ) {
     332           0 :     WRITE_U64( 0UL, out, out_sz );
     333           0 :     return 0;
     334           0 :   }
     335             : 
     336        4200 :   ulong len = fd_vote_authorized_voters_treap_ele_cnt( treap );
     337        4200 :   WRITE_U64( len, out, out_sz );
     338             : 
     339        4200 :   for( fd_vote_authorized_voters_treap_fwd_iter_t iter = fd_vote_authorized_voters_treap_fwd_iter_init( treap, pool );
     340        8400 :        !fd_vote_authorized_voters_treap_fwd_iter_done( iter );
     341        4200 :        iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, pool ) ) {
     342        4200 :     fd_vote_authorized_voter_t const * voter = fd_vote_authorized_voters_treap_fwd_iter_ele_const( iter, pool );
     343        4200 :     WRITE_U64( voter->epoch, out, out_sz );
     344        4200 :     WRITE_PUBKEY( voter->pubkey, out, out_sz );
     345        4200 :   }
     346        4200 :   return 0;
     347        4200 : }
     348             : 
     349             : /* Prior voters (fixed-size circular buffer of 32 entries)
     350             :    We can directly memcpy the entire buffer because the wire
     351             :    format is identical to the in-memory representation of the
     352             :    array. */
     353             : static int
     354             : ser_prior_voters( fd_vote_prior_voters_t const * prior_voters,
     355             :                   uchar **                       out,
     356           0 :                   ulong *                        out_sz ) {
     357           0 :   WRITE_BYTES( prior_voters->buf, PRIOR_VOTERS_MAX*sizeof(fd_vote_prior_voter_t), out, out_sz );
     358           0 :   WRITE_U64( prior_voters->idx, out, out_sz );
     359           0 :   WRITE_BOOL( prior_voters->is_empty, out, out_sz );
     360           0 :   return 0;
     361           0 : }
     362             : 
     363             : /* Epoch credits (Vec<EpochCredits>) */
     364             : static int
     365             : ser_epoch_credits( fd_vote_epoch_credits_t const * epoch_credits,
     366             :                    uchar **                        out,
     367        4200 :                    ulong *                         out_sz ) {
     368        4200 :   if( FD_UNLIKELY( epoch_credits==NULL ) ) {
     369           0 :     WRITE_U64( 0UL, out, out_sz );
     370           0 :     return 0;
     371           0 :   }
     372             : 
     373        4200 :   ulong len = deq_fd_vote_epoch_credits_t_cnt( epoch_credits );
     374        4200 :   WRITE_U64( len, out, out_sz );
     375             : 
     376        4200 :   for( deq_fd_vote_epoch_credits_t_iter_t iter = deq_fd_vote_epoch_credits_t_iter_init( epoch_credits );
     377        4269 :        !deq_fd_vote_epoch_credits_t_iter_done( epoch_credits, iter );
     378        4200 :        iter = deq_fd_vote_epoch_credits_t_iter_next( epoch_credits, iter ) ) {
     379          69 :     fd_vote_epoch_credits_t const * elem = deq_fd_vote_epoch_credits_t_iter_ele_const( epoch_credits, iter );
     380          69 :     WRITE_BYTES( elem, sizeof(fd_vote_epoch_credits_t), out, out_sz );
     381          69 :   }
     382        4200 :   return 0;
     383        4200 : }
     384             : 
     385             : /**********************************************************************/
     386             : /* Wire layout offsets                                                */
     387             : /**********************************************************************/
     388             : 
     389             : /* Fixed-offset byte positions within the bincode wire format.
     390             :    For v1_14_11 and v3 the fixed prefix is: discriminant, node_pubkey,
     391             :    authorized_withdrawer, commission.  For v4 the prefix additionally
     392             :    includes inflation_rewards_collector, block_revenue_collector,
     393             :    inflation_rewards_commission_bps, block_revenue_commission_bps,
     394             :    and pending_delegator_rewards before the first variable field. */
     395             : 
     396         339 : #define WIRE_OFF_NODE_PUBKEY                    (4UL)
     397           0 : #define WIRE_OFF_V1V3_COMMISSION                (68UL)  /* 4 + 32 + 32 */
     398         339 : #define WIRE_OFF_V4_INFLATION_REWARDS_COLLECTOR (68UL)  /* 4 + 32 + 32 */
     399         339 : #define WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR     (100UL) /* 4 + 32 + 32 + 32 */
     400             : #define WIRE_OFF_V4_COMMISSION_BPS              (132UL) /* 4 + 32 + 32 + 32 + 32 */
     401             : 
     402             : /* Byte size of a Lockout on the wire: u64 slot + u32 confirmation_count */
     403           0 : #define WIRE_LOCKOUT_SZ     (12UL)
     404             : /* Byte size of a LandedVote on the wire: u8 latency + u64 slot + u32 confirmation_count */
     405          72 : #define WIRE_LANDED_VOTE_SZ (13UL)
     406             : /* Byte size of an authorized voter entry: u64 epoch + 32B pubkey */
     407          72 : #define WIRE_AUTH_VOTER_SZ  (40UL)
     408             : /* Byte size of prior_voters on the wire: 32 * 48B + 8B idx + 1B is_empty */
     409           0 : #define WIRE_PRIOR_VOTERS_SZ (PRIOR_VOTERS_MAX * 48UL + 8UL + 1UL)
     410             : 
     411             : /* Offset of the votes vector (v1/v3) or BLS option (v4) — first byte
     412             :    after the fixed-offset prefix. */
     413           0 : #define WIRE_VOTES_OFF_V1_V3 (69UL)   /* 4 + 32 + 32 + 1 */
     414        1437 : #define WIRE_BLS_OFF_V4      (144UL)  /* 4 + 32 + 32 + 32 + 32 + 2 + 2 + 8 */
     415             : 
     416             : /**********************************************************************/
     417             : /* Vote account state -- direct field accessors                       */
     418             : /* These read fields directly from raw bincode-encoded vote account   */
     419             : /* data without full deserialization.                                  */
     420             : /**********************************************************************/
     421             : 
     422             : int
     423             : fd_vote_account_node_pubkey( uchar const *  data,
     424             :                              ulong          data_sz,
     425         339 :                              fd_pubkey_t *  out ) {
     426         339 :   CHECK( data_sz>=WIRE_OFF_NODE_PUBKEY+32UL );
     427         339 :   fd_memcpy( out, data+WIRE_OFF_NODE_PUBKEY, 32UL );
     428         339 :   return 0;
     429         339 : }
     430             : 
     431             : int
     432             : fd_vote_account_commission_bps( uchar const * data,
     433             :                                 ulong         data_sz,
     434             :                                 int           commission_rate_in_basis_points,
     435         339 :                                 ushort *      out ) {
     436         339 :   uchar const * ptr       = data;
     437         339 :   ulong         remaining = data_sz;
     438             : 
     439         339 :   uint discriminant;
     440         339 :   READ_U32( discriminant, &ptr, &remaining );
     441             : 
     442         339 :   switch( discriminant ) {
     443           0 :     case fd_vote_state_versioned_enum_v1_14_11: /* fallthrough */
     444           0 :     case fd_vote_state_versioned_enum_v3:
     445           0 :       CHECK( data_sz>WIRE_OFF_V1V3_COMMISSION );
     446           0 :       *out = data[ WIRE_OFF_V1V3_COMMISSION ] * 100U;
     447           0 :       return 0;
     448         339 :     case fd_vote_state_versioned_enum_v4:
     449         339 :       CHECK( data_sz>=WIRE_OFF_V4_COMMISSION_BPS+2UL );
     450         339 :       *out = FD_LOAD( ushort, data+WIRE_OFF_V4_COMMISSION_BPS );
     451             : 
     452             :       /* Round down to the nearest whole percentage if SIMD-0291 is not
     453             :          yet active. */
     454         339 :       if( !commission_rate_in_basis_points ) {
     455         267 :         *out = (*out / 100U) * 100U;
     456         267 :       }
     457         339 :       return 0;
     458           0 :     default:
     459           0 :       return 1;
     460         339 :   }
     461         339 : }
     462             : 
     463             : int
     464             : fd_vote_account_collectors( uchar const *       data,
     465             :                             ulong               data_sz,
     466             :                             fd_pubkey_t const * vote_pubkey,
     467             :                             fd_pubkey_t const * node_pubkey,
     468             :                             fd_pubkey_t *       inflation_rewards_collector_out,
     469         339 :                             fd_pubkey_t *       block_revenue_collector_out ) {
     470         339 :   uchar const * ptr       = data;
     471         339 :   ulong         remaining = data_sz;
     472             : 
     473         339 :   uint discriminant;
     474         339 :   READ_U32( discriminant, &ptr, &remaining );
     475             : 
     476         339 :   switch( discriminant ) {
     477           0 :     case fd_vote_state_versioned_enum_v1_14_11: /* fallthrough */
     478           0 :     case fd_vote_state_versioned_enum_v3:
     479             :       /* Pre-v4 vote states have no collector fields: default to the
     480             :          vote account (inflation) and the node identity (block
     481             :          revenue). */
     482           0 :       *inflation_rewards_collector_out = *vote_pubkey;
     483           0 :       *block_revenue_collector_out     = *node_pubkey;
     484           0 :       return 0;
     485         339 :     case fd_vote_state_versioned_enum_v4:
     486         339 :       CHECK( data_sz>=WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR+32UL );
     487         339 :       fd_memcpy( inflation_rewards_collector_out, data+WIRE_OFF_V4_INFLATION_REWARDS_COLLECTOR, 32UL );
     488         339 :       fd_memcpy( block_revenue_collector_out,     data+WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR,     32UL );
     489         339 :       return 0;
     490           0 :     default:
     491           0 :       return 1;
     492         339 :   }
     493         339 : }
     494             : 
     495             : /* Seeks past variable-length fields to the start of epoch_credits.
     496             :    On success sets *out_ptr to the first entry and *out_cnt to the
     497             :    entry count.  Returns 0 on success, 1 on error. */
     498             : 
     499             : static int
     500             : seek_epoch_credits( uchar const *                    data,
     501             :                     ulong                            data_sz,
     502             :                     fd_vote_epoch_credits_t const ** out_ptr,
     503         747 :                     ulong *                          out_cnt ) {
     504         747 :   uchar const * ptr       = data;
     505         747 :   ulong         remaining = data_sz;
     506             : 
     507         747 :   uint discriminant;
     508         747 :   READ_U32( discriminant, &ptr, &remaining );
     509             : 
     510         747 :   switch( discriminant ) {
     511           0 :     case fd_vote_state_versioned_enum_v1_14_11: {
     512           0 :       SKIP_BYTES( WIRE_VOTES_OFF_V1_V3-4UL, &ptr, &remaining );
     513             : 
     514             :       /* Skip votes Vec<Lockout> */
     515           0 :       ulong votes_len;
     516           0 :       READ_U64( votes_len, &ptr, &remaining );
     517           0 :       CHECK_U64_MUL_OVERFLOW( votes_len, WIRE_LOCKOUT_SZ );
     518           0 :       SKIP_BYTES( votes_len*WIRE_LOCKOUT_SZ, &ptr, &remaining );
     519             : 
     520             :       /* Skip root_slot Option<u64> */
     521           0 :       uchar has_root_slot;
     522           0 :       READ_U8( has_root_slot, &ptr, &remaining );
     523           0 :       if( has_root_slot ) {
     524           0 :         SKIP_BYTES( 8UL, &ptr, &remaining );
     525           0 :       }
     526             : 
     527             :       /* Skip authorized_voters BTreeMap<u64, Pubkey> */
     528           0 :       ulong authorized_voters_len;
     529           0 :       READ_U64( authorized_voters_len, &ptr, &remaining );
     530           0 :       CHECK_U64_MUL_OVERFLOW( authorized_voters_len, WIRE_AUTH_VOTER_SZ );
     531           0 :       SKIP_BYTES( authorized_voters_len*WIRE_AUTH_VOTER_SZ, &ptr, &remaining );
     532             : 
     533             :       /* Skip prior_voters (fixed size) */
     534           0 :       SKIP_BYTES( WIRE_PRIOR_VOTERS_SZ, &ptr, &remaining );
     535           0 :       break;
     536           0 :     }
     537             : 
     538           0 :     case fd_vote_state_versioned_enum_v3: {
     539           0 :       SKIP_BYTES( WIRE_VOTES_OFF_V1_V3-4UL, &ptr, &remaining );
     540             : 
     541             :       /* Skip votes Vec<LandedVote> */
     542           0 :       ulong votes_len;
     543           0 :       READ_U64( votes_len, &ptr, &remaining );
     544           0 :       CHECK_U64_MUL_OVERFLOW( votes_len, WIRE_LANDED_VOTE_SZ );
     545           0 :       SKIP_BYTES( votes_len*WIRE_LANDED_VOTE_SZ, &ptr, &remaining );
     546             : 
     547             :       /* Skip root_slot Option<u64> */
     548           0 :       uchar has_root_slot;
     549           0 :       READ_U8( has_root_slot, &ptr, &remaining );
     550           0 :       if( has_root_slot ) {
     551           0 :         SKIP_BYTES( 8UL, &ptr, &remaining );
     552           0 :       }
     553             : 
     554             :       /* Skip authorized_voters BTreeMap<u64, Pubkey> */
     555           0 :       ulong authorized_voters_len;
     556           0 :       READ_U64( authorized_voters_len, &ptr, &remaining );
     557           0 :       CHECK_U64_MUL_OVERFLOW( authorized_voters_len, WIRE_AUTH_VOTER_SZ );
     558           0 :       SKIP_BYTES( authorized_voters_len*WIRE_AUTH_VOTER_SZ, &ptr, &remaining );
     559             : 
     560             :       /* Skip prior_voters (fixed size) */
     561           0 :       SKIP_BYTES( WIRE_PRIOR_VOTERS_SZ, &ptr, &remaining );
     562           0 :       break;
     563           0 :     }
     564             : 
     565         747 :     case fd_vote_state_versioned_enum_v4: {
     566         747 :       SKIP_BYTES( WIRE_BLS_OFF_V4-4UL, &ptr, &remaining );
     567             : 
     568             :       /* Skip Option<bls_pubkey_compressed> */
     569         747 :       uchar has_bls_pubkey;
     570         747 :       READ_U8( has_bls_pubkey, &ptr, &remaining );
     571         747 :       if( has_bls_pubkey ) {
     572         690 :         SKIP_BYTES( FD_BLS_PUBKEY_COMPRESSED_SZ, &ptr, &remaining );
     573         690 :       }
     574             : 
     575             :       /* Skip votes Vec<LandedVote> */
     576         747 :       ulong votes_len;
     577         747 :       READ_U64( votes_len, &ptr, &remaining );
     578         747 :       CHECK_U64_MUL_OVERFLOW( votes_len, WIRE_LANDED_VOTE_SZ );
     579         747 :       SKIP_BYTES( votes_len*WIRE_LANDED_VOTE_SZ, &ptr, &remaining );
     580             : 
     581             :       /* Skip root_slot Option<u64> */
     582         747 :       uchar has_root_slot;
     583         747 :       READ_U8( has_root_slot, &ptr, &remaining );
     584         747 :       if( has_root_slot ) {
     585           0 :         SKIP_BYTES( 8UL, &ptr, &remaining );
     586           0 :       }
     587             : 
     588             :       /* Skip authorized_voters BTreeMap<u64, Pubkey> */
     589         747 :       ulong authorized_voters_len;
     590         747 :       READ_U64( authorized_voters_len, &ptr, &remaining );
     591         747 :       CHECK_U64_MUL_OVERFLOW( authorized_voters_len, WIRE_AUTH_VOTER_SZ );
     592         747 :       SKIP_BYTES( authorized_voters_len*WIRE_AUTH_VOTER_SZ, &ptr, &remaining );
     593         747 :       break;
     594         747 :     }
     595             : 
     596         747 :     default:
     597           0 :       return 1;
     598         747 :   }
     599             : 
     600             :   /* Now at epoch_credits deque */
     601         747 :   ulong epoch_credits_len;
     602         747 :   READ_U64( epoch_credits_len, &ptr, &remaining );
     603         747 :   CHECK( epoch_credits_len<=MAX_EPOCH_CREDITS_HISTORY );
     604         747 :   CHECK_U64_MUL_OVERFLOW( epoch_credits_len, sizeof(fd_vote_epoch_credits_t) );
     605         747 :   CHECK( epoch_credits_len*sizeof(fd_vote_epoch_credits_t)<=remaining );
     606             : 
     607         747 :   *out_ptr = (fd_vote_epoch_credits_t const *)ptr;
     608         747 :   *out_cnt = epoch_credits_len;
     609         747 :   return 0;
     610         747 : }
     611             : 
     612             : int
     613             : fd_vote_account_last_timestamp( uchar const *             data,
     614             :                                 ulong                     data_sz,
     615         408 :                                 fd_vote_block_timestamp_t * out ) {
     616         408 :   fd_vote_epoch_credits_t const * epoch_credits_ptr;
     617         408 :   ulong                           epoch_credits_len;
     618         408 :   CHECK( !seek_epoch_credits( data, data_sz, &epoch_credits_ptr, &epoch_credits_len ) );
     619             : 
     620         408 :   uchar const * timestamp_ptr = (uchar const *)( epoch_credits_ptr + epoch_credits_len );
     621         408 :   CHECK( timestamp_ptr+sizeof(fd_vote_block_timestamp_t)<=data+data_sz );
     622             : 
     623         408 :   fd_memcpy( out, timestamp_ptr, sizeof(fd_vote_block_timestamp_t) );
     624         408 :   return 0;
     625         408 : }
     626             : 
     627             : int
     628             : fd_vote_account_is_v4_with_bls_pubkey( uchar const * data,
     629        1026 :                                        ulong         data_sz ) {
     630        1026 :   if( FD_UNLIKELY( data_sz<WIRE_BLS_OFF_V4+1UL ) ) return 0;
     631        1026 :   uint discriminant = FD_LOAD( uint, data );
     632        1026 :   if( discriminant!=fd_vote_state_versioned_enum_v4 ) return 0;
     633        1026 :   return !!data[ WIRE_BLS_OFF_V4 ];
     634        1026 : }
     635             : 
     636             : int
     637             : fd_vote_account_bls_pubkey( uchar const * data,
     638             :                             ulong         data_sz,
     639         339 :                             uchar         out[ static FD_BLS_PUBKEY_COMPRESSED_SZ ] ) {
     640         339 :   if( FD_UNLIKELY( !fd_vote_account_is_v4_with_bls_pubkey( data, data_sz ) )      ) return 1;
     641         339 :   if( FD_UNLIKELY( data_sz<WIRE_BLS_OFF_V4+1UL+FD_BLS_PUBKEY_COMPRESSED_SZ )      ) return 1;
     642         339 :   fd_memcpy( out, data+WIRE_BLS_OFF_V4+1UL, FD_BLS_PUBKEY_COMPRESSED_SZ );
     643         339 :   return 0;
     644         339 : }
     645             : 
     646             : fd_vote_epoch_credits_t const *
     647             : fd_vote_account_epoch_credits( uchar const * data,
     648             :                                ulong         data_sz,
     649         339 :                                ulong *       cnt ) {
     650         339 :   fd_vote_epoch_credits_t const * ptr;
     651         339 :   CHECK_RET_NULL( !seek_epoch_credits( data, data_sz, &ptr, cnt ) );
     652         339 :   return ptr;
     653         339 : }
     654             : 
     655             : /**********************************************************************/
     656             : /* Vote account state -- public API                                   */
     657             : /**********************************************************************/
     658             : 
     659             : fd_vote_state_versioned_t *
     660             : fd_vote_state_versioned_new( fd_vote_state_versioned_t * self,
     661        4323 :                              uint                        kind ) {
     662        4323 :   if( FD_UNLIKELY( !self ) ) {
     663           0 :     FD_LOG_WARNING(( "NULL mem" ));
     664           0 :     return NULL;
     665           0 :   }
     666             : 
     667             :   /* Init and join data structures */
     668        4323 :   fd_landed_vote_t * votes = deq_fd_landed_vote_t_join(
     669        4323 :     deq_fd_landed_vote_t_new( self->landed_votes_mem, MAX_LOCKOUT_HISTORY_CAPACITY )
     670        4323 :   );
     671        4323 :   fd_vote_epoch_credits_t * epoch_credits = deq_fd_vote_epoch_credits_t_join(
     672        4323 :     deq_fd_vote_epoch_credits_t_new( self->epoch_credits_mem )
     673        4323 :   );
     674        4323 :   fd_vote_authorized_voter_t * authorized_voters_pool  = fd_vote_authorized_voters_pool_join(
     675        4323 :     fd_vote_authorized_voters_pool_new( self->authorized_voters_pool_mem, MAX_AUTHORIZED_VOTERS_CAPACITY )
     676        4323 :   );
     677        4323 :   fd_vote_authorized_voters_treap_t * authorized_voters_treap = fd_vote_authorized_voters_treap_join(
     678        4323 :     fd_vote_authorized_voters_treap_new( self->authorized_voters_treap_mem, MAX_AUTHORIZED_VOTERS_CAPACITY )
     679        4323 :   );
     680             : 
     681        4323 :   self->kind = kind;
     682        4323 :   switch( kind ) {
     683          27 :     case fd_vote_state_versioned_enum_uninitialized:
     684          27 :       break;
     685           3 :     case fd_vote_state_versioned_enum_v1_14_11:
     686           3 :       memset( &self->v1_14_11, 0, sizeof(fd_vote_state_1_14_11_t) );
     687           3 :       self->v1_14_11.votes                   = votes;
     688           3 :       self->v1_14_11.epoch_credits           = epoch_credits;
     689           3 :       self->v1_14_11.authorized_voters.pool  = authorized_voters_pool;
     690           3 :       self->v1_14_11.authorized_voters.treap = authorized_voters_treap;
     691           3 :       break;
     692           9 :     case fd_vote_state_versioned_enum_v3:
     693           9 :       memset( &self->v3, 0, sizeof(fd_vote_state_v3_t) );
     694           9 :       self->v3.votes                   = votes;
     695           9 :       self->v3.epoch_credits           = epoch_credits;
     696           9 :       self->v3.authorized_voters.pool  = authorized_voters_pool;
     697           9 :       self->v3.authorized_voters.treap = authorized_voters_treap;
     698           9 :       break;
     699        4284 :     case fd_vote_state_versioned_enum_v4:
     700        4284 :       memset( &self->v4, 0, sizeof(fd_vote_state_v4_t) );
     701        4284 :       self->v4.votes                    = votes;
     702        4284 :       self->v4.epoch_credits            = epoch_credits;
     703        4284 :       self->v4.authorized_voters.pool   = authorized_voters_pool;
     704        4284 :       self->v4.authorized_voters.treap  = authorized_voters_treap;
     705        4284 :       break;
     706           0 :     default:
     707           0 :       return NULL;
     708        4323 :   }
     709             : 
     710        4323 :   return self;
     711        4323 : }
     712             : 
     713             : static int
     714             : fd_vote_state_versioned_deserialize_inner( fd_vote_state_versioned_t * self,
     715             :                                            uchar const *               payload,
     716         237 :                                            ulong                       payload_sz ) {
     717         237 :   CHECK( self!=NULL );
     718         237 :   CHECK( payload!=NULL );
     719             : 
     720         237 :   uchar const * ptr = payload;
     721         237 :   ulong         rem = payload_sz;
     722             : 
     723         237 :   uint kind;
     724         237 :   READ_U32( kind, &ptr, &rem );
     725             : 
     726         237 :   CHECK( fd_vote_state_versioned_new( self, kind )!=NULL );
     727             : 
     728         237 :   switch( self->kind ) {
     729          27 :     case fd_vote_state_versioned_enum_uninitialized:
     730             :       /* No-op, nothing to decode */
     731          27 :       return 0;
     732             : 
     733           3 :     case fd_vote_state_versioned_enum_v1_14_11: {
     734           3 :       READ_PUBKEY( self->v1_14_11.node_pubkey, &ptr, &rem );
     735           0 :       READ_PUBKEY( self->v1_14_11.authorized_withdrawer, &ptr, &rem );
     736           0 :       READ_U8( self->v1_14_11.commission, &ptr, &rem );
     737           0 :       CHECK( !deser_votes( self->v1_14_11.votes, 1, &ptr, &rem ) ); /* v1_14_11 wire format is Lockout, not LandedVote */
     738           0 :       CHECK( !deser_root_slot( &self->v1_14_11.has_root_slot, &self->v1_14_11.root_slot, &ptr, &rem ) );
     739           0 :       CHECK( !deser_authorized_voters( self->v1_14_11.authorized_voters.pool, self->v1_14_11.authorized_voters.treap, &ptr, &rem ) );
     740           0 :       CHECK( !deser_prior_voters( &self->v1_14_11.prior_voters, &ptr, &rem ) );
     741           0 :       CHECK( !deser_epoch_credits( self->v1_14_11.epoch_credits, &ptr, &rem ) );
     742           0 :       READ_BYTES( &self->v1_14_11.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
     743           0 :       break;
     744           0 :     }
     745             : 
     746           9 :     case fd_vote_state_versioned_enum_v3: {
     747           9 :       READ_PUBKEY( self->v3.node_pubkey, &ptr, &rem );
     748           6 :       READ_PUBKEY( self->v3.authorized_withdrawer, &ptr, &rem );
     749           6 :       READ_U8( self->v3.commission, &ptr, &rem );
     750           6 :       CHECK( !deser_votes( self->v3.votes, 0, &ptr, &rem ) );
     751           6 :       CHECK( !deser_root_slot( &self->v3.has_root_slot, &self->v3.root_slot, &ptr, &rem ) );
     752           6 :       CHECK( !deser_authorized_voters( self->v3.authorized_voters.pool, self->v3.authorized_voters.treap, &ptr, &rem ) );
     753           6 :       CHECK( !deser_prior_voters( &self->v3.prior_voters, &ptr, &rem ) );
     754           6 :       CHECK( !deser_epoch_credits( self->v3.epoch_credits, &ptr, &rem ) );
     755           6 :       READ_BYTES( &self->v3.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
     756           6 :       break;
     757           6 :     }
     758             : 
     759         198 :     case fd_vote_state_versioned_enum_v4: {
     760         198 :       READ_PUBKEY( self->v4.node_pubkey, &ptr, &rem );
     761         195 :       READ_PUBKEY( self->v4.authorized_withdrawer, &ptr, &rem );
     762         195 :       READ_PUBKEY( self->v4.inflation_rewards_collector, &ptr, &rem );
     763         195 :       READ_PUBKEY( self->v4.block_revenue_collector, &ptr, &rem );
     764         195 :       READ_U16( self->v4.inflation_rewards_commission_bps, &ptr, &rem );
     765         195 :       READ_U16( self->v4.block_revenue_commission_bps, &ptr, &rem );
     766         195 :       READ_U64( self->v4.pending_delegator_rewards, &ptr, &rem );
     767             : 
     768             :       /* Option<[u8; 48]> */
     769         195 :       READ_OPTION( self->v4.has_bls_pubkey_compressed, &ptr, &rem );
     770         195 :       if( self->v4.has_bls_pubkey_compressed ) {
     771         102 :         READ_BYTES( self->v4.bls_pubkey_compressed, FD_BLS_PUBKEY_COMPRESSED_SZ, &ptr, &rem );
     772         102 :       }
     773             : 
     774         195 :       CHECK( !deser_votes( self->v4.votes, 0, &ptr, &rem ) );
     775         195 :       CHECK( !deser_root_slot( &self->v4.has_root_slot, &self->v4.root_slot, &ptr, &rem ) );
     776         195 :       CHECK( !deser_authorized_voters( self->v4.authorized_voters.pool, self->v4.authorized_voters.treap, &ptr, &rem ) );
     777         195 :       CHECK( !deser_epoch_credits( self->v4.epoch_credits, &ptr, &rem ) ); /* v4 has no prior_voters */
     778         195 :       READ_BYTES( &self->v4.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
     779         195 :       break;
     780         195 :     }
     781             : 
     782         195 :     default:
     783           0 :       return 1;
     784         237 :   }
     785             : 
     786         201 :   return 0;
     787         237 : }
     788             : 
     789             : fd_vote_state_versioned_t *
     790             : fd_vote_state_versioned_deserialize( fd_vote_state_versioned_t * self,
     791             :                                      uchar const *               payload,
     792         237 :                                      ulong                       payload_sz ) {
     793         237 :   CHECK_RET_NULL( !fd_vote_state_versioned_deserialize_inner( self, payload, payload_sz ) );
     794         228 :   return self;
     795         237 : }
     796             : 
     797             : int
     798             : fd_vote_state_versioned_serialize( fd_vote_state_versioned_t const * self,
     799             :                                    uchar *                           buf,
     800        4200 :                                    ulong                             buf_sz ) {
     801        4200 :   CHECK( self!=NULL );
     802        4200 :   CHECK( buf!=NULL );
     803             : 
     804        4200 :   uchar * out    = buf;
     805        4200 :   ulong   out_sz = buf_sz;
     806             : 
     807        4200 :   WRITE_U32( self->kind, &out, &out_sz );
     808             : 
     809        4200 :   switch( self->kind ) {
     810           0 :     case fd_vote_state_versioned_enum_uninitialized:
     811             :       /* No-op, nothing to encode */
     812           0 :       return 0;
     813             : 
     814           0 :     case fd_vote_state_versioned_enum_v1_14_11: {
     815           0 :       WRITE_PUBKEY( self->v1_14_11.node_pubkey, &out, &out_sz );
     816           0 :       WRITE_PUBKEY( self->v1_14_11.authorized_withdrawer, &out, &out_sz );
     817           0 :       WRITE_U8( self->v1_14_11.commission, &out, &out_sz );
     818           0 :       CHECK( !ser_votes( self->v1_14_11.votes, 1, &out, &out_sz ) ); /* v1_14_11 wire format is Lockout, not LandedVote */
     819           0 :       CHECK( !ser_root_slot( self->v1_14_11.has_root_slot, self->v1_14_11.root_slot, &out, &out_sz ) );
     820           0 :       CHECK( !ser_authorized_voters( self->v1_14_11.authorized_voters.pool, self->v1_14_11.authorized_voters.treap, &out, &out_sz ) );
     821           0 :       CHECK( !ser_prior_voters( &self->v1_14_11.prior_voters, &out, &out_sz ) );
     822           0 :       CHECK( !ser_epoch_credits( self->v1_14_11.epoch_credits, &out, &out_sz ) );
     823           0 :       WRITE_BYTES( &self->v1_14_11.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
     824           0 :       break;
     825           0 :     }
     826             : 
     827           0 :     case fd_vote_state_versioned_enum_v3: {
     828           0 :       WRITE_PUBKEY( self->v3.node_pubkey, &out, &out_sz );
     829           0 :       WRITE_PUBKEY( self->v3.authorized_withdrawer, &out, &out_sz );
     830           0 :       WRITE_U8( self->v3.commission, &out, &out_sz );
     831           0 :       CHECK( !ser_votes( self->v3.votes, 0, &out, &out_sz ) );
     832           0 :       CHECK( !ser_root_slot( self->v3.has_root_slot, self->v3.root_slot, &out, &out_sz ) );
     833           0 :       CHECK( !ser_authorized_voters( self->v3.authorized_voters.pool, self->v3.authorized_voters.treap, &out, &out_sz ) );
     834           0 :       CHECK( !ser_prior_voters( &self->v3.prior_voters, &out, &out_sz ) );
     835           0 :       CHECK( !ser_epoch_credits( self->v3.epoch_credits, &out, &out_sz ) );
     836           0 :       WRITE_BYTES( &self->v3.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
     837           0 :       break;
     838           0 :     }
     839             : 
     840        4200 :     case fd_vote_state_versioned_enum_v4: {
     841        4200 :       WRITE_PUBKEY( self->v4.node_pubkey, &out, &out_sz );
     842        4200 :       WRITE_PUBKEY( self->v4.authorized_withdrawer, &out, &out_sz );
     843        4200 :       WRITE_PUBKEY( self->v4.inflation_rewards_collector, &out, &out_sz );
     844        4200 :       WRITE_PUBKEY( self->v4.block_revenue_collector, &out, &out_sz );
     845        4200 :       WRITE_U16( self->v4.inflation_rewards_commission_bps, &out, &out_sz );
     846        4200 :       WRITE_U16( self->v4.block_revenue_commission_bps, &out, &out_sz );
     847        4200 :       WRITE_U64( self->v4.pending_delegator_rewards, &out, &out_sz );
     848             : 
     849             :       /* Option<[u8; 48]> */
     850        4200 :       WRITE_OPTION( self->v4.has_bls_pubkey_compressed, &out, &out_sz );
     851        4200 :       if( self->v4.has_bls_pubkey_compressed ) {
     852        4125 :         WRITE_BYTES( self->v4.bls_pubkey_compressed, FD_BLS_PUBKEY_COMPRESSED_SZ, &out, &out_sz );
     853        4125 :       }
     854             : 
     855        4200 :       CHECK( !ser_votes( self->v4.votes, 0, &out, &out_sz ) );
     856        4200 :       CHECK( !ser_root_slot( self->v4.has_root_slot, self->v4.root_slot, &out, &out_sz ) );
     857        4200 :       CHECK( !ser_authorized_voters( self->v4.authorized_voters.pool, self->v4.authorized_voters.treap, &out, &out_sz ) );
     858        4200 :       CHECK( !ser_epoch_credits( self->v4.epoch_credits, &out, &out_sz ) ); /* v4 has no prior_voters */
     859        4200 :       WRITE_BYTES( &self->v4.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
     860        4200 :       break;
     861        4200 :     }
     862             : 
     863        4200 :     default:
     864           0 :       return 1;
     865        4200 :   }
     866             : 
     867        4200 :   return 0;
     868        4200 : }
     869             : 
     870             : ulong
     871          72 : fd_vote_state_versioned_serialized_size( fd_vote_state_versioned_t const * self ) {
     872          72 :   switch( self->kind ) {
     873             : 
     874           0 :     case fd_vote_state_versioned_enum_uninitialized:
     875           0 :       return 4UL;
     876             : 
     877           0 :     case fd_vote_state_versioned_enum_v1_14_11: {
     878           0 :       ulong votes_cnt         = self->v1_14_11.votes                   ? deq_fd_landed_vote_t_cnt( self->v1_14_11.votes )                                  : 0UL;
     879           0 :       ulong auth_voters_cnt   = self->v1_14_11.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v1_14_11.authorized_voters.treap ) : 0UL;
     880           0 :       ulong epoch_credits_cnt = self->v1_14_11.epoch_credits           ? deq_fd_vote_epoch_credits_t_cnt( self->v1_14_11.epoch_credits )                   : 0UL;
     881           0 :       return WIRE_VOTES_OFF_V1_V3
     882           0 :            + 8UL + votes_cnt * WIRE_LOCKOUT_SZ
     883           0 :            + 1UL + (ulong)self->v1_14_11.has_root_slot * 8UL
     884           0 :            + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
     885           0 :            + WIRE_PRIOR_VOTERS_SZ
     886           0 :            + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
     887           0 :            + sizeof(fd_vote_block_timestamp_t);
     888           0 :     }
     889             : 
     890           0 :     case fd_vote_state_versioned_enum_v3: {
     891           0 :       ulong votes_cnt         = self->v3.votes                   ? deq_fd_landed_vote_t_cnt( self->v3.votes )                                  : 0UL;
     892           0 :       ulong auth_voters_cnt   = self->v3.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v3.authorized_voters.treap )  : 0UL;
     893           0 :       ulong epoch_credits_cnt = self->v3.epoch_credits           ? deq_fd_vote_epoch_credits_t_cnt( self->v3.epoch_credits )                    : 0UL;
     894           0 :       return WIRE_VOTES_OFF_V1_V3
     895           0 :            + 8UL + votes_cnt * WIRE_LANDED_VOTE_SZ
     896           0 :            + 1UL + (ulong)self->v3.has_root_slot * 8UL
     897           0 :            + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
     898           0 :            + WIRE_PRIOR_VOTERS_SZ
     899           0 :            + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
     900           0 :            + sizeof(fd_vote_block_timestamp_t);
     901           0 :     }
     902             : 
     903          72 :     case fd_vote_state_versioned_enum_v4: {
     904          72 :       ulong votes_cnt         = self->v4.votes                   ? deq_fd_landed_vote_t_cnt( self->v4.votes )                                  : 0UL;
     905          72 :       ulong auth_voters_cnt   = self->v4.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v4.authorized_voters.treap )  : 0UL;
     906          72 :       ulong epoch_credits_cnt = self->v4.epoch_credits           ? deq_fd_vote_epoch_credits_t_cnt( self->v4.epoch_credits )                    : 0UL;
     907          72 :       return WIRE_BLS_OFF_V4
     908          72 :            + 1UL + (ulong)self->v4.has_bls_pubkey_compressed * FD_BLS_PUBKEY_COMPRESSED_SZ
     909          72 :            + 8UL + votes_cnt * WIRE_LANDED_VOTE_SZ
     910          72 :            + 1UL + (ulong)self->v4.has_root_slot * 8UL
     911          72 :            + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
     912          72 :            + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
     913          72 :            + sizeof(fd_vote_block_timestamp_t);
     914           0 :     }
     915             : 
     916           0 :     default:
     917           0 :       return 0UL;
     918          72 :   }
     919          72 : }
     920             : 
     921             : /**********************************************************************/
     922             : /* Vote instruction -- per-variant deserializers                      */
     923             : /**********************************************************************/
     924             : 
     925             : static int
     926             : deser_vote_authorize( fd_vote_authorize_t * out,
     927             :                       uchar const **        data,
     928           3 :                       ulong *               sz ) {
     929           3 :   READ_ENUM( out->discriminant, 3U, data, sz );
     930           3 :   if( out->discriminant==fd_vote_authorize_enum_voter_with_bls ) {
     931           0 :     READ_BYTES( out->voter_with_bls.bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ, data, sz );
     932           0 :     READ_BYTES( out->voter_with_bls.bls_proof_of_possession, FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ, data, sz );
     933           0 :   }
     934           3 :   return 0;
     935           3 : }
     936             : 
     937             : static int
     938             : deser_vote_init( fd_vote_init_t * out,
     939             :                  uchar const **   data,
     940          24 :                  ulong *          sz ) {
     941          24 :   READ_BYTES( out, sizeof(fd_vote_init_t), data, sz );
     942          24 :   return 0;
     943          24 : }
     944             : 
     945             : static int
     946             : deser_vote_init_v2( fd_vote_init_v2_t * out,
     947             :                     uchar const **      data,
     948           6 :                     ulong *             sz ) {
     949           6 :   READ_PUBKEY( out->node_pubkey, data, sz );
     950           6 :   READ_PUBKEY( out->authorized_voter, data, sz );
     951           6 :   READ_BYTES( out->authorized_voter_bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ, data, sz );
     952           6 :   READ_BYTES( out->authorized_voter_bls_proof_of_possession, FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ, data, sz );
     953           6 :   READ_PUBKEY( out->authorized_withdrawer, data, sz );
     954           6 :   READ_U16( out->inflation_rewards_commission_bps, data, sz );
     955           6 :   READ_PUBKEY( out->inflation_rewards_collector, data, sz );
     956           6 :   READ_U16( out->block_revenue_commission_bps, data, sz );
     957           6 :   READ_PUBKEY( out->block_revenue_collector, data, sz );
     958           6 :   return 0;
     959           6 : }
     960             : 
     961             : static int
     962             : deser_vote( fd_vote_t *     out,
     963             :             uchar const **  data,
     964           0 :             ulong *         sz ) {
     965           0 :   ulong slots_len;
     966           0 :   READ_U64( slots_len, data, sz );
     967           0 :   CHECK( slots_len<=FD_VOTE_INSTR_MAX_SLOT_NUMS_LEN );
     968             : 
     969           0 :   out->slots = deq_ulong_join( deq_ulong_new( out->slots_mem, FD_VOTE_INSTR_MAX_SLOT_NUMS_LEN ) );
     970             : 
     971           0 :   for( ulong i=0UL; i<slots_len; i++ ) {
     972           0 :     ulong * elem = deq_ulong_push_tail_nocopy( out->slots );
     973           0 :     READ_U64( *elem, data, sz );
     974           0 :   }
     975             : 
     976           0 :   READ_HASH( out->hash, data, sz );
     977           0 :   READ_OPTION( out->has_timestamp, data, sz );
     978           0 :   if( out->has_timestamp ) {
     979           0 :     READ_I64( out->timestamp, data, sz );
     980           0 :   }
     981           0 :   return 0;
     982           0 : }
     983             : 
     984             : static int
     985             : deser_vote_state_update( fd_vote_state_update_t * out,
     986             :                          uchar const **           data,
     987           0 :                          ulong *                  sz ) {
     988           0 :   ulong lockouts_len;
     989           0 :   READ_U64( lockouts_len, data, sz );
     990           0 :   CHECK( lockouts_len<=FD_VOTE_INSTR_MAX_LOCKOUTS_LEN );
     991             : 
     992           0 :   out->lockouts = deq_fd_vote_lockout_t_join( deq_fd_vote_lockout_t_new( out->lockouts_mem, FD_VOTE_INSTR_MAX_LOCKOUTS_LEN ) );
     993             : 
     994           0 :   for( ulong i=0; i<lockouts_len; i++ ) {
     995           0 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( out->lockouts );
     996           0 :     READ_U64( elem->slot, data, sz );
     997           0 :     READ_U32( elem->confirmation_count, data, sz );
     998           0 :   }
     999             : 
    1000           0 :   READ_OPTION( out->has_root, data, sz );
    1001           0 :   if( out->has_root ) {
    1002           0 :     READ_U64( out->root, data, sz );
    1003           0 :   }
    1004           0 :   READ_HASH( out->hash, data, sz );
    1005           0 :   READ_OPTION( out->has_timestamp, data, sz );
    1006           0 :   if( out->has_timestamp ) {
    1007           0 :     READ_I64( out->timestamp, data, sz );
    1008           0 :   }
    1009           0 :   return 0;
    1010           0 : }
    1011             : 
    1012             : /* This function contains slightly custom deserialization logic to
    1013             :    adhere to serde_compact_vote_state_update in Agave.
    1014             :    https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.1.1/vote-interface/src/state/mod.rs#L265-L299 */
    1015             : static int
    1016             : deser_compact_vote_state_update( fd_compact_vote_state_update_t * out,
    1017             :                                  uchar const **                   data,
    1018           0 :                                  ulong *                          sz ) {
    1019           0 :   READ_U64( out->root, data, sz );
    1020             : 
    1021           0 :   ushort lockouts_len;
    1022           0 :   READ_COMPACT_U16( lockouts_len, data, sz );
    1023           0 :   CHECK( lockouts_len<=FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN );
    1024           0 :   out->lockouts_len = lockouts_len;
    1025             : 
    1026           0 :   out->lockouts = (fd_lockout_offset_t *)out->lockouts_mem;
    1027             : 
    1028           0 :   ulong slot = out->root!=ULONG_MAX ? out->root : 0UL;
    1029           0 :   for( ushort i=0; i<lockouts_len; i++ ) {
    1030           0 :     READ_U64_VARINT( out->lockouts[i].offset, data, sz );
    1031           0 :     READ_U8( out->lockouts[i].confirmation_count, data, sz );
    1032             : 
    1033             :     /* Custom logic: check that slot+lockout_offset
    1034             :        does not overflow */
    1035           0 :     CHECK( !__builtin_uaddl_overflow( slot, out->lockouts[i].offset, &slot ) );
    1036           0 :   }
    1037             : 
    1038           0 :   READ_HASH( out->hash, data, sz );
    1039           0 :   READ_OPTION( out->has_timestamp, data, sz );
    1040           0 :   if( out->has_timestamp ) {
    1041           0 :     READ_I64( out->timestamp, data, sz );
    1042           0 :   }
    1043           0 :   return 0;
    1044           0 : }
    1045             : 
    1046             : /* Similar to above. Tower sync uses delta-encoded lockout offsets,
    1047             :    converting them to absolute slot numbers on the fly.  Mirrors the
    1048             :    checked arithmetic from Agave's custom deserializer:
    1049             :    https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.1.1/vote-interface/src/state/mod.rs#L360-L396 */
    1050             : 
    1051             : static int
    1052             : deser_tower_sync( fd_tower_sync_t * out,
    1053             :                   uchar const **    data,
    1054           0 :                   ulong *           sz ) {
    1055           0 :   READ_U64( out->root, data, sz );
    1056           0 :   out->has_root = 1;
    1057             : 
    1058             :   /* First bit of custom logic: if root is ULONG_MAX, set root to 0. */
    1059           0 :   if( FD_UNLIKELY( out->root==ULONG_MAX ) ) {
    1060           0 :     out->has_root = 0;
    1061           0 :     out->root     = 0UL;
    1062           0 :   }
    1063             : 
    1064           0 :   ushort lockout_offsets_len;
    1065           0 :   READ_COMPACT_U16( lockout_offsets_len, data, sz );
    1066           0 :   CHECK( lockout_offsets_len<=FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN );
    1067             : 
    1068           0 :   out->lockouts = deq_fd_vote_lockout_t_join( deq_fd_vote_lockout_t_new( out->lockouts_mem, FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN ) );
    1069             : 
    1070           0 :   ulong last_slot = out->root;
    1071           0 :   for( ushort i=0; i<lockout_offsets_len; i++ ) {
    1072           0 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( out->lockouts );
    1073             : 
    1074           0 :     ulong offset;
    1075           0 :     READ_U64_VARINT( offset, data, sz );
    1076             : 
    1077           0 :     uchar confirmation_count;
    1078           0 :     READ_U8( confirmation_count, data, sz );
    1079             : 
    1080             :     /* Second bit of custom logic: check that last_slot+offset does not
    1081             :        overflow */
    1082           0 :     CHECK( !__builtin_uaddl_overflow( last_slot, offset, &elem->slot ) );
    1083           0 :     elem->confirmation_count = (uint)confirmation_count;
    1084           0 :     last_slot = elem->slot;
    1085           0 :   }
    1086             : 
    1087           0 :   out->lockouts_cnt = (ulong)lockout_offsets_len;
    1088             : 
    1089           0 :   READ_HASH( out->hash, data, sz );
    1090           0 :   READ_OPTION( out->has_timestamp, data, sz );
    1091           0 :   if( out->has_timestamp ) {
    1092           0 :     READ_I64( out->timestamp, data, sz );
    1093           0 :   }
    1094           0 :   READ_HASH( out->block_id, data, sz );
    1095           0 :   return 0;
    1096           0 : }
    1097             : 
    1098             : static int
    1099             : deser_vote_authorize_with_seed( fd_vote_authorize_with_seed_args_t * out,
    1100             :                                 uchar const **                       data,
    1101           0 :                                 ulong *                              sz ) {
    1102           0 :   CHECK( !deser_vote_authorize( &out->authorization_type, data, sz ) );
    1103           0 :   READ_PUBKEY( out->current_authority_derived_key_owner, data, sz );
    1104             : 
    1105           0 :   ulong seed_len;
    1106           0 :   READ_U64( seed_len, data, sz );
    1107             :   /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L42-L49 */
    1108           0 :   CHECK( seed_len<=FD_VOTE_INSTR_SEED_MAX );
    1109           0 :   out->current_authority_derived_key_seed_len = seed_len;
    1110             : 
    1111           0 :   READ_BYTES( out->current_authority_derived_key_seed, seed_len, data, sz );
    1112           0 :   CHECK( fd_utf8_verify( (char const *)out->current_authority_derived_key_seed, seed_len ) );
    1113             : 
    1114           0 :   READ_PUBKEY( out->new_authority, data, sz );
    1115           0 :   return 0;
    1116           0 : }
    1117             : 
    1118             : static int
    1119             : deser_vote_authorize_checked_with_seed( fd_vote_authorize_checked_with_seed_args_t * out,
    1120             :                                         uchar const **                               data,
    1121           0 :                                         ulong *                                      sz ) {
    1122           0 :   CHECK( !deser_vote_authorize( &out->authorization_type, data, sz ) );
    1123           0 :   READ_PUBKEY( out->current_authority_derived_key_owner, data, sz );
    1124             : 
    1125           0 :   ulong seed_len;
    1126           0 :   READ_U64( seed_len, data, sz );
    1127             :   /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L130 */
    1128           0 :   CHECK( seed_len<=FD_VOTE_INSTR_SEED_MAX );
    1129           0 :   out->current_authority_derived_key_seed_len = seed_len;
    1130             : 
    1131           0 :   READ_BYTES( out->current_authority_derived_key_seed, seed_len, data, sz );
    1132           0 :   CHECK( fd_utf8_verify( (char const *)out->current_authority_derived_key_seed, seed_len ) );
    1133           0 :   return 0;
    1134           0 : }
    1135             : 
    1136             : /**********************************************************************/
    1137             : /* Vote instruction -- top-level decoder                              */
    1138             : /**********************************************************************/
    1139             : 
    1140             : static int
    1141             : fd_vote_instruction_deserialize_inner( fd_vote_instruction_t * instruction,
    1142             :                                        uchar const *           data,
    1143         114 :                                        ulong                   data_sz ) {
    1144         114 :   fd_memset( instruction, 0, sizeof(fd_vote_instruction_t) );
    1145             : 
    1146         114 :   uchar const ** p  = &data;
    1147         114 :   ulong *        sz = &data_sz;
    1148             : 
    1149         114 :   READ_U32( instruction->discriminant, p, sz );
    1150             : 
    1151         114 :   switch( instruction->discriminant ) {
    1152             : 
    1153          24 :     case fd_vote_instruction_enum_initialize_account:
    1154          24 :       return deser_vote_init( &instruction->initialize_account, p, sz );
    1155             : 
    1156           3 :     case fd_vote_instruction_enum_authorize: {
    1157           3 :       READ_PUBKEY( instruction->authorize.pubkey, p, sz );
    1158           3 :       return deser_vote_authorize( &instruction->authorize.vote_authorize, p, sz );
    1159           3 :     }
    1160             : 
    1161           0 :     case fd_vote_instruction_enum_vote:
    1162           0 :       return deser_vote( &instruction->vote, p, sz );
    1163             : 
    1164           0 :     case fd_vote_instruction_enum_withdraw:
    1165           0 :       READ_U64( instruction->withdraw, p, sz );
    1166           0 :       return 0;
    1167             : 
    1168           6 :     case fd_vote_instruction_enum_update_validator_identity:
    1169           6 :       return 0;
    1170             : 
    1171           0 :     case fd_vote_instruction_enum_update_commission:
    1172           0 :       READ_U8( instruction->update_commission, p, sz );
    1173           0 :       return 0;
    1174             : 
    1175           0 :     case fd_vote_instruction_enum_vote_switch:
    1176           0 :       CHECK( !deser_vote( &instruction->vote_switch.vote, p, sz ) );
    1177           0 :       READ_HASH( instruction->vote_switch.hash, p, sz );
    1178           0 :       return 0;
    1179             : 
    1180           0 :     case fd_vote_instruction_enum_authorize_checked:
    1181           0 :       return deser_vote_authorize( &instruction->authorize_checked, p, sz );
    1182             : 
    1183           0 :     case fd_vote_instruction_enum_update_vote_state:
    1184           0 :       return deser_vote_state_update( &instruction->update_vote_state, p, sz );
    1185             : 
    1186           0 :     case fd_vote_instruction_enum_update_vote_state_switch:
    1187           0 :       CHECK( !deser_vote_state_update( &instruction->update_vote_state_switch.vote_state_update, p, sz ) );
    1188           0 :       READ_HASH( instruction->update_vote_state_switch.hash, p, sz );
    1189           0 :       return 0;
    1190             : 
    1191           0 :     case fd_vote_instruction_enum_authorize_with_seed:
    1192           0 :       return deser_vote_authorize_with_seed( &instruction->authorize_with_seed, p, sz );
    1193             : 
    1194           0 :     case fd_vote_instruction_enum_authorize_checked_with_seed:
    1195           0 :       return deser_vote_authorize_checked_with_seed( &instruction->authorize_checked_with_seed, p, sz );
    1196             : 
    1197           0 :     case fd_vote_instruction_enum_compact_update_vote_state:
    1198           0 :       return deser_compact_vote_state_update( &instruction->compact_update_vote_state, p, sz );
    1199             : 
    1200           0 :     case fd_vote_instruction_enum_compact_update_vote_state_switch:
    1201           0 :       CHECK( !deser_compact_vote_state_update( &instruction->compact_update_vote_state_switch.compact_vote_state_update, p, sz ) );
    1202           0 :       READ_HASH( instruction->compact_update_vote_state_switch.hash, p, sz );
    1203           0 :       return 0;
    1204             : 
    1205           0 :     case fd_vote_instruction_enum_tower_sync:
    1206           0 :       return deser_tower_sync( &instruction->tower_sync, p, sz );
    1207             : 
    1208           0 :     case fd_vote_instruction_enum_tower_sync_switch:
    1209           0 :       CHECK( !deser_tower_sync( &instruction->tower_sync_switch.tower_sync, p, sz ) );
    1210           0 :       READ_HASH( instruction->tower_sync_switch.hash, p, sz );
    1211           0 :       return 0;
    1212             : 
    1213           6 :     case fd_vote_instruction_enum_initialize_account_v2:
    1214           6 :       return deser_vote_init_v2( &instruction->initialize_account_v2, p, sz );
    1215             : 
    1216          72 :     case fd_vote_instruction_enum_update_commission_collector:
    1217          72 :       READ_ENUM( instruction->update_commission_collector.discriminant, 2U, p, sz );
    1218          72 :       return 0;
    1219             : 
    1220           3 :     case fd_vote_instruction_enum_update_commission_bps:
    1221           3 :       READ_U16( instruction->update_commission_bps.commission_bps, p, sz );
    1222           3 :       READ_ENUM( instruction->update_commission_bps.kind.discriminant, 2U, p, sz );
    1223           3 :       return 0;
    1224             : 
    1225           0 :     case fd_vote_instruction_enum_deposit_delegator_rewards:
    1226           0 :       READ_U64( instruction->deposit_delegator_rewards.deposit, p, sz );
    1227           0 :       return 0;
    1228             : 
    1229           0 :     default:
    1230           0 :       return 1;
    1231         114 :   }
    1232         114 : }
    1233             : 
    1234             : fd_vote_instruction_t *
    1235             : fd_vote_instruction_deserialize( fd_vote_instruction_t * instruction,
    1236             :                                  uchar const *           data,
    1237         114 :                                  ulong                   data_sz ) {
    1238             :   /* limited_deserialize(data, PACKET_DATA_SIZE)
    1239             :      https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L130 */
    1240         114 :   data_sz = fd_ulong_min( data_sz, FD_TXN_MTU_V0 );
    1241         114 :   CHECK_RET_NULL( !fd_vote_instruction_deserialize_inner( instruction, data, data_sz ) );
    1242         114 :   return instruction;
    1243         114 : }

Generated by: LCOV version 1.14