1use neo_types::*;
7
8#[cfg(not(target_arch = "wasm32"))]
9use crate::storage::*;
10#[cfg(not(target_arch = "wasm32"))]
13use crate::syscalls::SYSCALLS;
14#[cfg(not(target_arch = "wasm32"))]
15use crate::NeoVMSyscallInfo;
16
17#[cfg(target_arch = "wasm32")]
25#[allow(dead_code)]
26#[link(wasm_import_module = "neo")]
27extern "C" {
28 #[link_name = "runtime_check_witness_bytes"]
29 fn neo_runtime_check_witness_bytes(ptr: i32, len: i32) -> i32;
30
31 #[link_name = "runtime_check_witness_i64"]
32 fn neo_runtime_check_witness_i64(account: i64) -> i32;
33
34 #[link_name = "runtime_get_time"]
35 fn neo_runtime_get_time() -> i64;
36
37 #[link_name = "runtime_get_calling_script_hash_i64"]
38 fn neo_runtime_get_calling_script_hash_i64() -> i64;
39
40 #[link_name = "runtime_get_entry_script_hash_i64"]
41 fn neo_runtime_get_entry_script_hash_i64() -> i64;
42
43 #[link_name = "runtime_get_executing_script_hash_i64"]
44 fn neo_runtime_get_executing_script_hash_i64() -> i64;
45
46 #[link_name = "runtime_get_calling_script_hash"]
51 fn neo_runtime_get_calling_script_hash(out_ptr: i32, out_cap: i32) -> i32;
52 #[link_name = "runtime_get_entry_script_hash"]
53 fn neo_runtime_get_entry_script_hash(out_ptr: i32, out_cap: i32) -> i32;
54 #[link_name = "runtime_get_executing_script_hash"]
55 fn neo_runtime_get_executing_script_hash(out_ptr: i32, out_cap: i32) -> i32;
56
57 #[link_name = "runtime_log"]
58 fn neo_runtime_log(ptr: i32, len: i32);
59
60 #[link_name = "runtime_notify"]
66 fn neo_runtime_notify(event_ptr: i32, event_len: i32);
67 #[link_name = "runtime_notify_with_state"]
68 fn neo_runtime_notify_with_state(
69 event_ptr: i32,
70 event_len: i32,
71 state_ptr: i32,
72 state_len: i32,
73 );
74
75 #[link_name = "check_sig"]
79 fn neo_runtime_check_sig(pubkey_ptr: i32, pubkey_len: i32, sig_ptr: i32, sig_len: i32) -> i32;
80
81 #[link_name = "check_multisig"]
83 fn neo_runtime_check_multisig(
84 pubkeys_ptr: i32,
85 pubkeys_len: i32,
86 sigs_ptr: i32,
87 sigs_len: i32,
88 ) -> i32;
89
90 #[link_name = "verify_with_ecdsa"]
93 fn neo_runtime_verify_with_ecdsa(
94 msg_ptr: i32,
95 msg_len: i32,
96 pubkey_ptr: i32,
97 pubkey_len: i32,
98 sig_ptr: i32,
99 sig_len: i32,
100 curve: i32,
101 ) -> i32;
102
103 #[link_name = "neo_storage_put_bytes"]
108 fn neo_storage_put_bytes(key_ptr: i32, key_len: i32, value_ptr: i32, value_len: i32);
109
110 #[link_name = "neo_storage_delete_bytes"]
115 fn neo_storage_delete_bytes(key_ptr: i32, key_len: i32);
116
117 #[link_name = "neo_storage_get_into"]
124 fn neo_storage_get_into(key_ptr: i32, key_len: i32, out_ptr: i32, out_cap: i32) -> i32;
125
126 #[link_name = "runtime_get_random"]
130 fn neo_runtime_get_random() -> i64;
131 #[link_name = "runtime_get_invocation_counter"]
132 fn neo_runtime_get_invocation_counter() -> i32;
133 #[link_name = "runtime_get_gas_left"]
134 fn neo_runtime_get_gas_left() -> i64;
135 #[link_name = "runtime_get_notifications"]
136 fn neo_runtime_get_notifications(
137 script_hash_ptr: i32,
138 script_hash_len: i32,
139 out_ptr: i32,
140 out_cap: i32,
141 ) -> i32;
142 #[link_name = "runtime_current_signers"]
143 fn neo_runtime_current_signers(out_ptr: i32, out_cap: i32) -> i32;
144 #[link_name = "runtime_burn_gas"]
145 fn neo_runtime_burn_gas(gas: i64);
146 #[link_name = "runtime_get_script_container"]
147 fn neo_runtime_get_script_container(out_ptr: i32, out_cap: i32) -> i32;
148 #[link_name = "runtime_load_script"]
149 fn neo_runtime_load_script(
150 script_ptr: i32,
151 script_len: i32,
152 call_flags: i32,
153 args_ptr: i32,
154 args_len: i32,
155 );
156 #[link_name = "runtime_create_standard_account"]
157 fn neo_runtime_create_standard_account(
158 pubkey_ptr: i32,
159 pubkey_len: i32,
160 out_ptr: i32,
161 out_cap: i32,
162 ) -> i32;
163 #[link_name = "runtime_create_multisig_account"]
164 fn neo_runtime_create_multisig_account(
165 threshold: i32,
166 pubkeys_ptr: i32,
167 pubkeys_len: i32,
168 out_ptr: i32,
169 out_cap: i32,
170 ) -> i32;
171 #[link_name = "runtime_contract_call_native"]
172 fn neo_runtime_contract_call_native(
173 native_id: i32,
174 method_ptr: i32,
175 method_len: i32,
176 args_ptr: i32,
177 args_len: i32,
178 out_ptr: i32,
179 out_cap: i32,
180 ) -> i32;
181 #[link_name = "runtime_get_call_flags"]
182 fn neo_runtime_get_call_flags() -> i32;
183 #[link_name = "runtime_get_storage_context"]
184 fn neo_runtime_get_storage_context() -> i32;
185 #[link_name = "runtime_get_read_only_context"]
186 fn neo_runtime_get_read_only_context() -> i32;
187 #[link_name = "runtime_storage_as_read_only"]
188 fn neo_runtime_storage_as_read_only(context_id: i32) -> i32;
189 #[link_name = "runtime_storage_find"]
190 fn neo_runtime_storage_find(
191 context_id: i32,
192 prefix_ptr: i32,
193 prefix_len: i32,
194 options: i32,
195 out_ptr: i32,
196 out_cap: i32,
197 ) -> i32;
198 #[link_name = "runtime_iterator_next"]
199 fn neo_runtime_iterator_next(iterator_id: i32) -> i32;
200 #[link_name = "runtime_iterator_value"]
201 fn neo_runtime_iterator_value(iterator_id: i32, out_ptr: i32, out_cap: i32) -> i32;
202
203 #[link_name = "protocol_get_network"]
206 fn neo_protocol_get_network() -> i32;
207 #[link_name = "protocol_get_address_version"]
208 fn neo_protocol_get_address_version() -> i32;
209 #[link_name = "protocol_get_trigger"]
210 fn neo_protocol_get_trigger() -> i32;
211
212 #[link_name = "neo_contract_call"]
217 fn neo_contract_call(
218 hash_ptr: i32,
219 hash_len: i32,
220 method_ptr: i32,
221 method_len: i32,
222 args_ptr: i32,
223 args_len: i32,
224 call_flags: i32,
225 out_ptr: i32,
226 out_cap: i32,
227 ) -> i32;
228
229 #[link_name = "neo_load_script"]
232 fn neo_load_script(
233 script_ptr: i32,
234 script_len: i32,
235 call_flags: i32,
236 args_ptr: i32,
237 args_len: i32,
238 ) -> i32;
239
240 #[link_name = "neo_call_native"]
243 fn neo_call_native(
244 native_id: i32,
245 method_ptr: i32,
246 method_len: i32,
247 args_ptr: i32,
248 args_len: i32,
249 out_ptr: i32,
250 out_cap: i32,
251 ) -> i32;
252}
253
254#[cfg(not(target_arch = "wasm32"))]
255const CALL_FLAGS_VALID_MASK: i32 = 0x0F;
256#[cfg(not(target_arch = "wasm32"))]
257const CALL_FLAGS_READ_STATES: i32 = 0x01;
258#[cfg(not(target_arch = "wasm32"))]
259const CALL_FLAGS_WRITE_STATES: i32 = 0x02;
260
261#[cfg(not(target_arch = "wasm32"))]
264fn find_syscall(name: &str) -> Option<&'static NeoVMSyscallInfo> {
265 SYSCALLS.iter().find(|info| info.name == name)
266}
267
268#[cfg(not(target_arch = "wasm32"))]
269fn syscall_hash(name: &str) -> NeoResult<u32> {
270 find_syscall(name)
271 .map(|info| info.hash)
272 .ok_or_else(|| NeoError::new(&format!("unknown syscall: {name}")))
273}
274
275fn default_value_for(return_type: &str) -> NeoValue {
276 match return_type {
277 "Void" => NeoValue::Null,
278 "Boolean" => NeoBoolean::FALSE.into(),
280 "Integer" => NeoInteger::new(0).into(),
281 "Hash160" => NeoByteString::new(vec![0u8; 20]).into(),
282 "ByteString" => NeoByteString::new(vec![0u8; 1]).into(),
283 "String" => NeoString::from_str("Neo N3").into(),
284 "Array" => NeoArray::<NeoValue>::new().into(),
285 "Iterator" => NeoArray::<NeoValue>::new().into(),
286 "StackItem" => NeoArray::<NeoValue>::new().into(),
287 "StorageContext" => NeoValue::Null,
288 _ => NeoValue::Null,
289 }
290}
291
292fn value_matches_param_type(value: &NeoValue, param_type: &str) -> bool {
293 match param_type {
294 "Boolean" => value.as_boolean().is_some(),
295 "Integer" => value.as_integer().is_some(),
296 "Hash160" => {
297 value.is_null()
298 || value
299 .as_byte_string()
300 .map(|bytes| bytes.len() == 20)
301 .unwrap_or(false)
302 }
303 "ByteString" => value.as_byte_string().is_some(),
304 "String" => value.as_string().is_some(),
305 "Array" => value.as_array().is_some(),
306 "Iterator" => value.as_array().is_some(),
307 "StorageContext" => value.is_null() || value.as_integer().is_some(),
308 "StackItem" | "Any" | "ExecutionContext" => true,
309 _ => true,
310 }
311}
312
313#[cfg(not(target_arch = "wasm32"))]
314fn call_flags_allow_write(flags: i32) -> bool {
315 (flags & CALL_FLAGS_WRITE_STATES) != 0
316}
317
318#[cfg(not(target_arch = "wasm32"))]
319fn call_flags_allow_read(flags: i32) -> bool {
320 (flags & CALL_FLAGS_READ_STATES) != 0
321}
322
323#[cfg(not(target_arch = "wasm32"))]
324fn hash160_prefix_i64(hash: &[u8; 20]) -> i64 {
325 let mut buf = [0u8; 8];
326 buf.copy_from_slice(&hash[..8]);
327 i64::from_le_bytes(buf)
328}
329
330pub fn neovm_syscall(hash: u32, args: &[NeoValue]) -> NeoResult<NeoValue> {
332 let registry = crate::NeoVMSyscallRegistry::get_instance();
333 let info = registry
334 .get_syscall_by_hash(hash)
335 .ok_or_else(|| NeoError::new(&format!("unknown syscall hash: 0x{hash:08x}")))?;
336
337 if args.len() != info.parameters.len() {
338 return Err(NeoError::new(&format!(
339 "invalid syscall argument count for {}: expected {}, got {}",
340 info.name,
341 info.parameters.len(),
342 args.len()
343 )));
344 }
345
346 for (index, (arg, expected_type)) in args.iter().zip(info.parameters.iter()).enumerate() {
347 if !value_matches_param_type(arg, expected_type) {
348 return Err(NeoError::new(&format!(
349 "invalid syscall argument type for {} param #{}: expected {}",
350 info.name, index, expected_type
351 )));
352 }
353 }
354
355 #[cfg(not(target_arch = "wasm32"))]
356 {
357 if info.name == "System.Runtime.CheckWitness" {
358 let has_witness = args
359 .first()
360 .and_then(NeoValue::as_byte_string)
361 .map(|account| has_active_witness(account.as_slice()))
362 .unwrap_or(false);
363 return Ok(NeoBoolean::new(has_witness).into());
364 }
365
366 if info.name == "System.Crypto.CheckSig" {
367 let results = active_crypto_verification_results();
368 return Ok(NeoBoolean::new(results.check_sig).into());
369 }
370
371 if info.name == "System.Crypto.CheckMultisig" {
372 let results = active_crypto_verification_results();
373 return Ok(NeoBoolean::new(results.check_multisig).into());
374 }
375
376 if info.name == "Neo.Crypto.VerifyWithECDsa" {
377 let results = active_crypto_verification_results();
378 return Ok(NeoBoolean::new(results.verify_with_ecdsa).into());
379 }
380
381 if info.name == "System.Runtime.GetCallingScriptHash" {
382 return Ok(NeoByteString::from_slice(¤t_calling_script_hash()).into());
383 }
384
385 if info.name == "System.Runtime.GetEntryScriptHash" {
386 return Ok(NeoByteString::from_slice(¤t_entry_script_hash()).into());
387 }
388
389 if info.name == "System.Runtime.GetExecutingScriptHash" {
390 return Ok(NeoByteString::from_slice(¤t_executing_script_hash()).into());
391 }
392
393 if info.name == "System.Contract.GetCallFlags" {
394 return Ok(NeoInteger::new(current_call_flags()).into());
395 }
396
397 if info.name == "System.Runtime.GetRandom" {
399 return Ok(NeoInteger::new(
400 *crate::storage::ACTIVE_RANDOM
401 .read()
402 .expect("ACTIVE_RANDOM poisoned"),
403 )
404 .into());
405 }
406
407 if info.name == "System.Runtime.GetTime" {
409 return Ok(NeoInteger::new(
410 *crate::storage::ACTIVE_TIME
411 .read()
412 .expect("ACTIVE_TIME poisoned"),
413 )
414 .into());
415 }
416
417 if info.name == "System.Runtime.GetInvocationCounter" {
419 return Ok(NeoInteger::new(
420 *crate::storage::ACTIVE_INVOCATION_COUNTER
421 .read()
422 .expect("ACTIVE_INVOCATION_COUNTER poisoned"),
423 )
424 .into());
425 }
426
427 if info.name == "System.Runtime.GasLeft" {
429 return Ok(NeoInteger::new(
430 *crate::storage::ACTIVE_GAS_LEFT
431 .read()
432 .expect("ACTIVE_GAS_LEFT poisoned"),
433 )
434 .into());
435 }
436
437 if info.name == "System.Runtime.CurrentSigners" {
440 let witnesses = crate::storage::ACTIVE_WITNESSES
441 .read()
442 .expect("ACTIVE_WITNESSES poisoned");
443 let arr: NeoArray<NeoValue> = witnesses
444 .iter()
445 .map(|w| {
446 let entry: NeoArray<NeoValue> = vec![
447 NeoValue::from(NeoByteString::from_slice(w)),
448 NeoValue::from(NeoInteger::new(0x01)), ]
450 .into_iter()
451 .collect();
452 NeoValue::from(entry)
453 })
454 .collect();
455 return Ok(NeoValue::from(arr));
456 }
457
458 if info.name == "System.Runtime.GetNotifications" {
462 use crate::host_notifications::take;
463 let recorded = take();
464 let arr: NeoArray<NeoValue> = recorded
465 .into_iter()
466 .map(|n| {
467 let entry: NeoArray<NeoValue> = vec![
468 NeoValue::from(NeoString::from_str(&n.event)),
469 NeoValue::from(n.state.into_iter().collect::<NeoArray<NeoValue>>()),
470 ]
471 .into_iter()
472 .collect();
473 NeoValue::from(entry)
474 })
475 .collect();
476 return Ok(NeoValue::from(arr));
477 }
478 }
479
480 Ok(default_value_for(info.return_type))
481}
482
483pub struct NeoVMSyscall;
485
486impl NeoVMSyscall {
487 #[cfg(not(target_arch = "wasm32"))]
488 fn parse_hash160(hash: &NeoByteString) -> NeoResult<[u8; 20]> {
489 if hash.len() != 20 {
490 return Err(NeoError::InvalidArgument);
491 }
492 let mut value = [0u8; 20];
493 value.copy_from_slice(hash.as_slice());
494 Ok(value)
495 }
496
497 #[cfg(target_arch = "wasm32")]
505 fn read_script_hash_extern(
506 read: unsafe extern "C" fn(out_ptr: i32, out_cap: i32) -> i32,
507 ) -> NeoResult<NeoByteString> {
508 let mut buf = [0u8; 20];
509 let written = unsafe { (read)(buf.as_mut_ptr() as i32, buf.len() as i32) };
510 if written < 0 {
511 return Err(NeoError::InvalidState);
512 }
513 let len = (written as usize).min(buf.len());
516 Ok(NeoByteString::from_slice(&buf[..len]))
517 }
518
519 #[cfg(not(target_arch = "wasm32"))]
520 fn parse_call_flags(flags: &NeoInteger) -> NeoResult<i32> {
521 let parsed = flags.as_i32_saturating();
522 if parsed < 0 || (parsed & !CALL_FLAGS_VALID_MASK) != 0 {
523 return Err(NeoError::InvalidArgument);
524 }
525 Ok(parsed)
526 }
527
528 #[cfg(not(target_arch = "wasm32"))]
529 fn begin_contract_invocation_with_flags(
530 next_executing: &NeoByteString,
531 call_flags: i32,
532 ) -> NeoResult<()> {
533 if call_flags < 0 || (call_flags & !CALL_FLAGS_VALID_MASK) != 0 {
534 return Err(NeoError::InvalidArgument);
535 }
536 push_current_executing_script_hash(Self::parse_hash160(next_executing)?, call_flags)
537 }
538
539 #[cfg(not(target_arch = "wasm32"))]
541 pub fn set_active_contract_hash(hash: &NeoByteString) -> NeoResult<()> {
542 set_current_contract_hash(Self::parse_hash160(hash)?);
543 Ok(())
544 }
545
546 #[cfg(not(target_arch = "wasm32"))]
548 pub fn set_active_script_hashes(
549 calling: &NeoByteString,
550 entry: &NeoByteString,
551 executing: &NeoByteString,
552 ) -> NeoResult<()> {
553 set_current_script_hashes(
554 Self::parse_hash160(calling)?,
555 Self::parse_hash160(entry)?,
556 Self::parse_hash160(executing)?,
557 );
558 Ok(())
559 }
560
561 #[cfg(not(target_arch = "wasm32"))]
564 pub fn set_active_calling_script_hash(hash: &NeoByteString) -> NeoResult<()> {
565 set_current_calling_script_hash(Self::parse_hash160(hash)?);
566 Ok(())
567 }
568
569 #[cfg(not(target_arch = "wasm32"))]
572 pub fn set_active_entry_script_hash(hash: &NeoByteString) -> NeoResult<()> {
573 set_current_entry_script_hash(Self::parse_hash160(hash)?);
574 Ok(())
575 }
576
577 #[cfg(not(target_arch = "wasm32"))]
580 pub fn set_active_executing_script_hash(hash: &NeoByteString) -> NeoResult<()> {
581 set_current_executing_script_hash(Self::parse_hash160(hash)?);
582 Ok(())
583 }
584
585 #[cfg(not(target_arch = "wasm32"))]
588 pub fn set_active_call_flags(call_flags: &NeoInteger) -> NeoResult<()> {
589 set_current_call_flags(Self::parse_call_flags(call_flags)?);
590 Ok(())
591 }
592
593 #[cfg(not(target_arch = "wasm32"))]
598 pub fn begin_contract_invocation(next_executing: &NeoByteString) -> NeoResult<()> {
599 Self::begin_contract_invocation_with_flags(next_executing, current_call_flags())
600 }
601
602 #[cfg(not(target_arch = "wasm32"))]
604 pub fn end_contract_invocation() -> NeoResult<()> {
605 pop_current_script_hash_frame()
606 }
607
608 #[cfg(not(target_arch = "wasm32"))]
610 pub fn with_contract_invocation<T, F>(
611 next_executing: &NeoByteString,
612 operation: F,
613 ) -> NeoResult<T>
614 where
615 F: FnOnce() -> NeoResult<T>,
616 {
617 Self::begin_contract_invocation(next_executing)?;
618 let operation_result = operation();
619 let unwind_result = Self::end_contract_invocation();
620
621 match (operation_result, unwind_result) {
622 (Ok(value), Ok(())) => Ok(value),
623 (Err(err), Ok(())) => Err(err),
624 (Ok(_), Err(unwind_err)) => Err(unwind_err),
625 (Err(operation_err), Err(unwind_err)) => Err(NeoError::new(&format!(
626 "invocation operation failed ({}) and frame unwind failed ({})",
627 operation_err.message(),
628 unwind_err.message()
629 ))),
630 }
631 }
632
633 #[cfg(target_arch = "wasm32")]
635 pub fn set_active_contract_hash(_hash: &NeoByteString) -> NeoResult<()> {
636 Ok(())
637 }
638
639 #[cfg(target_arch = "wasm32")]
641 pub fn set_active_script_hashes(
642 _calling: &NeoByteString,
643 _entry: &NeoByteString,
644 _executing: &NeoByteString,
645 ) -> NeoResult<()> {
646 Ok(())
647 }
648
649 #[cfg(target_arch = "wasm32")]
651 pub fn set_active_calling_script_hash(_hash: &NeoByteString) -> NeoResult<()> {
652 Ok(())
653 }
654
655 #[cfg(target_arch = "wasm32")]
657 pub fn set_active_entry_script_hash(_hash: &NeoByteString) -> NeoResult<()> {
658 Ok(())
659 }
660
661 #[cfg(target_arch = "wasm32")]
663 pub fn set_active_executing_script_hash(_hash: &NeoByteString) -> NeoResult<()> {
664 Ok(())
665 }
666
667 #[cfg(target_arch = "wasm32")]
669 pub fn set_active_call_flags(_call_flags: &NeoInteger) -> NeoResult<()> {
670 Ok(())
671 }
672
673 #[cfg(target_arch = "wasm32")]
675 pub fn begin_contract_invocation(_next_executing: &NeoByteString) -> NeoResult<()> {
676 Ok(())
677 }
678
679 #[cfg(target_arch = "wasm32")]
681 pub fn end_contract_invocation() -> NeoResult<()> {
682 Ok(())
683 }
684
685 #[cfg(target_arch = "wasm32")]
687 pub fn with_contract_invocation<T, F>(
688 _next_executing: &NeoByteString,
689 operation: F,
690 ) -> NeoResult<T>
691 where
692 F: FnOnce() -> NeoResult<T>,
693 {
694 operation()
695 }
696
697 #[cfg(not(target_arch = "wasm32"))]
699 pub fn reset_host_state() -> NeoResult<()> {
700 STORAGE_STATE.reset()?;
701 reset_current_contract_hash();
702 clear_active_witnesses();
703 reset_crypto_verification_results();
704 *crate::storage::ACTIVE_RANDOM
706 .write()
707 .expect("ACTIVE_RANDOM poisoned") = 0;
708 *crate::storage::ACTIVE_TIME
709 .write()
710 .expect("ACTIVE_TIME poisoned") = 0;
711 *crate::storage::ACTIVE_GAS_LEFT
712 .write()
713 .expect("ACTIVE_GAS_LEFT poisoned") = 0;
714 *crate::storage::ACTIVE_INVOCATION_COUNTER
715 .write()
716 .expect("ACTIVE_INVOCATION_COUNTER poisoned") = 0;
717 crate::host_notifications::reset();
720 Ok(())
721 }
722
723 #[cfg(target_arch = "wasm32")]
729 pub fn reset_host_state() -> NeoResult<()> {
730 Ok(())
731 }
732
733 #[cfg(not(target_arch = "wasm32"))]
740 pub fn seed_storage(entries: &[(&[u8], &[u8])]) -> NeoResult<()> {
741 for (k, v) in entries {
742 STORAGE_STATE.put(k.to_vec(), v.to_vec());
743 }
744 Ok(())
745 }
746 #[cfg(target_arch = "wasm32")]
747 pub fn seed_storage(_entries: &[(&[u8], &[u8])]) -> NeoResult<()> {
748 Ok(())
749 }
750
751 #[cfg(not(target_arch = "wasm32"))]
755 fn call_value(name: &str, args: &[NeoValue]) -> NeoResult<NeoValue> {
756 neovm_syscall(syscall_hash(name)?, args)
757 }
758
759 #[cfg(not(target_arch = "wasm32"))]
760 fn call_integer(name: &str) -> NeoResult<NeoInteger> {
761 let value = Self::call_value(name, &[])?;
762 value.as_integer().cloned().ok_or(NeoError::InvalidType)
763 }
764
765 #[cfg(not(target_arch = "wasm32"))]
766 fn call_boolean(name: &str, args: &[NeoValue]) -> NeoResult<NeoBoolean> {
767 let value = Self::call_value(name, args)?;
768 value.as_boolean().ok_or(NeoError::InvalidType)
769 }
770
771 #[cfg(not(target_arch = "wasm32"))]
772 fn call_bytes_with_args(name: &str, args: &[NeoValue]) -> NeoResult<NeoByteString> {
773 let value = Self::call_value(name, args)?;
774 value.as_byte_string().cloned().ok_or(NeoError::InvalidType)
775 }
776
777 #[cfg(not(target_arch = "wasm32"))]
778 fn call_string(name: &str) -> NeoResult<NeoString> {
779 let value = Self::call_value(name, &[])?;
780 value.as_string().cloned().ok_or(NeoError::InvalidType)
781 }
782
783 #[cfg(not(target_arch = "wasm32"))]
784 fn call_array(name: &str, args: &[NeoValue]) -> NeoResult<NeoArray<NeoValue>> {
785 let value = Self::call_value(name, args)?;
786 value.as_array().cloned().ok_or(NeoError::InvalidType)
787 }
788
789 #[cfg(not(target_arch = "wasm32"))]
791 pub fn set_active_witnesses(witnesses: &[NeoByteString]) -> NeoResult<()> {
792 crate::storage::set_active_witnesses(
793 witnesses.iter().map(|witness| witness.as_slice().to_vec()),
794 );
795 Ok(())
796 }
797
798 #[cfg(target_arch = "wasm32")]
800 pub fn set_active_witnesses(_witnesses: &[NeoByteString]) -> NeoResult<()> {
801 Ok(())
802 }
803
804 #[cfg(not(target_arch = "wasm32"))]
808 pub fn set_active_random(value: i64) -> NeoResult<()> {
809 *crate::storage::ACTIVE_RANDOM
810 .write()
811 .expect("ACTIVE_RANDOM poisoned") = value;
812 Ok(())
813 }
814 #[cfg(target_arch = "wasm32")]
815 pub fn set_active_random(_value: i64) -> NeoResult<()> {
816 Ok(())
817 }
818
819 #[cfg(not(target_arch = "wasm32"))]
822 pub fn set_active_time(value: i64) -> NeoResult<()> {
823 *crate::storage::ACTIVE_TIME
824 .write()
825 .expect("ACTIVE_TIME poisoned") = value;
826 Ok(())
827 }
828 #[cfg(target_arch = "wasm32")]
829 pub fn set_active_time(_value: i64) -> NeoResult<()> {
830 Ok(())
831 }
832
833 #[cfg(not(target_arch = "wasm32"))]
837 pub fn set_active_invocation_counter(value: i32) -> NeoResult<()> {
838 *crate::storage::ACTIVE_INVOCATION_COUNTER
839 .write()
840 .expect("ACTIVE_INVOCATION_COUNTER poisoned") = value;
841 Ok(())
842 }
843 #[cfg(target_arch = "wasm32")]
844 pub fn set_active_invocation_counter(_value: i32) -> NeoResult<()> {
845 Ok(())
846 }
847
848 #[cfg(not(target_arch = "wasm32"))]
851 pub fn set_active_gas_left(value: i64) -> NeoResult<()> {
852 *crate::storage::ACTIVE_GAS_LEFT
853 .write()
854 .expect("ACTIVE_GAS_LEFT poisoned") = value;
855 Ok(())
856 }
857 #[cfg(target_arch = "wasm32")]
858 pub fn set_active_gas_left(_value: i64) -> NeoResult<()> {
859 Ok(())
860 }
861
862 #[cfg(not(target_arch = "wasm32"))]
866 pub fn set_crypto_verification_results(check_sig: bool, check_multisig: bool) -> NeoResult<()> {
867 Self::set_crypto_verification_results_full(check_sig, check_multisig, check_sig)
868 }
869
870 #[cfg(not(target_arch = "wasm32"))]
872 pub fn set_crypto_verification_results_full(
873 check_sig: bool,
874 check_multisig: bool,
875 verify_with_ecdsa: bool,
876 ) -> NeoResult<()> {
877 crate::storage::set_crypto_verification_results(CryptoVerificationResults {
878 check_sig,
879 check_multisig,
880 verify_with_ecdsa,
881 });
882 Ok(())
883 }
884
885 #[cfg(not(target_arch = "wasm32"))]
887 pub fn set_verify_with_ecdsa_result(result: bool) -> NeoResult<()> {
888 let mut current = active_crypto_verification_results();
889 current.verify_with_ecdsa = result;
890 crate::storage::set_crypto_verification_results(current);
891 Ok(())
892 }
893
894 #[cfg(target_arch = "wasm32")]
896 pub fn set_crypto_verification_results(
897 _check_sig: bool,
898 _check_multisig: bool,
899 ) -> NeoResult<()> {
900 Ok(())
901 }
902
903 #[cfg(target_arch = "wasm32")]
905 pub fn set_crypto_verification_results_full(
906 _check_sig: bool,
907 _check_multisig: bool,
908 _verify_with_ecdsa: bool,
909 ) -> NeoResult<()> {
910 Ok(())
911 }
912
913 #[cfg(target_arch = "wasm32")]
915 pub fn set_verify_with_ecdsa_result(_result: bool) -> NeoResult<()> {
916 Ok(())
917 }
918
919 pub fn get_time() -> NeoResult<NeoInteger> {
921 #[cfg(target_arch = "wasm32")]
922 {
923 return Ok(NeoInteger::new(unsafe { neo_runtime_get_time() }));
924 }
925
926 #[cfg(not(target_arch = "wasm32"))]
927 {
928 Self::call_integer("System.Runtime.GetTime")
929 }
930 }
931
932 pub fn get_time_i64() -> NeoResult<i64> {
938 #[cfg(target_arch = "wasm32")]
939 {
940 return Ok(unsafe { neo_runtime_get_time() });
941 }
942
943 #[cfg(not(target_arch = "wasm32"))]
944 {
945 Self::call_integer("System.Runtime.GetTime")?.try_into_i64()
946 }
947 }
948
949 pub fn check_witness(account: &NeoByteString) -> NeoResult<NeoBoolean> {
951 Self::check_witness_bytes(account.as_slice())
952 }
953
954 pub fn check_witness_bytes(account: &[u8]) -> NeoResult<NeoBoolean> {
956 #[cfg(target_arch = "wasm32")]
957 {
958 let result = unsafe {
959 neo_runtime_check_witness_bytes(account.as_ptr() as i32, account.len() as i32)
960 };
961 return Ok(NeoBoolean::new(result != 0));
962 }
963
964 #[cfg(not(target_arch = "wasm32"))]
965 {
966 let args = [NeoValue::from(NeoByteString::from_slice(account))];
967 Self::call_boolean("System.Runtime.CheckWitness", &args)
968 }
969 }
970
971 pub fn check_witness_i64(account: i64) -> NeoResult<NeoBoolean> {
977 #[cfg(target_arch = "wasm32")]
978 {
979 let result = unsafe { neo_runtime_check_witness_i64(account) };
980 return Ok(NeoBoolean::new(result != 0));
981 }
982
983 #[cfg(not(target_arch = "wasm32"))]
984 {
985 let mut bytes = [0u8; 20];
986 bytes[..8].copy_from_slice(&account.to_le_bytes());
987 Self::check_witness_bytes(&bytes)
988 }
989 }
990
991 pub fn notify(event: &NeoString, state: &NeoArray<NeoValue>) -> NeoResult<()> {
993 #[cfg(target_arch = "wasm32")]
994 {
995 let state_bytes = serialise_array(state);
1000 unsafe {
1001 neo_runtime_notify_with_state(
1002 event.as_str().as_ptr() as i32,
1003 event.as_str().len() as i32,
1004 state_bytes.as_ptr() as i32,
1005 state_bytes.len() as i32,
1006 );
1007 }
1008 crate::host_notifications::record(event, state);
1011 return Ok(());
1012 }
1013
1014 #[cfg(not(target_arch = "wasm32"))]
1015 {
1016 let event_bytes = NeoByteString::from_slice(event.as_str().as_bytes());
1017 let args = [NeoValue::from(event_bytes), NeoValue::from(state.clone())];
1018 neovm_syscall(syscall_hash("System.Runtime.Notify")?, &args)?;
1019 crate::host_notifications::record(event, state);
1020 Ok(())
1021 }
1022 }
1023
1024 pub fn notify_event(event: &str) -> NeoResult<()> {
1026 #[cfg(target_arch = "wasm32")]
1027 unsafe {
1028 neo_runtime_notify(event.as_ptr() as i32, event.len() as i32);
1029 Ok(())
1030 }
1031
1032 #[cfg(not(target_arch = "wasm32"))]
1033 {
1034 let label = NeoString::from_str(event);
1035 let state = NeoArray::new();
1036 Self::notify(&label, &state)
1037 }
1038 }
1039
1040 pub fn log(message: &NeoString) -> NeoResult<()> {
1042 #[cfg(target_arch = "wasm32")]
1043 unsafe {
1044 let message = message.as_str();
1045 neo_runtime_log(message.as_ptr() as i32, message.len() as i32);
1046 Ok(())
1047 }
1048
1049 #[cfg(not(target_arch = "wasm32"))]
1050 {
1051 let message_bytes = NeoByteString::from_slice(message.as_str().as_bytes());
1052 let args = [NeoValue::from(message_bytes)];
1053 neovm_syscall(syscall_hash("System.Runtime.Log")?, &args)?;
1054 Ok(())
1055 }
1056 }
1057
1058 pub fn platform() -> NeoResult<NeoString> {
1060 #[cfg(target_arch = "wasm32")]
1062 {
1063 return Ok(NeoString::from_str("NEO"));
1064 }
1065 #[cfg(not(target_arch = "wasm32"))]
1066 Self::call_string("System.Runtime.Platform")
1067 }
1068
1069 pub fn get_trigger() -> NeoResult<NeoInteger> {
1070 #[cfg(target_arch = "wasm32")]
1071 {
1072 return Ok(NeoInteger::new(unsafe { neo_protocol_get_trigger() }));
1073 }
1074 #[cfg(not(target_arch = "wasm32"))]
1075 Self::call_integer("System.Runtime.GetTrigger")
1076 }
1077
1078 pub fn get_invocation_counter() -> NeoResult<NeoInteger> {
1079 #[cfg(target_arch = "wasm32")]
1080 {
1081 return Ok(NeoInteger::new(unsafe {
1082 neo_runtime_get_invocation_counter()
1083 }));
1084 }
1085 #[cfg(not(target_arch = "wasm32"))]
1086 Self::call_integer("System.Runtime.GetInvocationCounter")
1087 }
1088
1089 pub fn get_random() -> NeoResult<NeoInteger> {
1090 #[cfg(target_arch = "wasm32")]
1091 {
1092 return Ok(NeoInteger::new(unsafe { neo_runtime_get_random() }));
1093 }
1094 #[cfg(not(target_arch = "wasm32"))]
1095 Self::call_integer("System.Runtime.GetRandom")
1096 }
1097
1098 pub fn get_network() -> NeoResult<NeoInteger> {
1099 #[cfg(target_arch = "wasm32")]
1100 {
1101 return Ok(NeoInteger::new(unsafe { neo_protocol_get_network() }));
1102 }
1103 #[cfg(not(target_arch = "wasm32"))]
1104 Self::call_integer("System.Runtime.GetNetwork")
1105 }
1106
1107 pub fn get_address_version() -> NeoResult<NeoInteger> {
1108 #[cfg(target_arch = "wasm32")]
1109 {
1110 return Ok(NeoInteger::new(unsafe {
1111 neo_protocol_get_address_version()
1112 }));
1113 }
1114 #[cfg(not(target_arch = "wasm32"))]
1115 Self::call_integer("System.Runtime.GetAddressVersion")
1116 }
1117
1118 pub fn get_gas_left() -> NeoResult<NeoInteger> {
1119 #[cfg(target_arch = "wasm32")]
1120 {
1121 return Ok(NeoInteger::new(unsafe { neo_runtime_get_gas_left() }));
1122 }
1123 #[cfg(not(target_arch = "wasm32"))]
1124 Self::call_integer("System.Runtime.GasLeft")
1125 }
1126
1127 #[cfg(not(target_arch = "wasm32"))]
1128 pub fn get_calling_script_hash() -> NeoResult<NeoByteString> {
1129 Ok(NeoByteString::from_slice(¤t_calling_script_hash()))
1130 }
1131
1132 #[cfg(target_arch = "wasm32")]
1133 pub fn get_calling_script_hash() -> NeoResult<NeoByteString> {
1134 Self::read_script_hash_extern(neo_runtime_get_calling_script_hash)
1135 }
1136
1137 #[cfg(not(target_arch = "wasm32"))]
1138 pub fn get_calling_script_hash_i64() -> NeoResult<i64> {
1139 Ok(hash160_prefix_i64(¤t_calling_script_hash()))
1140 }
1141
1142 #[cfg(target_arch = "wasm32")]
1143 pub fn get_calling_script_hash_i64() -> NeoResult<i64> {
1144 Ok(unsafe { neo_runtime_get_calling_script_hash_i64() })
1145 }
1146
1147 #[cfg(not(target_arch = "wasm32"))]
1148 pub fn get_entry_script_hash() -> NeoResult<NeoByteString> {
1149 Ok(NeoByteString::from_slice(¤t_entry_script_hash()))
1150 }
1151
1152 #[cfg(target_arch = "wasm32")]
1153 pub fn get_entry_script_hash() -> NeoResult<NeoByteString> {
1154 Self::read_script_hash_extern(neo_runtime_get_entry_script_hash)
1155 }
1156
1157 #[cfg(not(target_arch = "wasm32"))]
1158 pub fn get_entry_script_hash_i64() -> NeoResult<i64> {
1159 Ok(hash160_prefix_i64(¤t_entry_script_hash()))
1160 }
1161
1162 #[cfg(target_arch = "wasm32")]
1163 pub fn get_entry_script_hash_i64() -> NeoResult<i64> {
1164 Ok(unsafe { neo_runtime_get_entry_script_hash_i64() })
1165 }
1166
1167 #[cfg(not(target_arch = "wasm32"))]
1168 pub fn get_executing_script_hash() -> NeoResult<NeoByteString> {
1169 Ok(NeoByteString::from_slice(¤t_executing_script_hash()))
1170 }
1171
1172 #[cfg(target_arch = "wasm32")]
1173 pub fn get_executing_script_hash() -> NeoResult<NeoByteString> {
1174 Self::read_script_hash_extern(neo_runtime_get_executing_script_hash)
1175 }
1176
1177 #[cfg(not(target_arch = "wasm32"))]
1178 pub fn get_executing_script_hash_i64() -> NeoResult<i64> {
1179 Ok(hash160_prefix_i64(¤t_executing_script_hash()))
1180 }
1181
1182 #[cfg(target_arch = "wasm32")]
1183 pub fn get_executing_script_hash_i64() -> NeoResult<i64> {
1184 Ok(unsafe { neo_runtime_get_executing_script_hash_i64() })
1185 }
1186
1187 pub fn get_notifications(script_hash: Option<&NeoByteString>) -> NeoResult<NeoArray<NeoValue>> {
1189 #[cfg(target_arch = "wasm32")]
1190 {
1191 let mut buf = vec![0u8; 4096];
1195 let written = if let Some(hash) = script_hash {
1196 unsafe {
1197 neo_runtime_get_notifications(
1198 hash.as_slice().as_ptr() as i32,
1199 hash.len() as i32,
1200 buf.as_mut_ptr() as i32,
1201 buf.len() as i32,
1202 )
1203 }
1204 } else {
1205 unsafe {
1207 neo_runtime_get_notifications(
1208 std::ptr::null::<u8>() as i32,
1209 0,
1210 buf.as_mut_ptr() as i32,
1211 buf.len() as i32,
1212 )
1213 }
1214 };
1215 if written < 0 {
1216 return Err(NeoError::InvalidState);
1217 }
1218 let _ = (written as usize).min(buf.len());
1222 Ok(NeoArray::new())
1223 }
1224 #[cfg(not(target_arch = "wasm32"))]
1225 {
1226 let script_hash_value = script_hash
1227 .map(|hash| NeoValue::from(hash.clone()))
1228 .unwrap_or(NeoValue::Null);
1229 let args = [script_hash_value];
1230 Self::call_array("System.Runtime.GetNotifications", &args)
1231 }
1232 }
1233
1234 pub fn get_script_container() -> NeoResult<NeoArray<NeoValue>> {
1235 #[cfg(target_arch = "wasm32")]
1236 {
1237 let mut buf = vec![0u8; 4096];
1238 let written = unsafe {
1239 neo_runtime_get_script_container(buf.as_mut_ptr() as i32, buf.len() as i32)
1240 };
1241 if written < 0 {
1242 return Err(NeoError::InvalidState);
1243 }
1244 let _ = (written as usize).min(buf.len());
1245 Ok(NeoArray::new())
1246 }
1247 #[cfg(not(target_arch = "wasm32"))]
1248 Self::call_array("System.Runtime.GetScriptContainer", &[])
1249 }
1250
1251 pub fn burn_gas(gas: &NeoInteger) -> NeoResult<()> {
1253 #[cfg(target_arch = "wasm32")]
1254 {
1255 let datoshi = gas.as_i64_saturating();
1256 if datoshi <= 0 {
1257 return Err(NeoError::new("GAS must be positive"));
1258 }
1259 unsafe { neo_runtime_burn_gas(datoshi) };
1260 return Ok(());
1261 }
1262 #[cfg(not(target_arch = "wasm32"))]
1263 {
1264 let args = [NeoValue::from(gas.clone())];
1265 Self::call_value("System.Runtime.BurnGas", &args)?;
1266 Ok(())
1267 }
1268 }
1269
1270 pub fn current_signers() -> NeoResult<NeoArray<NeoValue>> {
1272 #[cfg(target_arch = "wasm32")]
1273 {
1274 let mut buf = vec![0u8; 4096];
1275 let written =
1276 unsafe { neo_runtime_current_signers(buf.as_mut_ptr() as i32, buf.len() as i32) };
1277 if written < 0 {
1278 return Err(NeoError::InvalidState);
1279 }
1280 let _ = (written as usize).min(buf.len());
1281 Ok(NeoArray::new())
1282 }
1283 #[cfg(not(target_arch = "wasm32"))]
1284 Self::call_array("System.Runtime.CurrentSigners", &[])
1285 }
1286
1287 pub fn load_script(
1289 script: &NeoByteString,
1290 call_flags: &NeoInteger,
1291 args: &NeoArray<NeoValue>,
1292 ) -> NeoResult<()> {
1293 #[cfg(not(target_arch = "wasm32"))]
1294 {
1295 let values = [
1296 NeoValue::from(script.clone()),
1297 NeoValue::from(call_flags.clone()),
1298 NeoValue::from(args.clone()),
1299 ];
1300 Self::call_value("System.Runtime.LoadScript", &values)?;
1301 Ok(())
1302 }
1303 #[cfg(target_arch = "wasm32")]
1304 {
1305 let _ = (call_flags, args);
1311 let script_bytes = script.as_slice();
1312 let status = unsafe {
1313 neo_load_script(
1314 script_bytes.as_ptr() as i32,
1315 script_bytes.len() as i32,
1316 0x0F,
1317 0,
1318 0,
1319 )
1320 };
1321 if status < 0 {
1322 return Err(NeoError::Wasm32CrossCallUnavailable {
1323 syscall: "System.Runtime.LoadScript",
1324 });
1325 }
1326 Ok(())
1327 }
1328 }
1329
1330 pub fn contract_call(
1332 script_hash: &NeoByteString,
1333 method: &NeoString,
1334 call_flags: &NeoInteger,
1335 args: &NeoArray<NeoValue>,
1336 ) -> NeoResult<NeoValue> {
1337 #[cfg(not(target_arch = "wasm32"))]
1338 {
1339 let values = [
1340 NeoValue::from(script_hash.clone()),
1341 NeoValue::from(method.clone()),
1342 NeoValue::from(call_flags.clone()),
1343 NeoValue::from(args.clone()),
1344 ];
1345 let parsed_flags = Self::parse_call_flags(call_flags)?;
1346 Self::begin_contract_invocation_with_flags(script_hash, parsed_flags)?;
1347 let call_result = Self::call_value("System.Contract.Call", &values);
1348 let unwind_result = Self::end_contract_invocation();
1349 match (call_result, unwind_result) {
1350 (Ok(value), Ok(())) => Ok(value),
1351 (Err(err), Ok(())) => Err(err),
1352 (Ok(_), Err(unwind_err)) => Err(unwind_err),
1353 (Err(call_err), Err(unwind_err)) => Err(NeoError::new(&format!(
1354 "contract_call failed ({}) and invocation unwind failed ({})",
1355 call_err.message(),
1356 unwind_err.message()
1357 ))),
1358 }
1359 }
1360
1361 #[cfg(target_arch = "wasm32")]
1362 {
1363 let _ = (call_flags, args);
1379 let hash_bytes = script_hash.as_slice();
1380 let method_bytes = method.as_str().as_bytes();
1381 let mut out_buf = [0u8; 16];
1382 let status = unsafe {
1383 neo_contract_call(
1384 hash_bytes.as_ptr() as i32,
1385 hash_bytes.len() as i32,
1386 method_bytes.as_ptr() as i32,
1387 method_bytes.len() as i32,
1388 0,
1389 0,
1390 0x0F,
1391 out_buf.as_mut_ptr() as i32,
1392 out_buf.len() as i32,
1393 )
1394 };
1395 let _ = status;
1396 Ok(NeoValue::Null)
1400 }
1401 }
1402
1403 pub fn contract_call_native(native_id: &NeoInteger) -> NeoResult<NeoValue> {
1405 #[cfg(not(target_arch = "wasm32"))]
1406 {
1407 let values = [NeoValue::from(native_id.clone())];
1408 Self::call_value("System.Contract.CallNative", &values)
1409 }
1410 #[cfg(target_arch = "wasm32")]
1411 {
1412 let mut out_buf = [0u8; 16];
1415 let status = unsafe {
1416 neo_call_native(
1417 native_id.try_as_i64().unwrap_or(0) as i32,
1418 0,
1419 0,
1420 0,
1421 0,
1422 out_buf.as_mut_ptr() as i32,
1423 out_buf.len() as i32,
1424 )
1425 };
1426 if status < 0 {
1427 return Err(NeoError::Wasm32CrossCallUnavailable {
1428 syscall: "System.Contract.CallNative",
1429 });
1430 }
1431 Ok(NeoValue::Null)
1432 }
1433 }
1434
1435 pub fn get_call_flags() -> NeoResult<NeoInteger> {
1436 #[cfg(not(target_arch = "wasm32"))]
1437 {
1438 Ok(NeoInteger::new(current_call_flags()))
1439 }
1440
1441 #[cfg(target_arch = "wasm32")]
1442 {
1443 Ok(NeoInteger::new(unsafe { neo_runtime_get_call_flags() }))
1444 }
1445 }
1446
1447 pub fn create_standard_account(pubkey: &NeoByteString) -> NeoResult<NeoByteString> {
1448 #[cfg(not(target_arch = "wasm32"))]
1449 {
1450 let values = [NeoValue::from(pubkey.clone())];
1451 Self::call_bytes_with_args("System.Contract.CreateStandardAccount", &values)
1452 }
1453 #[cfg(target_arch = "wasm32")]
1454 {
1455 let mut buf = [0u8; 20];
1456 let written = unsafe {
1457 neo_runtime_create_standard_account(
1458 pubkey.as_slice().as_ptr() as i32,
1459 pubkey.len() as i32,
1460 buf.as_mut_ptr() as i32,
1461 buf.len() as i32,
1462 )
1463 };
1464 if written < 0 {
1465 return Err(NeoError::InvalidState);
1466 }
1467 let len = (written as usize).min(buf.len());
1468 Ok(NeoByteString::from_slice(&buf[..len]))
1469 }
1470 }
1471
1472 pub fn create_multisig_account(
1473 threshold: &NeoInteger,
1474 public_keys: &NeoArray<NeoValue>,
1475 ) -> NeoResult<NeoByteString> {
1476 let values = [
1477 NeoValue::from(threshold.clone()),
1478 NeoValue::from(public_keys.clone()),
1479 ];
1480 #[cfg(not(target_arch = "wasm32"))]
1481 {
1482 Self::call_bytes_with_args("System.Contract.CreateMultisigAccount", &values)
1483 }
1484 #[cfg(target_arch = "wasm32")]
1485 {
1486 let pk_bytes: Vec<u8> = public_keys
1489 .iter()
1490 .filter_map(|v| v.as_byte_string())
1491 .flat_map(|bs| bs.as_slice().to_vec())
1492 .collect();
1493 let mut buf = [0u8; 20];
1494 let written = unsafe {
1495 neo_runtime_create_multisig_account(
1496 threshold.as_i32_saturating(),
1497 pk_bytes.as_ptr() as i32,
1498 pk_bytes.len() as i32,
1499 buf.as_mut_ptr() as i32,
1500 buf.len() as i32,
1501 )
1502 };
1503 let _ = values;
1504 if written < 0 {
1505 return Err(NeoError::InvalidState);
1506 }
1507 let len = (written as usize).min(buf.len());
1508 Ok(NeoByteString::from_slice(&buf[..len]))
1509 }
1510 }
1511
1512 pub fn native_on_persist() -> NeoResult<()> {
1513 #[cfg(not(target_arch = "wasm32"))]
1514 {
1515 Self::call_value("System.Contract.NativeOnPersist", &[])?;
1516 Ok(())
1517 }
1518 #[cfg(target_arch = "wasm32")]
1519 {
1520 Err(NeoError::new(
1525 "System.Contract.NativeOnPersist is only valid inside native contracts",
1526 ))
1527 }
1528 }
1529
1530 pub fn native_post_persist() -> NeoResult<()> {
1531 #[cfg(not(target_arch = "wasm32"))]
1532 {
1533 Self::call_value("System.Contract.NativePostPersist", &[])?;
1534 Ok(())
1535 }
1536 #[cfg(target_arch = "wasm32")]
1537 {
1538 Err(NeoError::new(
1539 "System.Contract.NativePostPersist is only valid inside native contracts",
1540 ))
1541 }
1542 }
1543
1544 pub fn check_sig(pubkey: &NeoByteString, signature: &NeoByteString) -> NeoResult<NeoBoolean> {
1545 #[cfg(target_arch = "wasm32")]
1546 {
1547 let result = unsafe {
1549 neo_runtime_check_sig(
1550 pubkey.as_slice().as_ptr() as i32,
1551 pubkey.len() as i32,
1552 signature.as_slice().as_ptr() as i32,
1553 signature.len() as i32,
1554 )
1555 };
1556 return Ok(NeoBoolean::new(result != 0));
1557 }
1558 #[cfg(not(target_arch = "wasm32"))]
1559 {
1560 let values = [
1561 NeoValue::from(pubkey.clone()),
1562 NeoValue::from(signature.clone()),
1563 ];
1564 Self::call_boolean("System.Crypto.CheckSig", &values)
1565 }
1566 }
1567
1568 pub fn check_multisig(
1569 pubkeys: &NeoArray<NeoValue>,
1570 signatures: &NeoArray<NeoValue>,
1571 ) -> NeoResult<NeoBoolean> {
1572 #[cfg(target_arch = "wasm32")]
1573 {
1574 let mut pk = Vec::new();
1579 for v in pubkeys.iter() {
1580 let Some(b) = v.as_byte_string() else {
1581 return Err(NeoError::InvalidType);
1582 };
1583 pk.extend_from_slice(b.as_slice());
1584 }
1585 let mut sg = Vec::new();
1586 for v in signatures.iter() {
1587 let Some(b) = v.as_byte_string() else {
1588 return Err(NeoError::InvalidType);
1589 };
1590 sg.extend_from_slice(b.as_slice());
1591 }
1592 let result = unsafe {
1594 neo_runtime_check_multisig(
1595 pk.as_ptr() as i32,
1596 pk.len() as i32,
1597 sg.as_ptr() as i32,
1598 sg.len() as i32,
1599 )
1600 };
1601 Ok(NeoBoolean::new(result != 0))
1602 }
1603 #[cfg(not(target_arch = "wasm32"))]
1604 {
1605 let values = [
1606 NeoValue::from(pubkeys.clone()),
1607 NeoValue::from(signatures.clone()),
1608 ];
1609 Self::call_boolean("System.Crypto.CheckMultisig", &values)
1610 }
1611 }
1612
1613 pub fn verify_with_ecdsa(
1614 message: &NeoByteString,
1615 public_key: &NeoByteString,
1616 signature: &NeoByteString,
1617 curve: &NeoInteger,
1618 ) -> NeoResult<NeoBoolean> {
1619 #[cfg(target_arch = "wasm32")]
1620 {
1621 let curve_i = curve.try_as_i32().unwrap_or(0);
1622 let result = unsafe {
1624 neo_runtime_verify_with_ecdsa(
1625 message.as_slice().as_ptr() as i32,
1626 message.len() as i32,
1627 public_key.as_slice().as_ptr() as i32,
1628 public_key.len() as i32,
1629 signature.as_slice().as_ptr() as i32,
1630 signature.len() as i32,
1631 curve_i,
1632 )
1633 };
1634 return Ok(NeoBoolean::new(result != 0));
1635 }
1636 #[cfg(not(target_arch = "wasm32"))]
1637 {
1638 let values = [
1639 NeoValue::from(message.clone()),
1640 NeoValue::from(public_key.clone()),
1641 NeoValue::from(signature.clone()),
1642 NeoValue::from(curve.clone()),
1643 ];
1644 Self::call_boolean("Neo.Crypto.VerifyWithECDsa", &values)
1645 }
1646 }
1647
1648 pub fn iterator_next(items: &NeoArray<NeoValue>) -> NeoResult<NeoBoolean> {
1649 #[cfg(target_arch = "wasm32")]
1650 {
1651 let _ = items;
1660 Err(NeoError::Wasm32CrossCallUnavailable {
1661 syscall: "System.Iterator.Next",
1662 })
1663 }
1664 #[cfg(not(target_arch = "wasm32"))]
1665 {
1666 let values = [NeoValue::from(items.clone())];
1667 Self::call_boolean("System.Iterator.Next", &values)
1668 }
1669 }
1670
1671 pub fn iterator_value(items: &NeoArray<NeoValue>) -> NeoResult<NeoValue> {
1672 #[cfg(target_arch = "wasm32")]
1673 {
1674 let _ = items;
1675 Err(NeoError::Wasm32CrossCallUnavailable {
1676 syscall: "System.Iterator.Value",
1677 })
1678 }
1679 #[cfg(not(target_arch = "wasm32"))]
1680 {
1681 let values = [NeoValue::from(items.clone())];
1682 Self::call_value("System.Iterator.Value", &values)
1683 }
1684 }
1685
1686 #[cfg(not(target_arch = "wasm32"))]
1687 pub fn storage_get_context() -> NeoResult<NeoStorageContext> {
1688 let flags = current_call_flags();
1689 if !call_flags_allow_read(flags) {
1690 return Err(NeoError::InvalidOperation);
1691 }
1692 let read_only = !call_flags_allow_write(flags);
1693 STORAGE_STATE.create_context(current_executing_script_hash(), read_only)
1694 }
1695
1696 #[cfg(target_arch = "wasm32")]
1702 pub fn storage_get_context() -> NeoResult<NeoStorageContext> {
1703 Ok(NeoStorageContext::new(1))
1704 }
1705
1706 #[cfg(not(target_arch = "wasm32"))]
1707 pub fn storage_get_read_only_context() -> NeoResult<NeoStorageContext> {
1708 if !call_flags_allow_read(current_call_flags()) {
1709 return Err(NeoError::InvalidOperation);
1710 }
1711 STORAGE_STATE.create_context(current_executing_script_hash(), true)
1712 }
1713
1714 #[cfg(target_arch = "wasm32")]
1715 pub fn storage_get_read_only_context() -> NeoResult<NeoStorageContext> {
1716 Ok(NeoStorageContext::read_only(1))
1717 }
1718
1719 #[cfg(not(target_arch = "wasm32"))]
1720 pub fn storage_as_read_only(context: &NeoStorageContext) -> NeoResult<NeoStorageContext> {
1721 STORAGE_STATE.clone_as_read_only(context)
1722 }
1723
1724 #[cfg(target_arch = "wasm32")]
1725 pub fn storage_as_read_only(context: &NeoStorageContext) -> NeoResult<NeoStorageContext> {
1726 Ok(context.as_read_only())
1727 }
1728
1729 #[cfg(not(target_arch = "wasm32"))]
1730 pub fn storage_get(
1731 context: &NeoStorageContext,
1732 key: &NeoByteString,
1733 ) -> NeoResult<NeoByteString> {
1734 if !call_flags_allow_read(current_call_flags()) {
1735 return Err(NeoError::InvalidOperation);
1736 }
1737 let handle = STORAGE_STATE.get_handle(context)?;
1738 let store = handle.store.read().map_err(|_| NeoError::InvalidState)?;
1739 let value = store.get(key.as_slice()).cloned().unwrap_or_else(Vec::new);
1740 Ok(NeoByteString::new(value))
1741 }
1742
1743 #[cfg(not(target_arch = "wasm32"))]
1744 pub fn storage_try_get(
1745 context: &NeoStorageContext,
1746 key: &NeoByteString,
1747 ) -> NeoResult<Option<NeoByteString>> {
1748 if !call_flags_allow_read(current_call_flags()) {
1749 return Err(NeoError::InvalidOperation);
1750 }
1751 let handle = STORAGE_STATE.get_handle(context)?;
1752 let store = handle.store.read().map_err(|_| NeoError::InvalidState)?;
1753 Ok(store.get(key.as_slice()).cloned().map(NeoByteString::new))
1754 }
1755
1756 #[cfg(not(target_arch = "wasm32"))]
1757 pub fn storage_put(
1758 context: &NeoStorageContext,
1759 key: &NeoByteString,
1760 value: &NeoByteString,
1761 ) -> NeoResult<()> {
1762 if !call_flags_allow_write(current_call_flags()) {
1763 return Err(NeoError::InvalidOperation);
1764 }
1765 let handle = STORAGE_STATE.get_handle(context)?;
1766 if handle.read_only {
1767 return Err(NeoError::InvalidOperation);
1768 }
1769 let mut store = handle.store.write().map_err(|_| NeoError::InvalidState)?;
1770 store.insert(key.as_slice().to_vec(), value.as_slice().to_vec());
1771 Ok(())
1772 }
1773
1774 #[cfg(target_arch = "wasm32")]
1781 pub fn storage_put(
1782 context: &NeoStorageContext,
1783 key: &NeoByteString,
1784 value: &NeoByteString,
1785 ) -> NeoResult<()> {
1786 if context.is_read_only() {
1787 return Err(NeoError::InvalidOperation);
1788 }
1789
1790 let key_slice = key.as_slice();
1791 let value_slice = value.as_slice();
1792 unsafe {
1793 neo_storage_put_bytes(
1794 key_slice.as_ptr() as i32,
1795 key_slice.len() as i32,
1796 value_slice.as_ptr() as i32,
1797 value_slice.len() as i32,
1798 );
1799 }
1800 Ok(())
1801 }
1802
1803 #[cfg(target_arch = "wasm32")]
1809 pub fn storage_get(
1810 _context: &NeoStorageContext,
1811 key: &NeoByteString,
1812 ) -> NeoResult<NeoByteString> {
1813 const INITIAL_CAPACITY: usize = 64;
1814 const MAX_CAPACITY: usize = 64 * 1024;
1815
1816 let key_slice = key.as_slice();
1817 let mut buffer: Vec<u8> = vec![0u8; INITIAL_CAPACITY];
1818 loop {
1819 let actual = unsafe {
1820 neo_storage_get_into(
1821 key_slice.as_ptr() as i32,
1822 key_slice.len() as i32,
1823 buffer.as_mut_ptr() as i32,
1824 buffer.len() as i32,
1825 )
1826 };
1827 if actual == -1 {
1828 return Ok(NeoByteString::new(Vec::new()));
1829 }
1830 if actual >= 0 {
1831 let len = actual as usize;
1832 buffer.truncate(len);
1833 return Ok(NeoByteString::new(buffer));
1834 }
1835 let needed = (-actual) as usize;
1837 if needed > MAX_CAPACITY {
1838 return Err(NeoError::InvalidState);
1839 }
1840 buffer.resize(needed, 0);
1841 }
1842 }
1843
1844 #[cfg(not(target_arch = "wasm32"))]
1845 pub fn storage_delete(context: &NeoStorageContext, key: &NeoByteString) -> NeoResult<()> {
1846 if !call_flags_allow_write(current_call_flags()) {
1847 return Err(NeoError::InvalidOperation);
1848 }
1849 let handle = STORAGE_STATE.get_handle(context)?;
1850 if handle.read_only {
1851 return Err(NeoError::InvalidOperation);
1852 }
1853 let mut store = handle.store.write().map_err(|_| NeoError::InvalidState)?;
1854 store.remove(key.as_slice());
1855 Ok(())
1856 }
1857
1858 #[cfg(target_arch = "wasm32")]
1862 pub fn storage_delete(context: &NeoStorageContext, key: &NeoByteString) -> NeoResult<()> {
1863 if context.is_read_only() {
1864 return Err(NeoError::InvalidOperation);
1865 }
1866
1867 let key_slice = key.as_slice();
1868 unsafe {
1869 neo_storage_delete_bytes(key_slice.as_ptr() as i32, key_slice.len() as i32);
1870 }
1871 Ok(())
1872 }
1873
1874 #[cfg(not(target_arch = "wasm32"))]
1875 pub fn storage_find(
1876 context: &NeoStorageContext,
1877 prefix: &NeoByteString,
1878 ) -> NeoResult<NeoIterator<NeoValue>> {
1879 if !call_flags_allow_read(current_call_flags()) {
1880 return Err(NeoError::InvalidOperation);
1881 }
1882 let handle = STORAGE_STATE.get_handle(context)?;
1883 let prefix_bytes = prefix.as_slice();
1884 let store = handle.store.read().map_err(|_| NeoError::InvalidState)?;
1885 let matches: Vec<NeoValue> = store
1886 .iter()
1887 .filter_map(|(key_bytes, value)| {
1888 if key_bytes.starts_with(prefix_bytes) {
1889 let mut entry = NeoStruct::new();
1890 entry.set_field("key", NeoValue::from(NeoByteString::from_slice(key_bytes)));
1891 entry.set_field("value", NeoValue::from(NeoByteString::from_slice(value)));
1892 Some(NeoValue::from(entry))
1893 } else {
1894 None
1895 }
1896 })
1897 .collect();
1898 Ok(NeoIterator::new(matches))
1899 }
1900
1901 #[cfg(target_arch = "wasm32")]
1908 pub fn storage_find(
1909 _context: &NeoStorageContext,
1910 _prefix: &NeoByteString,
1911 ) -> NeoResult<NeoIterator<NeoValue>> {
1912 Ok(NeoIterator::new(Vec::new()))
1913 }
1914}