LCOV - code coverage report
Current view: top level - discof/backtest - fd_blockstore2shredcap.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 78 0.0 %
Date: 2025-12-06 04:45:29 Functions: 0 3 0.0 %

          Line data    Source code
       1             : #include "fd_backtest_rocksdb.h"
       2             : #include "../../util/fd_util.h"
       3             : #include "../../util/net/fd_pcapng.h"
       4             : #include "../../util/net/fd_ip4.h"
       5             : #include "fd_shredcap.h"
       6             : #include "../../ballet/shred/fd_shred.h"
       7             : #include "../../flamenco/gossip/fd_gossip_types.h"
       8             : #include "fd_libc_zstd.h"
       9             : 
      10             : #include <errno.h>
      11             : #include <stdio.h>
      12             : #include <stdlib.h>
      13             : #include <fcntl.h>
      14             : 
      15             : /* Hardcoded constants */
      16             : 
      17           0 : #define IF_IDX_NET      (0)
      18           0 : #define IF_IDX_SHREDCAP (1)
      19           0 : #define SHRED_PORT      ((ushort)8003)
      20             : 
      21             : static int
      22           0 : usage( int rc ) {
      23           0 :   fputs(
      24           0 :     "\n"
      25           0 :     "Usage: fd_blockstore2shredcap --rocksdb <path> --out <path>\n"
      26           0 :     "\n"
      27           0 :     "Extract rooted blocks from Agave RocksDB.\n"
      28           0 :     "Produces shredcap 0.1 (pcapng) file containing shreds and bank hashes.\n"
      29           0 :     "\n"
      30           0 :     "  --rocksdb <path>  Agave RocksDB directory\n"
      31           0 :     "  --out     <path>  File path to new shredcap file (fails if file already exists)\n"
      32           0 : #   if FD_HAS_ZSTD
      33           0 :     "  --zstd            Output compressed .pcapng.zst stream instead of raw pcapng\n"
      34           0 :     "  --zstd-level      Zstandard compression level\n"
      35           0 : #   endif
      36           0 :     "\n",
      37           0 :     stderr
      38           0 :   );
      39           0 :   return rc;
      40           0 : }
      41             : 
      42             : static void
      43             : write_bank_hash( FILE *      pcap,
      44             :                  ulong       slot,
      45             :                  ulong       shred_cnt,
      46           0 :                  uchar const bank_hash[32] ) {
      47           0 :   struct __attribute__((packed)) {
      48           0 :     uint type;
      49           0 :     fd_shredcap_bank_hash_v0_t bank_hash_rec;
      50           0 :   } packet;
      51           0 :   memset( &packet, 0, sizeof(packet) );
      52             : 
      53           0 :   packet.type = FD_SHREDCAP_TYPE_BANK_HASH_V0;
      54           0 :   fd_shredcap_bank_hash_v0_t * bank_hash_rec = &packet.bank_hash_rec;
      55           0 :   bank_hash_rec->slot           = slot;
      56           0 :   bank_hash_rec->data_shred_cnt = shred_cnt;
      57           0 :   memcpy( bank_hash_rec->bank_hash, bank_hash, 32UL );
      58             : 
      59           0 :   fd_pcapng_fwrite_pkt1( pcap, &packet, sizeof(packet), NULL, 0UL, IF_IDX_SHREDCAP, 0L );
      60           0 : }
      61             : 
      62             : static void
      63             : write_shred( FILE *       pcap,
      64           0 :              void const * shred ) {
      65           0 :   ulong shred_sz = fd_shred_sz( shred );
      66           0 :   FD_TEST( shred_sz<=FD_SHRED_MAX_SZ );
      67             : 
      68           0 :   struct __attribute__((packed)) {
      69           0 :     fd_ip4_hdr_t ip4;
      70           0 :     fd_udp_hdr_t udp;
      71           0 :     uchar shred[ FD_SHRED_MAX_SZ ];
      72           0 :   } packet;
      73             : 
      74           0 :   packet.ip4 = (fd_ip4_hdr_t) {
      75           0 :     .verihl       = FD_IP4_VERIHL( 4, 5 ),
      76           0 :     .tos          = 0,
      77           0 :     .net_tot_len  = fd_ushort_bswap( (ushort)( 28+shred_sz ) ),
      78           0 :     .net_id       = 0,
      79           0 :     .net_frag_off = fd_ushort_bswap( FD_IP4_HDR_FRAG_OFF_DF ),
      80           0 :     .ttl          = 64,
      81           0 :     .protocol     = FD_IP4_HDR_PROTOCOL_UDP,
      82           0 :     .check        = 0,
      83           0 :     .saddr        = FD_IP4_ADDR( 127,0,0,1 ),
      84           0 :     .daddr        = FD_IP4_ADDR( 127,0,0,1 ),
      85           0 :   };
      86           0 :   packet.ip4.check = fd_ip4_hdr_check_fast( &packet.ip4 );
      87           0 :   packet.udp = (fd_udp_hdr_t) {
      88           0 :     .net_sport = fd_ushort_bswap( 42424 ),
      89           0 :     .net_dport = fd_ushort_bswap( SHRED_PORT ),
      90           0 :     .net_len   = fd_ushort_bswap( (ushort)( 8+shred_sz ) ),
      91           0 :     .check     = 0,
      92           0 :   };
      93           0 :   fd_memcpy( packet.shred, shred, shred_sz );
      94             : 
      95           0 :   struct __attribute__((packed)) {
      96           0 :     ushort option_type;
      97           0 :     ushort option_sz;
      98           0 :     uint   pen;
      99           0 :     ushort magic;
     100           0 :     ushort gossip_tag;
     101           0 :   } option = {
     102           0 :     .option_type = 2989,   /* Custom Option containing binary octects, copyable */
     103           0 :     .option_sz   = 8,
     104           0 :     .pen         = 31592,  /* Jump Trading, LLC */
     105           0 :     .magic       = 0x4071, /* SOL! */
     106           0 :     .gossip_tag  = FD_CONTACT_INFO_SOCKET_TVU
     107           0 :   };
     108             : 
     109           0 :   fd_pcapng_fwrite_pkt1( pcap, &packet, 28UL+shred_sz, &option, sizeof(option), IF_IDX_NET, 0L );
     110           0 : }
     111             : 
     112             : int
     113             : main( int     argc,
     114             :       char ** argv ) {
     115             :   if( fd_env_strip_cmdline_contains( &argc, &argv, "--help" ) ) return usage( 0 );
     116             : 
     117             :   char const * rocksdb_path = fd_env_strip_cmdline_cstr( &argc, &argv, "--rocksdb", NULL, NULL );
     118             :   char const * out_path     = fd_env_strip_cmdline_cstr( &argc, &argv, "--out",     NULL, NULL );
     119             :   char const * out_short    = fd_env_strip_cmdline_cstr( &argc, &argv, "--o",       NULL, NULL );
     120             :   if( !out_path ) out_path = out_short;
     121             : 
     122             :   int   use_zstd   = fd_env_strip_cmdline_contains( &argc, &argv, "--zstd"                      );
     123             :   int   zstd_level = fd_env_strip_cmdline_int     ( &argc, &argv, "--zstd-level", NULL,       3 );
     124             :   ulong zstd_bufsz = fd_env_strip_cmdline_ulong   ( &argc, &argv, "--zstd-bufsz", NULL, 4UL<<20 ); /* 4MB default */
     125             : # if !FD_HAS_ZSTD
     126             :   if( use_zstd ) FD_LOG_ERR(( "This build does not support ZSTD compression" ));
     127             :   (void)zstd_level;
     128             : # endif
     129             : 
     130             :   if( FD_UNLIKELY( !rocksdb_path ) ) {
     131             :     fputs( "Error: --rocksdb not specified\n", stderr );
     132             :     return usage( 1 );
     133             :   }
     134             :   if( FD_UNLIKELY( !out_path ) ) {
     135             :     fputs( "Error: --out not specified\n", stderr );
     136             :     return usage( 1 );
     137             :   }
     138             : 
     139             :   fd_boot( &argc, &argv );
     140             : 
     141             :   void * rocks_mem = aligned_alloc( fd_backtest_rocksdb_align(), fd_backtest_rocksdb_footprint() );
     142             :   if( FD_UNLIKELY( !rocks_mem ) ) FD_LOG_ERR(( "out of memory" ));
     143             :   fd_backtest_rocksdb_t * rocksdb = fd_backtest_rocksdb_join( fd_backtest_rocksdb_new( rocks_mem, rocksdb_path ) );
     144             :   if( FD_UNLIKELY( !rocksdb ) ) FD_LOG_ERR(( "failed to open RocksDB at %s", rocksdb_path ));
     145             :   fd_backtest_rocksdb_init( rocksdb, 0UL );
     146             : 
     147             :   int out_fd = open( out_path, O_WRONLY|O_CREAT|O_EXCL, 0644 );
     148             :   if( FD_UNLIKELY( out_fd<0 ) ) FD_LOG_ERR(( "failed to create file %s (%i-%s)", out_path, errno, fd_io_strerror( errno ) ));
     149             :   FILE * out = fdopen( out_fd, "wb" );
     150             :   if( FD_UNLIKELY( !out ) ) FD_LOG_ERR(( "fdopen failed on %s (%i-%s)", out_path, errno, fd_io_strerror( errno ) ));
     151             : 
     152             : # if FD_HAS_ZSTD
     153             :   if( use_zstd ) {
     154             :     out = fd_zstd_wstream_open( out, zstd_level, zstd_bufsz );
     155             :     if( FD_UNLIKELY( !out ) ) FD_LOG_ERR(( "failed to initialize ZSTD compression" ));
     156             :   }
     157             : # endif
     158             : 
     159             :   /* Write pcapng header */
     160             :   {
     161             :     fd_pcapng_shb_opts_t shb_opts;
     162             :     fd_pcapng_shb_defaults( &shb_opts );
     163             :     if( FD_UNLIKELY( !fd_pcapng_fwrite_shb( &shb_opts, out ) ) ) FD_LOG_ERR(( "pcap write error" ));
     164             :   }
     165             :   uint idb_cnt = 0U;
     166             :   {
     167             :     fd_pcapng_idb_opts_t idb_opts = {
     168             :       .name     = "lo",
     169             :       .ip4_addr = { 127,0,0,1 }
     170             :     };
     171             :     if( FD_UNLIKELY( !fd_pcapng_fwrite_idb( FD_PCAPNG_LINKTYPE_IPV4, &idb_opts, out ) ) ) FD_LOG_ERR(( "pcap write error" ));
     172             :     FD_TEST( idb_cnt++==IF_IDX_NET );
     173             :   }
     174             :   {
     175             :     fd_pcapng_idb_opts_t idb_opts = {
     176             :       .name = "shredcap0",
     177             :     };
     178             :     if( FD_UNLIKELY( !fd_pcapng_fwrite_idb( FD_PCAPNG_LINKTYPE_USER0, &idb_opts, out ) ) ) FD_LOG_ERR(( "pcap write error" ));
     179             :     FD_TEST( idb_cnt++==IF_IDX_SHREDCAP );
     180             :   }
     181             : 
     182             :   ulong slot_cnt = 0UL;
     183             :   for( ;; slot_cnt++ ) {
     184             : 
     185             :     ulong root_slot;
     186             :     ulong shred_cnt;
     187             :     int root_ok = fd_backtest_rocksdb_next_root_slot( rocksdb, &root_slot, &shred_cnt );
     188             :     if( !root_ok ) break;
     189             :     uchar const * bank_hash = fd_backtest_rocksdb_bank_hash( rocksdb, root_slot );
     190             :     if( FD_UNLIKELY( !bank_hash ) ) FD_LOG_ERR(( "failed to extract bank hash for root slot %lu", root_slot ));
     191             : 
     192             :     write_bank_hash( out, root_slot, shred_cnt, bank_hash );
     193             : 
     194             :     for( ulong i=0UL; i<shred_cnt; i++ ) {
     195             :       void const * shred = fd_backtest_rocksdb_shred( rocksdb, root_slot, i );
     196             :       if( FD_UNLIKELY( !shred ) ) {
     197             :         FD_LOG_WARNING(( "missing shred %lu for slot %lu", i, root_slot ));
     198             :         break;
     199             :       }
     200             :       write_shred( out, shred );
     201             :     }
     202             : 
     203             :   }
     204             : 
     205             :   long off = ftell( out );
     206             :   FD_LOG_NOTICE(( "%s: wrote %lu slots, %ld bytes", out_path, slot_cnt, off ));
     207             : 
     208             :   /* FIXME missing destructor for backtest_rocksdb */
     209             :   if( FD_UNLIKELY( 0!=fclose( out ) ) ) {
     210             :     FD_LOG_ERR(( "fclose failed on %s (%i-%s), output file may be corrupt", out_path, errno, fd_io_strerror( errno ) ));
     211             :   }
     212             :   free( rocks_mem );
     213             : 
     214             :   fd_halt();
     215             :   return 0;
     216             : }

Generated by: LCOV version 1.14