1use crate::{
21 exec::{ExecError, ExecResult, Ext, Key, TopicOf},
22 gas::{ChargedAmount, Token},
23 primitives::ExecReturnValue,
24 weights::WeightInfo,
25 BalanceOf, CodeHash, Config, DebugBufferVec, Error, SENTINEL,
26};
27use alloc::{boxed::Box, vec, vec::Vec};
28use codec::{Decode, DecodeLimit, Encode, MaxEncodedLen};
29use core::fmt;
30use frame_support::{
31 dispatch::DispatchInfo, ensure, pallet_prelude::DispatchResultWithPostInfo, parameter_types,
32 traits::Get, weights::Weight,
33};
34use pallet_contracts_proc_macro::define_env;
35use pallet_contracts_uapi::{CallFlags, ReturnFlags};
36use sp_io::hashing::{blake2_128, blake2_256, keccak_256, sha2_256};
37use sp_runtime::{
38 traits::{Bounded, Zero},
39 DispatchError, RuntimeDebug,
40};
41use wasmi::{core::HostError, errors::LinkerError, Linker, Memory, Store};
42
43type CallOf<T> = <T as frame_system::Config>::RuntimeCall;
44
45const MAX_DECODE_NESTING: u32 = 256;
47
48pub enum AllowDeprecatedInterface {
50 No,
52 Yes,
54}
55
56pub enum AllowUnstableInterface {
58 No,
60 Yes,
62}
63
64pub trait Environment<HostState> {
67 fn define(
70 store: &mut Store<HostState>,
71 linker: &mut Linker<HostState>,
72 allow_unstable: AllowUnstableInterface,
73 allow_deprecated: AllowDeprecatedInterface,
74 ) -> Result<(), LinkerError>;
75}
76
77enum KeyType {
79 Fix,
81 Var(u32),
84}
85
86pub use pallet_contracts_uapi::ReturnErrorCode;
87
88parameter_types! {
89 const CallRuntimeFailed: ReturnErrorCode = ReturnErrorCode::CallRuntimeFailed;
91 const XcmExecutionFailed: ReturnErrorCode = ReturnErrorCode::XcmExecutionFailed;
93}
94
95impl From<ExecReturnValue> for ReturnErrorCode {
96 fn from(from: ExecReturnValue) -> Self {
97 if from.flags.contains(ReturnFlags::REVERT) {
98 Self::CalleeReverted
99 } else {
100 Self::Success
101 }
102 }
103}
104
105#[derive(RuntimeDebug)]
107pub struct ReturnData {
108 flags: u32,
111 data: Vec<u8>,
113}
114
115#[derive(RuntimeDebug)]
122pub enum TrapReason {
123 SupervisorError(DispatchError),
126 Return(ReturnData),
128 Termination,
131}
132
133impl<T: Into<DispatchError>> From<T> for TrapReason {
134 fn from(from: T) -> Self {
135 Self::SupervisorError(from.into())
136 }
137}
138
139impl fmt::Display for TrapReason {
140 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
141 Ok(())
142 }
143}
144
145impl HostError for TrapReason {}
146
147#[cfg_attr(test, derive(Debug, PartialEq, Eq))]
148#[derive(Copy, Clone)]
149pub enum RuntimeCosts {
150 HostFn,
152 CopyFromContract(u32),
154 CopyToContract(u32),
156 Caller,
158 IsContract,
160 CodeHash,
162 OwnCodeHash,
164 CallerIsOrigin,
166 CallerIsRoot,
168 Address,
170 GasLeft,
172 Balance,
174 ValueTransferred,
176 MinimumBalance,
178 BlockNumber,
180 Now,
182 WeightToFee,
184 Terminate(u32),
186 Random,
188 DepositEvent { num_topic: u32, len: u32 },
190 DebugMessage(u32),
192 SetStorage { old_bytes: u32, new_bytes: u32 },
194 ClearStorage(u32),
196 ContainsStorage(u32),
198 GetStorage(u32),
200 TakeStorage(u32),
202 SetTransientStorage { old_bytes: u32, new_bytes: u32 },
204 ClearTransientStorage(u32),
206 ContainsTransientStorage(u32),
208 GetTransientStorage(u32),
210 TakeTransientStorage(u32),
212 Transfer,
214 CallBase,
216 DelegateCallBase,
218 CallTransferSurcharge,
220 CallInputCloned(u32),
222 Instantiate { input_data_len: u32, salt_len: u32 },
224 HashSha256(u32),
226 HashKeccak256(u32),
228 HashBlake256(u32),
230 HashBlake128(u32),
232 EcdsaRecovery,
234 Sr25519Verify(u32),
236 ChainExtension(Weight),
238 CallRuntime(Weight),
240 CallXcmExecute(Weight),
242 SetCodeHash,
244 EcdsaToEthAddress,
246 ReentranceCount,
248 AccountReentranceCount,
250 InstantiationNonce,
252 LockDelegateDependency,
254 UnlockDelegateDependency,
256}
257
258macro_rules! cost_storage {
263 (write_transient, $name:ident $(, $arg:expr )*) => {
264 T::WeightInfo::$name($( $arg ),*)
265 .saturating_add(T::WeightInfo::rollback_transient_storage())
266 .saturating_add(T::WeightInfo::set_transient_storage_full()
267 .saturating_sub(T::WeightInfo::set_transient_storage_empty()))
268 };
269
270 (read_transient, $name:ident $(, $arg:expr )*) => {
271 T::WeightInfo::$name($( $arg ),*)
272 .saturating_add(T::WeightInfo::get_transient_storage_full()
273 .saturating_sub(T::WeightInfo::get_transient_storage_empty()))
274 };
275
276 (write, $name:ident $(, $arg:expr )*) => {
277 T::WeightInfo::$name($( $arg ),*)
278 .saturating_add(T::WeightInfo::set_storage_full()
279 .saturating_sub(T::WeightInfo::set_storage_empty()))
280 };
281
282 (read, $name:ident $(, $arg:expr )*) => {
283 T::WeightInfo::$name($( $arg ),*)
284 .saturating_add(T::WeightInfo::get_storage_full()
285 .saturating_sub(T::WeightInfo::get_storage_empty()))
286 };
287}
288
289macro_rules! cost_args {
290 ($name:ident, $( $arg: expr ),+) => {
292 (T::WeightInfo::$name($( $arg ),+).saturating_sub(cost_args!(@call_zero $name, $( $arg ),+)))
293 };
294 (@call_zero $name:ident, $( $arg:expr ),*) => {
296 T::WeightInfo::$name($( cost_args!(@replace_token $arg) ),*)
297 };
298 (@replace_token $_in:tt) => { 0 };
300}
301
302impl<T: Config> Token<T> for RuntimeCosts {
303 fn influence_lowest_gas_limit(&self) -> bool {
304 match self {
305 &Self::CallXcmExecute(_) => false,
306 _ => true,
307 }
308 }
309
310 fn weight(&self) -> Weight {
311 use self::RuntimeCosts::*;
312 match *self {
313 HostFn => cost_args!(noop_host_fn, 1),
314 CopyToContract(len) => T::WeightInfo::seal_input(len),
315 CopyFromContract(len) => T::WeightInfo::seal_return(len),
316 Caller => T::WeightInfo::seal_caller(),
317 IsContract => T::WeightInfo::seal_is_contract(),
318 CodeHash => T::WeightInfo::seal_code_hash(),
319 OwnCodeHash => T::WeightInfo::seal_own_code_hash(),
320 CallerIsOrigin => T::WeightInfo::seal_caller_is_origin(),
321 CallerIsRoot => T::WeightInfo::seal_caller_is_root(),
322 Address => T::WeightInfo::seal_address(),
323 GasLeft => T::WeightInfo::seal_gas_left(),
324 Balance => T::WeightInfo::seal_balance(),
325 ValueTransferred => T::WeightInfo::seal_value_transferred(),
326 MinimumBalance => T::WeightInfo::seal_minimum_balance(),
327 BlockNumber => T::WeightInfo::seal_block_number(),
328 Now => T::WeightInfo::seal_now(),
329 WeightToFee => T::WeightInfo::seal_weight_to_fee(),
330 Terminate(locked_dependencies) => T::WeightInfo::seal_terminate(locked_dependencies),
331 Random => T::WeightInfo::seal_random(),
332 DepositEvent { num_topic, len } => T::WeightInfo::seal_deposit_event(num_topic, len)
335 .saturating_add(Weight::from_parts(
336 T::Schedule::get().limits.event_ref_time.saturating_mul(len.into()),
337 0,
338 )),
339 DebugMessage(len) => T::WeightInfo::seal_debug_message(len),
340 SetStorage { new_bytes, old_bytes } =>
341 cost_storage!(write, seal_set_storage, new_bytes, old_bytes),
342 ClearStorage(len) => cost_storage!(write, seal_clear_storage, len),
343 ContainsStorage(len) => cost_storage!(read, seal_contains_storage, len),
344 GetStorage(len) => cost_storage!(read, seal_get_storage, len),
345 TakeStorage(len) => cost_storage!(write, seal_take_storage, len),
346 SetTransientStorage { new_bytes, old_bytes } =>
347 cost_storage!(write_transient, seal_set_transient_storage, new_bytes, old_bytes),
348 ClearTransientStorage(len) =>
349 cost_storage!(write_transient, seal_clear_transient_storage, len),
350 ContainsTransientStorage(len) =>
351 cost_storage!(read_transient, seal_contains_transient_storage, len),
352 GetTransientStorage(len) =>
353 cost_storage!(read_transient, seal_get_transient_storage, len),
354 TakeTransientStorage(len) =>
355 cost_storage!(write_transient, seal_take_transient_storage, len),
356 Transfer => T::WeightInfo::seal_transfer(),
357 CallBase => T::WeightInfo::seal_call(0, 0),
358 DelegateCallBase => T::WeightInfo::seal_delegate_call(),
359 CallTransferSurcharge => cost_args!(seal_call, 1, 0),
360 CallInputCloned(len) => cost_args!(seal_call, 0, len),
361 Instantiate { input_data_len, salt_len } =>
362 T::WeightInfo::seal_instantiate(input_data_len, salt_len),
363 HashSha256(len) => T::WeightInfo::seal_hash_sha2_256(len),
364 HashKeccak256(len) => T::WeightInfo::seal_hash_keccak_256(len),
365 HashBlake256(len) => T::WeightInfo::seal_hash_blake2_256(len),
366 HashBlake128(len) => T::WeightInfo::seal_hash_blake2_128(len),
367 EcdsaRecovery => T::WeightInfo::seal_ecdsa_recover(),
368 Sr25519Verify(len) => T::WeightInfo::seal_sr25519_verify(len),
369 ChainExtension(weight) | CallRuntime(weight) | CallXcmExecute(weight) => weight,
370 SetCodeHash => T::WeightInfo::seal_set_code_hash(),
371 EcdsaToEthAddress => T::WeightInfo::seal_ecdsa_to_eth_address(),
372 ReentranceCount => T::WeightInfo::seal_reentrance_count(),
373 AccountReentranceCount => T::WeightInfo::seal_account_reentrance_count(),
374 InstantiationNonce => T::WeightInfo::seal_instantiation_nonce(),
375 LockDelegateDependency => T::WeightInfo::lock_delegate_dependency(),
376 UnlockDelegateDependency => T::WeightInfo::unlock_delegate_dependency(),
377 }
378 }
379}
380
381macro_rules! charge_gas {
386 ($runtime:expr, $costs:expr) => {{
387 $runtime.ext.gas_meter_mut().charge($costs)
388 }};
389}
390
391enum CallType {
393 Call { callee_ptr: u32, value_ptr: u32, deposit_ptr: u32, weight: Weight },
395 DelegateCall { code_hash_ptr: u32 },
397}
398
399impl CallType {
400 fn cost(&self) -> RuntimeCosts {
401 match self {
402 CallType::Call { .. } => RuntimeCosts::CallBase,
403 CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase,
404 }
405 }
406}
407
408fn already_charged(_: u32) -> Option<RuntimeCosts> {
412 None
413}
414
415pub struct Runtime<'a, E: Ext + 'a> {
417 ext: &'a mut E,
418 input_data: Option<Vec<u8>>,
419 memory: Option<Memory>,
420 chain_extension: Option<Box<<E::T as Config>::ChainExtension>>,
421}
422
423impl<'a, E: Ext + 'a> Runtime<'a, E> {
424 pub fn new(ext: &'a mut E, input_data: Vec<u8>) -> Self {
425 Runtime {
426 ext,
427 input_data: Some(input_data),
428 memory: None,
429 chain_extension: Some(Box::new(Default::default())),
430 }
431 }
432
433 pub fn memory(&self) -> Option<Memory> {
434 self.memory
435 }
436
437 pub fn set_memory(&mut self, memory: Memory) {
438 self.memory = Some(memory);
439 }
440
441 pub fn to_execution_result(self, sandbox_result: Result<(), wasmi::Error>) -> ExecResult {
443 use wasmi::{
444 core::TrapCode,
445 errors::{ErrorKind, FuelError},
446 };
447 use TrapReason::*;
448
449 let Err(error) = sandbox_result else {
450 return Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
452 };
453 if let ErrorKind::Fuel(FuelError::OutOfFuel) = error.kind() {
454 return Err(Error::<E::T>::OutOfGas.into())
458 }
459 match error.as_trap_code() {
460 Some(TrapCode::OutOfFuel) => {
461 return Err(Error::<E::T>::OutOfGas.into())
463 },
464 Some(_trap_code) => {
465 return Err(Error::<E::T>::ContractTrapped.into())
467 },
468 None => {},
469 }
470 if let Some(reason) = &error.downcast_ref::<TrapReason>() {
472 match &reason {
473 Return(ReturnData { flags, data }) => {
474 let flags =
475 ReturnFlags::from_bits(*flags).ok_or(Error::<E::T>::InvalidCallFlags)?;
476 return Ok(ExecReturnValue { flags, data: data.to_vec() })
477 },
478 Termination =>
479 return Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() }),
480 SupervisorError(error) => return Err((*error).into()),
481 }
482 }
483
484 log::debug!("Code rejected: {:?}", error);
491 Err(Error::<E::T>::CodeRejected.into())
492 }
493
494 pub fn ext(&mut self) -> &mut E {
499 self.ext
500 }
501
502 pub fn charge_gas(&mut self, costs: RuntimeCosts) -> Result<ChargedAmount, DispatchError> {
506 charge_gas!(self, costs)
507 }
508
509 pub fn adjust_gas(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) {
514 self.ext.gas_meter_mut().adjust_gas(charged, actual_costs);
515 }
516
517 fn call_dispatchable<ErrorReturnCode: Get<ReturnErrorCode>>(
519 &mut self,
520 dispatch_info: DispatchInfo,
521 runtime_cost: impl Fn(Weight) -> RuntimeCosts,
522 run: impl FnOnce(&mut Self) -> DispatchResultWithPostInfo,
523 ) -> Result<ReturnErrorCode, TrapReason> {
524 use frame_support::dispatch::extract_actual_weight;
525 let charged = self.charge_gas(runtime_cost(dispatch_info.call_weight))?;
526 let result = run(self);
527 let actual_weight = extract_actual_weight(&result, &dispatch_info);
528 self.adjust_gas(charged, runtime_cost(actual_weight));
529 match result {
530 Ok(_) => Ok(ReturnErrorCode::Success),
531 Err(e) => {
532 if self.ext.debug_buffer_enabled() {
533 self.ext.append_debug_buffer("call failed with: ");
534 self.ext.append_debug_buffer(e.into());
535 };
536 Ok(ErrorReturnCode::get())
537 },
538 }
539 }
540
541 pub fn read_sandbox_memory(
547 &self,
548 memory: &[u8],
549 ptr: u32,
550 len: u32,
551 ) -> Result<Vec<u8>, DispatchError> {
552 ensure!(len <= self.ext.schedule().limits.max_memory_size(), Error::<E::T>::OutOfBounds);
553 let mut buf = vec![0u8; len as usize];
554 self.read_sandbox_memory_into_buf(memory, ptr, buf.as_mut_slice())?;
555 Ok(buf)
556 }
557
558 pub fn read_sandbox_memory_into_buf(
564 &self,
565 memory: &[u8],
566 ptr: u32,
567 buf: &mut [u8],
568 ) -> Result<(), DispatchError> {
569 let ptr = ptr as usize;
570 let bound_checked =
571 memory.get(ptr..ptr + buf.len()).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
572 buf.copy_from_slice(bound_checked);
573 Ok(())
574 }
575
576 pub fn read_sandbox_memory_as<D: Decode + MaxEncodedLen>(
583 &self,
584 memory: &[u8],
585 ptr: u32,
586 ) -> Result<D, DispatchError> {
587 let ptr = ptr as usize;
588 let mut bound_checked = memory.get(ptr..).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
589
590 let decoded = D::decode_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked)
591 .map_err(|_| DispatchError::from(Error::<E::T>::DecodingFailed))?;
592 Ok(decoded)
593 }
594
595 pub fn read_sandbox_memory_as_unbounded<D: Decode>(
607 &self,
608 memory: &[u8],
609 ptr: u32,
610 len: u32,
611 ) -> Result<D, DispatchError> {
612 let ptr = ptr as usize;
613 let mut bound_checked =
614 memory.get(ptr..ptr + len as usize).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
615
616 let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked)
617 .map_err(|_| DispatchError::from(Error::<E::T>::DecodingFailed))?;
618
619 Ok(decoded)
620 }
621
622 pub fn write_sandbox_output(
642 &mut self,
643 memory: &mut [u8],
644 out_ptr: u32,
645 out_len_ptr: u32,
646 buf: &[u8],
647 allow_skip: bool,
648 create_token: impl FnOnce(u32) -> Option<RuntimeCosts>,
649 ) -> Result<(), DispatchError> {
650 if allow_skip && out_ptr == SENTINEL {
651 return Ok(())
652 }
653
654 let buf_len = buf.len() as u32;
655 let len: u32 = self.read_sandbox_memory_as(memory, out_len_ptr)?;
656
657 if len < buf_len {
658 return Err(Error::<E::T>::OutputBufferTooSmall.into())
659 }
660
661 if let Some(costs) = create_token(buf_len) {
662 self.charge_gas(costs)?;
663 }
664
665 self.write_sandbox_memory(memory, out_ptr, buf)?;
666 self.write_sandbox_memory(memory, out_len_ptr, &buf_len.encode())
667 }
668
669 fn write_sandbox_memory(
675 &self,
676 memory: &mut [u8],
677 ptr: u32,
678 buf: &[u8],
679 ) -> Result<(), DispatchError> {
680 let ptr = ptr as usize;
681 let bound_checked =
682 memory.get_mut(ptr..ptr + buf.len()).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
683 bound_checked.copy_from_slice(buf);
684 Ok(())
685 }
686
687 fn compute_hash_on_intermediate_buffer<F, R>(
700 &self,
701 memory: &mut [u8],
702 hash_fn: F,
703 input_ptr: u32,
704 input_len: u32,
705 output_ptr: u32,
706 ) -> Result<(), DispatchError>
707 where
708 F: FnOnce(&[u8]) -> R,
709 R: AsRef<[u8]>,
710 {
711 let input = self.read_sandbox_memory(memory, input_ptr, input_len)?;
713 let hash = hash_fn(&input);
715 self.write_sandbox_memory(memory, output_ptr, hash.as_ref())?;
717 Ok(())
718 }
719
720 fn err_into_return_code(from: DispatchError) -> Result<ReturnErrorCode, DispatchError> {
722 use ReturnErrorCode::*;
723
724 let transfer_failed = Error::<E::T>::TransferFailed.into();
725 let no_code = Error::<E::T>::CodeNotFound.into();
726 let not_found = Error::<E::T>::ContractNotFound.into();
727
728 match from {
729 x if x == transfer_failed => Ok(TransferFailed),
730 x if x == no_code => Ok(CodeNotFound),
731 x if x == not_found => Ok(NotCallable),
732 err => Err(err),
733 }
734 }
735
736 fn exec_into_return_code(from: ExecResult) -> Result<ReturnErrorCode, DispatchError> {
738 use crate::exec::ErrorOrigin::Callee;
739
740 let ExecError { error, origin } = match from {
741 Ok(retval) => return Ok(retval.into()),
742 Err(err) => err,
743 };
744
745 match (error, origin) {
746 (_, Callee) => Ok(ReturnErrorCode::CalleeTrapped),
747 (err, _) => Self::err_into_return_code(err),
748 }
749 }
750 fn decode_key(
751 &self,
752 memory: &[u8],
753 key_type: KeyType,
754 key_ptr: u32,
755 ) -> Result<crate::exec::Key<E::T>, TrapReason> {
756 let res = match key_type {
757 KeyType::Fix => {
758 let key = self.read_sandbox_memory(memory, key_ptr, 32u32)?;
759 Key::try_from_fix(key)
760 },
761 KeyType::Var(len) => {
762 ensure!(
763 len <= <<E as Ext>::T as Config>::MaxStorageKeyLen::get(),
764 Error::<E::T>::DecodingFailed
765 );
766 let key = self.read_sandbox_memory(memory, key_ptr, len)?;
767 Key::try_from_var(key)
768 },
769 };
770
771 res.map_err(|_| Error::<E::T>::DecodingFailed.into())
772 }
773
774 fn set_storage(
775 &mut self,
776 memory: &[u8],
777 key_type: KeyType,
778 key_ptr: u32,
779 value_ptr: u32,
780 value_len: u32,
781 ) -> Result<u32, TrapReason> {
782 let max_size = self.ext.max_value_size();
783 let charged = self
784 .charge_gas(RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: max_size })?;
785 if value_len > max_size {
786 return Err(Error::<E::T>::ValueTooLarge.into())
787 }
788 let key = self.decode_key(memory, key_type, key_ptr)?;
789 let value = Some(self.read_sandbox_memory(memory, value_ptr, value_len)?);
790 let write_outcome = self.ext.set_storage(&key, value, false)?;
791
792 self.adjust_gas(
793 charged,
794 RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: write_outcome.old_len() },
795 );
796 Ok(write_outcome.old_len_with_sentinel())
797 }
798
799 fn clear_storage(
800 &mut self,
801 memory: &[u8],
802 key_type: KeyType,
803 key_ptr: u32,
804 ) -> Result<u32, TrapReason> {
805 let charged = self.charge_gas(RuntimeCosts::ClearStorage(self.ext.max_value_size()))?;
806 let key = self.decode_key(memory, key_type, key_ptr)?;
807 let outcome = self.ext.set_storage(&key, None, false)?;
808
809 self.adjust_gas(charged, RuntimeCosts::ClearStorage(outcome.old_len()));
810 Ok(outcome.old_len_with_sentinel())
811 }
812
813 fn get_storage(
814 &mut self,
815 memory: &mut [u8],
816 key_type: KeyType,
817 key_ptr: u32,
818 out_ptr: u32,
819 out_len_ptr: u32,
820 ) -> Result<ReturnErrorCode, TrapReason> {
821 let charged = self.charge_gas(RuntimeCosts::GetStorage(self.ext.max_value_size()))?;
822 let key = self.decode_key(memory, key_type, key_ptr)?;
823 let outcome = self.ext.get_storage(&key);
824
825 if let Some(value) = outcome {
826 self.adjust_gas(charged, RuntimeCosts::GetStorage(value.len() as u32));
827 self.write_sandbox_output(
828 memory,
829 out_ptr,
830 out_len_ptr,
831 &value,
832 false,
833 already_charged,
834 )?;
835 Ok(ReturnErrorCode::Success)
836 } else {
837 self.adjust_gas(charged, RuntimeCosts::GetStorage(0));
838 Ok(ReturnErrorCode::KeyNotFound)
839 }
840 }
841
842 fn contains_storage(
843 &mut self,
844 memory: &[u8],
845 key_type: KeyType,
846 key_ptr: u32,
847 ) -> Result<u32, TrapReason> {
848 let charged = self.charge_gas(RuntimeCosts::ContainsStorage(self.ext.max_value_size()))?;
849 let key = self.decode_key(memory, key_type, key_ptr)?;
850 let outcome = self.ext.get_storage_size(&key);
851
852 self.adjust_gas(charged, RuntimeCosts::ContainsStorage(outcome.unwrap_or(0)));
853 Ok(outcome.unwrap_or(SENTINEL))
854 }
855
856 fn set_transient_storage(
857 &mut self,
858 memory: &[u8],
859 key_type: KeyType,
860 key_ptr: u32,
861 value_ptr: u32,
862 value_len: u32,
863 ) -> Result<u32, TrapReason> {
864 let max_size = self.ext.max_value_size();
865 let charged = self.charge_gas(RuntimeCosts::SetTransientStorage {
866 new_bytes: value_len,
867 old_bytes: max_size,
868 })?;
869 if value_len > max_size {
870 return Err(Error::<E::T>::ValueTooLarge.into())
871 }
872 let key = self.decode_key(memory, key_type, key_ptr)?;
873 let value = Some(self.read_sandbox_memory(memory, value_ptr, value_len)?);
874 let write_outcome = self.ext.set_transient_storage(&key, value, false)?;
875 self.adjust_gas(
876 charged,
877 RuntimeCosts::SetTransientStorage {
878 new_bytes: value_len,
879 old_bytes: write_outcome.old_len(),
880 },
881 );
882 Ok(write_outcome.old_len_with_sentinel())
883 }
884
885 fn clear_transient_storage(
886 &mut self,
887 memory: &[u8],
888 key_type: KeyType,
889 key_ptr: u32,
890 ) -> Result<u32, TrapReason> {
891 let charged =
892 self.charge_gas(RuntimeCosts::ClearTransientStorage(self.ext.max_value_size()))?;
893 let key = self.decode_key(memory, key_type, key_ptr)?;
894 let outcome = self.ext.set_transient_storage(&key, None, false)?;
895
896 self.adjust_gas(charged, RuntimeCosts::ClearTransientStorage(outcome.old_len()));
897 Ok(outcome.old_len_with_sentinel())
898 }
899
900 fn get_transient_storage(
901 &mut self,
902 memory: &mut [u8],
903 key_type: KeyType,
904 key_ptr: u32,
905 out_ptr: u32,
906 out_len_ptr: u32,
907 ) -> Result<ReturnErrorCode, TrapReason> {
908 let charged =
909 self.charge_gas(RuntimeCosts::GetTransientStorage(self.ext.max_value_size()))?;
910 let key = self.decode_key(memory, key_type, key_ptr)?;
911 let outcome = self.ext.get_transient_storage(&key);
912
913 if let Some(value) = outcome {
914 self.adjust_gas(charged, RuntimeCosts::GetTransientStorage(value.len() as u32));
915 self.write_sandbox_output(
916 memory,
917 out_ptr,
918 out_len_ptr,
919 &value,
920 false,
921 already_charged,
922 )?;
923 Ok(ReturnErrorCode::Success)
924 } else {
925 self.adjust_gas(charged, RuntimeCosts::GetTransientStorage(0));
926 Ok(ReturnErrorCode::KeyNotFound)
927 }
928 }
929
930 fn contains_transient_storage(
931 &mut self,
932 memory: &[u8],
933 key_type: KeyType,
934 key_ptr: u32,
935 ) -> Result<u32, TrapReason> {
936 let charged =
937 self.charge_gas(RuntimeCosts::ContainsTransientStorage(self.ext.max_value_size()))?;
938 let key = self.decode_key(memory, key_type, key_ptr)?;
939 let outcome = self.ext.get_transient_storage_size(&key);
940
941 self.adjust_gas(charged, RuntimeCosts::ContainsTransientStorage(outcome.unwrap_or(0)));
942 Ok(outcome.unwrap_or(SENTINEL))
943 }
944
945 fn take_transient_storage(
946 &mut self,
947 memory: &mut [u8],
948 key_type: KeyType,
949 key_ptr: u32,
950 out_ptr: u32,
951 out_len_ptr: u32,
952 ) -> Result<ReturnErrorCode, TrapReason> {
953 let charged =
954 self.charge_gas(RuntimeCosts::TakeTransientStorage(self.ext.max_value_size()))?;
955 let key = self.decode_key(memory, key_type, key_ptr)?;
956 if let crate::storage::WriteOutcome::Taken(value) =
957 self.ext.set_transient_storage(&key, None, true)?
958 {
959 self.adjust_gas(charged, RuntimeCosts::TakeTransientStorage(value.len() as u32));
960 self.write_sandbox_output(
961 memory,
962 out_ptr,
963 out_len_ptr,
964 &value,
965 false,
966 already_charged,
967 )?;
968 Ok(ReturnErrorCode::Success)
969 } else {
970 self.adjust_gas(charged, RuntimeCosts::TakeTransientStorage(0));
971 Ok(ReturnErrorCode::KeyNotFound)
972 }
973 }
974
975 fn call(
976 &mut self,
977 memory: &mut [u8],
978 flags: CallFlags,
979 call_type: CallType,
980 input_data_ptr: u32,
981 input_data_len: u32,
982 output_ptr: u32,
983 output_len_ptr: u32,
984 ) -> Result<ReturnErrorCode, TrapReason> {
985 self.charge_gas(call_type.cost())?;
986
987 let input_data = if flags.contains(CallFlags::CLONE_INPUT) {
988 let input = self.input_data.as_ref().ok_or(Error::<E::T>::InputForwarded)?;
989 charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?;
990 input.clone()
991 } else if flags.contains(CallFlags::FORWARD_INPUT) {
992 self.input_data.take().ok_or(Error::<E::T>::InputForwarded)?
993 } else {
994 self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?;
995 self.read_sandbox_memory(memory, input_data_ptr, input_data_len)?
996 };
997
998 let call_outcome = match call_type {
999 CallType::Call { callee_ptr, value_ptr, deposit_ptr, weight } => {
1000 let callee: <<E as Ext>::T as frame_system::Config>::AccountId =
1001 self.read_sandbox_memory_as(memory, callee_ptr)?;
1002 let deposit_limit: BalanceOf<<E as Ext>::T> = if deposit_ptr == SENTINEL {
1003 BalanceOf::<<E as Ext>::T>::zero()
1004 } else {
1005 self.read_sandbox_memory_as(memory, deposit_ptr)?
1006 };
1007 let read_only = flags.contains(CallFlags::READ_ONLY);
1008 let value: BalanceOf<<E as Ext>::T> =
1009 self.read_sandbox_memory_as(memory, value_ptr)?;
1010 if value > 0u32.into() {
1011 if read_only || self.ext.is_read_only() {
1014 return Err(Error::<E::T>::StateChangeDenied.into());
1015 }
1016 self.charge_gas(RuntimeCosts::CallTransferSurcharge)?;
1017 }
1018 self.ext.call(
1019 weight,
1020 deposit_limit,
1021 callee,
1022 value,
1023 input_data,
1024 flags.contains(CallFlags::ALLOW_REENTRY),
1025 read_only,
1026 )
1027 },
1028 CallType::DelegateCall { code_hash_ptr } => {
1029 if flags.intersects(CallFlags::ALLOW_REENTRY | CallFlags::READ_ONLY) {
1030 return Err(Error::<E::T>::InvalidCallFlags.into())
1031 }
1032 let code_hash = self.read_sandbox_memory_as(memory, code_hash_ptr)?;
1033 self.ext.delegate_call(code_hash, input_data)
1034 },
1035 };
1036
1037 if flags.contains(CallFlags::TAIL_CALL) {
1040 if let Ok(return_value) = call_outcome {
1041 return Err(TrapReason::Return(ReturnData {
1042 flags: return_value.flags.bits(),
1043 data: return_value.data,
1044 }))
1045 }
1046 }
1047
1048 if let Ok(output) = &call_outcome {
1049 self.write_sandbox_output(
1050 memory,
1051 output_ptr,
1052 output_len_ptr,
1053 &output.data,
1054 true,
1055 |len| Some(RuntimeCosts::CopyToContract(len)),
1056 )?;
1057 }
1058 Ok(Runtime::<E>::exec_into_return_code(call_outcome)?)
1059 }
1060
1061 fn instantiate(
1062 &mut self,
1063 memory: &mut [u8],
1064 code_hash_ptr: u32,
1065 weight: Weight,
1066 deposit_ptr: u32,
1067 value_ptr: u32,
1068 input_data_ptr: u32,
1069 input_data_len: u32,
1070 address_ptr: u32,
1071 address_len_ptr: u32,
1072 output_ptr: u32,
1073 output_len_ptr: u32,
1074 salt_ptr: u32,
1075 salt_len: u32,
1076 ) -> Result<ReturnErrorCode, TrapReason> {
1077 self.charge_gas(RuntimeCosts::Instantiate { input_data_len, salt_len })?;
1078 let deposit_limit: BalanceOf<<E as Ext>::T> = if deposit_ptr == SENTINEL {
1079 BalanceOf::<<E as Ext>::T>::zero()
1080 } else {
1081 self.read_sandbox_memory_as(memory, deposit_ptr)?
1082 };
1083 let value: BalanceOf<<E as Ext>::T> = self.read_sandbox_memory_as(memory, value_ptr)?;
1084 let code_hash: CodeHash<<E as Ext>::T> =
1085 self.read_sandbox_memory_as(memory, code_hash_ptr)?;
1086 let input_data = self.read_sandbox_memory(memory, input_data_ptr, input_data_len)?;
1087 let salt = self.read_sandbox_memory(memory, salt_ptr, salt_len)?;
1088 let instantiate_outcome =
1089 self.ext.instantiate(weight, deposit_limit, code_hash, value, input_data, &salt);
1090 if let Ok((address, output)) = &instantiate_outcome {
1091 if !output.flags.contains(ReturnFlags::REVERT) {
1092 self.write_sandbox_output(
1093 memory,
1094 address_ptr,
1095 address_len_ptr,
1096 &address.encode(),
1097 true,
1098 already_charged,
1099 )?;
1100 }
1101 self.write_sandbox_output(
1102 memory,
1103 output_ptr,
1104 output_len_ptr,
1105 &output.data,
1106 true,
1107 |len| Some(RuntimeCosts::CopyToContract(len)),
1108 )?;
1109 }
1110 Ok(Runtime::<E>::exec_into_return_code(instantiate_outcome.map(|(_, retval)| retval))?)
1111 }
1112
1113 fn terminate(&mut self, memory: &[u8], beneficiary_ptr: u32) -> Result<(), TrapReason> {
1114 let count = self.ext.locked_delegate_dependencies_count() as _;
1115 self.charge_gas(RuntimeCosts::Terminate(count))?;
1116
1117 let beneficiary: <<E as Ext>::T as frame_system::Config>::AccountId =
1118 self.read_sandbox_memory_as(memory, beneficiary_ptr)?;
1119 self.ext.terminate(&beneficiary)?;
1120 Err(TrapReason::Termination)
1121 }
1122}
1123
1124#[define_env(doc)]
1132pub mod env {
1133
1134 #[cfg(feature = "runtime-benchmarks")]
1136 #[unstable]
1137 fn noop(ctx: _, memory: _) -> Result<(), TrapReason> {
1138 Ok(())
1139 }
1140
1141 #[prefixed_alias]
1144 #[mutating]
1145 fn set_storage(
1146 ctx: _,
1147 memory: _,
1148 key_ptr: u32,
1149 value_ptr: u32,
1150 value_len: u32,
1151 ) -> Result<(), TrapReason> {
1152 ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
1153 }
1154
1155 #[version(1)]
1158 #[prefixed_alias]
1159 #[mutating]
1160 fn set_storage(
1161 ctx: _,
1162 memory: _,
1163 key_ptr: u32,
1164 value_ptr: u32,
1165 value_len: u32,
1166 ) -> Result<u32, TrapReason> {
1167 ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len)
1168 }
1169
1170 #[version(2)]
1173 #[prefixed_alias]
1174 #[mutating]
1175 fn set_storage(
1176 ctx: _,
1177 memory: _,
1178 key_ptr: u32,
1179 key_len: u32,
1180 value_ptr: u32,
1181 value_len: u32,
1182 ) -> Result<u32, TrapReason> {
1183 ctx.set_storage(memory, KeyType::Var(key_len), key_ptr, value_ptr, value_len)
1184 }
1185
1186 #[prefixed_alias]
1189 #[mutating]
1190 fn clear_storage(ctx: _, memory: _, key_ptr: u32) -> Result<(), TrapReason> {
1191 ctx.clear_storage(memory, KeyType::Fix, key_ptr).map(|_| ())
1192 }
1193
1194 #[version(1)]
1197 #[prefixed_alias]
1198 #[mutating]
1199 fn clear_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
1200 ctx.clear_storage(memory, KeyType::Var(key_len), key_ptr)
1201 }
1202
1203 #[prefixed_alias]
1206 fn get_storage(
1207 ctx: _,
1208 memory: _,
1209 key_ptr: u32,
1210 out_ptr: u32,
1211 out_len_ptr: u32,
1212 ) -> Result<ReturnErrorCode, TrapReason> {
1213 ctx.get_storage(memory, KeyType::Fix, key_ptr, out_ptr, out_len_ptr)
1214 }
1215
1216 #[version(1)]
1219 #[prefixed_alias]
1220 fn get_storage(
1221 ctx: _,
1222 memory: _,
1223 key_ptr: u32,
1224 key_len: u32,
1225 out_ptr: u32,
1226 out_len_ptr: u32,
1227 ) -> Result<ReturnErrorCode, TrapReason> {
1228 ctx.get_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr)
1229 }
1230
1231 #[prefixed_alias]
1234 fn contains_storage(ctx: _, memory: _, key_ptr: u32) -> Result<u32, TrapReason> {
1235 ctx.contains_storage(memory, KeyType::Fix, key_ptr)
1236 }
1237
1238 #[version(1)]
1241 #[prefixed_alias]
1242 fn contains_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
1243 ctx.contains_storage(memory, KeyType::Var(key_len), key_ptr)
1244 }
1245
1246 #[prefixed_alias]
1249 #[mutating]
1250 fn take_storage(
1251 ctx: _,
1252 memory: _,
1253 key_ptr: u32,
1254 key_len: u32,
1255 out_ptr: u32,
1256 out_len_ptr: u32,
1257 ) -> Result<ReturnErrorCode, TrapReason> {
1258 let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?;
1259 ensure!(
1260 key_len <= <<E as Ext>::T as Config>::MaxStorageKeyLen::get(),
1261 Error::<E::T>::DecodingFailed
1262 );
1263 let key = ctx.read_sandbox_memory(memory, key_ptr, key_len)?;
1264 if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage(
1265 &Key::<E::T>::try_from_var(key).map_err(|_| Error::<E::T>::DecodingFailed)?,
1266 None,
1267 true,
1268 )? {
1269 ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32));
1270 ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &value, false, already_charged)?;
1271 Ok(ReturnErrorCode::Success)
1272 } else {
1273 ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0));
1274 Ok(ReturnErrorCode::KeyNotFound)
1275 }
1276 }
1277
1278 #[unstable]
1280 fn set_transient_storage(
1281 ctx: _,
1282 memory: _,
1283 key_ptr: u32,
1284 key_len: u32,
1285 value_ptr: u32,
1286 value_len: u32,
1287 ) -> Result<u32, TrapReason> {
1288 ctx.set_transient_storage(memory, KeyType::Var(key_len), key_ptr, value_ptr, value_len)
1289 }
1290
1291 #[unstable]
1293 fn clear_transient_storage(
1294 ctx: _,
1295 memory: _,
1296 key_ptr: u32,
1297 key_len: u32,
1298 ) -> Result<u32, TrapReason> {
1299 ctx.clear_transient_storage(memory, KeyType::Var(key_len), key_ptr)
1300 }
1301
1302 #[unstable]
1304 fn get_transient_storage(
1305 ctx: _,
1306 memory: _,
1307 key_ptr: u32,
1308 key_len: u32,
1309 out_ptr: u32,
1310 out_len_ptr: u32,
1311 ) -> Result<ReturnErrorCode, TrapReason> {
1312 ctx.get_transient_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr)
1313 }
1314
1315 #[unstable]
1317 fn contains_transient_storage(
1318 ctx: _,
1319 memory: _,
1320 key_ptr: u32,
1321 key_len: u32,
1322 ) -> Result<u32, TrapReason> {
1323 ctx.contains_transient_storage(memory, KeyType::Var(key_len), key_ptr)
1324 }
1325
1326 #[unstable]
1328 fn take_transient_storage(
1329 ctx: _,
1330 memory: _,
1331 key_ptr: u32,
1332 key_len: u32,
1333 out_ptr: u32,
1334 out_len_ptr: u32,
1335 ) -> Result<ReturnErrorCode, TrapReason> {
1336 ctx.take_transient_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr)
1337 }
1338
1339 #[prefixed_alias]
1342 #[mutating]
1343 fn transfer(
1344 ctx: _,
1345 memory: _,
1346 account_ptr: u32,
1347 _account_len: u32,
1348 value_ptr: u32,
1349 _value_len: u32,
1350 ) -> Result<ReturnErrorCode, TrapReason> {
1351 ctx.charge_gas(RuntimeCosts::Transfer)?;
1352 let callee: <<E as Ext>::T as frame_system::Config>::AccountId =
1353 ctx.read_sandbox_memory_as(memory, account_ptr)?;
1354 let value: BalanceOf<<E as Ext>::T> = ctx.read_sandbox_memory_as(memory, value_ptr)?;
1355 let result = ctx.ext.transfer(&callee, value);
1356 match result {
1357 Ok(()) => Ok(ReturnErrorCode::Success),
1358 Err(err) => {
1359 let code = Runtime::<E>::err_into_return_code(err)?;
1360 Ok(code)
1361 },
1362 }
1363 }
1364
1365 #[prefixed_alias]
1373 fn call(
1374 ctx: _,
1375 memory: _,
1376 callee_ptr: u32,
1377 _callee_len: u32,
1378 gas: u64,
1379 value_ptr: u32,
1380 _value_len: u32,
1381 input_data_ptr: u32,
1382 input_data_len: u32,
1383 output_ptr: u32,
1384 output_len_ptr: u32,
1385 ) -> Result<ReturnErrorCode, TrapReason> {
1386 ctx.call(
1387 memory,
1388 CallFlags::ALLOW_REENTRY,
1389 CallType::Call {
1390 callee_ptr,
1391 value_ptr,
1392 deposit_ptr: SENTINEL,
1393 weight: Weight::from_parts(gas, 0),
1394 },
1395 input_data_ptr,
1396 input_data_len,
1397 output_ptr,
1398 output_len_ptr,
1399 )
1400 }
1401
1402 #[version(1)]
1405 #[prefixed_alias]
1406 fn call(
1407 ctx: _,
1408 memory: _,
1409 flags: u32,
1410 callee_ptr: u32,
1411 gas: u64,
1412 value_ptr: u32,
1413 input_data_ptr: u32,
1414 input_data_len: u32,
1415 output_ptr: u32,
1416 output_len_ptr: u32,
1417 ) -> Result<ReturnErrorCode, TrapReason> {
1418 ctx.call(
1419 memory,
1420 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
1421 CallType::Call {
1422 callee_ptr,
1423 value_ptr,
1424 deposit_ptr: SENTINEL,
1425 weight: Weight::from_parts(gas, 0),
1426 },
1427 input_data_ptr,
1428 input_data_len,
1429 output_ptr,
1430 output_len_ptr,
1431 )
1432 }
1433
1434 #[version(2)]
1437 fn call(
1438 ctx: _,
1439 memory: _,
1440 flags: u32,
1441 callee_ptr: u32,
1442 ref_time_limit: u64,
1443 proof_size_limit: u64,
1444 deposit_ptr: u32,
1445 value_ptr: u32,
1446 input_data_ptr: u32,
1447 input_data_len: u32,
1448 output_ptr: u32,
1449 output_len_ptr: u32,
1450 ) -> Result<ReturnErrorCode, TrapReason> {
1451 ctx.call(
1452 memory,
1453 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
1454 CallType::Call {
1455 callee_ptr,
1456 value_ptr,
1457 deposit_ptr,
1458 weight: Weight::from_parts(ref_time_limit, proof_size_limit),
1459 },
1460 input_data_ptr,
1461 input_data_len,
1462 output_ptr,
1463 output_len_ptr,
1464 )
1465 }
1466
1467 #[prefixed_alias]
1470 fn delegate_call(
1471 ctx: _,
1472 memory: _,
1473 flags: u32,
1474 code_hash_ptr: u32,
1475 input_data_ptr: u32,
1476 input_data_len: u32,
1477 output_ptr: u32,
1478 output_len_ptr: u32,
1479 ) -> Result<ReturnErrorCode, TrapReason> {
1480 ctx.call(
1481 memory,
1482 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
1483 CallType::DelegateCall { code_hash_ptr },
1484 input_data_ptr,
1485 input_data_len,
1486 output_ptr,
1487 output_len_ptr,
1488 )
1489 }
1490
1491 #[prefixed_alias]
1500 #[mutating]
1501 fn instantiate(
1502 ctx: _,
1503 memory: _,
1504 code_hash_ptr: u32,
1505 _code_hash_len: u32,
1506 gas: u64,
1507 value_ptr: u32,
1508 _value_len: u32,
1509 input_data_ptr: u32,
1510 input_data_len: u32,
1511 address_ptr: u32,
1512 address_len_ptr: u32,
1513 output_ptr: u32,
1514 output_len_ptr: u32,
1515 salt_ptr: u32,
1516 salt_len: u32,
1517 ) -> Result<ReturnErrorCode, TrapReason> {
1518 ctx.instantiate(
1519 memory,
1520 code_hash_ptr,
1521 Weight::from_parts(gas, 0),
1522 SENTINEL,
1523 value_ptr,
1524 input_data_ptr,
1525 input_data_len,
1526 address_ptr,
1527 address_len_ptr,
1528 output_ptr,
1529 output_len_ptr,
1530 salt_ptr,
1531 salt_len,
1532 )
1533 }
1534
1535 #[version(1)]
1538 #[prefixed_alias]
1539 #[mutating]
1540 fn instantiate(
1541 ctx: _,
1542 memory: _,
1543 code_hash_ptr: u32,
1544 gas: u64,
1545 value_ptr: u32,
1546 input_data_ptr: u32,
1547 input_data_len: u32,
1548 address_ptr: u32,
1549 address_len_ptr: u32,
1550 output_ptr: u32,
1551 output_len_ptr: u32,
1552 salt_ptr: u32,
1553 salt_len: u32,
1554 ) -> Result<ReturnErrorCode, TrapReason> {
1555 ctx.instantiate(
1556 memory,
1557 code_hash_ptr,
1558 Weight::from_parts(gas, 0),
1559 SENTINEL,
1560 value_ptr,
1561 input_data_ptr,
1562 input_data_len,
1563 address_ptr,
1564 address_len_ptr,
1565 output_ptr,
1566 output_len_ptr,
1567 salt_ptr,
1568 salt_len,
1569 )
1570 }
1571
1572 #[version(2)]
1575 #[mutating]
1576 fn instantiate(
1577 ctx: _,
1578 memory: _,
1579 code_hash_ptr: u32,
1580 ref_time_limit: u64,
1581 proof_size_limit: u64,
1582 deposit_ptr: u32,
1583 value_ptr: u32,
1584 input_data_ptr: u32,
1585 input_data_len: u32,
1586 address_ptr: u32,
1587 address_len_ptr: u32,
1588 output_ptr: u32,
1589 output_len_ptr: u32,
1590 salt_ptr: u32,
1591 salt_len: u32,
1592 ) -> Result<ReturnErrorCode, TrapReason> {
1593 ctx.instantiate(
1594 memory,
1595 code_hash_ptr,
1596 Weight::from_parts(ref_time_limit, proof_size_limit),
1597 deposit_ptr,
1598 value_ptr,
1599 input_data_ptr,
1600 input_data_len,
1601 address_ptr,
1602 address_len_ptr,
1603 output_ptr,
1604 output_len_ptr,
1605 salt_ptr,
1606 salt_len,
1607 )
1608 }
1609
1610 #[prefixed_alias]
1619 #[mutating]
1620 fn terminate(
1621 ctx: _,
1622 memory: _,
1623 beneficiary_ptr: u32,
1624 _beneficiary_len: u32,
1625 ) -> Result<(), TrapReason> {
1626 ctx.terminate(memory, beneficiary_ptr)
1627 }
1628
1629 #[version(1)]
1632 #[prefixed_alias]
1633 #[mutating]
1634 fn terminate(ctx: _, memory: _, beneficiary_ptr: u32) -> Result<(), TrapReason> {
1635 ctx.terminate(memory, beneficiary_ptr)
1636 }
1637
1638 #[prefixed_alias]
1641 fn input(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1642 if let Some(input) = ctx.input_data.take() {
1643 ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &input, false, |len| {
1644 Some(RuntimeCosts::CopyToContract(len))
1645 })?;
1646 ctx.input_data = Some(input);
1647 Ok(())
1648 } else {
1649 Err(Error::<E::T>::InputForwarded.into())
1650 }
1651 }
1652
1653 fn seal_return(
1656 ctx: _,
1657 memory: _,
1658 flags: u32,
1659 data_ptr: u32,
1660 data_len: u32,
1661 ) -> Result<(), TrapReason> {
1662 ctx.charge_gas(RuntimeCosts::CopyFromContract(data_len))?;
1663 Err(TrapReason::Return(ReturnData {
1664 flags,
1665 data: ctx.read_sandbox_memory(memory, data_ptr, data_len)?,
1666 }))
1667 }
1668
1669 #[prefixed_alias]
1672 fn caller(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1673 ctx.charge_gas(RuntimeCosts::Caller)?;
1674 let caller = ctx.ext.caller().account_id()?.clone();
1675 Ok(ctx.write_sandbox_output(
1676 memory,
1677 out_ptr,
1678 out_len_ptr,
1679 &caller.encode(),
1680 false,
1681 already_charged,
1682 )?)
1683 }
1684
1685 #[prefixed_alias]
1688 fn is_contract(ctx: _, memory: _, account_ptr: u32) -> Result<u32, TrapReason> {
1689 ctx.charge_gas(RuntimeCosts::IsContract)?;
1690 let address: <<E as Ext>::T as frame_system::Config>::AccountId =
1691 ctx.read_sandbox_memory_as(memory, account_ptr)?;
1692
1693 Ok(ctx.ext.is_contract(&address) as u32)
1694 }
1695
1696 #[prefixed_alias]
1699 fn code_hash(
1700 ctx: _,
1701 memory: _,
1702 account_ptr: u32,
1703 out_ptr: u32,
1704 out_len_ptr: u32,
1705 ) -> Result<ReturnErrorCode, TrapReason> {
1706 ctx.charge_gas(RuntimeCosts::CodeHash)?;
1707 let address: <<E as Ext>::T as frame_system::Config>::AccountId =
1708 ctx.read_sandbox_memory_as(memory, account_ptr)?;
1709 if let Some(value) = ctx.ext.code_hash(&address) {
1710 ctx.write_sandbox_output(
1711 memory,
1712 out_ptr,
1713 out_len_ptr,
1714 &value.encode(),
1715 false,
1716 already_charged,
1717 )?;
1718 Ok(ReturnErrorCode::Success)
1719 } else {
1720 Ok(ReturnErrorCode::KeyNotFound)
1721 }
1722 }
1723
1724 #[prefixed_alias]
1727 fn own_code_hash(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1728 ctx.charge_gas(RuntimeCosts::OwnCodeHash)?;
1729 let code_hash_encoded = &ctx.ext.own_code_hash().encode();
1730 Ok(ctx.write_sandbox_output(
1731 memory,
1732 out_ptr,
1733 out_len_ptr,
1734 code_hash_encoded,
1735 false,
1736 already_charged,
1737 )?)
1738 }
1739
1740 #[prefixed_alias]
1743 fn caller_is_origin(ctx: _, _memory: _) -> Result<u32, TrapReason> {
1744 ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?;
1745 Ok(ctx.ext.caller_is_origin() as u32)
1746 }
1747
1748 fn caller_is_root(ctx: _, _memory: _) -> Result<u32, TrapReason> {
1751 ctx.charge_gas(RuntimeCosts::CallerIsRoot)?;
1752 Ok(ctx.ext.caller_is_root() as u32)
1753 }
1754
1755 #[prefixed_alias]
1758 fn address(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1759 ctx.charge_gas(RuntimeCosts::Address)?;
1760 Ok(ctx.write_sandbox_output(
1761 memory,
1762 out_ptr,
1763 out_len_ptr,
1764 &ctx.ext.address().encode(),
1765 false,
1766 already_charged,
1767 )?)
1768 }
1769
1770 #[prefixed_alias]
1773 fn weight_to_fee(
1774 ctx: _,
1775 memory: _,
1776 gas: u64,
1777 out_ptr: u32,
1778 out_len_ptr: u32,
1779 ) -> Result<(), TrapReason> {
1780 let gas = Weight::from_parts(gas, 0);
1781 ctx.charge_gas(RuntimeCosts::WeightToFee)?;
1782 Ok(ctx.write_sandbox_output(
1783 memory,
1784 out_ptr,
1785 out_len_ptr,
1786 &ctx.ext.get_weight_price(gas).encode(),
1787 false,
1788 already_charged,
1789 )?)
1790 }
1791
1792 #[version(1)]
1795 #[unstable]
1796 fn weight_to_fee(
1797 ctx: _,
1798 memory: _,
1799 ref_time_limit: u64,
1800 proof_size_limit: u64,
1801 out_ptr: u32,
1802 out_len_ptr: u32,
1803 ) -> Result<(), TrapReason> {
1804 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
1805 ctx.charge_gas(RuntimeCosts::WeightToFee)?;
1806 Ok(ctx.write_sandbox_output(
1807 memory,
1808 out_ptr,
1809 out_len_ptr,
1810 &ctx.ext.get_weight_price(weight).encode(),
1811 false,
1812 already_charged,
1813 )?)
1814 }
1815
1816 #[prefixed_alias]
1819 fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1820 ctx.charge_gas(RuntimeCosts::GasLeft)?;
1821 let gas_left = &ctx.ext.gas_meter().gas_left().ref_time().encode();
1822 Ok(ctx.write_sandbox_output(
1823 memory,
1824 out_ptr,
1825 out_len_ptr,
1826 gas_left,
1827 false,
1828 already_charged,
1829 )?)
1830 }
1831
1832 #[version(1)]
1835 #[unstable]
1836 fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1837 ctx.charge_gas(RuntimeCosts::GasLeft)?;
1838 let gas_left = &ctx.ext.gas_meter().gas_left().encode();
1839 Ok(ctx.write_sandbox_output(
1840 memory,
1841 out_ptr,
1842 out_len_ptr,
1843 gas_left,
1844 false,
1845 already_charged,
1846 )?)
1847 }
1848
1849 #[prefixed_alias]
1852 fn balance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1853 ctx.charge_gas(RuntimeCosts::Balance)?;
1854 Ok(ctx.write_sandbox_output(
1855 memory,
1856 out_ptr,
1857 out_len_ptr,
1858 &ctx.ext.balance().encode(),
1859 false,
1860 already_charged,
1861 )?)
1862 }
1863
1864 #[prefixed_alias]
1867 fn value_transferred(
1868 ctx: _,
1869 memory: _,
1870 out_ptr: u32,
1871 out_len_ptr: u32,
1872 ) -> Result<(), TrapReason> {
1873 ctx.charge_gas(RuntimeCosts::ValueTransferred)?;
1874 Ok(ctx.write_sandbox_output(
1875 memory,
1876 out_ptr,
1877 out_len_ptr,
1878 &ctx.ext.value_transferred().encode(),
1879 false,
1880 already_charged,
1881 )?)
1882 }
1883
1884 #[prefixed_alias]
1893 #[deprecated]
1894 fn random(
1895 ctx: _,
1896 memory: _,
1897 subject_ptr: u32,
1898 subject_len: u32,
1899 out_ptr: u32,
1900 out_len_ptr: u32,
1901 ) -> Result<(), TrapReason> {
1902 ctx.charge_gas(RuntimeCosts::Random)?;
1903 if subject_len > ctx.ext.schedule().limits.subject_len {
1904 return Err(Error::<E::T>::RandomSubjectTooLong.into())
1905 }
1906 let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
1907 Ok(ctx.write_sandbox_output(
1908 memory,
1909 out_ptr,
1910 out_len_ptr,
1911 &ctx.ext.random(&subject_buf).0.encode(),
1912 false,
1913 already_charged,
1914 )?)
1915 }
1916
1917 #[version(1)]
1939 #[prefixed_alias]
1940 #[deprecated]
1941 fn random(
1942 ctx: _,
1943 memory: _,
1944 subject_ptr: u32,
1945 subject_len: u32,
1946 out_ptr: u32,
1947 out_len_ptr: u32,
1948 ) -> Result<(), TrapReason> {
1949 ctx.charge_gas(RuntimeCosts::Random)?;
1950 if subject_len > ctx.ext.schedule().limits.subject_len {
1951 return Err(Error::<E::T>::RandomSubjectTooLong.into())
1952 }
1953 let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
1954 Ok(ctx.write_sandbox_output(
1955 memory,
1956 out_ptr,
1957 out_len_ptr,
1958 &ctx.ext.random(&subject_buf).encode(),
1959 false,
1960 already_charged,
1961 )?)
1962 }
1963
1964 #[prefixed_alias]
1967 fn now(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1968 ctx.charge_gas(RuntimeCosts::Now)?;
1969 Ok(ctx.write_sandbox_output(
1970 memory,
1971 out_ptr,
1972 out_len_ptr,
1973 &ctx.ext.now().encode(),
1974 false,
1975 already_charged,
1976 )?)
1977 }
1978
1979 #[prefixed_alias]
1982 fn minimum_balance(
1983 ctx: _,
1984 memory: _,
1985 out_ptr: u32,
1986 out_len_ptr: u32,
1987 ) -> Result<(), TrapReason> {
1988 ctx.charge_gas(RuntimeCosts::MinimumBalance)?;
1989 Ok(ctx.write_sandbox_output(
1990 memory,
1991 out_ptr,
1992 out_len_ptr,
1993 &ctx.ext.minimum_balance().encode(),
1994 false,
1995 already_charged,
1996 )?)
1997 }
1998
1999 #[prefixed_alias]
2010 #[deprecated]
2011 fn tombstone_deposit(
2012 ctx: _,
2013 memory: _,
2014 out_ptr: u32,
2015 out_len_ptr: u32,
2016 ) -> Result<(), TrapReason> {
2017 ctx.charge_gas(RuntimeCosts::Balance)?;
2018 let deposit = <BalanceOf<E::T>>::zero().encode();
2019 Ok(ctx.write_sandbox_output(
2020 memory,
2021 out_ptr,
2022 out_len_ptr,
2023 &deposit,
2024 false,
2025 already_charged,
2026 )?)
2027 }
2028
2029 #[prefixed_alias]
2036 #[deprecated]
2037 fn restore_to(
2038 ctx: _,
2039 memory: _,
2040 _dest_ptr: u32,
2041 _dest_len: u32,
2042 _code_hash_ptr: u32,
2043 _code_hash_len: u32,
2044 _rent_allowance_ptr: u32,
2045 _rent_allowance_len: u32,
2046 _delta_ptr: u32,
2047 _delta_count: u32,
2048 ) -> Result<(), TrapReason> {
2049 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2050 Ok(())
2051 }
2052
2053 #[version(1)]
2060 #[prefixed_alias]
2061 #[deprecated]
2062 fn restore_to(
2063 ctx: _,
2064 memory: _,
2065 _dest_ptr: u32,
2066 _code_hash_ptr: u32,
2067 _rent_allowance_ptr: u32,
2068 _delta_ptr: u32,
2069 _delta_count: u32,
2070 ) -> Result<(), TrapReason> {
2071 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2072 Ok(())
2073 }
2074
2075 #[prefixed_alias]
2082 #[deprecated]
2083 fn set_rent_allowance(
2084 ctx: _,
2085 memory: _,
2086 _value_ptr: u32,
2087 _value_len: u32,
2088 ) -> Result<(), TrapReason> {
2089 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2090 Ok(())
2091 }
2092
2093 #[version(1)]
2100 #[prefixed_alias]
2101 #[deprecated]
2102 fn set_rent_allowance(ctx: _, _memory: _, _value_ptr: u32) -> Result<(), TrapReason> {
2103 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2104 Ok(())
2105 }
2106
2107 #[prefixed_alias]
2114 #[deprecated]
2115 fn rent_allowance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
2116 ctx.charge_gas(RuntimeCosts::Balance)?;
2117 let rent_allowance = <BalanceOf<E::T>>::max_value().encode();
2118 Ok(ctx.write_sandbox_output(
2119 memory,
2120 out_ptr,
2121 out_len_ptr,
2122 &rent_allowance,
2123 false,
2124 already_charged,
2125 )?)
2126 }
2127
2128 #[prefixed_alias]
2131 #[mutating]
2132 fn deposit_event(
2133 ctx: _,
2134 memory: _,
2135 topics_ptr: u32,
2136 topics_len: u32,
2137 data_ptr: u32,
2138 data_len: u32,
2139 ) -> Result<(), TrapReason> {
2140 let num_topic = topics_len
2141 .checked_div(core::mem::size_of::<TopicOf<E::T>>() as u32)
2142 .ok_or("Zero sized topics are not allowed")?;
2143 ctx.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?;
2144 if data_len > ctx.ext.max_value_size() {
2145 return Err(Error::<E::T>::ValueTooLarge.into())
2146 }
2147
2148 let topics: Vec<TopicOf<<E as Ext>::T>> = match topics_len {
2149 0 => Vec::new(),
2150 _ => ctx.read_sandbox_memory_as_unbounded(memory, topics_ptr, topics_len)?,
2151 };
2152
2153 if topics.len() > ctx.ext.schedule().limits.event_topics as usize {
2155 return Err(Error::<E::T>::TooManyTopics.into())
2156 }
2157
2158 let event_data = ctx.read_sandbox_memory(memory, data_ptr, data_len)?;
2159
2160 ctx.ext.deposit_event(topics, event_data);
2161
2162 Ok(())
2163 }
2164
2165 #[prefixed_alias]
2168 fn block_number(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
2169 ctx.charge_gas(RuntimeCosts::BlockNumber)?;
2170 Ok(ctx.write_sandbox_output(
2171 memory,
2172 out_ptr,
2173 out_len_ptr,
2174 &ctx.ext.block_number().encode(),
2175 false,
2176 already_charged,
2177 )?)
2178 }
2179
2180 #[prefixed_alias]
2183 fn hash_sha2_256(
2184 ctx: _,
2185 memory: _,
2186 input_ptr: u32,
2187 input_len: u32,
2188 output_ptr: u32,
2189 ) -> Result<(), TrapReason> {
2190 ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?;
2191 Ok(ctx.compute_hash_on_intermediate_buffer(
2192 memory, sha2_256, input_ptr, input_len, output_ptr,
2193 )?)
2194 }
2195
2196 #[prefixed_alias]
2199 fn hash_keccak_256(
2200 ctx: _,
2201 memory: _,
2202 input_ptr: u32,
2203 input_len: u32,
2204 output_ptr: u32,
2205 ) -> Result<(), TrapReason> {
2206 ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
2207 Ok(ctx.compute_hash_on_intermediate_buffer(
2208 memory, keccak_256, input_ptr, input_len, output_ptr,
2209 )?)
2210 }
2211
2212 #[prefixed_alias]
2215 fn hash_blake2_256(
2216 ctx: _,
2217 memory: _,
2218 input_ptr: u32,
2219 input_len: u32,
2220 output_ptr: u32,
2221 ) -> Result<(), TrapReason> {
2222 ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?;
2223 Ok(ctx.compute_hash_on_intermediate_buffer(
2224 memory, blake2_256, input_ptr, input_len, output_ptr,
2225 )?)
2226 }
2227
2228 #[prefixed_alias]
2231 fn hash_blake2_128(
2232 ctx: _,
2233 memory: _,
2234 input_ptr: u32,
2235 input_len: u32,
2236 output_ptr: u32,
2237 ) -> Result<(), TrapReason> {
2238 ctx.charge_gas(RuntimeCosts::HashBlake128(input_len))?;
2239 Ok(ctx.compute_hash_on_intermediate_buffer(
2240 memory, blake2_128, input_ptr, input_len, output_ptr,
2241 )?)
2242 }
2243
2244 #[prefixed_alias]
2247 fn call_chain_extension(
2248 ctx: _,
2249 memory: _,
2250 id: u32,
2251 input_ptr: u32,
2252 input_len: u32,
2253 output_ptr: u32,
2254 output_len_ptr: u32,
2255 ) -> Result<u32, TrapReason> {
2256 use crate::chain_extension::{ChainExtension, Environment, RetVal};
2257 if !<E::T as Config>::ChainExtension::enabled() {
2258 return Err(Error::<E::T>::NoChainExtension.into())
2259 }
2260 let mut chain_extension = ctx.chain_extension.take().expect(
2261 "Constructor initializes with `Some`. This is the only place where it is set to `None`.\
2262 It is always reset to `Some` afterwards. qed"
2263 );
2264 let env =
2265 Environment::new(ctx, memory, id, input_ptr, input_len, output_ptr, output_len_ptr);
2266 let ret = match chain_extension.call(env)? {
2267 RetVal::Converging(val) => Ok(val),
2268 RetVal::Diverging { flags, data } =>
2269 Err(TrapReason::Return(ReturnData { flags: flags.bits(), data })),
2270 };
2271 ctx.chain_extension = Some(chain_extension);
2272 ret
2273 }
2274
2275 #[prefixed_alias]
2293 fn debug_message(
2294 ctx: _,
2295 memory: _,
2296 str_ptr: u32,
2297 str_len: u32,
2298 ) -> Result<ReturnErrorCode, TrapReason> {
2299 let str_len = str_len.min(DebugBufferVec::<E::T>::bound() as u32);
2300 ctx.charge_gas(RuntimeCosts::DebugMessage(str_len))?;
2301 if ctx.ext.append_debug_buffer("") {
2302 let data = ctx.read_sandbox_memory(memory, str_ptr, str_len)?;
2303 if let Some(msg) = core::str::from_utf8(&data).ok() {
2304 ctx.ext.append_debug_buffer(msg);
2305 }
2306 }
2307 Ok(ReturnErrorCode::Success)
2308 }
2309
2310 #[mutating]
2313 fn call_runtime(
2314 ctx: _,
2315 memory: _,
2316 call_ptr: u32,
2317 call_len: u32,
2318 ) -> Result<ReturnErrorCode, TrapReason> {
2319 use frame_support::dispatch::GetDispatchInfo;
2320 ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?;
2321 let call: <E::T as Config>::RuntimeCall =
2322 ctx.read_sandbox_memory_as_unbounded(memory, call_ptr, call_len)?;
2323 ctx.call_dispatchable::<CallRuntimeFailed>(
2324 call.get_dispatch_info(),
2325 RuntimeCosts::CallRuntime,
2326 |ctx| ctx.ext.call_runtime(call),
2327 )
2328 }
2329
2330 #[mutating]
2333 fn xcm_execute(
2334 ctx: _,
2335 memory: _,
2336 msg_ptr: u32,
2337 msg_len: u32,
2338 ) -> Result<ReturnErrorCode, TrapReason> {
2339 use frame_support::dispatch::DispatchInfo;
2340 use xcm::VersionedXcm;
2341 use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo};
2342
2343 ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
2344 let message: VersionedXcm<CallOf<E::T>> =
2345 ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
2346
2347 let execute_weight =
2348 <<E::T as Config>::Xcm as ExecuteController<_, _>>::WeightInfo::execute();
2349 let weight = ctx.ext.gas_meter().gas_left().max(execute_weight);
2350 let dispatch_info = DispatchInfo { call_weight: weight, ..Default::default() };
2351
2352 ctx.call_dispatchable::<XcmExecutionFailed>(
2353 dispatch_info,
2354 RuntimeCosts::CallXcmExecute,
2355 |ctx| {
2356 let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
2357 let weight_used = <<E::T as Config>::Xcm>::execute(
2358 origin,
2359 Box::new(message),
2360 weight.saturating_sub(execute_weight),
2361 )?;
2362
2363 Ok(Some(weight_used.saturating_add(execute_weight)).into())
2364 },
2365 )
2366 }
2367
2368 #[mutating]
2371 fn xcm_send(
2372 ctx: _,
2373 memory: _,
2374 dest_ptr: u32,
2375 msg_ptr: u32,
2376 msg_len: u32,
2377 output_ptr: u32,
2378 ) -> Result<ReturnErrorCode, TrapReason> {
2379 use xcm::{VersionedLocation, VersionedXcm};
2380 use xcm_builder::{SendController, SendControllerWeightInfo};
2381
2382 ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
2383 let dest: VersionedLocation = ctx.read_sandbox_memory_as(memory, dest_ptr)?;
2384
2385 let message: VersionedXcm<()> =
2386 ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
2387 let weight = <<E::T as Config>::Xcm as SendController<_>>::WeightInfo::send();
2388 ctx.charge_gas(RuntimeCosts::CallRuntime(weight))?;
2389 let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
2390
2391 match <<E::T as Config>::Xcm>::send(origin, dest.into(), message.into()) {
2392 Ok(message_id) => {
2393 ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?;
2394 Ok(ReturnErrorCode::Success)
2395 },
2396 Err(e) => {
2397 if ctx.ext.append_debug_buffer("") {
2398 ctx.ext.append_debug_buffer("seal0::xcm_send failed with: ");
2399 ctx.ext.append_debug_buffer(e.into());
2400 };
2401 Ok(ReturnErrorCode::XcmSendFailed)
2402 },
2403 }
2404 }
2405
2406 #[prefixed_alias]
2409 fn ecdsa_recover(
2410 ctx: _,
2411 memory: _,
2412 signature_ptr: u32,
2413 message_hash_ptr: u32,
2414 output_ptr: u32,
2415 ) -> Result<ReturnErrorCode, TrapReason> {
2416 ctx.charge_gas(RuntimeCosts::EcdsaRecovery)?;
2417
2418 let mut signature: [u8; 65] = [0; 65];
2419 ctx.read_sandbox_memory_into_buf(memory, signature_ptr, &mut signature)?;
2420 let mut message_hash: [u8; 32] = [0; 32];
2421 ctx.read_sandbox_memory_into_buf(memory, message_hash_ptr, &mut message_hash)?;
2422
2423 let result = ctx.ext.ecdsa_recover(&signature, &message_hash);
2424
2425 match result {
2426 Ok(pub_key) => {
2427 ctx.write_sandbox_memory(memory, output_ptr, pub_key.as_ref())?;
2430
2431 Ok(ReturnErrorCode::Success)
2432 },
2433 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
2434 }
2435 }
2436
2437 fn sr25519_verify(
2440 ctx: _,
2441 memory: _,
2442 signature_ptr: u32,
2443 pub_key_ptr: u32,
2444 message_len: u32,
2445 message_ptr: u32,
2446 ) -> Result<ReturnErrorCode, TrapReason> {
2447 ctx.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?;
2448
2449 let mut signature: [u8; 64] = [0; 64];
2450 ctx.read_sandbox_memory_into_buf(memory, signature_ptr, &mut signature)?;
2451
2452 let mut pub_key: [u8; 32] = [0; 32];
2453 ctx.read_sandbox_memory_into_buf(memory, pub_key_ptr, &mut pub_key)?;
2454
2455 let message: Vec<u8> = ctx.read_sandbox_memory(memory, message_ptr, message_len)?;
2456
2457 if ctx.ext.sr25519_verify(&signature, &message, &pub_key) {
2458 Ok(ReturnErrorCode::Success)
2459 } else {
2460 Ok(ReturnErrorCode::Sr25519VerifyFailed)
2461 }
2462 }
2463
2464 #[prefixed_alias]
2467 #[mutating]
2468 fn set_code_hash(ctx: _, memory: _, code_hash_ptr: u32) -> Result<ReturnErrorCode, TrapReason> {
2469 ctx.charge_gas(RuntimeCosts::SetCodeHash)?;
2470 let code_hash: CodeHash<<E as Ext>::T> =
2471 ctx.read_sandbox_memory_as(memory, code_hash_ptr)?;
2472 match ctx.ext.set_code_hash(code_hash) {
2473 Err(err) => {
2474 let code = Runtime::<E>::err_into_return_code(err)?;
2475 Ok(code)
2476 },
2477 Ok(()) => Ok(ReturnErrorCode::Success),
2478 }
2479 }
2480
2481 #[prefixed_alias]
2484 fn ecdsa_to_eth_address(
2485 ctx: _,
2486 memory: _,
2487 key_ptr: u32,
2488 out_ptr: u32,
2489 ) -> Result<ReturnErrorCode, TrapReason> {
2490 ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?;
2491 let mut compressed_key: [u8; 33] = [0; 33];
2492 ctx.read_sandbox_memory_into_buf(memory, key_ptr, &mut compressed_key)?;
2493 let result = ctx.ext.ecdsa_to_eth_address(&compressed_key);
2494 match result {
2495 Ok(eth_address) => {
2496 ctx.write_sandbox_memory(memory, out_ptr, eth_address.as_ref())?;
2497 Ok(ReturnErrorCode::Success)
2498 },
2499 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
2500 }
2501 }
2502
2503 #[unstable]
2507 fn reentrance_count(ctx: _, memory: _) -> Result<u32, TrapReason> {
2508 ctx.charge_gas(RuntimeCosts::ReentranceCount)?;
2509 Ok(ctx.ext.reentrance_count())
2510 }
2511
2512 #[unstable]
2516 fn account_reentrance_count(ctx: _, memory: _, account_ptr: u32) -> Result<u32, TrapReason> {
2517 ctx.charge_gas(RuntimeCosts::AccountReentranceCount)?;
2518 let account_id: <<E as Ext>::T as frame_system::Config>::AccountId =
2519 ctx.read_sandbox_memory_as(memory, account_ptr)?;
2520 Ok(ctx.ext.account_reentrance_count(&account_id))
2521 }
2522
2523 fn instantiation_nonce(ctx: _, _memory: _) -> Result<u64, TrapReason> {
2526 ctx.charge_gas(RuntimeCosts::InstantiationNonce)?;
2527 Ok(ctx.ext.nonce())
2528 }
2529
2530 #[mutating]
2533 fn lock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> {
2534 ctx.charge_gas(RuntimeCosts::LockDelegateDependency)?;
2535 let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?;
2536 ctx.ext.lock_delegate_dependency(code_hash)?;
2537 Ok(())
2538 }
2539
2540 #[mutating]
2543 fn unlock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> {
2544 ctx.charge_gas(RuntimeCosts::UnlockDelegateDependency)?;
2545 let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?;
2546 ctx.ext.unlock_delegate_dependency(&code_hash)?;
2547 Ok(())
2548 }
2549}