Line data Source code
1 :
2 : #undef FD_SPAD_USE_HANDHOLDING
3 : #define FD_SPAD_USE_HANDHOLDING 1
4 :
5 : #include "fd_instr_harness.h"
6 : #include "../../fd_system_ids.h"
7 : #include "../../sysvar/fd_sysvar_clock.h"
8 : #include "../../sysvar/fd_sysvar_epoch_schedule.h"
9 : #include "../../sysvar/fd_sysvar_recent_hashes.h"
10 : #include "../../sysvar/fd_sysvar_last_restart_slot.h"
11 : #include "../../sysvar/fd_sysvar_rent.h"
12 :
13 : int
14 : fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner,
15 : fd_exec_instr_ctx_t * ctx,
16 : fd_exec_test_instr_context_t const * test_ctx,
17 0 : bool is_syscall ) {
18 :
19 0 : memset( ctx, 0, sizeof(fd_exec_instr_ctx_t) );
20 :
21 0 : fd_funk_t * funk = runner->funk;
22 :
23 : /* Generate unique ID for funk txn */
24 :
25 0 : fd_funk_txn_xid_t xid[1] = {0};
26 0 : xid[0] = fd_funk_generate_xid();
27 :
28 : /* Create temporary funk transaction and txn / slot / epoch contexts */
29 :
30 0 : fd_funk_txn_start_write( funk );
31 0 : fd_funk_txn_t * funk_txn = fd_funk_txn_prepare( funk, NULL, xid, 1 );
32 0 : fd_funk_txn_end_write( funk );
33 :
34 : /* Allocate contexts */
35 0 : uchar * slot_ctx_mem = fd_spad_alloc( runner->spad,FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT );
36 0 : uchar * txn_ctx_mem = fd_spad_alloc( runner->spad,FD_EXEC_TXN_CTX_ALIGN, FD_EXEC_TXN_CTX_FOOTPRINT );
37 :
38 0 : fd_exec_slot_ctx_t * slot_ctx = fd_exec_slot_ctx_join ( fd_exec_slot_ctx_new ( slot_ctx_mem ) );
39 0 : fd_exec_txn_ctx_t * txn_ctx = fd_exec_txn_ctx_join ( fd_exec_txn_ctx_new ( txn_ctx_mem ), runner->spad, fd_wksp_containing( runner->spad ) );
40 :
41 0 : assert( slot_ctx );
42 :
43 0 : ctx->txn_ctx = txn_ctx;
44 :
45 : /* Set up slot context */
46 :
47 0 : slot_ctx->funk_txn = funk_txn;
48 0 : slot_ctx->funk = funk;
49 :
50 : /* Bank manager */
51 :
52 0 : slot_ctx->bank = runner->bank;
53 0 : fd_bank_clear_bank( slot_ctx->bank );
54 :
55 0 : fd_features_t * features = fd_bank_features_modify( slot_ctx->bank );
56 0 : fd_exec_test_feature_set_t const * feature_set = &test_ctx->epoch_context.features;
57 0 : if( !fd_runtime_fuzz_restore_features( features, feature_set ) ) {
58 0 : return 0;
59 0 : }
60 :
61 : /* Set up epoch context. Defaults obtained from GenesisConfig::Default() */
62 :
63 0 : fd_rent_t * rent_bm = fd_bank_rent_modify( slot_ctx->bank );
64 0 : rent_bm->lamports_per_uint8_year = 3480;
65 0 : rent_bm->exemption_threshold = 2;
66 0 : rent_bm->burn_percent = 50;
67 :
68 : /* Blockhash queue init */
69 :
70 0 : fd_block_hash_queue_global_t * block_hash_queue = fd_bank_block_hash_queue_modify( slot_ctx->bank );
71 :
72 0 : uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)block_hash_queue + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) );
73 0 : uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() );
74 0 : fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, 400 ) );
75 :
76 0 : block_hash_queue->max_age = FD_BLOCKHASH_QUEUE_MAX_ENTRIES;
77 0 : block_hash_queue->ages_root_offset = 0UL;
78 0 : fd_block_hash_queue_ages_pool_update( block_hash_queue, ages_pool );
79 0 : block_hash_queue->last_hash_index = 0UL;
80 0 : block_hash_queue->last_hash_offset = (ulong)last_hash_mem - (ulong)block_hash_queue;
81 :
82 0 : memset( last_hash_mem, 0, sizeof(fd_hash_t) );
83 :
84 : /* Set up txn context */
85 :
86 0 : fd_wksp_t * funk_wksp = fd_funk_wksp( funk );
87 0 : fd_wksp_t * runtime_wksp = fd_wksp_containing( slot_ctx );
88 0 : ulong funk_txn_gaddr = fd_wksp_gaddr( funk_wksp, funk_txn );
89 0 : ulong funk_gaddr = fd_wksp_gaddr( funk_wksp, funk->shmem );
90 :
91 : /* Set up mock txn descriptor */
92 0 : fd_txn_t * txn_descriptor = fd_spad_alloc( runner->spad, fd_txn_align(), fd_txn_footprint( 1UL, 0UL ) );
93 0 : txn_descriptor->transaction_version = FD_TXN_V0;
94 0 : txn_descriptor->acct_addr_cnt = (ushort)test_ctx->accounts_count;
95 :
96 0 : fd_exec_txn_ctx_from_exec_slot_ctx( slot_ctx,
97 0 : txn_ctx,
98 0 : funk_wksp,
99 0 : runtime_wksp,
100 0 : funk_txn_gaddr,
101 0 : funk_gaddr,
102 0 : NULL );
103 0 : fd_exec_txn_ctx_setup_basic( txn_ctx );
104 :
105 0 : txn_ctx->txn_descriptor = txn_descriptor;
106 0 : txn_ctx->compute_unit_limit = test_ctx->cu_avail;
107 0 : txn_ctx->compute_meter = test_ctx->cu_avail;
108 0 : txn_ctx->vote_accounts_pool = NULL;
109 0 : txn_ctx->spad = runner->spad;
110 0 : txn_ctx->instr_info_cnt = 1UL;
111 :
112 : /* Set up instruction context */
113 :
114 0 : fd_instr_info_t * info = fd_spad_alloc( runner->spad, 8UL, sizeof(fd_instr_info_t) );
115 0 : assert( info );
116 0 : memset( info, 0, sizeof(fd_instr_info_t) );
117 :
118 0 : if( test_ctx->data ) {
119 0 : info->data_sz = (ushort)test_ctx->data->size;
120 0 : info->data = test_ctx->data->bytes;
121 0 : }
122 :
123 : /* Prepare borrowed account table (correctly handles aliasing) */
124 :
125 0 : if( FD_UNLIKELY( test_ctx->accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) {
126 0 : FD_LOG_NOTICE(( "too many accounts" ));
127 0 : return 0;
128 0 : }
129 :
130 : /* Load accounts into database */
131 :
132 0 : fd_txn_account_t * accts = txn_ctx->accounts;
133 0 : fd_memset( accts, 0, test_ctx->accounts_count * sizeof(fd_txn_account_t) );
134 0 : txn_ctx->accounts_cnt = test_ctx->accounts_count;
135 :
136 0 : int has_program_id = 0;
137 :
138 0 : for( ulong j=0UL; j < test_ctx->accounts_count; j++ ) {
139 0 : memcpy( &(txn_ctx->account_keys[j]), test_ctx->accounts[j].address, sizeof(fd_pubkey_t) );
140 0 : if( !fd_runtime_fuzz_load_account( &accts[j], funk, funk_txn, &test_ctx->accounts[j], 0 ) ) {
141 0 : return 0;
142 0 : }
143 :
144 0 : fd_txn_account_t * acc = &accts[j];
145 0 : if( acc->vt->get_meta( acc ) ) {
146 0 : uchar * data = fd_spad_alloc( txn_ctx->spad, FD_ACCOUNT_REC_ALIGN, FD_ACC_TOT_SZ_MAX );
147 0 : ulong dlen = acc->vt->get_data_len( acc );
148 0 : fd_memcpy( data, acc->vt->get_meta( acc ), sizeof(fd_account_meta_t)+dlen );
149 0 : fd_txn_account_init_from_meta_and_data_readonly( acc,
150 0 : (fd_account_meta_t const *)data,
151 0 : data + sizeof(fd_account_meta_t) );
152 0 : }
153 :
154 0 : if( !memcmp( accts[j].pubkey, test_ctx->program_id, sizeof(fd_pubkey_t) ) ) {
155 0 : has_program_id = 1;
156 0 : info->program_id = (uchar)txn_ctx->accounts_cnt;
157 0 : }
158 :
159 : /* Since the instructions sysvar is set as mutable at the txn level, we need to make it mutable here as well. */
160 0 : if( !memcmp( accts[j].pubkey, &fd_sysvar_instructions_id, sizeof(fd_pubkey_t) ) ) {
161 0 : acc->vt->set_mutable( acc );
162 0 : }
163 0 : }
164 :
165 : /* If the program id is not in the set of accounts it must be added to the set of accounts. */
166 0 : if( FD_UNLIKELY( !has_program_id ) ) {
167 0 : fd_txn_account_t * program_acc = &accts[ test_ctx->accounts_count ];
168 0 : fd_pubkey_t * program_key = &txn_ctx->account_keys[ txn_ctx->accounts_cnt ];
169 0 : fd_txn_account_init( program_acc );
170 0 : memcpy( program_key, test_ctx->program_id, sizeof(fd_pubkey_t) );
171 0 : memcpy( program_acc->pubkey, test_ctx->program_id, sizeof(fd_pubkey_t) );
172 0 : fd_account_meta_t * meta = fd_spad_alloc( txn_ctx->spad, alignof(fd_account_meta_t), sizeof(fd_account_meta_t) );
173 0 : fd_account_meta_init( meta );
174 0 : program_acc->vt->set_meta_mutable( program_acc, meta );
175 0 : info->program_id = (uchar)txn_ctx->accounts_cnt;
176 0 : txn_ctx->accounts_cnt++;
177 0 : }
178 :
179 : /* Load in executable accounts */
180 0 : for( ulong i = 0; i < txn_ctx->accounts_cnt; i++ ) {
181 0 : fd_txn_account_t * acc = &accts[i];
182 0 : if ( !fd_executor_pubkey_is_bpf_loader( acc->vt->get_owner( acc ) ) ) {
183 0 : continue;
184 0 : }
185 :
186 0 : fd_account_meta_t const * meta = acc->vt->get_meta( acc );
187 0 : if (meta == NULL) {
188 0 : fd_txn_account_setup_sentinel_meta_readonly( acc, txn_ctx->spad, txn_ctx->spad_wksp );
189 0 : continue;
190 0 : }
191 :
192 0 : if( FD_UNLIKELY( 0 == memcmp(meta->info.owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t)) ) ) {
193 0 : int err = 0;
194 0 : fd_bpf_upgradeable_loader_state_t * program_loader_state = read_bpf_upgradeable_loader_state_for_program( txn_ctx,
195 0 : (ushort)i,
196 0 : &err );
197 :
198 0 : if( FD_UNLIKELY( !program_loader_state ) ) {
199 0 : continue;
200 0 : }
201 :
202 0 : if( !fd_bpf_upgradeable_loader_state_is_program( program_loader_state ) ) {
203 0 : continue;
204 0 : }
205 :
206 0 : fd_pubkey_t * programdata_acc = &program_loader_state->inner.program.programdata_address;
207 0 : if( FD_UNLIKELY( fd_txn_account_init_from_funk_readonly( &txn_ctx->executable_accounts[txn_ctx->executable_cnt],
208 0 : programdata_acc,
209 0 : txn_ctx->funk,
210 0 : txn_ctx->funk_txn ) ) ) {
211 0 : continue;
212 0 : }
213 0 : txn_ctx->executable_cnt++;
214 0 : }
215 0 : }
216 :
217 : /* Add accounts to bpf program cache */
218 0 : fd_bpf_scan_and_create_bpf_program_cache_entry( slot_ctx, runner->spad );
219 :
220 : /* Fill missing sysvar cache values with defaults */
221 : /* We create mock accounts for each of the sysvars and hardcode the data fields before loading it into the account manager */
222 : /* We use Agave sysvar defaults for data field values */
223 :
224 : /* Clock */
225 : // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L466-L474
226 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( funk, funk_txn, runner->spad );
227 0 : if( !clock ) {
228 0 : fd_sol_sysvar_clock_t sysvar_clock = {
229 0 : .slot = 10UL,
230 0 : .epoch_start_timestamp = 0L,
231 0 : .epoch = 0UL,
232 0 : .leader_schedule_epoch = 0UL,
233 0 : .unix_timestamp = 0L
234 0 : };
235 0 : fd_sysvar_clock_write( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &sysvar_clock );
236 0 : }
237 :
238 : /* Epoch schedule */
239 : // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L476-L483
240 0 : fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, runner->spad );
241 0 : if( !epoch_schedule ) {
242 0 : fd_epoch_schedule_t sysvar_epoch_schedule = {
243 0 : .slots_per_epoch = 432000UL,
244 0 : .leader_schedule_slot_offset = 432000UL,
245 0 : .warmup = 1,
246 0 : .first_normal_epoch = 14UL,
247 0 : .first_normal_slot = 524256UL
248 0 : };
249 0 : fd_sysvar_epoch_schedule_write( slot_ctx, &sysvar_epoch_schedule );
250 0 : }
251 :
252 : /* Rent */
253 : // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L487-L500
254 0 : fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad );
255 0 : if( !rent ) {
256 0 : fd_rent_t sysvar_rent = {
257 0 : .lamports_per_uint8_year = 3480UL,
258 0 : .exemption_threshold = 2.0,
259 0 : .burn_percent = 50
260 0 : };
261 0 : fd_sysvar_rent_write( slot_ctx, &sysvar_rent );
262 0 : }
263 :
264 0 : fd_sol_sysvar_last_restart_slot_t const * last_restart_slot = fd_sysvar_last_restart_slot_read( funk, funk_txn, runner->spad );
265 0 : if( !last_restart_slot ) {
266 :
267 0 : fd_sol_sysvar_last_restart_slot_t restart = { .slot = 5000UL };
268 :
269 0 : fd_sysvar_set( slot_ctx->bank,
270 0 : slot_ctx->funk,
271 0 : slot_ctx->funk_txn,
272 0 : &fd_sysvar_owner_id,
273 0 : &fd_sysvar_last_restart_slot_id,
274 0 : &restart.slot,
275 0 : sizeof(ulong),
276 0 : slot_ctx->slot );
277 :
278 0 : }
279 :
280 : /* Set slot bank variables */
281 0 : clock = fd_sysvar_clock_read( funk, funk_txn, runner->spad );
282 :
283 0 : slot_ctx->slot = clock->slot;
284 0 : slot_ctx->bank->slot = clock->slot;
285 :
286 : /* Handle undefined behavior if sysvars are malicious (!!!) */
287 :
288 : /* Override epoch bank rent setting */
289 0 : rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad );
290 0 : if( rent ) {
291 0 : fd_bank_rent_set( slot_ctx->bank, *rent );
292 0 : }
293 :
294 : /* Override most recent blockhash if given */
295 0 : fd_recent_block_hashes_global_t const * rbh_global = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad );
296 0 : fd_recent_block_hashes_t rbh[1];
297 0 : if( rbh_global ) {
298 0 : rbh->hashes = deq_fd_block_block_hash_entry_t_join( (uchar*)rbh_global + rbh_global->hashes_offset );
299 0 : }
300 :
301 0 : if( rbh_global && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) {
302 0 : fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_tail_const( rbh->hashes );
303 0 : if( last ) {
304 0 : block_hash_queue = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0];
305 0 : fd_hash_t * last_hash = fd_block_hash_queue_last_hash_join( block_hash_queue );
306 0 : fd_memcpy( last_hash, &last->blockhash, sizeof(fd_hash_t) );
307 :
308 0 : fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
309 :
310 0 : fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature );
311 0 : }
312 0 : }
313 :
314 : /* Load instruction accounts */
315 :
316 0 : if( FD_UNLIKELY( test_ctx->instr_accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) {
317 0 : FD_LOG_NOTICE(( "too many instruction accounts" ));
318 0 : return 0;
319 0 : }
320 :
321 0 : uchar acc_idx_seen[ FD_INSTR_ACCT_MAX ] = {0};
322 0 : for( ulong j=0UL; j < test_ctx->instr_accounts_count; j++ ) {
323 0 : uint index = test_ctx->instr_accounts[j].index;
324 0 : if( index >= test_ctx->accounts_count ) {
325 0 : FD_LOG_NOTICE( ( "instruction account index out of range (%u > %u)", index, test_ctx->instr_accounts_count ) );
326 0 : return 0;
327 0 : }
328 :
329 0 : fd_txn_account_t * acc = &accts[ index ];
330 :
331 : /* Setup instruction accounts */
332 0 : fd_instr_info_setup_instr_account( info,
333 0 : acc_idx_seen,
334 0 : (ushort)index,
335 0 : (ushort)j,
336 0 : (ushort)j,
337 0 : test_ctx->instr_accounts[j].is_writable,
338 0 : test_ctx->instr_accounts[j].is_signer );
339 :
340 0 : if( test_ctx->instr_accounts[j].is_writable ) {
341 0 : acc->vt->set_mutable( acc );
342 0 : }
343 0 : }
344 0 : info->acct_cnt = (uchar)test_ctx->instr_accounts_count;
345 :
346 : /* The remaining checks enforce that the program is in the accounts list. */
347 0 : bool found_program_id = false;
348 0 : for( uint i = 0; i < test_ctx->accounts_count; i++ ) {
349 0 : if( 0 == memcmp( test_ctx->accounts[i].address, test_ctx->program_id, sizeof(fd_pubkey_t) ) ) {
350 0 : info->program_id = (uchar) i;
351 0 : found_program_id = true;
352 0 : break;
353 0 : }
354 0 : }
355 :
356 : /* Early returning only happens in instruction execution. */
357 0 : if( !is_syscall && !found_program_id ) {
358 0 : FD_LOG_NOTICE(( " Unable to find program_id in accounts" ));
359 0 : return 0;
360 0 : }
361 :
362 0 : ctx->instr = info;
363 :
364 : /* Refresh the setup from the updated slot and epoch ctx. */
365 0 : fd_exec_txn_ctx_from_exec_slot_ctx( slot_ctx,
366 0 : txn_ctx,
367 0 : funk_wksp,
368 0 : runtime_wksp,
369 0 : funk_txn_gaddr,
370 0 : funk_gaddr,
371 0 : NULL );
372 :
373 0 : fd_log_collector_init( &ctx->txn_ctx->log_collector, 1 );
374 0 : fd_base58_encode_32( txn_ctx->account_keys[ ctx->instr->program_id ].uc, NULL, ctx->program_id_base58 );
375 :
376 0 : return 1;
377 0 : }
378 :
379 :
380 :
381 : void
382 : fd_runtime_fuzz_instr_ctx_destroy( fd_runtime_fuzz_runner_t * runner,
383 0 : fd_exec_instr_ctx_t * ctx ) {
384 0 : if( !ctx ) return;
385 0 : fd_funk_txn_t * funk_txn = ctx->txn_ctx->funk_txn;
386 :
387 0 : fd_funk_txn_cancel( runner->funk, funk_txn, 1 );
388 0 : }
389 :
390 :
391 : ulong
392 : fd_runtime_fuzz_instr_run( fd_runtime_fuzz_runner_t * runner,
393 : void const * input_,
394 : void ** output_,
395 : void * output_buf,
396 0 : ulong output_bufsz ) {
397 0 : fd_exec_test_instr_context_t const * input = fd_type_pun_const( input_ );
398 0 : fd_exec_test_instr_effects_t ** output = fd_type_pun( output_ );
399 :
400 : /* Convert the Protobuf inputs to a fd_exec context */
401 0 : fd_exec_instr_ctx_t ctx[1];
402 0 : if( !fd_runtime_fuzz_instr_ctx_create( runner, ctx, input, false ) ) {
403 0 : fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
404 0 : return 0UL;
405 0 : }
406 :
407 0 : fd_instr_info_t * instr = (fd_instr_info_t *) ctx->instr;
408 :
409 : /* Execute the test */
410 0 : int exec_result = fd_execute_instr(ctx->txn_ctx, instr);
411 :
412 : /* Allocate space to capture outputs */
413 :
414 0 : ulong output_end = (ulong)output_buf + output_bufsz;
415 0 : FD_SCRATCH_ALLOC_INIT( l, output_buf );
416 :
417 0 : fd_exec_test_instr_effects_t * effects =
418 0 : FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_instr_effects_t),
419 0 : sizeof (fd_exec_test_instr_effects_t) );
420 0 : if( FD_UNLIKELY( _l > output_end ) ) {
421 0 : fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
422 0 : return 0UL;
423 0 : }
424 0 : fd_memset( effects, 0, sizeof(fd_exec_test_instr_effects_t) );
425 :
426 : /* Capture error code */
427 :
428 0 : effects->result = -exec_result;
429 0 : effects->cu_avail = ctx->txn_ctx->compute_meter;
430 :
431 0 : if( exec_result == FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR ) {
432 0 : effects->custom_err = ctx->txn_ctx->custom_err;
433 0 : }
434 :
435 : /* Allocate space for captured accounts */
436 0 : ulong modified_acct_cnt = ctx->txn_ctx->accounts_cnt;
437 :
438 0 : fd_exec_test_acct_state_t * modified_accts =
439 0 : FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_acct_state_t),
440 0 : sizeof (fd_exec_test_acct_state_t) * modified_acct_cnt );
441 0 : if( FD_UNLIKELY( _l > output_end ) ) {
442 0 : fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
443 0 : return 0;
444 0 : }
445 0 : effects->modified_accounts = modified_accts;
446 0 : effects->modified_accounts_count = 0UL;
447 :
448 : /* Capture borrowed accounts */
449 :
450 0 : for( ulong j=0UL; j < ctx->txn_ctx->accounts_cnt; j++ ) {
451 0 : fd_txn_account_t * acc = &ctx->txn_ctx->accounts[j];
452 0 : if( !acc->vt->get_meta( acc ) ) {
453 0 : continue;
454 0 : }
455 :
456 0 : ulong modified_idx = effects->modified_accounts_count;
457 0 : assert( modified_idx < modified_acct_cnt );
458 :
459 0 : fd_exec_test_acct_state_t * out_acct = &effects->modified_accounts[ modified_idx ];
460 0 : memset( out_acct, 0, sizeof(fd_exec_test_acct_state_t) );
461 : /* Copy over account content */
462 :
463 0 : memcpy( out_acct->address, acc->pubkey, sizeof(fd_pubkey_t) );
464 0 : out_acct->lamports = acc->vt->get_lamports( acc );
465 0 : if( acc->vt->get_data_len( acc )>0UL ) {
466 0 : out_acct->data =
467 0 : FD_SCRATCH_ALLOC_APPEND( l, alignof(pb_bytes_array_t),
468 0 : PB_BYTES_ARRAY_T_ALLOCSIZE( acc->vt->get_data_len( acc ) ) );
469 0 : if( FD_UNLIKELY( _l > output_end ) ) {
470 0 : fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
471 0 : return 0UL;
472 0 : }
473 0 : out_acct->data->size = (pb_size_t)acc->vt->get_data_len( acc );
474 0 : fd_memcpy( out_acct->data->bytes, acc->vt->get_data( acc ), acc->vt->get_data_len( acc ) );
475 0 : }
476 :
477 0 : out_acct->executable = acc->vt->is_executable( acc );
478 0 : out_acct->rent_epoch = acc->vt->get_rent_epoch( acc );
479 0 : memcpy( out_acct->owner, acc->vt->get_owner( acc ), sizeof(fd_pubkey_t) );
480 :
481 0 : effects->modified_accounts_count++;
482 0 : }
483 :
484 : /* Capture return data */
485 0 : fd_txn_return_data_t * return_data = &ctx->txn_ctx->return_data;
486 0 : if( return_data->len>0UL ) {
487 0 : effects->return_data = FD_SCRATCH_ALLOC_APPEND(l, alignof(pb_bytes_array_t),
488 0 : PB_BYTES_ARRAY_T_ALLOCSIZE( return_data->len ) );
489 0 : if( FD_UNLIKELY( _l > output_end ) ) {
490 0 : fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
491 0 : return 0UL;
492 0 : }
493 0 : effects->return_data->size = (pb_size_t)return_data->len;
494 0 : fd_memcpy( effects->return_data->bytes, return_data->data, return_data->len );
495 0 : }
496 :
497 0 : ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
498 0 : fd_runtime_fuzz_instr_ctx_destroy( runner, ctx );
499 :
500 0 : *output = effects;
501 0 : return actual_end - (ulong)output_buf;
502 :
503 0 : }
|