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