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

Generated by: LCOV version 1.14