Line data Source code
1 : #undef FD_SPAD_USE_HANDHOLDING
2 : #define FD_SPAD_USE_HANDHOLDING 1
3 :
4 : #include "fd_solfuzz_private.h"
5 : #include "fd_instr_harness.h"
6 : #include "../fd_executor.h"
7 : #include "../fd_runtime.h"
8 : #include "../program/fd_bpf_loader_program.h"
9 : #include "../program/fd_loader_v4_program.h"
10 : #include "../fd_system_ids.h"
11 : #include "../../log_collector/fd_log_collector.h"
12 : #include <assert.h>
13 :
14 : int
15 : fd_solfuzz_pb_instr_ctx_create( fd_solfuzz_runner_t * runner,
16 : fd_exec_instr_ctx_t * ctx,
17 : fd_exec_test_instr_context_t const * test_ctx,
18 0 : bool is_syscall ) {
19 :
20 0 : memset( ctx, 0, sizeof(fd_exec_instr_ctx_t) );
21 :
22 : /* Generate unique ID for funk txn */
23 :
24 0 : fd_funk_txn_xid_t xid[1] = {{ .ul={ LONG_MAX, LONG_MAX } }};
25 :
26 : /* Create temporary funk transaction and txn / slot / epoch contexts */
27 :
28 0 : fd_funk_txn_xid_t parent_xid; fd_funk_txn_xid_set_root( &parent_xid );
29 0 : fd_accdb_attach_child ( runner->accdb_admin, &parent_xid, xid );
30 0 : fd_progcache_txn_attach_child( runner->progcache_admin, &parent_xid, xid );
31 :
32 0 : fd_txn_in_t * txn_in = fd_spad_alloc( runner->spad, alignof(fd_txn_in_t), sizeof(fd_txn_in_t) );
33 0 : fd_txn_out_t * txn_out = fd_spad_alloc( runner->spad, alignof(fd_txn_out_t), sizeof(fd_txn_out_t) );
34 :
35 0 : fd_log_collector_t * log = fd_spad_alloc( runner->spad, alignof(fd_log_collector_t), sizeof(fd_log_collector_t) );
36 :
37 0 : fd_runtime_t * runtime = runner->runtime;
38 :
39 0 : runtime->log.log_collector = log;
40 :
41 0 : ctx->txn_out = txn_out;
42 0 : ctx->txn_in = txn_in;
43 :
44 0 : memset( txn_out->accounts.account, 0, sizeof(fd_accdb_rw_t) * MAX_TX_ACCOUNT_LOCKS );
45 :
46 0 : memset( txn_out->accounts.account, 0, sizeof(fd_accdb_rw_t) * MAX_TX_ACCOUNT_LOCKS );
47 :
48 : /* Bank manager */
49 0 : fd_banks_clear_bank( runner->banks, runner->bank, 4UL );
50 :
51 0 : fd_features_t * features = fd_bank_features_modify( runner->bank );
52 0 : fd_exec_test_feature_set_t const * feature_set = &test_ctx->epoch_context.features;
53 0 : if( !fd_solfuzz_pb_restore_features( features, feature_set ) ) {
54 0 : return 0;
55 0 : }
56 :
57 : /* Blockhash queue init */
58 :
59 0 : ulong blockhash_seed; FD_TEST( fd_rng_secure( &blockhash_seed, sizeof(ulong) ) );
60 0 : fd_blockhashes_t * blockhashes = fd_blockhashes_init( fd_bank_block_hash_queue_modify( runner->bank ), blockhash_seed );
61 0 : fd_memset( fd_blockhash_deq_push_tail_nocopy( blockhashes->d.deque ), 0, sizeof(fd_hash_t) );
62 :
63 : /* Set up mock txn descriptor and payload
64 : FIXME: More fields may need to be initialized. This seems to be
65 : the minimal set of fields needed to retain full context for
66 : precompile execution. */
67 0 : fd_txn_p_t * txn = fd_spad_alloc_check( runner->spad, alignof(fd_txn_p_t), sizeof(fd_txn_p_t) );
68 0 : fd_txn_t * txn_descriptor = TXN( txn );
69 0 : if( test_ctx->data ) {
70 0 : memcpy( txn->payload, test_ctx->data->bytes, test_ctx->data->size );
71 0 : txn->payload_sz = test_ctx->data->size;
72 0 : } else {
73 0 : txn->payload_sz = 0;
74 0 : }
75 0 : txn_descriptor->transaction_version = FD_TXN_VLEGACY;
76 0 : txn_descriptor->acct_addr_cnt = (ushort)test_ctx->accounts_count;
77 0 : txn_descriptor->instr_cnt = 1;
78 0 : txn_descriptor->instr[0] = (fd_txn_instr_t) {
79 0 : .acct_cnt = (ushort)test_ctx->accounts_count,
80 0 : .data_off = 0,
81 0 : .data_sz = (ushort)txn->payload_sz,
82 0 : };
83 :
84 0 : runtime->log.enable_log_collector = 0;
85 :
86 0 : fd_compute_budget_details_new( &txn_out->details.compute_budget );
87 0 : runtime->instr.stack_sz = 0;
88 0 : txn_out->accounts.cnt = 0UL;
89 0 : runtime->accounts.executable_cnt = 0UL;
90 :
91 0 : txn_out->details.programs_to_reverify_cnt = 0UL;
92 0 : txn_out->details.loaded_accounts_data_size = 0UL;
93 0 : txn_out->details.accounts_resize_delta = 0UL;
94 :
95 0 : memset( txn_out->details.return_data.program_id.key, 0, sizeof(fd_pubkey_t) );
96 0 : txn_out->details.return_data.len = 0;
97 :
98 0 : runtime->log.capture_ctx = NULL;
99 :
100 0 : runtime->instr.trace_length = 1UL;
101 :
102 0 : txn_out->err.exec_err = 0;
103 0 : txn_out->err.exec_err_kind = FD_EXECUTOR_ERR_KIND_NONE;
104 0 : runtime->instr.current_idx = 0;
105 :
106 0 : txn_in->txn = txn;
107 0 : txn_out->details.compute_budget.compute_unit_limit = test_ctx->cu_avail;
108 0 : txn_out->details.compute_budget.compute_meter = test_ctx->cu_avail;
109 0 : runtime->log.enable_vm_tracing = runner->enable_vm_tracing;
110 0 : runtime->log.tracing_mem = runner->enable_vm_tracing ?
111 0 : fd_spad_alloc_check( runner->spad, FD_RUNTIME_VM_TRACE_STATIC_ALIGN, FD_RUNTIME_VM_TRACE_STATIC_FOOTPRINT * FD_MAX_INSTRUCTION_STACK_DEPTH ) :
112 0 : NULL;
113 :
114 : /* Set up instruction context */
115 0 : fd_instr_info_t * info = &runtime->instr.trace[ 0UL ];
116 0 : memset( info, 0, sizeof(fd_instr_info_t) );
117 0 : info->stack_height = 1;
118 :
119 0 : if( test_ctx->data ) {
120 0 : if( FD_UNLIKELY( test_ctx->data->size>FD_INSTR_DATA_MAX ) ) {
121 0 : FD_LOG_ERR(( "invariant violation: instr data sz is too large %u > %lu", test_ctx->data->size, FD_INSTR_DATA_MAX ));
122 0 : }
123 0 : info->data_sz = (ushort)test_ctx->data->size;
124 0 : memcpy( info->data, test_ctx->data->bytes, info->data_sz );
125 0 : }
126 :
127 : /* Prepare borrowed account table (correctly handles aliasing) */
128 :
129 0 : if( FD_UNLIKELY( test_ctx->accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) {
130 0 : FD_LOG_NOTICE(( "too many accounts" ));
131 0 : return 0;
132 0 : }
133 :
134 : /* Load accounts into database */
135 :
136 0 : fd_account_meta_t * metas[MAX_TX_ACCOUNT_LOCKS] = {0};
137 0 : txn_out->accounts.cnt = test_ctx->accounts_count;
138 :
139 0 : int has_program_id = 0;
140 :
141 0 : for( ulong j=0UL; j < test_ctx->accounts_count; j++ ) {
142 0 : fd_pubkey_t * acc_key = (fd_pubkey_t *)test_ctx->accounts[j].address;
143 :
144 0 : memcpy( &(txn_out->accounts.keys[j]), test_ctx->accounts[j].address, sizeof(fd_pubkey_t) );
145 0 : runtime->accounts.refcnt[j] = 0UL;
146 :
147 0 : uchar * data = fd_spad_alloc( runner->spad, FD_ACCOUNT_REC_ALIGN, FD_ACC_TOT_SZ_MAX );
148 0 : fd_account_meta_t * meta = (fd_account_meta_t *)data;
149 0 : uint dlen = test_ctx->accounts[j].data ? test_ctx->accounts[j].data->size : 0U;
150 0 : if( test_ctx->accounts[j].data ) {
151 0 : fd_memcpy( meta+1, test_ctx->accounts[j].data->bytes, dlen );
152 0 : }
153 0 : meta->dlen = dlen;
154 0 : meta->lamports = test_ctx->accounts[j].lamports;
155 0 : meta->executable = test_ctx->accounts[j].executable;
156 0 : fd_memcpy( meta->owner, test_ctx->accounts[j].owner, sizeof(fd_pubkey_t) );
157 0 : metas[j] = meta;
158 0 : fd_accdb_rw_init_nodb( &txn_out->accounts.account[j], acc_key, metas[j], FD_RUNTIME_ACC_SZ_MAX );
159 0 : txn_out->accounts.keys[j] = *acc_key;
160 :
161 0 : if( !memcmp( acc_key, test_ctx->program_id, sizeof(fd_pubkey_t) ) ) {
162 0 : has_program_id = 1;
163 0 : info->program_id = (uchar)txn_out->accounts.cnt;
164 0 : }
165 0 : }
166 :
167 : /* If the program id is not in the set of accounts it must be added to the set of accounts. */
168 0 : if( FD_UNLIKELY( !has_program_id ) ) {
169 0 : fd_pubkey_t * program_key = &txn_out->accounts.keys[ txn_out->accounts.cnt ];
170 0 : memcpy( program_key, test_ctx->program_id, sizeof(fd_pubkey_t) );
171 :
172 0 : fd_account_meta_t * meta = fd_spad_alloc( runner->spad, alignof(fd_account_meta_t), sizeof(fd_account_meta_t) );
173 0 : fd_account_meta_init( meta );
174 :
175 0 : txn_out->accounts.account[test_ctx->accounts_count].meta = meta;
176 :
177 0 : info->program_id = (uchar)txn_out->accounts.cnt;
178 0 : txn_out->accounts.cnt++;
179 0 : }
180 :
181 : /* Load in executable accounts */
182 0 : for( ulong i = 0; i < txn_out->accounts.cnt; i++ ) {
183 :
184 0 : fd_account_meta_t * meta = txn_out->accounts.account[i].meta;
185 0 : if( !fd_executor_pubkey_is_bpf_loader( fd_type_pun( meta->owner ) ) ) {
186 0 : continue;
187 0 : }
188 :
189 0 : if( FD_UNLIKELY( !memcmp( meta->owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
190 0 : fd_bpf_upgradeable_loader_state_t program_loader_state[1];
191 0 : int err = fd_bpf_loader_program_get_state( meta, program_loader_state );
192 0 : if( FD_UNLIKELY( err!=FD_EXECUTOR_INSTR_SUCCESS ) ) {
193 0 : continue;
194 0 : }
195 :
196 0 : if( !fd_bpf_upgradeable_loader_state_is_program( program_loader_state ) ) {
197 0 : continue;
198 0 : }
199 :
200 0 : fd_pubkey_t * programdata_acc = &program_loader_state->inner.program.programdata_address;
201 :
202 0 : meta = NULL;
203 0 : for( ulong j=0UL; j<test_ctx->accounts_count; j++ ) {
204 0 : if( !memcmp( test_ctx->accounts[j].address, programdata_acc, sizeof(fd_pubkey_t) ) ) {
205 0 : meta = txn_out->accounts.account[j].meta;
206 0 : break;
207 0 : }
208 0 : }
209 0 : if( FD_UNLIKELY( meta==NULL ) ) {
210 0 : continue;
211 0 : }
212 :
213 0 : FD_TEST( runtime->accounts.executable_cnt < MAX_TX_ACCOUNT_LOCKS );
214 0 : fd_accdb_ro_t * ro = &runtime->accounts.executable[ runtime->accounts.executable_cnt ];
215 0 : fd_accdb_ro_init_nodb( ro, programdata_acc, meta );
216 0 : runtime->accounts.executable_cnt++;
217 0 : } else if( FD_UNLIKELY( !memcmp( meta->owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ||
218 0 : !memcmp( meta->owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) ) ) {
219 0 : meta = txn_out->accounts.account[i].meta;
220 0 : } else if( !memcmp( meta->owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
221 0 : int err;
222 0 : fd_loader_v4_state_t const * state = fd_loader_v4_get_state( fd_account_data( meta ), meta->dlen, &err );
223 0 : if( FD_UNLIKELY( err ) ) {
224 0 : continue;
225 0 : }
226 :
227 : /* The program must be deployed or finalized. */
228 0 : if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( state ) ) ) {
229 0 : continue;
230 0 : }
231 0 : meta = txn_out->accounts.account[i].meta;
232 0 : }
233 :
234 0 : FD_SPAD_FRAME_BEGIN( runner->spad ) {
235 0 : uchar * scratch = fd_spad_alloc( runner->spad, FD_FUNK_REC_ALIGN, meta->dlen );
236 0 : fd_progcache_inject_rec( runner->progcache_admin,
237 0 : &txn_out->accounts.keys[i],
238 0 : meta,
239 0 : features,
240 0 : fd_bank_slot_get( runner->bank ),
241 0 : scratch,
242 0 : meta->dlen );
243 0 : } FD_SPAD_FRAME_END;
244 0 : }
245 :
246 0 : fd_funk_txn_xid_t exec_xid[1] = {{ .ul={ fd_bank_slot_get( runner->bank ), runner->bank->data->idx } }};
247 0 : fd_accdb_attach_child ( runner->accdb_admin, xid, exec_xid );
248 0 : fd_progcache_txn_attach_child( runner->progcache_admin, xid, exec_xid );
249 :
250 : /* Load instruction accounts */
251 :
252 0 : if( FD_UNLIKELY( test_ctx->instr_accounts_count > MAX_TX_ACCOUNT_LOCKS ) ) {
253 0 : FD_LOG_NOTICE(( "too many instruction accounts" ));
254 0 : return 0;
255 0 : }
256 :
257 : /* Restore sysvar cache */
258 0 : fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( runner->bank );
259 0 : ctx->sysvar_cache = sysvar_cache;
260 0 : for( ulong i=0UL; i<txn_out->accounts.cnt; i++ ) {
261 0 : fd_sysvar_cache_restore_from_ref( sysvar_cache, txn_out->accounts.account[i].ro );
262 0 : }
263 :
264 0 : ctx->runtime = runtime;
265 :
266 0 : fd_sol_sysvar_clock_t clock_[1];
267 0 : fd_sol_sysvar_clock_t * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, clock_ );
268 0 : FD_TEST( clock );
269 0 : fd_bank_slot_set( runner->bank, clock->slot );
270 :
271 0 : fd_epoch_schedule_t epoch_schedule_[1];
272 0 : fd_epoch_schedule_t * epoch_schedule = fd_sysvar_cache_epoch_schedule_read( ctx->sysvar_cache, epoch_schedule_ );
273 0 : if( FD_UNLIKELY( !epoch_schedule ) ) { return 0; }
274 0 : fd_bank_epoch_schedule_set( runner->bank, *epoch_schedule );
275 :
276 0 : fd_rent_t rent_[1];
277 0 : fd_rent_t * rent = fd_sysvar_cache_rent_read( ctx->sysvar_cache, rent_ );
278 0 : FD_TEST( rent );
279 0 : fd_bank_rent_set( runner->bank, *rent );
280 :
281 0 : fd_block_block_hash_entry_t const * deq = fd_sysvar_cache_recent_hashes_join_const( ctx->sysvar_cache );
282 0 : FD_TEST( deq );
283 0 : if( !deq_fd_block_block_hash_entry_t_empty( deq ) ) {
284 0 : fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_tail_const( deq );
285 0 : if( last ) {
286 0 : fd_blockhashes_t * blockhashes = fd_bank_block_hash_queue_modify( runner->bank );
287 0 : fd_blockhashes_pop_new( blockhashes );
288 0 : fd_blockhash_info_t * info = fd_blockhashes_push_new( blockhashes, &last->blockhash );
289 0 : info->fee_calculator = last->fee_calculator;
290 :
291 0 : fd_bank_rbh_lamports_per_sig_set( runner->bank, last->fee_calculator.lamports_per_signature );
292 0 : }
293 0 : }
294 0 : fd_sysvar_cache_recent_hashes_leave_const( ctx->sysvar_cache, deq );
295 :
296 0 : uchar acc_idx_seen[ FD_TXN_ACCT_ADDR_MAX ] = {0};
297 0 : for( ulong j=0UL; j < test_ctx->instr_accounts_count; j++ ) {
298 0 : uint index = test_ctx->instr_accounts[j].index;
299 0 : if( index >= test_ctx->accounts_count ) {
300 0 : FD_LOG_NOTICE( ( "instruction account index out of range (%u > %u)", index, test_ctx->instr_accounts_count ) );
301 0 : return 0;
302 0 : }
303 :
304 : /* Setup instruction accounts */
305 0 : fd_instr_info_setup_instr_account( info,
306 0 : acc_idx_seen,
307 0 : (ushort)index,
308 0 : (ushort)j,
309 0 : (ushort)j,
310 0 : test_ctx->instr_accounts[j].is_writable,
311 0 : test_ctx->instr_accounts[j].is_signer );
312 0 : }
313 0 : info->acct_cnt = (uchar)test_ctx->instr_accounts_count;
314 :
315 : /* The remaining checks enforce that the program is in the accounts list. */
316 0 : bool found_program_id = false;
317 0 : for( uint i = 0; i < test_ctx->accounts_count; i++ ) {
318 0 : if( 0 == memcmp( test_ctx->accounts[i].address, test_ctx->program_id, sizeof(fd_pubkey_t) ) ) {
319 0 : info->program_id = (uchar) i;
320 0 : found_program_id = true;
321 0 : break;
322 0 : }
323 0 : }
324 :
325 : /* Early returning only happens in instruction execution. */
326 0 : if( !is_syscall && !found_program_id ) {
327 0 : FD_LOG_NOTICE(( " Unable to find program_id in accounts" ));
328 0 : return 0;
329 0 : }
330 :
331 0 : ctx->instr = info;
332 0 : ctx->runtime->progcache = runner->progcache;
333 0 : ctx->runtime->accdb = runner->accdb;
334 :
335 0 : runtime->log.enable_log_collector = 0;
336 :
337 0 : fd_log_collector_init( ctx->runtime->log.log_collector, 1 );
338 0 : fd_base58_encode_32( txn_out->accounts.keys[ ctx->instr->program_id ].uc, NULL, ctx->program_id_base58 );
339 :
340 0 : return 1;
341 0 : }
342 :
343 : void
344 : fd_solfuzz_pb_instr_ctx_destroy( fd_solfuzz_runner_t * runner,
345 0 : fd_exec_instr_ctx_t * ctx ) {
346 0 : if( !ctx ) return;
347 0 : fd_accdb_clear( runner->accdb_admin );
348 0 : fd_progcache_clear( runner->progcache_admin );
349 :
350 : /* In order to check for leaks in the workspace, we need to compact the
351 : allocators. Without doing this, empty superblocks may be retained
352 : by the fd_alloc instance, which mean we cannot check for leaks. */
353 0 : fd_alloc_compact( runner->accdb_admin->funk->alloc );
354 0 : fd_alloc_compact( runner->progcache_admin->funk->alloc );
355 0 : }
356 :
357 : ulong
358 : fd_solfuzz_pb_instr_run( fd_solfuzz_runner_t * runner,
359 : void const * input_,
360 : void ** output_,
361 : void * output_buf,
362 0 : ulong output_bufsz ) {
363 0 : fd_exec_test_instr_context_t const * input = fd_type_pun_const( input_ );
364 0 : fd_exec_test_instr_effects_t ** output = fd_type_pun( output_ );
365 :
366 : /* Convert the Protobuf inputs to a fd_exec context */
367 0 : fd_exec_instr_ctx_t ctx[1];
368 0 : if( !fd_solfuzz_pb_instr_ctx_create( runner, ctx, input, false ) ) {
369 0 : fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
370 0 : return 0UL;
371 0 : }
372 :
373 0 : fd_instr_info_t * instr = (fd_instr_info_t *) ctx->instr;
374 :
375 : /* Execute the test */
376 0 : int exec_result = fd_execute_instr( ctx->runtime, runner->bank, ctx->txn_in, ctx->txn_out, instr );
377 :
378 : /* Allocate space to capture outputs */
379 :
380 0 : ulong output_end = (ulong)output_buf + output_bufsz;
381 0 : FD_SCRATCH_ALLOC_INIT( l, output_buf );
382 :
383 0 : fd_exec_test_instr_effects_t * effects =
384 0 : FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_instr_effects_t),
385 0 : sizeof (fd_exec_test_instr_effects_t) );
386 0 : if( FD_UNLIKELY( _l > output_end ) ) {
387 0 : fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
388 0 : return 0UL;
389 0 : }
390 0 : fd_memset( effects, 0, sizeof(fd_exec_test_instr_effects_t) );
391 :
392 : /* Capture error code */
393 :
394 0 : effects->result = -exec_result;
395 0 : effects->cu_avail = ctx->txn_out->details.compute_budget.compute_meter;
396 :
397 : /* Don't capture custom error codes if the program is a precompile */
398 0 : if( FD_LIKELY( effects->result ) ) {
399 0 : int program_id_idx = ctx->instr[ 0UL ].program_id;
400 0 : if( exec_result==FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR &&
401 0 : fd_executor_lookup_native_precompile_program( &ctx->txn_out->accounts.keys[ program_id_idx ] )==NULL ) {
402 0 : effects->custom_err = ctx->txn_out->err.custom_err;
403 0 : }
404 0 : }
405 :
406 : /* Allocate space for captured accounts */
407 0 : ulong modified_acct_cnt = ctx->txn_out->accounts.cnt;
408 :
409 0 : fd_exec_test_acct_state_t * modified_accts =
410 0 : FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_acct_state_t),
411 0 : sizeof (fd_exec_test_acct_state_t) * modified_acct_cnt );
412 0 : if( FD_UNLIKELY( _l > output_end ) ) {
413 0 : fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
414 0 : return 0;
415 0 : }
416 0 : effects->modified_accounts = modified_accts;
417 0 : effects->modified_accounts_count = 0UL;
418 :
419 : /* Capture borrowed accounts */
420 :
421 0 : for( ulong j=0UL; j < ctx->txn_out->accounts.cnt; j++ ) {
422 0 : fd_pubkey_t * acc_key = &ctx->txn_out->accounts.keys[j];
423 0 : fd_account_meta_t * acc = ctx->txn_out->accounts.account[j].meta;
424 0 : if( !acc ) {
425 0 : continue;
426 0 : }
427 :
428 0 : ulong modified_idx = effects->modified_accounts_count;
429 0 : assert( modified_idx < modified_acct_cnt );
430 :
431 0 : fd_exec_test_acct_state_t * out_acct = &effects->modified_accounts[ modified_idx ];
432 0 : memset( out_acct, 0, sizeof(fd_exec_test_acct_state_t) );
433 : /* Copy over account content */
434 :
435 0 : memcpy( out_acct->address, acc_key, sizeof(fd_pubkey_t) );
436 0 : out_acct->lamports = acc->lamports;
437 0 : if( acc->dlen>0UL ) {
438 0 : out_acct->data =
439 0 : FD_SCRATCH_ALLOC_APPEND( l, alignof(pb_bytes_array_t),
440 0 : PB_BYTES_ARRAY_T_ALLOCSIZE( acc->dlen ) );
441 0 : if( FD_UNLIKELY( _l > output_end ) ) {
442 0 : fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
443 0 : return 0UL;
444 0 : }
445 0 : out_acct->data->size = (pb_size_t)acc->dlen;
446 0 : fd_memcpy( out_acct->data->bytes, fd_account_data( acc ), acc->dlen );
447 0 : }
448 :
449 0 : out_acct->executable = acc->executable;
450 0 : memcpy( out_acct->owner, acc->owner, sizeof(fd_pubkey_t) );
451 :
452 0 : effects->modified_accounts_count++;
453 0 : }
454 :
455 : /* Capture return data */
456 0 : fd_txn_return_data_t * return_data = &ctx->txn_out->details.return_data;
457 0 : if( return_data->len>0UL ) {
458 0 : effects->return_data = FD_SCRATCH_ALLOC_APPEND(l, alignof(pb_bytes_array_t),
459 0 : PB_BYTES_ARRAY_T_ALLOCSIZE( return_data->len ) );
460 0 : if( FD_UNLIKELY( _l > output_end ) ) {
461 0 : fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
462 0 : return 0UL;
463 0 : }
464 0 : effects->return_data->size = (pb_size_t)return_data->len;
465 0 : fd_memcpy( effects->return_data->bytes, return_data->data, return_data->len );
466 0 : }
467 :
468 0 : ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL );
469 0 : fd_solfuzz_pb_instr_ctx_destroy( runner, ctx );
470 :
471 0 : *output = effects;
472 0 : return actual_end - (ulong)output_buf;
473 0 : }
|