LCOV - code coverage report
Current view: top level - flamenco/runtime/sysvar - fd_sysvar_slot_history.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 105 0.0 %
Date: 2026-02-22 05:44:04 Functions: 0 8 0.0 %

          Line data    Source code
       1             : #include "fd_sysvar_slot_history.h"
       2             : #include "fd_sysvar.h"
       3             : #include "../fd_system_ids.h"
       4             : #include "../../accdb/fd_accdb_sync.h"
       5             : 
       6             : /* FIXME These constants should be header defines */
       7             : 
       8             : /* TODO: move into separate bitvec library */
       9           0 : #define FD_SLOT_HISTORY_BITS_PER_BLOCK (8UL * sizeof(ulong))
      10             : 
      11           0 : #define FD_SLOT_HISTORY_BLOCKS_LEN (FD_SLOT_HISTORY_MAX_ENTRIES / FD_SLOT_HISTORY_BITS_PER_BLOCK)
      12             : 
      13             : void
      14             : fd_sysvar_slot_history_set( fd_slot_history_global_t * history,
      15           0 :                             ulong                      i ) {
      16           0 :   if( FD_UNLIKELY( i > history->next_slot && i - history->next_slot >= FD_SLOT_HISTORY_MAX_ENTRIES ) ) {
      17           0 :     FD_LOG_WARNING(( "Ignoring out of bounds (i=%lu next_slot=%lu)", i, history->next_slot ));
      18           0 :     return;
      19           0 :   }
      20             : 
      21           0 :   ulong * blocks     = (ulong *)((uchar*)history + history->bits_bitvec_offset);
      22           0 :   ulong   blocks_len = history->bits_bitvec_len;
      23             : 
      24             :   // Skipped slots, delete them from history
      25           0 :   if( FD_UNLIKELY( blocks_len == 0 ) ) return;
      26           0 :   for( ulong j = history->next_slot; j < i; j++ ) {
      27           0 :     ulong block_idx = (j / FD_SLOT_HISTORY_BITS_PER_BLOCK) % (blocks_len);
      28           0 :     blocks[ block_idx ] &= ~( 1UL << ( j % FD_SLOT_HISTORY_BITS_PER_BLOCK ) );
      29           0 :   }
      30           0 :   ulong block_idx = (i / FD_SLOT_HISTORY_BITS_PER_BLOCK) % (blocks_len);
      31           0 :   blocks[ block_idx ] |= ( 1UL << ( i % FD_SLOT_HISTORY_BITS_PER_BLOCK ) );
      32           0 : }
      33             : 
      34             : 
      35             : void
      36             : fd_sysvar_slot_history_write_history( fd_bank_t *                bank,
      37             :                                       fd_accdb_user_t *          accdb,
      38             :                                       fd_funk_txn_xid_t const *  xid,
      39             :                                       fd_capture_ctx_t *         capture_ctx,
      40           0 :                                       fd_slot_history_global_t * history ) {
      41           0 :   uchar __attribute__((aligned(FD_SYSVAR_SLOT_HISTORY_ALIGN))) slot_history_mem[ FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ ] = {0};
      42           0 :   fd_bincode_encode_ctx_t ctx = {
      43           0 :     .data    = slot_history_mem,
      44           0 :     .dataend = slot_history_mem + FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ
      45           0 :   };
      46           0 :   int err = fd_slot_history_encode_global( history, &ctx );
      47           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) FD_LOG_ERR(( "fd_slot_history_encode_global failed" ));
      48           0 :   fd_sysvar_account_update( bank, accdb, xid, capture_ctx, &fd_sysvar_slot_history_id, slot_history_mem, FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ );
      49           0 : }
      50             : 
      51             : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L16 */
      52             : 
      53             : void
      54             : fd_sysvar_slot_history_init( fd_bank_t *               bank,
      55             :                              fd_accdb_user_t *         accdb,
      56             :                              fd_funk_txn_xid_t const * xid,
      57           0 :                              fd_capture_ctx_t *        capture_ctx ) {
      58             :   /* Create a new slot history instance */
      59             : 
      60             :   /* We need to construct the gaddr-aware slot history object */
      61           0 :   uchar __attribute__((aligned(FD_SYSVAR_SLOT_HISTORY_ALIGN))) slot_history_mem[ FD_SYSVAR_SLOT_HISTORY_FOOTPRINT ] = {0};
      62           0 :   fd_slot_history_global_t * history = (fd_slot_history_global_t *)slot_history_mem;
      63           0 :   ulong *                    blocks  = (ulong *)fd_ulong_align_up( (ulong)((uchar*)history + sizeof(fd_slot_history_global_t)), alignof(ulong) );
      64             : 
      65           0 :   history->next_slot          = fd_bank_slot_get( bank ) + 1UL;
      66           0 :   history->bits_bitvec_offset = (ulong)((uchar*)blocks - (uchar*)history);
      67           0 :   history->bits_len           = FD_SLOT_HISTORY_MAX_ENTRIES;
      68           0 :   history->bits_bitvec_len    = FD_SLOT_HISTORY_BLOCKS_LEN;
      69           0 :   history->has_bits           = 1;
      70             : 
      71             :   /* TODO: handle slot != 0 init case */
      72           0 :   fd_sysvar_slot_history_set( history, fd_bank_slot_get( bank ) );
      73           0 :   fd_sysvar_slot_history_write_history( bank, accdb, xid, capture_ctx, history );
      74           0 : }
      75             : 
      76             : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/bank.rs#L2345 */
      77             : int
      78             : fd_sysvar_slot_history_update( fd_bank_t *               bank,
      79             :                                fd_accdb_user_t *         accdb,
      80             :                                fd_funk_txn_xid_t const * xid,
      81           0 :                                fd_capture_ctx_t *        capture_ctx ) {
      82             :   /* Set current_slot, and update next_slot */
      83           0 :   fd_pubkey_t const * key = &fd_sysvar_slot_history_id;
      84             : 
      85           0 :   fd_accdb_ro_t ro[1];
      86           0 :   if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, ro, xid, key ) ) ) FD_LOG_ERR(( "slot history account does not exist, cannot continue" ));
      87           0 :   fd_bincode_decode_ctx_t ctx = {
      88           0 :     .data    = fd_accdb_ref_data_const( ro ),
      89           0 :     .dataend = (uchar const *)fd_accdb_ref_data_const( ro ) + fd_accdb_ref_data_sz( ro )
      90           0 :   };
      91             : 
      92           0 :   uchar __attribute__((aligned(FD_SYSVAR_SLOT_HISTORY_ALIGN))) slot_history_mem[ FD_SYSVAR_SLOT_HISTORY_FOOTPRINT ] = {0};
      93           0 :   fd_slot_history_global_t * history = fd_slot_history_decode_global( slot_history_mem, &ctx );
      94           0 :   if( FD_UNLIKELY( !history ) ) FD_LOG_HEXDUMP_ERR(( "corrupt slot history sysvar", fd_accdb_ref_data_const( ro ), fd_accdb_ref_data_sz( ro ) ));
      95           0 :   fd_accdb_close_ro( accdb, ro );
      96             : 
      97             :   /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L48 */
      98           0 :   fd_sysvar_slot_history_set( history, fd_bank_slot_get( bank ) );
      99           0 :   history->next_slot = fd_bank_slot_get( bank ) + 1;
     100             : 
     101           0 :   fd_sysvar_slot_history_write_history( bank, accdb, xid, capture_ctx, history );
     102             : 
     103           0 :   return 0;
     104           0 : }
     105             : 
     106             : fd_slot_history_global_t *
     107             : fd_sysvar_slot_history_read( fd_accdb_user_t *         accdb,
     108             :                              fd_funk_txn_xid_t const * xid,
     109           0 :                              uchar                     out_mem[ static FD_SYSVAR_SLOT_HISTORY_FOOTPRINT ] ) {
     110             :   /* Set current_slot, and update next_slot */
     111             : 
     112           0 :   fd_pubkey_t const * key = &fd_sysvar_slot_history_id;
     113             : 
     114           0 :   fd_accdb_ro_t ro[1];
     115           0 :   if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, ro, xid, key ) ) ) {
     116           0 :     FD_LOG_CRIT(( "slot history account does not exist, cannot continue" ));
     117           0 :   }
     118             : 
     119             :   /* This check is needed as a quirk of the fuzzer. If a sysvar account
     120             :      exists in the accounts database, but doesn't have any lamports,
     121             :      this means that the account does not exist. This wouldn't happen
     122             :      in a real execution environment. */
     123           0 :   if( FD_UNLIKELY( fd_accdb_ref_lamports( ro )==0UL ) ) {
     124           0 :     fd_accdb_close_ro( accdb, ro );
     125           0 :     return NULL;
     126           0 :   }
     127             : 
     128           0 :   ulong data_len = fd_accdb_ref_data_sz( ro );
     129           0 :   if( FD_UNLIKELY( data_len>FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ ) ) {
     130           0 :     FD_LOG_ERR(( "corrupt slot history sysvar: sysvar data is too large (%lu bytes)", data_len ));
     131           0 :   }
     132             : 
     133           0 :   fd_bincode_decode_ctx_t ctx = {
     134           0 :     .data    = fd_accdb_ref_data_const( ro ),
     135           0 :     .dataend = (uchar const *)fd_accdb_ref_data_const( ro ) + fd_accdb_ref_data_sz( ro )
     136           0 :   };
     137           0 :   fd_slot_history_global_t * history = fd_slot_history_decode_global( out_mem, &ctx );
     138           0 :   fd_accdb_close_ro( accdb, ro );
     139           0 :   return history;
     140           0 : }
     141             : 
     142             : int
     143             : fd_sysvar_slot_history_find_slot( fd_slot_history_global_t const * history,
     144           0 :                                   ulong                            slot ) {
     145             : 
     146           0 :   ulong * blocks = (ulong *)((uchar*)history + history->bits_bitvec_offset);
     147           0 :   if( FD_UNLIKELY( !blocks ) ) {
     148           0 :     FD_LOG_ERR(( "Unable to find slot history blocks" ));
     149           0 :   }
     150           0 :   ulong blocks_len = history->bits_bitvec_len;
     151             : 
     152           0 :   if( slot > history->next_slot - 1UL ) {
     153           0 :     return FD_SLOT_HISTORY_SLOT_FUTURE;
     154           0 :   } else if ( slot < fd_ulong_sat_sub( history->next_slot, FD_SLOT_HISTORY_MAX_ENTRIES ) ) {
     155           0 :     return FD_SLOT_HISTORY_SLOT_TOO_OLD;
     156           0 :   } else {
     157           0 :     ulong block_idx = (slot / FD_SLOT_HISTORY_BITS_PER_BLOCK) % blocks_len;
     158           0 :     if( blocks[ block_idx ] & ( 1UL << ( slot % FD_SLOT_HISTORY_BITS_PER_BLOCK ) ) ) {
     159           0 :       return FD_SLOT_HISTORY_SLOT_FOUND;
     160           0 :     } else {
     161           0 :       return FD_SLOT_HISTORY_SLOT_NOT_FOUND;
     162           0 :     }
     163           0 :   }
     164           0 : }
     165             : 
     166             : ulong
     167           0 : fd_sysvar_slot_history_newest( fd_slot_history_global_t const * history ) {
     168           0 :   FD_TEST( history->has_bits );
     169           0 :   return history->next_slot - 1UL;
     170           0 : }
     171             : 
     172             : ulong
     173           0 : fd_sysvar_slot_history_len( fd_slot_history_global_t const * history ) {
     174           0 :   FD_TEST( history->has_bits );
     175           0 :   return history->bits_len;
     176           0 : }

Generated by: LCOV version 1.14