LCOV - code coverage report
Current view: top level - choreo/tower - fd_tower_file.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 124 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 2 0.0 %

          Line data    Source code
       1             : #include "fd_tower_file.h"
       2             : 
       3             : #include "../../ballet/ed25519/fd_ed25519.h"
       4             : 
       5             : #define SAVED_TOWER_KIND (1U) /* SavedTowerVersions::Current */
       6             : #define LAST_VOTE_KIND   (3U) /* VoteTransaction::TowerSync */
       7             : #define THRESHOLD_DEPTH  (8UL)
       8             : #define THRESHOLD_SIZE   (2.0/3.0)
       9             : #define TOWER_SYNC_MAX   (512UL)
      10             : 
      11           0 : #define SIG_OFF  FD_TOWER_FILE_SIG_OFF
      12           0 : #define DATA_OFF FD_TOWER_FILE_DATA_OFF
      13             : 
      14           0 : #define LOAD( T, dst ) do {                              \
      15           0 :     if( FD_UNLIKELY( sizeof(T)>buf_sz-off ) ) return FD_TOWER_FILE_ERR_SIZE; \
      16           0 :     (dst) = FD_LOAD( T, buf+off );                       \
      17           0 :     off += sizeof(T);                                    \
      18           0 :   } while(0)
      19             : 
      20           0 : #define SKIP( sz ) do {                                  \
      21           0 :     if( FD_UNLIKELY( (sz)>buf_sz-off ) ) return FD_TOWER_FILE_ERR_SIZE; \
      22           0 :     off += (sz);                                         \
      23           0 :   } while(0)
      24             : 
      25             : int
      26             : fd_tower_file_de( uchar const *       buf,
      27             :                   ulong               buf_sz,
      28             :                   fd_pubkey_t const * identity,
      29           0 :                   fd_tower_file_t *   out ) {
      30           0 :   if( FD_UNLIKELY( buf_sz>FD_TOWER_FILE_MAX ) ) return FD_TOWER_FILE_ERR_SIZE;
      31           0 :   ulong off = 0UL;
      32             : 
      33           0 :   uint kind;    LOAD( uint, kind );
      34           0 :   if( FD_UNLIKELY( kind!=SAVED_TOWER_KIND ) ) return FD_TOWER_FILE_ERR_VERSION;
      35             : 
      36           0 :   if( FD_UNLIKELY( buf_sz<DATA_OFF ) ) return FD_TOWER_FILE_ERR_SIZE;
      37           0 :   uchar const * sig = buf+SIG_OFF;
      38           0 :   off = SIG_OFF+64UL;
      39           0 :   ulong data_sz; LOAD( ulong, data_sz );
      40           0 :   if( FD_UNLIKELY( data_sz!=buf_sz-DATA_OFF ) ) return FD_TOWER_FILE_ERR_SIZE;
      41             : 
      42           0 :   fd_sha512_t sha[ 1 ];
      43           0 :   if( FD_UNLIKELY( FD_ED25519_SUCCESS!=fd_ed25519_verify( buf+DATA_OFF, data_sz, sig, identity->uc, sha ) ) ) return FD_TOWER_FILE_ERR_SIG;
      44             : 
      45           0 :   if( FD_UNLIKELY( 32UL>buf_sz-off ) ) return FD_TOWER_FILE_ERR_SIZE;
      46           0 :   if( FD_UNLIKELY( !fd_memeq( buf+off, identity->uc, 32UL ) ) ) return FD_TOWER_FILE_ERR_IDENTITY;
      47           0 :   off += 32UL;
      48             : 
      49           0 :   ulong  threshold_depth; LOAD( ulong,  threshold_depth );
      50           0 :   double threshold_size;  LOAD( double, threshold_size  );
      51           0 :   if( FD_UNLIKELY( threshold_depth!=THRESHOLD_DEPTH ) ) return FD_TOWER_FILE_ERR_TOWER;
      52           0 :   if( FD_UNLIKELY( threshold_size !=THRESHOLD_SIZE  ) ) return FD_TOWER_FILE_ERR_TOWER;
      53             : 
      54           0 :   SKIP( 32UL ); /* node_pubkey */
      55           0 :   SKIP( 32UL ); /* authorized_withdrawer */
      56           0 :   SKIP( 1UL  ); /* commission */
      57             : 
      58           0 :   ulong votes_cnt; LOAD( ulong, votes_cnt );
      59           0 :   if( FD_UNLIKELY( !votes_cnt || votes_cnt>FD_TOWER_VOTE_MAX ) ) return FD_TOWER_FILE_ERR_TOWER;
      60           0 :   fd_tower_vote_t votes[ FD_TOWER_VOTE_MAX ];
      61           0 :   for( ulong i=0UL; i<votes_cnt; i++ ) {
      62           0 :     ulong slot; LOAD( ulong, slot );
      63           0 :     uint  conf; LOAD( uint,  conf );
      64           0 :     votes[ i ].slot = slot;
      65           0 :     votes[ i ].conf = conf;
      66           0 :   }
      67             : 
      68           0 :   uchar has_root; LOAD( uchar, has_root );
      69           0 :   if( FD_UNLIKELY( has_root!=1 ) ) return FD_TOWER_FILE_ERR_TOWER;
      70           0 :   ulong root; LOAD( ulong, root );
      71           0 :   if( FD_UNLIKELY( root==ULONG_MAX ) ) return FD_TOWER_FILE_ERR_TOWER;
      72             : 
      73           0 :   ulong authorized_voters_cnt; LOAD( ulong, authorized_voters_cnt );
      74           0 :   if( FD_UNLIKELY( authorized_voters_cnt>(buf_sz-off)/40UL ) ) return FD_TOWER_FILE_ERR_SIZE;
      75           0 :   SKIP( authorized_voters_cnt*40UL );
      76           0 :   SKIP( 32UL*48UL+8UL ); /* prior_voters buf, idx */
      77           0 :   uchar prior_voters_empty; LOAD( uchar, prior_voters_empty );
      78           0 :   if( FD_UNLIKELY( prior_voters_empty>1U ) ) return FD_TOWER_FILE_ERR_TOWER;
      79           0 :   ulong epoch_credits_cnt; LOAD( ulong, epoch_credits_cnt );
      80           0 :   if( FD_UNLIKELY( epoch_credits_cnt>(buf_sz-off)/24UL ) ) return FD_TOWER_FILE_ERR_SIZE;
      81           0 :   SKIP( epoch_credits_cnt*24UL );
      82           0 :   SKIP( 8UL ); /* last_timestamp slot */
      83           0 :   SKIP( 8UL ); /* last_timestamp ts */
      84             : 
      85           0 :   uint last_vote_kind; LOAD( uint, last_vote_kind );
      86           0 :   if( FD_UNLIKELY( last_vote_kind!=LAST_VOTE_KIND ) ) return FD_TOWER_FILE_ERR_VERSION;
      87             : 
      88           0 :   if( FD_UNLIKELY( off>buf_sz || buf_sz-off<16UL ) ) return FD_TOWER_FILE_ERR_SIZE;
      89           0 :   ulong sync_sz = buf_sz-off-16UL;
      90           0 :   fd_compact_tower_sync_serde_t sync;
      91           0 :   if( FD_UNLIKELY( fd_compact_tower_sync_de( &sync, buf+off, sync_sz ) ) ) return FD_TOWER_FILE_ERR_TOWER;
      92             : 
      93           0 :   uchar sync_buf[ TOWER_SYNC_MAX ];
      94           0 :   ulong canonical_sz;
      95           0 :   if( FD_UNLIKELY( fd_compact_tower_sync_ser( &sync, sync_buf, sizeof(sync_buf), &canonical_sz ) ) ) return FD_TOWER_FILE_ERR_TOWER;
      96           0 :   if( FD_UNLIKELY( canonical_sz!=sync_sz || !fd_memeq( sync_buf, buf+off, sync_sz ) ) ) return FD_TOWER_FILE_ERR_SIZE;
      97           0 :   if( FD_UNLIKELY( sync.root!=root || sync.lockouts_cnt!=votes_cnt ) ) return FD_TOWER_FILE_ERR_TOWER;
      98             : 
      99           0 :   fd_tower_vote_t decoded[ FD_TOWER_VOTE_MAX ];
     100           0 :   ulong           decoded_cnt;
     101           0 :   ulong           decoded_root;
     102           0 :   if( FD_UNLIKELY( fd_compact_tower_sync_to_votes( &sync, decoded, &decoded_cnt, &decoded_root ) ) ) return FD_TOWER_FILE_ERR_TOWER;
     103           0 :   if( FD_UNLIKELY( decoded_cnt!=votes_cnt || decoded_root!=root ||
     104           0 :                    !fd_memeq( decoded, votes, votes_cnt*sizeof(fd_tower_vote_t) ) ) ) return FD_TOWER_FILE_ERR_TOWER;
     105           0 :   if( FD_UNLIKELY( votes[ votes_cnt-1UL ].slot==ULONG_MAX ) ) return FD_TOWER_FILE_ERR_TOWER;
     106             : 
     107           0 :   off += sync_sz;
     108           0 :   ulong last_timestamp_slot; LOAD( ulong, last_timestamp_slot );
     109           0 :   long  last_timestamp;      LOAD( long,  last_timestamp      );
     110           0 :   if( FD_UNLIKELY( off!=buf_sz ) ) return FD_TOWER_FILE_ERR_SIZE;
     111             : 
     112           0 :   fd_memset( out, 0, sizeof(fd_tower_file_t) );
     113           0 :   fd_memcpy( out->votes, votes, votes_cnt*sizeof(fd_tower_vote_t) );
     114           0 :   out->votes_cnt      = votes_cnt;
     115           0 :   out->root           = root;
     116           0 :   out->bank_hash      = sync.hash;
     117           0 :   out->block_id       = sync.block_id;
     118           0 :   out->timestamp_slot = last_timestamp_slot;
     119           0 :   out->timestamp      = last_timestamp;
     120             : 
     121           0 :   return FD_TOWER_FILE_SUCCESS;
     122           0 : }
     123             : 
     124             : #undef LOAD
     125             : #undef SKIP
     126             : 
     127             : ulong
     128             : fd_tower_file_ser( fd_compact_tower_sync_serde_t const * sync,
     129             :                    fd_pubkey_t const *                   identity,
     130           0 :                    uchar                                 buf[ static FD_TOWER_FILE_MAX ] ) {
     131           0 :   fd_tower_vote_t votes[ FD_TOWER_VOTE_MAX ];
     132           0 :   ulong           votes_cnt;
     133           0 :   ulong           root;
     134           0 :   FD_TEST( !fd_compact_tower_sync_to_votes( sync, votes, &votes_cnt, &root ) && votes_cnt );
     135           0 :   ulong last      = votes[ votes_cnt-1UL ].slot;
     136           0 :   long  timestamp = fd_long_if( sync->timestamp_option, sync->timestamp, 0L );
     137             : 
     138           0 :   ulong off = DATA_OFF;
     139           0 : # define PUT( T, v ) do { FD_STORE( T, buf+off, (v) ); off += sizeof(T); } while(0)
     140           0 :   fd_memcpy( buf+off, identity->uc, 32UL ); off += 32UL;
     141           0 :   PUT( ulong,  THRESHOLD_DEPTH );
     142           0 :   PUT( double, THRESHOLD_SIZE  );
     143           0 :   fd_memset( buf+off, 0, 65UL ); off += 65UL; /* node_pubkey, authorized_withdrawer, commission */
     144           0 :   PUT( ulong, votes_cnt );
     145           0 :   for( ulong i=0UL; i<votes_cnt; i++ ) {
     146           0 :     PUT( ulong, votes[ i ].slot       );
     147           0 :     PUT( uint,  (uint)votes[ i ].conf );
     148           0 :   }
     149           0 :   PUT( uchar, root!=ULONG_MAX );
     150           0 :   if( root!=ULONG_MAX ) PUT( ulong, root );
     151           0 :   PUT( ulong, 0UL ); /* authorized_voters */
     152           0 :   fd_memset( buf+off, 0, 32UL*48UL+8UL ); off += 32UL*48UL+8UL; /* prior_voters buf, idx */
     153           0 :   PUT( uchar, 1   ); /* prior_voters is_empty */
     154           0 :   PUT( ulong, 0UL ); /* epoch_credits */
     155           0 :   PUT( ulong, 0UL ); PUT( long, 0L ); /* vote_state last_timestamp */
     156           0 :   PUT( uint,  LAST_VOTE_KIND );
     157           0 :   ulong sync_sz;
     158           0 :   FD_TEST( !fd_compact_tower_sync_ser( sync, buf+off, FD_TOWER_FILE_MAX-off, &sync_sz ) );
     159           0 :   off += sync_sz;
     160           0 :   PUT( ulong, last ); PUT( long, timestamp ); /* last_timestamp */
     161           0 : # undef PUT
     162             : 
     163           0 :   FD_STORE( uint,  buf,             SAVED_TOWER_KIND );
     164           0 :   FD_STORE( ulong, buf+SIG_OFF+64UL, off-DATA_OFF    );
     165           0 :   return off;
     166           0 : }

Generated by: LCOV version 1.14