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 : }
|