LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_svm_mini.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 544 593 91.7 %
Date: 2026-09-01 04:28:17 Functions: 18 20 90.0 %

          Line data    Source code
       1             : #define _GNU_SOURCE
       2             : #include "fd_svm_mini.h"
       3             : #include "../../progcache/fd_progcache_admin.h"
       4             : #include "../../progcache/fd_progcache_user.h"
       5             : #include "../../runtime/fd_bank.h"
       6             : #include "../../runtime/program/fd_builtin_programs.h"
       7             : #include "../../runtime/fd_system_ids.h"
       8             : #include "../../runtime/fd_runtime_const.h"
       9             : #include "../../log_collector/fd_log_collector.h"
      10             : #include "../../runtime/fd_runtime.h"
      11             : #include "../../runtime/sysvar/fd_sysvar_cache.h"
      12             : #include "../../runtime/sysvar/fd_sysvar_rent.h"
      13             : #include "../../runtime/sysvar/fd_sysvar_epoch_schedule.h"
      14             : #include "../../runtime/sysvar/fd_sysvar_slot_history.h"
      15             : #include "../../runtime/program/fd_vote_program.h"
      16             : #include "../../stakes/fd_stake_types.h"
      17             : #include "../../stakes/fd_stake_delegations.h"
      18             : #include "../../stakes/fd_vote_stakes.h"
      19             : #include "../../leaders/fd_leaders.h"
      20             : #include <errno.h>
      21             : #include <stdlib.h>
      22             : #include <sys/mman.h>
      23             : #include <unistd.h>
      24             : 
      25        4080 : #define TEST_CACHE_MIN_RESERVED FD_ACCDB_CACHE_MIN_RESERVED_TXN
      26        4080 : #define TEST_CACHE_FOOTPRINT    (4UL<<30UL)
      27        4080 : #define TEST_PARTITION_CNT      (8192UL)
      28        3966 : #define TEST_PARTITION_SZ       (1UL<<30UL)
      29        4080 : #define TEST_WRITES_PER_SLOT    (8192UL)
      30             : 
      31        3909 : #define SENTINEL ((fd_accdb_fork_id_t){ .val = USHORT_MAX })
      32             : 
      33             : static fd_wksp_t *
      34             : fd_wksp_new_lazy( ulong footprint,
      35          57 :                   ulong addl_part_cnt ) {
      36          57 :   footprint = fd_ulong_align_up( footprint, FD_SHMEM_NORMAL_PAGE_SZ );
      37          57 :   void * mem = mmap( NULL, footprint, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );
      38          57 :   if( FD_UNLIKELY( mem==MAP_FAILED ) ) {
      39           0 :     FD_LOG_ERR(( "mmap(NULL,%lu KiB,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS) failed (%i-%s)",
      40           0 :                  footprint>>10, errno, fd_io_strerror( errno ) ));
      41           0 :   }
      42             : 
      43          57 :   ulong part_max = fd_wksp_part_max_est( footprint, 64UL<<10 );
      44          57 :   FD_TEST( part_max );
      45          57 :   part_max += addl_part_cnt;
      46          57 :   ulong data_max = fd_wksp_data_max_est( footprint, part_max );
      47          57 :   FD_TEST( data_max );
      48          57 :   fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, "wksp", 1U, part_max, data_max ) );
      49          57 :   FD_TEST( wksp );
      50             : 
      51          57 :   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 ) );
      52          57 :   return wksp;
      53          57 : }
      54             : 
      55             : fd_svm_mini_t *
      56             : fd_svm_test_boot( int *    pargc,
      57             :                   char *** pargv,
      58          57 :                   fd_svm_mini_limits_t const * limits ) {
      59             : 
      60          57 :   fd_boot( pargc, pargv );
      61             : 
      62          57 :   char const * page_sz_cstr = fd_env_strip_cmdline_cstr ( pargc, pargv, "--page-sz",  NULL, NULL            );
      63          57 :   ulong        page_cnt     = fd_env_strip_cmdline_ulong( pargc, pargv, "--page-cnt", NULL, 0UL             );
      64          57 :   char const * wksp_name    = fd_env_strip_cmdline_cstr ( pargc, pargv, "--wksp",     NULL, NULL            );
      65          57 :   ulong        near_cpu     = fd_env_strip_cmdline_ulong( pargc, pargv, "--near-cpu", NULL, fd_log_cpu_id() );
      66          57 :   ulong        wksp_tag     = limits->wksp_tag ? limits->wksp_tag : 42UL;
      67             : 
      68          57 :   ulong data_max = fd_svm_mini_wksp_data_max( limits );
      69          57 :   ulong part_max = fd_wksp_part_max_est( data_max, 64UL<<10 );
      70          57 :   ulong wksp_sz  = fd_wksp_footprint( part_max, data_max );
      71          57 :   fd_wksp_t * wksp = NULL;
      72          57 :   if( wksp_name && !!wksp_name[0] ) {
      73           0 :     FD_LOG_NOTICE(( "Attaching to --wksp %s", wksp_name ));
      74           0 :     wksp = fd_wksp_attach( wksp_name );
      75          57 :   } else if( page_sz_cstr ) {
      76          57 :     ulong page_sz = fd_cstr_to_shmem_page_sz( page_sz_cstr );
      77          57 :     if( FD_UNLIKELY( !page_sz ) ) FD_LOG_ERR(( "Invalid --page-sz %s", page_sz_cstr ));
      78          57 :     if( FD_UNLIKELY( page_sz*page_cnt < wksp_sz ) ) {
      79          57 :       FD_LOG_WARNING(( "--page-sz %s * --page-cnt %lu is smaller than required wksp_sz %lu KiB; falling back to lazy anonymous memory",
      80          57 :                        page_sz_cstr, page_cnt, wksp_sz>>10 ));
      81          57 :       goto fallback;
      82          57 :     }
      83           0 :     FD_LOG_NOTICE(( "--wksp not specified, using anonymous pinned shmem" ));
      84           0 :     wksp = fd_wksp_new_anonymous( page_sz, page_cnt, near_cpu, "wksp", wksp_tag );
      85           0 :   } else {
      86          57 : fallback:
      87          57 :     FD_LOG_NOTICE(( "--page-sz not specified, using lazy paged memory" ));
      88          57 :     wksp = fd_wksp_new_lazy( wksp_sz, limits->wksp_addl_part_cnt );
      89          57 :   }
      90          57 :   if( FD_UNLIKELY( !wksp ) ) FD_LOG_ERR(( "Unable to attach to wksp" ));
      91             : 
      92          57 :   return fd_svm_mini_create( wksp, limits );
      93          57 : }
      94             : 
      95             : void
      96          57 : fd_svm_test_halt( fd_svm_mini_t * mini ) {
      97          57 :   fd_svm_mini_destroy( mini );
      98          57 :   fd_halt();
      99          57 : }
     100             : 
     101             : ulong
     102          57 : fd_svm_mini_wksp_data_max( fd_svm_mini_limits_t const * limits ) {
     103          57 :   ulong txn_max     = limits->max_live_slots;
     104          57 :   ulong joiner_cnt  = fd_ulong_max( limits->accdb_joiner_cnt, 1UL );
     105             : 
     106          57 :   ulong pcache_sz         = fd_progcache_shmem_footprint( txn_max, limits->max_progcache_recs );
     107          57 :   ulong txncache_shmem_sz = fd_txncache_shmem_footprint( txn_max, limits->max_txn_per_slot, 0 );
     108          57 :   ulong txncache_sz       = fd_txncache_footprint( txn_max );
     109          57 :   ulong banks_sz          = fd_banks_footprint( txn_max, limits->max_fork_width, limits->max_stake_accounts, limits->max_fallback_stake_accounts, limits->max_vote_accounts );
     110          57 :   ulong runtime_stack_sz  = fd_runtime_stack_footprint( limits->max_vote_accounts, limits->max_vote_accounts, limits->max_stake_accounts );
     111             : 
     112          57 :   ulong accdb_shmem_sz = fd_accdb_shmem_footprint( limits->max_accounts, limits->max_live_slots,
     113          57 :                                                     TEST_WRITES_PER_SLOT, TEST_PARTITION_CNT,
     114          57 :                                                     TEST_CACHE_FOOTPRINT, TEST_CACHE_MIN_RESERVED, joiner_cnt, 0UL );
     115          57 :   ulong accdb_join_sz  = fd_accdb_footprint( limits->max_live_slots );
     116             : 
     117         741 : # define WKSP_ALLOC(a,s) fd_ulong_align_up( fd_ulong_max((s),1UL), fd_ulong_max((a),FD_WKSP_ALIGN_DEFAULT) )
     118          57 :   ulong sz = 0UL;
     119          57 :   sz += WKSP_ALLOC( alignof(fd_svm_mini_t),     sizeof(fd_svm_mini_t)            );
     120          57 :   sz += WKSP_ALLOC( fd_accdb_shmem_align(),     accdb_shmem_sz                   );
     121          57 :   sz += WKSP_ALLOC( fd_accdb_align(),           accdb_join_sz                    );
     122          57 :   sz += WKSP_ALLOC( fd_progcache_shmem_align(), pcache_sz                        );
     123          57 :   sz += WKSP_ALLOC( FD_PROGCACHE_SCRATCH_ALIGN, FD_PROGCACHE_SCRATCH_FOOTPRINT   );
     124          57 :   sz += WKSP_ALLOC( fd_txncache_shmem_align(),  txncache_shmem_sz                );
     125          57 :   sz += WKSP_ALLOC( fd_txncache_align(),        txncache_sz                      );
     126          57 :   sz += WKSP_ALLOC( fd_banks_align(),           banks_sz                         );
     127          57 :   sz += WKSP_ALLOC( alignof(fd_runtime_t),      sizeof(fd_runtime_t)             );
     128          57 :   sz += WKSP_ALLOC( fd_runtime_stack_align(),   runtime_stack_sz                 );
     129          57 :   sz += WKSP_ALLOC( fd_vm_align(),              fd_vm_footprint()                );
     130          57 :   sz += WKSP_ALLOC( 1UL,                        limits->max_progcache_heap_bytes );
     131          57 :   sz += WKSP_ALLOC( 16UL,                       limits->wksp_addl_sz             );
     132          57 : # undef WKSP_ALLOC
     133             : 
     134          57 :   return sz;
     135          57 : }
     136             : 
     137             : fd_svm_mini_t *
     138             : fd_svm_mini_create( fd_wksp_t *                  wksp,
     139          57 :                     fd_svm_mini_limits_t const * limits ) {
     140             : 
     141          57 :   ulong const wksp_tag    = limits->wksp_tag ? limits->wksp_tag : 42UL;
     142          57 :   ulong const txn_max     = limits->max_live_slots;
     143          57 :   ulong const joiner_cnt  = fd_ulong_max( limits->accdb_joiner_cnt, 1UL );
     144             : 
     145          57 :   ulong pcache_sz        = fd_progcache_shmem_footprint( txn_max, limits->max_progcache_recs );
     146          57 :   ulong txncache_shmem_sz = fd_txncache_shmem_footprint( txn_max, limits->max_txn_per_slot, 0 );
     147          57 :   ulong txncache_sz       = fd_txncache_footprint( txn_max );
     148          57 :   ulong banks_sz         = fd_banks_footprint( txn_max, limits->max_fork_width,
     149          57 :                                                limits->max_stake_accounts, limits->max_fallback_stake_accounts,
     150          57 :                                                limits->max_vote_accounts );
     151          57 :   ulong runtime_stack_sz = fd_runtime_stack_footprint( limits->max_vote_accounts, limits->max_vote_accounts, limits->max_stake_accounts );
     152             : 
     153          57 :   ulong accdb_shmem_sz = fd_accdb_shmem_footprint( limits->max_accounts, limits->max_live_slots,
     154          57 :                                                     TEST_WRITES_PER_SLOT, TEST_PARTITION_CNT,
     155          57 :                                                     TEST_CACHE_FOOTPRINT, TEST_CACHE_MIN_RESERVED, joiner_cnt, 0UL );
     156          57 :   ulong accdb_join_sz  = fd_accdb_footprint( limits->max_live_slots );
     157             : 
     158             :   /* Allocate objects */
     159             : 
     160          57 :   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 )) );
     161          57 :   void *          accdb_shmem;   FD_TEST( (accdb_shmem    = fd_wksp_alloc_laddr( wksp, fd_accdb_shmem_align(),     accdb_shmem_sz,                 wksp_tag )) );
     162          57 :   void *          accdb_join;    FD_TEST( (accdb_join     = fd_wksp_alloc_laddr( wksp, fd_accdb_align(),           accdb_join_sz,                  wksp_tag )) );
     163          57 :   void *          pcache_mem;    FD_TEST( (pcache_mem     = fd_wksp_alloc_laddr( wksp, fd_progcache_shmem_align(), pcache_sz,                      wksp_tag )) );
     164          57 :   uchar *         scratch;       FD_TEST( (scratch        = fd_wksp_alloc_laddr( wksp, FD_PROGCACHE_SCRATCH_ALIGN, FD_PROGCACHE_SCRATCH_FOOTPRINT, wksp_tag )) );
     165          57 :   void *          txncache_shmem; FD_TEST( (txncache_shmem = fd_wksp_alloc_laddr( wksp, fd_txncache_shmem_align(), txncache_shmem_sz,              wksp_tag )) );
     166          57 :   void *          txncache_mem;   FD_TEST( (txncache_mem   = fd_wksp_alloc_laddr( wksp, fd_txncache_align(),       txncache_sz,                    wksp_tag )) );
     167          57 :   void *          banks_mem;     FD_TEST( (banks_mem      = fd_wksp_alloc_laddr( wksp, fd_banks_align(),           banks_sz,                       wksp_tag )) );
     168          57 :   fd_runtime_t *  runtime;       FD_TEST( (runtime        = fd_wksp_alloc_laddr( wksp, alignof(fd_runtime_t),      sizeof(fd_runtime_t),           wksp_tag )) );
     169          57 :   void *          rstack_mem;    FD_TEST( (rstack_mem     = fd_wksp_alloc_laddr( wksp, fd_runtime_stack_align(),   runtime_stack_sz,               wksp_tag )) );
     170          57 :   void *          vm_mem;        FD_TEST( (vm_mem         = fd_wksp_alloc_laddr( wksp, fd_vm_align(),              fd_vm_footprint(),              wksp_tag )) );
     171             : 
     172             :   /* Initialize objects */
     173             : 
     174          57 :   fd_memset( mini, 0, sizeof(fd_svm_mini_t) );
     175          57 :   mini->wksp = wksp;
     176             : 
     177          57 :   fd_txncache_shmem_t * shtxncache = fd_txncache_shmem_join( fd_txncache_shmem_new( txncache_shmem, txn_max, limits->max_txn_per_slot, 0, 0UL ) );
     178          57 :   if( FD_UNLIKELY( !shtxncache ) ) FD_LOG_ERR(( "fd_txncache_shmem_new failed" ));
     179             : 
     180             :   /* Create accdb backed by memfd */
     181          57 :   int accdb_fd = memfd_create( "accdb_test", 0 );
     182          57 :   if( FD_UNLIKELY( accdb_fd<0 ) ) FD_LOG_ERR(( "memfd_create failed (%i-%s)", errno, fd_io_strerror( errno ) ));
     183             : 
     184          57 :   fd_accdb_shmem_t * shmem = fd_accdb_shmem_join(
     185          57 :       fd_accdb_shmem_new( accdb_shmem, limits->max_accounts, limits->max_live_slots,
     186          57 :                           TEST_WRITES_PER_SLOT, TEST_PARTITION_CNT,
     187          57 :                           TEST_PARTITION_SZ, TEST_CACHE_FOOTPRINT, TEST_CACHE_MIN_RESERVED, 0, 42UL, joiner_cnt, 0UL ) );
     188          57 :   FD_TEST( shmem );
     189          57 :   fd_accdb_t * accdb = fd_accdb_join( fd_accdb_new( accdb_join, shmem, accdb_fd, 0UL, NULL ) );
     190          57 :   FD_TEST( accdb );
     191             : 
     192             :   /* Save accdb init params for reset */
     193          57 :   mini->accdb_fd             = accdb_fd;
     194          57 :   mini->accdb_shmem_mem      = accdb_shmem;
     195          57 :   mini->accdb_join_mem       = accdb_join;
     196          57 :   mini->accdb_max_accounts   = limits->max_accounts;
     197          57 :   mini->accdb_max_live_slots = limits->max_live_slots;
     198          57 :   mini->accdb_joiner_cnt     = joiner_cnt;
     199             : 
     200          57 :   void * shpcache = fd_progcache_shmem_new( pcache_mem, wksp_tag, 1UL, txn_max, limits->max_progcache_recs );
     201          57 :   if( FD_UNLIKELY( !shpcache ) ) FD_LOG_ERR(( "fd_progcache_shmem_new failed" ));
     202             : 
     203          57 :   FD_TEST( fd_progcache_join( mini->progcache, pcache_mem, scratch, FD_PROGCACHE_SCRATCH_FOOTPRINT ) );
     204          57 :   mini->txncache_shmem = shtxncache;
     205          57 :   FD_TEST( (mini->txncache = fd_txncache_join( fd_txncache_new( txncache_mem, shtxncache ) )) );
     206             : 
     207          57 :   mini->banks = fd_banks_join( fd_banks_new( banks_mem, txn_max, limits->max_fork_width,
     208          57 :                                limits->max_stake_accounts, limits->max_fallback_stake_accounts,
     209          57 :                                limits->max_vote_accounts, 0, 8888UL ) );
     210          57 :   FD_TEST( mini->banks );
     211             : 
     212          57 :   mini->runtime = runtime;
     213             : 
     214          57 :   runtime->accdb        = accdb;
     215          57 :   runtime->status_cache = mini->txncache;
     216          57 :   runtime->progcache    = mini->progcache;
     217             : 
     218          57 :   runtime->instr.stack_sz          = 0;
     219          57 :   runtime->instr.trace_length      = 0;
     220          57 :   runtime->instr.current_idx       = 0;
     221          57 :   runtime->accounts.executable_cnt = 0;
     222          57 :   runtime->accounts.account_cnt    = 0;
     223          57 :   fd_memset( &runtime->log,     0, sizeof(runtime->log)     );
     224          57 :   fd_memset( &runtime->metrics, 0, sizeof(runtime->metrics) );
     225          57 :   fd_memset( &runtime->fuzz,    0, sizeof(runtime->fuzz)    );
     226             : 
     227          57 :   mini->runtime_stack = fd_runtime_stack_join( fd_runtime_stack_new( rstack_mem,
     228          57 :       limits->max_vote_accounts, limits->max_vote_accounts, limits->max_stake_accounts, 42UL ) );
     229          57 :   FD_TEST( mini->runtime_stack );
     230             : 
     231          57 :   fd_log_collector_init( mini->log_collector, 1 );
     232          57 :   runtime->log.enable_log_collector = 0;
     233          57 :   runtime->log.log_collector        = mini->log_collector;
     234             : 
     235          57 :   fd_features_disable_all( mini->features );
     236          57 :   fd_features_enable_cleaned_up( mini->features );
     237             : 
     238          57 :   FD_TEST( fd_sha256_join( fd_sha256_new( mini->sha256 ) ) );
     239             : 
     240          57 :   mini->vm = fd_vm_join( fd_vm_new( vm_mem ) );
     241          57 :   FD_TEST( mini->vm );
     242             : 
     243          57 :   return mini;
     244          57 : }
     245             : 
     246             : void
     247          57 : fd_svm_mini_destroy( fd_svm_mini_t * mini ) {
     248          57 :   if( FD_UNLIKELY( !mini ) ) return;
     249             : 
     250          57 :   if( mini->vm ) fd_wksp_free_laddr( fd_vm_delete( fd_vm_leave( mini->vm ) ) );
     251          57 :   if( mini->runtime_stack ) fd_wksp_free_laddr( mini->runtime_stack );
     252          57 :   if( mini->runtime ) fd_wksp_free_laddr( mini->runtime );
     253          57 :   if( mini->banks ) fd_wksp_free_laddr( mini->banks );
     254             : 
     255          57 :   if( mini->txncache ) {
     256          57 :     fd_wksp_free_laddr( mini->txncache );
     257          57 :     if( mini->txncache_shmem ) fd_wksp_free_laddr( mini->txncache_shmem );
     258          57 :   }
     259             : 
     260          57 :   uchar * scratch = mini->progcache->scratch;
     261          57 :   fd_progcache_shmem_t * shpcache = NULL;
     262          57 :   fd_progcache_leave( mini->progcache, &shpcache );
     263          57 :   if( scratch  ) fd_wksp_free_laddr( scratch );
     264          57 :   if( shpcache ) fd_wksp_free_laddr( fd_progcache_shmem_delete( shpcache ) );
     265             : 
     266             :   /* accdb shmem and join are workspace allocations, freed with mini */
     267             : 
     268          57 :   fd_wksp_free_laddr( mini );
     269          57 : }
     270             : 
     271             : static void
     272          87 : drain_background( fd_accdb_t * accdb ) {
     273          87 :   int charge_busy = 0;
     274          87 :   fd_accdb_background( accdb, &charge_busy );
     275          87 : }
     276             : 
     277             : static void
     278             : fd_svm_mini_init_mock_validators( fd_svm_mini_t *              mini,
     279             :                                   fd_bank_t *                  bank,
     280        3885 :                                   fd_svm_mini_params_t const * params ) {
     281             : 
     282        3885 :   ulong const N             = params->mock_validator_cnt;
     283        3885 :   ulong const uniform_stake = 1000000000UL; /* 1 SOL */
     284        3885 :   ulong const vote_min_bal  = fd_rent_exempt_minimum_balance( &bank->f.rent, FD_VOTE_STATE_V4_SZ );
     285        3885 :   ulong const stake_min_bal = fd_rent_exempt_minimum_balance( &bank->f.rent, FD_STAKE_STATE_SZ );
     286        3885 :   ulong const vote_bal      = fd_ulong_max( vote_min_bal, uniform_stake );
     287             : 
     288        3885 :   fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
     289        3885 :   ulong              fork_id     = bank->vote_stakes_fork_id;
     290             : 
     291        3885 :   fd_stake_delegations_t * stake_delegations = fd_banks_stake_delegations_root_query( mini->banks );
     292             : 
     293        3885 :   fd_vote_stake_weight_t * stakes = calloc( N, sizeof(fd_vote_stake_weight_t) );
     294        3885 :   FD_TEST( stakes );
     295             : 
     296        3885 :   fd_rng_t rng[1];
     297        3885 :   fd_rng_join( fd_rng_new( rng, (uint)params->hash_seed, 0UL ) );
     298             : 
     299        3885 :   fd_accdb_t *       accdb   = mini->runtime->accdb;
     300        3885 :   fd_accdb_fork_id_t root_fk = fd_banks_root( mini->banks )->accdb_fork_id;
     301             : 
     302        7797 :   for( ulong i=0UL; i<N; i++ ) {
     303             : 
     304             :     /* Generate deterministic pubkeys */
     305             : 
     306        3912 :     fd_pubkey_t identity_key, vote_key, stake_key;
     307       19560 :     for( ulong j=0UL; j<4UL; j++ ) identity_key.ul[j] = fd_rng_ulong( rng );
     308       19560 :     for( ulong j=0UL; j<4UL; j++ ) vote_key.ul[j]     = fd_rng_ulong( rng );
     309       19560 :     for( ulong j=0UL; j<4UL; j++ ) stake_key.ul[j]     = fd_rng_ulong( rng );
     310             : 
     311             :     /* Identity account */
     312             : 
     313        3912 :     fd_svm_mini_add_lamports_rooted( mini, &identity_key, 500000000000UL /* 500 SOL */ );
     314             : 
     315             :     /* Vote account */
     316             : 
     317        3912 :     {
     318        3912 :       uchar vote_state_data[ FD_VOTE_STATE_V4_SZ ] = {0};
     319             : 
     320        3912 :       fd_vote_state_versioned_t versioned[1];
     321        3912 :       FD_TEST( fd_vote_state_versioned_new( versioned, fd_vote_state_versioned_enum_v4 ) );
     322             : 
     323        3912 :       fd_vote_state_v4_t * vs               = &versioned->v4;
     324        3912 :       vs->node_pubkey                        = identity_key;
     325        3912 :       vs->authorized_withdrawer              = identity_key;
     326        3912 :       vs->inflation_rewards_collector        = vote_key;
     327        3912 :       vs->block_revenue_collector            = identity_key;
     328        3912 :       vs->inflation_rewards_commission_bps   = 1234U;
     329        3912 :       vs->block_revenue_commission_bps       = 10000U;
     330        3912 :       vs->has_bls_pubkey_compressed          = 1U;
     331        3912 :       fd_memset( vs->bls_pubkey_compressed, 0xBB, FD_BLS_PUBKEY_COMPRESSED_SZ );
     332             : 
     333        3912 :       fd_vote_authorized_voter_t * ele = fd_vote_authorized_voters_pool_ele_acquire( vs->authorized_voters.pool );
     334        3912 :       *ele = (fd_vote_authorized_voter_t){
     335        3912 :         .epoch  = 0UL,
     336        3912 :         .pubkey = identity_key,
     337        3912 :         .prio   = identity_key.uc[0],
     338        3912 :       };
     339        3912 :       fd_vote_authorized_voters_treap_ele_insert( vs->authorized_voters.treap, ele, vs->authorized_voters.pool );
     340        3912 :       FD_TEST( !fd_vote_state_versioned_serialize( versioned, vote_state_data, sizeof(vote_state_data) ) );
     341             : 
     342        3912 :       fd_acc_t acc = fd_accdb_write_one( accdb, root_fk, vote_key.uc );
     343        3912 :       acc.lamports = vote_bal;
     344        3912 :       fd_memcpy( acc.owner, fd_solana_vote_program_id.uc, 32UL );
     345        3912 :       fd_memcpy( acc.data, vote_state_data, FD_VOTE_STATE_V4_SZ );
     346        3912 :       acc.data_len = FD_VOTE_STATE_V4_SZ;
     347        3912 :       acc.commit = 1;
     348        3912 :       fd_accdb_unwrite_one( accdb, &acc );
     349        3912 :     }
     350             : 
     351             :     /* Stake account */
     352             : 
     353           0 :     {
     354        3912 :       uchar stake_data[ FD_STAKE_STATE_SZ ] = {0};
     355        3912 :       FD_STORE( fd_stake_state_t, stake_data, ((fd_stake_state_t) {
     356        3912 :         .stake_type = FD_STAKE_STATE_STAKE,
     357        3912 :         .stake = {
     358        3912 :           .meta = {
     359        3912 :             .rent_exempt_reserve = stake_min_bal,
     360        3912 :             .staker              = identity_key,
     361        3912 :             .withdrawer          = identity_key,
     362        3912 :           },
     363        3912 :           .stake = (fd_stake_t) {
     364        3912 :             .delegation = (fd_delegation_t) {
     365        3912 :               .voter_pubkey         = vote_key,
     366        3912 :               .stake                = uniform_stake,
     367        3912 :               .activation_epoch     = ULONG_MAX,
     368        3912 :               .deactivation_epoch   = ULONG_MAX,
     369        3912 :               .warmup_cooldown_rate = 0.25,
     370        3912 :             },
     371        3912 :             .credits_observed = 0UL,
     372        3912 :           },
     373        3912 :         },
     374        3912 :       }) );
     375             : 
     376        3912 :       fd_acc_t acc = fd_accdb_write_one( accdb, root_fk, stake_key.uc );
     377        3912 :       acc.lamports = fd_ulong_max( stake_min_bal, uniform_stake );
     378        3912 :       fd_memcpy( acc.owner, fd_solana_stake_program_id.uc, 32UL );
     379        3912 :       fd_memcpy( acc.data, stake_data, FD_STAKE_STATE_SZ );
     380        3912 :       acc.data_len = FD_STAKE_STATE_SZ;
     381        3912 :       acc.commit = 1;
     382        3912 :       fd_accdb_unwrite_one( accdb, &acc );
     383        3912 :     }
     384             : 
     385             :     /* Populate bank structures */
     386             : 
     387        3912 :     uchar const no_bls[ FD_BLS_PUBKEY_COMPRESSED_SZ ] = {0}; /* zeroed means no key is registered */
     388        3912 :     fd_vote_stakes_snap_insert_t_1( vote_stakes, fork_id, &vote_key, &identity_key, uniform_stake, 1234U, no_bls );
     389        3912 :     fd_vote_stakes_snap_insert_t_2( vote_stakes, fork_id, &vote_key, &identity_key, uniform_stake, 1234U, no_bls );
     390        3912 :     fd_vote_stakes_update_state( vote_stakes, fork_id, &vote_key, 0UL, 0L, 1 );
     391             : 
     392        3912 :     fd_epoch_credits_t * epoch_credits = &fd_bank_epoch_credits( bank )[ i ];
     393        3912 :     fd_memcpy( epoch_credits->pubkey, &vote_key, sizeof(fd_pubkey_t) );
     394        3912 :     epoch_credits->cnt          = 0UL;
     395        3912 :     epoch_credits->base_credits = 0UL;
     396             : 
     397        3912 :     fd_stake_delegations_root_update( stake_delegations,
     398        3912 :                                       &stake_key, &vote_key,
     399        3912 :                                       uniform_stake,
     400        3912 :                                       ULONG_MAX,  /* activation_epoch (bootstrap) */
     401        3912 :                                       ULONG_MAX,  /* deactivation_epoch */
     402        3912 :                                       0UL,        /* credits_observed */
     403        3912 :                                       fd_ulong_max( stake_min_bal, uniform_stake ),
     404        3912 :                                       (uint)FD_STAKE_STATE_SZ,
     405        3912 :                                       FD_STAKE_DELEGATIONS_WARMUP_COOLDOWN_RATE_ENUM_025 /* warmup_cooldown_rate */ );
     406             : 
     407        3912 :     stakes[i] = (fd_vote_stake_weight_t){
     408        3912 :       .vote_key = vote_key,
     409        3912 :       .id_key   = identity_key,
     410        3912 :       .stake    = uniform_stake,
     411        3912 :     };
     412        3912 :   }
     413        3885 :   *fd_bank_epoch_credits_len( bank ) = N;
     414             : 
     415             :   /* Create leader schedule */
     416             : 
     417        3885 :   ulong epoch    = bank->f.epoch;
     418        3885 :   ulong slot0    = fd_epoch_slot0( &bank->f.epoch_schedule, epoch );
     419        3885 :   ulong slot_cnt = bank->f.epoch_schedule.slots_per_epoch;
     420             : 
     421        3885 :   void * leaders_mem = fd_bank_epoch_leaders_modify( bank, epoch );
     422        3885 :   FD_TEST( fd_epoch_leaders_join( fd_epoch_leaders_new(
     423        3885 :       leaders_mem, epoch, slot0, slot_cnt, N, stakes ) ) );
     424             : 
     425        3885 :   fd_rng_delete( fd_rng_leave( rng ) );
     426        3885 :   free( stakes );
     427        3885 : }
     428             : 
     429             : ulong
     430             : fd_svm_mini_reset( fd_svm_mini_t *        mini,
     431        3909 :                    fd_svm_mini_params_t * params ) {
     432             : 
     433        3909 :   ulong mock_validator_max = fd_ulong_min( mini->banks->max_vote_accounts, FD_RUNTIME_MAX_VAT_VOTE_ACCOUNTS );
     434        3909 :   if( FD_UNLIKELY( params->mock_validator_cnt>mock_validator_max ) ) {
     435           0 :     FD_LOG_WARNING(( "mock_validator_cnt %lu exceeds capacity %lu",
     436           0 :                      params->mock_validator_cnt, mock_validator_max ));
     437           0 :     return ULONG_MAX;
     438           0 :   }
     439             : 
     440             :   /* Reset accdb: destroy and recreate shmem + join.
     441             :      The accdb shmem and join memory are wksp allocations that remain
     442             :      valid; we just re-initialize them in place. */
     443        3909 :   int accdb_fd = mini->accdb_fd;
     444             : 
     445             :   /* Re-initialize shmem in place */
     446        3909 :   fd_accdb_shmem_t * shmem = fd_accdb_shmem_join(
     447        3909 :       fd_accdb_shmem_new( mini->accdb_shmem_mem, mini->accdb_max_accounts, mini->accdb_max_live_slots,
     448        3909 :                           TEST_WRITES_PER_SLOT, TEST_PARTITION_CNT,
     449        3909 :                           TEST_PARTITION_SZ, TEST_CACHE_FOOTPRINT, TEST_CACHE_MIN_RESERVED, 0, 42UL, mini->accdb_joiner_cnt, 0UL ) );
     450        3909 :   FD_TEST( shmem );
     451             : 
     452             :   /* Re-truncate memfd */
     453        3909 :   FD_TEST( 0==ftruncate( accdb_fd, 0 ) );
     454             : 
     455             :   /* Re-initialize accdb join in place */
     456        3909 :   fd_accdb_t * accdb = fd_accdb_join( fd_accdb_new( mini->accdb_join_mem, shmem, accdb_fd, 0UL, NULL ) );
     457        3909 :   FD_TEST( accdb );
     458        3909 :   mini->runtime->accdb = accdb;
     459             : 
     460        3909 :   fd_progcache_reset( mini->progcache->join );
     461        3909 :   fd_txncache_reset( mini->txncache );
     462        3909 :   fd_banks_clear   ( mini->banks    );
     463             : 
     464        3909 :   fd_bank_t * bank = fd_banks_init_bank( mini->banks );
     465        3909 :   FD_TEST( bank );
     466        3909 :   ulong bank_idx = bank->idx;
     467             : 
     468        3909 :   bank->f.slot = params->root_slot;
     469             : 
     470        3909 :   bank->progcache_fork_id = fd_progcache_fork_id_initial();
     471        3909 :   bank->txncache_fork_id  = fd_txncache_attach_child( mini->txncache, (fd_txncache_fork_id_t){ USHORT_MAX } );
     472             : 
     473             :   /* Create the root fork in accdb */
     474        3909 :   fd_accdb_fork_id_t root_fork_id = fd_accdb_attach_child( accdb, SENTINEL );
     475        3909 :   bank->accdb_fork_id        = root_fork_id;
     476        3909 :   bank->parent_accdb_fork_id = root_fork_id;
     477             : 
     478        3909 :   if( params->clock ) {
     479           3 :     bank->f.slot  = params->clock->slot;
     480           3 :     bank->f.epoch = params->clock->epoch;
     481           3 :   }
     482             : 
     483        3909 :   if( params->epoch_schedule ) {
     484           0 :     bank->f.epoch_schedule = *params->epoch_schedule;
     485        3909 :   } else {
     486        3909 :     bank->f.epoch_schedule = (fd_epoch_schedule_t) {
     487        3909 :       .slots_per_epoch             = params->slots_per_epoch,
     488        3909 :       .leader_schedule_slot_offset = params->slots_per_epoch,
     489        3909 :       .warmup                      = 0,
     490        3909 :       .first_normal_epoch          = 0UL,
     491        3909 :       .first_normal_slot           = 0UL,
     492        3909 :     };
     493        3909 :   }
     494             : 
     495             :   /* Default slots_per_year matches Solana mainnet genesis defaults
     496             :      (target_tick_duration=6250000ns, ticks_per_slot=64). */
     497        3909 :   bank->f.slot_params                = FD_SLOT_PARAMS_400MS;
     498        3909 :   bank->f.slot_params.slots_per_year = SECONDS_PER_YEAR * (1000000000.0 / 6250000.0) / 64.0;
     499        3909 :   bank->f.slot_params_default        = bank->f.slot_params;
     500             : 
     501        3909 :   if( params->rent ) {
     502          27 :     bank->f.rent = *params->rent;
     503        3882 :   } else {
     504        3882 :     bank->f.rent = (fd_rent_t) {
     505        3882 :       .lamports_per_uint8_year = 3480UL,
     506        3882 :       .exemption_threshold     = 2.0,
     507        3882 :       .burn_percent            = 50,
     508        3882 :     };
     509        3882 :   }
     510             : 
     511        3909 :   fd_features_disable_all( &bank->f.features );
     512        3909 :   fd_features_enable_cleaned_up( &bank->f.features );
     513             : 
     514        3909 :   if( params->init_builtins ) {
     515        3909 :     fd_builtin_program_t const * builtins = fd_builtins();
     516       39090 :     for( ulong i=0UL; i<fd_num_builtins(); i++ ) {
     517       35181 :       char const * data = builtins[i].data;
     518       35181 :       ulong        sz   = strlen( data );
     519       35181 :       fd_acc_t acc = fd_accdb_write_one( accdb, root_fork_id, builtins[i].pubkey->uc );
     520       35181 :       acc.lamports = 1UL;
     521       35181 :       fd_memcpy( acc.owner, fd_solana_native_loader_id.uc, 32UL );
     522       35181 :       if( sz ) fd_memcpy( acc.data, data, sz );
     523       35181 :       acc.data_len   = sz;
     524       35181 :       acc.executable = 1;
     525       35181 :       acc.commit     = 1;
     526       35181 :       fd_accdb_unwrite_one( accdb, &acc );
     527       35181 :       bank->f.capitalization += acc.lamports;
     528       35181 :     }
     529             : 
     530        3909 :     fd_pubkey_t const * precompiles[] = {
     531        3909 :       &fd_solana_keccak_secp_256k_program_id,
     532        3909 :       &fd_solana_ed25519_sig_verify_program_id,
     533        3909 :       &fd_solana_secp256r1_program_id,
     534        3909 :     };
     535       15636 :     for( ulong i=0UL; i<3UL; i++ ) {
     536       11727 :       fd_acc_t acc = fd_accdb_write_one( accdb, root_fork_id, precompiles[i]->uc );
     537       11727 :       acc.lamports   = 1UL;
     538       11727 :       fd_memcpy( acc.owner, fd_solana_native_loader_id.uc, 32UL );
     539       11727 :       acc.data_len   = 0;
     540       11727 :       acc.executable = 1;
     541       11727 :       acc.commit     = 1;
     542       11727 :       fd_accdb_unwrite_one( accdb, &acc );
     543       11727 :       bank->f.capitalization += acc.lamports;
     544       11727 :     }
     545        3909 :   }
     546             : 
     547        3909 :   if( params->init_feature_accounts ) {
     548           0 :     for( fd_feature_id_t const * id = fd_feature_iter_init();
     549           0 :          !fd_feature_iter_done( id );
     550           0 :          id = fd_feature_iter_next( id ) ) {
     551           0 :       ulong activation_slot = fd_features_get( &bank->f.features, id );
     552           0 :       if( activation_slot==FD_FEATURE_DISABLED ) continue;
     553             : 
     554           0 :       fd_feature_t feature = { .is_active = 1, .activation_slot = activation_slot };
     555           0 :       fd_acc_t acc = fd_accdb_write_one( accdb, root_fork_id, id->id.uc );
     556           0 :       acc.lamports = 1UL;
     557           0 :       fd_memcpy( acc.owner, fd_solana_feature_program_id.uc, 32UL );
     558           0 :       fd_memcpy( acc.data, &feature, sizeof(fd_feature_t) );
     559           0 :       acc.data_len = sizeof(fd_feature_t);
     560           0 :       acc.commit   = 1;
     561           0 :       fd_accdb_unwrite_one( accdb, &acc );
     562           0 :       bank->f.capitalization += acc.lamports;
     563           0 :     }
     564           0 :   }
     565             : 
     566        3909 :   if( params->init_sysvars ) {
     567             : 
     568             :     /* Blockhash queue -- must be initialized before recent_hashes sysvar */
     569        3909 :     fd_blockhashes_t * bhq = fd_blockhashes_init( &bank->f.block_hash_queue, params->hash_seed );
     570        3909 :     fd_hash_t genesis_hash = {0};
     571        3909 :     fd_memset( genesis_hash.uc, 0xAB, FD_HASH_FOOTPRINT );
     572        3909 :     fd_blockhash_info_t * bh_info = fd_blockhashes_push_new( bhq, &genesis_hash );
     573        3909 :     bh_info->lamports_per_signature = 0UL;
     574        3909 :     bank->f.poh = genesis_hash;
     575             : 
     576             :     /* Clock */
     577        3909 :     fd_sol_sysvar_clock_t clock = {
     578        3909 :       .slot                  = bank->f.slot,
     579        3909 :       .leader_schedule_epoch = 1,
     580        3909 :     };
     581        3909 :     if( params->clock ) clock = *params->clock;
     582             : 
     583             :     /* Last restart slot */
     584        3909 :     uchar last_restart_enc[ FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ ] = {0};
     585             : 
     586             :     /* Recent hashes (encodes from blockhash queue -- initially 1 acc) */
     587        3909 :     uchar recent_hashes_enc[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] = {0};
     588        3909 :     ulong rbh_cnt = 1UL;
     589        3909 :     memcpy( recent_hashes_enc, &rbh_cnt, sizeof(ulong) );
     590        3909 :     memcpy( recent_hashes_enc + sizeof(ulong), genesis_hash.uc, 32 );
     591             :     /* lamports_per_signature = 0 already zeroed */
     592             : 
     593             :     /* Slot hashes (empty) */
     594        3909 :     uchar slot_hashes_enc[ FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ] = {0};
     595             : 
     596             :     /* Slot history -- well-formed bincode (large, heap alloc) */
     597        3909 :     uchar * slot_history_enc = calloc( 1, FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ );
     598        3909 :     FD_TEST( slot_history_enc );
     599        3909 :     ulong sh_blocks_len = FD_SLOT_HISTORY_MAX_ENTRIES / 64UL;
     600        3909 :     slot_history_enc[0] = 1; /* has_bits */
     601        3909 :     FD_STORE( ulong, slot_history_enc+1, sh_blocks_len );
     602        3909 :     uchar * sh_footer = slot_history_enc + 9UL + sh_blocks_len * sizeof(ulong);
     603        3909 :     FD_STORE( ulong, sh_footer,     FD_SLOT_HISTORY_MAX_ENTRIES );
     604        3909 :     FD_STORE( ulong, sh_footer+8UL, bank->f.slot + 1UL );
     605             : 
     606             :     /* Stake history (empty) */
     607        3909 :     uchar stake_history_enc[ FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ] = {0};
     608             : 
     609        3909 :     struct { fd_pubkey_t const * addr; void const * data; ulong sz; } sysvars[] = {
     610        3909 :       { &fd_sysvar_clock_id,               &clock,                  sizeof(clock)                     },
     611        3909 :       { &fd_sysvar_epoch_schedule_id,      &bank->f.epoch_schedule, sizeof(bank->f.epoch_schedule)    },
     612        3909 :       { &fd_sysvar_rent_id,                &bank->f.rent,           sizeof(bank->f.rent)              },
     613        3909 :       { &fd_sysvar_last_restart_slot_id,   last_restart_enc,        sizeof(last_restart_enc)          },
     614        3909 :       { &fd_sysvar_recent_block_hashes_id, recent_hashes_enc,       sizeof(recent_hashes_enc)         },
     615        3909 :       { &fd_sysvar_slot_hashes_id,         slot_hashes_enc,         sizeof(slot_hashes_enc)           },
     616        3909 :       { &fd_sysvar_slot_history_id,        slot_history_enc,        FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ },
     617        3909 :       { &fd_sysvar_stake_history_id,       stake_history_enc,       sizeof(stake_history_enc)         },
     618        3909 :     };
     619       35181 :     for( ulong i=0UL; i<8UL; i++ ) {
     620       31272 :       fd_acc_t acc = fd_accdb_write_one( accdb, root_fork_id, sysvars[i].addr->uc );
     621       31272 :       acc.lamports = fd_rent_exempt_minimum_balance( &bank->f.rent, sysvars[i].sz );
     622       31272 :       fd_memcpy( acc.owner, fd_sysvar_owner_id.uc, 32UL );
     623       31272 :       if( sysvars[i].sz ) fd_memcpy( acc.data, sysvars[i].data, sysvars[i].sz );
     624       31272 :       acc.data_len = sysvars[i].sz;
     625       31272 :       acc.commit   = 1;
     626       31272 :       fd_accdb_unwrite_one( accdb, &acc );
     627       31272 :       bank->f.capitalization += acc.lamports;
     628       31272 :     }
     629             : 
     630        3909 :     free( slot_history_enc );
     631             : 
     632        3909 :     FD_TEST( fd_sysvar_cache_restore( bank, accdb ) );
     633        3909 :   }
     634             : 
     635        3909 :   *fd_bank_epoch_credits_len( bank ) = 0UL;
     636             : 
     637        3909 :   if( params->mock_validator_cnt ) {
     638        3885 :     fd_svm_mini_init_mock_validators( mini, bank, params );
     639        3885 :   }
     640             : 
     641        3909 :   fd_hash_t const * root_block_hash = fd_blockhashes_peek_last_hash( &bank->f.block_hash_queue );
     642        3909 :   if( FD_LIKELY( root_block_hash ) ) {
     643        3909 :     fd_txncache_finalize_fork( mini->txncache, bank->txncache_fork_id, 0UL, root_block_hash->uc );
     644        3909 :   }
     645             : 
     646        3909 :   return bank_idx;
     647        3909 : }
     648             : 
     649             : ulong
     650             : fd_svm_mini_attach_child( fd_svm_mini_t * mini,
     651             :                           ulong           parent_bank_idx,
     652        4098 :                           ulong           child_slot ) {
     653             : 
     654        4098 :   fd_bank_t * parent_bank = fd_banks_bank_query( mini->banks, parent_bank_idx );
     655        4098 :   if( FD_UNLIKELY( !parent_bank ) ) FD_LOG_ERR(( "invalid parent_bank_idx" ));
     656        4098 :   ulong parent_slot = parent_bank->f.slot;
     657        4098 :   if( FD_UNLIKELY( child_slot<=parent_slot ) ) FD_LOG_ERR(( "child_slot (%lu) <= parent_slot (%lu)", child_slot, parent_slot ));
     658             : 
     659        4098 :   fd_accdb_t * accdb = mini->runtime->accdb;
     660             : 
     661        4098 :   fd_bank_t * bank = fd_banks_new_bank( mini->banks, parent_bank_idx, 0L, 0 );
     662        4098 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "fd_banks_new_bank failed" ));
     663        4098 :   bank = fd_banks_clone_from_parent( mini->banks, bank->idx );
     664        4098 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "fd_banks_clone_from_parent failed" ));
     665        4098 :   ulong bank_idx = bank->idx;
     666        4098 :   bank->f.slot = child_slot;
     667             : 
     668        4098 :   bank->progcache_fork_id    = fd_progcache_attach_child( mini->progcache->join, parent_bank->progcache_fork_id );
     669        4098 :   bank->txncache_fork_id     = fd_txncache_attach_child ( mini->txncache,        parent_bank->txncache_fork_id  );
     670        4098 :   bank->accdb_fork_id        = fd_accdb_attach_child    ( accdb,                 parent_bank->accdb_fork_id     );
     671        4098 :   bank->parent_accdb_fork_id = parent_bank->accdb_fork_id;
     672             : 
     673        4098 :   int is_epoch_boundary = 0;
     674        4098 :   fd_runtime_block_execute_prepare( mini->banks, bank, accdb, mini->runtime_stack, NULL, &is_epoch_boundary );
     675             : 
     676        4098 :   return bank_idx;
     677        4098 : }
     678             : 
     679             : void
     680             : fd_svm_mini_freeze( fd_svm_mini_t * mini,
     681         345 :                     ulong           bank_idx ) {
     682         345 :   fd_bank_t * bank = fd_svm_mini_bank( mini, bank_idx );
     683         345 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     684             :   /* Derive a mock POH hash so each frozen slot registers a unique
     685             :      blockhash.  (Real POH is computed by the PoH tile.) */
     686         345 :   fd_sha256_hash( bank->f.poh.hash, 32UL, bank->f.poh.hash );
     687         345 :   fd_runtime_block_execute_finalize( bank, mini->runtime->accdb, NULL, NULL, 0UL );
     688         345 :   fd_hash_t const * block_hash = fd_blockhashes_peek_last_hash( &bank->f.block_hash_queue );
     689         345 :   FD_TEST( block_hash );
     690         345 :   fd_txncache_finalize_fork( mini->txncache, bank->txncache_fork_id, 0UL, block_hash->uc );
     691         345 :   fd_banks_mark_bank_frozen( bank );
     692         345 : }
     693             : 
     694             : void
     695             : fd_svm_mini_register_blockhash( fd_svm_mini_t *   mini,
     696             :                                 ulong             bank_idx,
     697          39 :                                 fd_hash_t const * blockhash ) {
     698          39 :   fd_bank_t * bank = fd_svm_mini_bank( mini, bank_idx );
     699          39 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     700             :   /* A txncache query for blockhash B from fork F succeeds only if F
     701             :      descends from the fork B is registered on; a fork's descends-set
     702             :      contains its ancestors, NOT itself.  So register B on bank_idx's
     703             :      PARENT fork — the bank then executes as a descendant and the
     704             :      status-cache query resolves B. */
     705          39 :   fd_bank_t * parent = fd_banks_get_parent( mini->banks, bank );
     706          39 :   if( FD_UNLIKELY( !parent ) ) FD_LOG_ERR(( "bank_idx has no parent fork to register the blockhash on" ));
     707             :   /* finalize_fork (not attach_blockhash): the status-cache query
     708             :      requires the carrier fork to be fully finalized (frozen==2), which
     709             :      attach_blockhash (frozen==1) does not satisfy.  finalize_fork
     710             :      registers the blockhash in the map and sets frozen==2. */
     711          39 :   fd_txncache_finalize_fork( mini->txncache, parent->txncache_fork_id, 0UL, blockhash->uc );
     712          39 : }
     713             : 
     714             : static void
     715             : fd_svm_mini_txncache_cancel_subtree( fd_svm_mini_t * mini,
     716           0 :                                      fd_bank_t *     bank ) {
     717           0 :   ulong child_idx = bank->child_idx;
     718           0 :   while( child_idx!=ULONG_MAX ) {
     719           0 :     fd_bank_t * child = fd_banks_bank_query( mini->banks, child_idx );
     720           0 :     FD_TEST( child );
     721           0 :     ulong sibling_idx = child->sibling_idx;
     722           0 :     fd_svm_mini_txncache_cancel_subtree( mini, child );
     723           0 :     child_idx = sibling_idx;
     724           0 :   }
     725           0 :   fd_txncache_cancel_fork( mini->txncache, bank->txncache_fork_id );
     726           0 : }
     727             : 
     728             : void
     729             : fd_svm_mini_cancel_fork( fd_svm_mini_t * mini,
     730           0 :                          ulong           bank_idx ) {
     731             : 
     732           0 :   fd_bank_t * bank = fd_svm_mini_bank( mini, bank_idx );
     733           0 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     734             : 
     735           0 :   fd_progcache_cancel_fork( mini->progcache->join, bank->progcache_fork_id );
     736           0 :   fd_svm_mini_txncache_cancel_subtree( mini, bank );
     737             : 
     738           0 :   fd_accdb_purge( mini->runtime->accdb, bank->accdb_fork_id );
     739           0 :   drain_background( mini->runtime->accdb );
     740           0 : }
     741             : 
     742             : void
     743             : fd_svm_mini_advance_root( fd_svm_mini_t * mini,
     744          87 :                           ulong           bank_idx ) {
     745             : 
     746          87 :   fd_bank_t * bank = fd_banks_bank_query( mini->banks, bank_idx );
     747          87 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     748             : 
     749          87 :   fd_progcache_advance_root( mini->progcache->join, bank->progcache_fork_id );
     750          87 :   fd_txncache_advance_root ( mini->txncache,        bank->txncache_fork_id  );
     751          87 :   fd_accdb_advance_root( mini->runtime->accdb, bank->accdb_fork_id );
     752          87 :   drain_background( mini->runtime->accdb );
     753          87 :   fd_banks_advance_root( mini->banks, bank_idx );
     754          87 : }
     755             : 
     756             : fd_bank_t *
     757             : fd_svm_mini_bank( fd_svm_mini_t * mini,
     758        8043 :                   ulong           bank_idx ) {
     759        8043 :   if( FD_UNLIKELY( bank_idx>=fd_banks_pool_max_cnt( mini->banks ) ) ) return NULL;
     760        8043 :   fd_bank_t * bank = fd_banks_bank_query( mini->banks, bank_idx );
     761        8043 :   if( FD_UNLIKELY( !bank ) ) return NULL;
     762        8043 :   return bank;
     763        8043 : }
     764             : 
     765             : fd_accdb_fork_id_t
     766             : fd_svm_mini_fork_id( fd_svm_mini_t * mini,
     767         876 :                      ulong           bank_idx ) {
     768         876 :   fd_bank_t * bank = fd_banks_bank_query( mini->banks, bank_idx );
     769         876 :   if( FD_UNLIKELY( !bank ) ) FD_LOG_ERR(( "invalid bank_idx" ));
     770         876 :   return bank->accdb_fork_id;
     771         876 : }
     772             : 
     773             : void
     774             : fd_svm_mini_put_account_rooted( fd_svm_mini_t *  mini,
     775        7860 :                                 fd_acc_t const * ro ) {
     776        7860 :   fd_accdb_t *       accdb   = mini->runtime->accdb;
     777        7860 :   fd_bank_t *        root    = fd_banks_root( mini->banks );
     778        7860 :   fd_accdb_fork_id_t root_fk = root->accdb_fork_id;
     779             : 
     780        7860 :   ulong old_lamports = fd_accdb_lamports( accdb, root_fk, ro->pubkey );
     781        7860 :   if( old_lamports==ULONG_MAX ) old_lamports = 0UL;
     782             : 
     783        7860 :   fd_acc_t acc = fd_accdb_write_one( accdb, root_fk, ro->pubkey );
     784        7860 :   acc.lamports   = ro->lamports;
     785        7860 :   fd_memcpy( acc.owner, ro->owner, 32UL );
     786        7860 :   acc.executable = ro->executable;
     787        7860 :   acc.data_len   = ro->data_len;
     788        7860 :   if( ro->data_len && ro->data ) fd_memcpy( acc.data, ro->data, ro->data_len );
     789        7860 :   acc.commit = 1;
     790        7860 :   fd_accdb_unwrite_one( accdb, &acc );
     791             : 
     792        7860 :   if( root ) {
     793        7860 :     if( ro->lamports >= old_lamports )
     794        7857 :       root->f.capitalization += ro->lamports - old_lamports;
     795           3 :     else
     796           3 :       root->f.capitalization -= old_lamports - ro->lamports;
     797        7860 :   }
     798        7860 : }
     799             : 
     800             : void
     801             : fd_svm_mini_add_lamports_rooted( fd_svm_mini_t *     mini,
     802             :                                  fd_pubkey_t const * pubkey,
     803        3933 :                                  ulong               lamports ) {
     804        3933 :   fd_accdb_t *       accdb   = mini->runtime->accdb;
     805        3933 :   fd_bank_t *        root    = fd_banks_root( mini->banks );
     806        3933 :   fd_accdb_fork_id_t root_fk = root->accdb_fork_id;
     807             : 
     808        3933 :   fd_acc_t acc = fd_accdb_write_one( accdb, root_fk, pubkey->uc );
     809        3933 :   ulong balance = acc.lamports;
     810        3933 :   FD_TEST( !__builtin_uaddl_overflow( balance, lamports, &balance ) );
     811        3933 :   acc.lamports = balance;
     812        3933 :   acc.commit = 1;
     813        3933 :   fd_accdb_unwrite_one( accdb, &acc );
     814             : 
     815        3933 :   if( root ) root->f.capitalization += lamports;
     816        3933 : }
     817             : 
     818             : void
     819             : fd_svm_mini_add_lamports( fd_svm_mini_t *     mini,
     820             :                           fd_accdb_fork_id_t  fork_id,
     821             :                           fd_pubkey_t const * pubkey,
     822          54 :                           ulong               lamports ) {
     823          54 :   fd_accdb_t * accdb = mini->runtime->accdb;
     824             : 
     825          54 :   fd_acc_t acc = fd_accdb_write_one( accdb, fork_id, pubkey->uc );
     826          54 :   ulong balance = acc.lamports;
     827          54 :   FD_TEST( !__builtin_uaddl_overflow( balance, lamports, &balance ) );
     828          54 :   acc.lamports = balance;
     829          54 :   acc.commit = 1;
     830          54 :   fd_accdb_unwrite_one( accdb, &acc );
     831             : 
     832             :   /* Find the bank with this fork_id to update capitalization.
     833             :      Linear scan is fine for test code. */
     834          99 :   for( ulong i=0UL; i<fd_banks_pool_max_cnt( mini->banks ); i++ ) {
     835          99 :     fd_bank_t * bank = fd_banks_bank_query( mini->banks, i );
     836          99 :     if( bank && bank->accdb_fork_id.val==fork_id.val ) {
     837          54 :       bank->f.capitalization += lamports;
     838          54 :       break;
     839          54 :     }
     840          99 :   }
     841          54 : }

Generated by: LCOV version 1.14