LCOV - code coverage report
Current view: top level - flamenco/alpenglow - fd_block_marker_serde.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 358 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 17 0.0 %

          Line data    Source code
       1             : #include "fd_block_marker_serde.h"
       2             : 
       3             : #include "../../ballet/txn/fd_compact_u16.h"
       4             : 
       5           0 : #define FAIL( cond, err ) do { if( FD_UNLIKELY( cond ) ) return FD_BLOCK_MARKER_DE_ERR_##err; } while( 0 )
       6             : 
       7             : /* BlockComponent:       https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L486-L488
       8             :    VersionedBlockMarker: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L435-L438
       9             :    LengthPrefixed:       https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L172-L175 */
      10             : 
      11             : struct marker_serde {
      12             :   ulong         entry_cnt; /* BlockComponent::BlockMarker            (u64, always 0) */
      13             :   ushort        version;   /* VersionedBlockMarker::V1               (u16 tag)       */
      14             :   uchar         tag;       /* BlockMarkerV1                          (u8 tag)        */
      15             :   ushort        length;    /* LengthPrefixed<VersionedBlock*>::len   (u16)           */
      16             :   uchar const * payload;   /* LengthPrefixed<VersionedBlock*>::inner (length bytes)  */
      17             : };
      18             : typedef struct marker_serde marker_serde_t;
      19             : 
      20             : /* VersionedBlockHeader: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L364-L367
      21             :    BlockHeaderV1:        https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L251-L254 */
      22             : 
      23             : struct header_serde {
      24             :   uchar         version;         /* VersionedBlockHeader::V1       (u8 tag, #[wincode(tag = 1)]) */
      25             :   ulong         parent_slot;     /* BlockHeaderV1::parent_slot     (Slot)                        */
      26             :   uchar const * parent_block_id; /* BlockHeaderV1::parent_block_id (Hash)                        */
      27             : };
      28             : typedef struct header_serde header_serde_t;
      29             : 
      30             : /* VersionedUpdateParent: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L371-L374
      31             :    UpdateParentV1:        https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L257-L260 */
      32             : 
      33             : struct update_parent_serde {
      34             :   uchar         version;             /* VersionedUpdateParent::V1           (u8 tag, #[wincode(tag = 1)]) */
      35             :   ulong         new_parent_slot;     /* UpdateParentV1::new_parent_slot     (Slot)                        */
      36             :   uchar const * new_parent_block_id; /* UpdateParentV1::new_parent_block_id (Hash)                        */
      37             : };
      38             : typedef struct update_parent_serde update_parent_serde_t;
      39             : 
      40             : /* solana_signer_store base2 bitmap: one byte version tag, u16 bit count,
      41             :    then the bits packed LSB first, bit i naming rank i.  Only base2 goes
      42             :    in a footer; base3 pairs are a votor wire shape (ag_bls_serde.h). */
      43             : 
      44             : struct bitmap_serde {
      45             :   uchar         version;    /* solana_signer_store::Version  (u8 tag), base2 */
      46             :   ushort        bit_cnt;    /* solana_signer_store::num_bits (u16)           */
      47             :   uchar const * payload;    /* solana_signer_store::data_bytes               */
      48             :   ulong         payload_sz; /* bit_cnt rounded up to a byte                  */
      49             : };
      50             : typedef struct bitmap_serde bitmap_serde_t;
      51             : 
      52             : /* VotesAggregate: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L324-L328
      53             :    Not the wire framing in ag_cert_serde.h: the signature is compressed
      54             :    and the bitmap sits under a u16 byte count rather than a u64. */
      55             : 
      56             : struct votes_aggregate_serde {
      57             :   uchar const * signature; /* VotesAggregate::signature  (BLSSignatureCompressed)         */
      58             :   ushort        bitmap_sz; /* VotesAggregate::bitmap len (FixIntLen<u16>)                 */
      59             :   uchar const * bitmap;    /* VotesAggregate::bitmap     (WincodeVec<u8, FixIntLen<u16>>) */
      60             : };
      61             : typedef struct votes_aggregate_serde votes_aggregate_serde_t;
      62             : 
      63             : /* BlockFinalizationCert: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L299-L304 */
      64             : 
      65             : struct final_cert_serde {
      66             :   ulong         slot;                /* BlockFinalizationCert::slot            (Slot)                             */
      67             :   uchar const * block_id;            /* BlockFinalizationCert::block_id        (Hash)                             */
      68             :   uchar const * final_aggregate;     /* BlockFinalizationCert::final_aggregate (VotesAggregate)                   */
      69             :   uchar         has_notar_aggregate; /* BlockFinalizationCert::notar_aggregate (Option<VotesAggregate> tag)       */
      70             :   uchar const * notar_aggregate;     /* BlockFinalizationCert::notar_aggregate (VotesAggregate, NULL when absent) */
      71             : };
      72             : typedef struct final_cert_serde final_cert_serde_t;
      73             : 
      74             : /* SkipRewardCertificate: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/votor-messages/src/reward_certificate.rs#L34-L42
      75             :    The bitmap byte count is a ShortU16, not the aggregate's u16. */
      76             : 
      77             : struct skip_reward_cert_serde {
      78             :   ulong         slot;      /* SkipRewardCertificate::slot       (Slot)                     */
      79             :   uchar const * signature; /* SkipRewardCertificate::signature  (BLSSignatureCompressed)   */
      80             :   ushort        bitmap_sz; /* SkipRewardCertificate::bitmap len (ShortU16)                 */
      81             :   uchar const * bitmap;    /* SkipRewardCertificate::bitmap     (WincodeVec<u8, ShortU16>) */
      82             : };
      83             : typedef struct skip_reward_cert_serde skip_reward_cert_serde_t;
      84             : 
      85             : /* NotarRewardCertificate: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/votor-messages/src/reward_certificate.rs#L75-L85 */
      86             : 
      87             : struct notar_reward_cert_serde {
      88             :   ulong         slot;      /* NotarRewardCertificate::slot       (Slot)                     */
      89             :   uchar const * block_id;  /* NotarRewardCertificate::block_id   (Hash)                     */
      90             :   uchar const * signature; /* NotarRewardCertificate::signature  (BLSSignatureCompressed)   */
      91             :   ushort        bitmap_sz; /* NotarRewardCertificate::bitmap len (ShortU16)                 */
      92             :   uchar const * bitmap;    /* NotarRewardCertificate::bitmap     (WincodeVec<u8, ShortU16>) */
      93             : };
      94             : typedef struct notar_reward_cert_serde notar_reward_cert_serde_t;
      95             : 
      96             : /* VersionedBlockFooter: https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L357-L360
      97             :    BlockFooterV1:        https://github.com/anza-xyz/agave/blob/v4.3.0-beta.0/entry/src/block_component.rs#L240-L248
      98             :    Each Option is a one byte tag immediately followed by its own body
      99             :    when present, so a cert's length shifts the next tag. */
     100             : 
     101             : struct footer_serde {
     102             :   uchar         version;                   /* VersionedBlockFooter::V1                 (u8 tag, #[wincode(tag = 1)])        */
     103             :   uchar const * bank_hash;                 /* BlockFooterV1::bank_hash                 (Hash)                               */
     104             :   ulong         block_producer_time_nanos; /* BlockFooterV1::block_producer_time_nanos (u64)                                */
     105             :   uchar         user_agent_len;            /* BlockFooterV1::block_user_agent len      (FixIntLen<u8>)                      */
     106             :   uchar const * user_agent;                /* BlockFooterV1::block_user_agent          (WincodeVec<u8, FixIntLen<u8>>)      */
     107             :   uchar         has_block_final_cert;      /* BlockFooterV1::block_final_cert          (Option<BlockFinalizationCert> tag)  */
     108             :   uchar const * block_final_cert;          /* BlockFooterV1::block_final_cert          (BlockFinalizationCert)              */
     109             :   uchar         has_skip_reward_cert;      /* BlockFooterV1::skip_reward_cert          (Option<SkipRewardCertificate> tag)  */
     110             :   uchar const * skip_reward_cert;          /* BlockFooterV1::skip_reward_cert          (SkipRewardCertificate)              */
     111             :   uchar         has_notar_reward_cert;     /* BlockFooterV1::notar_reward_cert         (Option<NotarRewardCertificate> tag) */
     112             :   uchar const * notar_reward_cert;         /* BlockFooterV1::notar_reward_cert         (NotarRewardCertificate)             */
     113             : };
     114             : typedef struct footer_serde footer_serde_t;
     115             : 
     116             : static ulong
     117             : header_ser( fd_block_header_t const * header,
     118           0 :             uchar *                   buf ) {
     119           0 :   header_serde_t hdr;
     120             : 
     121           0 :   hdr.version         = (uchar)1;
     122           0 :   hdr.parent_slot     = header->parent_slot;
     123           0 :   hdr.parent_block_id = header->parent_block_id.uc;
     124             : 
     125           0 :   ulong off = 0UL;
     126           0 :   buf[ off ] = hdr.version;                                  off += sizeof(uchar);
     127           0 :   FD_STORE( ulong, buf+off, hdr.parent_slot );               off += sizeof(ulong);
     128           0 :   memcpy( buf+off, hdr.parent_block_id, sizeof(fd_hash_t) ); off += sizeof(fd_hash_t);
     129             : 
     130           0 :   return off;
     131           0 : }
     132             : 
     133             : /* bitmap_ser writes the base2 bitmap naming the ranks in signer_set,
     134             :    exactly nbits wide: a footer cert re-emits the width it carries, so
     135             :    one that came off the wire goes back out byte for byte.  Returns the
     136             :    bytes written, or 0UL if nbits passes AG_VAT_MAX (which sizes
     137             :    FD_BLOCK_FOOTER_SER_MAX) or a rank sits at or past nbits. */
     138             : 
     139             : static ulong
     140             : bitmap_ser( ulong                nbits,
     141             :             fd_bls_set_t const * signer_set,
     142           0 :             uchar *              buf ) {
     143           0 :   ulong bits = fd_ulong_min( FD_BLS_SET_MAX, fd_bls_set_last( signer_set )+1UL ); /* one past the highest rank, 0 when empty */
     144           0 :   if( FD_UNLIKELY( nbits>AG_VAT_MAX || bits>nbits ) ) return 0UL;
     145             : 
     146           0 :   bitmap_serde_t bm;
     147             : 
     148           0 :   bm.version    = (uchar)0; /* base2 */
     149           0 :   bm.bit_cnt    = (ushort)nbits;
     150           0 :   bm.payload    = NULL; /* written straight into buf below */
     151           0 :   bm.payload_sz = FD_BLOCK_BITMAP_SER_SZ( nbits )-FD_BLOCK_BITMAP_SER_HDR_SZ;
     152             : 
     153           0 :   ulong off = 0UL;
     154           0 :   buf[ off ] = bm.version;                 off += sizeof(uchar);
     155           0 :   FD_STORE( ushort, buf+off, bm.bit_cnt ); off += sizeof(ushort);
     156           0 :   fd_memset( buf+off, 0, bm.payload_sz );
     157           0 :   for( ulong i=0UL; i<bits; i++ ) {
     158           0 :     if( fd_bls_set_test( signer_set, i ) ) buf[ off+(i>>3) ] |= (uchar)( 1U << (i&7U) );
     159           0 :   }
     160           0 :                                            off += bm.payload_sz;
     161           0 :   return off;
     162           0 : }
     163             : 
     164             : static ulong
     165             : votes_aggregate_ser( fd_block_footer_cert_t const * cert,
     166           0 :                      uchar *                        buf ) {
     167           0 :   votes_aggregate_serde_t aggregate;
     168             : 
     169           0 :   aggregate.signature = cert->sig; /* already compressed */
     170           0 :   aggregate.bitmap_sz = (ushort)FD_BLOCK_BITMAP_SER_SZ( cert->nbits );
     171           0 :   aggregate.bitmap    = NULL; /* written straight into buf by bitmap_ser below */
     172             : 
     173           0 :   ulong off = 0UL;
     174           0 :   ulong sz;
     175           0 :   memcpy( buf+off, aggregate.signature, FD_BLS_SIG_COMPRESSED_SZ );                     off += FD_BLS_SIG_COMPRESSED_SZ;
     176           0 :   FD_STORE( ushort, buf+off, aggregate.bitmap_sz );                                     off += sizeof(ushort);
     177           0 :   if( FD_UNLIKELY( !(sz=bitmap_ser( cert->nbits, cert->signer_set, buf+off )) ) ) return 0UL;
     178           0 :                                                                                         off += sz;
     179           0 :   return off;
     180           0 : }
     181             : 
     182             : static ulong
     183             : final_cert_ser( fd_block_footer_t const * footer,
     184           0 :                 uchar *                   buf ) {
     185           0 :   int is_fast = footer->has_fast_final_cert;
     186             :   /* one block_id goes on the wire, so the two certs of a slow
     187             :      finalization must name one slot */
     188           0 :   if( FD_UNLIKELY( !is_fast && footer->final_cert.slot!=footer->notar_cert.slot ) ) return 0UL;
     189             : 
     190           0 :   final_cert_serde_t cert;
     191             : 
     192           0 :   cert.slot                = is_fast ? footer->fast_final_cert.slot        : footer->final_cert.slot;
     193           0 :   cert.block_id            = is_fast ? footer->fast_final_cert.block_id.uc : footer->notar_cert.block_id.uc;
     194           0 :   cert.final_aggregate     = NULL; /* written straight into buf by votes_aggregate_ser below */
     195           0 :   cert.has_notar_aggregate = (uchar)!is_fast;
     196           0 :   cert.notar_aggregate     = NULL;
     197             : 
     198           0 :   ulong off = 0UL;
     199           0 :   ulong sz;
     200           0 :   FD_STORE( ulong, buf+off, cert.slot );                                                                          off += sizeof(ulong);
     201           0 :   memcpy( buf+off, cert.block_id, sizeof(fd_hash_t) );                                                            off += sizeof(fd_hash_t);
     202           0 :   if( FD_UNLIKELY( !(sz=votes_aggregate_ser( is_fast ? &footer->fast_final_cert : &footer->final_cert, buf+off )) ) ) return 0UL;
     203           0 :                                                                                                                   off += sz;
     204           0 :   buf[ off ] = cert.has_notar_aggregate;                                                                          off += sizeof(uchar);
     205           0 :   if( cert.has_notar_aggregate ) {
     206           0 :     if( FD_UNLIKELY( !(sz=votes_aggregate_ser( &footer->notar_cert, buf+off )) ) ) return 0UL;
     207           0 :                                                                                                                   off += sz;
     208           0 :   }
     209           0 :   return off;
     210           0 : }
     211             : 
     212             : static ulong
     213             : skip_reward_cert_ser( fd_block_footer_cert_t const * cert,
     214           0 :                       uchar *                        buf ) {
     215           0 :   skip_reward_cert_serde_t reward;
     216             : 
     217           0 :   reward.slot      = cert->slot;
     218           0 :   reward.signature = cert->sig; /* already compressed */
     219           0 :   reward.bitmap_sz = (ushort)FD_BLOCK_BITMAP_SER_SZ( cert->nbits );
     220           0 :   reward.bitmap    = NULL; /* written straight into buf by bitmap_ser below */
     221             : 
     222           0 :   ulong off = 0UL;
     223           0 :   ulong sz;
     224           0 :   FD_STORE( ulong, buf+off, reward.slot );                                              off += sizeof(ulong);
     225           0 :   memcpy( buf+off, reward.signature, FD_BLS_SIG_COMPRESSED_SZ );                        off += FD_BLS_SIG_COMPRESSED_SZ;
     226           0 :                                                                                         off += fd_cu16_enc( reward.bitmap_sz, buf+off );
     227           0 :   if( FD_UNLIKELY( !(sz=bitmap_ser( cert->nbits, cert->signer_set, buf+off )) ) ) return 0UL;
     228           0 :                                                                                         off += sz;
     229           0 :   return off;
     230           0 : }
     231             : 
     232             : static ulong
     233             : notar_reward_cert_ser( fd_block_footer_cert_t const * cert,
     234           0 :                        uchar *                        buf ) {
     235           0 :   notar_reward_cert_serde_t reward;
     236             : 
     237           0 :   reward.slot      = cert->slot;
     238           0 :   reward.block_id  = cert->block_id.uc;
     239           0 :   reward.signature = cert->sig; /* already compressed */
     240           0 :   reward.bitmap_sz = (ushort)FD_BLOCK_BITMAP_SER_SZ( cert->nbits );
     241           0 :   reward.bitmap    = NULL; /* written straight into buf by bitmap_ser below */
     242             : 
     243           0 :   ulong off = 0UL;
     244           0 :   ulong sz;
     245           0 :   FD_STORE( ulong, buf+off, reward.slot );                                              off += sizeof(ulong);
     246           0 :   memcpy( buf+off, reward.block_id, sizeof(fd_hash_t) );                                off += sizeof(fd_hash_t);
     247           0 :   memcpy( buf+off, reward.signature, FD_BLS_SIG_COMPRESSED_SZ );                        off += FD_BLS_SIG_COMPRESSED_SZ;
     248           0 :                                                                                         off += fd_cu16_enc( reward.bitmap_sz, buf+off );
     249           0 :   if( FD_UNLIKELY( !(sz=bitmap_ser( cert->nbits, cert->signer_set, buf+off )) ) ) return 0UL;
     250           0 :                                                                                         off += sz;
     251           0 :   return off;
     252           0 : }
     253             : 
     254             : static ulong
     255             : footer_ser( fd_block_footer_t const * footer,
     256           0 :             uchar *                   buf ) {
     257           0 :   if( FD_UNLIKELY( footer->has_fast_final_cert && footer->has_final_cert ) ) return 0UL; /* one finalization shape or the other */
     258           0 :   if( FD_UNLIKELY( footer->user_agent_len>FD_BLOCK_FOOTER_USER_AGENT_MAX ) ) return 0UL;
     259             : 
     260           0 :   footer_serde_t ftr;
     261             : 
     262           0 :   ftr.version                   = (uchar)1;
     263           0 :   ftr.bank_hash                 = footer->bank_hash.uc;
     264           0 :   ftr.block_producer_time_nanos = footer->block_producer_time_nanos;
     265           0 :   ftr.user_agent_len            = (uchar)footer->user_agent_len;
     266           0 :   ftr.user_agent                = footer->user_agent;
     267           0 :   ftr.has_block_final_cert      = (uchar)( footer->has_fast_final_cert || footer->has_final_cert );
     268           0 :   ftr.block_final_cert          = NULL; /* the three cert bodies are written straight into buf below */
     269           0 :   ftr.has_skip_reward_cert      = (uchar)!!footer->has_skip_reward_cert;
     270           0 :   ftr.skip_reward_cert          = NULL;
     271           0 :   ftr.has_notar_reward_cert     = (uchar)!!footer->has_notar_reward_cert;
     272           0 :   ftr.notar_reward_cert         = NULL;
     273             : 
     274           0 :   ulong off = 0UL;
     275           0 :   ulong sz;
     276           0 :   buf[ off ] = ftr.version;                                                                          off += sizeof(uchar);
     277           0 :   memcpy( buf+off, ftr.bank_hash, sizeof(fd_hash_t) );                                               off += sizeof(fd_hash_t);
     278           0 :   FD_STORE( ulong, buf+off, ftr.block_producer_time_nanos );                                         off += sizeof(ulong);
     279           0 :   buf[ off ] = ftr.user_agent_len;                                                                   off += sizeof(uchar);
     280           0 :   memcpy( buf+off, ftr.user_agent, ftr.user_agent_len );                                             off += ftr.user_agent_len;
     281           0 :   buf[ off ] = ftr.has_block_final_cert;                                                             off += sizeof(uchar);
     282           0 :   if( ftr.has_block_final_cert ) {
     283           0 :     if( FD_UNLIKELY( !(sz=final_cert_ser( footer, buf+off )) ) ) return 0UL;
     284           0 :                                                                                                      off += sz;
     285           0 :   }
     286           0 :   buf[ off ] = ftr.has_skip_reward_cert;                                                             off += sizeof(uchar);
     287           0 :   if( ftr.has_skip_reward_cert ) {
     288           0 :     if( FD_UNLIKELY( !(sz=skip_reward_cert_ser( &footer->skip_reward_cert, buf+off )) ) ) return 0UL;
     289           0 :                                                                                                      off += sz;
     290           0 :   }
     291           0 :   buf[ off ] = ftr.has_notar_reward_cert;                                                            off += sizeof(uchar);
     292           0 :   if( ftr.has_notar_reward_cert ) {
     293           0 :     if( FD_UNLIKELY( !(sz=notar_reward_cert_ser( &footer->notar_reward_cert, buf+off )) ) ) return 0UL;
     294           0 :                                                                                                      off += sz;
     295           0 :   }
     296             : 
     297           0 :   return off;
     298           0 : }
     299             : 
     300             : ulong
     301             : fd_block_marker_ser( fd_block_marker_t const * self,
     302           0 :                      uchar                     buf[ static FD_BLOCK_MARKER_SER_MAX ] ) {
     303           0 :   uchar * payload = buf+FD_BLOCK_MARKER_PREAMBLE_SZ;
     304           0 :   ulong   payload_sz;
     305           0 :   switch( self->kind ) {
     306           0 :   case FD_BLOCK_MARKER_KIND_FOOTER: payload_sz = footer_ser( &self->footer, payload ); break;
     307           0 :   case FD_BLOCK_MARKER_KIND_HEADER: payload_sz = header_ser( &self->header, payload ); break;
     308           0 :   default:                          return 0UL; /* nothing we produce is an UpdateParent or GenesisCertificate */
     309           0 :   }
     310           0 :   if( FD_UNLIKELY( !payload_sz ) ) return 0UL;
     311             : 
     312           0 :   marker_serde_t marker;
     313             : 
     314           0 :   marker.entry_cnt = 0UL;
     315           0 :   marker.version   = (ushort)1;
     316           0 :   marker.tag       = (uchar)self->kind;
     317           0 :   marker.length    = (ushort)payload_sz;
     318           0 :   marker.payload   = payload; /* already in place */
     319             : 
     320           0 :   ulong off = 0UL;
     321           0 :   FD_STORE( ulong,  buf+off, marker.entry_cnt ); off += sizeof(ulong);
     322           0 :   FD_STORE( ushort, buf+off, marker.version );   off += sizeof(ushort);
     323           0 :   buf[ off ] = marker.tag;                       off += sizeof(uchar);
     324           0 :   FD_STORE( ushort, buf+off, marker.length );    off += sizeof(ushort);
     325           0 :                                                  off += payload_sz;
     326             : 
     327           0 :   return off;
     328           0 : }
     329             : 
     330             : static int
     331             : header_de( fd_block_header_t * header,
     332             :            uchar const *       buf,
     333             :            ulong               buf_sz,
     334           0 :            ulong *             sz ) {
     335           0 :   FAIL( buf_sz<FD_BLOCK_HEADER_SER_SZ, SZ );
     336             : 
     337           0 :   header_serde_t hdr; ulong off = 0UL;
     338           0 :   hdr.version         = buf[ off ];                off += sizeof(uchar);
     339           0 :   FAIL( hdr.version!=1, INVAL ); /* VersionedBlockHeader has only V1 */
     340           0 :   hdr.parent_slot     = FD_LOAD( ulong, buf+off ); off += sizeof(ulong);
     341           0 :   hdr.parent_block_id = buf+off;                   off += sizeof(fd_hash_t);
     342             : 
     343           0 :   header->parent_slot = hdr.parent_slot;
     344           0 :   memcpy( header->parent_block_id.uc, hdr.parent_block_id, sizeof(fd_hash_t) );
     345             : 
     346           0 :   *sz = off;
     347           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     348           0 : }
     349             : 
     350             : static int
     351             : update_parent_de( fd_update_parent_t * update_parent,
     352             :                   uchar const *        buf,
     353             :                   ulong                buf_sz,
     354           0 :                   ulong *              sz ) {
     355           0 :   FAIL( buf_sz<FD_UPDATE_PARENT_SER_SZ, SZ );
     356             : 
     357           0 :   update_parent_serde_t upd; ulong off = 0UL;
     358           0 :   upd.version             = buf[ off ];                off += sizeof(uchar);
     359           0 :   FAIL( upd.version!=1, INVAL ); /* VersionedUpdateParent has only V1 */
     360           0 :   upd.new_parent_slot     = FD_LOAD( ulong, buf+off ); off += sizeof(ulong);
     361           0 :   upd.new_parent_block_id = buf+off;                   off += sizeof(fd_hash_t);
     362             : 
     363           0 :   update_parent->new_parent_slot = upd.new_parent_slot;
     364           0 :   memcpy( update_parent->new_parent_block_id.uc, upd.new_parent_block_id, sizeof(fd_hash_t) );
     365             : 
     366           0 :   *sz = off;
     367           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     368           0 : }
     369             : 
     370             : /* bitmap_de decodes the base2 bitmap at b into nbits and signer_set,
     371             :    checking the version, the width against FD_BLS_SET_MAX and the
     372             :    payload length against the width.  The width is kept verbatim, so a
     373             :    cert re-encodes at the width it came with. */
     374             : 
     375             : static int
     376             : bitmap_de( ushort *       nbits,
     377             :            fd_bls_set_t * signer_set,
     378             :            uchar const *  b,
     379           0 :            ulong          b_sz ) {
     380           0 :   FAIL( b_sz<FD_BLOCK_BITMAP_SER_HDR_SZ, SZ );
     381             : 
     382           0 :   bitmap_serde_t bm; ulong off = 0UL;
     383           0 :   bm.version    = b[ off ];                 off += sizeof(uchar);
     384           0 :   FAIL( bm.version!=0, INVAL ); /* base2 only */
     385           0 :   bm.bit_cnt    = FD_LOAD( ushort, b+off ); off += sizeof(ushort);
     386           0 :   FAIL( (ulong)bm.bit_cnt>FD_BLS_SET_MAX, SZ );
     387           0 :   bm.payload    = b+off;
     388           0 :   bm.payload_sz = b_sz-off;
     389           0 :   FAIL( bm.payload_sz!=FD_BLOCK_BITMAP_SER_SZ( bm.bit_cnt )-FD_BLOCK_BITMAP_SER_HDR_SZ, INVAL );
     390             : 
     391           0 :   fd_bls_set_null( signer_set );
     392           0 :   for( ulong i=0UL; i<(ulong)bm.bit_cnt; i++ ) {
     393           0 :     if( (bm.payload[ i>>3 ] >> (i&7U)) & 1U ) fd_bls_set_insert( signer_set, i );
     394           0 :   }
     395           0 :   *nbits = bm.bit_cnt;
     396           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     397           0 : }
     398             : 
     399             : static int
     400             : votes_aggregate_de( fd_block_footer_cert_t * cert,
     401             :                     uchar const *            buf,
     402             :                     ulong                    buf_sz,
     403           0 :                     ulong *                  sz ) {
     404           0 :   FAIL( buf_sz<FD_BLOCK_VOTES_AGGREGATE_SER_HDR_SZ, SZ );
     405             : 
     406           0 :   votes_aggregate_serde_t aggregate; ulong off = 0UL;
     407           0 :   aggregate.signature = buf+off;                    off += FD_BLS_SIG_COMPRESSED_SZ;
     408           0 :   aggregate.bitmap_sz = FD_LOAD( ushort, buf+off ); off += sizeof(ushort);
     409           0 :   FAIL( (ulong)aggregate.bitmap_sz>buf_sz-off, SZ );
     410           0 :   aggregate.bitmap    = buf+off;                    off += aggregate.bitmap_sz;
     411             : 
     412           0 :   int err = bitmap_de( &cert->nbits, cert->signer_set, aggregate.bitmap, aggregate.bitmap_sz );
     413           0 :   if( FD_UNLIKELY( err ) ) return err;
     414           0 :   memcpy( cert->sig, aggregate.signature, FD_BLS_SIG_COMPRESSED_SZ ); /* stays compressed for votor */
     415             : 
     416           0 :   *sz = off;
     417           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     418           0 : }
     419             : 
     420             : static int
     421             : final_cert_de( fd_block_footer_t * footer,
     422             :                uchar const *       buf,
     423             :                ulong               buf_sz,
     424           0 :                ulong *             sz ) {
     425           0 :   FAIL( buf_sz<FD_BLOCK_FINAL_CERT_SER_HDR_SZ, SZ );
     426             : 
     427           0 :   final_cert_serde_t cert; ulong off = 0UL;
     428           0 :   cert.slot            = FD_LOAD( ulong, buf+off ); off += sizeof(ulong);
     429           0 :   cert.block_id        = buf+off;                   off += sizeof(fd_hash_t);
     430           0 :   cert.final_aggregate = buf+off;
     431             : 
     432             :   /* zeroed so final_cert.block_id stays zero on the slow path */
     433           0 :   fd_block_footer_cert_t final_agg[1]; fd_memset( final_agg, 0, sizeof(final_agg) );
     434           0 :   ulong agg_sz;
     435           0 :   int   err = votes_aggregate_de( final_agg, cert.final_aggregate, buf_sz-off, &agg_sz );
     436           0 :   if( FD_UNLIKELY( err ) ) return err;
     437           0 :   off += agg_sz;
     438             : 
     439           0 :   FAIL( buf_sz-off<sizeof(uchar), SZ );
     440           0 :   cert.has_notar_aggregate = buf[ off ];            off += sizeof(uchar);
     441           0 :   FAIL( cert.has_notar_aggregate>1, INVAL );
     442           0 :   cert.notar_aggregate     = cert.has_notar_aggregate ? buf+off : NULL;
     443             : 
     444           0 :   if( !cert.notar_aggregate ) {
     445           0 :     footer->has_fast_final_cert  = 1;
     446           0 :     footer->fast_final_cert      = *final_agg;
     447           0 :     footer->fast_final_cert.slot = cert.slot;
     448           0 :     memcpy( footer->fast_final_cert.block_id.uc, cert.block_id, sizeof(fd_hash_t) );
     449           0 :   } else {
     450           0 :     err = votes_aggregate_de( &footer->notar_cert, cert.notar_aggregate, buf_sz-off, &agg_sz );
     451           0 :     if( FD_UNLIKELY( err ) ) return err;
     452           0 :     off += agg_sz;
     453           0 :     footer->has_final_cert  = 1;
     454           0 :     footer->final_cert      = *final_agg;
     455           0 :     footer->final_cert.slot = cert.slot;
     456           0 :     footer->notar_cert.slot = cert.slot;
     457           0 :     memcpy( footer->notar_cert.block_id.uc, cert.block_id, sizeof(fd_hash_t) );
     458           0 :   }
     459             : 
     460           0 :   *sz = off;
     461           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     462           0 : }
     463             : 
     464             : static int
     465             : skip_reward_cert_de( fd_block_footer_cert_t * cert,
     466             :                      uchar const *            buf,
     467             :                      ulong                    buf_sz,
     468           0 :                      ulong *                  sz ) {
     469           0 :   FAIL( buf_sz<FD_BLOCK_SKIP_REWARD_CERT_SER_HDR_SZ, SZ );
     470             : 
     471           0 :   skip_reward_cert_serde_t reward; ulong off = 0UL;
     472           0 :   reward.slot      = FD_LOAD( ulong, buf+off );             off += sizeof(ulong);
     473           0 :   reward.signature = buf+off;                               off += FD_BLS_SIG_COMPRESSED_SZ;
     474           0 :   FAIL( buf_sz==off, SZ ); /* no byte for the ShortU16 */
     475           0 :   ulong cu16_sz = fd_cu16_dec_sz( buf+off, buf_sz-off );
     476           0 :   FAIL( !cu16_sz, INVAL ); /* ShortU16 malformed (or a multi byte one cut short, which fd_cu16_dec_sz cannot tell apart) */
     477           0 :   reward.bitmap_sz = fd_cu16_dec_fixed( buf+off, cu16_sz ); off += cu16_sz;
     478           0 :   FAIL( (ulong)reward.bitmap_sz>buf_sz-off, SZ );
     479           0 :   reward.bitmap    = buf+off;                               off += reward.bitmap_sz;
     480             : 
     481           0 :   int err = bitmap_de( &cert->nbits, cert->signer_set, reward.bitmap, reward.bitmap_sz );
     482           0 :   if( FD_UNLIKELY( err ) ) return err;
     483           0 :   cert->slot = reward.slot; /* block_id stays zero */
     484           0 :   memcpy( cert->sig, reward.signature, FD_BLS_SIG_COMPRESSED_SZ );
     485             : 
     486           0 :   *sz = off;
     487           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     488           0 : }
     489             : 
     490             : static int
     491             : notar_reward_cert_de( fd_block_footer_cert_t * cert,
     492             :                       uchar const *            buf,
     493             :                       ulong                    buf_sz,
     494           0 :                       ulong *                  sz ) {
     495           0 :   FAIL( buf_sz<FD_BLOCK_NOTAR_REWARD_CERT_SER_HDR_SZ, SZ );
     496             : 
     497           0 :   notar_reward_cert_serde_t reward; ulong off = 0UL;
     498           0 :   reward.slot      = FD_LOAD( ulong, buf+off );             off += sizeof(ulong);
     499           0 :   reward.block_id  = buf+off;                               off += sizeof(fd_hash_t);
     500           0 :   reward.signature = buf+off;                               off += FD_BLS_SIG_COMPRESSED_SZ;
     501           0 :   FAIL( buf_sz==off, SZ ); /* no byte for the ShortU16 */
     502           0 :   ulong cu16_sz = fd_cu16_dec_sz( buf+off, buf_sz-off );
     503           0 :   FAIL( !cu16_sz, INVAL ); /* ShortU16 malformed (or a multi byte one cut short, which fd_cu16_dec_sz cannot tell apart) */
     504           0 :   reward.bitmap_sz = fd_cu16_dec_fixed( buf+off, cu16_sz ); off += cu16_sz;
     505           0 :   FAIL( (ulong)reward.bitmap_sz>buf_sz-off, SZ );
     506           0 :   reward.bitmap    = buf+off;                               off += reward.bitmap_sz;
     507             : 
     508           0 :   int err = bitmap_de( &cert->nbits, cert->signer_set, reward.bitmap, reward.bitmap_sz );
     509           0 :   if( FD_UNLIKELY( err ) ) return err;
     510           0 :   cert->slot = reward.slot;
     511           0 :   memcpy( cert->block_id.uc, reward.block_id, sizeof(fd_hash_t) );
     512           0 :   memcpy( cert->sig, reward.signature, FD_BLS_SIG_COMPRESSED_SZ );
     513             : 
     514           0 :   *sz = off;
     515           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     516           0 : }
     517             : 
     518             : static int
     519             : footer_de( fd_block_footer_t * footer,
     520             :            uchar const *       buf,
     521             :            ulong               buf_sz,
     522           0 :            ulong *             sz ) {
     523           0 :   FAIL( buf_sz<FD_BLOCK_FOOTER_SER_HDR_SZ, SZ );
     524             : 
     525           0 :   footer_serde_t ftr; ulong off = 0UL;
     526           0 :   ftr.version                   = buf[ off ];                off += sizeof(uchar);
     527           0 :   FAIL( ftr.version!=1, INVAL ); /* VersionedBlockFooter has only V1 */
     528           0 :   ftr.bank_hash                 = buf+off;                   off += sizeof(fd_hash_t);
     529           0 :   ftr.block_producer_time_nanos = FD_LOAD( ulong, buf+off ); off += sizeof(ulong);
     530           0 :   ftr.user_agent_len            = buf[ off ];                off += sizeof(uchar);
     531           0 :   FAIL( buf_sz-off<(ulong)ftr.user_agent_len, SZ );
     532           0 :   ftr.user_agent                = buf+off;                   off += ftr.user_agent_len;
     533             : 
     534           0 :   memcpy( footer->bank_hash.uc, ftr.bank_hash, sizeof(fd_hash_t) );
     535           0 :   footer->block_producer_time_nanos = ftr.block_producer_time_nanos;
     536           0 :   footer->user_agent_len            = (ulong)ftr.user_agent_len;
     537           0 :   memcpy( footer->user_agent, ftr.user_agent, ftr.user_agent_len );
     538             : 
     539           0 :   int   err;
     540           0 :   ulong part_sz;
     541             : 
     542           0 :   FAIL( buf_sz-off<sizeof(uchar), SZ );
     543           0 :   ftr.has_block_final_cert  = buf[ off ];                    off += sizeof(uchar);
     544           0 :   FAIL( ftr.has_block_final_cert>1, INVAL );
     545           0 :   ftr.block_final_cert      = ftr.has_block_final_cert ? buf+off : NULL;
     546           0 :   if( ftr.block_final_cert ) {
     547           0 :     err = final_cert_de( footer, ftr.block_final_cert, buf_sz-off, &part_sz ); /* sets has_fast_final_cert or has_final_cert itself */
     548           0 :     if( FD_UNLIKELY( err ) ) return err;
     549           0 :     off += part_sz;
     550           0 :   }
     551             : 
     552           0 :   FAIL( buf_sz-off<sizeof(uchar), SZ );
     553           0 :   ftr.has_skip_reward_cert  = buf[ off ];                    off += sizeof(uchar);
     554           0 :   FAIL( ftr.has_skip_reward_cert>1, INVAL );
     555           0 :   ftr.skip_reward_cert      = ftr.has_skip_reward_cert ? buf+off : NULL;
     556           0 :   if( ftr.skip_reward_cert ) {
     557           0 :     err = skip_reward_cert_de( &footer->skip_reward_cert, ftr.skip_reward_cert, buf_sz-off, &part_sz );
     558           0 :     if( FD_UNLIKELY( err ) ) return err;
     559           0 :     off += part_sz;
     560           0 :     footer->has_skip_reward_cert = 1;
     561           0 :   }
     562             : 
     563           0 :   FAIL( buf_sz-off<sizeof(uchar), SZ );
     564           0 :   ftr.has_notar_reward_cert = buf[ off ];                    off += sizeof(uchar);
     565           0 :   FAIL( ftr.has_notar_reward_cert>1, INVAL );
     566           0 :   ftr.notar_reward_cert     = ftr.has_notar_reward_cert ? buf+off : NULL;
     567           0 :   if( ftr.notar_reward_cert ) {
     568           0 :     err = notar_reward_cert_de( &footer->notar_reward_cert, ftr.notar_reward_cert, buf_sz-off, &part_sz );
     569           0 :     if( FD_UNLIKELY( err ) ) return err;
     570           0 :     off += part_sz;
     571           0 :     footer->has_notar_reward_cert = 1;
     572           0 :   }
     573             : 
     574           0 :   *sz = off;
     575           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     576           0 : }
     577             : 
     578             : int
     579             : fd_block_marker_de( fd_block_marker_t * self,
     580             :                     uchar const *       buf,
     581           0 :                     ulong               buf_sz ) {
     582           0 :   FAIL( buf_sz<FD_BLOCK_MARKER_PREAMBLE_SZ, SZ );
     583             : 
     584           0 :   marker_serde_t marker; ulong off = 0UL;
     585           0 :   marker.entry_cnt = FD_LOAD( ulong,  buf+off ); off += sizeof(ulong);
     586           0 :   marker.version   = FD_LOAD( ushort, buf+off ); off += sizeof(ushort);
     587           0 :   marker.tag       = buf[ off ];                 off += sizeof(uchar);
     588           0 :   marker.length    = FD_LOAD( ushort, buf+off ); off += sizeof(ushort);
     589           0 :   FAIL( marker.entry_cnt!=0UL, INVAL ); /* an entry batch, not a marker */
     590           0 :   FAIL( marker.version!=1,     INVAL ); /* VersionedBlockMarker has only V1 */
     591           0 :   FAIL( (ulong)marker.length>buf_sz-off, SZ );
     592           0 :   marker.payload   = buf+off;
     593             : 
     594           0 :   fd_memset( self, 0, sizeof(fd_block_marker_t) );
     595           0 :   self->kind = (uint)marker.tag;
     596             : 
     597           0 :   int   err;
     598           0 :   ulong payload_sz;
     599           0 :   switch( self->kind ) {
     600           0 :   case FD_BLOCK_MARKER_KIND_FOOTER:        err = footer_de       ( &self->footer,        marker.payload, marker.length, &payload_sz ); break;
     601           0 :   case FD_BLOCK_MARKER_KIND_HEADER:        err = header_de       ( &self->header,        marker.payload, marker.length, &payload_sz ); break;
     602           0 :   case FD_BLOCK_MARKER_KIND_UPDATE_PARENT: err = update_parent_de( &self->update_parent, marker.payload, marker.length, &payload_sz ); break;
     603           0 :   case FD_BLOCK_MARKER_KIND_GENESIS_CERT:  return FD_BLOCK_MARKER_DE_ERR_UNSUPPORTED;
     604           0 :   default:                                 return FD_BLOCK_MARKER_DE_ERR_INVAL;
     605           0 :   }
     606           0 :   if( FD_UNLIKELY( err ) ) return err;
     607           0 :   FAIL( payload_sz!=(ulong)marker.length, SZ ); /* LengthPrefixed::len is exact */
     608             : 
     609           0 :   return FD_BLOCK_MARKER_DE_SUCCESS;
     610           0 : }

Generated by: LCOV version 1.14