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