LCOV - code coverage report
Current view: top level - flamenco/runtime/sysvar - fd_sysvar_recent_hashes.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 69 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 4 0.0 %

          Line data    Source code
       1             : #include <stdio.h>
       2             : #include "../fd_acc_mgr.h"
       3             : #include "../fd_hashes.h"
       4             : #include "fd_sysvar.h"
       5             : #include "../fd_runtime.h"
       6             : #include "../fd_system_ids.h"
       7             : #include "../context/fd_exec_slot_ctx.h"
       8             : 
       9           0 : #define FD_RECENT_BLOCKHASHES_ACCOUNT_MAX_SIZE  sizeof(ulong) + FD_RECENT_BLOCKHASHES_MAX_ENTRIES * (sizeof(fd_hash_t) + sizeof(ulong))
      10             : 
      11             : // run --ledger /home/jsiegel/test-ledger --db /home/jsiegel/funk --cmd accounts --accounts /home/jsiegel/test-ledger/accounts/ --pages 15 --index-max 120000000 --start-slot 2 --end-slot 2 --start-id 35 --end-id 37
      12             : // run --ledger /home/jsiegel/test-ledger --db /home/jsiegel/funk --cmd replay --pages 15 --index-max 120000000 --start-slot 0 --end-slot 3
      13             : 
      14             : // {meta = {write_version_obsolete = 137,
      15             : // data_len = 6008, pubkey = "\006\247\325\027\031,V\216\340\212\204_sҗ\210\317\003\\1E\262\032\263D\330\006.\251@\000"}, info = {lamports = 42706560, rent_epoch = 0, owner = "\006\247\325\027\030u\367)\307=\223@\217!a \006~،v\340\214(\177\301\224`\000\000\000", executable = 0 '\000', padding = "K\000\f\376\177\000"}, hash = {value = "\302Q\316\035qTY\347\352]\260\335\213\224R\227ԯ\366R\273\063H\345֑c\377\207/k\275"}}
      16             : 
      17             : // owner:      Sysvar1111111111111111111111111111111111111 pubkey:      SysvarRecentB1ockHashes11111111111111111111 hash:     E5YSehyvJ7xXcNnQjWCH9UhMJ1dxDBJ1RuuPh1Y3RZgg file: /home/jsiegel/test-ledger/accounts//2.37
      18             : //   {blockhash = JCidNXtcMXMWQwMDM3ZQq5pxaw3hQpNbeHg1KcstjuF4,  fee_calculator={lamports_per_signature = 5000}}
      19             : //   {blockhash = GQN3oV8G1Ra3GCX76dE1YYJ6UjMyDreNCEWM4tZ39zj1,  fee_calculator={lamports_per_signature = 5000}}
      20             : //   {blockhash = Ha5DVgnD1xSA8oQc337jtA3atEfQ4TFX1ajeZG1Y2tUx,  fee_calculator={lamports_per_signature = 0}}
      21             : 
      22             : /* Skips fd_types encoding preflight checks and directly serializes the blockhash queue into a buffer representing
      23             :    account data for the recent blockhashes sysvar. */
      24             : static void
      25           0 : encode_rbh_from_blockhash_queue( fd_exec_slot_ctx_t * slot_ctx, uchar * enc ) {
      26             :   /* recent_blockhashes_account::update_account's `take` call takes at most 150 elements
      27             :      https://github.com/anza-xyz/agave/blob/v2.1.6/runtime/src/bank/recent_blockhashes_account.rs#L15-L28 */
      28           0 :   fd_block_hash_queue_t const * queue = &slot_ctx->slot_bank.block_hash_queue;
      29           0 :   ulong queue_sz                      = fd_hash_hash_age_pair_t_map_size( queue->ages_pool, queue->ages_root );
      30           0 :   ulong hashes_len                    = fd_ulong_min( queue_sz, FD_RECENT_BLOCKHASHES_MAX_ENTRIES );
      31           0 :   fd_memcpy( enc, &hashes_len, sizeof(ulong) );
      32           0 :   enc += sizeof(ulong);
      33             : 
      34             :   /* Iterate over blockhash queue and encode the recent blockhashes. We can do direct memcpying
      35             :      and avoid redundant checks from fd_types encoders since the enc buffer is already sized out to
      36             :      the worst-case bound. */
      37           0 :   fd_hash_hash_age_pair_t_mapnode_t const * nn;
      38           0 :   for( fd_hash_hash_age_pair_t_mapnode_t const * n = fd_hash_hash_age_pair_t_map_minimum_const( queue->ages_pool, queue->ages_root ); n; n = nn ) {
      39           0 :     nn = fd_hash_hash_age_pair_t_map_successor_const( queue->ages_pool, n );
      40           0 :     ulong enc_idx = queue->last_hash_index - n->elem.val.hash_index;
      41           0 :     if( enc_idx>=hashes_len ) {
      42           0 :       continue;
      43           0 :     }
      44           0 :     fd_hash_t hash = n->elem.key;
      45           0 :     ulong     lps  = n->elem.val.fee_calculator.lamports_per_signature;
      46             : 
      47           0 :     fd_memcpy( enc + enc_idx * (FD_HASH_FOOTPRINT + sizeof(ulong)), &hash, FD_HASH_FOOTPRINT );
      48           0 :     fd_memcpy( enc + enc_idx * (FD_HASH_FOOTPRINT + sizeof(ulong)) + sizeof(fd_hash_t), &lps, sizeof(ulong) );
      49           0 :   }
      50           0 : }
      51             : 
      52             : // https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/fee_calculator.rs#L110
      53             : void
      54             : fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx,
      55           0 :                               fd_spad_t *          runtime_spad ) {
      56             : 
      57           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
      58             : 
      59           0 :   if( slot_ctx->slot_bank.slot != 0 ) {
      60           0 :     return;
      61           0 :   }
      62             : 
      63           0 :   ulong   sz  = FD_RECENT_BLOCKHASHES_ACCOUNT_MAX_SIZE;
      64           0 :   uchar * enc = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, sz );
      65           0 :   fd_memset( enc, 0, sz );
      66           0 :   encode_rbh_from_blockhash_queue( slot_ctx, enc );
      67           0 :   fd_sysvar_set( slot_ctx, fd_sysvar_owner_id.key, &fd_sysvar_recent_block_hashes_id, enc, sz, slot_ctx->slot_bank.slot );
      68             : 
      69           0 :   } FD_SPAD_FRAME_END;
      70           0 : }
      71             : 
      72             : // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L113
      73             : static void
      74           0 : register_blockhash( fd_exec_slot_ctx_t * slot_ctx, fd_hash_t const * hash ) {
      75           0 :   fd_block_hash_queue_t * queue = &slot_ctx->slot_bank.block_hash_queue;
      76             :   // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L114
      77           0 :   queue->last_hash_index++;
      78           0 :   if ( fd_hash_hash_age_pair_t_map_size( queue->ages_pool, queue->ages_root ) >= queue->max_age ) {
      79           0 :     fd_hash_hash_age_pair_t_mapnode_t * nn;
      80           0 :     for ( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum( queue->ages_pool, queue->ages_root ); n; n = nn ) {
      81           0 :       nn = fd_hash_hash_age_pair_t_map_successor( queue->ages_pool, n );
      82             :       /* NOTE: Yes, this check is incorrect. It should be >= which caps the blockhash queue at max_age
      83             :          entries, but instead max_age + 1 entries are allowed to exist in the queue at once. This mimics
      84             :          Agave to stay conformant with their implementation.
      85             :          https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L109 */
      86           0 :       if ( queue->last_hash_index - n->elem.val.hash_index > queue->max_age ) {
      87           0 :         fd_hash_hash_age_pair_t_map_remove( queue->ages_pool, &queue->ages_root, n );
      88           0 :         fd_hash_hash_age_pair_t_map_release( queue->ages_pool, n );
      89           0 :       }
      90           0 :     }
      91           0 :   }
      92             : 
      93           0 :   fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( queue->ages_pool );
      94           0 :   node->elem = (fd_hash_hash_age_pair_t){
      95           0 :     .key = *hash,
      96           0 :     .val = (fd_hash_age_t){ .hash_index = queue->last_hash_index, .fee_calculator = (fd_fee_calculator_t){.lamports_per_signature = slot_ctx->slot_bank.lamports_per_signature}, .timestamp = (ulong)fd_log_wallclock() }
      97           0 :   };
      98             :   // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L121-L128
      99           0 :   fd_hash_hash_age_pair_t_map_insert( slot_ctx->slot_bank.block_hash_queue.ages_pool, &slot_ctx->slot_bank.block_hash_queue.ages_root, node );
     100             :   // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L130
     101           0 :   fd_memcpy( queue->last_hash, hash, sizeof(fd_hash_t) );
     102           0 : }
     103             : 
     104             : /* This implementation is more consistent with Agave's bank implementation for updating the block hashes sysvar:
     105             :    1. Update the block hash queue with the latest poh
     106             :    2. Take the first 150 blockhashes from the queue (or fewer if there are)
     107             :    3. Manually serialize the recent blockhashes
     108             :    4. Set the sysvar account with the new data */
     109             : void
     110           0 : fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) {
     111           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
     112             :   /* Update the blockhash queue */
     113           0 :   register_blockhash( slot_ctx, &slot_ctx->slot_bank.poh );
     114             : 
     115             :   /* Derive the new sysvar recent blockhashes from the blockhash queue */
     116           0 :   ulong   sz        = FD_RECENT_BLOCKHASHES_ACCOUNT_MAX_SIZE;
     117           0 :   uchar * enc       = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, sz );
     118           0 :   uchar * enc_start = enc;
     119           0 :   fd_memset( enc, 0, sz );
     120             : 
     121             :   /* Encode the recent blockhashes */
     122           0 :   encode_rbh_from_blockhash_queue( slot_ctx, enc );
     123             : 
     124             :   /* Set the sysvar from the encoded data */
     125           0 :   fd_sysvar_set( slot_ctx,
     126           0 :                  fd_sysvar_owner_id.key,
     127           0 :                  &fd_sysvar_recent_block_hashes_id,
     128           0 :                  enc_start,
     129           0 :                  sz,
     130           0 :                  slot_ctx->slot_bank.slot );
     131           0 :   } FD_SPAD_FRAME_END;
     132           0 : }

Generated by: LCOV version 1.14