LCOV - code coverage report
Current view: top level - choreo/tower - fd_tower_serdes.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 156 0.0 %
Date: 2026-03-19 18:19:27 Functions: 0 11 0.0 %

          Line data    Source code
       1             : #include "fd_tower_serdes.h"
       2             : #include "fd_tower.h"
       3             : 
       4             : #define SHORTVEC 0
       5             : 
       6           0 : #define DE( T, name ) do {                                  \
       7           0 :     if( FD_UNLIKELY( off+sizeof(T)>buf_sz ) ) return -1;    \
       8           0 :     serde->name = *(T const *)fd_type_pun_const( buf+off ); \
       9           0 :     off += sizeof(T);                                       \
      10           0 : } while(0)
      11             : 
      12           0 : #define SER( T, name ) do {                              \
      13           0 :     if( FD_UNLIKELY( off+sizeof(T)>buf_sz ) ) return -1; \
      14           0 :     FD_STORE( T, buf+off, serde->name );                 \
      15           0 :     off += sizeof(T);                                    \
      16           0 : } while(0)
      17             : 
      18             : static ulong
      19           0 : de_short_u16( ushort * dst, uchar const * src ) {
      20           0 :   if     ( FD_LIKELY( !(0x80U & src[0]) ) ) { *dst = (ushort)src[0];                                                                           return 1; }
      21           0 :   else if( FD_LIKELY( !(0x80U & src[1]) ) ) { *dst = (ushort)((ulong)(src[0]&0x7FUL) + (((ulong)src[1])<<7));                                  return 2; }
      22           0 :   else                                      { *dst = (ushort)((ulong)(src[0]&0x7FUL) + (((ulong)(src[1]&0x7FUL))<<7) + (((ulong)src[2])<<14)); return 3; }
      23           0 : }
      24             : 
      25             : static ulong
      26             : de_var_int( ulong *       dst,
      27             :             uchar const * src,
      28           0 :             ulong         src_sz ) {
      29           0 :   *dst = 0;
      30           0 :   ulong off = 0;
      31           0 :   ulong bit = 0;
      32           0 :   while( FD_LIKELY( bit < 64 ) ) {
      33           0 :     if( FD_UNLIKELY( off >= src_sz ) ) return 0;
      34           0 :     uchar byte = *(uchar const *)(src+off);
      35           0 :     off       += 1;
      36           0 :     *dst      |= (byte & 0x7FUL) << bit;
      37           0 :     if( FD_LIKELY( (byte & 0x80U) == 0U ) ) {
      38           0 :       if( FD_UNLIKELY( (*dst>>bit) != byte                ) ) return 0;
      39           0 :       if( FD_UNLIKELY( byte==0U && (bit!=0U || *dst!=0UL) ) ) return 0;
      40           0 :       return off;
      41           0 :     }
      42           0 :     bit += 7;
      43           0 :   }
      44           0 :   return 0;
      45           0 : }
      46             : 
      47             : static ulong
      48           0 : ser_short_u16( uchar * dst, ushort val ) {
      49           0 :   if     ( FD_LIKELY( val < 0x80U ) ) {
      50           0 :     dst[0] = (uchar)val;
      51           0 :     return 1;
      52           0 :   }
      53           0 :   else if( FD_LIKELY( val < 0x4000U ) ) {
      54           0 :     dst[0] = (uchar)((val & 0x7FUL) | 0x80U);
      55           0 :     dst[1] = (uchar)(val >> 7);
      56           0 :     return 2;
      57           0 :   }
      58           0 :   else {
      59           0 :     dst[0] = (uchar)((val & 0x7FUL) | 0x80U);
      60           0 :     dst[1] = (uchar)(((val >> 7) & 0x7FUL) | 0x80U);
      61           0 :     dst[2] = (uchar)(val >> 14);
      62           0 :     return 3;
      63           0 :   }
      64           0 : }
      65             : 
      66             : static ulong
      67           0 : ser_var_int( uchar * dst, ulong val ) {
      68           0 :   ulong off = 0;
      69           0 :   while( FD_LIKELY( val >= 0x80UL ) ) {
      70           0 :     dst[off] = (uchar)((val & 0x7FUL) | 0x80U);
      71           0 :     val >>= 7;
      72           0 :     off  += 1;
      73           0 :   }
      74           0 :   dst[off] = (uchar)val;
      75           0 :   return off + 1;
      76           0 : }
      77             : 
      78             : int
      79             : fd_compact_tower_sync_de( fd_compact_tower_sync_serde_t * serde,
      80             :                           uchar const *                   buf,
      81           0 :                           ulong                           buf_sz ) {
      82           0 :   ulong off = 0;
      83           0 :   DE( ulong, root );
      84           0 :   off += de_short_u16( &serde->lockouts_cnt, buf+off );
      85           0 :   if( FD_UNLIKELY( serde->lockouts_cnt > FD_TOWER_VOTE_MAX ) ) return -1;
      86           0 :   for( ulong i = 0; i < serde->lockouts_cnt; i++ ) {
      87           0 :     ulong varint_sz = de_var_int( &serde->lockouts[i].offset, buf+off, buf_sz-off );
      88           0 :     if( FD_UNLIKELY( !varint_sz ) ) return -1;
      89           0 :     off += varint_sz;
      90           0 :     DE( uchar, lockouts[i].confirmation_count );
      91           0 :   }
      92           0 :   DE( fd_hash_t, hash             );
      93           0 :   DE( uchar,     timestamp_option );
      94           0 :   if( FD_LIKELY( serde->timestamp_option ) ) {
      95           0 :     DE( long, timestamp );
      96           0 :   }
      97           0 :   DE( fd_hash_t, block_id );
      98           0 :   return 0;
      99           0 : }
     100             : 
     101             : int
     102             : fd_compact_tower_sync_ser( fd_compact_tower_sync_serde_t const * serde,
     103             :                            uchar *                               buf,
     104             :                            ulong                                 buf_sz,
     105           0 :                            ulong *                               out_sz ) {
     106           0 :   ulong off = 0;
     107           0 :   SER( ulong, root );
     108           0 :   off += ser_short_u16( buf+off, serde->lockouts_cnt );
     109           0 :   if( FD_UNLIKELY( serde->lockouts_cnt > FD_TOWER_VOTE_MAX ) ) return -1;
     110           0 :   for( ulong i = 0; i < serde->lockouts_cnt; i++ ) {
     111           0 :     off += ser_var_int( buf+off, serde->lockouts[i].offset );
     112           0 :     SER( uchar, lockouts[i].confirmation_count );
     113           0 :   }
     114           0 :   SER( fd_hash_t, hash             );
     115           0 :   SER( uchar,     timestamp_option );
     116           0 :   if( FD_LIKELY( serde->timestamp_option ) ) {
     117           0 :     SER( long, timestamp );
     118           0 :   }
     119           0 :   SER( fd_hash_t, block_id );
     120           0 :   if( FD_LIKELY( out_sz ) ) *out_sz = off;
     121           0 :   return 0;
     122           0 : }
     123             : 
     124             : static fd_vote_acc_vote_t const *
     125           0 : v4_off( fd_vote_acc_t const * voter ) {
     126           0 :   return (fd_vote_acc_vote_t const *)( voter->v4.bls_pubkey_compressed + voter->v4.has_bls_pubkey_compressed * sizeof(voter->v4.bls_pubkey_compressed) + sizeof(ulong) );
     127           0 : }
     128             : 
     129             : ulong
     130           0 : fd_vote_acc_vote_cnt( uchar const * vote_account_data ) {
     131           0 :   fd_vote_acc_t const * voter = (fd_vote_acc_t const *)fd_type_pun_const( vote_account_data );
     132           0 :   switch( voter->kind ) {
     133           0 :   case FD_VOTE_ACC_V4: return fd_ulong_load_8( voter->v4.bls_pubkey_compressed + voter->v4.has_bls_pubkey_compressed * sizeof(voter->v4.bls_pubkey_compressed) );
     134           0 :   case FD_VOTE_ACC_V3: return voter->v3.votes_cnt;
     135           0 :   case FD_VOTE_ACC_V2: return voter->v2.votes_cnt;
     136           0 :   default: FD_LOG_HEXDUMP_CRIT(( "bad voter", vote_account_data, 3762 ));
     137           0 :   }
     138           0 : }
     139             : 
     140             : /* fd_vote_acc_vote_slot takes a voter's vote account data and returns the
     141             :    voter's most recent vote slot in the tower.  Returns ULONG_MAX if
     142             :    they have an empty tower. */
     143             : 
     144             : ulong
     145           0 : fd_vote_acc_vote_slot( uchar const * vote_account_data ) {
     146           0 :   fd_vote_acc_t const * voter = (fd_vote_acc_t const *)fd_type_pun_const( vote_account_data );
     147           0 :   ulong              cnt   = fd_vote_acc_vote_cnt( vote_account_data );
     148           0 :   switch( voter->kind ) {
     149           0 :   case FD_VOTE_ACC_V4: return cnt ? v4_off( voter )[cnt-1].slot : ULONG_MAX;
     150           0 :   case FD_VOTE_ACC_V3: return cnt ? voter->v3.votes[cnt-1].slot : ULONG_MAX;
     151           0 :   case FD_VOTE_ACC_V2: return cnt ? voter->v2.votes[cnt-1].slot : ULONG_MAX;
     152           0 :   default: FD_LOG_HEXDUMP_CRIT(( "bad voter", vote_account_data, 3762 ));
     153           0 :   }
     154           0 : }
     155             : 
     156             : /* fd_vote_acc_root_slot takes a voter's vote account data and returns the
     157             :    voter's root slot.  Returns ULONG_MAX if they don't have a root. */
     158             : 
     159             : ulong
     160           0 : fd_vote_acc_root_slot( uchar const * vote_account_data ) {
     161           0 :   fd_vote_acc_t const * voter = (fd_vote_acc_t const *)fd_type_pun_const( vote_account_data );
     162           0 :   ulong              cnt   = fd_vote_acc_vote_cnt( vote_account_data );
     163           0 :   switch( voter->kind ) {
     164           0 :   case FD_VOTE_ACC_V4: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&v4_off( voter )[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&v4_off( voter )[cnt] + 1UL ) : ULONG_MAX; }
     165           0 :   case FD_VOTE_ACC_V3: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&voter->v3.votes[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&voter->v3.votes[cnt] + 1UL ) : ULONG_MAX; }
     166           0 :   case FD_VOTE_ACC_V2: { uchar root_option = fd_uchar_load_1_fast( (uchar *)&voter->v2.votes[cnt] ); return root_option ? fd_ulong_load_8_fast( (uchar *)&voter->v2.votes[cnt] + 1UL ) : ULONG_MAX; }
     167           0 :   default:          FD_LOG_CRIT(( "unhandled kind %u", voter->kind ));
     168           0 :   }
     169           0 : }
     170             : 
     171             : int
     172             : fd_txn_parse_simple_vote( fd_txn_t const * txn,
     173             :                           uchar    const * payload,
     174             :                           fd_pubkey_t *    opt_identity,
     175             :                           fd_pubkey_t *    opt_vote_acct,
     176           0 :                           ulong *          opt_vote_slot ) {
     177           0 :   fd_txn_instr_t const * instr      = &txn->instr[ 0 ];
     178           0 :   ulong required_accts = txn->signature_cnt==1 ? 2UL : 3UL;
     179           0 :   if( FD_UNLIKELY( !fd_txn_is_simple_vote_transaction( txn, payload ) || instr->data_sz < sizeof(uint) || txn->acct_addr_cnt < required_accts ) ) return 0;
     180             : 
     181           0 :   uchar const *          instr_data = payload + instr->data_off;
     182           0 :   uint                   kind       = fd_uint_load_4_fast( instr_data );
     183             :   /* Older vote instruction kinds are deprecated / ignored */
     184           0 :   if( FD_UNLIKELY( kind == FD_VOTE_IX_KIND_TOWER_SYNC || kind == FD_VOTE_IX_KIND_TOWER_SYNC_SWITCH ) ) {
     185           0 :     fd_compact_tower_sync_serde_t compact_tower_sync_serde[ 1 ];
     186           0 :     int err = fd_compact_tower_sync_de( compact_tower_sync_serde, instr_data + sizeof(uint), instr->data_sz - sizeof(uint) );
     187           0 :     if( FD_LIKELY( !err ) ) {
     188           0 :       if( !!opt_vote_slot ) {
     189           0 :         *opt_vote_slot = compact_tower_sync_serde->root;
     190           0 :         for( ulong i = 0; i < compact_tower_sync_serde->lockouts_cnt; i++ ) *opt_vote_slot += compact_tower_sync_serde->lockouts[ i ].offset;
     191           0 :       }
     192           0 :       fd_pubkey_t const * accs = (fd_pubkey_t const *)fd_type_pun_const( payload + txn->acct_addr_off );
     193           0 :       if( !!opt_vote_acct ) {
     194           0 :         if( FD_UNLIKELY( txn->signature_cnt==1 ) ) *opt_vote_acct = *(fd_pubkey_t const *)fd_type_pun_const( &accs[ 1 ] ); /* identity and authority same, account idx 1 is the vote account address */
     195           0 :         else                                       *opt_vote_acct = *(fd_pubkey_t const *)fd_type_pun_const( &accs[ 2 ] ); /* identity and authority diff, account idx 2 is the vote account address */
     196           0 :       }
     197           0 :       if( !!opt_identity ) {
     198           0 :         *opt_identity = *(fd_pubkey_t const *)fd_type_pun_const( &accs[ 0 ] );
     199           0 :       }
     200           0 :       return 1;
     201           0 :     }
     202           0 :   }
     203           0 :   return 0;
     204           0 : }

Generated by: LCOV version 1.14