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