LCOV - code coverage report
Current view: top level - flamenco/types - fd_types_custom.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 65 238 27.3 %
Date: 2025-07-03 04:52:04 Functions: 6 18 33.3 %

          Line data    Source code
       1             : #include "fd_types_custom.h"
       2             : #include "fd_bincode.h"
       3             : #include "fd_types.h"
       4             : #include "fd_types_meta.h"
       5             : #ifndef SOURCE_fd_src_flamenco_types_fd_types_c
       6             : #error "fd_types_custom.c is part of the fd_types.c compile uint"
       7             : #endif /* !SOURCE_fd_src_flamenco_types_fd_types_c */
       8             : 
       9             : #include "../runtime/fd_system_ids.h"
      10             : #include "../runtime/fd_executor_err.h"
      11             : 
      12             : #include <stdio.h>
      13             : 
      14             : int
      15           3 : fd_flamenco_txn_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
      16           3 :   *total_sz += sizeof(fd_flamenco_txn_t);
      17           3 :   void const * start_data = ctx->data;
      18           3 :   int err = fd_flamenco_txn_decode_footprint_inner( ctx, total_sz );
      19           3 :   ctx->data = start_data;
      20           3 :   return err;
      21           3 : }
      22             : 
      23             : int
      24           9 : fd_flamenco_txn_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
      25           9 :   if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
      26           9 :   ulong bufsz = (ulong)ctx->dataend - (ulong)ctx->data;
      27           9 :   fd_flamenco_txn_t self;
      28           9 :   ulong sz  = 0UL;
      29           9 :   ulong res = fd_txn_parse_core( ctx->data,
      30           9 :                                  bufsz,
      31           9 :                                  self.txn,
      32           9 :                                  NULL,
      33           9 :                                  &sz );
      34           9 :   if( FD_UNLIKELY( !res ) ) {
      35           0 :     return -1000001;
      36           0 :   }
      37           9 :   ctx->data  = (void *)( (ulong)ctx->data + sz );
      38           9 :   *total_sz += sz;
      39           9 :   return 0;
      40           9 : }
      41             : 
      42             : int FD_FN_UNUSED
      43             : fd_flamenco_txn_encode_global( fd_flamenco_txn_t const * self,
      44           0 :                                fd_bincode_encode_ctx_t * ctx ) {
      45           0 :   (void)self;
      46           0 :   (void)ctx;
      47           0 :   FD_LOG_ERR(( "only exists for testing" ));
      48           0 : }
      49             : 
      50             : void * FD_FN_UNUSED
      51             : fd_flamenco_txn_decode_global( void *                    mem,
      52           0 :                                fd_bincode_decode_ctx_t * ctx ) {
      53           0 :   (void)mem;
      54           0 :   (void)ctx;
      55           0 :   FD_LOG_ERR(( "only exists for testing" ));
      56           0 : }
      57             : 
      58             : void *
      59           3 : fd_flamenco_txn_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) {
      60           3 :   fd_flamenco_txn_t * self = (fd_flamenco_txn_t *)mem;
      61           3 :   fd_flamenco_txn_new( self );
      62           3 :   void *   alloc_region = (uchar *)mem + sizeof(fd_flamenco_txn_t);
      63           3 :   void * * alloc_mem    = &alloc_region;
      64           3 :   fd_flamenco_txn_decode_inner( mem, alloc_mem, ctx );
      65           3 :   return self;
      66           3 : }
      67             : 
      68             : void
      69           9 : fd_flamenco_txn_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
      70           9 :   fd_flamenco_txn_t * self = (fd_flamenco_txn_t *)struct_mem;
      71           9 :   static FD_TL fd_txn_parse_counters_t counters[1];
      72           9 :   ulong bufsz = (ulong)ctx->dataend - (ulong)ctx->data;
      73           9 :   ulong sz    = 0UL;
      74           9 :   ulong res   = fd_txn_parse_core( ctx->data,
      75           9 :                                    bufsz,
      76           9 :                                    self->txn,
      77           9 :                                    counters,
      78           9 :                                    &sz );
      79           9 :   if( FD_UNLIKELY( !res ) ) {
      80           0 :     FD_LOG_ERR(( "Failed to decode txn (fd_txn.c:%lu)",
      81           0 :                  counters->failure_ring[ counters->failure_cnt % FD_TXN_PARSE_COUNTERS_RING_SZ ] ));
      82           0 :     return;
      83           0 :   }
      84           9 :   fd_memcpy( self->raw, ctx->data, sz );
      85           9 :   self->raw_sz = sz;
      86           9 :   ctx->data = (void *)( (ulong)ctx->data + sz );
      87           9 : }
      88             : 
      89             : void
      90             : fd_gossip_ip4_addr_walk( void *                       w,
      91             :                          fd_gossip_ip4_addr_t const * self,
      92             :                          fd_types_walk_fn_t           fun,
      93             :                          char const *                 name,
      94             :                          uint                         level,
      95          93 :                          uint                         varint ) {
      96          93 :   (void) varint;
      97             : 
      98          93 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip4_addr", level++, 0 );
      99          93 :   uchar * octet = (uchar *)self;
     100         465 :   for( uchar i = 0; i < 4; ++i ) {
     101         372 :     fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level, 0 );
     102         372 :   }
     103          93 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip4_addr", level--, 0 );
     104             :   /* TODO: Add support for optional pretty-printing like serde?
     105             :      Saving this in the meantime */
     106             :   // char buf[ 16 ];
     107             :   // sprintf( buf, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( *self ) );
     108             :   // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip4_addr", level );
     109          93 : }
     110             : 
     111             : void
     112             : fd_gossip_ip6_addr_walk( void *                       w,
     113             :                          fd_gossip_ip6_addr_t const * self,
     114             :                          fd_types_walk_fn_t           fun,
     115             :                          char const *                 name,
     116             :                          uint                         level,
     117           0 :                          uint                         varint ) {
     118           0 :   (void) varint;
     119             : 
     120           0 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip6_addr", level++, 0 );
     121           0 :   uchar * octet = (uchar *)self;
     122           0 :   for( uchar i = 0; i < 16; ++i ) {
     123           0 :     fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level, 0 );
     124           0 :   }
     125           0 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip6_addr", level--, 0 );
     126             :   /* Saving this for when we support configurable pretty-printing mode */
     127             :   // char buf[ 40 ];
     128             :   // sprintf( buf,
     129             :   //          "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
     130             :   //          FD_LOG_HEX16_FMT_ARGS( self->us ) );
     131             :   // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip6_addr", level );
     132           0 : }
     133             : 
     134           0 : int fd_tower_sync_encode( fd_tower_sync_t const * self, fd_bincode_encode_ctx_t * ctx ) {
     135           0 :   FD_LOG_ERR(( "todo"));
     136           0 : }
     137             : 
     138             : static void fd_hash_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
     139             : static int fd_hash_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
     140             : static void fd_lockout_offset_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
     141             : static int fd_lockout_offset_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
     142             : 
     143           0 : int fd_tower_sync_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
     144             :   /* This is a modified version of fd_compact_tower_sync_decode_footprint_inner() */
     145           0 :   int err = 0;
     146           0 :   if( FD_UNLIKELY( ctx->data>ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     147           0 :   err = fd_bincode_uint64_decode_footprint( ctx );
     148             : 
     149             :   /* The first modification is that we want to grab the value fo the root. */
     150           0 :   ulong root = 0UL;
     151           0 :   fd_bincode_decode_ctx_t root_ctx = { .data = (uchar*)ctx->data - sizeof(ulong), .dataend = ctx->data };
     152           0 :   if( FD_UNLIKELY( ((ulong)ctx->data)+sizeof(ulong)>(ulong)ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     153           0 :   fd_bincode_uint64_decode_unsafe( &root, &root_ctx );
     154           0 :   root = root != ULONG_MAX ? root : 0UL;
     155             :   /* Done with first modification */
     156             : 
     157           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
     158           0 :   ushort lockout_offsets_len;
     159           0 :   if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     160           0 :   err = fd_bincode_compact_u16_decode( &lockout_offsets_len, ctx );
     161             : 
     162           0 :   if( FD_UNLIKELY( err ) ) return err;
     163           0 :   ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
     164           0 :   *total_sz += deq_fd_lockout_offset_t_align() + deq_fd_lockout_offset_t_footprint( lockout_offsets_max );
     165             : 
     166           0 :   for( ulong i = 0; i < lockout_offsets_len; ++i ) {
     167             : 
     168           0 :     uchar const * start_data = ctx->data;
     169           0 :     err = fd_lockout_offset_decode_footprint_inner( ctx, total_sz );
     170           0 :     if( FD_UNLIKELY( err ) ) return err;
     171             : 
     172             :     /* The second modification is that we want to grab the lockout offset from
     173             :     the deque to make sure that we can do a checked add successfully. */
     174           0 :     fd_lockout_offset_t lockout_offset = {0};
     175           0 :     fd_bincode_decode_ctx_t lockout_ctx = { .data = start_data, .dataend = start_data+sizeof(fd_lockout_offset_t) };
     176           0 :     if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     177           0 :     fd_lockout_offset_decode_inner( &lockout_offset, NULL, &lockout_ctx );
     178           0 :     err = __builtin_uaddl_overflow( root, lockout_offset.offset, &root );
     179           0 :     if( FD_UNLIKELY( err ) ) {
     180           0 :       return err;
     181           0 :     }
     182             :     /* Done with second modification. */
     183           0 :   }
     184             : 
     185           0 :   if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     186           0 :   err = fd_hash_decode_footprint_inner( ctx, total_sz );
     187           0 :   if( FD_UNLIKELY( err ) ) return err;
     188           0 :   {
     189           0 :     uchar o;
     190           0 :     if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     191           0 :     err = fd_bincode_bool_decode( &o, ctx );
     192           0 :     if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
     193           0 :     if( o ) {
     194           0 :       if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     195           0 :       err = fd_bincode_int64_decode_footprint( ctx );
     196           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
     197           0 :     }
     198           0 :   }
     199           0 :   if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     200           0 :   err = fd_hash_decode_footprint_inner( ctx, total_sz );
     201           0 :   if( FD_UNLIKELY( err ) ) return err;
     202           0 :   return 0;
     203           0 : }
     204             : 
     205           0 : int fd_tower_sync_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
     206           0 :   *total_sz += sizeof(fd_tower_sync_t);
     207           0 :   void const * start_data = ctx->data;
     208           0 :   int err = fd_tower_sync_decode_footprint_inner( ctx, total_sz );
     209           0 :   ctx->data = start_data;
     210           0 :   return err;
     211           0 : }
     212             : 
     213           0 : void fd_tower_sync_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     214           0 :   fd_tower_sync_t * self = (fd_tower_sync_t *)struct_mem;
     215           0 :   self->has_root = 1;
     216           0 :   fd_bincode_uint64_decode_unsafe( &self->root, ctx );
     217           0 :   self->has_root = self->root != ULONG_MAX;
     218             : 
     219           0 :   ushort lockout_offsets_len;
     220           0 :   fd_bincode_compact_u16_decode_unsafe( &lockout_offsets_len, ctx );
     221           0 :   ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
     222           0 :   self->lockouts = deq_fd_vote_lockout_t_join_new( alloc_mem, lockout_offsets_max );
     223             : 
     224             :   /* NOTE: Agave does a a checked add on the sum of the root with all of the
     225             :      lockout offsets in their custom deserializer for tower sync votes. If the
     226             :      checked add is violated (this should never happen), the deocder will
     227             :      return NULL.  */
     228             : 
     229             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L1062-L1077
     230           0 :   ulong last_slot = ((self->root == ULONG_MAX) ? 0 : self->root);
     231           0 :   for( ulong i=0; i < lockout_offsets_len; i++ ) {
     232           0 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( self->lockouts );
     233             : 
     234           0 :     fd_lockout_offset_t o;
     235           0 :     fd_lockout_offset_decode_inner( &o, alloc_mem, ctx );
     236             : 
     237           0 :     elem->slot = last_slot + o.offset;
     238           0 :     elem->confirmation_count = o.confirmation_count;
     239           0 :     last_slot = elem->slot;
     240           0 :   }
     241             : 
     242           0 :   fd_hash_decode_inner( &self->hash, alloc_mem, ctx );
     243           0 :   {
     244           0 :     uchar o;
     245           0 :     fd_bincode_bool_decode_unsafe( &o, ctx );
     246           0 :     self->has_timestamp = !!o;
     247           0 :     if( o ) {
     248           0 :       fd_bincode_int64_decode_unsafe( &self->timestamp, ctx );
     249           0 :     }
     250           0 :   }
     251           0 :   fd_hash_decode_inner( &self->block_id, alloc_mem, ctx );
     252           0 : }
     253             : 
     254           0 : void * fd_tower_sync_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) {
     255           0 :   fd_tower_sync_t * self = (fd_tower_sync_t *)mem;
     256           0 :   fd_tower_sync_new( self );
     257           0 :   void * alloc_region = (uchar *)mem + sizeof(fd_tower_sync_t);
     258           0 :   void * * alloc_mem = &alloc_region;
     259           0 :   fd_tower_sync_decode_inner( mem, alloc_mem, ctx );
     260           0 :   return self;
     261           0 : }
     262             : 
     263           0 : void fd_tower_sync_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     264           0 :   FD_LOG_ERR(("TODO: Implement"));
     265           0 : }
     266             : 
     267             : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2374
     268             : //
     269             : // During the call to Duration::new(...), it normalizes the seconds and nanoseconds automatically.  We need to
     270             : // match this behavior correctly
     271             : //
     272             : void
     273           0 : fd_rust_duration_normalize ( fd_rust_duration_t * self ) {
     274           0 :   if( self->nanoseconds < 1000000000U )
     275           0 :     return;
     276           0 :   uint secs = self->nanoseconds/1000000000U;
     277           0 :   self->seconds += secs;
     278           0 :   self->nanoseconds -= secs * 1000000000U;
     279           0 : }
     280             : 
     281             : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2203
     282             : //
     283             : // There is an overflow check at line 2373 that turns an overflow into an encoding error
     284             : //
     285             : int
     286           0 : fd_rust_duration_footprint_validator ( fd_bincode_decode_ctx_t * ctx ) {
     287           0 :   fd_rust_duration_t *d = (fd_rust_duration_t *) ctx->data;
     288           0 :   if( d->nanoseconds < 1000000000U )
     289           0 :     return FD_BINCODE_SUCCESS;
     290           0 :   ulong out;
     291           0 :   if( __builtin_uaddl_overflow( d->seconds, d->nanoseconds/1000000000U, &out ) )
     292           0 :     return FD_BINCODE_ERR_ENCODING;
     293           0 :   return FD_BINCODE_SUCCESS;
     294           0 : }
     295             : 
     296           0 : void fd_vote_accounts_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     297           0 :   fd_vote_accounts_t * self = (fd_vote_accounts_t *)struct_mem;
     298           0 :   ulong vote_accounts_len;
     299           0 :   fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
     300           0 :   self->vote_accounts_pool = fd_vote_accounts_pair_t_map_join_new( alloc_mem, fd_ulong_max( vote_accounts_len, 50000 ) );
     301           0 :   self->vote_accounts_root = NULL;
     302           0 :   for( ulong i=0; i < vote_accounts_len; i++ ) {
     303           0 :     fd_vote_accounts_pair_t_mapnode_t * node = fd_vote_accounts_pair_t_map_acquire( self->vote_accounts_pool );
     304           0 :     fd_vote_accounts_pair_new( &node->elem );
     305           0 :     fd_vote_accounts_pair_decode_inner( &node->elem, alloc_mem, ctx );
     306             :     // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L323
     307             :     // throws an error and
     308           0 :     if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     309             :       // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L429
     310             :       // causes the entry to not get added
     311           0 :       fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, node );
     312           0 :     } else {
     313           0 :       fd_vote_accounts_pair_t_mapnode_t * out = NULL;
     314           0 :       fd_vote_accounts_pair_t_map_insert_or_replace( self->vote_accounts_pool, &self->vote_accounts_root, node, &out );
     315           0 :       if( !!out ) {
     316           0 :         fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, out );
     317           0 :       }
     318           0 :     }
     319           0 :   }
     320           0 : }
     321             : 
     322           6 : void fd_vote_accounts_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     323           6 :   fd_vote_accounts_global_t * self = (fd_vote_accounts_global_t *)struct_mem;
     324           6 :   ulong vote_accounts_len;
     325           6 :   fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
     326           6 :   *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, fd_vote_accounts_pair_global_t_map_align() );
     327           6 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_pool = fd_vote_accounts_pair_global_t_map_join_new( alloc_mem, fd_ulong_max( vote_accounts_len, 50000 ) );
     328           6 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = NULL;
     329           6 :   for( ulong i=0; i < vote_accounts_len; i++ ) {
     330           0 :     fd_vote_accounts_pair_global_t_mapnode_t * node = fd_vote_accounts_pair_global_t_map_acquire( vote_accounts_pool );
     331           0 :     fd_vote_accounts_pair_new( (fd_vote_accounts_pair_t *)fd_type_pun(&node->elem) );
     332           0 :     fd_vote_accounts_pair_decode_inner_global( &node->elem, alloc_mem, ctx );
     333           0 :     if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     334           0 :       fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, node );
     335           0 :     } else {
     336           0 :       fd_vote_accounts_pair_global_t_mapnode_t * out = NULL;
     337           0 :       fd_vote_accounts_pair_global_t_map_insert_or_replace( vote_accounts_pool, &vote_accounts_root, node, &out );
     338           0 :       if( !!out ) {
     339           0 :         fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, out );
     340           0 :       }
     341           0 :     }
     342           0 :   }
     343           6 :   self->vote_accounts_pool_offset = (ulong)fd_vote_accounts_pair_global_t_map_leave( vote_accounts_pool ) - (ulong)struct_mem;
     344           6 :   self->vote_accounts_root_offset = (ulong)vote_accounts_root - (ulong)struct_mem;
     345           6 : }

Generated by: LCOV version 1.14