Line data Source code
1 : #include "fd_vm_syscall.h"
2 :
3 : #include "../../../ballet/bn254/fd_bn254.h"
4 : #include "../../../ballet/bn254/fd_poseidon.h"
5 : #include "../../../ballet/secp256k1/fd_secp256k1.h"
6 :
7 : int
8 : fd_vm_syscall_sol_alt_bn128_group_op( void * _vm,
9 : ulong group_op,
10 : ulong input_addr,
11 : ulong input_sz,
12 : ulong result_addr,
13 : FD_PARAM_UNUSED ulong r5,
14 0 : ulong * _ret ) {
15 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1509 */
16 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
17 0 : ulong ret = 1UL; /* by default return Ok(1) == error */
18 :
19 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1520-L1549 */
20 0 : ulong cost = 0UL;
21 0 : ulong output_sz = 0UL;
22 0 : switch( group_op ) {
23 :
24 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_ADD:
25 0 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
26 0 : cost = FD_VM_ALT_BN128_ADDITION_COST;
27 0 : break;
28 :
29 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_MUL:
30 0 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
31 0 : cost = FD_VM_ALT_BN128_MULTIPLICATION_COST;
32 0 : break;
33 :
34 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING:
35 0 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
36 0 : ulong elements_len = input_sz / FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_INPUT_EL_SZ;
37 0 : cost = FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_FIRST
38 0 : + FD_VM_SHA256_BASE_COST
39 0 : + FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING_OUTPUT_SZ;
40 0 : cost = fd_ulong_sat_add( cost,
41 0 : fd_ulong_sat_mul( FD_VM_ALT_BN128_PAIRING_ONE_PAIR_COST_OTHER,
42 0 : fd_ulong_sat_sub( elements_len, 1 ) ) );
43 0 : cost = fd_ulong_sat_add( cost, input_sz );
44 0 : break;
45 :
46 0 : default:
47 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
48 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
49 0 : }
50 :
51 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1551 */
52 :
53 0 : FD_VM_CU_UPDATE( vm, cost );
54 :
55 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L1660-L1664 */
56 :
57 0 : fd_vm_haddr_query_t call_result_query = {
58 0 : .vaddr = result_addr,
59 0 : .align = FD_VM_ALIGN_RUST_U8,
60 0 : .sz = output_sz,
61 0 : .is_slice = 1,
62 0 : };
63 :
64 0 : fd_vm_haddr_query_t * queries[] = { &call_result_query };
65 0 : FD_VM_TRANSLATE_MUT( vm, queries );
66 :
67 0 : uchar * call_result = call_result_query.haddr;
68 0 : uchar const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr, FD_VM_ALIGN_RUST_U8, input_sz );
69 :
70 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1567-L1598
71 : Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
72 0 : switch( group_op ) {
73 :
74 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_ADD:
75 : /* Compute add */
76 0 : if( FD_LIKELY( fd_bn254_g1_add_syscall( call_result, input, input_sz )==0 ) ) {
77 0 : ret = 0UL; /* success */
78 0 : }
79 0 : break;
80 :
81 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_MUL:
82 : /* Compute scalar mul */
83 0 : if( FD_LIKELY( fd_bn254_g1_scalar_mul_syscall( call_result, input, input_sz,
84 0 : FD_FEATURE_ACTIVE( vm->instr_ctx->txn_ctx->slot, &vm->instr_ctx->txn_ctx->features, fix_alt_bn128_multiplication_input_length ) )==0 ) ) {
85 0 : ret = 0UL; /* success */
86 0 : }
87 0 : break;
88 :
89 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_PAIRING:
90 : /* Compute pairing */
91 0 : if( FD_LIKELY( fd_bn254_pairing_is_one_syscall( call_result, input, input_sz )==0 ) ) {
92 0 : ret = 0UL; /* success */
93 0 : }
94 0 : break;
95 0 : }
96 :
97 0 : *_ret = ret;
98 0 : return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
99 0 : }
100 :
101 : int
102 : fd_vm_syscall_sol_alt_bn128_compression( void * _vm,
103 : ulong op,
104 : ulong input_addr,
105 : ulong input_sz,
106 : ulong result_addr,
107 : FD_PARAM_UNUSED ulong r5,
108 0 : ulong * _ret ) {
109 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1776 */
110 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
111 0 : ulong ret = 1UL; /* by default return Ok(1) == error */
112 :
113 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1791-L1811 */
114 0 : ulong cost = 0UL;
115 0 : ulong output_sz = 0UL;
116 0 : switch( op ) {
117 :
118 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS:
119 0 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ;
120 0 : cost = FD_VM_ALT_BN128_G1_COMPRESS;
121 0 : break;
122 :
123 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS:
124 0 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ;
125 0 : cost = FD_VM_ALT_BN128_G1_DECOMPRESS;
126 0 : break;
127 :
128 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS:
129 0 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ;
130 0 : cost = FD_VM_ALT_BN128_G2_COMPRESS;
131 0 : break;
132 :
133 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS:
134 0 : output_sz = FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ;
135 0 : cost = FD_VM_ALT_BN128_G2_DECOMPRESS;
136 0 : break;
137 :
138 0 : default:
139 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE );
140 0 : return FD_VM_SYSCALL_ERR_INVALID_ATTRIBUTE; /* SyscallError::InvalidAttribute */
141 0 : }
142 0 : cost = fd_ulong_sat_add( cost, FD_VM_SYSCALL_BASE_COST );
143 :
144 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1813 */
145 :
146 0 : FD_VM_CU_UPDATE( vm, cost );
147 :
148 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1815-L1827 */
149 :
150 0 : fd_vm_haddr_query_t call_result_query = {
151 0 : .vaddr = result_addr,
152 0 : .align = FD_VM_ALIGN_RUST_U8,
153 0 : .sz = output_sz,
154 0 : .is_slice = 1,
155 0 : };
156 :
157 0 : fd_vm_haddr_query_t * queries[] = { &call_result_query };
158 0 : FD_VM_TRANSLATE_MUT( vm, queries );
159 :
160 0 : uchar * call_result = call_result_query.haddr;
161 0 : void const * input = FD_VM_MEM_SLICE_HADDR_LD( vm, input_addr, FD_VM_ALIGN_RUST_U8, input_sz );
162 :
163 : /* input and call_result may alias. Therefore, buffer via out_buf */
164 0 : uchar out_buf[128];
165 :
166 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1829-L1891
167 : Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
168 0 : switch( op ) {
169 :
170 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESS:
171 0 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ ) ) {
172 0 : goto soft_error;
173 0 : }
174 0 : if( FD_LIKELY( fd_bn254_g1_compress( out_buf, fd_type_pun_const(input) ) ) ) {
175 0 : fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ );
176 0 : ret = 0UL; /* success */
177 0 : }
178 0 : break;
179 :
180 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G1_DECOMPRESS:
181 0 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G1_COMPRESSED_SZ ) ) {
182 0 : goto soft_error;
183 0 : }
184 0 : if( FD_LIKELY( fd_bn254_g1_decompress( out_buf, fd_type_pun_const(input) ) ) ) {
185 0 : fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G1_SZ );
186 0 : ret = 0UL; /* success */
187 0 : }
188 0 : break;
189 :
190 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESS:
191 0 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ ) ) {
192 0 : goto soft_error;
193 0 : }
194 0 : if( FD_LIKELY( fd_bn254_g2_compress( out_buf, fd_type_pun_const(input) ) ) ) {
195 0 : fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ );
196 0 : ret = 0UL; /* success */
197 0 : }
198 0 : break;
199 :
200 0 : case FD_VM_SYSCALL_SOL_ALT_BN128_G2_DECOMPRESS:
201 0 : if( FD_UNLIKELY( input_sz!=FD_VM_SYSCALL_SOL_ALT_BN128_G2_COMPRESSED_SZ ) ) {
202 0 : goto soft_error;
203 0 : }
204 0 : if( FD_LIKELY( fd_bn254_g2_decompress( out_buf, fd_type_pun_const(input) ) ) ) {
205 0 : fd_memcpy( call_result, out_buf, FD_VM_SYSCALL_SOL_ALT_BN128_G2_SZ );
206 0 : ret = 0UL; /* success */
207 0 : }
208 0 : break;
209 0 : }
210 :
211 0 : soft_error:
212 0 : *_ret = ret;
213 0 : return FD_VM_SUCCESS; /* Ok(SUCCESS) or Ok(ERROR) */
214 0 : }
215 :
216 : int
217 : fd_vm_syscall_sol_poseidon( void * _vm,
218 : ulong params,
219 : ulong endianness,
220 : ulong vals_addr,
221 : ulong vals_len,
222 : ulong result_addr,
223 0 : ulong * _ret ) {
224 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1678 */
225 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
226 0 : ulong ret = 1UL; /* by default return Ok(1) == error */
227 :
228 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1688 */
229 :
230 0 : if( FD_UNLIKELY( params!=0UL ) ) {
231 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS );
232 0 : return FD_VM_SYSCALL_ERR_POSEIDON_INVALID_PARAMS; /* PoseidonSyscallError::InvalidParameters */
233 0 : }
234 :
235 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1689 */
236 :
237 0 : if( FD_UNLIKELY(
238 0 : endianness!=0UL /* Big endian */
239 0 : && endianness!=1UL /* Little endian */
240 0 : ) ) {
241 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS );
242 0 : return FD_VM_SYSCALL_ERR_POSEIDON_INVALID_ENDIANNESS; /* PoseidonSyscallError::InvalidEndianness */
243 0 : }
244 :
245 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1691-L1698 */
246 :
247 0 : if( FD_UNLIKELY( vals_len > FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ) ) {
248 : /* Max msg_sz = 47 - 3 + 20 = 64 < 127 => we can use printf */
249 0 : fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
250 0 : "Poseidon hashing %lu sequences is not supported", vals_len );
251 0 : FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_LENGTH );
252 0 : return FD_VM_SYSCALL_ERR_INVALID_LENGTH; /* SyscallError::InvalidLength */
253 0 : }
254 :
255 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1700-L1707
256 : poseidon_cost(): https://github.com/solana-labs/solana/blob/v1.18.12/program-runtime/src/compute_budget.rs#L211 */
257 :
258 : /* vals_len^2 * A + C */
259 0 : ulong cost = fd_ulong_sat_add(
260 0 : fd_ulong_sat_mul(
261 0 : fd_ulong_sat_mul( vals_len, vals_len ),
262 0 : FD_VM_POSEIDON_COST_COEFFICIENT_A
263 0 : ),
264 0 : FD_VM_POSEIDON_COST_COEFFICIENT_C
265 0 : );
266 :
267 : /* The following can never happen, left as comment for completeness.
268 : if( FD_UNLIKELY( cost == ULONG_MAX ) ) {
269 : fd_vm_log_append_printf( vm, "Overflow while calculating the compute cost" );
270 : return FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW; // SyscallError::ArithmeticOverflow
271 : }
272 : */
273 :
274 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1708 */
275 :
276 0 : FD_VM_CU_UPDATE( vm, cost );
277 :
278 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1710-L1715 */
279 :
280 0 : fd_vm_haddr_query_t hash_result_query = {
281 0 : .vaddr = result_addr,
282 0 : .align = FD_VM_ALIGN_RUST_U8,
283 0 : .sz = 32UL,
284 0 : .is_slice = 1,
285 0 : };
286 :
287 0 : fd_vm_haddr_query_t * queries[] = { &hash_result_query };
288 0 : FD_VM_TRANSLATE_MUT( vm, queries );
289 :
290 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1716-L1732 */
291 :
292 : /* Agave allocates a vector of translated slices (that can return a fatal
293 : error), and then computes Poseidon, returning a soft error in case of
294 : issues (e.g. invalid input).
295 :
296 : We must be careful in returning the correct fatal vs soft error.
297 :
298 : The special case of vals_len==0 returns Ok(1), so for simplicity
299 : we capture it explicitly. */
300 :
301 0 : if( FD_UNLIKELY( !vals_len ) ) {
302 0 : goto soft_error;
303 0 : }
304 :
305 : /* First loop to memory map. This can return a fatal error. */
306 0 : fd_vm_vec_t const * input_vec_haddr = (fd_vm_vec_t const *)FD_VM_MEM_HADDR_LD( vm, vals_addr, FD_VM_VEC_ALIGN, vals_len*sizeof(fd_vm_vec_t) );
307 0 : void const * inputs_haddr[ FD_VM_SYSCALL_SOL_POSEIDON_MAX_VALS ];
308 0 : for( ulong i=0UL; i<vals_len; i++ ) {
309 0 : inputs_haddr[i] = FD_VM_MEM_SLICE_HADDR_LD( vm, input_vec_haddr[i].addr, FD_VM_ALIGN_RUST_U8, input_vec_haddr[i].len );
310 0 : }
311 :
312 : /* https://github.com/anza-xyz/agave/blob/v1.18.12/programs/bpf_loader/src/syscalls/mod.rs#L1734-L1750
313 : Note: this implementation is post SIMD-0129, we only support the simplified error codes. */
314 :
315 : /* Second loop to computed Poseidon. This can return a soft error. */
316 0 : int big_endian = endianness==0;
317 0 : fd_poseidon_t pos[1];
318 0 : fd_poseidon_init( pos, big_endian );
319 :
320 0 : for( ulong i=0UL; i<vals_len; i++ ) {
321 0 : if( FD_UNLIKELY( fd_poseidon_append( pos, inputs_haddr[ i ], input_vec_haddr[i].len )==NULL ) ) {
322 0 : goto soft_error;
323 0 : }
324 0 : }
325 :
326 0 : ret = !fd_poseidon_fini( pos, hash_result_query.haddr );
327 :
328 0 : soft_error:
329 0 : *_ret = ret;
330 0 : return FD_VM_SUCCESS; /* Ok(1) == error */
331 0 : }
332 :
333 : int
334 : fd_vm_syscall_sol_secp256k1_recover( /**/ void * _vm,
335 : /**/ ulong hash_vaddr,
336 : /**/ ulong recovery_id_val,
337 : /**/ ulong signature_vaddr,
338 : /**/ ulong result_vaddr,
339 : FD_PARAM_UNUSED ulong r5,
340 0 : /**/ ulong * _ret ) {
341 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L810 */
342 0 : fd_vm_t * vm = (fd_vm_t *)_vm;
343 :
344 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L820-L821 */
345 :
346 0 : FD_VM_CU_UPDATE( vm, FD_VM_SECP256K1_RECOVER_COST );
347 :
348 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L952-L956 */
349 0 : fd_vm_haddr_query_t pubkey_result_query = {
350 0 : .vaddr = result_vaddr,
351 0 : .align = FD_VM_ALIGN_RUST_U8,
352 0 : .sz = 64UL,
353 0 : .is_slice = 1,
354 0 : };
355 :
356 0 : fd_vm_haddr_query_t * queries[] = { &pubkey_result_query };
357 0 : FD_VM_TRANSLATE_MUT( vm, queries );
358 :
359 : /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mod.rs#L957-L968 */
360 :
361 0 : uchar const * hash = FD_VM_MEM_HADDR_LD( vm, hash_vaddr, FD_VM_ALIGN_RUST_U8, 32UL );
362 0 : uchar const * sig = FD_VM_MEM_HADDR_LD( vm, signature_vaddr, FD_VM_ALIGN_RUST_U8, 64UL );
363 :
364 : /* CRITICAL */
365 :
366 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L842-L853 */
367 :
368 : /* Secp256k1RecoverError::InvalidHash
369 : This can never happen, as `libsecp256k1::Message::parse_slice(hash)`
370 : only checks that hash is 32-byte long, and that's by construction.
371 : https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L657-L665
372 :
373 : if( FD_UNLIKELY( 0 ) ) {
374 : *_ret = 1UL; // Secp256k1RecoverError::InvalidHash
375 : return FD_VM_SUCCESS;
376 : }
377 : */
378 :
379 : /* Secp256k1RecoverError::InvalidRecoveryId
380 : Agave code has 2 checks: the first is a cast from u64 to u8.
381 : The second is `libsecp256k1::RecoveryId::parse(adjusted_recover_id_val)` that
382 : checks if `adjusted_recover_id_val < 4`.
383 : https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L674-L680
384 : */
385 :
386 0 : if( FD_UNLIKELY( recovery_id_val >= 4UL ) ) {
387 0 : *_ret = 2UL; /* Secp256k1RecoverError::InvalidRecoveryId */
388 0 : return FD_VM_SUCCESS;
389 0 : }
390 :
391 : /* Secp256k1RecoverError::InvalidSignature
392 : We omit this check, as this is done as part of fd_secp256k1_recover() below,
393 : and the return code is the same.
394 :
395 : In more details, this checks that the signature is valid, i.e. if the
396 : signature is represented as two scalars (r, s), it checks that both r
397 : and s are canonical scalars.
398 :
399 : Note the `?` at the end of this line:
400 : https://github.com/paritytech/libsecp256k1/blob/v0.6.0/src/lib.rs#L535
401 : And following the code, `scalar::check_overflow` is checks that the scalar is valid:
402 : https://github.com/paritytech/libsecp256k1/blob/master/core/src/scalar.rs#L70-L87 */
403 :
404 : /* https://github.com/anza-xyz/agave/blob/v1.18.8/programs/bpf_loader/src/syscalls/mod.rs#L855-L860 */
405 :
406 0 : uchar secp256k1_pubkey[64];
407 0 : if( FD_UNLIKELY( !fd_secp256k1_recover( secp256k1_pubkey, hash, sig, (int)recovery_id_val ) ) ) {
408 0 : *_ret = 3UL; /* Secp256k1RecoverError::InvalidSignature */
409 0 : return FD_VM_SUCCESS;
410 0 : }
411 :
412 0 : memcpy( pubkey_result_query.haddr, secp256k1_pubkey, 64UL );
413 :
414 0 : *_ret = 0UL;
415 0 : return FD_VM_SUCCESS;
416 0 : }
|