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: 459 815 56.3 %
Date: 2026-08-13 04:56:22 Functions: 26 33 78.8 %

          Line data    Source code
       1             : #include "fd_vote_codec.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      110967 : #define CHECK( cond ) do {               \
      13      110967 :   if( FD_UNLIKELY( !(cond) ) ) return 1; \
      14      110967 : } while( 0 )
      15             : 
      16         609 : #define CHECK_RET_NULL( cond ) do {          \
      17         609 :   if( FD_UNLIKELY( !(cond) ) ) return NULL;  \
      18         609 : } while( 0 )
      19             : 
      20        2106 : #define CHECK_U64_MUL_OVERFLOW( a, b ) do {                \
      21        2106 :   ulong _dummy;                                            \
      22        2106 :   CHECK( !__builtin_umull_overflow( (a), (b), &_dummy ) ); \
      23        2106 : } while( 0 )
      24             : 
      25             : /**********************************************************************/
      26             : /* Read macros                                                        */
      27             : /**********************************************************************/
      28             : 
      29         936 : #define READ_BYTES( dst, n, data, sz ) do { \
      30         936 :   CHECK( (n)<=(*(sz)) );                    \
      31         936 :   fd_memcpy( (dst), *(data), (n) );         \
      32         927 :   *(data) += (n);                           \
      33         927 :   *(sz) -= (n);                             \
      34         927 : } while( 0 )
      35             : 
      36        2751 : #define SKIP_BYTES( n, data, sz ) do { \
      37        2751 :   CHECK( (n)<=(*(sz)) );               \
      38        2751 :   *(data) += (n);                      \
      39        2751 :   *(sz) -= (n);                        \
      40        2751 : } while( 0 )
      41             : 
      42        1686 : #define READ_U8( dst, data, sz ) do { \
      43        1686 :   CHECK( 1UL<=(*(sz)) );              \
      44        1686 :   (dst) = FD_LOAD( uchar, *(data) );  \
      45        1686 :   *(data) += 1UL;                     \
      46        1686 :   *(sz) -= 1UL;                       \
      47        1686 : } while( 0 )
      48             : 
      49         279 : #define READ_U16( dst, data, sz ) do {  \
      50         279 :   CHECK( 2UL<=(*(sz)) );                \
      51         279 :   (dst) = FD_LOAD( ushort, *(data) );   \
      52         279 :   *(data) += 2UL;                       \
      53         279 :   *(sz) -= 2UL;                         \
      54         279 : } while( 0 )
      55             : 
      56        1632 : #define READ_U32( dst, data, sz ) do { \
      57        1632 :   CHECK( 4UL<=(*(sz)) );               \
      58        1632 :   (dst) = FD_LOAD( uint, *(data) );    \
      59        1632 :   *(data) += 4UL;                      \
      60        1632 :   *(sz) -= 4UL;                        \
      61        1632 : } while( 0 )
      62             : 
      63        2793 : #define READ_U64( dst, data, sz ) do {  \
      64        2793 :   CHECK( 8UL<=(*(sz)) );                \
      65        2793 :   (dst) = FD_LOAD( ulong, *(data) );    \
      66        2793 :   *(data) += 8UL;                       \
      67        2793 :   *(sz) -= 8UL;                         \
      68        2793 : } 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         717 :   READ_BYTES( (dst).uc, 32UL, data, sz )
      79             : 
      80         717 : #define READ_PUBKEY READ_HASH
      81             : 
      82         276 : #define READ_BOOL( dst, data, sz ) do { \
      83         276 :   READ_U8( dst, data, sz );             \
      84         276 :   CHECK( (dst)==0 || (dst)==1 );        \
      85         276 : } while( 0 )
      86             : 
      87         270 : #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       28497 : #define WRITE_BYTES( src, n, out, out_sz ) do { \
     130       28497 :   CHECK( (n)<=(*(out_sz)) );                    \
     131       28497 :   fd_memcpy( *(out), (src), (n) );              \
     132       28497 :   *(out) += (n);                                \
     133       28497 :   *(out_sz) -= (n);                             \
     134       28497 : } while( 0 )
     135             : 
     136        8154 : #define WRITE_U8( val, out, out_sz ) do { \
     137        8154 :   CHECK( 1UL<=(*(out_sz)) );              \
     138        8154 :   FD_STORE( uchar, *(out), (val) );       \
     139        8154 :   *(out) += 1UL;                          \
     140        8154 :   *(out_sz) -= 1UL;                       \
     141        8154 : } while( 0 )
     142             : 
     143        8154 : #define WRITE_U16( val, out, out_sz ) do { \
     144        8154 :   CHECK( 2UL<=(*(out_sz)) );               \
     145        8154 :   FD_STORE( ushort, *(out), (val) );       \
     146        8154 :   *(out) += 2UL;                           \
     147        8154 :   *(out_sz) -= 2UL;                        \
     148        8154 : } while( 0 )
     149             : 
     150        4077 : #define WRITE_U32( val, out, out_sz ) do { \
     151        4077 :   CHECK( 4UL<=(*(out_sz)) );               \
     152        4077 :   FD_STORE( uint, *(out), (val) );         \
     153        4077 :   *(out) += 4UL;                           \
     154        4077 :   *(out_sz) -= 4UL;                        \
     155        4077 : } while( 0 )
     156             : 
     157       20385 : #define WRITE_U64( val, out, out_sz ) do { \
     158       20385 :   CHECK( 8UL<=(*(out_sz)) );               \
     159       20385 :   FD_STORE( ulong, *(out), (val) );        \
     160       20385 :   *(out) += 8UL;                           \
     161       20385 :   *(out_sz) -= 8UL;                        \
     162       20385 : } 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       20385 :   WRITE_BYTES( (src).uc, 32UL, out, out_sz )
     173             : 
     174             : #define WRITE_BOOL( val, out, out_sz ) \
     175        8154 :   WRITE_U8( (uchar)!!(val), out, out_sz )
     176             : 
     177        4077 : #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         138 :              ulong *            rem ) {
     191         138 :   ulong votes_len;
     192         138 :   READ_U64( votes_len, ptr, rem );
     193         138 :   CHECK( votes_len<=MAX_LOCKOUT_HISTORY );
     194             : 
     195         138 :   for( ulong i=0UL; i<votes_len; i++ ) {
     196           0 :     fd_landed_vote_t * elem = deq_fd_landed_vote_t_push_tail_nocopy( votes );
     197           0 :     if( is_v1_14_11 ) {
     198           0 :       elem->latency = 0; /* Unused field for v1_14_11 */
     199           0 :     } else {
     200           0 :       READ_U8( elem->latency, ptr, rem );
     201           0 :     }
     202           0 :     READ_U64( elem->lockout.slot, ptr, rem );
     203           0 :     READ_U32( elem->lockout.confirmation_count, ptr, rem );
     204           0 :   }
     205         138 :   return 0;
     206         138 : }
     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         138 :                  ulong *         rem ) {
     214         138 :   uchar opt;
     215         138 :   READ_OPTION( opt, ptr, rem );
     216         138 :   *has_root_slot = opt;
     217         138 :   if( opt ) {
     218           0 :     READ_U64( *root_slot, ptr, rem );
     219           0 :   }
     220         138 :   return 0;
     221         138 : }
     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         138 :                          ulong *                             rem ) {
     229         138 :   ulong authorized_voters_len;
     230         138 :   READ_U64( authorized_voters_len, ptr, rem );
     231         138 :   CHECK( authorized_voters_len<=MAX_AUTHORIZED_VOTERS );
     232         273 :   for( ulong i=0UL; i<authorized_voters_len; i++ ) {
     233         135 :     fd_vote_authorized_voter_t * voter = fd_vote_authorized_voters_pool_ele_acquire( pool );
     234         135 :     READ_U64( voter->epoch, ptr, rem );
     235         135 :     READ_PUBKEY( voter->pubkey, ptr, rem );
     236         135 :     voter->prio = voter->pubkey.uc[0];
     237             : 
     238             :     /* Check for existing entries, overwrite if exists */
     239         135 :     fd_vote_authorized_voter_t * existing_voter = fd_vote_authorized_voters_treap_ele_query( treap, voter->epoch, pool );
     240         135 :     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         135 :     fd_vote_authorized_voters_treap_ele_insert( treap, voter, pool );
     246         135 :   }
     247         138 :   return 0;
     248         138 : }
     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         138 :                      ulong *                   rem ) {
     269         138 :   ulong epoch_credits_len;
     270         138 :   READ_U64( epoch_credits_len, ptr, rem );
     271         138 :   CHECK( epoch_credits_len<=MAX_EPOCH_CREDITS_HISTORY );
     272         138 :   for( ulong i=0UL; i<epoch_credits_len; i++ ) {
     273           0 :     fd_vote_epoch_credits_t * elem = deq_fd_vote_epoch_credits_t_push_tail_nocopy( epoch_credits );
     274           0 :     READ_BYTES( elem, sizeof(fd_vote_epoch_credits_t), ptr, rem );
     275           0 :   }
     276         138 :   return 0;
     277         138 : }
     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        4077 :            ulong *                  out_sz ) {
     291        4077 :   if( FD_UNLIKELY( votes==NULL ) ) {
     292           0 :     WRITE_U64( 0UL, out, out_sz );
     293           0 :     return 0;
     294           0 :   }
     295             : 
     296        4077 :   ulong votes_len = deq_fd_landed_vote_t_cnt( votes );
     297        4077 :   WRITE_U64( votes_len, out, out_sz );
     298             : 
     299        4077 :   for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( votes );
     300        4077 :        !deq_fd_landed_vote_t_iter_done( votes, iter );
     301        4077 :        iter = deq_fd_landed_vote_t_iter_next( votes, iter ) ) {
     302           0 :     fd_landed_vote_t const * elem = deq_fd_landed_vote_t_iter_ele_const( votes, iter );
     303           0 :     if( !is_v1_14_11 ) {
     304           0 :       WRITE_U8( elem->latency, out, out_sz );
     305           0 :     }
     306           0 :     WRITE_U64( elem->lockout.slot, out, out_sz );
     307           0 :     WRITE_U32( elem->lockout.confirmation_count, out, out_sz );
     308           0 :   }
     309        4077 :   return 0;
     310        4077 : }
     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        4077 :                ulong *  out_sz ) {
     318        4077 :   WRITE_BOOL( has_root_slot, out, out_sz );
     319        4077 :   if( has_root_slot ) {
     320           0 :     WRITE_U64( root_slot, out, out_sz );
     321           0 :   }
     322        4077 :   return 0;
     323        4077 : }
     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        4077 :                        ulong *                                   out_sz ) {
     331        4077 :   if( FD_UNLIKELY( treap==NULL ) ) {
     332           0 :     WRITE_U64( 0UL, out, out_sz );
     333           0 :     return 0;
     334           0 :   }
     335             : 
     336        4077 :   ulong len = fd_vote_authorized_voters_treap_ele_cnt( treap );
     337        4077 :   WRITE_U64( len, out, out_sz );
     338             : 
     339        4077 :   for( fd_vote_authorized_voters_treap_fwd_iter_t iter = fd_vote_authorized_voters_treap_fwd_iter_init( treap, pool );
     340        8154 :        !fd_vote_authorized_voters_treap_fwd_iter_done( iter );
     341        4077 :        iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, pool ) ) {
     342        4077 :     fd_vote_authorized_voter_t const * voter = fd_vote_authorized_voters_treap_fwd_iter_ele_const( iter, pool );
     343        4077 :     WRITE_U64( voter->epoch, out, out_sz );
     344        4077 :     WRITE_PUBKEY( voter->pubkey, out, out_sz );
     345        4077 :   }
     346        4077 :   return 0;
     347        4077 : }
     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        4077 :                    ulong *                         out_sz ) {
     368        4077 :   if( FD_UNLIKELY( epoch_credits==NULL ) ) {
     369           0 :     WRITE_U64( 0UL, out, out_sz );
     370           0 :     return 0;
     371           0 :   }
     372             : 
     373        4077 :   ulong len = deq_fd_vote_epoch_credits_t_cnt( epoch_credits );
     374        4077 :   WRITE_U64( len, out, out_sz );
     375             : 
     376        4077 :   for( deq_fd_vote_epoch_credits_t_iter_t iter = deq_fd_vote_epoch_credits_t_iter_init( epoch_credits );
     377        4110 :        !deq_fd_vote_epoch_credits_t_iter_done( epoch_credits, iter );
     378        4077 :        iter = deq_fd_vote_epoch_credits_t_iter_next( epoch_credits, iter ) ) {
     379          33 :     fd_vote_epoch_credits_t const * elem = deq_fd_vote_epoch_credits_t_iter_ele_const( epoch_credits, iter );
     380          33 :     WRITE_BYTES( elem, sizeof(fd_vote_epoch_credits_t), out, out_sz );
     381          33 :   }
     382        4077 :   return 0;
     383        4077 : }
     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         321 : #define WIRE_OFF_NODE_PUBKEY                    (4UL)
     397           0 : #define WIRE_OFF_V1V3_COMMISSION                (68UL)  /* 4 + 32 + 32 */
     398         321 : #define WIRE_OFF_V4_INFLATION_REWARDS_COLLECTOR (68UL)  /* 4 + 32 + 32 */
     399         321 : #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         402 : #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         321 :                              fd_pubkey_t *  out ) {
     426         321 :   CHECK( data_sz>=WIRE_OFF_NODE_PUBKEY+32UL );
     427         321 :   fd_memcpy( out, data+WIRE_OFF_NODE_PUBKEY, 32UL );
     428         321 :   return 0;
     429         321 : }
     430             : 
     431             : int
     432             : fd_vote_account_commission_bps( uchar const * data,
     433             :                                 ulong         data_sz,
     434             :                                 int           commission_rate_in_basis_points,
     435         321 :                                 ushort *      out ) {
     436         321 :   uchar const * ptr       = data;
     437         321 :   ulong         remaining = data_sz;
     438             : 
     439         321 :   uint discriminant;
     440         321 :   READ_U32( discriminant, &ptr, &remaining );
     441             : 
     442         321 :   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         321 :     case fd_vote_state_versioned_enum_v4:
     449         321 :       CHECK( data_sz>=WIRE_OFF_V4_COMMISSION_BPS+2UL );
     450         321 :       *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         321 :       if( !commission_rate_in_basis_points ) {
     455         249 :         *out = (*out / 100U) * 100U;
     456         249 :       }
     457         321 :       return 0;
     458           0 :     default:
     459           0 :       return 1;
     460         321 :   }
     461         321 : }
     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         321 :                             fd_pubkey_t *       block_revenue_collector_out ) {
     470         321 :   uchar const * ptr       = data;
     471         321 :   ulong         remaining = data_sz;
     472             : 
     473         321 :   uint discriminant;
     474         321 :   READ_U32( discriminant, &ptr, &remaining );
     475             : 
     476         321 :   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         321 :     case fd_vote_state_versioned_enum_v4:
     486         321 :       CHECK( data_sz>=WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR+32UL );
     487         321 :       fd_memcpy( inflation_rewards_collector_out, data+WIRE_OFF_V4_INFLATION_REWARDS_COLLECTOR, 32UL );
     488         321 :       fd_memcpy( block_revenue_collector_out,     data+WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR,     32UL );
     489         321 :       return 0;
     490           0 :     default:
     491           0 :       return 1;
     492         321 :   }
     493         321 : }
     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         702 :                     ulong *                          out_cnt ) {
     504         702 :   uchar const * ptr       = data;
     505         702 :   ulong         remaining = data_sz;
     506             : 
     507         702 :   uint discriminant;
     508         702 :   READ_U32( discriminant, &ptr, &remaining );
     509             : 
     510         702 :   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         702 :     case fd_vote_state_versioned_enum_v4: {
     566         702 :       SKIP_BYTES( WIRE_BLS_OFF_V4-4UL, &ptr, &remaining );
     567             : 
     568             :       /* Skip Option<bls_pubkey_compressed> */
     569         702 :       uchar has_bls_pubkey;
     570         702 :       READ_U8( has_bls_pubkey, &ptr, &remaining );
     571         702 :       if( has_bls_pubkey ) {
     572         645 :         SKIP_BYTES( FD_BLS_PUBKEY_COMPRESSED_SZ, &ptr, &remaining );
     573         645 :       }
     574             : 
     575             :       /* Skip votes Vec<LandedVote> */
     576         702 :       ulong votes_len;
     577         702 :       READ_U64( votes_len, &ptr, &remaining );
     578         702 :       CHECK_U64_MUL_OVERFLOW( votes_len, WIRE_LANDED_VOTE_SZ );
     579         702 :       SKIP_BYTES( votes_len*WIRE_LANDED_VOTE_SZ, &ptr, &remaining );
     580             : 
     581             :       /* Skip root_slot Option<u64> */
     582         702 :       uchar has_root_slot;
     583         702 :       READ_U8( has_root_slot, &ptr, &remaining );
     584         702 :       if( has_root_slot ) {
     585           0 :         SKIP_BYTES( 8UL, &ptr, &remaining );
     586           0 :       }
     587             : 
     588             :       /* Skip authorized_voters BTreeMap<u64, Pubkey> */
     589         702 :       ulong authorized_voters_len;
     590         702 :       READ_U64( authorized_voters_len, &ptr, &remaining );
     591         702 :       CHECK_U64_MUL_OVERFLOW( authorized_voters_len, WIRE_AUTH_VOTER_SZ );
     592         702 :       SKIP_BYTES( authorized_voters_len*WIRE_AUTH_VOTER_SZ, &ptr, &remaining );
     593         702 :       break;
     594         702 :     }
     595             : 
     596         702 :     default:
     597           0 :       return 1;
     598         702 :   }
     599             : 
     600             :   /* Now at epoch_credits deque */
     601         702 :   ulong epoch_credits_len;
     602         702 :   READ_U64( epoch_credits_len, &ptr, &remaining );
     603         702 :   CHECK( epoch_credits_len<=MAX_EPOCH_CREDITS_HISTORY );
     604         702 :   CHECK_U64_MUL_OVERFLOW( epoch_credits_len, sizeof(fd_vote_epoch_credits_t) );
     605         702 :   CHECK( epoch_credits_len*sizeof(fd_vote_epoch_credits_t)<=remaining );
     606             : 
     607         702 :   *out_ptr = (fd_vote_epoch_credits_t const *)ptr;
     608         702 :   *out_cnt = epoch_credits_len;
     609         702 :   return 0;
     610         702 : }
     611             : 
     612             : int
     613             : fd_vote_account_last_timestamp( uchar const *             data,
     614             :                                 ulong                     data_sz,
     615         381 :                                 fd_vote_block_timestamp_t * out ) {
     616         381 :   fd_vote_epoch_credits_t const * epoch_credits_ptr;
     617         381 :   ulong                           epoch_credits_len;
     618         381 :   CHECK( !seek_epoch_credits( data, data_sz, &epoch_credits_ptr, &epoch_credits_len ) );
     619             : 
     620         381 :   uchar const * timestamp_ptr = (uchar const *)( epoch_credits_ptr + epoch_credits_len );
     621         381 :   CHECK( timestamp_ptr+sizeof(fd_vote_block_timestamp_t)<=data+data_sz );
     622             : 
     623         381 :   fd_memcpy( out, timestamp_ptr, sizeof(fd_vote_block_timestamp_t) );
     624         381 :   return 0;
     625         381 : }
     626             : 
     627             : int
     628             : fd_vote_account_is_v4_with_bls_pubkey( uchar const * data,
     629         330 :                                        ulong         data_sz ) {
     630         330 :   if( FD_UNLIKELY( data_sz<WIRE_BLS_OFF_V4+1UL ) ) return 0;
     631         330 :   uint discriminant = FD_LOAD( uint, data );
     632         330 :   if( discriminant!=fd_vote_state_versioned_enum_v4 ) return 0;
     633         330 :   return !!data[ WIRE_BLS_OFF_V4 ];
     634         330 : }
     635             : 
     636             : fd_vote_epoch_credits_t const *
     637             : fd_vote_account_epoch_credits( uchar const * data,
     638             :                                ulong         data_sz,
     639         321 :                                ulong *       cnt ) {
     640         321 :   fd_vote_epoch_credits_t const * ptr;
     641         321 :   CHECK_RET_NULL( !seek_epoch_credits( data, data_sz, &ptr, cnt ) );
     642         321 :   return ptr;
     643         321 : }
     644             : 
     645             : /**********************************************************************/
     646             : /* Vote account state -- public API                                   */
     647             : /**********************************************************************/
     648             : 
     649             : fd_vote_state_versioned_t *
     650             : fd_vote_state_versioned_new( fd_vote_state_versioned_t * self,
     651        4170 :                              uint                        kind ) {
     652        4170 :   if( FD_UNLIKELY( !self ) ) {
     653           0 :     FD_LOG_WARNING(( "NULL mem" ));
     654           0 :     return NULL;
     655           0 :   }
     656             : 
     657             :   /* Init and join data structures */
     658        4170 :   fd_landed_vote_t * votes = deq_fd_landed_vote_t_join(
     659        4170 :     deq_fd_landed_vote_t_new( self->landed_votes_mem, MAX_LOCKOUT_HISTORY_CAPACITY )
     660        4170 :   );
     661        4170 :   fd_vote_epoch_credits_t * epoch_credits = deq_fd_vote_epoch_credits_t_join(
     662        4170 :     deq_fd_vote_epoch_credits_t_new( self->epoch_credits_mem )
     663        4170 :   );
     664        4170 :   fd_vote_authorized_voter_t * authorized_voters_pool  = fd_vote_authorized_voters_pool_join(
     665        4170 :     fd_vote_authorized_voters_pool_new( self->authorized_voters_pool_mem, MAX_AUTHORIZED_VOTERS_CAPACITY )
     666        4170 :   );
     667        4170 :   fd_vote_authorized_voters_treap_t * authorized_voters_treap = fd_vote_authorized_voters_treap_join(
     668        4170 :     fd_vote_authorized_voters_treap_new( self->authorized_voters_treap_mem, MAX_AUTHORIZED_VOTERS_CAPACITY )
     669        4170 :   );
     670             : 
     671        4170 :   self->kind = kind;
     672        4170 :   switch( kind ) {
     673          27 :     case fd_vote_state_versioned_enum_uninitialized:
     674          27 :       break;
     675           3 :     case fd_vote_state_versioned_enum_v1_14_11:
     676           3 :       memset( &self->v1_14_11, 0, sizeof(fd_vote_state_1_14_11_t) );
     677           3 :       self->v1_14_11.votes                   = votes;
     678           3 :       self->v1_14_11.epoch_credits           = epoch_credits;
     679           3 :       self->v1_14_11.authorized_voters.pool  = authorized_voters_pool;
     680           3 :       self->v1_14_11.authorized_voters.treap = authorized_voters_treap;
     681           3 :       break;
     682           9 :     case fd_vote_state_versioned_enum_v3:
     683           9 :       memset( &self->v3, 0, sizeof(fd_vote_state_v3_t) );
     684           9 :       self->v3.votes                   = votes;
     685           9 :       self->v3.epoch_credits           = epoch_credits;
     686           9 :       self->v3.authorized_voters.pool  = authorized_voters_pool;
     687           9 :       self->v3.authorized_voters.treap = authorized_voters_treap;
     688           9 :       break;
     689        4131 :     case fd_vote_state_versioned_enum_v4:
     690        4131 :       memset( &self->v4, 0, sizeof(fd_vote_state_v4_t) );
     691        4131 :       self->v4.votes                    = votes;
     692        4131 :       self->v4.epoch_credits            = epoch_credits;
     693        4131 :       self->v4.authorized_voters.pool   = authorized_voters_pool;
     694        4131 :       self->v4.authorized_voters.treap  = authorized_voters_treap;
     695        4131 :       break;
     696           0 :     default:
     697           0 :       return NULL;
     698        4170 :   }
     699             : 
     700        4170 :   return self;
     701        4170 : }
     702             : 
     703             : static int
     704             : fd_vote_state_versioned_deserialize_inner( fd_vote_state_versioned_t * self,
     705             :                                            uchar const *               payload,
     706         174 :                                            ulong                       payload_sz ) {
     707         174 :   CHECK( self!=NULL );
     708         174 :   CHECK( payload!=NULL );
     709             : 
     710         174 :   uchar const * ptr = payload;
     711         174 :   ulong         rem = payload_sz;
     712             : 
     713         174 :   uint kind;
     714         174 :   READ_U32( kind, &ptr, &rem );
     715             : 
     716         174 :   CHECK( fd_vote_state_versioned_new( self, kind )!=NULL );
     717             : 
     718         174 :   switch( self->kind ) {
     719          27 :     case fd_vote_state_versioned_enum_uninitialized:
     720             :       /* No-op, nothing to decode */
     721          27 :       return 0;
     722             : 
     723           3 :     case fd_vote_state_versioned_enum_v1_14_11: {
     724           3 :       READ_PUBKEY( self->v1_14_11.node_pubkey, &ptr, &rem );
     725           0 :       READ_PUBKEY( self->v1_14_11.authorized_withdrawer, &ptr, &rem );
     726           0 :       READ_U8( self->v1_14_11.commission, &ptr, &rem );
     727           0 :       CHECK( !deser_votes( self->v1_14_11.votes, 1, &ptr, &rem ) ); /* v1_14_11 wire format is Lockout, not LandedVote */
     728           0 :       CHECK( !deser_root_slot( &self->v1_14_11.has_root_slot, &self->v1_14_11.root_slot, &ptr, &rem ) );
     729           0 :       CHECK( !deser_authorized_voters( self->v1_14_11.authorized_voters.pool, self->v1_14_11.authorized_voters.treap, &ptr, &rem ) );
     730           0 :       CHECK( !deser_prior_voters( &self->v1_14_11.prior_voters, &ptr, &rem ) );
     731           0 :       CHECK( !deser_epoch_credits( self->v1_14_11.epoch_credits, &ptr, &rem ) );
     732           0 :       READ_BYTES( &self->v1_14_11.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
     733           0 :       break;
     734           0 :     }
     735             : 
     736           9 :     case fd_vote_state_versioned_enum_v3: {
     737           9 :       READ_PUBKEY( self->v3.node_pubkey, &ptr, &rem );
     738           6 :       READ_PUBKEY( self->v3.authorized_withdrawer, &ptr, &rem );
     739           6 :       READ_U8( self->v3.commission, &ptr, &rem );
     740           6 :       CHECK( !deser_votes( self->v3.votes, 0, &ptr, &rem ) );
     741           6 :       CHECK( !deser_root_slot( &self->v3.has_root_slot, &self->v3.root_slot, &ptr, &rem ) );
     742           6 :       CHECK( !deser_authorized_voters( self->v3.authorized_voters.pool, self->v3.authorized_voters.treap, &ptr, &rem ) );
     743           6 :       CHECK( !deser_prior_voters( &self->v3.prior_voters, &ptr, &rem ) );
     744           6 :       CHECK( !deser_epoch_credits( self->v3.epoch_credits, &ptr, &rem ) );
     745           6 :       READ_BYTES( &self->v3.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
     746           6 :       break;
     747           6 :     }
     748             : 
     749         135 :     case fd_vote_state_versioned_enum_v4: {
     750         135 :       READ_PUBKEY( self->v4.node_pubkey, &ptr, &rem );
     751         132 :       READ_PUBKEY( self->v4.authorized_withdrawer, &ptr, &rem );
     752         132 :       READ_PUBKEY( self->v4.inflation_rewards_collector, &ptr, &rem );
     753         132 :       READ_PUBKEY( self->v4.block_revenue_collector, &ptr, &rem );
     754         132 :       READ_U16( self->v4.inflation_rewards_commission_bps, &ptr, &rem );
     755         132 :       READ_U16( self->v4.block_revenue_commission_bps, &ptr, &rem );
     756         132 :       READ_U64( self->v4.pending_delegator_rewards, &ptr, &rem );
     757             : 
     758             :       /* Option<[u8; 48]> */
     759         132 :       READ_OPTION( self->v4.has_bls_pubkey_compressed, &ptr, &rem );
     760         132 :       if( self->v4.has_bls_pubkey_compressed ) {
     761          39 :         READ_BYTES( self->v4.bls_pubkey_compressed, FD_BLS_PUBKEY_COMPRESSED_SZ, &ptr, &rem );
     762          39 :       }
     763             : 
     764         132 :       CHECK( !deser_votes( self->v4.votes, 0, &ptr, &rem ) );
     765         132 :       CHECK( !deser_root_slot( &self->v4.has_root_slot, &self->v4.root_slot, &ptr, &rem ) );
     766         132 :       CHECK( !deser_authorized_voters( self->v4.authorized_voters.pool, self->v4.authorized_voters.treap, &ptr, &rem ) );
     767         132 :       CHECK( !deser_epoch_credits( self->v4.epoch_credits, &ptr, &rem ) ); /* v4 has no prior_voters */
     768         132 :       READ_BYTES( &self->v4.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
     769         132 :       break;
     770         132 :     }
     771             : 
     772         132 :     default:
     773           0 :       return 1;
     774         174 :   }
     775             : 
     776         138 :   return 0;
     777         174 : }
     778             : 
     779             : fd_vote_state_versioned_t *
     780             : fd_vote_state_versioned_deserialize( fd_vote_state_versioned_t * self,
     781             :                                      uchar const *               payload,
     782         174 :                                      ulong                       payload_sz ) {
     783         174 :   CHECK_RET_NULL( !fd_vote_state_versioned_deserialize_inner( self, payload, payload_sz ) );
     784         165 :   return self;
     785         174 : }
     786             : 
     787             : int
     788             : fd_vote_state_versioned_serialize( fd_vote_state_versioned_t const * self,
     789             :                                    uchar *                           buf,
     790        4077 :                                    ulong                             buf_sz ) {
     791        4077 :   CHECK( self!=NULL );
     792        4077 :   CHECK( buf!=NULL );
     793             : 
     794        4077 :   uchar * out    = buf;
     795        4077 :   ulong   out_sz = buf_sz;
     796             : 
     797        4077 :   WRITE_U32( self->kind, &out, &out_sz );
     798             : 
     799        4077 :   switch( self->kind ) {
     800           0 :     case fd_vote_state_versioned_enum_uninitialized:
     801             :       /* No-op, nothing to encode */
     802           0 :       return 0;
     803             : 
     804           0 :     case fd_vote_state_versioned_enum_v1_14_11: {
     805           0 :       WRITE_PUBKEY( self->v1_14_11.node_pubkey, &out, &out_sz );
     806           0 :       WRITE_PUBKEY( self->v1_14_11.authorized_withdrawer, &out, &out_sz );
     807           0 :       WRITE_U8( self->v1_14_11.commission, &out, &out_sz );
     808           0 :       CHECK( !ser_votes( self->v1_14_11.votes, 1, &out, &out_sz ) ); /* v1_14_11 wire format is Lockout, not LandedVote */
     809           0 :       CHECK( !ser_root_slot( self->v1_14_11.has_root_slot, self->v1_14_11.root_slot, &out, &out_sz ) );
     810           0 :       CHECK( !ser_authorized_voters( self->v1_14_11.authorized_voters.pool, self->v1_14_11.authorized_voters.treap, &out, &out_sz ) );
     811           0 :       CHECK( !ser_prior_voters( &self->v1_14_11.prior_voters, &out, &out_sz ) );
     812           0 :       CHECK( !ser_epoch_credits( self->v1_14_11.epoch_credits, &out, &out_sz ) );
     813           0 :       WRITE_BYTES( &self->v1_14_11.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
     814           0 :       break;
     815           0 :     }
     816             : 
     817           0 :     case fd_vote_state_versioned_enum_v3: {
     818           0 :       WRITE_PUBKEY( self->v3.node_pubkey, &out, &out_sz );
     819           0 :       WRITE_PUBKEY( self->v3.authorized_withdrawer, &out, &out_sz );
     820           0 :       WRITE_U8( self->v3.commission, &out, &out_sz );
     821           0 :       CHECK( !ser_votes( self->v3.votes, 0, &out, &out_sz ) );
     822           0 :       CHECK( !ser_root_slot( self->v3.has_root_slot, self->v3.root_slot, &out, &out_sz ) );
     823           0 :       CHECK( !ser_authorized_voters( self->v3.authorized_voters.pool, self->v3.authorized_voters.treap, &out, &out_sz ) );
     824           0 :       CHECK( !ser_prior_voters( &self->v3.prior_voters, &out, &out_sz ) );
     825           0 :       CHECK( !ser_epoch_credits( self->v3.epoch_credits, &out, &out_sz ) );
     826           0 :       WRITE_BYTES( &self->v3.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
     827           0 :       break;
     828           0 :     }
     829             : 
     830        4077 :     case fd_vote_state_versioned_enum_v4: {
     831        4077 :       WRITE_PUBKEY( self->v4.node_pubkey, &out, &out_sz );
     832        4077 :       WRITE_PUBKEY( self->v4.authorized_withdrawer, &out, &out_sz );
     833        4077 :       WRITE_PUBKEY( self->v4.inflation_rewards_collector, &out, &out_sz );
     834        4077 :       WRITE_PUBKEY( self->v4.block_revenue_collector, &out, &out_sz );
     835        4077 :       WRITE_U16( self->v4.inflation_rewards_commission_bps, &out, &out_sz );
     836        4077 :       WRITE_U16( self->v4.block_revenue_commission_bps, &out, &out_sz );
     837        4077 :       WRITE_U64( self->v4.pending_delegator_rewards, &out, &out_sz );
     838             : 
     839             :       /* Option<[u8; 48]> */
     840        4077 :       WRITE_OPTION( self->v4.has_bls_pubkey_compressed, &out, &out_sz );
     841        4077 :       if( self->v4.has_bls_pubkey_compressed ) {
     842        4002 :         WRITE_BYTES( self->v4.bls_pubkey_compressed, FD_BLS_PUBKEY_COMPRESSED_SZ, &out, &out_sz );
     843        4002 :       }
     844             : 
     845        4077 :       CHECK( !ser_votes( self->v4.votes, 0, &out, &out_sz ) );
     846        4077 :       CHECK( !ser_root_slot( self->v4.has_root_slot, self->v4.root_slot, &out, &out_sz ) );
     847        4077 :       CHECK( !ser_authorized_voters( self->v4.authorized_voters.pool, self->v4.authorized_voters.treap, &out, &out_sz ) );
     848        4077 :       CHECK( !ser_epoch_credits( self->v4.epoch_credits, &out, &out_sz ) ); /* v4 has no prior_voters */
     849        4077 :       WRITE_BYTES( &self->v4.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
     850        4077 :       break;
     851        4077 :     }
     852             : 
     853        4077 :     default:
     854           0 :       return 1;
     855        4077 :   }
     856             : 
     857        4077 :   return 0;
     858        4077 : }
     859             : 
     860             : ulong
     861          72 : fd_vote_state_versioned_serialized_size( fd_vote_state_versioned_t const * self ) {
     862          72 :   switch( self->kind ) {
     863             : 
     864           0 :     case fd_vote_state_versioned_enum_uninitialized:
     865           0 :       return 4UL;
     866             : 
     867           0 :     case fd_vote_state_versioned_enum_v1_14_11: {
     868           0 :       ulong votes_cnt         = self->v1_14_11.votes                   ? deq_fd_landed_vote_t_cnt( self->v1_14_11.votes )                                  : 0UL;
     869           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;
     870           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;
     871           0 :       return WIRE_VOTES_OFF_V1_V3
     872           0 :            + 8UL + votes_cnt * WIRE_LOCKOUT_SZ
     873           0 :            + 1UL + (ulong)self->v1_14_11.has_root_slot * 8UL
     874           0 :            + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
     875           0 :            + WIRE_PRIOR_VOTERS_SZ
     876           0 :            + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
     877           0 :            + sizeof(fd_vote_block_timestamp_t);
     878           0 :     }
     879             : 
     880           0 :     case fd_vote_state_versioned_enum_v3: {
     881           0 :       ulong votes_cnt         = self->v3.votes                   ? deq_fd_landed_vote_t_cnt( self->v3.votes )                                  : 0UL;
     882           0 :       ulong auth_voters_cnt   = self->v3.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v3.authorized_voters.treap )  : 0UL;
     883           0 :       ulong epoch_credits_cnt = self->v3.epoch_credits           ? deq_fd_vote_epoch_credits_t_cnt( self->v3.epoch_credits )                    : 0UL;
     884           0 :       return WIRE_VOTES_OFF_V1_V3
     885           0 :            + 8UL + votes_cnt * WIRE_LANDED_VOTE_SZ
     886           0 :            + 1UL + (ulong)self->v3.has_root_slot * 8UL
     887           0 :            + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
     888           0 :            + WIRE_PRIOR_VOTERS_SZ
     889           0 :            + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
     890           0 :            + sizeof(fd_vote_block_timestamp_t);
     891           0 :     }
     892             : 
     893          72 :     case fd_vote_state_versioned_enum_v4: {
     894          72 :       ulong votes_cnt         = self->v4.votes                   ? deq_fd_landed_vote_t_cnt( self->v4.votes )                                  : 0UL;
     895          72 :       ulong auth_voters_cnt   = self->v4.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v4.authorized_voters.treap )  : 0UL;
     896          72 :       ulong epoch_credits_cnt = self->v4.epoch_credits           ? deq_fd_vote_epoch_credits_t_cnt( self->v4.epoch_credits )                    : 0UL;
     897          72 :       return WIRE_BLS_OFF_V4
     898          72 :            + 1UL + (ulong)self->v4.has_bls_pubkey_compressed * FD_BLS_PUBKEY_COMPRESSED_SZ
     899          72 :            + 8UL + votes_cnt * WIRE_LANDED_VOTE_SZ
     900          72 :            + 1UL + (ulong)self->v4.has_root_slot * 8UL
     901          72 :            + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
     902          72 :            + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
     903          72 :            + sizeof(fd_vote_block_timestamp_t);
     904           0 :     }
     905             : 
     906           0 :     default:
     907           0 :       return 0UL;
     908          72 :   }
     909          72 : }
     910             : 
     911             : /**********************************************************************/
     912             : /* Vote instruction -- per-variant deserializers                      */
     913             : /**********************************************************************/
     914             : 
     915             : static int
     916             : deser_vote_authorize( fd_vote_authorize_t * out,
     917             :                       uchar const **        data,
     918           3 :                       ulong *               sz ) {
     919           3 :   READ_ENUM( out->discriminant, 3U, data, sz );
     920           3 :   if( out->discriminant==fd_vote_authorize_enum_voter_with_bls ) {
     921           0 :     READ_BYTES( out->voter_with_bls.bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ, data, sz );
     922           0 :     READ_BYTES( out->voter_with_bls.bls_proof_of_possession, FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ, data, sz );
     923           0 :   }
     924           3 :   return 0;
     925           3 : }
     926             : 
     927             : static int
     928             : deser_vote_init( fd_vote_init_t * out,
     929             :                  uchar const **   data,
     930          24 :                  ulong *          sz ) {
     931          24 :   READ_BYTES( out, sizeof(fd_vote_init_t), data, sz );
     932          24 :   return 0;
     933          24 : }
     934             : 
     935             : static int
     936             : deser_vote_init_v2( fd_vote_init_v2_t * out,
     937             :                     uchar const **      data,
     938           6 :                     ulong *             sz ) {
     939           6 :   READ_PUBKEY( out->node_pubkey, data, sz );
     940           6 :   READ_PUBKEY( out->authorized_voter, data, sz );
     941           6 :   READ_BYTES( out->authorized_voter_bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ, data, sz );
     942           6 :   READ_BYTES( out->authorized_voter_bls_proof_of_possession, FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ, data, sz );
     943           6 :   READ_PUBKEY( out->authorized_withdrawer, data, sz );
     944           6 :   READ_U16( out->inflation_rewards_commission_bps, data, sz );
     945           6 :   READ_PUBKEY( out->inflation_rewards_collector, data, sz );
     946           6 :   READ_U16( out->block_revenue_commission_bps, data, sz );
     947           6 :   READ_PUBKEY( out->block_revenue_collector, data, sz );
     948           6 :   return 0;
     949           6 : }
     950             : 
     951             : static int
     952             : deser_vote( fd_vote_t *     out,
     953             :             uchar const **  data,
     954           0 :             ulong *         sz ) {
     955           0 :   ulong slots_len;
     956           0 :   READ_U64( slots_len, data, sz );
     957           0 :   CHECK( slots_len<=FD_VOTE_INSTR_MAX_SLOT_NUMS_LEN );
     958             : 
     959           0 :   out->slots = deq_ulong_join( deq_ulong_new( out->slots_mem, FD_VOTE_INSTR_MAX_SLOT_NUMS_LEN ) );
     960             : 
     961           0 :   for( ulong i=0UL; i<slots_len; i++ ) {
     962           0 :     ulong * elem = deq_ulong_push_tail_nocopy( out->slots );
     963           0 :     READ_U64( *elem, data, sz );
     964           0 :   }
     965             : 
     966           0 :   READ_HASH( out->hash, data, sz );
     967           0 :   READ_OPTION( out->has_timestamp, data, sz );
     968           0 :   if( out->has_timestamp ) {
     969           0 :     READ_I64( out->timestamp, data, sz );
     970           0 :   }
     971           0 :   return 0;
     972           0 : }
     973             : 
     974             : static int
     975             : deser_vote_state_update( fd_vote_state_update_t * out,
     976             :                          uchar const **           data,
     977           0 :                          ulong *                  sz ) {
     978           0 :   ulong lockouts_len;
     979           0 :   READ_U64( lockouts_len, data, sz );
     980           0 :   CHECK( lockouts_len<=FD_VOTE_INSTR_MAX_LOCKOUTS_LEN );
     981             : 
     982           0 :   out->lockouts = deq_fd_vote_lockout_t_join( deq_fd_vote_lockout_t_new( out->lockouts_mem, FD_VOTE_INSTR_MAX_LOCKOUTS_LEN ) );
     983             : 
     984           0 :   for( ulong i=0; i<lockouts_len; i++ ) {
     985           0 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( out->lockouts );
     986           0 :     READ_U64( elem->slot, data, sz );
     987           0 :     READ_U32( elem->confirmation_count, data, sz );
     988           0 :   }
     989             : 
     990           0 :   READ_OPTION( out->has_root, data, sz );
     991           0 :   if( out->has_root ) {
     992           0 :     READ_U64( out->root, data, sz );
     993           0 :   }
     994           0 :   READ_HASH( out->hash, data, sz );
     995           0 :   READ_OPTION( out->has_timestamp, data, sz );
     996           0 :   if( out->has_timestamp ) {
     997           0 :     READ_I64( out->timestamp, data, sz );
     998           0 :   }
     999           0 :   return 0;
    1000           0 : }
    1001             : 
    1002             : /* This function contains slightly custom deserialization logic to
    1003             :    adhere to serde_compact_vote_state_update in Agave.
    1004             :    https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.1.1/vote-interface/src/state/mod.rs#L265-L299 */
    1005             : static int
    1006             : deser_compact_vote_state_update( fd_compact_vote_state_update_t * out,
    1007             :                                  uchar const **                   data,
    1008           0 :                                  ulong *                          sz ) {
    1009           0 :   READ_U64( out->root, data, sz );
    1010             : 
    1011           0 :   ushort lockouts_len;
    1012           0 :   READ_COMPACT_U16( lockouts_len, data, sz );
    1013           0 :   CHECK( lockouts_len<=FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN );
    1014           0 :   out->lockouts_len = lockouts_len;
    1015             : 
    1016           0 :   out->lockouts = (fd_lockout_offset_t *)out->lockouts_mem;
    1017             : 
    1018           0 :   ulong slot = out->root!=ULONG_MAX ? out->root : 0UL;
    1019           0 :   for( ushort i=0; i<lockouts_len; i++ ) {
    1020           0 :     READ_U64_VARINT( out->lockouts[i].offset, data, sz );
    1021           0 :     READ_U8( out->lockouts[i].confirmation_count, data, sz );
    1022             : 
    1023             :     /* Custom logic: check that slot+lockout_offset
    1024             :        does not overflow */
    1025           0 :     CHECK( !__builtin_uaddl_overflow( slot, out->lockouts[i].offset, &slot ) );
    1026           0 :   }
    1027             : 
    1028           0 :   READ_HASH( out->hash, data, sz );
    1029           0 :   READ_OPTION( out->has_timestamp, data, sz );
    1030           0 :   if( out->has_timestamp ) {
    1031           0 :     READ_I64( out->timestamp, data, sz );
    1032           0 :   }
    1033           0 :   return 0;
    1034           0 : }
    1035             : 
    1036             : /* Similar to above. Tower sync uses delta-encoded lockout offsets,
    1037             :    converting them to absolute slot numbers on the fly.  Mirrors the
    1038             :    checked arithmetic from Agave's custom deserializer:
    1039             :    https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.1.1/vote-interface/src/state/mod.rs#L360-L396 */
    1040             : 
    1041             : static int
    1042             : deser_tower_sync( fd_tower_sync_t * out,
    1043             :                   uchar const **    data,
    1044           0 :                   ulong *           sz ) {
    1045           0 :   READ_U64( out->root, data, sz );
    1046           0 :   out->has_root = 1;
    1047             : 
    1048             :   /* First bit of custom logic: if root is ULONG_MAX, set root to 0. */
    1049           0 :   if( FD_UNLIKELY( out->root==ULONG_MAX ) ) {
    1050           0 :     out->has_root = 0;
    1051           0 :     out->root     = 0UL;
    1052           0 :   }
    1053             : 
    1054           0 :   ushort lockout_offsets_len;
    1055           0 :   READ_COMPACT_U16( lockout_offsets_len, data, sz );
    1056           0 :   CHECK( lockout_offsets_len<=FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN );
    1057             : 
    1058           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 ) );
    1059             : 
    1060           0 :   ulong last_slot = out->root;
    1061           0 :   for( ushort i=0; i<lockout_offsets_len; i++ ) {
    1062           0 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( out->lockouts );
    1063             : 
    1064           0 :     ulong offset;
    1065           0 :     READ_U64_VARINT( offset, data, sz );
    1066             : 
    1067           0 :     uchar confirmation_count;
    1068           0 :     READ_U8( confirmation_count, data, sz );
    1069             : 
    1070             :     /* Second bit of custom logic: check that last_slot+offset does not
    1071             :        overflow */
    1072           0 :     CHECK( !__builtin_uaddl_overflow( last_slot, offset, &elem->slot ) );
    1073           0 :     elem->confirmation_count = (uint)confirmation_count;
    1074           0 :     last_slot = elem->slot;
    1075           0 :   }
    1076             : 
    1077           0 :   out->lockouts_cnt = (ulong)lockout_offsets_len;
    1078             : 
    1079           0 :   READ_HASH( out->hash, data, sz );
    1080           0 :   READ_OPTION( out->has_timestamp, data, sz );
    1081           0 :   if( out->has_timestamp ) {
    1082           0 :     READ_I64( out->timestamp, data, sz );
    1083           0 :   }
    1084           0 :   READ_HASH( out->block_id, data, sz );
    1085           0 :   return 0;
    1086           0 : }
    1087             : 
    1088             : static int
    1089             : deser_vote_authorize_with_seed( fd_vote_authorize_with_seed_args_t * out,
    1090             :                                 uchar const **                       data,
    1091           0 :                                 ulong *                              sz ) {
    1092           0 :   CHECK( !deser_vote_authorize( &out->authorization_type, data, sz ) );
    1093           0 :   READ_PUBKEY( out->current_authority_derived_key_owner, data, sz );
    1094             : 
    1095           0 :   ulong seed_len;
    1096           0 :   READ_U64( seed_len, data, sz );
    1097             :   /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L42-L49 */
    1098           0 :   CHECK( seed_len<=FD_VOTE_INSTR_SEED_MAX );
    1099           0 :   out->current_authority_derived_key_seed_len = seed_len;
    1100             : 
    1101           0 :   READ_BYTES( out->current_authority_derived_key_seed, seed_len, data, sz );
    1102           0 :   CHECK( fd_utf8_verify( (char const *)out->current_authority_derived_key_seed, seed_len ) );
    1103             : 
    1104           0 :   READ_PUBKEY( out->new_authority, data, sz );
    1105           0 :   return 0;
    1106           0 : }
    1107             : 
    1108             : static int
    1109             : deser_vote_authorize_checked_with_seed( fd_vote_authorize_checked_with_seed_args_t * out,
    1110             :                                         uchar const **                               data,
    1111           0 :                                         ulong *                                      sz ) {
    1112           0 :   CHECK( !deser_vote_authorize( &out->authorization_type, data, sz ) );
    1113           0 :   READ_PUBKEY( out->current_authority_derived_key_owner, data, sz );
    1114             : 
    1115           0 :   ulong seed_len;
    1116           0 :   READ_U64( seed_len, data, sz );
    1117             :   /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L130 */
    1118           0 :   CHECK( seed_len<=FD_VOTE_INSTR_SEED_MAX );
    1119           0 :   out->current_authority_derived_key_seed_len = seed_len;
    1120             : 
    1121           0 :   READ_BYTES( out->current_authority_derived_key_seed, seed_len, data, sz );
    1122           0 :   CHECK( fd_utf8_verify( (char const *)out->current_authority_derived_key_seed, seed_len ) );
    1123           0 :   return 0;
    1124           0 : }
    1125             : 
    1126             : /**********************************************************************/
    1127             : /* Vote instruction -- top-level decoder                              */
    1128             : /**********************************************************************/
    1129             : 
    1130             : static int
    1131             : fd_vote_instruction_deserialize_inner( fd_vote_instruction_t * instruction,
    1132             :                                        uchar const *           data,
    1133         114 :                                        ulong                   data_sz ) {
    1134         114 :   fd_memset( instruction, 0, sizeof(fd_vote_instruction_t) );
    1135             : 
    1136         114 :   uchar const ** p  = &data;
    1137         114 :   ulong *        sz = &data_sz;
    1138             : 
    1139         114 :   READ_U32( instruction->discriminant, p, sz );
    1140             : 
    1141         114 :   switch( instruction->discriminant ) {
    1142             : 
    1143          24 :     case fd_vote_instruction_enum_initialize_account:
    1144          24 :       return deser_vote_init( &instruction->initialize_account, p, sz );
    1145             : 
    1146           3 :     case fd_vote_instruction_enum_authorize: {
    1147           3 :       READ_PUBKEY( instruction->authorize.pubkey, p, sz );
    1148           3 :       return deser_vote_authorize( &instruction->authorize.vote_authorize, p, sz );
    1149           3 :     }
    1150             : 
    1151           0 :     case fd_vote_instruction_enum_vote:
    1152           0 :       return deser_vote( &instruction->vote, p, sz );
    1153             : 
    1154           0 :     case fd_vote_instruction_enum_withdraw:
    1155           0 :       READ_U64( instruction->withdraw, p, sz );
    1156           0 :       return 0;
    1157             : 
    1158           6 :     case fd_vote_instruction_enum_update_validator_identity:
    1159           6 :       return 0;
    1160             : 
    1161           0 :     case fd_vote_instruction_enum_update_commission:
    1162           0 :       READ_U8( instruction->update_commission, p, sz );
    1163           0 :       return 0;
    1164             : 
    1165           0 :     case fd_vote_instruction_enum_vote_switch:
    1166           0 :       CHECK( !deser_vote( &instruction->vote_switch.vote, p, sz ) );
    1167           0 :       READ_HASH( instruction->vote_switch.hash, p, sz );
    1168           0 :       return 0;
    1169             : 
    1170           0 :     case fd_vote_instruction_enum_authorize_checked:
    1171           0 :       return deser_vote_authorize( &instruction->authorize_checked, p, sz );
    1172             : 
    1173           0 :     case fd_vote_instruction_enum_update_vote_state:
    1174           0 :       return deser_vote_state_update( &instruction->update_vote_state, p, sz );
    1175             : 
    1176           0 :     case fd_vote_instruction_enum_update_vote_state_switch:
    1177           0 :       CHECK( !deser_vote_state_update( &instruction->update_vote_state_switch.vote_state_update, p, sz ) );
    1178           0 :       READ_HASH( instruction->update_vote_state_switch.hash, p, sz );
    1179           0 :       return 0;
    1180             : 
    1181           0 :     case fd_vote_instruction_enum_authorize_with_seed:
    1182           0 :       return deser_vote_authorize_with_seed( &instruction->authorize_with_seed, p, sz );
    1183             : 
    1184           0 :     case fd_vote_instruction_enum_authorize_checked_with_seed:
    1185           0 :       return deser_vote_authorize_checked_with_seed( &instruction->authorize_checked_with_seed, p, sz );
    1186             : 
    1187           0 :     case fd_vote_instruction_enum_compact_update_vote_state:
    1188           0 :       return deser_compact_vote_state_update( &instruction->compact_update_vote_state, p, sz );
    1189             : 
    1190           0 :     case fd_vote_instruction_enum_compact_update_vote_state_switch:
    1191           0 :       CHECK( !deser_compact_vote_state_update( &instruction->compact_update_vote_state_switch.compact_vote_state_update, p, sz ) );
    1192           0 :       READ_HASH( instruction->compact_update_vote_state_switch.hash, p, sz );
    1193           0 :       return 0;
    1194             : 
    1195           0 :     case fd_vote_instruction_enum_tower_sync:
    1196           0 :       return deser_tower_sync( &instruction->tower_sync, p, sz );
    1197             : 
    1198           0 :     case fd_vote_instruction_enum_tower_sync_switch:
    1199           0 :       CHECK( !deser_tower_sync( &instruction->tower_sync_switch.tower_sync, p, sz ) );
    1200           0 :       READ_HASH( instruction->tower_sync_switch.hash, p, sz );
    1201           0 :       return 0;
    1202             : 
    1203           6 :     case fd_vote_instruction_enum_initialize_account_v2:
    1204           6 :       return deser_vote_init_v2( &instruction->initialize_account_v2, p, sz );
    1205             : 
    1206          72 :     case fd_vote_instruction_enum_update_commission_collector:
    1207          72 :       READ_ENUM( instruction->update_commission_collector.discriminant, 2U, p, sz );
    1208          72 :       return 0;
    1209             : 
    1210           3 :     case fd_vote_instruction_enum_update_commission_bps:
    1211           3 :       READ_U16( instruction->update_commission_bps.commission_bps, p, sz );
    1212           3 :       READ_ENUM( instruction->update_commission_bps.kind.discriminant, 2U, p, sz );
    1213           3 :       return 0;
    1214             : 
    1215           0 :     case fd_vote_instruction_enum_deposit_delegator_rewards:
    1216           0 :       READ_U64( instruction->deposit_delegator_rewards.deposit, p, sz );
    1217           0 :       return 0;
    1218             : 
    1219           0 :     default:
    1220           0 :       return 1;
    1221         114 :   }
    1222         114 : }
    1223             : 
    1224             : fd_vote_instruction_t *
    1225             : fd_vote_instruction_deserialize( fd_vote_instruction_t * instruction,
    1226             :                                  uchar const *           data,
    1227         114 :                                  ulong                   data_sz ) {
    1228             :   /* limited_deserialize(data, PACKET_DATA_SIZE)
    1229             :      https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L130 */
    1230         114 :   data_sz = fd_ulong_min( data_sz, FD_TXN_MTU_V0 );
    1231         114 :   CHECK_RET_NULL( !fd_vote_instruction_deserialize_inner( instruction, data, data_sz ) );
    1232         114 :   return instruction;
    1233         114 : }

Generated by: LCOV version 1.14