LCOV - code coverage report
Current view: top level - flamenco/accdb - fd_accdb_fsck_vinyl.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 238 0.0 %
Date: 2025-12-06 04:45:29 Functions: 0 2 0.0 %

          Line data    Source code
       1             : #include "fd_accdb_fsck.h"
       2             : #include "../runtime/fd_runtime_const.h"
       3             : #include "../../ballet/lthash/fd_lthash_adder.h"
       4             : 
       5             : #define VINYL_KEY_FMT             "%016lx%016lx%016lx%016lx"
       6             : #define VINYL_KEY_FMT_ARGS( key ) fd_ulong_bswap( (key).ul[0] ), fd_ulong_bswap( (key).ul[1] ), fd_ulong_bswap( (key).ul[2] ), fd_ulong_bswap( (key).ul[3] )
       7             : 
       8             : /* meta_query_fast is a simplified version of fd_vinyl_meta_prepare */
       9             : 
      10             : static fd_vinyl_meta_ele_t *
      11             : meta_query_fast( fd_vinyl_meta_t *      join,
      12             :                  fd_vinyl_key_t const * key,
      13           0 :                  ulong                  memo ) {
      14           0 :   fd_vinyl_meta_ele_t * ele0      = join->ele;
      15           0 :   ulong                 ele_max   = join->ele_max;
      16           0 :   ulong                 probe_max = join->probe_max;
      17           0 :   void *                ctx       = join->ctx;
      18             : 
      19           0 :   ulong start_idx = memo & (ele_max-1UL);
      20             : 
      21           0 :   for(;;) {
      22           0 :     ulong ele_idx = start_idx;
      23           0 :     for( ulong probe_rem=probe_max; probe_rem; probe_rem-- ) {
      24           0 :       fd_vinyl_meta_ele_t * ele = ele0 + ele_idx;
      25           0 :       if( fd_vinyl_meta_private_ele_is_free( ctx, ele ) ) return NULL;
      26           0 :       if( fd_vinyl_key_eq( &ele->phdr.key, key ) ) {
      27           0 :         if( FD_UNLIKELY( ele->memo != memo ) ) FD_LOG_ERR(( "memo mismatch" ));
      28           0 :         return ele;
      29           0 :       }
      30           0 :       ele_idx = (ele_idx+1UL) & (ele_max-1UL);
      31           0 :     }
      32           0 :     return NULL;
      33           0 :   }
      34           0 :   __builtin_unreachable();
      35           0 : }
      36             : 
      37             : uint
      38             : fd_accdb_fsck_vinyl( fd_vinyl_io_t *   io,
      39             :                      fd_vinyl_meta_t * meta,
      40           0 :                      uint              flags ) {
      41           0 :   _Bool const lthash = !!( flags & FD_ACCDB_FSCK_FLAGS_LTHASH );
      42             : 
      43           0 :   uint        err     = FD_ACCDB_FSCK_NO_ERROR;
      44           0 :   ulong       err_cnt =   0UL;
      45           0 :   ulong const err_max = 512UL;
      46             : 
      47             :   /* Join memory-mapped bstream */
      48             : 
      49           0 :   ulong         const io_seed     = fd_vinyl_io_seed( io );
      50           0 :   uchar const * const mmio        = fd_vinyl_mmio   ( io );
      51           0 :   ulong         const mmio_sz     = fd_vinyl_mmio_sz( io );
      52           0 :   ulong         const seq_past    = io->seq_past;
      53           0 :   ulong         const seq_present = io->seq_present;
      54           0 :   ulong         const dev_sz      = mmio_sz;
      55           0 :   FD_LOG_INFO(( "FSCK starting ... seq_past=%lu seq_present=%lu mmio_sz=%lu",
      56           0 :                 seq_past, seq_present, mmio_sz ));
      57             :   /* FIXME ASSUMING dev_sz==mmio_sz IS NOT VAILD ACCORDING TO DOCS */
      58             : 
      59           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( seq_past, FD_VINYL_BSTREAM_BLOCK_SZ ) ) ) {
      60           0 :     FD_LOG_WARNING(( "misaligned seq_past (%lu)", seq_past ));
      61           0 :     return FD_ACCDB_FSCK_INVARIANT;
      62           0 :   }
      63           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( seq_present, FD_VINYL_BSTREAM_BLOCK_SZ ) ) ) {
      64           0 :     FD_LOG_WARNING(( "misaligned seq_present (%lu)", seq_present ));
      65           0 :     return FD_ACCDB_FSCK_INVARIANT;
      66           0 :   }
      67           0 :   ulong dseq = seq_present - seq_past;
      68           0 :   if( FD_UNLIKELY( fd_vinyl_seq_gt( seq_past, seq_present ) || dseq>mmio_sz ) ) {
      69           0 :     FD_LOG_WARNING(( "invalid seq range [%lu,%lu) for mmio_sz %lu", seq_past, seq_present, mmio_sz ));
      70           0 :     return FD_ACCDB_FSCK_INVARIANT;
      71           0 :   }
      72             : 
      73             :   /* Phase 1: Scan meta map left-to-right.  Verify the following:
      74             :      - memo (key hash correct?)
      75             :      - ctl (obviously incorrect meta entry?)
      76             :      - probe_max (key outside of probe range?)
      77             :      - query (is this key visible to queries? detect duplicate)
      78             :      Mark each element as not-visited. */
      79             : 
      80           0 :   ulong                 const meta_seed   = meta->seed;
      81           0 :   fd_vinyl_meta_ele_t * const ele0        = meta->ele;
      82           0 :   ulong                 const ele_max     = meta->ele_max;
      83             : 
      84           0 :   for( ulong i=0UL; i<ele_max; i++ ) {
      85           0 :     fd_vinyl_meta_ele_t * ele = &ele0[ i ];
      86           0 :     if( FD_LIKELY( fd_vinyl_meta_private_ele_is_free( meta->ctx, ele ) ) ) continue;
      87             : 
      88           0 :     ulong memo    = fd_vinyl_key_memo( meta_seed, &ele->phdr.key );
      89           0 :     ulong val_esz = fd_vinyl_bstream_ctl_sz( ele->phdr.ctl );
      90             : 
      91           0 :     int bad_ctl   = fd_vinyl_bstream_ctl_type ( ele->phdr.ctl )!=FD_VINYL_BSTREAM_CTL_TYPE_PAIR;
      92           0 :     int bad_style = fd_vinyl_bstream_ctl_style( ele->phdr.ctl )!=FD_VINYL_BSTREAM_CTL_STYLE_RAW;
      93           0 :     int bad_memo  = memo != ele->memo;
      94           0 :     int bad_query = meta_query_fast( meta, &ele->phdr.key, ele->memo )!=ele;
      95           0 :     int bad_sz    = val_esz > sizeof(fd_account_meta_t)+FD_RUNTIME_ACC_SZ_MAX;
      96           0 :     int bad_seq0  = fd_vinyl_seq_lt( ele->seq, seq_past ) | fd_vinyl_seq_ge( ele->seq, seq_present );
      97           0 :     int bad_seq1  = fd_vinyl_seq_gt( ele->seq+fd_vinyl_bstream_pair_sz( val_esz ), seq_present );
      98             : 
      99           0 :     if( FD_UNLIKELY( bad_ctl | bad_style | bad_memo | bad_query | bad_sz | bad_seq0 | bad_seq1 ) ) {
     100           0 :       FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: index corruption detected key=" VINYL_KEY_FMT " memo=%016lx meta_idx=%lu seq=%lu err=%s",
     101           0 :                        VINYL_KEY_FMT_ARGS( ele->phdr.key ),
     102           0 :                        memo,
     103           0 :                        i,
     104           0 :                        ele->seq,
     105           0 :                        bad_ctl   ? "bad ctl"   :
     106           0 :                        bad_style ? "bad style" :
     107           0 :                        bad_memo  ? "bad memo"  :
     108           0 :                        bad_query ? "bad query" :
     109           0 :                        bad_sz    ? "bad sz"    :
     110           0 :                        bad_seq0  ? "bad seq0"  :
     111           0 :                                    "bad seq1" ));
     112           0 :       if( FD_UNLIKELY( ++err_cnt>=err_max ) ) {
     113           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: too many errors, stopping" ));
     114           0 :         return FD_ACCDB_FSCK_UNKNOWN;
     115           0 :       }
     116           0 :     }
     117             : 
     118           0 :     ele->line_idx = ULONG_MAX; /* mark not visited */
     119           0 :   }
     120             : 
     121           0 :   if( !err_cnt ) FD_LOG_INFO(( "FSCK: meta OK" ));
     122             : 
     123             :   /* Phase 2: Scan bstream past-to-present.  Mark meta elements as
     124             :      visited along the way.  Verify that:
     125             :      - meta entries match bstream blocks
     126             :      - bstream block checksums are valid */
     127             : 
     128           0 :   fd_lthash_value_t sum[1]; fd_lthash_zero( sum );
     129           0 :   fd_lthash_adder_t adder_[1];
     130           0 :   fd_lthash_adder_t * adder = NULL;
     131           0 :   if( lthash ) {
     132           0 :     adder = fd_lthash_adder_new( adder_ );
     133           0 :     FD_TEST( adder );
     134           0 :   }
     135             : 
     136           0 :   ulong seq        = seq_past;
     137           0 :   ulong seq_report = seq;
     138           0 :   while( seq<seq_present ) {
     139           0 :     if( FD_UNLIKELY( seq>=seq_report+(1UL<<30) ) ) {
     140           0 :       FD_LOG_INFO(( "FSCK progress: seq=%lu", seq ));
     141           0 :       seq_report = seq;
     142           0 :     }
     143             : 
     144             :     /* Map block to device */
     145           0 :     ulong mm_off  = seq % dev_sz;
     146           0 :     ulong dev_off = mm_off+FD_VINYL_BSTREAM_BLOCK_SZ;
     147           0 :     if( FD_UNLIKELY( mm_off+FD_VINYL_BSTREAM_BLOCK_SZ > mmio_sz ) ) {
     148           0 :       FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: bstream block crosses mmio boundary: seq=%lu dev_off=%lu", seq, dev_off ));
     149           0 :       return FD_ACCDB_FSCK_CORRUPT;
     150           0 :     }
     151             : 
     152             :     /* Interpret block */
     153           0 :     fd_vinyl_bstream_block_t block = FD_LOAD( fd_vinyl_bstream_block_t, mmio+mm_off );
     154           0 :     int ctl_type = fd_vinyl_bstream_ctl_type( block.ctl );
     155           0 :     switch( ctl_type ) {
     156             : 
     157           0 :     case FD_VINYL_BSTREAM_CTL_TYPE_PAIR: {
     158           0 :       ulong val_esz  = fd_vinyl_bstream_ctl_sz( block.ctl );
     159           0 :       ulong block_sz = fd_vinyl_bstream_pair_sz( val_esz );
     160           0 :       if( FD_UNLIKELY( block_sz<FD_VINYL_BSTREAM_BLOCK_SZ ) ) {
     161           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: bstream pair has invalid block size (%lu) at seq=%lu dev_off=%lu", block_sz, seq, dev_off ));
     162           0 :         err_cnt++;
     163           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_INVARIANT );
     164           0 :         seq += FD_VINYL_BSTREAM_BLOCK_SZ;
     165           0 :         break;
     166           0 :       }
     167           0 :       ulong seq1     = seq + block_sz;
     168           0 :       ulong dev_off1 = seq1 % dev_sz;
     169             : 
     170           0 :       if( FD_UNLIKELY( val_esz>sizeof(fd_account_meta_t)+FD_RUNTIME_ACC_SZ_MAX ) ) {
     171           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: bstream pair has invalid record size (%lu) at seq=%lu dev_off=%lu", val_esz, seq, dev_off ));
     172           0 :         err_cnt++;
     173           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_INVARIANT );
     174           0 :         goto next;
     175           0 :       }
     176           0 :       if( FD_UNLIKELY( mm_off>=dev_off1 ) ) {
     177           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: bstream pair is fragmented around bstream boundary: seq=%lu dev_off=%lu", seq, dev_off ));
     178           0 :         err_cnt++;
     179           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_INVARIANT );
     180           0 :         goto next;
     181           0 :       }
     182             : 
     183           0 :       char const * errstr = fd_vinyl_bstream_pair_test( io_seed, seq, (void *)( mmio+mm_off ), block_sz );
     184           0 :       if( FD_UNLIKELY( errstr ) ) {
     185           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: invalid pair block (%s): key=" VINYL_KEY_FMT " seq=%lu dev_off=%lu", errstr, VINYL_KEY_FMT_ARGS( block.phdr.key ), seq, dev_off ));
     186           0 :         err_cnt++;
     187           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_CORRUPT );
     188           0 :         goto next;
     189           0 :       }
     190             : 
     191           0 :       ulong memo = fd_vinyl_key_memo( meta_seed, &block.phdr.key );
     192           0 :       fd_vinyl_meta_ele_t * ele = meta_query_fast( meta, &block.phdr.key, memo );
     193           0 :       if( FD_UNLIKELY( !ele ) ) {
     194           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: bstream pair has no matching meta entry: key=" VINYL_KEY_FMT " memo=%016lx seq=%lu dev_off=%lu",
     195           0 :                          VINYL_KEY_FMT_ARGS( block.phdr.key ), memo, seq, dev_off ));
     196           0 :         err_cnt++;
     197           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_INVARIANT );
     198           0 :         goto next;
     199           0 :       }
     200           0 :       if( FD_UNLIKELY( ele->seq < seq ) ) {
     201           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: meta entry points to older bstream seq: key=" VINYL_KEY_FMT " memo=%016lx meta_seq=%lu bstream_seq=%lu dev_off=%lu",
     202           0 :                          VINYL_KEY_FMT_ARGS( block.phdr.key ), memo, ele->seq, seq, dev_off ));
     203           0 :         err_cnt++;
     204           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_INVARIANT );
     205           0 :         goto next;
     206           0 :       }
     207           0 :       if( FD_UNLIKELY( ele->seq > seq ) ) goto next;  /* ignore, assume bstream entry is stale */
     208             : 
     209             :       /* Mark as visited */
     210           0 :       if( FD_UNLIKELY( ele->line_idx==0UL ) ) {
     211           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: duplicate bstream entry detected: key=" VINYL_KEY_FMT " memo=%016lx seq=%lu dev_off=%lu",
     212           0 :                          VINYL_KEY_FMT_ARGS( block.phdr.key ), memo, seq, dev_off ));
     213           0 :         err_cnt++;
     214           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_CORRUPT );
     215           0 :         goto next;
     216           0 :       }
     217           0 :       ele->line_idx = 0UL;
     218             : 
     219           0 :       int phdr_ok = fd_memeq( &ele->phdr, &block.phdr, sizeof(fd_vinyl_bstream_phdr_t) );
     220           0 :       if( FD_UNLIKELY( !phdr_ok ) ) {
     221           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: bstream pair header mismatch at seq=%lu dev_off=%lu", seq, dev_off ));
     222           0 :         err_cnt++;
     223           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_CORRUPT );
     224           0 :       }
     225             : 
     226             :       /* At this point, found the latest revision of an account for the
     227             :          first time */
     228           0 :       fd_account_meta_t const * meta       = fd_type_pun_const( mmio+mm_off+sizeof(fd_vinyl_bstream_phdr_t) );
     229           0 :       void const *              data       = (void const *)( meta+1 );
     230           0 :       void const *              pubkey     = &ele->phdr.key.uc;
     231           0 :       ulong                     data_sz    = meta->dlen;
     232           0 :       ulong                     lamports   = meta->lamports;
     233           0 :       _Bool                     executable = !!meta->executable;
     234           0 :       void const *              owner      = meta->owner;
     235           0 :       if( lthash && FD_LIKELY( lamports ) ) {
     236           0 :         fd_lthash_adder_push_solana_account( adder, sum, pubkey, data, data_sz, lamports, executable, owner );
     237           0 :       }
     238             : 
     239           0 : next:
     240           0 :       seq = seq1;
     241           0 :       break;
     242           0 :     }
     243             : 
     244           0 :     case FD_VINYL_BSTREAM_CTL_TYPE_ZPAD: {
     245           0 :       char const * errstr = fd_vinyl_bstream_zpad_test( io_seed, seq, &block );
     246           0 :       if( FD_UNLIKELY( errstr ) ) {
     247           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: invalid zpad block (%s): seq=%lu dev_off=%lu", errstr, seq, dev_off ) );
     248           0 :         err_cnt++;
     249           0 :         err = fd_uint_max( err, FD_ACCDB_FSCK_INVARIANT );
     250           0 :       }
     251           0 :       seq += FD_VINYL_BSTREAM_BLOCK_SZ;
     252           0 :       break;
     253           0 :     }
     254             : 
     255           0 :     default:
     256           0 :       FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: unexpected block type %i at seq=%lu dev_off=%lu", ctl_type, seq, dev_off ));
     257           0 :       err_cnt++;
     258           0 :       return FD_ACCDB_FSCK_INVARIANT;
     259             : 
     260           0 :     }
     261             : 
     262           0 :     if( FD_UNLIKELY( err_cnt>=err_max ) ) {
     263           0 :       FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: too many errors, stopping" ));
     264           0 :       return FD_ACCDB_FSCK_UNKNOWN;
     265           0 :     }
     266           0 :   }
     267             : 
     268           0 :   if( FD_UNLIKELY( seq!=seq_present ) ) {
     269           0 :     FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: bstream scan ended abruptly at seq=%lu (expected %lu)", seq, seq_present ));
     270           0 :     return FD_ACCDB_FSCK_CORRUPT;
     271           0 :   }
     272             : 
     273           0 :   if( lthash ) {
     274           0 :     fd_lthash_adder_flush( adder, sum );
     275           0 :     uchar hash32[32]; fd_blake3_hash( sum->bytes, FD_LTHASH_LEN_BYTES, hash32 );
     276           0 :     FD_BASE58_ENCODE_32_BYTES( sum->bytes, sum_enc    );
     277           0 :     FD_BASE58_ENCODE_32_BYTES( hash32,     hash32_enc );
     278           0 :     FD_LOG_NOTICE(( "FSCK: lthash[..32]=%s blake3(lthash)=%s", sum_enc, hash32_enc ));
     279           0 :   }
     280             : 
     281           0 :   if( !err_cnt ) FD_LOG_INFO(( "FSCK: bstream OK" ));
     282             : 
     283             :   /* Phase 3: Scan meta map left-to-right.  Verify that all elements
     284             :      were visited. */
     285             : 
     286           0 :   for( ulong i=0UL; i<ele_max; i++ ) {
     287           0 :     fd_vinyl_meta_ele_t * ele = &ele0[ i ];
     288           0 :     if( FD_LIKELY( fd_vinyl_meta_private_ele_is_free( meta->ctx, ele ) ) ) continue;
     289           0 :     if( FD_UNLIKELY( ele->line_idx==ULONG_MAX ) ) {
     290           0 :       FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: unvisited meta entry detected"
     291           0 :                        " key=%016lx:%016lx:%016lx:%016lx"
     292           0 :                        " memo=%016lx"
     293           0 :                        " meta_idx=%lu"
     294           0 :                        " seq=%lu",
     295           0 :                        fd_ulong_bswap( ele->phdr.key.ul[0] ), fd_ulong_bswap( ele->phdr.key.ul[1] ),
     296           0 :                        fd_ulong_bswap( ele->phdr.key.ul[2] ), fd_ulong_bswap( ele->phdr.key.ul[3] ),
     297           0 :                        ele->memo, i, ele->seq ));
     298           0 :       if( FD_UNLIKELY( ++err_cnt>=err_max ) ) {
     299           0 :         FD_LOG_WARNING(( "fd_accdb_fsck_vinyl: too many errors, stopping" ));
     300           0 :         return FD_ACCDB_FSCK_UNKNOWN;
     301           0 :       }
     302           0 :       err = fd_uint_max( err, FD_ACCDB_FSCK_CORRUPT );
     303           0 :     } else {
     304           0 :       ele->line_idx = ULONG_MAX; /* reset mark */
     305           0 :     }
     306           0 :   }
     307             : 
     308           0 :   if( !err_cnt ) FD_LOG_INFO(( "FSCK: meta-bstream sync OK" ));
     309             : 
     310           0 :   return err;
     311           0 : }

Generated by: LCOV version 1.14