Line data Source code
1 : #include "fd_vm_syscall.h"
2 : #include "../../runtime/program/fd_vote_program.h"
3 : #include "../../runtime/context/fd_exec_instr_ctx.h"
4 : #include "../../runtime/fd_system_ids.h"
5 : #include "fd_vm_syscall_macros.h"
6 :
7 : /* FIXME: In the original version of this code, there was an FD_TEST
8 : to check if the VM was attached to an instruction context (that
9 : would have crashed anyway because of pointer chasing). If the VM
10 : is being run outside the Solana runtime, it should never invoke
11 : this syscall in the first place. So we treat this as a SIGCALL in
12 : a non-crashing way for the time being. */
13 :
14 : int
15 : fd_vm_syscall_sol_get_clock_sysvar( /**/ void * _vm,
16 : /**/ ulong out_vaddr,
17 : FD_PARAM_UNUSED ulong r2,
18 : FD_PARAM_UNUSED ulong r3,
19 : FD_PARAM_UNUSED ulong r4,
20 : FD_PARAM_UNUSED ulong r5,
21 81 : /**/ ulong * _ret ) {
22 81 : fd_vm_t * vm = _vm;
23 81 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
24 81 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
25 :
26 162 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sol_sysvar_clock_t) ) );
27 :
28 81 : if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
29 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
30 0 : return FD_VM_ERR_INVAL;
31 0 : }
32 :
33 81 : fd_vm_haddr_query_t var_query = {
34 81 : .vaddr = out_vaddr,
35 81 : .align = FD_VM_ALIGN_RUST_SYSVAR_CLOCK,
36 81 : .sz = sizeof(fd_sol_sysvar_clock_t),
37 81 : .is_slice = 0,
38 81 : };
39 :
40 81 : fd_vm_haddr_query_t * queries[] = { &var_query };
41 81 : FD_VM_TRANSLATE_MUT( vm, queries );
42 :
43 81 : fd_sol_sysvar_clock_t clock = fd_sysvar_cache_clock_read_nofail( instr_ctx->sysvar_cache );
44 0 : memcpy( var_query.haddr, &clock, sizeof(fd_sol_sysvar_clock_t) );
45 :
46 81 : *_ret = 0UL;
47 81 : return FD_VM_SUCCESS;
48 81 : }
49 :
50 : int
51 : fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/ void * _vm,
52 : /**/ ulong out_vaddr,
53 : FD_PARAM_UNUSED ulong r2,
54 : FD_PARAM_UNUSED ulong r3,
55 : FD_PARAM_UNUSED ulong r4,
56 : FD_PARAM_UNUSED ulong r5,
57 46 : /**/ ulong * _ret ) {
58 46 : fd_vm_t * vm = _vm;
59 46 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
60 46 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
61 :
62 92 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_epoch_schedule_t) ) );
63 :
64 46 : if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
65 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
66 0 : return FD_VM_ERR_INVAL;
67 0 : }
68 :
69 46 : fd_vm_haddr_query_t var_query = {
70 46 : .vaddr = out_vaddr,
71 46 : .align = FD_VM_ALIGN_RUST_SYSVAR_EPOCH_SCHEDULE,
72 46 : .sz = sizeof(fd_epoch_schedule_t),
73 46 : .is_slice = 0,
74 46 : };
75 :
76 46 : fd_vm_haddr_query_t * queries[] = { &var_query };
77 46 : FD_VM_TRANSLATE_MUT( vm, queries );
78 :
79 46 : fd_epoch_schedule_t schedule;
80 46 : if( FD_UNLIKELY( !fd_sysvar_cache_epoch_schedule_read( instr_ctx->sysvar_cache, &schedule ) ) ) {
81 0 : FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_out, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_out->err.exec_err_idx );
82 0 : return FD_VM_ERR_INVAL;
83 0 : }
84 46 : memcpy( var_query.haddr, &schedule, sizeof(fd_epoch_schedule_t) );
85 :
86 46 : *_ret = 0UL;
87 46 : return FD_VM_SUCCESS;
88 46 : }
89 :
90 : int
91 : fd_vm_syscall_sol_get_rent_sysvar( /**/ void * _vm,
92 : /**/ ulong out_vaddr,
93 : FD_PARAM_UNUSED ulong r2,
94 : FD_PARAM_UNUSED ulong r3,
95 : FD_PARAM_UNUSED ulong r4,
96 : FD_PARAM_UNUSED ulong r5,
97 98 : /**/ ulong * _ret ) {
98 98 : fd_vm_t * vm = _vm;
99 :
100 : /* Unreachable in a real SVM, used for testing */
101 :
102 98 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
103 98 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
104 :
105 196 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_rent_t) ) );
106 :
107 98 : if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
108 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
109 0 : return FD_VM_ERR_INVAL;
110 0 : }
111 :
112 98 : fd_vm_haddr_query_t var_query = {
113 98 : .vaddr = out_vaddr,
114 98 : .align = FD_VM_ALIGN_RUST_SYSVAR_RENT,
115 98 : .sz = sizeof(fd_rent_t),
116 98 : .is_slice = 0,
117 98 : };
118 :
119 98 : fd_vm_haddr_query_t * queries[] = { &var_query };
120 98 : FD_VM_TRANSLATE_MUT( vm, queries );
121 :
122 98 : fd_rent_t rent = fd_sysvar_cache_rent_read_nofail( instr_ctx->sysvar_cache );
123 0 : memcpy( var_query.haddr, &rent, sizeof(fd_rent_t) );
124 :
125 98 : *_ret = 0UL;
126 98 : return FD_VM_SUCCESS;
127 98 : }
128 :
129 : /* https://github.com/anza-xyz/agave/blob/v2.3.2/programs/bpf_loader/src/syscalls/sysvar.rs#L149 */
130 : int
131 : fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/ void * _vm,
132 : /**/ ulong out_vaddr,
133 : FD_PARAM_UNUSED ulong r2,
134 : FD_PARAM_UNUSED ulong r3,
135 : FD_PARAM_UNUSED ulong r4,
136 : FD_PARAM_UNUSED ulong r5,
137 76 : /**/ ulong * _ret ) {
138 76 : fd_vm_t * vm = _vm;
139 76 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
140 76 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
141 :
142 152 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sol_sysvar_last_restart_slot_t) ) );
143 :
144 76 : if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
145 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
146 0 : return FD_VM_ERR_INVAL;
147 0 : }
148 :
149 76 : fd_vm_haddr_query_t var_query = {
150 76 : .vaddr = out_vaddr,
151 76 : .align = FD_VM_ALIGN_RUST_SYSVAR_LAST_RESTART_SLOT,
152 76 : .sz = sizeof(fd_sol_sysvar_last_restart_slot_t),
153 76 : .is_slice = 0,
154 76 : };
155 :
156 76 : fd_vm_haddr_query_t * queries[] = { &var_query };
157 76 : FD_VM_TRANSLATE_MUT( vm, queries );
158 :
159 76 : fd_sol_sysvar_last_restart_slot_t last_restart_slot;
160 76 : if( FD_UNLIKELY( !fd_sysvar_cache_last_restart_slot_read( vm->instr_ctx->sysvar_cache, &last_restart_slot ) ) ) {
161 0 : FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_out, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_out->err.exec_err_idx );
162 0 : return FD_VM_ERR_INVAL;
163 0 : }
164 :
165 76 : memcpy( var_query.haddr, &last_restart_slot, sizeof(fd_sol_sysvar_last_restart_slot_t) );
166 :
167 76 : *_ret = 0UL;
168 76 : return FD_VM_SUCCESS;
169 76 : }
170 :
171 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L167-L232 */
172 : int
173 : fd_vm_syscall_sol_get_sysvar( /**/ void * _vm,
174 : /**/ ulong sysvar_id_vaddr,
175 : /**/ ulong out_vaddr,
176 : /**/ ulong offset,
177 : /**/ ulong sz,
178 : FD_PARAM_UNUSED ulong r5,
179 296 : /**/ ulong * _ret ) {
180 296 : fd_vm_t * vm = _vm;
181 296 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
182 296 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
183 :
184 : /* sysvar_id_cost seems to just always be 32 / 250 = 0...
185 : https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L190-L197 */
186 296 : ulong sysvar_buf_cost = sz / FD_VM_CPI_BYTES_PER_UNIT;
187 296 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, fd_ulong_max( sysvar_buf_cost, FD_VM_MEM_OP_BASE_COST ) ) );
188 :
189 269 : if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
190 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
191 0 : return FD_VM_ERR_INVAL;
192 0 : }
193 :
194 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/sysvar.rs#L207-L211 */
195 269 : fd_vm_haddr_query_t var_query = {
196 269 : .vaddr = out_vaddr,
197 269 : .align = FD_VM_ALIGN_RUST_U8,
198 269 : .sz = sz,
199 269 : .is_slice = 1,
200 269 : };
201 :
202 269 : fd_vm_haddr_query_t * queries[] = { &var_query };
203 269 : FD_VM_TRANSLATE_MUT( vm, queries );
204 :
205 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L199-L200 */
206 648 : const fd_pubkey_t * sysvar_id = FD_VM_MEM_HADDR_LD( vm, sysvar_id_vaddr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
207 :
208 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L205-L208 */
209 0 : ulong offset_length;
210 648 : int err = fd_int_if( __builtin_uaddl_overflow( offset, sz, &offset_length ), FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW, FD_EXECUTOR_INSTR_SUCCESS );
211 648 : if( FD_UNLIKELY( err ) ) {
212 0 : FD_VM_ERR_FOR_LOG_INSTR( vm, err );
213 0 : return FD_VM_SYSCALL_ERR_ABORT;
214 0 : }
215 :
216 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L210-L213
217 : We don't need this, we already checked we can store in out_vaddr with requested sz. */
218 :
219 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L215-L221 */
220 216 : if( FD_UNLIKELY( memcmp( sysvar_id->uc, fd_sysvar_clock_id.uc, FD_PUBKEY_FOOTPRINT ) &&
221 216 : memcmp( sysvar_id->uc, fd_sysvar_epoch_schedule_id.uc, FD_PUBKEY_FOOTPRINT ) &&
222 216 : memcmp( sysvar_id->uc, fd_sysvar_epoch_rewards_id.uc, FD_PUBKEY_FOOTPRINT ) &&
223 216 : memcmp( sysvar_id->uc, fd_sysvar_rent_id.uc, FD_PUBKEY_FOOTPRINT ) &&
224 216 : memcmp( sysvar_id->uc, fd_sysvar_slot_hashes_id.uc, FD_PUBKEY_FOOTPRINT ) &&
225 216 : memcmp( sysvar_id->uc, fd_sysvar_stake_history_id.uc, FD_PUBKEY_FOOTPRINT ) &&
226 216 : memcmp( sysvar_id->uc, fd_sysvar_last_restart_slot_id.uc, FD_PUBKEY_FOOTPRINT ) ) ) {
227 164 : *_ret = 2UL;
228 164 : return FD_VM_SUCCESS;
229 164 : }
230 :
231 52 : ulong sysvar_buf_len;
232 52 : uchar const * sysvar_buf =
233 52 : fd_sysvar_cache_data_query( vm->instr_ctx->sysvar_cache, sysvar_id, &sysvar_buf_len );
234 52 : if( FD_UNLIKELY( !sysvar_buf ) ) {
235 0 : *_ret = 2UL;
236 0 : return FD_VM_SUCCESS;
237 0 : }
238 :
239 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L223-L228
240 : Note the length check is at the very end to fail after performing sufficient checks. */
241 :
242 52 : if( FD_UNLIKELY( offset_length>sysvar_buf_len ) ) {
243 0 : *_ret = 1UL;
244 0 : return FD_VM_SUCCESS;
245 0 : }
246 :
247 52 : if( FD_UNLIKELY( sz==0UL ) ) {
248 21 : *_ret = 0UL;
249 21 : return FD_VM_SUCCESS;
250 21 : }
251 :
252 31 : fd_memcpy( var_query.haddr, sysvar_buf + offset, sz );
253 31 : *_ret = 0;
254 31 : return FD_VM_SUCCESS;
255 52 : }
256 :
257 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2043-L2118 */
258 : int
259 : fd_vm_syscall_sol_get_epoch_stake( /**/ void * _vm,
260 : /**/ ulong var_addr,
261 : FD_PARAM_UNUSED ulong r2,
262 : FD_PARAM_UNUSED ulong r3,
263 : FD_PARAM_UNUSED ulong r4,
264 : FD_PARAM_UNUSED ulong r5,
265 16 : /**/ ulong * _ret ) {
266 16 : fd_vm_t * vm = (fd_vm_t *)_vm;
267 :
268 : /* Var addr of 0 returns the total active stake on the cluster.
269 :
270 : https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2057-L2075 */
271 16 : if( FD_UNLIKELY( var_addr==0UL ) ) {
272 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2065-L2066 */
273 0 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
274 :
275 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2074 */
276 0 : *_ret = fd_bank_total_epoch_stake_get( vm->instr_ctx->bank );
277 0 : return FD_VM_SUCCESS;
278 0 : }
279 :
280 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2083-L2091
281 : FD_PUBKEY_FOOTPRINT/FD_VM_CPI_BYTES_PER_UNIT is always 32/250 = 0,
282 : so we can omit it */
283 :
284 32 : FD_VM_CU_UPDATE( vm, FD_VM_MEM_OP_BASE_COST + FD_VM_SYSCALL_BASE_COST );
285 :
286 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/mod.rs#L2103-L2104 */
287 16 : fd_pubkey_t const * vote_address = FD_VM_MEM_HADDR_LD( vm, var_addr, FD_VM_ALIGN_RUST_PUBKEY, FD_PUBKEY_FOOTPRINT );
288 :
289 : /* https://github.com/anza-xyz/agave/blob/v2.2.14/runtime/src/bank.rs#L6954 */
290 0 : fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes_locking_modify( vm->instr_ctx->bank );
291 :
292 16 : ulong stake;
293 16 : fd_pubkey_t node_account;
294 16 : int found = fd_vote_stakes_query_t_1( vote_stakes, vm->instr_ctx->bank->data->vote_stakes_fork_id, vote_address, &stake, &node_account );
295 16 : *_ret = found ? stake : 0UL;
296 16 : fd_bank_vote_stakes_end_locking_modify( vm->instr_ctx->bank );
297 :
298 16 : return FD_VM_SUCCESS;
299 32 : }
300 :
301 : int
302 : fd_vm_syscall_sol_get_stack_height( /**/ void * _vm,
303 : FD_PARAM_UNUSED ulong r1,
304 : FD_PARAM_UNUSED ulong r2,
305 : FD_PARAM_UNUSED ulong r3,
306 : FD_PARAM_UNUSED ulong r4,
307 : FD_PARAM_UNUSED ulong r5,
308 86 : /**/ ulong * _ret ) {
309 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1547 */
310 86 : fd_vm_t * vm = (fd_vm_t *)_vm;
311 :
312 86 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
313 :
314 0 : *_ret = vm->instr_ctx->runtime->instr.stack_sz;
315 86 : return FD_VM_SUCCESS;
316 86 : }
317 :
318 : int
319 : fd_vm_syscall_sol_get_return_data( /**/ void * _vm,
320 : /**/ ulong return_data_vaddr,
321 : /**/ ulong sz,
322 : /**/ ulong program_id_vaddr,
323 : FD_PARAM_UNUSED ulong r4,
324 : FD_PARAM_UNUSED ulong r5,
325 105 : /**/ ulong * _ret ) {
326 105 : fd_vm_t * vm = (fd_vm_t *)_vm;
327 :
328 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1465 */
329 105 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
330 :
331 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1467 */
332 0 : fd_txn_return_data_t const * return_data = &vm->instr_ctx->txn_out->details.return_data;
333 :
334 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1468 */
335 105 : ulong length = fd_ulong_min( return_data->len, sz );
336 :
337 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1469-L1492 */
338 105 : if( FD_LIKELY( length ) ) {
339 :
340 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1470-L1474 */
341 24 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( length, sizeof(fd_pubkey_t) ) / FD_VM_CPI_BYTES_PER_UNIT );
342 :
343 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1476-L1481 */
344 0 : fd_vm_haddr_query_t return_data_query = {
345 24 : .vaddr = return_data_vaddr,
346 24 : .align = FD_VM_ALIGN_RUST_U8,
347 24 : .sz = length,
348 24 : .is_slice = 1
349 24 : };
350 :
351 24 : fd_vm_haddr_query_t program_id_query = {
352 24 : .vaddr = program_id_vaddr,
353 24 : .align = FD_VM_ALIGN_RUST_PUBKEY,
354 24 : .sz = sizeof(fd_pubkey_t),
355 24 : .is_slice = 0
356 24 : };
357 :
358 24 : fd_vm_haddr_query_t * queries[] = { &return_data_query, &program_id_query };
359 24 : FD_VM_TRANSLATE_MUT( vm, queries );
360 :
361 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1490-L1491 */
362 22 : memcpy( return_data_query.haddr, return_data->data, length );
363 22 : memcpy( program_id_query.haddr, &return_data->program_id, sizeof(fd_pubkey_t) );
364 22 : }
365 :
366 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1495 */
367 103 : *_ret = return_data->len;
368 103 : return FD_VM_SUCCESS;
369 105 : }
370 :
371 : int
372 : fd_vm_syscall_sol_set_return_data( /**/ void * _vm,
373 : /**/ ulong src_vaddr,
374 : /**/ ulong src_sz,
375 : FD_PARAM_UNUSED ulong r3,
376 : FD_PARAM_UNUSED ulong r4,
377 : FD_PARAM_UNUSED ulong r5,
378 116 : /**/ ulong * _ret ) {
379 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1297 */
380 116 : fd_vm_t * vm = (fd_vm_t *)_vm;
381 :
382 : /* In the original version of this code, there was an FD_TEST
383 : to check if the VM was attached to an instruction context (that
384 : would have crashed anyway because of pointer chasing). If the VM
385 : is being run outside the Solana runtime, it should never invoke
386 : this syscall in the first place. So we treat this as a SIGCALL in
387 : a non-crashing way for the time being. */
388 116 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
389 116 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
390 :
391 232 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSCALL_BASE_COST, src_sz / FD_VM_CPI_BYTES_PER_UNIT ) );
392 :
393 : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L1316 */
394 116 : if( FD_UNLIKELY( src_sz>FD_VM_RETURN_DATA_MAX ) ) {
395 : /* TODO: this is a bit annoying, we may want to unify return codes...
396 : - FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE is Agave's return code,
397 : also used for logging */
398 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE );
399 0 : return FD_VM_SYSCALL_ERR_RETURN_DATA_TOO_LARGE;
400 0 : }
401 :
402 : /* src_sz == 0 is ok */
403 232 : void const * src = FD_VM_MEM_SLICE_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, src_sz );
404 :
405 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/programs/bpf_loader/src/syscalls/mod.rs#L1480-L1484 */
406 0 : fd_pubkey_t const * program_id = NULL;
407 232 : int err = fd_exec_instr_ctx_get_last_program_key( vm->instr_ctx, &program_id );
408 232 : if( FD_UNLIKELY( err ) ) {
409 0 : FD_VM_ERR_FOR_LOG_INSTR( vm, err );
410 0 : return err;
411 0 : }
412 :
413 116 : fd_txn_return_data_t * return_data = &instr_ctx->txn_out->details.return_data;
414 :
415 116 : return_data->len = src_sz;
416 116 : if( FD_LIKELY( src_sz!=0UL ) ) {
417 116 : fd_memcpy( return_data->data, src, src_sz );
418 116 : }
419 116 : return_data->program_id = *program_id;
420 :
421 116 : *_ret = 0;
422 116 : return FD_VM_SUCCESS;
423 232 : }
424 :
425 : /* Used to query and convey information about the sibling instruction
426 : https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/sdk/program/src/instruction.rs#L676
427 :
428 : */
429 : struct fd_vm_syscall_processed_sibling_instruction {
430 : /* Length of the instruction data */
431 : ulong data_len;
432 : /* Number of accounts */
433 : ulong accounts_len;
434 : };
435 : typedef struct fd_vm_syscall_processed_sibling_instruction fd_vm_syscall_processed_sibling_instruction_t;
436 :
437 2 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE (16UL)
438 2 : #define FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN (8UL )
439 :
440 : /* https://github.com/anza-xyz/agave/blob/70089cce5119c9afaeb2986e2ecaa6d4505ec15d/programs/bpf_loader/src/syscalls/mod.rs#L1402 */
441 : int
442 : fd_vm_syscall_sol_get_processed_sibling_instruction(
443 : void * _vm,
444 : ulong index,
445 : ulong result_meta_vaddr,
446 : ulong result_program_id_vaddr,
447 : ulong result_data_vaddr,
448 : ulong result_accounts_vaddr,
449 : ulong * _ret
450 75 : ) {
451 75 : fd_vm_t * vm = (fd_vm_t *)_vm;
452 :
453 : /* Consume base compute cost
454 : https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1513 */
455 75 : FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
456 :
457 : /* Get the current instruction stack height. This value is 1-indexed
458 : (top level instruction has a stack height of 1).
459 : https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1517 */
460 0 : ulong stack_height = vm->instr_ctx->runtime->instr.stack_sz;
461 :
462 : /* Reverse iterate through the instruction trace, ignoring anything except instructions on the same level.
463 : https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1518-L1522 */
464 75 : ulong instruction_trace_length = vm->instr_ctx->runtime->instr.trace_length;
465 75 : ulong reverse_index_at_stack_height = 0UL;
466 75 : fd_instr_info_t * found_instruction_context = NULL;
467 191 : for( ulong index_in_trace=instruction_trace_length; index_in_trace>0UL; index_in_trace-- ) {
468 :
469 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1524-L1526
470 : This error can never happen */
471 :
472 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1527-L1529 */
473 147 : fd_instr_info_t * instruction_context = &vm->instr_ctx->runtime->instr.trace[ index_in_trace-1UL ];
474 147 : if( FD_LIKELY( instruction_context->stack_height<stack_height ) ) {
475 29 : break;
476 29 : }
477 :
478 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1530-L1536 */
479 118 : if( FD_UNLIKELY( instruction_context->stack_height==stack_height ) ) {
480 85 : if( FD_UNLIKELY( fd_ulong_sat_add( index, 1UL )==reverse_index_at_stack_height ) ) {
481 2 : found_instruction_context = instruction_context;
482 2 : break;
483 2 : }
484 83 : reverse_index_at_stack_height = fd_ulong_sat_add( reverse_index_at_stack_height, 1UL );
485 83 : }
486 118 : }
487 :
488 : /* If we have found an entry, then copy the instruction into the
489 : result addresses.
490 : https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1539-L1588
491 : */
492 75 : if( FD_LIKELY( found_instruction_context != NULL ) ) {
493 2 : fd_vm_haddr_query_t result_header_query = {
494 2 : .vaddr = result_meta_vaddr,
495 2 : .align = FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_ALIGN,
496 2 : .sz = FD_VM_SYSCALL_PROCESSED_SIBLING_INSTRUCTION_SIZE,
497 2 : .is_slice = 0,
498 2 : };
499 :
500 2 : fd_vm_haddr_query_t * queries[] = { &result_header_query };
501 2 : FD_VM_TRANSLATE_MUT( vm, queries );
502 :
503 2 : fd_vm_syscall_processed_sibling_instruction_t * result_header = result_header_query.haddr;
504 :
505 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1546-L1583 */
506 2 : if( result_header->data_len==found_instruction_context->data_sz && result_header->accounts_len==found_instruction_context->acct_cnt ) {
507 1 : fd_vm_haddr_query_t program_id_query = {
508 1 : .vaddr = result_program_id_vaddr,
509 1 : .align = FD_VM_ALIGN_RUST_PUBKEY,
510 1 : .sz = sizeof(fd_pubkey_t),
511 1 : .is_slice = 0,
512 1 : };
513 :
514 1 : fd_vm_haddr_query_t data_query = {
515 1 : .vaddr = result_data_vaddr,
516 1 : .align = FD_VM_ALIGN_RUST_U8,
517 1 : .sz = result_header->data_len,
518 1 : .is_slice = 1,
519 1 : };
520 :
521 1 : fd_vm_haddr_query_t accounts_query = {
522 1 : .vaddr = result_accounts_vaddr,
523 1 : .align = FD_VM_RUST_ACCOUNT_META_ALIGN,
524 1 : .sz = fd_ulong_sat_mul( result_header->accounts_len, FD_VM_RUST_ACCOUNT_META_SIZE ),
525 1 : .is_slice = 1,
526 1 : };
527 :
528 1 : fd_vm_haddr_query_t * queries[] = { &program_id_query, &data_query, &accounts_query, &result_header_query };
529 1 : FD_VM_TRANSLATE_MUT( vm, queries );
530 :
531 1 : fd_pubkey_t * program_id = program_id_query.haddr;
532 1 : uchar * data = data_query.haddr;
533 1 : fd_vm_rust_account_meta_t * accounts = accounts_query.haddr;
534 :
535 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1561-L1562 */
536 1 : fd_pubkey_t const * instr_ctx_program_id = NULL;
537 1 : int err = fd_runtime_get_key_of_account_at_index(
538 1 : vm->instr_ctx->txn_out,
539 1 : found_instruction_context->program_id,
540 1 : &instr_ctx_program_id
541 1 : );
542 1 : if( FD_UNLIKELY( err ) ) {
543 0 : FD_VM_ERR_FOR_LOG_INSTR( vm, err );
544 0 : return err;
545 0 : }
546 1 : fd_memcpy( program_id, instr_ctx_program_id, sizeof(fd_pubkey_t) );
547 :
548 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1563 */
549 1 : fd_memcpy( data, found_instruction_context->data, found_instruction_context->data_sz );
550 :
551 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1564-L1581 */
552 259 : for( ushort i=0; i<found_instruction_context->acct_cnt; i++ ) {
553 258 : fd_pubkey_t const * account_key;
554 258 : ushort txn_idx = found_instruction_context->accounts[ i ].index_in_transaction;
555 258 : err = fd_runtime_get_key_of_account_at_index( vm->instr_ctx->txn_out, txn_idx, &account_key );
556 258 : if( FD_UNLIKELY( err ) ) {
557 0 : FD_VM_ERR_FOR_LOG_INSTR( vm, err );
558 0 : return err;
559 0 : }
560 :
561 258 : fd_memcpy( accounts[ i ].pubkey, account_key, sizeof(fd_pubkey_t) );
562 258 : accounts[ i ].is_signer = !!(found_instruction_context->accounts[ i ].is_signer );
563 258 : accounts[ i ].is_writable = !!(found_instruction_context->accounts[ i ].is_writable );
564 258 : }
565 1 : } else {
566 : /* Copy the actual metadata into the result meta struct
567 : https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1584-L1586 */
568 1 : result_header->data_len = found_instruction_context->data_sz;
569 1 : result_header->accounts_len = found_instruction_context->acct_cnt;
570 1 : }
571 :
572 : /* Return true as we found a sibling instruction
573 : https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1588 */
574 2 : *_ret = 1UL;
575 2 : return FD_VM_SUCCESS;
576 2 : }
577 :
578 : /* Return false if we didn't find a sibling instruction
579 : https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1590 */
580 73 : *_ret = 0UL;
581 73 : return FD_VM_SUCCESS;
582 75 : }
583 :
584 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/sysvar.rs#L80 */
585 : int
586 : fd_vm_syscall_sol_get_epoch_rewards_sysvar( /**/ void * _vm,
587 : /**/ ulong out_vaddr,
588 : FD_PARAM_UNUSED ulong r2,
589 : FD_PARAM_UNUSED ulong r3,
590 : FD_PARAM_UNUSED ulong r4,
591 : FD_PARAM_UNUSED ulong r5,
592 3425 : /**/ ulong * _ret ) {
593 3425 : fd_vm_t * vm = _vm;
594 3425 : fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx;
595 3425 : if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME;
596 :
597 6850 : FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sysvar_epoch_rewards_t) ) );
598 :
599 3425 : if( FD_UNLIKELY( vm->stricter_abi_and_runtime_constraints && out_vaddr>=FD_VM_MEM_MAP_INPUT_REGION_START ) ) {
600 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_POINTER );
601 0 : return FD_VM_ERR_INVAL;
602 0 : }
603 :
604 3425 : uchar * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_REWARDS, sizeof(fd_sysvar_epoch_rewards_t) );
605 :
606 0 : fd_sysvar_epoch_rewards_t epoch_rewards;
607 3420 : if( FD_UNLIKELY( !fd_sysvar_cache_epoch_rewards_read( instr_ctx->sysvar_cache, &epoch_rewards ) ) ) {
608 3267 : FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_out, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_out->err.exec_err_idx );
609 3267 : return FD_VM_ERR_INVAL;
610 3267 : }
611 153 : memcpy( out, &epoch_rewards, sizeof(fd_sysvar_epoch_rewards_t) );
612 153 : memset( out+81, 0, 15 ); /* padding */
613 :
614 153 : *_ret = 0UL;
615 153 : return FD_VM_SUCCESS;
616 3420 : }
|