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