LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_svm_mini.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 577 626 92.2 %
Date: 2026-10-18 04:43:39 Functions: 18 20 90.0 %

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

Generated by: LCOV version 1.14