LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_svm_mini.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 461 521 88.5 %
Date: 2026-06-01 09:39:41 Functions: 15 17 88.2 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fd_svm_mini.h"
       3             : #include "../../accdb/fd_accdb_admin_v1.h"
       4             : #include "../../accdb/fd_accdb_sync.h"
       5             : #include "../../accdb/fd_accdb_impl_v1.h"
       6             : #include "../../accdb/fd_accdb_funk.h"
       7             : #include "../../progcache/fd_progcache_admin.h"
       8             : #include "../../progcache/fd_progcache_user.h"
       9             : #include "../../runtime/fd_bank.h"
      10             : #include "../../runtime/program/fd_builtin_programs.h"
      11             : #include "../../runtime/fd_system_ids.h"
      12             : #include "../../runtime/fd_runtime_const.h"
      13             : #include "../../log_collector/fd_log_collector.h"
      14             : #include "../../runtime/fd_runtime.h"
      15             : #include "../../runtime/sysvar/fd_sysvar_cache.h"
      16             : #include "../../runtime/sysvar/fd_sysvar_rent.h"
      17             : #include "../../runtime/sysvar/fd_sysvar_epoch_schedule.h"
      18             : #include "../../runtime/sysvar/fd_sysvar_slot_history.h"
      19             : #include "../../runtime/program/fd_vote_program.h"
      20             : #include "../../stakes/fd_stake_types.h"
      21             : #include "../../stakes/fd_vote_stakes.h"
      22             : #include "../../stakes/fd_stake_delegations.h"
      23             : #include "../../stakes/fd_top_votes.h"
      24             : #include "../../leaders/fd_leaders.h"
      25             : #include <errno.h>
      26             : #include <stdlib.h>
      27             : #include <sys/mman.h>
      28             : 
      29             : static fd_wksp_t *
      30           0 : fd_wksp_new_lazy( ulong footprint ) {
      31           0 :   footprint = fd_ulong_align_up( footprint, FD_SHMEM_NORMAL_PAGE_SZ );
      32           0 :   void * mem = mmap( NULL, footprint, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );
      33           0 :   if( FD_UNLIKELY( mem==MAP_FAILED ) ) {
      34           0 :     FD_LOG_ERR(( "mmap(NULL,%lu KiB,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS) failed (%i-%s)",
      35           0 :                  footprint>>10, errno, fd_io_strerror( errno ) ));
      36           0 :   }
      37             : 
      38           0 :   ulong part_max = fd_wksp_part_max_est( footprint, 64UL<<10 );
      39           0 :   FD_TEST( part_max );
      40           0 :   ulong data_max = fd_wksp_data_max_est( footprint, part_max );
      41           0 :   FD_TEST( data_max );
      42           0 :   fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, "wksp", 1U, part_max, data_max ) );
      43           0 :   FD_TEST( wksp );
      44             : 
      45           0 :   FD_TEST( 0==fd_shmem_join_anonymous( "wksp", FD_SHMEM_JOIN_MODE_READ_WRITE, wksp, mem, FD_SHMEM_NORMAL_PAGE_SZ, footprint>>FD_SHMEM_NORMAL_LG_PAGE_SZ ) );
      46           0 :   return wksp;
      47           0 : }
      48             : 
      49             : fd_svm_mini_t *
      50             : fd_svm_test_boot( int *    pargc,
      51             :                   char *** pargv,
      52          30 :                   fd_svm_mini_limits_t const * limits ) {
      53             : 
      54          30 :   fd_boot( pargc, pargv );
      55             : 
      56          30 :   char const * page_sz_cstr = fd_env_strip_cmdline_cstr ( pargc, pargv, "--page-sz",  NULL, NULL            );
      57          30 :   ulong        page_cnt     = fd_env_strip_cmdline_ulong( pargc, pargv, "--page-cnt", NULL, 0UL             );
      58          30 :   char const * wksp_name    = fd_env_strip_cmdline_cstr ( pargc, pargv, "--wksp",     NULL, NULL            );
      59          30 :   ulong        near_cpu     = fd_env_strip_cmdline_ulong( pargc, pargv, "--near-cpu", NULL, fd_log_cpu_id() );
      60          30 :   ulong        wksp_tag     = limits->wksp_tag ? limits->wksp_tag : 42UL;
      61             : 
      62          30 :   ulong data_max = fd_svm_mini_wksp_data_max( limits );
      63          30 :   ulong part_max = fd_wksp_part_max_est( data_max, 64UL<<10 );
      64          30 :   ulong wksp_sz  = fd_wksp_footprint( part_max, data_max );
      65          30 :   fd_wksp_t * wksp = NULL;
      66          30 :   if( wksp_name && !!wksp_name[0] ) {
      67           0 :     FD_LOG_NOTICE(( "Attaching to --wksp %s", wksp_name ));
      68           0 :     wksp = fd_wksp_attach( wksp_name );
      69          30 :   } else if( page_sz_cstr ) {
      70          30 :     ulong page_sz = fd_cstr_to_shmem_page_sz( page_sz_cstr );
      71          30 :     if( FD_UNLIKELY( !page_sz ) ) FD_LOG_ERR(( "Invalid --page-sz %s", page_sz_cstr ));
      72          30 :     if( FD_UNLIKELY( page_sz*page_cnt < wksp_sz ) ) {
      73           0 :       FD_LOG_WARNING(( "--page-sz %s * --page-cnt %lu is smaller than required wksp_sz %lu KiB; falling back to lazy anonymous memory",
      74           0 :                        page_sz_cstr, page_cnt, wksp_sz>>10 ));
      75           0 :       goto fallback;
      76           0 :     }
      77          30 :     FD_LOG_NOTICE(( "--wksp not specified, using anonymous pinned shmem" ));
      78          30 :     wksp = fd_wksp_new_anonymous( page_sz, page_cnt, near_cpu, "wksp", wksp_tag );
      79          30 :   } else {
      80           0 : fallback:
      81           0 :     FD_LOG_NOTICE(( "--page-sz not specified, using lazy paged memory" ));
      82           0 :     wksp = fd_wksp_new_lazy( wksp_sz );
      83           0 :   }
      84          30 :   if( FD_UNLIKELY( !wksp ) ) FD_LOG_ERR(( "Unable to attach to wksp" ));
      85             : 
      86          30 :   return fd_svm_mini_create( wksp, limits );
      87          30 : }
      88             : 
      89             : void
      90          30 : fd_svm_test_halt( fd_svm_mini_t * mini ) {
      91          30 :   fd_svm_mini_destroy( mini );
      92          30 :   fd_halt();
      93          30 : }
      94             : 
      95             : ulong
      96          30 : fd_svm_mini_wksp_data_max( fd_svm_mini_limits_t const * limits ) {
      97          30 :   ulong txn_max = limits->max_live_slots;
      98          30 :   ulong rec_max = limits->max_accounts;
      99             : 
     100          30 :   ulong acc_pool_cnt     = fd_ulong_max( limits->max_txn_write_locks + 2UL, FD_ACC_POOL_MIN_ACCOUNT_CNT_PER_TX );
     101          30 :   ulong funk_sz           = fd_funk_shmem_footprint( txn_max, rec_max );
     102          30 :   ulong funk_lock_sz      = fd_funk_locks_footprint( txn_max, rec_max );
     103          30 :   ulong pcache_sz         = fd_progcache_shmem_footprint( txn_max, limits->max_progcache_recs );
     104          30 :   ulong banks_sz          = fd_banks_footprint( txn_max, limits->max_fork_width, limits->max_stake_accounts, limits->max_vote_accounts );
     105          30 :   ulong acc_pool_sz       = fd_acc_pool_footprint( acc_pool_cnt );
     106          30 :   ulong runtime_stack_sz  = fd_runtime_stack_footprint( limits->max_vote_accounts, limits->max_vote_accounts, limits->max_stake_accounts );
     107             : 
     108         360 : # define WKSP_ALLOC(a,s) fd_ulong_align_up( fd_ulong_max((s),1UL), fd_ulong_max((a),FD_WKSP_ALIGN_DEFAULT) )
     109          30 :   ulong sz = 0UL;
     110          30 :   sz += WKSP_ALLOC( alignof(fd_svm_mini_t),     sizeof(fd_svm_mini_t)            );
     111          30 :   sz += WKSP_ALLOC( fd_funk_align(),            funk_sz                          );
     112          30 :   sz += WKSP_ALLOC( fd_funk_align(),            funk_lock_sz                     );
     113          30 :   sz += WKSP_ALLOC( fd_progcache_shmem_align(), pcache_sz                        );
     114          30 :   sz += WKSP_ALLOC( FD_PROGCACHE_SCRATCH_ALIGN, FD_PROGCACHE_SCRATCH_FOOTPRINT   );
     115          30 :   sz += WKSP_ALLOC( fd_banks_align(),           banks_sz                         );
     116          30 :   sz += WKSP_ALLOC( fd_acc_pool_align(),        acc_pool_sz                      );
     117          30 :   sz += WKSP_ALLOC( alignof(fd_runtime_t),      sizeof(fd_runtime_t)             );
     118          30 :   sz += WKSP_ALLOC( fd_runtime_stack_align(),   runtime_stack_sz                 );
     119          30 :   sz += WKSP_ALLOC( fd_vm_align(),              fd_vm_footprint()                );
     120          30 :   sz += WKSP_ALLOC( 16UL,                       limits->max_account_space_bytes  );
     121          30 :   sz += WKSP_ALLOC( 1UL,                        limits->max_progcache_heap_bytes );
     122          30 : # undef WKSP_ALLOC
     123             : 
     124          30 :   return sz;
     125          30 : }
     126             : 
     127             : fd_svm_mini_t *
     128             : fd_svm_mini_create( fd_wksp_t *                  wksp,
     129          30 :                     fd_svm_mini_limits_t const * limits ) {
     130             : 
     131          30 :   ulong const wksp_tag = limits->wksp_tag ? limits->wksp_tag : 42UL;
     132          30 :   ulong const txn_max  = limits->max_live_slots;
     133          30 :   ulong const rec_max  = limits->max_accounts;
     134             : 
     135          30 :   ulong acc_pool_cnt     = fd_ulong_max( limits->max_txn_write_locks + 2UL, FD_ACC_POOL_MIN_ACCOUNT_CNT_PER_TX );
     136          30 :   ulong funk_sz          = fd_funk_shmem_footprint( txn_max, rec_max );
     137          30 :   ulong funk_lock_sz     = fd_funk_locks_footprint( txn_max, rec_max );
     138          30 :   ulong pcache_sz        = fd_progcache_shmem_footprint( txn_max, limits->max_progcache_recs );
     139          30 :   ulong banks_sz         = fd_banks_footprint( txn_max, limits->max_fork_width,
     140          30 :                                                limits->max_stake_accounts, limits->max_vote_accounts );
     141          30 :   ulong acc_pool_sz      = fd_acc_pool_footprint( acc_pool_cnt );
     142          30 :   ulong runtime_stack_sz = fd_runtime_stack_footprint( limits->max_vote_accounts, limits->max_vote_accounts, limits->max_stake_accounts );
     143             : 
     144             :   /* Allocate objects */
     145             : 
     146          30 :   fd_svm_mini_t * mini;          FD_TEST( (mini         = fd_wksp_alloc_laddr( wksp, alignof(fd_svm_mini_t),     sizeof(fd_svm_mini_t),          wksp_tag )) );
     147          30 :   void *          funk_mem;      FD_TEST( (funk_mem     = fd_wksp_alloc_laddr( wksp, fd_funk_align(),            funk_sz,                        wksp_tag )) );
     148          30 :   void *          funk_locks;    FD_TEST( (funk_locks   = fd_wksp_alloc_laddr( wksp, fd_funk_align(),            funk_lock_sz,                   wksp_tag )) );
     149          30 :   void *          pcache_mem;    FD_TEST( (pcache_mem   = fd_wksp_alloc_laddr( wksp, fd_progcache_shmem_align(), pcache_sz,                      wksp_tag )) );
     150          30 :   uchar *         scratch;       FD_TEST( (scratch      = fd_wksp_alloc_laddr( wksp, FD_PROGCACHE_SCRATCH_ALIGN, FD_PROGCACHE_SCRATCH_FOOTPRINT, wksp_tag )) );
     151          30 :   void *          banks_mem;     FD_TEST( (banks_mem    = fd_wksp_alloc_laddr( wksp, fd_banks_align(),           banks_sz,                       wksp_tag )) );
     152          30 :   void *          acc_pool_mem;  FD_TEST( (acc_pool_mem = fd_wksp_alloc_laddr( wksp, fd_acc_pool_align(),        acc_pool_sz,                    wksp_tag )) );
     153          30 :   fd_runtime_t *  runtime;       FD_TEST( (runtime      = fd_wksp_alloc_laddr( wksp, alignof(fd_runtime_t),      sizeof(fd_runtime_t),           wksp_tag )) );
     154          30 :   void *          rstack_mem;    FD_TEST( (rstack_mem   = fd_wksp_alloc_laddr( wksp, fd_runtime_stack_align(),   runtime_stack_sz,               wksp_tag )) );
     155          30 :   void *          vm_mem;        FD_TEST( (vm_mem       = fd_wksp_alloc_laddr( wksp, fd_vm_align(),              fd_vm_footprint(),              wksp_tag )) );
     156             : 
     157             :   /* Initialize objects */
     158             : 
     159          30 :   fd_memset( mini, 0, sizeof(fd_svm_mini_t) );
     160          30 :   mini->wksp = wksp;
     161             : 
     162          30 :   void * shfunk   = fd_funk_shmem_new     ( funk_mem,   wksp_tag, 1UL, txn_max, rec_max );
     163          30 :   void * shpcache = fd_progcache_shmem_new( pcache_mem, wksp_tag, 1UL, txn_max, limits->max_progcache_recs );
     164          30 :   if( FD_UNLIKELY( !shfunk   ) ) FD_LOG_ERR(( "fd_funk_shmem_new failed"      ));
     165          30 :   if( FD_UNLIKELY( !shpcache ) ) FD_LOG_ERR(( "fd_progcache_shmem_new failed" ));
     166          30 :   FD_TEST( fd_funk_locks_new( funk_locks, txn_max, rec_max ) );
     167             : 
     168          30 :   FD_TEST( fd_accdb_admin_v1_init( mini->accdb_admin, funk_mem, funk_locks ) );
     169          30 :   FD_TEST( fd_accdb_user_v1_init ( mini->accdb,       funk_mem, funk_locks, txn_max ) );
     170             : 
     171          30 :   FD_TEST( fd_progcache_join( mini->progcache, pcache_mem, scratch, FD_PROGCACHE_SCRATCH_FOOTPRINT ) );
     172             : 
     173          30 :   mini->banks = fd_banks_join( fd_banks_new( banks_mem, txn_max, limits->max_fork_width,
     174          30 :                                limits->max_stake_accounts, limits->max_vote_accounts, 0, 8888UL ) );
     175          30 :   FD_TEST( mini->banks );
     176             : 
     177          30 :   mini->acc_pool = fd_acc_pool_join( fd_acc_pool_new( acc_pool_mem, acc_pool_cnt ) );
     178          30 :   FD_TEST( mini->acc_pool );
     179             : 
     180          30 :   mini->runtime = runtime;
     181             : 
     182          30 :   runtime->accdb        = mini->accdb;
     183          30 :   runtime->status_cache = NULL;
     184          30 :   runtime->progcache    = mini->progcache;
     185          30 :   runtime->acc_pool     = mini->acc_pool;
     186             : 
     187          30 :   runtime->instr.stack_sz          = 0;
     188          30 :   runtime->instr.trace_length      = 0;
     189          30 :   runtime->instr.current_idx       = 0;
     190          30 :   runtime->accounts.executable_cnt = 0;
     191          30 :   fd_memset( &runtime->log,     0, sizeof(runtime->log)     );
     192          30 :   fd_memset( &runtime->metrics, 0, sizeof(runtime->metrics) );
     193          30 :   fd_memset( &runtime->fuzz,    0, sizeof(runtime->fuzz)    );
     194             : 
     195          30 :   mini->runtime_stack = fd_runtime_stack_join( fd_runtime_stack_new( rstack_mem,
     196          30 :       limits->max_vote_accounts, limits->max_vote_accounts, limits->max_stake_accounts, 42UL ) );
     197          30 :   FD_TEST( mini->runtime_stack );
     198             : 
     199          30 :   fd_log_collector_init( mini->log_collector, 1 );
     200          30 :   runtime->log.enable_log_collector = 0;
     201          30 :   runtime->log.log_collector        = mini->log_collector;
     202             : 
     203          30 :   fd_features_disable_all( mini->features );
     204          30 :   fd_features_enable_cleaned_up( mini->features );
     205             : 
     206          30 :   FD_TEST( fd_sha256_join( fd_sha256_new( mini->sha256 ) ) );
     207             : 
     208          30 :   mini->vm = fd_vm_join( fd_vm_new( vm_mem ) );
     209          30 :   FD_TEST( mini->vm );
     210             : 
     211          30 :   return mini;
     212          30 : }
     213             : 
     214             : void
     215          30 : fd_svm_mini_destroy( fd_svm_mini_t * mini ) {
     216          30 :   if( FD_UNLIKELY( !mini ) ) return;
     217             : 
     218          30 :   if( mini->vm ) fd_wksp_free_laddr( fd_vm_delete( fd_vm_leave( mini->vm ) ) );
     219          30 :   if( mini->runtime_stack ) fd_wksp_free_laddr( mini->runtime_stack );
     220          30 :   if( mini->runtime ) fd_wksp_free_laddr( mini->runtime );
     221          30 :   if( mini->acc_pool ) fd_wksp_free_laddr( mini->acc_pool );
     222          30 :   if( mini->banks ) fd_wksp_free_laddr( mini->banks );
     223             : 
     224          30 :   uchar * scratch = mini->progcache->scratch;
     225          30 :   fd_progcache_shmem_t * shpcache = NULL;
     226          30 :   fd_progcache_leave( mini->progcache, &shpcache );
     227          30 :   if( scratch  ) fd_wksp_free_laddr( scratch );
     228          30 :   if( shpcache ) fd_wksp_free_laddr( fd_progcache_shmem_delete( shpcache ) );
     229             : 
     230          30 :   void * shfunk      = fd_accdb_user_v1_funk( mini->accdb )->shmem;
     231          30 :   void * shfunk_lock = (void *)fd_accdb_user_v1_funk( mini->accdb )->txn_lock;
     232          30 :   fd_accdb_user_fini ( mini->accdb );
     233          30 :   fd_accdb_admin_fini( mini->accdb_admin );
     234          30 :   fd_wksp_free_laddr( shfunk_lock );
     235          30 :   fd_wksp_free_laddr( fd_funk_delete( shfunk ) );
     236             : 
     237          30 :   fd_wksp_free_laddr( mini );
     238          30 : }
     239             : 
     240             : static void
     241             : fd_svm_mini_init_mock_validators( fd_svm_mini_t *              mini,
     242             :                                   fd_bank_t *                  bank,
     243        3438 :                                   fd_svm_mini_params_t const * params ) {
     244             : 
     245        3438 :   ulong const N             = params->mock_validator_cnt;
     246        3438 :   ulong const uniform_stake = 1000000000UL; /* 1 SOL */
     247        3438 :   ulong const vote_min_bal  = fd_rent_exempt_minimum_balance( &bank->f.rent, FD_VOTE_STATE_V3_SZ );
     248        3438 :   ulong const stake_min_bal = fd_rent_exempt_minimum_balance( &bank->f.rent, FD_STAKE_STATE_SZ );
     249             : 
     250        3438 :   fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
     251        3438 :   fd_vote_stakes_reset( vote_stakes );
     252             : 
     253        3438 :   fd_top_votes_t * top_votes_t_1 = fd_bank_top_votes_t_1_modify( bank );
     254        3438 :   fd_top_votes_init( top_votes_t_1 );
     255        3438 :   fd_top_votes_t * top_votes_t_2 = fd_bank_top_votes_t_2_modify( bank );
     256        3438 :   fd_top_votes_init( top_votes_t_2 );
     257             : 
     258        3438 :   fd_stake_delegations_t * stake_delegations = fd_banks_stake_delegations_root_query( mini->banks );
     259             : 
     260        3438 :   fd_vote_stake_weight_t * stakes = calloc( N, sizeof(fd_vote_stake_weight_t) );
     261        3438 :   FD_TEST( stakes );
     262             : 
     263        3438 :   fd_rng_t rng[1];
     264        3438 :   fd_rng_join( fd_rng_new( rng, (uint)params->hash_seed, 0UL ) );
     265             : 
     266        6882 :   for( ulong i=0UL; i<N; i++ ) {
     267             : 
     268             :     /* Generate deterministic pubkeys */
     269             : 
     270        3444 :     fd_pubkey_t identity_key, vote_key, stake_key;
     271       17220 :     for( ulong j=0UL; j<4UL; j++ ) identity_key.ul[j] = fd_rng_ulong( rng );
     272       17220 :     for( ulong j=0UL; j<4UL; j++ ) vote_key.ul[j]     = fd_rng_ulong( rng );
     273       17220 :     for( ulong j=0UL; j<4UL; j++ ) stake_key.ul[j]     = fd_rng_ulong( rng );
     274             : 
     275             :     /* Identity account */
     276             : 
     277        3444 :     fd_svm_mini_add_lamports_rooted( mini, &identity_key, 500000000000UL /* 500 SOL */ );
     278             : 
     279             :     /* Vote account */
     280             : 
     281        3444 :     {
     282        3444 :       uchar vote_state_data[ FD_VOTE_STATE_V3_SZ ] = {0};
     283             : 
     284        3444 :       fd_vote_state_versioned_t versioned[1];
     285        3444 :       fd_vote_state_versioned_new( versioned, fd_vote_state_versioned_enum_v3 );
     286             : 
     287        3444 :       fd_vote_state_v3_t * vs   = &versioned->v3;
     288        3444 :       vs->node_pubkey           = identity_key;
     289        3444 :       vs->authorized_withdrawer = identity_key;
     290        3444 :       vs->commission            = 100;
     291             : 
     292        3444 :       fd_vote_authorized_voter_t * ele = fd_vote_authorized_voters_pool_ele_acquire( vs->authorized_voters.pool );
     293        3444 :       *ele = (fd_vote_authorized_voter_t){
     294        3444 :         .epoch  = 0UL,
     295        3444 :         .pubkey = identity_key,
     296        3444 :         .prio   = identity_key.uc[0],
     297        3444 :       };
     298        3444 :       fd_vote_authorized_voters_treap_ele_insert( vs->authorized_voters.treap, ele, vs->authorized_voters.pool );
     299        3444 :       FD_TEST( !fd_vote_state_versioned_serialize( versioned, vote_state_data, sizeof(vote_state_data) ) );
     300             : 
     301        3444 :       fd_account_meta_t meta = { .lamports = vote_min_bal, .dlen = FD_VOTE_STATE_V3_SZ };
     302        3444 :       memcpy( meta.owner, fd_solana_vote_program_id.uc, 32UL );
     303        3444 :       fd_accdb_ro_t ro[1];
     304        3444 :       fd_accdb_ro_init_nodb_oob( ro, &vote_key, &meta, vote_state_data );
     305        3444 :       fd_svm_mini_put_account_rooted( mini, ro );
     306        3444 :     }
     307             : 
     308             :     /* Stake account */
     309             : 
     310           0 :     {
     311        3444 :       uchar stake_data[ FD_STAKE_STATE_SZ ] = {0};
     312        3444 :       FD_STORE( fd_stake_state_t, stake_data, ((fd_stake_state_t) {
     313        3444 :         .stake_type = FD_STAKE_STATE_STAKE,
     314        3444 :         .stake = {
     315        3444 :           .meta = {
     316        3444 :             .rent_exempt_reserve = stake_min_bal,
     317        3444 :             .staker              = identity_key,
     318        3444 :             .withdrawer          = identity_key,
     319        3444 :           },
     320        3444 :           .stake = (fd_stake_t) {
     321        3444 :             .delegation = (fd_delegation_t) {
     322        3444 :               .voter_pubkey         = vote_key,
     323        3444 :               .stake                = uniform_stake,
     324        3444 :               .activation_epoch     = ULONG_MAX,
     325        3444 :               .deactivation_epoch   = ULONG_MAX,
     326        3444 :               .warmup_cooldown_rate = 0.25,
     327        3444 :             },
     328        3444 :             .credits_observed = 0UL,
     329        3444 :           },
     330        3444 :         },
     331        3444 :       }) );
     332             : 
     333        3444 :       fd_account_meta_t meta = {
     334        3444 :         .lamports = fd_ulong_max( stake_min_bal, uniform_stake ),
     335        3444 :         .dlen     = FD_STAKE_STATE_SZ,
     336        3444 :       };
     337        3444 :       memcpy( meta.owner, fd_solana_stake_program_id.uc, 32UL );
     338        3444 :       fd_accdb_ro_t ro[1];
     339        3444 :       fd_accdb_ro_init_nodb_oob( ro, &stake_key, &meta, stake_data );
     340        3444 :       fd_svm_mini_put_account_rooted( mini, ro );
     341        3444 :     }
     342             : 
     343             :     /* Populate bank structures */
     344             : 
     345        3444 :     fd_vote_stakes_root_insert_key ( vote_stakes, &vote_key, &identity_key, uniform_stake, 0, 0UL );
     346        3444 :     fd_vote_stakes_root_update_meta( vote_stakes, &vote_key, &identity_key, uniform_stake, 0, 0UL );
     347             : 
     348        3444 :     fd_top_votes_insert( top_votes_t_1, &vote_key, &identity_key, uniform_stake, 0 );
     349        3444 :     fd_top_votes_insert( top_votes_t_2, &vote_key, &identity_key, uniform_stake, 0 );
     350             : 
     351        3444 :     fd_stake_delegations_root_update( stake_delegations,
     352        3444 :                                       &stake_key, &vote_key,
     353        3444 :                                       uniform_stake,
     354        3444 :                                       ULONG_MAX,  /* activation_epoch (bootstrap) */
     355        3444 :                                       ULONG_MAX,  /* deactivation_epoch */
     356        3444 :                                       0UL,        /* credits_observed */
     357        3444 :                                       FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_025 /* warmup_cooldown_rate */ );
     358             : 
     359        3444 :     stakes[i] = (fd_vote_stake_weight_t){
     360        3444 :       .vote_key = vote_key,
     361        3444 :       .id_key   = identity_key,
     362        3444 :       .stake    = uniform_stake,
     363        3444 :     };
     364        3444 :   }
     365             : 
     366        3438 :   fd_vote_stakes_genesis_fini( vote_stakes );
     367             : 
     368             :   /* Create leader schedule */
     369             : 
     370        3438 :   ulong epoch    = bank->f.epoch;
     371        3438 :   ulong slot0    = fd_epoch_slot0( &bank->f.epoch_schedule, epoch );
     372        3438 :   ulong slot_cnt = bank->f.epoch_schedule.slots_per_epoch;
     373             : 
     374        3438 :   void * leaders_mem = fd_bank_epoch_leaders_modify( bank, epoch );
     375        3438 :   FD_TEST( fd_epoch_leaders_join( fd_epoch_leaders_new(
     376        3438 :       leaders_mem, epoch, slot0, slot_cnt, N, stakes, 0UL ) ) );
     377             : 
     378        3438 :   fd_rng_delete( fd_rng_leave( rng ) );
     379        3438 :   free( stakes );
     380        3438 : }
     381             : 
     382             : ulong
     383             : fd_svm_mini_reset( fd_svm_mini_t *        mini,
     384        3447 :                    fd_svm_mini_params_t * params ) {
     385             : 
     386        3447 :   fd_accdb_v1_clear( mini->accdb_admin );
     387        3447 :   fd_progcache_reset( mini->progcache->join );
     388        3447 :   fd_banks_clear( mini->banks           );
     389             : 
     390        3447 :   fd_bank_t * bank = fd_banks_init_bank( mini->banks );
     391        3447 :   FD_TEST( bank );
     392        3447 :   ulong bank_idx = bank->idx;
     393             : 
     394        3447 :   bank->f.slot = params->root_slot;
     395             : 
     396        3447 :   fd_xid_t root_xid = fd_bank_xid( bank );
     397        3447 :   fd_funk_t * funk = fd_accdb_user_v1_funk( mini->accdb );
     398        3447 :   fd_funk_txn_xid_copy( funk->shmem->last_publish, &root_xid );
     399        3447 :   bank->progcache_fork_id = fd_progcache_fork_id_initial();
     400             : 
     401        3447 :   if( params->clock ) {
     402           0 :     bank->f.slot  = params->clock->slot;
     403           0 :     bank->f.epoch = params->clock->epoch;
     404           0 :   }
     405             : 
     406        3447 :   if( params->epoch_schedule ) {
     407           0 :     bank->f.epoch_schedule = *params->epoch_schedule;
     408        3447 :   } else {
     409        3447 :     bank->f.epoch_schedule = (fd_epoch_schedule_t) {
     410        3447 :       .slots_per_epoch             = params->slots_per_epoch,
     411        3447 :       .leader_schedule_slot_offset = params->slots_per_epoch,
     412        3447 :       .warmup                      = 0,
     413        3447 :       .first_normal_epoch          = 0UL,
     414        3447 :       .first_normal_slot           = 0UL,
     415        3447 :     };
     416        3447 :   }
     417             : 
     418             :   /* Default slots_per_year matches Solana mainnet genesis defaults
     419             :      (target_tick_duration=6250000ns, ticks_per_slot=64). */
     420        3447 :   bank->f.slots_per_year = SECONDS_PER_YEAR * (1000000000.0 / 6250000.0) / 64.0;
     421             : 
     422        3447 :   if( params->rent ) {
     423           0 :     bank->f.rent = *params->rent;
     424        3447 :   } else {
     425        3447 :     bank->f.rent = (fd_rent_t) {
     426        3447 :       .lamports_per_uint8_year = 3480UL,
     427        3447 :       .exemption_threshold     = 2.0,
     428        3447 :       .burn_percent            = 50,
     429        3447 :     };
     430        3447 :   }
     431             : 
     432        3447 :   fd_features_disable_all( &bank->f.features );
     433        3447 :   fd_features_enable_cleaned_up( &bank->f.features );
     434             : 
     435        3447 :   if( params->init_builtins ) {
     436        3447 :     fd_builtin_program_t const * builtins = fd_builtins();
     437       34470 :     for( ulong i=0UL; i<fd_num_builtins(); i++ ) {
     438       31023 :       char const * data = builtins[i].data;
     439       31023 :       ulong        sz   = strlen( data );
     440       31023 :       fd_account_meta_t meta = { .lamports = 1UL, .dlen = (uint)sz, .executable = 1 };
     441       31023 :       memcpy( meta.owner, fd_solana_native_loader_id.uc, 32UL );
     442       31023 :       fd_accdb_ro_t ro[1];
     443       31023 :       fd_accdb_ro_init_nodb_oob( ro, builtins[i].pubkey, &meta, data );
     444       31023 :       fd_svm_mini_put_account_rooted( mini, ro );
     445       31023 :     }
     446             : 
     447        3447 :     fd_pubkey_t const * precompiles[] = {
     448        3447 :       &fd_solana_keccak_secp_256k_program_id,
     449        3447 :       &fd_solana_ed25519_sig_verify_program_id,
     450        3447 :       &fd_solana_secp256r1_program_id,
     451        3447 :     };
     452       13788 :     for( ulong i=0UL; i<3UL; i++ ) {
     453       10341 :       fd_account_meta_t meta = { .lamports = 1UL, .dlen = 0, .executable = 1 };
     454       10341 :       memcpy( meta.owner, fd_solana_native_loader_id.uc, 32UL );
     455       10341 :       fd_accdb_ro_t ro[1];
     456       10341 :       fd_accdb_ro_init_nodb_oob( ro, precompiles[i], &meta, NULL );
     457       10341 :       fd_svm_mini_put_account_rooted( mini, ro );
     458       10341 :     }
     459        3447 :   }
     460             : 
     461        3447 :   if( params->init_feature_accounts ) {
     462           0 :     for( fd_feature_id_t const * id = fd_feature_iter_init();
     463           0 :          !fd_feature_iter_done( id );
     464           0 :          id = fd_feature_iter_next( id ) ) {
     465           0 :       ulong activation_slot = fd_features_get( &bank->f.features, id );
     466           0 :       if( activation_slot==FD_FEATURE_DISABLED ) continue;
     467             : 
     468           0 :       fd_feature_t feature = { .is_active = 1, .activation_slot = activation_slot };
     469           0 :       fd_account_meta_t meta = { .lamports = 1UL, .dlen = sizeof(fd_feature_t) };
     470           0 :       memcpy( meta.owner, fd_solana_feature_program_id.uc, 32UL );
     471           0 :       fd_accdb_ro_t ro[1];
     472           0 :       fd_accdb_ro_init_nodb_oob( ro, &id->id, &meta, &feature );
     473           0 :       fd_svm_mini_put_account_rooted( mini, ro );
     474           0 :     }
     475           0 :   }
     476             : 
     477        3447 :   if( params->init_sysvars ) {
     478             : 
     479             :     /* Blockhash queue -- must be initialized before recent_hashes sysvar */
     480        3447 :     fd_blockhashes_t * bhq = fd_blockhashes_init( &bank->f.block_hash_queue, params->hash_seed );
     481        3447 :     fd_hash_t genesis_hash = {0};
     482        3447 :     fd_memset( genesis_hash.uc, 0xAB, FD_HASH_FOOTPRINT );
     483        3447 :     fd_blockhash_info_t * bh_info = fd_blockhashes_push_new( bhq, &genesis_hash );
     484        3447 :     bh_info->lamports_per_signature = 0UL;
     485        3447 :     bank->f.poh = genesis_hash;
     486             : 
     487             :     /* Clock */
     488        3447 :     fd_sol_sysvar_clock_t clock = {
     489        3447 :       .slot                  = bank->f.slot,
     490        3447 :       .leader_schedule_epoch = 1,
     491        3447 :     };
     492        3447 :     if( params->clock ) clock = *params->clock;
     493             : 
     494             :     /* Last restart slot */
     495        3447 :     uchar last_restart_enc[ FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ ] = {0};
     496             : 
     497             :     /* Recent hashes (encodes from blockhash queue -- initially 1 entry) */
     498        3447 :     uchar recent_hashes_enc[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] = {0};
     499        3447 :     ulong rbh_cnt = 1UL;
     500        3447 :     memcpy( recent_hashes_enc, &rbh_cnt, sizeof(ulong) );
     501        3447 :     memcpy( recent_hashes_enc + sizeof(ulong), genesis_hash.uc, 32 );
     502             :     /* lamports_per_signature = 0 already zeroed */
     503             : 
     504             :     /* Slot hashes (empty) */
     505        3447 :     uchar slot_hashes_enc[ FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ] = {0};
     506             : 
     507             :     /* Slot history -- well-formed bincode (large, heap alloc) */
     508        3447 :     uchar * slot_history_enc = calloc( 1, FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ );
     509        3447 :     FD_TEST( slot_history_enc );
     510        3447 :     ulong sh_blocks_len = FD_SLOT_HISTORY_MAX_ENTRIES / 64UL;
     511        3447 :     slot_history_enc[0] = 1; /* has_bits */
     512        3447 :     FD_STORE( ulong, slot_history_enc+1, sh_blocks_len );
     513        3447 :     uchar * sh_footer = slot_history_enc + 9UL + sh_blocks_len * sizeof(ulong);
     514        3447 :     FD_STORE( ulong, sh_footer,     FD_SLOT_HISTORY_MAX_ENTRIES );
     515        3447 :     FD_STORE( ulong, sh_footer+8UL, bank->f.slot + 1UL );
     516             : 
     517             :     /* Stake history (empty) */
     518        3447 :     uchar stake_history_enc[ FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ] = {0};
     519             : 
     520        3447 :     struct { fd_pubkey_t const * addr; void const * data; ulong sz; } sysvars[] = {
     521        3447 :       { &fd_sysvar_clock_id,               &clock,                  sizeof(clock)                     },
     522        3447 :       { &fd_sysvar_epoch_schedule_id,      &bank->f.epoch_schedule, sizeof(bank->f.epoch_schedule)    },
     523        3447 :       { &fd_sysvar_rent_id,                &bank->f.rent,           sizeof(bank->f.rent)              },
     524        3447 :       { &fd_sysvar_last_restart_slot_id,   last_restart_enc,        sizeof(last_restart_enc)          },
     525        3447 :       { &fd_sysvar_recent_block_hashes_id, recent_hashes_enc,       sizeof(recent_hashes_enc)         },
     526        3447 :       { &fd_sysvar_slot_hashes_id,         slot_hashes_enc,         sizeof(slot_hashes_enc)           },
     527        3447 :       { &fd_sysvar_slot_history_id,        slot_history_enc,        FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ },
     528        3447 :       { &fd_sysvar_stake_history_id,       stake_history_enc,       sizeof(stake_history_enc)         },
     529        3447 :     };
     530       31023 :     for( ulong i=0UL; i<8UL; i++ ) {
     531       27576 :       fd_account_meta_t meta = {
     532       27576 :         .lamports = fd_rent_exempt_minimum_balance( &bank->f.rent, sysvars[i].sz ),
     533       27576 :         .dlen     = (uint)sysvars[i].sz,
     534       27576 :       };
     535       27576 :       memcpy( meta.owner, fd_sysvar_owner_id.uc, 32UL );
     536       27576 :       fd_accdb_ro_t ro[1];
     537       27576 :       fd_accdb_ro_init_nodb_oob( ro, sysvars[i].addr, &meta, sysvars[i].data );
     538       27576 :       fd_svm_mini_put_account_rooted( mini, ro );
     539       27576 :     }
     540             : 
     541        3447 :     free( slot_history_enc );
     542             : 
     543        3447 :     fd_sysvar_cache_restore( bank, mini->accdb, &root_xid );
     544        3447 :   }
     545             : 
     546        3447 :   if( params->mock_validator_cnt ) {
     547        3438 :     fd_svm_mini_init_mock_validators( mini, bank, params );
     548        3438 :   }
     549             : 
     550        3447 :   return bank_idx;
     551        3447 : }
     552             : 
     553             : ulong
     554             : fd_svm_mini_attach_child( fd_svm_mini_t * mini,
     555             :                           ulong           parent_bank_idx,
     556        3510 :                           ulong           child_slot ) {
     557             : 
     558        3510 :   fd_bank_t * parent_bank = fd_banks_bank_query( mini->banks, parent_bank_idx );
     559        3510 :   if( FD_UNLIKELY( !parent_bank ) ) FD_LOG_ERR(( "invalid parent_bank_idx" ));
     560        3510 :   ulong parent_slot = parent_bank->f.slot;
     561        3510 :   if( FD_UNLIKELY( child_slot<=parent_slot ) ) FD_LOG_ERR(( "child_slot (%lu) <= parent_slot (%lu)", child_slot, parent_slot ));
     562        3510 :   fd_xid_t parent_xid = fd_bank_xid( parent_bank );
     563             : 
     564        3510 :   fd_bank_t * bank = fd_banks_new_bank( mini->banks, parent_bank_idx, 0L );
     565        3510 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "fd_banks_new_bank failed" ));
     566        3510 :   bank = fd_banks_clone_from_parent( mini->banks, bank->idx );
     567        3510 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "fd_banks_clone_from_parent failed" ));
     568        3510 :   ulong bank_idx = bank->idx;
     569        3510 :   bank->f.slot = child_slot;
     570        3510 :   fd_xid_t xid = fd_bank_xid( bank );
     571             : 
     572        3510 :   fd_accdb_attach_child( mini->accdb_admin, &parent_xid, &xid );
     573        3510 :   bank->progcache_fork_id = fd_progcache_attach_child( mini->progcache->join, parent_bank->progcache_fork_id );
     574             : 
     575        3510 :   int is_epoch_boundary = 0;
     576        3510 :   fd_runtime_block_execute_prepare( mini->banks, bank, mini->accdb, mini->runtime_stack, NULL, &is_epoch_boundary );
     577             : 
     578        3510 :   return bank_idx;
     579        3510 : }
     580             : 
     581             : void
     582             : fd_svm_mini_freeze( fd_svm_mini_t * mini,
     583          78 :                     ulong           bank_idx ) {
     584          78 :   fd_bank_t * bank = fd_svm_mini_bank( mini, bank_idx );
     585          78 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     586             :   /* Derive a mock POH hash so each frozen slot registers a unique
     587             :      blockhash.  (Real POH is computed by the PoH tile.) */
     588          78 :   fd_sha256_hash( bank->f.poh.hash, 32UL, bank->f.poh.hash );
     589          78 :   fd_runtime_block_execute_finalize( bank, mini->accdb, NULL );
     590          78 : }
     591             : 
     592             : void
     593             : fd_svm_mini_cancel_fork( fd_svm_mini_t * mini,
     594           0 :                          ulong           bank_idx ) {
     595             : 
     596           0 :   fd_bank_t * bank = fd_svm_mini_bank( mini, bank_idx );
     597           0 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     598           0 :   fd_xid_t xid = fd_bank_xid( bank );
     599             : 
     600           0 :   fd_accdb_cancel         ( mini->accdb_admin,     &xid );
     601           0 :   fd_progcache_cancel_fork( mini->progcache->join, bank->progcache_fork_id );
     602           0 : }
     603             : 
     604             : void
     605             : fd_svm_mini_advance_root( fd_svm_mini_t * mini,
     606          24 :                           ulong           bank_idx ) {
     607             : 
     608          24 :   fd_bank_t * bank = fd_banks_bank_query( mini->banks, bank_idx );
     609          24 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     610          24 :   fd_xid_t xid = fd_bank_xid( bank );
     611             : 
     612          24 :   fd_accdb_advance_root    ( mini->accdb_admin,     &xid );
     613          24 :   fd_progcache_advance_root( mini->progcache->join, bank->progcache_fork_id );
     614          24 :   fd_banks_advance_root    ( mini->banks, bank_idx );
     615          24 : }
     616             : 
     617             : fd_bank_t *
     618             : fd_svm_mini_bank( fd_svm_mini_t * mini,
     619        6849 :                   ulong           bank_idx ) {
     620        6849 :   if( FD_UNLIKELY( bank_idx>=fd_banks_pool_max_cnt( mini->banks ) ) ) return NULL;
     621        6849 :   fd_bank_t * bank = fd_banks_bank_query( mini->banks, bank_idx );
     622        6849 :   if( FD_UNLIKELY( !bank ) ) return NULL;
     623        6840 :   return bank;
     624        6849 : }
     625             : 
     626             : fd_xid_t
     627             : fd_svm_mini_xid( fd_svm_mini_t * mini,
     628         282 :                  ulong           bank_idx ) {
     629         282 :   fd_bank_t * bank = fd_banks_bank_query( mini->banks, bank_idx );
     630         282 :   return fd_bank_xid( bank );
     631         282 : }
     632             : 
     633             : void
     634             : fd_svm_mini_put_account_rooted( fd_svm_mini_t *       mini,
     635       83472 :                                 fd_accdb_ro_t const * ro ) {
     636       83472 :   fd_funk_t * funk = fd_accdb_user_v1_funk( mini->accdb );
     637       83472 :   fd_funk_xid_key_pair_t pair = { .xid = {{ .ul = { ULONG_MAX, ULONG_MAX } }} };
     638       83472 :   memcpy( pair.key, ro->ref->address, sizeof(fd_funk_rec_key_t) );
     639       83472 :   fd_funk_rec_map_query_t query[1];
     640       83472 :   int remove_err = fd_funk_rec_map_remove( funk->rec_map, &pair, NULL, query, 0 );
     641       83472 :   FD_TEST( remove_err==FD_MAP_SUCCESS || remove_err==FD_MAP_ERR_KEY );
     642       83472 :   ulong old_lamports = 0UL;
     643       83472 :   if( remove_err==FD_MAP_SUCCESS ) {
     644          57 :     fd_funk_rec_t * old_rec = query->ele;
     645          57 :     fd_account_meta_t const * old_meta = fd_funk_val_const( old_rec, funk->wksp );
     646          57 :     if( old_meta ) old_lamports = old_meta->lamports;
     647          57 :     memset( &old_rec->pair, 0, sizeof(fd_funk_xid_key_pair_t) );
     648          57 :     old_rec->map_next = FD_FUNK_REC_IDX_NULL;
     649          57 :     fd_funk_val_flush( old_rec, funk->alloc, funk->wksp );
     650          57 :     fd_funk_rec_pool_release( funk->rec_pool, old_rec );
     651          57 :   }
     652             : 
     653       83472 :   fd_accdb_rw_t rw[1];
     654       83472 :   FD_TEST( fd_accdb_funk_create( funk, rw, NULL, ro->ref->address, fd_accdb_ref_data_sz( ro ) ) );
     655       83472 :   fd_accdb_ref_lamports_set( rw, fd_accdb_ref_lamports( ro ) );
     656       83472 :   fd_accdb_ref_owner_set   ( rw, fd_accdb_ref_owner   ( ro ) );
     657       83472 :   fd_accdb_ref_exec_bit_set( rw, fd_accdb_ref_exec_bit( ro ) );
     658       83472 :   fd_accdb_ref_slot_set    ( rw, fd_accdb_ref_slot    ( ro ) );
     659       83472 :   fd_accdb_ref_data_set( mini->accdb, rw, fd_accdb_ref_data_const( ro ), fd_accdb_ref_data_sz( ro ) );
     660       83472 :   fd_funk_rec_t * rec = (fd_funk_rec_t *)rw->ref->user_data;
     661       83472 :   fd_funk_rec_prepare_t prepare = { .rec = rec, .rec_head_idx = NULL, .rec_tail_idx = NULL };
     662       83472 :   fd_funk_rec_publish( funk, &prepare );
     663       83472 :   memset( rw, 0, sizeof(fd_accdb_rw_t) );
     664             : 
     665       83472 :   fd_bank_t * root = fd_banks_root( mini->banks );
     666       83472 :   if( root ) {
     667       83472 :     ulong new_lamports = fd_accdb_ref_lamports( ro );
     668       83472 :     if( new_lamports >= old_lamports )
     669       83469 :       root->f.capitalization += new_lamports - old_lamports;
     670           3 :     else
     671           3 :       root->f.capitalization -= old_lamports - new_lamports;
     672       83472 :   }
     673       83472 : }
     674             : 
     675             : void
     676             : fd_svm_mini_add_lamports_rooted( fd_svm_mini_t *     mini,
     677             :                                  fd_pubkey_t const * pubkey,
     678        3444 :                                  ulong               lamports ) {
     679        3444 :   fd_funk_t * funk = fd_accdb_user_v1_funk( mini->accdb );
     680        3444 :   fd_funk_xid_key_pair_t pair = { .xid = {{ .ul = { ULONG_MAX, ULONG_MAX } }} };
     681        3444 :   memcpy( pair.key, pubkey, sizeof(fd_funk_rec_key_t) );
     682        3444 :   fd_funk_rec_map_query_t query[1];
     683        3444 :   int query_err = fd_funk_rec_map_query_try( funk->rec_map, &pair, NULL, query, 0 );
     684        3444 :   FD_TEST( query_err==FD_MAP_SUCCESS || query_err==FD_MAP_ERR_KEY );
     685        3444 :   if( query_err==FD_MAP_SUCCESS ) {
     686           0 :     fd_funk_rec_t * rec = fd_funk_rec_map_query_ele( query );
     687           0 :     fd_account_meta_t * meta = fd_funk_val( rec, funk->wksp );
     688           0 :     ulong balance = meta->lamports;
     689           0 :     FD_TEST( !__builtin_uaddl_overflow( balance, lamports, &balance ) );
     690           0 :     meta->lamports = balance;
     691           0 :     FD_TEST( !fd_funk_rec_map_query_test( query ) );
     692        3444 :   } else if( query_err==FD_MAP_ERR_KEY ) {
     693        3444 :     fd_accdb_rw_t rw[1];
     694        3444 :     FD_TEST( fd_accdb_funk_create( funk, rw, NULL, pubkey, 0UL ) );
     695        3444 :     fd_accdb_ref_lamports_set( rw, lamports );
     696        3444 :     fd_funk_rec_t * rec = (fd_funk_rec_t *)rw->ref->user_data;
     697        3444 :     fd_funk_rec_prepare_t prepare = { .rec = rec, .rec_head_idx = NULL, .rec_tail_idx = NULL };
     698        3444 :     fd_funk_rec_publish( funk, &prepare );
     699        3444 :     memset( rw, 0, sizeof(fd_accdb_rw_t) );
     700        3444 :   } else {
     701           0 :     FD_LOG_ERR(( "fd_funk_rec_map_query_try failed (%i-%s)", query_err, fd_map_strerror( query_err ) ));
     702           0 :   }
     703             : 
     704        3444 :   fd_bank_t * root = fd_banks_root( mini->banks );
     705        3444 :   if( root ) root->f.capitalization += lamports;
     706        3444 : }
     707             : 
     708             : void
     709             : fd_svm_mini_add_lamports( fd_svm_mini_t *     mini,
     710             :                           fd_xid_t const *    xid,
     711             :                           fd_pubkey_t const * pubkey,
     712          45 :                           ulong               lamports ) {
     713          45 :   fd_accdb_user_t * accdb = mini->accdb;
     714             : 
     715          45 :   fd_accdb_rw_t rw[1];
     716          45 :   FD_TEST( fd_accdb_open_rw( accdb, rw, xid, pubkey, 0UL, FD_ACCDB_FLAG_CREATE ) );
     717          45 :   ulong balance = fd_accdb_ref_lamports( rw->ro );
     718          45 :   FD_TEST( !__builtin_uaddl_overflow( balance, lamports, &balance ) );
     719          45 :   fd_accdb_ref_lamports_set( rw, balance );
     720          45 :   fd_accdb_close_rw( accdb, rw );
     721             : 
     722          45 :   fd_bank_t * bank = fd_svm_mini_bank( mini, xid->ul[1] );
     723          45 :   if( bank ) bank->f.capitalization += lamports;
     724          45 : }

Generated by: LCOV version 1.14