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 130 0.0 %
Date: 2025-08-05 05:04:49 Functions: 0 6 0.0 %

          Line data    Source code
       1             : #include "fd_sysvar_slot_history.h"
       2             : #include "fd_sysvar.h"
       3             : #include "fd_sysvar_rent.h"
       4             : #include "../fd_system_ids.h"
       5             : #include "../fd_txn_account.h"
       6             : #include "../../../funk/fd_funk_txn.h"
       7             : 
       8             : /* FIXME These constants should be header defines */
       9             : 
      10             : static const ulong slot_history_min_account_size = 131097;
      11             : 
      12             : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L37 */
      13             : static const ulong slot_history_max_entries = 1024 * 1024;
      14             : 
      15             : /* TODO: move into separate bitvec library */
      16             : static const ulong bits_per_block = 8 * sizeof(ulong);
      17             : 
      18             : void
      19             : fd_sysvar_slot_history_set( fd_slot_history_global_t * history,
      20           0 :                             ulong                      i ) {
      21           0 :   if( FD_UNLIKELY( i > history->next_slot && i - history->next_slot >= slot_history_max_entries ) ) {
      22           0 :     FD_LOG_WARNING(( "Ignoring out of bounds (i=%lu next_slot=%lu)", i, history->next_slot ));
      23           0 :     return;
      24           0 :   }
      25             : 
      26           0 :   ulong * blocks     = (ulong *)((uchar*)history + history->bits_bitvec_offset);
      27           0 :   ulong   blocks_len = history->bits_bitvec_len;
      28             : 
      29             :   // Skipped slots, delete them from history
      30           0 :   if( FD_UNLIKELY( blocks_len == 0 ) ) return;
      31           0 :   for( ulong j = history->next_slot; j < i; j++ ) {
      32           0 :     ulong block_idx = (j / bits_per_block) % (blocks_len);
      33           0 :     blocks[ block_idx ] &= ~( 1UL << ( j % bits_per_block ) );
      34           0 :   }
      35           0 :   ulong block_idx = (i / bits_per_block) % (blocks_len);
      36           0 :   blocks[ block_idx ] |= ( 1UL << ( i % bits_per_block ) );
      37           0 : }
      38             : 
      39             : FD_FN_UNUSED static const ulong blocks_len = slot_history_max_entries / bits_per_block;
      40             : 
      41             : void
      42             : fd_sysvar_slot_history_write_history( fd_exec_slot_ctx_t *       slot_ctx,
      43           0 :                                       fd_slot_history_global_t * history ) {
      44           0 :   ulong sz = slot_history_min_account_size;
      45           0 :   uchar enc[ sz ];
      46           0 :   fd_memset( enc, 0, sz );
      47           0 :   fd_bincode_encode_ctx_t ctx;
      48           0 :   ctx.data    = enc;
      49           0 :   ctx.dataend = enc + sz;
      50           0 :   int err = fd_slot_history_encode_global( history, &ctx );
      51           0 :   if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) FD_LOG_ERR(( "fd_slot_history_encode_global failed" ));
      52           0 :   fd_sysvar_account_update( slot_ctx, &fd_sysvar_slot_history_id, enc, sz );
      53           0 : }
      54             : 
      55             : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L16 */
      56             : 
      57             : void
      58           0 : fd_sysvar_slot_history_init( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
      59           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
      60             :   /* Create a new slot history instance */
      61             : 
      62             :   /* We need to construct the gaddr-aware slot history object */
      63           0 :   ulong total_sz = sizeof(fd_slot_history_global_t) + alignof(fd_slot_history_global_t) +
      64           0 :                    (sizeof(ulong) + alignof(ulong)) * blocks_len;
      65             : 
      66           0 :   uchar * mem = fd_spad_alloc( runtime_spad, alignof(fd_slot_history_global_t), total_sz );
      67           0 :   fd_slot_history_global_t * history = (fd_slot_history_global_t *)mem;
      68           0 :   ulong *                    blocks  = (ulong *)fd_ulong_align_up( (ulong)((uchar*)history + sizeof(fd_slot_history_global_t)), alignof(ulong) );
      69             : 
      70           0 :   history->next_slot          = fd_bank_slot_get( slot_ctx->bank ) + 1UL;
      71           0 :   history->bits_bitvec_offset = (ulong)((uchar*)blocks - (uchar*)history);
      72           0 :   history->bits_len           = slot_history_max_entries;
      73           0 :   history->bits_bitvec_len    = blocks_len;
      74           0 :   history->has_bits           = 1;
      75           0 :   memset( blocks, 0, sizeof(ulong) * blocks_len );
      76             : 
      77             :   /* TODO: handle slot != 0 init case */
      78           0 :   fd_sysvar_slot_history_set( history, fd_bank_slot_get( slot_ctx->bank ) );
      79           0 :   fd_sysvar_slot_history_write_history( slot_ctx, history );
      80           0 :   } FD_SPAD_FRAME_END;
      81           0 : }
      82             : 
      83             : /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/bank.rs#L2345 */
      84             : int
      85           0 : fd_sysvar_slot_history_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
      86             :   /* Set current_slot, and update next_slot */
      87             : 
      88           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
      89             : 
      90           0 :   fd_pubkey_t const * key = &fd_sysvar_slot_history_id;
      91             : 
      92           0 :   FD_TXN_ACCOUNT_DECL( rec );
      93           0 :   int err = fd_txn_account_init_from_funk_readonly( rec, key, slot_ctx->funk, slot_ctx->funk_txn );
      94           0 :   if (err)
      95           0 :     FD_LOG_CRIT(( "fd_txn_account_init_from_funk_readonly(slot_history) failed: %d", err ));
      96             : 
      97           0 :   fd_bincode_decode_ctx_t ctx = {
      98           0 :     .data    = rec->vt->get_data( rec ),
      99           0 :     .dataend = rec->vt->get_data( rec ) + rec->vt->get_data_len( rec )
     100           0 :   };
     101             : 
     102           0 :   ulong total_sz = 0UL;
     103           0 :   err = fd_slot_history_decode_footprint( &ctx, &total_sz );
     104           0 :   if( FD_UNLIKELY( err ) ) {
     105           0 :     FD_LOG_CRIT(( "fd_slot_history_decode_footprint failed %d", err ));
     106           0 :   }
     107             : 
     108           0 :   uchar * mem = fd_spad_alloc( runtime_spad, fd_slot_history_align(), total_sz );
     109           0 :   if( FD_UNLIKELY( !mem ) ) {
     110           0 :     FD_LOG_CRIT(( "Unable to allocate memory for slot history" ));
     111           0 :   }
     112             : 
     113           0 :   fd_slot_history_global_t * history = fd_slot_history_decode_global( mem, &ctx );
     114             : 
     115             :   /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L48 */
     116           0 :   fd_sysvar_slot_history_set( history, fd_bank_slot_get( slot_ctx->bank ) );
     117           0 :   history->next_slot = fd_bank_slot_get( slot_ctx->bank ) + 1;
     118             : 
     119           0 :   ulong sz = fd_ulong_max( rec->vt->get_data_len( rec ), slot_history_min_account_size );
     120           0 :   err = fd_txn_account_init_from_funk_mutable( rec, key, slot_ctx->funk, slot_ctx->funk_txn, 0, sz );
     121           0 :   if (err)
     122           0 :     FD_LOG_CRIT(( "fd_txn_account_init_from_funk_mutable(slot_history) failed: %d", err ));
     123             : 
     124           0 :   fd_bincode_encode_ctx_t e_ctx = {
     125           0 :     .data    = rec->vt->get_data_mut( rec ),
     126           0 :     .dataend = rec->vt->get_data_mut( rec )+sz,
     127           0 :   };
     128             : 
     129           0 :   if( FD_UNLIKELY( fd_slot_history_encode_global( history, &e_ctx ) ) ) {
     130           0 :     FD_LOG_ERR(( "fd_slot_history_encode_global failed" ));
     131           0 :   }
     132             : 
     133           0 :   fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank );
     134           0 :   rec->vt->set_lamports( rec, fd_rent_exempt_minimum_balance( rent, sz ) );
     135             : 
     136           0 :   rec->vt->set_data_len( rec, sz );
     137           0 :   rec->vt->set_owner( rec, &fd_sysvar_owner_id );
     138             : 
     139           0 :   fd_txn_account_mutable_fini( rec, slot_ctx->funk, slot_ctx->funk_txn );
     140             : 
     141           0 :   return 0;
     142             : 
     143           0 :   } FD_SPAD_FRAME_END;
     144           0 : }
     145             : 
     146             : fd_slot_history_global_t *
     147             : fd_sysvar_slot_history_read( fd_funk_t *     funk,
     148             :                              fd_funk_txn_t * funk_txn,
     149           0 :                              fd_spad_t *     spad ) {
     150             : 
     151             :   /* Set current_slot, and update next_slot */
     152             : 
     153           0 :   fd_pubkey_t const * key = &fd_sysvar_slot_history_id;
     154             : 
     155           0 :   FD_TXN_ACCOUNT_DECL( rec );
     156           0 :   int err = fd_txn_account_init_from_funk_readonly( rec, key, funk, funk_txn );
     157           0 :   if( err ) {
     158           0 :     FD_LOG_CRIT(( "fd_txn_account_init_from_funk_readonly(slot_history) failed: %d", err ));
     159           0 :   }
     160             : 
     161             :   /* This check is needed as a quirk of the fuzzer. If a sysvar account
     162             :      exists in the accounts database, but doesn't have any lamports,
     163             :      this means that the account does not exist. This wouldn't happen
     164             :      in a real execution environment. */
     165           0 :   if( FD_UNLIKELY( rec->vt->get_lamports( rec ) == 0UL ) ) {
     166           0 :     return NULL;
     167           0 :   }
     168             : 
     169           0 :   fd_bincode_decode_ctx_t ctx = {
     170           0 :     .data    = rec->vt->get_data( rec ),
     171           0 :     .dataend = rec->vt->get_data( rec ) + rec->vt->get_data_len( rec )
     172           0 :   };
     173             : 
     174           0 :   ulong total_sz = 0UL;
     175           0 :   err = fd_slot_history_decode_footprint( &ctx, &total_sz );
     176           0 :   if( err ) {
     177           0 :     FD_LOG_ERR(( "fd_slot_history_decode_footprint failed" ));
     178           0 :   }
     179             : 
     180           0 :   uchar * mem = fd_spad_alloc( spad, fd_slot_history_align(), total_sz );
     181           0 :   if( !mem ) {
     182           0 :     FD_LOG_ERR(( "Unable to allocate memory for slot history" ));
     183           0 :   }
     184             : 
     185           0 :   return fd_slot_history_decode_global( mem, &ctx );
     186           0 : }
     187             : 
     188             : int
     189             : fd_sysvar_slot_history_find_slot( fd_slot_history_global_t const * history,
     190             :                                   ulong                            slot,
     191           0 :                                   fd_wksp_t *                      wksp ) {
     192           0 :   (void)wksp;
     193           0 :   ulong * blocks = (ulong *)((uchar*)history + history->bits_bitvec_offset);
     194           0 :   if( FD_UNLIKELY( !blocks ) ) {
     195           0 :     FD_LOG_ERR(( "Unable to find slot history blocks" ));
     196           0 :   }
     197           0 :   ulong blocks_len = history->bits_bitvec_len;
     198             : 
     199             : 
     200           0 :   if( slot > history->next_slot - 1UL ) {
     201           0 :     return FD_SLOT_HISTORY_SLOT_FUTURE;
     202           0 :   } else if ( slot < fd_ulong_sat_sub( history->next_slot, slot_history_max_entries ) ) {
     203           0 :     return FD_SLOT_HISTORY_SLOT_TOO_OLD;
     204           0 :   } else {
     205           0 :     ulong block_idx = (slot / bits_per_block) % blocks_len;
     206           0 :     if( blocks[ block_idx ] & ( 1UL << ( slot % bits_per_block ) ) ) {
     207           0 :       return FD_SLOT_HISTORY_SLOT_FOUND;
     208           0 :     } else {
     209           0 :       return FD_SLOT_HISTORY_SLOT_NOT_FOUND;
     210           0 :     }
     211           0 :   }
     212           0 : }

Generated by: LCOV version 1.14