LCOV - code coverage report
Current view: top level - discof/repair - fd_repair.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 257 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 19 0.0 %

          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           0 : fd_repair_new( void * shmem, fd_pubkey_t * identity_key ) {
       7             : 
       8           0 :   if( FD_UNLIKELY( !shmem ) ) {
       9           0 :     FD_LOG_WARNING(( "NULL mem" ));
      10           0 :     return NULL;
      11           0 :   }
      12             : 
      13           0 :   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           0 :   ulong footprint = fd_repair_footprint();
      19           0 :   fd_memset( shmem, 0, footprint );
      20             : 
      21           0 :   fd_repair_t * repair = (fd_repair_t *)shmem;
      22           0 :   repair->identity_key = *identity_key;
      23             : 
      24           0 :   return shmem;
      25           0 : }
      26             : 
      27             : fd_repair_t *
      28           0 : fd_repair_join( void * shrepair ) {
      29           0 :   fd_repair_t * repair = (fd_repair_t *)shrepair;
      30             : 
      31           0 :   if( FD_UNLIKELY( !repair ) ) {
      32           0 :     FD_LOG_WARNING(( "NULL repair" ));
      33           0 :     return NULL;
      34           0 :   }
      35             : 
      36           0 :   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           0 :   fd_wksp_t * wksp = fd_wksp_containing( repair );
      42           0 :   if( FD_UNLIKELY( !wksp ) ) {
      43           0 :     FD_LOG_WARNING(( "repair must be part of a workspace" ));
      44           0 :     return NULL;
      45           0 :   }
      46             : 
      47           0 :   return repair;
      48           0 : }
      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           0 :                  ulong             shred_idx ) {
      98           0 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
      99           0 :   repair->msg.kind            = FD_REPAIR_KIND_SHRED;
     100           0 :   repair->msg.shred.from      = repair->identity_key;
     101           0 :   repair->msg.shred.to        = *to;
     102           0 :   repair->msg.shred.ts        = ts;
     103           0 :   repair->msg.shred.nonce     = nonce;
     104           0 :   repair->msg.shred.slot      = slot;
     105           0 :   repair->msg.shred.shred_idx = shred_idx;
     106           0 :   return &repair->msg;
     107           0 : }
     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           0 :                          ulong             shred_idx ) {
     116           0 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     117           0 :   repair->msg.kind                    = FD_REPAIR_KIND_HIGHEST_SHRED;
     118           0 :   repair->msg.highest_shred.from      = repair->identity_key;
     119           0 :   repair->msg.highest_shred.to        = *to;
     120           0 :   repair->msg.highest_shred.ts        = ts;
     121           0 :   repair->msg.highest_shred.nonce     = nonce;
     122           0 :   repair->msg.highest_shred.slot      = slot;
     123           0 :   repair->msg.highest_shred.shred_idx = shred_idx;
     124           0 :   return &repair->msg;
     125           0 : }
     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           0 :                                     fd_hash_t const *   block_id ) {
     150           0 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     151           0 :   repair->msg.kind = AG_REPAIR_KIND_PARENT_FEC_COUNT;
     152           0 :   repair->msg.parent_fec_set_count.from = repair->identity_key;
     153           0 :   repair->msg.parent_fec_set_count.to = *to;
     154           0 :   repair->msg.parent_fec_set_count.ts = ts;
     155           0 :   repair->msg.parent_fec_set_count.nonce = nonce;
     156           0 :   repair->msg.parent_fec_set_count.slot = slot;
     157           0 :   repair->msg.parent_fec_set_count.block_id = *block_id;
     158           0 :   return &repair->msg;
     159           0 : }
     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           0 :                         uint                fec_set_idx ) {
     169           0 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     170           0 :   repair->msg.kind = AG_REPAIR_KIND_FEC_ROOT;
     171           0 :   repair->msg.fec_set_root.from = repair->identity_key;
     172           0 :   repair->msg.fec_set_root.to = *to;
     173           0 :   repair->msg.fec_set_root.ts = ts;
     174           0 :   repair->msg.fec_set_root.nonce = nonce;
     175           0 :   repair->msg.fec_set_root.slot = slot;
     176           0 :   repair->msg.fec_set_root.block_id = *block_id;
     177           0 :   repair->msg.fec_set_root.fec_set_idx = fec_set_idx;
     178           0 :   return &repair->msg;
     179           0 : }
     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           0 :                           uint                shred_idx ) {
     189           0 :   memset(&repair->msg, 0, sizeof(fd_repair_msg_t));
     190           0 :   repair->msg.kind = AG_REPAIR_KIND_SHRED_FOR_BLOCK_ID;
     191           0 :   repair->msg.shred_block_id.from = repair->identity_key;
     192           0 :   repair->msg.shred_block_id.to = *to;
     193           0 :   repair->msg.shred_block_id.ts = ts;
     194           0 :   repair->msg.shred_block_id.nonce = nonce;
     195           0 :   repair->msg.shred_block_id.slot = slot;
     196           0 :   repair->msg.shred_block_id.shred_idx = shred_idx;
     197           0 :   repair->msg.shred_block_id.block_id = *block_id;
     198           0 :   return &repair->msg;
     199           0 : }
     200             : 
     201             : int
     202             : ag_repair_response_de( ag_repair_response_t * response,
     203             :                        uchar const *          buf,
     204             :                        ulong                  buf_sz,
     205           0 :                        ulong                  fec_set_max ) {
     206           0 :   uchar const * cur = buf;
     207           0 :   ulong         rem = buf_sz;
     208             : 
     209           0 :   if( FD_UNLIKELY( rem<sizeof(uint) ) ) return -1;
     210           0 :   response->kind = fd_uint_load_4_fast( cur );
     211           0 :   cur += sizeof(uint); rem -= sizeof(uint);
     212             : 
     213           0 :   ulong   proof_sz; /* total bytes proof */
     214           0 :   uchar * proof;
     215             : 
     216           0 :   switch( response->kind ) {
     217           0 :     case AG_REPAIR_RESPONSE_PARENT_FEC_SET_COUNT: {
     218           0 :       ag_parent_fec_count_res_t * res = &response->parent_fec_set_res;
     219             : 
     220           0 :       if( FD_UNLIKELY( rem < sizeof(uint) ) ) return -1;
     221           0 :       res->fec_set_count = fd_uint_load_4_fast( cur );
     222           0 :       cur += sizeof(uint); rem -= sizeof(uint);
     223           0 :       if( FD_UNLIKELY( !res->fec_set_count || res->fec_set_count>fec_set_max ) ) return -1;
     224             : 
     225           0 :       if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
     226           0 :       res->parent_slot = fd_ulong_load_8_fast( cur );
     227           0 :       cur += sizeof(ulong); rem -= sizeof(ulong);
     228             : 
     229           0 :       if( FD_UNLIKELY( rem < sizeof(fd_hash_t) ) ) return -1;
     230           0 :       memcpy( res->parent_block_id.uc, cur, sizeof(fd_hash_t) );
     231           0 :       cur += sizeof(fd_hash_t); rem -= sizeof(fd_hash_t);
     232             : 
     233           0 :       if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
     234           0 :       proof_sz = fd_ulong_load_8_fast( cur );
     235           0 :       cur += sizeof(ulong); rem -= sizeof(ulong);
     236             : 
     237           0 :       res->proof_len = proof_sz / FD_SHRED_MERKLE_NODE_SZ;
     238           0 :       proof          = res->parent_proof[0];
     239           0 :       break;
     240           0 :     }
     241             : 
     242           0 :     case AG_REPAIR_RESPONSE_FEC_SET_ROOT: {
     243           0 :       ag_fec_root_res_t * res = &response->fec_set_root;
     244             : 
     245           0 :       if( FD_UNLIKELY( rem < FD_SHRED_MERKLE_NODE_SZ ) ) return -1;
     246           0 :       memcpy( res->root, cur, FD_SHRED_MERKLE_NODE_SZ );
     247           0 :       cur += FD_SHRED_MERKLE_NODE_SZ; rem -= FD_SHRED_MERKLE_NODE_SZ;
     248             : 
     249           0 :       if( FD_UNLIKELY( rem < sizeof(ulong) ) ) return -1;
     250           0 :       proof_sz = fd_ulong_load_8_fast( cur );
     251           0 :       cur += sizeof(ulong); rem -= sizeof(ulong);
     252             : 
     253           0 :       res->proof_len = proof_sz / FD_SHRED_MERKLE_NODE_SZ;
     254           0 :       proof          = res->fec_proof[0];
     255           0 :       break;
     256           0 :     }
     257           0 :     default: return -1;
     258           0 :   }
     259             : 
     260           0 :   if( FD_UNLIKELY( proof_sz % FD_SHRED_MERKLE_NODE_SZ                           ) ) return -1;
     261           0 :   if( FD_UNLIKELY( proof_sz > AG_MAX_FEC_PROOF_NODE_CNT*FD_SHRED_MERKLE_NODE_SZ ) ) return -1;
     262           0 :   if( FD_UNLIKELY( rem != proof_sz+sizeof(uint)                                 ) ) return -1; /* proof + trailing nonce, nothing more */
     263             : 
     264           0 :   memcpy( proof, cur, proof_sz );
     265           0 :   cur += proof_sz;
     266             : 
     267           0 :   response->nonce = fd_uint_load_4_fast( cur );
     268           0 :   return 0;
     269           0 : }
     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           0 :                      fd_hash_t const *  block_id ) {
     280           0 :   fd_bmtree_node_t root[1];
     281           0 :   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           0 :   if( FD_UNLIKELY( 0!=memcmp( root->hash, block_id->uc, sizeof(fd_hash_t) ) ) ) return -1;
     283           0 :   return 0;
     284           0 : }
     285             : 
     286             : int
     287             : ag_repair_parent_fec_count_verify( ag_parent_fec_count_res_t const * res,
     288           0 :                                    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           0 :   if( FD_UNLIKELY( res->proof_len != fd_bmtree_depth( res->fec_set_count+1UL )-1UL ) ) return -1;
     292             : 
     293           0 :   fd_bmtree_node_t leaf[1];
     294           0 :   fd_sha256_t sha[1];
     295           0 :   fd_sha256_init  ( sha );
     296           0 :   fd_sha256_append( sha, &res->parent_slot,       sizeof(ulong)     );
     297           0 :   fd_sha256_append( sha, res->parent_block_id.uc, sizeof(fd_hash_t) );
     298           0 :   fd_sha256_append( sha, &res->fec_set_count,     sizeof(uint)      );
     299           0 :   fd_sha256_fini  ( sha, leaf->hash );
     300             : 
     301           0 :   return verify_merkle_proof( leaf, res->fec_set_count, res->parent_proof[0], res->proof_len, block_id );
     302           0 : }
     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             :                                uint                      fec_set_idx,
     308           0 :                                uint                      fec_set_count ) {
     309             :   /* https://github.com/anza-xyz/agave/blob/5f11d68ab206fee323e8d29acd96d517fae3c9ec/core/src/repair/serve_repair.rs#L381 */
     310           0 :   if( FD_UNLIKELY( !fec_set_count                                             ) ) return -1;
     311           0 :   if( FD_UNLIKELY( fec_set_idx / FD_FEC_SHRED_CNT >= fec_set_count            ) ) return -1;
     312           0 :   if( FD_UNLIKELY( res->proof_len != fd_bmtree_depth( fec_set_count+1UL )-1UL ) ) return -1;
     313             : 
     314           0 :   fd_bmtree_node_t leaf[1] = {0};
     315           0 :   memcpy( leaf->hash, res->root, FD_SHRED_MERKLE_NODE_SZ );
     316             : 
     317           0 :   return verify_merkle_proof( leaf, fec_set_idx / FD_FEC_SHRED_CNT, res->fec_proof[0], res->proof_len, block_id );
     318           0 : }
     319             : 
     320             : ulong
     321             : ag_repair_parent_fec_count_ser( uchar *           buf,
     322             :                                 ulong             buf_sz,
     323             :                                 uint              fec_set_count,
     324             :                                 ulong             parent_slot,
     325             :                                 fd_hash_t const * parent_block_id,
     326             :                                 uchar const *     proof,
     327             :                                 ulong             proof_len,
     328           0 :                                 uint              nonce ) {
     329           0 :   ulong proof_sz = fd_ulong_sat_mul( proof_len, FD_SHRED_MERKLE_NODE_SZ );
     330           0 :   if( FD_UNLIKELY( proof_sz==ULONG_MAX )) return 0UL;
     331             : 
     332           0 :   ulong sz       = fd_ulong_sat_add( sizeof(uint) + sizeof(uint) + sizeof(ulong) + sizeof(fd_hash_t) + sizeof(ulong) + sizeof(uint),
     333           0 :                                      proof_sz );
     334           0 :   if( FD_UNLIKELY( sz>buf_sz )) return 0UL;
     335             : 
     336           0 :   uchar * cur = buf;
     337           0 :   FD_STORE( uint,  cur, AG_REPAIR_RESPONSE_PARENT_FEC_SET_COUNT ); cur += sizeof(uint);
     338           0 :   FD_STORE( uint,  cur, fec_set_count                           ); cur += sizeof(uint);
     339           0 :   FD_STORE( ulong, cur, parent_slot                             ); cur += sizeof(ulong);
     340           0 :   memcpy( cur, parent_block_id->uc, sizeof(fd_hash_t) );           cur += sizeof(fd_hash_t);
     341           0 :   FD_STORE( ulong, cur, proof_sz                                ); cur += sizeof(ulong);
     342           0 :   memcpy( cur, proof, proof_sz );                                  cur += proof_sz;
     343           0 :   FD_STORE( uint,  cur, nonce                                   ); cur += sizeof(uint);
     344           0 :   return sz;
     345           0 : }
     346             : 
     347             : ulong
     348             : ag_repair_fec_set_root_ser( uchar *       buf,
     349             :                             ulong         buf_sz,
     350             :                             uchar const * root,
     351             :                             uchar const * proof,
     352             :                             ulong         proof_len,
     353           0 :                             uint          nonce ) {
     354           0 :   ulong proof_sz = fd_ulong_sat_mul( proof_len, FD_SHRED_MERKLE_NODE_SZ );
     355           0 :   if( FD_UNLIKELY( proof_sz == ULONG_MAX )) return 0UL;
     356             : 
     357           0 :   ulong sz       = fd_ulong_sat_add( sizeof(uint) + FD_SHRED_MERKLE_NODE_SZ + sizeof(ulong) + sizeof(uint),
     358           0 :                                      proof_sz );
     359           0 :   if( FD_UNLIKELY( sz>buf_sz ) ) return 0UL;
     360             : 
     361           0 :   uchar * cur = buf;
     362           0 :   FD_STORE( uint,  cur, AG_REPAIR_RESPONSE_FEC_SET_ROOT ); cur += sizeof(uint);
     363           0 :   memcpy( cur, root, FD_SHRED_MERKLE_NODE_SZ );            cur += FD_SHRED_MERKLE_NODE_SZ;
     364           0 :   FD_STORE( ulong, cur, proof_sz                        ); cur += sizeof(ulong);
     365           0 :   memcpy( cur, proof, proof_sz );                          cur += proof_sz;
     366           0 :   FD_STORE( uint,  cur, nonce                           ); cur += sizeof(uint);
     367           0 :   return sz;
     368           0 : }
     369             : 
     370             : int
     371             : fd_repair_ping_de( fd_repair_ping_t * ping,
     372             :                    uchar      const * buf,
     373           0 :                    ulong              buf_sz ) {
     374           0 :   if( FD_UNLIKELY( buf_sz!=sizeof(fd_repair_ping_t) )) return -1;
     375             : 
     376           0 :   ping->kind = fd_uint_load_4_fast( buf );
     377           0 :   buf       += sizeof(uint);
     378             : 
     379           0 :   if( FD_UNLIKELY( ping->kind != FD_REPAIR_KIND_PING && ping->kind != AG_REPAIR_KIND_PING )) return -1;
     380             : 
     381             :   /* pong section */
     382             : 
     383           0 :   memcpy( &ping->ping.from, buf, sizeof(fd_pubkey_t) );
     384           0 :   buf += sizeof(fd_pubkey_t);
     385             : 
     386           0 :   memcpy( &ping->ping.hash, buf, sizeof(fd_hash_t) );
     387           0 :   buf += sizeof(fd_hash_t);
     388             : 
     389           0 :   memcpy( ping->ping.sig, buf, sizeof(fd_ed25519_sig_t) );
     390           0 :   buf += sizeof(fd_ed25519_sig_t);
     391           0 :   return 0;
     392           0 : }
     393             : 
     394             : int
     395             : fd_repair_ping_ser( fd_repair_ping_t const * ping,
     396             :                     uchar                    buf[static sizeof(fd_repair_ping_t)],
     397           0 :                     ulong                    buf_sz ) {
     398           0 :   ulong off = 0;
     399           0 :   if( FD_UNLIKELY( buf_sz!=sizeof(fd_repair_ping_t) )) return -1;
     400             : 
     401           0 :   FD_STORE( uint, buf+off, ping->kind );
     402           0 :   off += sizeof(uint);
     403             : 
     404           0 :   FD_STORE( fd_pubkey_t, buf+off, ping->ping.from );
     405           0 :   off += sizeof(fd_pubkey_t);
     406             : 
     407           0 :   FD_STORE( fd_hash_t, buf+off, ping->ping.hash );
     408           0 :   off += sizeof(fd_hash_t);
     409             : 
     410           0 :   memcpy( buf+off, ping->ping.sig, sizeof(fd_ed25519_sig_t) );
     411           0 :   off += sizeof(fd_ed25519_sig_t);
     412             : 
     413           0 :   return 0;
     414           0 : }

Generated by: LCOV version 1.14