LCOV - code coverage report
Current view: top level - flamenco/types - fd_types_custom.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 64 241 26.6 %
Date: 2025-07-01 05:00:49 Functions: 6 19 31.6 %

          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          93 :                          uint                         level ) {
      95             : 
      96          93 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip4_addr", level++ );
      97          93 :   uchar * octet = (uchar *)self;
      98         465 :   for( uchar i = 0; i < 4; ++i ) {
      99         372 :     fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level );
     100         372 :   }
     101          93 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip4_addr", level-- );
     102             :   /* TODO: Add support for optional pretty-printing like serde?
     103             :      Saving this in the meantime */
     104             :   // char buf[ 16 ];
     105             :   // sprintf( buf, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( *self ) );
     106             :   // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip4_addr", level );
     107          93 : }
     108             : 
     109             : void
     110             : fd_gossip_ip6_addr_walk( void *                       w,
     111             :                          fd_gossip_ip6_addr_t const * self,
     112             :                          fd_types_walk_fn_t           fun,
     113             :                          char const *                 name,
     114           0 :                          uint                         level ) {
     115           0 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR, "ip6_addr", level++ );
     116           0 :   uchar * octet = (uchar *)self;
     117           0 :   for( uchar i = 0; i < 16; ++i ) {
     118           0 :     fun( w, &octet[i], name, FD_FLAMENCO_TYPE_UCHAR, "uchar", level );
     119           0 :   }
     120           0 :   fun( w, self, name, FD_FLAMENCO_TYPE_ARR_END, "ip6_addr", level-- );
     121             :   /* Saving this for when we support configurable pretty-printing mode */
     122             :   // char buf[ 40 ];
     123             :   // sprintf( buf,
     124             :   //          "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
     125             :   //          FD_LOG_HEX16_FMT_ARGS( self->us ) );
     126             :   // fun( w, buf, name, FD_FLAMENCO_TYPE_CSTR, "ip6_addr", level );
     127           0 : }
     128             : 
     129           0 : int fd_tower_sync_encode( fd_tower_sync_t const * self, fd_bincode_encode_ctx_t * ctx ) {
     130           0 :   FD_LOG_ERR(( "todo"));
     131           0 : }
     132             : 
     133             : static void fd_hash_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
     134             : static int fd_hash_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
     135             : static void fd_lockout_offset_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx );
     136             : static int fd_lockout_offset_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz );
     137             : 
     138           0 : int fd_tower_sync_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
     139             :   /* This is a modified version of fd_compact_tower_sync_decode_footprint_inner() */
     140           0 :   int err = 0;
     141           0 :   if( FD_UNLIKELY( ctx->data>ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     142           0 :   err = fd_bincode_uint64_decode_footprint( ctx );
     143             : 
     144             :   /* The first modification is that we want to grab the value fo the root. */
     145           0 :   ulong root = 0UL;
     146           0 :   fd_bincode_decode_ctx_t root_ctx = { .data = (uchar*)ctx->data - sizeof(ulong), .dataend = ctx->data };
     147           0 :   if( FD_UNLIKELY( ((ulong)ctx->data)+sizeof(ulong)>(ulong)ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     148           0 :   fd_bincode_uint64_decode_unsafe( &root, &root_ctx );
     149           0 :   root = root != ULONG_MAX ? root : 0UL;
     150             :   /* Done with first modification */
     151             : 
     152           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
     153           0 :   ushort lockout_offsets_len;
     154           0 :   if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     155           0 :   err = fd_bincode_compact_u16_decode( &lockout_offsets_len, ctx );
     156             : 
     157           0 :   if( FD_UNLIKELY( err ) ) return err;
     158           0 :   ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
     159           0 :   *total_sz += deq_fd_lockout_offset_t_align() + deq_fd_lockout_offset_t_footprint( lockout_offsets_max );
     160             : 
     161           0 :   for( ulong i = 0; i < lockout_offsets_len; ++i ) {
     162             : 
     163           0 :     uchar const * start_data = ctx->data;
     164           0 :     err = fd_lockout_offset_decode_footprint_inner( ctx, total_sz );
     165           0 :     if( FD_UNLIKELY( err ) ) return err;
     166             : 
     167             :     /* The second modification is that we want to grab the lockout offset from
     168             :     the deque to make sure that we can do a checked add successfully. */
     169           0 :     fd_lockout_offset_t lockout_offset = {0};
     170           0 :     fd_bincode_decode_ctx_t lockout_ctx = { .data = start_data, .dataend = start_data+sizeof(fd_lockout_offset_t) };
     171           0 :     if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     172           0 :     fd_lockout_offset_decode_inner( &lockout_offset, NULL, &lockout_ctx );
     173           0 :     err = __builtin_uaddl_overflow( root, lockout_offset.offset, &root );
     174           0 :     if( FD_UNLIKELY( err ) ) {
     175           0 :       return err;
     176           0 :     }
     177             :     /* Done with second modification. */
     178           0 :   }
     179             : 
     180           0 :   if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     181           0 :   err = fd_hash_decode_footprint_inner( ctx, total_sz );
     182           0 :   if( FD_UNLIKELY( err ) ) return err;
     183           0 :   {
     184           0 :     uchar o;
     185           0 :     if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     186           0 :     err = fd_bincode_bool_decode( &o, ctx );
     187           0 :     if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
     188           0 :     if( o ) {
     189           0 :       if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     190           0 :       err = fd_bincode_int64_decode_footprint( ctx );
     191           0 :       if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
     192           0 :     }
     193           0 :   }
     194           0 :   if( FD_UNLIKELY( ctx->data>=ctx->dataend ) ) { return FD_BINCODE_ERR_OVERFLOW; }
     195           0 :   err = fd_hash_decode_footprint_inner( ctx, total_sz );
     196           0 :   if( FD_UNLIKELY( err ) ) return err;
     197           0 :   return 0;
     198           0 : }
     199             : 
     200           0 : int fd_tower_sync_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
     201           0 :   *total_sz += sizeof(fd_tower_sync_t);
     202           0 :   void const * start_data = ctx->data;
     203           0 :   int err = fd_tower_sync_decode_footprint_inner( ctx, total_sz );
     204           0 :   ctx->data = start_data;
     205           0 :   return err;
     206           0 : }
     207             : 
     208           0 : void fd_tower_sync_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     209           0 :   fd_tower_sync_t * self = (fd_tower_sync_t *)struct_mem;
     210           0 :   self->has_root = 1;
     211           0 :   fd_bincode_uint64_decode_unsafe( &self->root, ctx );
     212           0 :   self->has_root = self->root != ULONG_MAX;
     213             : 
     214           0 :   ushort lockout_offsets_len;
     215           0 :   fd_bincode_compact_u16_decode_unsafe( &lockout_offsets_len, ctx );
     216           0 :   ulong lockout_offsets_max = fd_ulong_max( lockout_offsets_len, 32 );
     217           0 :   self->lockouts = deq_fd_vote_lockout_t_join_new( alloc_mem, lockout_offsets_max );
     218             : 
     219             :   /* NOTE: Agave does a a checked add on the sum of the root with all of the
     220             :      lockout offsets in their custom deserializer for tower sync votes. If the
     221             :      checked add is violated (this should never happen), the deocder will
     222             :      return NULL.  */
     223             : 
     224             :   // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L1062-L1077
     225           0 :   ulong last_slot = ((self->root == ULONG_MAX) ? 0 : self->root);
     226           0 :   for( ulong i=0; i < lockout_offsets_len; i++ ) {
     227           0 :     fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( self->lockouts );
     228             : 
     229           0 :     fd_lockout_offset_t o;
     230           0 :     fd_lockout_offset_decode_inner( &o, alloc_mem, ctx );
     231             : 
     232           0 :     elem->slot = last_slot + o.offset;
     233           0 :     elem->confirmation_count = o.confirmation_count;
     234           0 :     last_slot = elem->slot;
     235           0 :   }
     236             : 
     237           0 :   fd_hash_decode_inner( &self->hash, alloc_mem, ctx );
     238           0 :   {
     239           0 :     uchar o;
     240           0 :     fd_bincode_bool_decode_unsafe( &o, ctx );
     241           0 :     self->has_timestamp = !!o;
     242           0 :     if( o ) {
     243           0 :       fd_bincode_int64_decode_unsafe( &self->timestamp, ctx );
     244           0 :     }
     245           0 :   }
     246           0 :   fd_hash_decode_inner( &self->block_id, alloc_mem, ctx );
     247           0 : }
     248             : 
     249           0 : void * fd_tower_sync_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) {
     250           0 :   fd_tower_sync_t * self = (fd_tower_sync_t *)mem;
     251           0 :   fd_tower_sync_new( self );
     252           0 :   void * alloc_region = (uchar *)mem + sizeof(fd_tower_sync_t);
     253           0 :   void * * alloc_mem = &alloc_region;
     254           0 :   fd_tower_sync_decode_inner( mem, alloc_mem, ctx );
     255           0 :   return self;
     256           0 : }
     257             : 
     258           0 : void fd_tower_sync_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     259           0 :   FD_LOG_ERR(("TODO: Implement"));
     260           0 : }
     261             : 
     262             : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2374
     263             : //
     264             : // During the call to Duration::new(...), it normalizes the seconds and nanoseconds automatically.  We need to
     265             : // match this behavior correctly
     266             : //
     267             : void
     268           0 : fd_rust_duration_normalize ( fd_rust_duration_t * self ) {
     269           0 :   if( self->nanoseconds < 1000000000U )
     270           0 :     return;
     271           0 :   uint secs = self->nanoseconds/1000000000U;
     272           0 :   self->seconds += secs;
     273           0 :   self->nanoseconds -= secs * 1000000000U;
     274           0 : }
     275             : 
     276             : // https://github.com/serde-rs/serde/blob/49d098debdf8b5c38bfb6868f455c6ce542c422c/serde/src/de/impls.rs#L2203
     277             : //
     278             : // There is an overflow check at line 2373 that turns an overflow into an encoding error
     279             : //
     280             : int
     281           0 : fd_rust_duration_footprint_validator ( fd_bincode_decode_ctx_t * ctx ) {
     282           0 :   fd_rust_duration_t *d = (fd_rust_duration_t *) ctx->data;
     283           0 :   if( d->nanoseconds < 1000000000U )
     284           0 :     return FD_BINCODE_SUCCESS;
     285           0 :   ulong out;
     286           0 :   if( __builtin_uaddl_overflow( d->seconds, d->nanoseconds/1000000000U, &out ) )
     287           0 :     return FD_BINCODE_ERR_ENCODING;
     288           0 :   return FD_BINCODE_SUCCESS;
     289           0 : }
     290             : 
     291             : int
     292           0 : fd_gossip_duplicate_shred_validator ( fd_bincode_decode_ctx_t * ctx ) {
     293             :   // Temporarily disable this till we understand better
     294             : #if 0
     295             :   fd_gossip_duplicate_shred_t *d = (fd_gossip_duplicate_shred_t *) ctx->data;
     296             :   if( FD_UNLIKELY( (d->_unused_shred_type != 0x5a) || (d->_unused_shred_type != 0xa5) ) )
     297             :     return FD_BINCODE_ERR_ENCODING;
     298             : #else
     299           0 :   (void) ctx;
     300           0 : #endif
     301           0 :   return FD_BINCODE_SUCCESS;
     302           0 : }
     303             : 
     304           0 : void fd_vote_accounts_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     305           0 :   fd_vote_accounts_t * self = (fd_vote_accounts_t *)struct_mem;
     306           0 :   ulong vote_accounts_len;
     307           0 :   fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
     308           0 :   self->vote_accounts_pool = fd_vote_accounts_pair_t_map_join_new( alloc_mem, fd_ulong_max( vote_accounts_len, 50000 ) );
     309           0 :   self->vote_accounts_root = NULL;
     310           0 :   for( ulong i=0; i < vote_accounts_len; i++ ) {
     311           0 :     fd_vote_accounts_pair_t_mapnode_t * node = fd_vote_accounts_pair_t_map_acquire( self->vote_accounts_pool );
     312           0 :     fd_vote_accounts_pair_new( &node->elem );
     313           0 :     fd_vote_accounts_pair_decode_inner( &node->elem, alloc_mem, ctx );
     314             :     // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L323
     315             :     // throws an error and
     316           0 :     if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     317             :       // https://github.com/firedancer-io/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/vote/src/vote_account.rs#L429
     318             :       // causes the entry to not get added
     319           0 :       fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, node );
     320           0 :     } else {
     321           0 :       fd_vote_accounts_pair_t_mapnode_t * out = NULL;
     322           0 :       fd_vote_accounts_pair_t_map_insert_or_replace( self->vote_accounts_pool, &self->vote_accounts_root, node, &out );
     323           0 :       if( !!out ) {
     324           0 :         fd_vote_accounts_pair_t_map_release( self->vote_accounts_pool, out );
     325           0 :       }
     326           0 :     }
     327           0 :   }
     328           0 : }
     329             : 
     330           6 : void fd_vote_accounts_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
     331           6 :   fd_vote_accounts_global_t * self = (fd_vote_accounts_global_t *)struct_mem;
     332           6 :   ulong vote_accounts_len;
     333           6 :   fd_bincode_uint64_decode_unsafe( &vote_accounts_len, ctx );
     334           6 :   *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, fd_vote_accounts_pair_global_t_map_align() );
     335           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 ) );
     336           6 :   fd_vote_accounts_pair_global_t_mapnode_t * vote_accounts_root = NULL;
     337           6 :   for( ulong i=0; i < vote_accounts_len; i++ ) {
     338           0 :     fd_vote_accounts_pair_global_t_mapnode_t * node = fd_vote_accounts_pair_global_t_map_acquire( vote_accounts_pool );
     339           0 :     fd_vote_accounts_pair_new( (fd_vote_accounts_pair_t *)fd_type_pun(&node->elem) );
     340           0 :     fd_vote_accounts_pair_decode_inner_global( &node->elem, alloc_mem, ctx );
     341           0 :     if( FD_UNLIKELY( 0!=memcmp( node->elem.value.owner.key, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
     342           0 :       fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, node );
     343           0 :     } else {
     344           0 :       fd_vote_accounts_pair_global_t_mapnode_t * out = NULL;
     345           0 :       fd_vote_accounts_pair_global_t_map_insert_or_replace( vote_accounts_pool, &vote_accounts_root, node, &out );
     346           0 :       if( !!out ) {
     347           0 :         fd_vote_accounts_pair_global_t_map_release( vote_accounts_pool, out );
     348           0 :       }
     349           0 :     }
     350           0 :   }
     351           6 :   self->vote_accounts_pool_offset = (ulong)fd_vote_accounts_pair_global_t_map_leave( vote_accounts_pool ) - (ulong)struct_mem;
     352           6 :   self->vote_accounts_root_offset = (ulong)vote_accounts_root - (ulong)struct_mem;
     353           6 : }

Generated by: LCOV version 1.14