Line data Source code
1 : #include "fd_vm_syscall.h"
2 : #include "../../runtime/sysvar/fd_sysvar.h"
3 : #include "../../runtime/sysvar/fd_sysvar_clock.h"
4 : #include "../../runtime/sysvar/fd_sysvar_epoch_schedule.h"
5 : #include "../../runtime/sysvar/fd_sysvar_fees.h"
6 : #include "../../runtime/sysvar/fd_sysvar_rent.h"
7 : #include "../../runtime/sysvar/fd_sysvar_last_restart_slot.h"
8 : #include "../../runtime/context/fd_exec_txn_ctx.h"
9 : #include "../../runtime/context/fd_exec_instr_ctx.h"
10 :
11 : int
12 : fd_vm_syscall_sol_get_clock_sysvar( /**/ void * _vm,
13 : /**/ ulong out_vaddr,
14 : FD_PARAM_UNUSED ulong r2,
15 : FD_PARAM_UNUSED ulong r3,
16 : FD_PARAM_UNUSED ulong r4,
17 : FD_PARAM_UNUSED ulong r5,
18 90 : /**/ ulong * _ret ) {
19 90 : fd_vm_t * vm = (fd_vm_t *)_vm;
20 :
21 : /* FIXME: In the original version of this code, there was an FD_TEST
22 : to check if the VM was attached to an instruction context (that
23 : would have crashed anyway because of pointer chasing). If the VM
24 : is being run outside the Solana runtime, it should never invoke
25 : this syscall in the first place. So we treat this as a SIGCALL in
26 : a non-crashing way. */
27 :
28 90 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
29 90 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
30 :
31 180 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SOL_SYSVAR_CLOCK_FOOTPRINT ) );
32 :
33 90 : void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_CLOCK, FD_SOL_SYSVAR_CLOCK_FOOTPRINT );
34 :
35 : /* FIXME: is it possible to do the read in-place? */
36 0 : fd_sol_sysvar_clock_t clock[1];
37 90 : fd_sol_sysvar_clock_new( clock ); /* FIXME: probably should be init as not a distributed persistent object */
38 90 : fd_sysvar_clock_read( clock, instr_ctx->slot_ctx );
39 : /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
40 :
41 90 : memcpy( out, clock, FD_SOL_SYSVAR_CLOCK_FOOTPRINT );
42 :
43 90 : *_ret = 0UL;
44 90 : return FD_VM_SUCCESS;
45 180 : }
46 :
47 : int
48 : fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/ void * _vm,
49 : /**/ ulong out_vaddr,
50 : FD_PARAM_UNUSED ulong r2,
51 : FD_PARAM_UNUSED ulong r3,
52 : FD_PARAM_UNUSED ulong r4,
53 : FD_PARAM_UNUSED ulong r5,
54 6 : /**/ ulong * _ret ) {
55 6 : fd_vm_t * vm = (fd_vm_t *)_vm;
56 :
57 : /* FIXME: In the original version of this code, there was an FD_TEST
58 : to check if the VM was attached to an instruction context (that
59 : would have crashed anyway because of pointer chasing). If the VM
60 : is being run outside the Solana runtime, it should never invoke
61 : this syscall in the first place. So we treat this as a SIGCALL in
62 : a non-crashing way for the time being. */
63 :
64 6 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
65 6 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
66 :
67 12 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_EPOCH_SCHEDULE_FOOTPRINT ) );
68 :
69 6 : void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_SCHEDULE, FD_EPOCH_SCHEDULE_FOOTPRINT );
70 :
71 : /* FIXME: is it possible to do the read in-place? */
72 0 : fd_epoch_schedule_t schedule[1];
73 6 : fd_epoch_schedule_new( schedule ); /* FIXME: probably should be init as not a distributed persistent object */
74 6 : fd_sysvar_epoch_schedule_read( schedule, instr_ctx->slot_ctx );
75 : /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
76 :
77 6 : memcpy( out, schedule, FD_EPOCH_SCHEDULE_FOOTPRINT );
78 :
79 6 : *_ret = 0UL;
80 6 : return FD_VM_SUCCESS;
81 12 : }
82 :
83 : int
84 : fd_vm_syscall_sol_get_fees_sysvar( /**/ void * _vm,
85 : /**/ ulong out_vaddr,
86 : FD_PARAM_UNUSED ulong r2,
87 : FD_PARAM_UNUSED ulong r3,
88 : FD_PARAM_UNUSED ulong r4,
89 : FD_PARAM_UNUSED ulong r5,
90 0 : /**/ ulong * _ret ) {
91 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
92 :
93 : /* FIXME: In the original version of this code, there was an FD_TEST
94 : to check if the VM was attached to an instruction context (that
95 : would have crashed anyway because of pointer chasing). If the VM
96 : is being run outside the Solana runtime, it should never invoke
97 : this syscall in the first place. So we treat this as a SIGCALL in
98 : a non-crashing way for the time being. */
99 :
100 0 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
101 0 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
102 :
103 0 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SYSVAR_FEES_FOOTPRINT ) );
104 :
105 0 : void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_FEES, FD_SYSVAR_FEES_FOOTPRINT );
106 :
107 : /* FIXME: is it possible to do the read in-place? */
108 0 : fd_sysvar_fees_t fees[1];
109 0 : fd_sysvar_fees_new( fees ); /* FIXME: probably should be init as not a distributed persistent object */
110 0 : fd_sysvar_fees_read( fees, instr_ctx->slot_ctx );
111 : /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
112 :
113 0 : memcpy( out, fees, FD_SYSVAR_FEES_FOOTPRINT );
114 :
115 0 : *_ret = 0UL;
116 0 : return FD_VM_SUCCESS;
117 0 : }
118 :
119 : int
120 : fd_vm_syscall_sol_get_rent_sysvar( /**/ void * _vm,
121 : /**/ ulong out_vaddr,
122 : FD_PARAM_UNUSED ulong r2,
123 : FD_PARAM_UNUSED ulong r3,
124 : FD_PARAM_UNUSED ulong r4,
125 : FD_PARAM_UNUSED ulong r5,
126 0 : /**/ ulong * _ret ) {
127 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
128 :
129 : /* FIXME: In the original version of this code, there was an FD_TEST
130 : to check if the VM was attached to an instruction context (that
131 : would have crashed anyway because of pointer chasing). If the VM
132 : is being run outside the Solana runtime, it should never invoke
133 : this syscall in the first place. So we treat this as a SIGCALL in
134 : a non-crashing way for the time being. */
135 :
136 0 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
137 0 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
138 :
139 0 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_RENT_FOOTPRINT ) );
140 :
141 0 : void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_RENT, FD_RENT_FOOTPRINT );
142 :
143 : /* FIXME: is it possible to do the read in-place? */
144 0 : fd_rent_t rent[1];
145 0 : fd_rent_new( rent ); /* FIXME: probably should be init as not a distributed persistent object */
146 0 : fd_sysvar_rent_read( rent, instr_ctx->slot_ctx );
147 : /* FIXME: no delete function to match new (probably should be fini for the same reason anyway) */
148 :
149 0 : memcpy( out, rent, FD_RENT_FOOTPRINT );
150 :
151 0 : *_ret = 0UL;
152 0 : return FD_VM_SUCCESS;
153 0 : }
154 :
155 : /* https://github.com/anza-xyz/agave/blob/36323b6dcd3e29e4d6fe6d73d716a3f33927148b/programs/bpf_loader/src/syscalls/sysvar.rs#L144 */
156 : int
157 : fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/ void * _vm,
158 : /**/ ulong out_vaddr,
159 : FD_PARAM_UNUSED ulong r2,
160 : FD_PARAM_UNUSED ulong r3,
161 : FD_PARAM_UNUSED ulong r4,
162 : FD_PARAM_UNUSED ulong r5,
163 3 : /**/ ulong * _ret ) {
164 3 : fd_vm_t * vm = (fd_vm_t *)_vm;
165 :
166 3 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, FD_SOL_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT ) );
167 :
168 0 : fd_sol_sysvar_last_restart_slot_t * out =
169 9 : FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_LAST_RESTART_SLOT, FD_SOL_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT );
170 3 : if( FD_UNLIKELY( fd_sysvar_last_restart_slot_read( out, vm->instr_ctx->slot_ctx ) == NULL ) ) {
171 0 : return FD_VM_ERR_ABORT;
172 0 : }
173 :
174 3 : *_ret = 0UL;
175 3 : return FD_VM_SUCCESS;
176 9 : }
177 :
178 : int
179 : fd_vm_syscall_sol_get_stack_height( /**/ void * _vm,
180 : FD_PARAM_UNUSED ulong r1,
181 : FD_PARAM_UNUSED ulong r2,
182 : FD_PARAM_UNUSED ulong r3,
183 : FD_PARAM_UNUSED ulong r4,
184 : FD_PARAM_UNUSED ulong r5,
185 3 : /**/ ulong * _ret ) {
186 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1547 */
187 3 : fd_vm_t * vm = (fd_vm_t *)_vm;
188 :
189 3 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
190 :
191 0 : *_ret = vm->instr_ctx->txn_ctx->instr_stack_sz;
192 3 : return FD_VM_SUCCESS;
193 3 : }
194 :
195 : int
196 : fd_vm_syscall_sol_get_return_data( /**/ void * _vm,
197 : /**/ ulong dst_vaddr,
198 : /**/ ulong dst_max,
199 : /**/ ulong program_id_vaddr,
200 : FD_PARAM_UNUSED ulong r4,
201 : FD_PARAM_UNUSED ulong r5,
202 6 : /**/ ulong * _ret ) {
203 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1345 */
204 6 : fd_vm_t * vm = (fd_vm_t *)_vm;
205 :
206 6 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
207 :
208 0 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
209 6 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
210 :
211 6 : fd_txn_return_data_t const * return_data = &instr_ctx->txn_ctx->return_data;
212 6 : ulong return_data_sz = return_data->len;
213 :
214 6 : ulong cpy_sz = fd_ulong_min( return_data_sz, dst_max );
215 :
216 6 : if( FD_LIKELY( cpy_sz ) ) {
217 :
218 6 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( cpy_sz, sizeof(fd_pubkey_t) ) / FD_VM_CPI_BYTES_PER_UNIT );
219 :
220 12 : void * dst = FD_VM_MEM_SLICE_HADDR_ST( vm, dst_vaddr, FD_VM_ALIGN_RUST_U8, cpy_sz );
221 :
222 0 : memcpy( dst, return_data->data, cpy_sz );
223 :
224 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1376-L1381
225 : These can never happen. */
226 :
227 12 : void * program_id = FD_VM_MEM_HADDR_ST( vm, program_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, sizeof(fd_pubkey_t) );
228 :
229 3 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm, (ulong)dst, cpy_sz, (ulong)program_id, sizeof(fd_pubkey_t) );
230 :
231 0 : memcpy( program_id, &return_data->program_id, sizeof(fd_pubkey_t) );
232 0 : }
233 :
234 0 : *_ret = return_data_sz;
235 0 : return FD_VM_SUCCESS;
236 6 : }
237 :
238 : int
239 : fd_vm_syscall_sol_set_return_data( /**/ void * _vm,
240 : /**/ ulong src_vaddr,
241 : /**/ ulong src_sz,
242 : FD_PARAM_UNUSED ulong r3,
243 : FD_PARAM_UNUSED ulong r4,
244 : FD_PARAM_UNUSED ulong r5,
245 0 : /**/ ulong * _ret ) {
246 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1297 */
247 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
248 :
249 0 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
250 0 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_ERR_SIGCALL;
251 :
252 0 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, src_sz / FD_VM_CPI_BYTES_PER_UNIT ) );
253 :
254 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1316 */
255 0 : if( FD_UNLIKELY( src_sz>FD_VM_RETURN_DATA_MAX ) ) {
256 : /* TODO: this is a bit annoying, we may want to unify return codes...
257 : - FD_VM_ERR_SYSCALL_RETURN_DATA_TOO_LARGE is Agave's return code,
258 : also used for logging
259 : - FD_VM_ERR_RETURN_DATA_TOO_LARGE is Firedancer return code */
260 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_ERR_SYSCALL_RETURN_DATA_TOO_LARGE );
261 0 : return FD_VM_ERR_RETURN_DATA_TOO_LARGE;
262 0 : }
263 :
264 : /* src_sz == 0 is ok */
265 0 : void const * src = FD_VM_MEM_SLICE_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, src_sz );
266 :
267 0 : fd_pubkey_t const * program_id = &instr_ctx->instr->program_id_pubkey;
268 0 : fd_txn_return_data_t * return_data = &instr_ctx->txn_ctx->return_data;
269 :
270 0 : return_data->len = src_sz;
271 0 : if( FD_LIKELY( src_sz!=0UL ) ) {
272 0 : fd_memcpy( return_data->data, src, src_sz );
273 0 : }
274 0 : memcpy( &return_data->program_id, program_id, sizeof(fd_pubkey_t) );
275 :
276 0 : *_ret = 0;
277 0 : return FD_VM_SUCCESS;
278 0 : }
279 :
280 : /* Used to query and convey information about the sibling instruction
281 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L676
282 :
283 : */
284 : struct fd_vm_syscall_processed_sibling_instruction {
285 : /* Length of the instruction data */
286 : ulong data_len;
287 : /* Number of accounts */
288 : ulong accounts_len;
289 : };
290 : typedef struct fd_vm_syscall_processed_sibling_instruction fd_vm_syscall_processed_sibling_instruction_t;
291 :
292 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE (16UL)
293 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN (8UL )
294 :
295 : /*
296 : sol_get_last_processed_sibling_instruction returns the last element from a reverse-ordered
297 : list of successfully processed sibling instructions: the "processed sibling instruction list".
298 :
299 : For example, given the call flow:
300 : A
301 : B -> C -> D
302 : B
303 : B -> F (current execution point)
304 :
305 : B's processed sibling instruction list is [A]
306 : F's processed sibling instruction list is [E, C]
307 :
308 : This allows the current instruction to know what the last processed sibling instruction was.
309 : This is useful to check that critical preceeding instructions have actually executed: for example
310 : ensuring that an assert instruction has successfully executed.
311 :
312 : Parameters:
313 : - index:
314 : - result_meta_vaddr: virtual address of the object where metadata about the last processed sibling instruction will be stored upon successful execution (the length of the arrays in the result).
315 : Has the type solana_program::instruction::ProcessedSiblingInstruction
316 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L672-L681
317 : - result_program_id_vaddr: virtual address where the pubkey of the program ID of the last processed sibling instruction will be stored upon successful execution
318 : - result_data_vaddr: virtual address where the instruction data of the last processed sibling instruction will be stored upon successful execution. The length of the data will be stored in ProcessedSiblingInstruction.data_len
319 : - result_accounts_vaddr: virtual address where an array of account meta structures will be stored into upon successful execution. The length of the data will be stored in ProcessedSiblingInstruction.accounts_len
320 : Each account meta has the type solana_program::instruction::AccountMeta
321 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L525-L548
322 :
323 : Result:
324 : If a processed sibling instruction is found then 1 will be written into r0, and the result_* data structures
325 : above will be populated with the last processed sibling instruction.
326 : If there is no processed sibling instruction, 0 will be written into r0.
327 :
328 : Syscall entrypoint: https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1402
329 : */
330 : int
331 : fd_vm_syscall_sol_get_processed_sibling_instruction(
332 : void * _vm,
333 : ulong index,
334 : ulong result_meta_vaddr,
335 : ulong result_program_id_vaddr,
336 : ulong result_data_vaddr,
337 : ulong result_accounts_vaddr,
338 : ulong * ret
339 0 : ) {
340 :
341 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
342 :
343 : /* Consume base compute cost
344 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1414 */
345 0 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
346 :
347 : /*
348 : Get the current instruction stack height.
349 :
350 : Top-level instructions in Agave's invocation stack have a depth of 1
351 : https://github.com/anza-xyz/agave/blob/d87e23d8d91c32d5f2be2bb3557c730bee1e9434/sdk/program/src/instruction.rs#L732-L733
352 : Ours have a depth of 0, so we need to add 1 to account for the difference
353 : */
354 0 : ulong stack_height = fd_ulong_sat_add( vm->instr_ctx->depth, 1UL );
355 :
356 : /* Reverse iterate through the instruction trace, ignoring anything except instructions on the same level.
357 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1422 */
358 0 : ulong instruction_trace_length = vm->instr_ctx->txn_ctx->instr_trace_length;
359 0 : ulong reverse_index_at_stack_height = 0UL;
360 0 : fd_exec_instr_trace_entry_t * trace_entry = NULL;
361 0 : for( ulong index_in_trace = instruction_trace_length; index_in_trace > 0UL; index_in_trace-- ) {
362 :
363 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1432-L1434
364 : This error can never happen */
365 :
366 0 : fd_exec_instr_trace_entry_t * candidate_trace_entry = &vm->instr_ctx->txn_ctx->instr_trace[ index_in_trace - 1UL ];
367 0 : if( FD_LIKELY( candidate_trace_entry->stack_height < stack_height ) ) {
368 0 : break;
369 0 : }
370 :
371 0 : if( FD_UNLIKELY( candidate_trace_entry->stack_height == stack_height ) ) {
372 0 : if( FD_UNLIKELY( fd_ulong_sat_add( index, 1UL ) == reverse_index_at_stack_height ) ) {
373 0 : trace_entry = candidate_trace_entry;
374 0 : break;
375 0 : }
376 0 : reverse_index_at_stack_height = fd_ulong_sat_add( reverse_index_at_stack_height, 1UL );
377 0 : }
378 0 : }
379 :
380 : /* If we have found an entry, then copy the instruction into the result addresses
381 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1440-L1533
382 : */
383 0 : if( FD_LIKELY( trace_entry != NULL ) ) {
384 0 : fd_instr_info_t * instr_info = trace_entry->instr_info;
385 :
386 0 : fd_vm_syscall_processed_sibling_instruction_t * result_meta_haddr = FD_VM_MEM_HADDR_ST(
387 0 : vm,
388 0 : result_meta_vaddr,
389 0 : FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN,
390 0 : FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE );
391 :
392 : /* https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1447 */
393 0 : if( ( result_meta_haddr->data_len == trace_entry->instr_info->data_sz ) &&
394 0 : ( result_meta_haddr->accounts_len == trace_entry->instr_info->acct_cnt ) ) {
395 :
396 0 : fd_pubkey_t * result_program_id_haddr = FD_VM_MEM_HADDR_ST(
397 0 : vm,
398 0 : result_program_id_vaddr,
399 0 : FD_VM_ALIGN_RUST_PUBKEY,
400 0 : sizeof(fd_pubkey_t) );
401 :
402 0 : uchar * result_data_haddr = FD_VM_MEM_SLICE_HADDR_ST(
403 0 : vm,
404 0 : result_data_vaddr,
405 0 : FD_VM_ALIGN_RUST_U8,
406 0 : result_meta_haddr->data_len);
407 :
408 0 : ulong accounts_meta_total_size = fd_ulong_sat_mul( result_meta_haddr->accounts_len, FD_VM_RUST_ACCOUNT_META_SIZE );
409 0 : fd_vm_rust_account_meta_t * result_accounts_haddr = FD_VM_MEM_SLICE_HADDR_ST(
410 0 : vm,
411 0 : result_accounts_vaddr,
412 0 : FD_VM_RUST_ACCOUNT_META_ALIGN,
413 0 : accounts_meta_total_size);
414 :
415 : /* Check for memory overlaps
416 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1469 */
417 :
418 0 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
419 0 : result_meta_vaddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
420 0 : result_program_id_vaddr, sizeof(fd_pubkey_t) );
421 0 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
422 0 : result_meta_vaddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
423 0 : result_accounts_vaddr, accounts_meta_total_size );
424 0 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
425 0 : result_meta_vaddr, FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
426 0 : result_data_vaddr, result_meta_haddr->data_len );
427 0 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
428 0 : result_program_id_vaddr, sizeof(fd_pubkey_t),
429 0 : result_data_vaddr, result_meta_haddr->data_len );
430 0 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
431 0 : result_program_id_vaddr, sizeof(fd_pubkey_t),
432 0 : result_accounts_vaddr, accounts_meta_total_size );
433 0 : FD_VM_MEM_CHECK_NON_OVERLAPPING( vm,
434 0 : result_data_vaddr, result_meta_haddr->data_len,
435 0 : result_accounts_vaddr, accounts_meta_total_size );
436 :
437 : /* Copy the instruction into the result addresses
438 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1506-L1528
439 :
440 : Note: we assume that the instr accounts are already correct at this point.
441 : Agave has many error checks. */
442 0 : fd_memcpy( result_program_id_haddr->key, instr_info->program_id_pubkey.key, FD_PUBKEY_FOOTPRINT );
443 0 : fd_memcpy( result_data_haddr, instr_info->data, instr_info->data_sz );
444 0 : for( ulong i = 0UL; i < instr_info->acct_cnt; i++ ) {
445 0 : fd_memcpy( result_accounts_haddr[ i ].pubkey,
446 0 : vm->instr_ctx->txn_ctx->accounts[ instr_info->acct_txn_idxs[ i ] ].key,
447 0 : FD_PUBKEY_FOOTPRINT );
448 0 : result_accounts_haddr[ i ].is_signer = !!(instr_info->acct_flags[ i ] & FD_INSTR_ACCT_FLAGS_IS_SIGNER);
449 0 : result_accounts_haddr[ i ].is_writable = !!(instr_info->acct_flags[ i ] & FD_INSTR_ACCT_FLAGS_IS_WRITABLE);
450 0 : }
451 0 : }
452 :
453 : /* Copy the actual metadata into the result meta struct
454 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1529-L1531 */
455 0 : result_meta_haddr->data_len = instr_info->data_sz;
456 0 : result_meta_haddr->accounts_len = instr_info->acct_cnt;
457 :
458 : /* Return true as we found a sibling instruction
459 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1532 */
460 0 : *ret = 1UL;
461 0 : return FD_VM_SUCCESS;
462 0 : }
463 :
464 : /* Return false if we didn't find a sibling instruction
465 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1534 */
466 0 : *ret = 0UL;
467 0 : return FD_VM_SUCCESS;
468 0 : }
|