LCOV - code coverage report
Current view: top level - discof/repair - fd_repair.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 145 224 64.7 %
Date: 2026-09-17 04:28:31 Functions: 11 17 64.7 %

          Line data    Source code
       1             : #include "fd_repair.h"
       2             : #include "../../ballet/sha256/fd_sha256.h"
       3             : #include "../../ballet/bmtree/fd_bmtree.h"
       4             : 
       5             : void *
       6          45 : fd_repair_new( void * shmem, fd_pubkey_t * identity_key ) {
       7             : 
       8          45 :   if( FD_UNLIKELY( !shmem ) ) {
       9           0 :     FD_LOG_WARNING(( "NULL mem" ));
      10           0 :     return NULL;
      11           0 :   }
      12             : 
      13          45 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_repair_align() ) ) ) {
      14           0 :     FD_LOG_WARNING(( "misaligned mem" ));
      15           0 :     return NULL;
      16           0 :   }
      17             : 
      18          45 :   ulong footprint = fd_repair_footprint();
      19          45 :   fd_memset( shmem, 0, footprint );
      20             : 
      21          45 :   fd_repair_t * repair = (fd_repair_t *)shmem;
      22          45 :   repair->identity_key = *identity_key;
      23             : 
      24          45 :   return shmem;
      25          45 : }
      26             : 
      27             : fd_repair_t *
      28          45 : fd_repair_join( void * shrepair ) {
      29          45 :   fd_repair_t * repair = (fd_repair_t *)shrepair;
      30             : 
      31          45 :   if( FD_UNLIKELY( !repair ) ) {
      32           0 :     FD_LOG_WARNING(( "NULL repair" ));
      33           0 :     return NULL;
      34           0 :   }
      35             : 
      36          45 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)repair, fd_repair_align() ) ) ) {
      37           0 :     FD_LOG_WARNING(( "misaligned repair" ));
      38           0 :     return NULL;
      39           0 :   }
      40             : 
      41          45 :   fd_wksp_t * wksp = fd_wksp_containing( repair );
      42          45 :   if( FD_UNLIKELY( !wksp ) ) {
      43           0 :     FD_LOG_WARNING(( "repair must be part of a workspace" ));
      44           0 :     return NULL;
      45           0 :   }
      46             : 
      47          45 :   return repair;
      48          45 : }
      49             : 
      50             : void *
      51           0 : fd_repair_leave( fd_repair_t const * repair ) {
      52             : 
      53           0 :   if( FD_UNLIKELY( !repair ) ) {
      54           0 :     FD_LOG_WARNING(( "NULL repair" ));
      55           0 :     return NULL;
      56           0 :   }
      57             : 
      58           0 :   return (void *)repair;
      59           0 : }
      60             : 
      61             : void *
      62           0 : fd_repair_delete( void * repair ) {
      63             : 
      64           0 :   if( FD_UNLIKELY( !repair ) ) {
      65           0 :     FD_LOG_WARNING(( "NULL repair" ));
      66           0 :     return NULL;
      67           0 :   }
      68             : 
      69           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned((ulong)repair, fd_repair_align() ) ) ) {
      70           0 :     FD_LOG_WARNING(( "misaligned repair" ));
      71           0 :     return NULL;
      72           0 :   }
      73             : 
      74           0 :   return repair;
      75           0 : }
      76             : 
      77             : fd_repair_msg_t *
      78           0 : fd_repair_pong( fd_repair_t * repair, fd_hash_t * ping_token ) {
      79           0 :   uchar pre_image[FD_REPAIR_PONG_PREIMAGE_SZ];
      80           0 :   memcpy( pre_image,      "SOLANA_PING_PONG", 16UL );
      81           0 :   memcpy( pre_image+16UL, ping_token->uc,     32UL );
      82             : 
      83             :   /* Generate response hash token */
      84           0 :   fd_sha256_hash( pre_image, FD_REPAIR_PONG_PREIMAGE_SZ, &repair->msg.pong.hash );
      85             : 
      86           0 :   repair->msg.kind      = FD_REPAIR_KIND_PONG;
      87           0 :   repair->msg.pong.from = repair->identity_key;
      88           0 :   return &repair->msg;
      89           0 : }
      90             : 
      91             : fd_repair_msg_t *
      92             : fd_repair_shred( fd_repair_t *     repair,
      93             :                  fd_pubkey_t const * to,
      94             :                  ulong             ts,
      95             :                  uint              nonce,
      96             :                  ulong             slot,
      97          39 :                  ulong             shred_idx ) {
      98          39 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
      99          39 :   repair->msg.kind            = FD_REPAIR_KIND_SHRED;
     100          39 :   repair->msg.shred.from      = repair->identity_key;
     101          39 :   repair->msg.shred.to        = *to;
     102          39 :   repair->msg.shred.ts        = ts;
     103          39 :   repair->msg.shred.nonce     = nonce;
     104          39 :   repair->msg.shred.slot      = slot;
     105          39 :   repair->msg.shred.shred_idx = shred_idx;
     106          39 :   return &repair->msg;
     107          39 : }
     108             : 
     109             : fd_repair_msg_t *
     110             : fd_repair_highest_shred( fd_repair_t *     repair,
     111             :                          fd_pubkey_t const * to,
     112             :                          ulong             ts,
     113             :                          uint              nonce,
     114             :                          ulong             slot,
     115          27 :                          ulong             shred_idx ) {
     116          27 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     117          27 :   repair->msg.kind                    = FD_REPAIR_KIND_HIGHEST_SHRED;
     118          27 :   repair->msg.highest_shred.from      = repair->identity_key;
     119          27 :   repair->msg.highest_shred.to        = *to;
     120          27 :   repair->msg.highest_shred.ts        = ts;
     121          27 :   repair->msg.highest_shred.nonce     = nonce;
     122          27 :   repair->msg.highest_shred.slot      = slot;
     123          27 :   repair->msg.highest_shred.shred_idx = shred_idx;
     124          27 :   return &repair->msg;
     125          27 : }
     126             : 
     127             : fd_repair_msg_t *
     128             : fd_repair_orphan( fd_repair_t *     repair,
     129             :                   fd_pubkey_t const * to,
     130             :                   ulong             ts,
     131             :                   uint              nonce,
     132           0 :                   ulong             slot ) {
     133           0 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     134           0 :   repair->msg.kind         = FD_REPAIR_KIND_ORPHAN;
     135           0 :   repair->msg.orphan.from  = repair->identity_key;
     136           0 :   repair->msg.orphan.to    = *to;
     137           0 :   repair->msg.orphan.ts    = ts;
     138           0 :   repair->msg.orphan.nonce = nonce;
     139           0 :   repair->msg.orphan.slot  = slot;
     140           0 :   return &repair->msg;
     141           0 : }
     142             : 
     143             : fd_repair_msg_t *
     144             : ag_repair_parent_and_fec_set_count( fd_repair_t *       repair,
     145             :                                     fd_pubkey_t const * to,
     146             :                                     ulong               ts,
     147             :                                     uint                nonce,
     148             :                                     ulong               slot,
     149          60 :                                     fd_hash_t const *   block_id ) {
     150          60 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     151          60 :   repair->msg.kind = AG_REPAIR_KIND_PARENT_FEC_COUNT;
     152          60 :   repair->msg.parent_fec_set_count.from = repair->identity_key;
     153          60 :   repair->msg.parent_fec_set_count.to = *to;
     154          60 :   repair->msg.parent_fec_set_count.ts = ts;
     155          60 :   repair->msg.parent_fec_set_count.nonce = nonce;
     156          60 :   repair->msg.parent_fec_set_count.slot = slot;
     157          60 :   repair->msg.parent_fec_set_count.block_id = *block_id;
     158          60 :   return &repair->msg;
     159          60 : }
     160             : 
     161             : fd_repair_msg_t *
     162             : ag_repair_fec_set_root( fd_repair_t *       repair,
     163             :                         fd_pubkey_t const * to,
     164             :                         ulong               ts,
     165             :                         uint                nonce,
     166             :                         ulong               slot,
     167             :                         fd_hash_t const *   block_id,
     168         111 :                         uint                fec_set_idx ) {
     169         111 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     170         111 :   repair->msg.kind = AG_REPAIR_KIND_FEC_ROOT;
     171         111 :   repair->msg.fec_set_root.from = repair->identity_key;
     172         111 :   repair->msg.fec_set_root.to = *to;
     173         111 :   repair->msg.fec_set_root.ts = ts;
     174         111 :   repair->msg.fec_set_root.nonce = nonce;
     175         111 :   repair->msg.fec_set_root.slot = slot;
     176         111 :   repair->msg.fec_set_root.block_id = *block_id;
     177         111 :   repair->msg.fec_set_root.fec_set_idx = fec_set_idx;
     178         111 :   return &repair->msg;
     179         111 : }
     180             : 
     181             : fd_repair_msg_t *
     182             : ag_repair_shred_block_id( fd_repair_t *       repair,
     183             :                           fd_pubkey_t const * to,
     184             :                           ulong               ts,
     185             :                           uint                nonce,
     186             :                           ulong               slot,
     187             :                           fd_hash_t const *   block_id,
     188        1923 :                           uint                shred_idx ) {
     189        1923 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     190        1923 :   repair->msg.kind = AG_REPAIR_KIND_SHRED_FOR_BLOCK_ID;
     191        1923 :   repair->msg.shred_block_id.from = repair->identity_key;
     192        1923 :   repair->msg.shred_block_id.to = *to;
     193        1923 :   repair->msg.shred_block_id.ts = ts;
     194        1923 :   repair->msg.shred_block_id.nonce = nonce;
     195        1923 :   repair->msg.shred_block_id.slot = slot;
     196        1923 :   repair->msg.shred_block_id.shred_idx = shred_idx;
     197        1923 :   repair->msg.shred_block_id.block_id = *block_id;
     198        1923 :   return &repair->msg;
     199        1923 : }
     200             : 
     201             : int
     202             : ag_repair_response_de( ag_repair_response_t * response,
     203             :                        uchar const *          buf,
     204             :                        ulong                  buf_sz,
     205         141 :                        ulong                  fec_set_max ) {
     206         141 :   uchar const * cur = buf;
     207         141 :   ulong         rem = buf_sz;
     208             : 
     209         141 :   if( FD_UNLIKELY( rem<sizeof(uint) ) ) return -1;
     210         141 :   response->kind = fd_uint_load_4_fast( cur );
     211         141 :   cur += sizeof(uint); rem -= sizeof(uint);
     212             : 
     213         141 :   ulong   proof_sz; /* total bytes proof */
     214         141 :   uchar * proof;
     215             : 
     216         141 :   switch( response->kind ) {
     217          48 :     case AG_REPAIR_RESPONSE_PARENT_FEC_SET_COUNT: {
     218          48 :       ag_parent_fec_count_res_t * res = &response->parent_fec_set_res;
     219             : 
     220          48 :       if( FD_UNLIKELY( rem < sizeof(uint) ) ) return -1;
     221          48 :       res->fec_set_count = fd_uint_load_4_fast( cur );
     222          48 :       cur += sizeof(uint); rem -= sizeof(uint);
     223          48 :       if( FD_UNLIKELY( res->fec_set_count>fec_set_max ) ) return -1;
     224             : 
     225          48 :       if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
     226          48 :       res->parent_slot = fd_ulong_load_8_fast( cur );
     227          48 :       cur += sizeof(ulong); rem -= sizeof(ulong);
     228             : 
     229          48 :       if( FD_UNLIKELY( rem < sizeof(fd_hash_t) ) ) return -1;
     230          48 :       memcpy( res->parent_block_id.uc, cur, sizeof(fd_hash_t) );
     231          48 :       cur += sizeof(fd_hash_t); rem -= sizeof(fd_hash_t);
     232             : 
     233          48 :       if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
     234          48 :       proof_sz = fd_ulong_load_8_fast( cur );
     235          48 :       cur += sizeof(ulong); rem -= sizeof(ulong);
     236             : 
     237          48 :       res->proof_len = proof_sz / FD_SHRED_MERKLE_NODE_SZ;
     238          48 :       proof          = res->parent_proof[0];
     239          48 :       break;
     240          48 :     }
     241             : 
     242          93 :     case AG_REPAIR_RESPONSE_FEC_SET_ROOT: {
     243          93 :       ag_fec_root_res_t * res = &response->fec_set_root;
     244             : 
     245          93 :       if( FD_UNLIKELY( rem < FD_SHRED_MERKLE_NODE_SZ ) ) return -1;
     246          93 :       memcpy( res->root, cur, FD_SHRED_MERKLE_NODE_SZ );
     247          93 :       cur += FD_SHRED_MERKLE_NODE_SZ; rem -= FD_SHRED_MERKLE_NODE_SZ;
     248             : 
     249          93 :       if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
     250          93 :       proof_sz = fd_ulong_load_8_fast( cur );
     251          93 :       cur += sizeof(ulong); rem -= sizeof(ulong);
     252             : 
     253          93 :       res->proof_len = proof_sz / FD_SHRED_MERKLE_NODE_SZ;
     254          93 :       proof          = res->fec_proof[0];
     255          93 :       break;
     256          93 :     }
     257           0 :     default: return -1;
     258         141 :   }
     259             : 
     260         141 :   if( FD_UNLIKELY( proof_sz % FD_SHRED_MERKLE_NODE_SZ                           ) ) return -1;
     261         141 :   if( FD_UNLIKELY( proof_sz > AG_MAX_FEC_PROOF_NODE_CNT*FD_SHRED_MERKLE_NODE_SZ ) ) return -1;
     262         141 :   if( FD_UNLIKELY( rem != proof_sz+sizeof(uint)                                 ) ) return -1; /* proof + trailing nonce, nothing more */
     263             : 
     264         141 :   memcpy( proof, cur, proof_sz );
     265         141 :   cur += proof_sz;
     266             : 
     267         141 :   response->nonce = fd_uint_load_4_fast( cur );
     268         141 :   return 0;
     269         141 : }
     270             : 
     271             : /* verify_merkle_proof reconstructs the double-merkle root from leaf at
     272             :    leaf_idx + proof and checks it equals block_id.  0 on match, -1 else. */
     273             : 
     274             : static int
     275             : verify_merkle_proof( fd_bmtree_node_t * leaf,
     276             :                      ulong              leaf_idx,
     277             :                      uchar const *      proof,
     278             :                      ulong              proof_len,
     279         135 :                      fd_hash_t const *  block_id ) {
     280         135 :   fd_bmtree_node_t root[1];
     281         135 :   if( FD_UNLIKELY( !fd_bmtree_from_proof( leaf, leaf_idx, root, proof, proof_len, FD_SHRED_MERKLE_NODE_SZ, FD_BMTREE_LONG_PREFIX_SZ ) ) ) return -1;
     282         135 :   if( FD_UNLIKELY( 0!=memcmp( root->hash, block_id->uc, sizeof(fd_hash_t) ) ) ) return -1;
     283         129 :   return 0;
     284         135 : }
     285             : 
     286             : int
     287             : ag_repair_parent_fec_count_verify( ag_parent_fec_count_res_t const * res,
     288          42 :                                    fd_hash_t const *                 block_id ) {
     289             :   /* The parent-info leaf is the last of the tree's fec_set_count+1
     290             :      leaves, so the proof must be exactly as deep as that tree. */
     291          42 :   if( FD_UNLIKELY( res->proof_len != fd_bmtree_depth( res->fec_set_count+1UL )-1UL ) ) return -1;
     292             : 
     293          42 :   fd_bmtree_node_t leaf[1];
     294          42 :   fd_sha256_t sha[1];
     295          42 :   fd_sha256_init  ( sha );
     296          42 :   fd_sha256_append( sha, &res->parent_slot,       sizeof(ulong)     );
     297          42 :   fd_sha256_append( sha, res->parent_block_id.uc, sizeof(fd_hash_t) );
     298          42 :   fd_sha256_append( sha, &res->fec_set_count,     sizeof(uint)      );
     299          42 :   fd_sha256_fini  ( sha, leaf->hash );
     300             : 
     301          42 :   return verify_merkle_proof( leaf, res->fec_set_count, res->parent_proof[0], res->proof_len, block_id );
     302          42 : }
     303             : 
     304             : int
     305             : ag_repair_fec_set_root_verify( ag_fec_root_res_t const * res,
     306             :                                fd_hash_t const *         block_id,
     307          93 :                                uint                      fec_set_idx ) {
     308          93 :   fd_bmtree_node_t leaf[1] = {0};
     309          93 :   memcpy( leaf->hash, res->root, FD_SHRED_MERKLE_NODE_SZ );
     310             : 
     311          93 :   return verify_merkle_proof( leaf, fec_set_idx / FD_FEC_SHRED_CNT, res->fec_proof[0], res->proof_len, block_id );
     312          93 : }
     313             : 
     314             : int
     315             : fd_repair_ping_de( fd_repair_ping_t * ping,
     316             :                    uchar      const * buf,
     317           0 :                    ulong              buf_sz ) {
     318           0 :   if( FD_UNLIKELY( buf_sz!=sizeof(fd_repair_ping_t) )) return -1;
     319             : 
     320           0 :   ping->kind = fd_uint_load_4_fast( buf );
     321           0 :   buf       += sizeof(uint);
     322             : 
     323           0 :   if( FD_UNLIKELY( ping->kind != FD_REPAIR_KIND_PING && ping->kind != AG_REPAIR_KIND_PING )) return -1;
     324             : 
     325             :   /* pong section */
     326             : 
     327           0 :   memcpy( &ping->ping.from, buf, sizeof(fd_pubkey_t) );
     328           0 :   buf += sizeof(fd_pubkey_t);
     329             : 
     330           0 :   memcpy( &ping->ping.hash, buf, sizeof(fd_hash_t) );
     331           0 :   buf += sizeof(fd_hash_t);
     332             : 
     333           0 :   memcpy( ping->ping.sig, buf, sizeof(fd_ed25519_sig_t) );
     334           0 :   buf += sizeof(fd_ed25519_sig_t);
     335           0 :   return 0;
     336           0 : }
     337             : 
     338             : int
     339             : fd_repair_ping_ser( fd_repair_ping_t const * ping,
     340             :                     uchar                    buf[static sizeof(fd_repair_ping_t)],
     341           0 :                     ulong                    buf_sz ) {
     342           0 :   ulong off = 0;
     343           0 :   if( FD_UNLIKELY( buf_sz!=sizeof(fd_repair_ping_t) )) return -1;
     344             : 
     345           0 :   FD_STORE( uint, buf+off, ping->kind );
     346           0 :   off += sizeof(uint);
     347             : 
     348           0 :   FD_STORE( fd_pubkey_t, buf+off, ping->ping.from );
     349           0 :   off += sizeof(fd_pubkey_t);
     350             : 
     351           0 :   FD_STORE( fd_hash_t, buf+off, ping->ping.hash );
     352           0 :   off += sizeof(fd_hash_t);
     353             : 
     354           0 :   memcpy( buf+off, ping->ping.sig, sizeof(fd_ed25519_sig_t) );
     355           0 :   off += sizeof(fd_ed25519_sig_t);
     356             : 
     357           0 :   return 0;
     358           0 : }

Generated by: LCOV version 1.14