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 Debug, DispatchError,
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(Debug)]
107pub struct ReturnData {
108 flags: u32,
111 data: Vec<u8>,
113}
114
115#[derive(Debug)]
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 },
343 ClearStorage(len) => cost_storage!(write, seal_clear_storage, len),
344 ContainsStorage(len) => cost_storage!(read, seal_contains_storage, len),
345 GetStorage(len) => cost_storage!(read, seal_get_storage, len),
346 TakeStorage(len) => cost_storage!(write, seal_take_storage, len),
347 SetTransientStorage { new_bytes, old_bytes } => {
348 cost_storage!(write_transient, seal_set_transient_storage, new_bytes, old_bytes)
349 },
350 ClearTransientStorage(len) => {
351 cost_storage!(write_transient, seal_clear_transient_storage, len)
352 },
353 ContainsTransientStorage(len) => {
354 cost_storage!(read_transient, seal_contains_transient_storage, len)
355 },
356 GetTransientStorage(len) => {
357 cost_storage!(read_transient, seal_get_transient_storage, len)
358 },
359 TakeTransientStorage(len) => {
360 cost_storage!(write_transient, seal_take_transient_storage, len)
361 },
362 Transfer => T::WeightInfo::seal_transfer(),
363 CallBase => T::WeightInfo::seal_call(0, 0),
364 DelegateCallBase => T::WeightInfo::seal_delegate_call(),
365 CallTransferSurcharge => cost_args!(seal_call, 1, 0),
366 CallInputCloned(len) => cost_args!(seal_call, 0, len),
367 Instantiate { input_data_len, salt_len } => {
368 T::WeightInfo::seal_instantiate(input_data_len, salt_len)
369 },
370 HashSha256(len) => T::WeightInfo::seal_hash_sha2_256(len),
371 HashKeccak256(len) => T::WeightInfo::seal_hash_keccak_256(len),
372 HashBlake256(len) => T::WeightInfo::seal_hash_blake2_256(len),
373 HashBlake128(len) => T::WeightInfo::seal_hash_blake2_128(len),
374 EcdsaRecovery => T::WeightInfo::seal_ecdsa_recover(),
375 Sr25519Verify(len) => T::WeightInfo::seal_sr25519_verify(len),
376 ChainExtension(weight) | CallRuntime(weight) | CallXcmExecute(weight) => weight,
377 SetCodeHash => T::WeightInfo::seal_set_code_hash(),
378 EcdsaToEthAddress => T::WeightInfo::seal_ecdsa_to_eth_address(),
379 ReentranceCount => T::WeightInfo::seal_reentrance_count(),
380 AccountReentranceCount => T::WeightInfo::seal_account_reentrance_count(),
381 InstantiationNonce => T::WeightInfo::seal_instantiation_nonce(),
382 LockDelegateDependency => T::WeightInfo::lock_delegate_dependency(),
383 UnlockDelegateDependency => T::WeightInfo::unlock_delegate_dependency(),
384 }
385 }
386}
387
388macro_rules! charge_gas {
393 ($runtime:expr, $costs:expr) => {{
394 $runtime.ext.gas_meter_mut().charge($costs)
395 }};
396}
397
398enum CallType {
400 Call { callee_ptr: u32, value_ptr: u32, deposit_ptr: u32, weight: Weight },
402 DelegateCall { code_hash_ptr: u32 },
404}
405
406impl CallType {
407 fn cost(&self) -> RuntimeCosts {
408 match self {
409 CallType::Call { .. } => RuntimeCosts::CallBase,
410 CallType::DelegateCall { .. } => RuntimeCosts::DelegateCallBase,
411 }
412 }
413}
414
415fn already_charged(_: u32) -> Option<RuntimeCosts> {
419 None
420}
421
422pub struct Runtime<'a, E: Ext + 'a> {
424 ext: &'a mut E,
425 input_data: Option<Vec<u8>>,
426 memory: Option<Memory>,
427 chain_extension: Option<Box<<E::T as Config>::ChainExtension>>,
428}
429
430impl<'a, E: Ext + 'a> Runtime<'a, E> {
431 pub fn new(ext: &'a mut E, input_data: Vec<u8>) -> Self {
432 Runtime {
433 ext,
434 input_data: Some(input_data),
435 memory: None,
436 chain_extension: Some(Box::new(Default::default())),
437 }
438 }
439
440 pub fn memory(&self) -> Option<Memory> {
441 self.memory
442 }
443
444 pub fn set_memory(&mut self, memory: Memory) {
445 self.memory = Some(memory);
446 }
447
448 pub fn to_execution_result(self, sandbox_result: Result<(), wasmi::Error>) -> ExecResult {
450 use wasmi::{
451 core::TrapCode,
452 errors::{ErrorKind, FuelError},
453 };
454 use TrapReason::*;
455
456 let Err(error) = sandbox_result else {
457 return Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() });
459 };
460 if let ErrorKind::Fuel(FuelError::OutOfFuel) = error.kind() {
461 return Err(Error::<E::T>::OutOfGas.into());
465 }
466 match error.as_trap_code() {
467 Some(TrapCode::OutOfFuel) => {
468 return Err(Error::<E::T>::OutOfGas.into());
470 },
471 Some(_trap_code) => {
472 return Err(Error::<E::T>::ContractTrapped.into());
474 },
475 None => {},
476 }
477 if let Some(reason) = &error.downcast_ref::<TrapReason>() {
479 match &reason {
480 Return(ReturnData { flags, data }) => {
481 let flags =
482 ReturnFlags::from_bits(*flags).ok_or(Error::<E::T>::InvalidCallFlags)?;
483 return Ok(ExecReturnValue { flags, data: data.to_vec() });
484 },
485 Termination => {
486 return Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Vec::new() })
487 },
488 SupervisorError(error) => return Err((*error).into()),
489 }
490 }
491
492 log::debug!("Code rejected: {:?}", error);
499 Err(Error::<E::T>::CodeRejected.into())
500 }
501
502 pub fn ext(&mut self) -> &mut E {
507 self.ext
508 }
509
510 pub fn charge_gas(&mut self, costs: RuntimeCosts) -> Result<ChargedAmount, DispatchError> {
514 charge_gas!(self, costs)
515 }
516
517 pub fn adjust_gas(&mut self, charged: ChargedAmount, actual_costs: RuntimeCosts) {
522 self.ext.gas_meter_mut().adjust_gas(charged, actual_costs);
523 }
524
525 fn call_dispatchable<ErrorReturnCode: Get<ReturnErrorCode>>(
527 &mut self,
528 dispatch_info: DispatchInfo,
529 runtime_cost: impl Fn(Weight) -> RuntimeCosts,
530 run: impl FnOnce(&mut Self) -> DispatchResultWithPostInfo,
531 ) -> Result<ReturnErrorCode, TrapReason> {
532 use frame_support::dispatch::extract_actual_weight;
533 let charged = self.charge_gas(runtime_cost(dispatch_info.call_weight))?;
534 let result = run(self);
535 let actual_weight = extract_actual_weight(&result, &dispatch_info);
536 self.adjust_gas(charged, runtime_cost(actual_weight));
537 match result {
538 Ok(_) => Ok(ReturnErrorCode::Success),
539 Err(e) => {
540 if self.ext.debug_buffer_enabled() {
541 self.ext.append_debug_buffer("call failed with: ");
542 self.ext.append_debug_buffer(e.into());
543 };
544 Ok(ErrorReturnCode::get())
545 },
546 }
547 }
548
549 pub fn read_sandbox_memory(
555 &self,
556 memory: &[u8],
557 ptr: u32,
558 len: u32,
559 ) -> Result<Vec<u8>, DispatchError> {
560 ensure!(len <= self.ext.schedule().limits.max_memory_size(), Error::<E::T>::OutOfBounds);
561 let mut buf = vec![0u8; len as usize];
562 self.read_sandbox_memory_into_buf(memory, ptr, buf.as_mut_slice())?;
563 Ok(buf)
564 }
565
566 pub fn read_sandbox_memory_into_buf(
572 &self,
573 memory: &[u8],
574 ptr: u32,
575 buf: &mut [u8],
576 ) -> Result<(), DispatchError> {
577 let ptr = ptr as usize;
578 let bound_checked =
579 memory.get(ptr..ptr + buf.len()).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
580 buf.copy_from_slice(bound_checked);
581 Ok(())
582 }
583
584 pub fn read_sandbox_memory_as<D: Decode + MaxEncodedLen>(
591 &self,
592 memory: &[u8],
593 ptr: u32,
594 ) -> Result<D, DispatchError> {
595 let ptr = ptr as usize;
596 let mut bound_checked = memory.get(ptr..).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
597
598 let decoded = D::decode_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked)
599 .map_err(|_| DispatchError::from(Error::<E::T>::DecodingFailed))?;
600 Ok(decoded)
601 }
602
603 pub fn read_sandbox_memory_as_unbounded<D: Decode>(
615 &self,
616 memory: &[u8],
617 ptr: u32,
618 len: u32,
619 ) -> Result<D, DispatchError> {
620 let ptr = ptr as usize;
621 let mut bound_checked =
622 memory.get(ptr..ptr + len as usize).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
623
624 let decoded = D::decode_all_with_depth_limit(MAX_DECODE_NESTING, &mut bound_checked)
625 .map_err(|_| DispatchError::from(Error::<E::T>::DecodingFailed))?;
626
627 Ok(decoded)
628 }
629
630 pub fn write_sandbox_output(
650 &mut self,
651 memory: &mut [u8],
652 out_ptr: u32,
653 out_len_ptr: u32,
654 buf: &[u8],
655 allow_skip: bool,
656 create_token: impl FnOnce(u32) -> Option<RuntimeCosts>,
657 ) -> Result<(), DispatchError> {
658 if allow_skip && out_ptr == SENTINEL {
659 return Ok(());
660 }
661
662 let buf_len = buf.len() as u32;
663 let len: u32 = self.read_sandbox_memory_as(memory, out_len_ptr)?;
664
665 if len < buf_len {
666 return Err(Error::<E::T>::OutputBufferTooSmall.into());
667 }
668
669 if let Some(costs) = create_token(buf_len) {
670 self.charge_gas(costs)?;
671 }
672
673 self.write_sandbox_memory(memory, out_ptr, buf)?;
674 self.write_sandbox_memory(memory, out_len_ptr, &buf_len.encode())
675 }
676
677 fn write_sandbox_memory(
683 &self,
684 memory: &mut [u8],
685 ptr: u32,
686 buf: &[u8],
687 ) -> Result<(), DispatchError> {
688 let ptr = ptr as usize;
689 let bound_checked =
690 memory.get_mut(ptr..ptr + buf.len()).ok_or_else(|| Error::<E::T>::OutOfBounds)?;
691 bound_checked.copy_from_slice(buf);
692 Ok(())
693 }
694
695 fn compute_hash_on_intermediate_buffer<F, R>(
708 &self,
709 memory: &mut [u8],
710 hash_fn: F,
711 input_ptr: u32,
712 input_len: u32,
713 output_ptr: u32,
714 ) -> Result<(), DispatchError>
715 where
716 F: FnOnce(&[u8]) -> R,
717 R: AsRef<[u8]>,
718 {
719 let input = self.read_sandbox_memory(memory, input_ptr, input_len)?;
721 let hash = hash_fn(&input);
723 self.write_sandbox_memory(memory, output_ptr, hash.as_ref())?;
725 Ok(())
726 }
727
728 fn err_into_return_code(from: DispatchError) -> Result<ReturnErrorCode, DispatchError> {
730 use ReturnErrorCode::*;
731
732 let transfer_failed = Error::<E::T>::TransferFailed.into();
733 let no_code = Error::<E::T>::CodeNotFound.into();
734 let not_found = Error::<E::T>::ContractNotFound.into();
735
736 match from {
737 x if x == transfer_failed => Ok(TransferFailed),
738 x if x == no_code => Ok(CodeNotFound),
739 x if x == not_found => Ok(NotCallable),
740 err => Err(err),
741 }
742 }
743
744 fn exec_into_return_code(from: ExecResult) -> Result<ReturnErrorCode, DispatchError> {
746 use crate::exec::ErrorOrigin::Callee;
747
748 let ExecError { error, origin } = match from {
749 Ok(retval) => return Ok(retval.into()),
750 Err(err) => err,
751 };
752
753 match (error, origin) {
754 (_, Callee) => Ok(ReturnErrorCode::CalleeTrapped),
755 (err, _) => Self::err_into_return_code(err),
756 }
757 }
758 fn decode_key(
759 &self,
760 memory: &[u8],
761 key_type: KeyType,
762 key_ptr: u32,
763 ) -> Result<crate::exec::Key<E::T>, TrapReason> {
764 let res = match key_type {
765 KeyType::Fix => {
766 let key = self.read_sandbox_memory(memory, key_ptr, 32u32)?;
767 Key::try_from_fix(key)
768 },
769 KeyType::Var(len) => {
770 ensure!(
771 len <= <<E as Ext>::T as Config>::MaxStorageKeyLen::get(),
772 Error::<E::T>::DecodingFailed
773 );
774 let key = self.read_sandbox_memory(memory, key_ptr, len)?;
775 Key::try_from_var(key)
776 },
777 };
778
779 res.map_err(|_| Error::<E::T>::DecodingFailed.into())
780 }
781
782 fn set_storage(
783 &mut self,
784 memory: &[u8],
785 key_type: KeyType,
786 key_ptr: u32,
787 value_ptr: u32,
788 value_len: u32,
789 ) -> Result<u32, TrapReason> {
790 let max_size = self.ext.max_value_size();
791 let charged = self
792 .charge_gas(RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: max_size })?;
793 if value_len > max_size {
794 return Err(Error::<E::T>::ValueTooLarge.into());
795 }
796 let key = self.decode_key(memory, key_type, key_ptr)?;
797 let value = Some(self.read_sandbox_memory(memory, value_ptr, value_len)?);
798 let write_outcome = self.ext.set_storage(&key, value, false)?;
799
800 self.adjust_gas(
801 charged,
802 RuntimeCosts::SetStorage { new_bytes: value_len, old_bytes: write_outcome.old_len() },
803 );
804 Ok(write_outcome.old_len_with_sentinel())
805 }
806
807 fn clear_storage(
808 &mut self,
809 memory: &[u8],
810 key_type: KeyType,
811 key_ptr: u32,
812 ) -> Result<u32, TrapReason> {
813 let charged = self.charge_gas(RuntimeCosts::ClearStorage(self.ext.max_value_size()))?;
814 let key = self.decode_key(memory, key_type, key_ptr)?;
815 let outcome = self.ext.set_storage(&key, None, false)?;
816
817 self.adjust_gas(charged, RuntimeCosts::ClearStorage(outcome.old_len()));
818 Ok(outcome.old_len_with_sentinel())
819 }
820
821 fn get_storage(
822 &mut self,
823 memory: &mut [u8],
824 key_type: KeyType,
825 key_ptr: u32,
826 out_ptr: u32,
827 out_len_ptr: u32,
828 ) -> Result<ReturnErrorCode, TrapReason> {
829 let charged = self.charge_gas(RuntimeCosts::GetStorage(self.ext.max_value_size()))?;
830 let key = self.decode_key(memory, key_type, key_ptr)?;
831 let outcome = self.ext.get_storage(&key);
832
833 if let Some(value) = outcome {
834 self.adjust_gas(charged, RuntimeCosts::GetStorage(value.len() as u32));
835 self.write_sandbox_output(
836 memory,
837 out_ptr,
838 out_len_ptr,
839 &value,
840 false,
841 already_charged,
842 )?;
843 Ok(ReturnErrorCode::Success)
844 } else {
845 self.adjust_gas(charged, RuntimeCosts::GetStorage(0));
846 Ok(ReturnErrorCode::KeyNotFound)
847 }
848 }
849
850 fn contains_storage(
851 &mut self,
852 memory: &[u8],
853 key_type: KeyType,
854 key_ptr: u32,
855 ) -> Result<u32, TrapReason> {
856 let charged = self.charge_gas(RuntimeCosts::ContainsStorage(self.ext.max_value_size()))?;
857 let key = self.decode_key(memory, key_type, key_ptr)?;
858 let outcome = self.ext.get_storage_size(&key);
859
860 self.adjust_gas(charged, RuntimeCosts::ContainsStorage(outcome.unwrap_or(0)));
861 Ok(outcome.unwrap_or(SENTINEL))
862 }
863
864 fn set_transient_storage(
865 &mut self,
866 memory: &[u8],
867 key_type: KeyType,
868 key_ptr: u32,
869 value_ptr: u32,
870 value_len: u32,
871 ) -> Result<u32, TrapReason> {
872 let max_size = self.ext.max_value_size();
873 let charged = self.charge_gas(RuntimeCosts::SetTransientStorage {
874 new_bytes: value_len,
875 old_bytes: max_size,
876 })?;
877 if value_len > max_size {
878 return Err(Error::<E::T>::ValueTooLarge.into());
879 }
880 let key = self.decode_key(memory, key_type, key_ptr)?;
881 let value = Some(self.read_sandbox_memory(memory, value_ptr, value_len)?);
882 let write_outcome = self.ext.set_transient_storage(&key, value, false)?;
883 self.adjust_gas(
884 charged,
885 RuntimeCosts::SetTransientStorage {
886 new_bytes: value_len,
887 old_bytes: write_outcome.old_len(),
888 },
889 );
890 Ok(write_outcome.old_len_with_sentinel())
891 }
892
893 fn clear_transient_storage(
894 &mut self,
895 memory: &[u8],
896 key_type: KeyType,
897 key_ptr: u32,
898 ) -> Result<u32, TrapReason> {
899 let charged =
900 self.charge_gas(RuntimeCosts::ClearTransientStorage(self.ext.max_value_size()))?;
901 let key = self.decode_key(memory, key_type, key_ptr)?;
902 let outcome = self.ext.set_transient_storage(&key, None, false)?;
903
904 self.adjust_gas(charged, RuntimeCosts::ClearTransientStorage(outcome.old_len()));
905 Ok(outcome.old_len_with_sentinel())
906 }
907
908 fn get_transient_storage(
909 &mut self,
910 memory: &mut [u8],
911 key_type: KeyType,
912 key_ptr: u32,
913 out_ptr: u32,
914 out_len_ptr: u32,
915 ) -> Result<ReturnErrorCode, TrapReason> {
916 let charged =
917 self.charge_gas(RuntimeCosts::GetTransientStorage(self.ext.max_value_size()))?;
918 let key = self.decode_key(memory, key_type, key_ptr)?;
919 let outcome = self.ext.get_transient_storage(&key);
920
921 if let Some(value) = outcome {
922 self.adjust_gas(charged, RuntimeCosts::GetTransientStorage(value.len() as u32));
923 self.write_sandbox_output(
924 memory,
925 out_ptr,
926 out_len_ptr,
927 &value,
928 false,
929 already_charged,
930 )?;
931 Ok(ReturnErrorCode::Success)
932 } else {
933 self.adjust_gas(charged, RuntimeCosts::GetTransientStorage(0));
934 Ok(ReturnErrorCode::KeyNotFound)
935 }
936 }
937
938 fn contains_transient_storage(
939 &mut self,
940 memory: &[u8],
941 key_type: KeyType,
942 key_ptr: u32,
943 ) -> Result<u32, TrapReason> {
944 let charged =
945 self.charge_gas(RuntimeCosts::ContainsTransientStorage(self.ext.max_value_size()))?;
946 let key = self.decode_key(memory, key_type, key_ptr)?;
947 let outcome = self.ext.get_transient_storage_size(&key);
948
949 self.adjust_gas(charged, RuntimeCosts::ContainsTransientStorage(outcome.unwrap_or(0)));
950 Ok(outcome.unwrap_or(SENTINEL))
951 }
952
953 fn take_transient_storage(
954 &mut self,
955 memory: &mut [u8],
956 key_type: KeyType,
957 key_ptr: u32,
958 out_ptr: u32,
959 out_len_ptr: u32,
960 ) -> Result<ReturnErrorCode, TrapReason> {
961 let charged =
962 self.charge_gas(RuntimeCosts::TakeTransientStorage(self.ext.max_value_size()))?;
963 let key = self.decode_key(memory, key_type, key_ptr)?;
964 if let crate::storage::WriteOutcome::Taken(value) =
965 self.ext.set_transient_storage(&key, None, true)?
966 {
967 self.adjust_gas(charged, RuntimeCosts::TakeTransientStorage(value.len() as u32));
968 self.write_sandbox_output(
969 memory,
970 out_ptr,
971 out_len_ptr,
972 &value,
973 false,
974 already_charged,
975 )?;
976 Ok(ReturnErrorCode::Success)
977 } else {
978 self.adjust_gas(charged, RuntimeCosts::TakeTransientStorage(0));
979 Ok(ReturnErrorCode::KeyNotFound)
980 }
981 }
982
983 fn call(
984 &mut self,
985 memory: &mut [u8],
986 flags: CallFlags,
987 call_type: CallType,
988 input_data_ptr: u32,
989 input_data_len: u32,
990 output_ptr: u32,
991 output_len_ptr: u32,
992 ) -> Result<ReturnErrorCode, TrapReason> {
993 self.charge_gas(call_type.cost())?;
994
995 let input_data = if flags.contains(CallFlags::CLONE_INPUT) {
996 let input = self.input_data.as_ref().ok_or(Error::<E::T>::InputForwarded)?;
997 charge_gas!(self, RuntimeCosts::CallInputCloned(input.len() as u32))?;
998 input.clone()
999 } else if flags.contains(CallFlags::FORWARD_INPUT) {
1000 self.input_data.take().ok_or(Error::<E::T>::InputForwarded)?
1001 } else {
1002 self.charge_gas(RuntimeCosts::CopyFromContract(input_data_len))?;
1003 self.read_sandbox_memory(memory, input_data_ptr, input_data_len)?
1004 };
1005
1006 let call_outcome = match call_type {
1007 CallType::Call { callee_ptr, value_ptr, deposit_ptr, weight } => {
1008 let callee: <<E as Ext>::T as frame_system::Config>::AccountId =
1009 self.read_sandbox_memory_as(memory, callee_ptr)?;
1010 let deposit_limit: BalanceOf<<E as Ext>::T> = if deposit_ptr == SENTINEL {
1011 BalanceOf::<<E as Ext>::T>::zero()
1012 } else {
1013 self.read_sandbox_memory_as(memory, deposit_ptr)?
1014 };
1015 let read_only = flags.contains(CallFlags::READ_ONLY);
1016 let value: BalanceOf<<E as Ext>::T> =
1017 self.read_sandbox_memory_as(memory, value_ptr)?;
1018 if value > 0u32.into() {
1019 if read_only || self.ext.is_read_only() {
1022 return Err(Error::<E::T>::StateChangeDenied.into());
1023 }
1024 self.charge_gas(RuntimeCosts::CallTransferSurcharge)?;
1025 }
1026 self.ext.call(
1027 weight,
1028 deposit_limit,
1029 callee,
1030 value,
1031 input_data,
1032 flags.contains(CallFlags::ALLOW_REENTRY),
1033 read_only,
1034 )
1035 },
1036 CallType::DelegateCall { code_hash_ptr } => {
1037 if flags.intersects(CallFlags::ALLOW_REENTRY | CallFlags::READ_ONLY) {
1038 return Err(Error::<E::T>::InvalidCallFlags.into());
1039 }
1040 let code_hash = self.read_sandbox_memory_as(memory, code_hash_ptr)?;
1041 self.ext.delegate_call(code_hash, input_data)
1042 },
1043 };
1044
1045 if flags.contains(CallFlags::TAIL_CALL) {
1048 if let Ok(return_value) = call_outcome {
1049 return Err(TrapReason::Return(ReturnData {
1050 flags: return_value.flags.bits(),
1051 data: return_value.data,
1052 }));
1053 }
1054 }
1055
1056 if let Ok(output) = &call_outcome {
1057 self.write_sandbox_output(
1058 memory,
1059 output_ptr,
1060 output_len_ptr,
1061 &output.data,
1062 true,
1063 |len| Some(RuntimeCosts::CopyToContract(len)),
1064 )?;
1065 }
1066 Ok(Runtime::<E>::exec_into_return_code(call_outcome)?)
1067 }
1068
1069 fn instantiate(
1070 &mut self,
1071 memory: &mut [u8],
1072 code_hash_ptr: u32,
1073 weight: Weight,
1074 deposit_ptr: u32,
1075 value_ptr: u32,
1076 input_data_ptr: u32,
1077 input_data_len: u32,
1078 address_ptr: u32,
1079 address_len_ptr: u32,
1080 output_ptr: u32,
1081 output_len_ptr: u32,
1082 salt_ptr: u32,
1083 salt_len: u32,
1084 ) -> Result<ReturnErrorCode, TrapReason> {
1085 self.charge_gas(RuntimeCosts::Instantiate { input_data_len, salt_len })?;
1086 let deposit_limit: BalanceOf<<E as Ext>::T> = if deposit_ptr == SENTINEL {
1087 BalanceOf::<<E as Ext>::T>::zero()
1088 } else {
1089 self.read_sandbox_memory_as(memory, deposit_ptr)?
1090 };
1091 let value: BalanceOf<<E as Ext>::T> = self.read_sandbox_memory_as(memory, value_ptr)?;
1092 let code_hash: CodeHash<<E as Ext>::T> =
1093 self.read_sandbox_memory_as(memory, code_hash_ptr)?;
1094 let input_data = self.read_sandbox_memory(memory, input_data_ptr, input_data_len)?;
1095 let salt = self.read_sandbox_memory(memory, salt_ptr, salt_len)?;
1096 let instantiate_outcome =
1097 self.ext.instantiate(weight, deposit_limit, code_hash, value, input_data, &salt);
1098 if let Ok((address, output)) = &instantiate_outcome {
1099 if !output.flags.contains(ReturnFlags::REVERT) {
1100 self.write_sandbox_output(
1101 memory,
1102 address_ptr,
1103 address_len_ptr,
1104 &address.encode(),
1105 true,
1106 already_charged,
1107 )?;
1108 }
1109 self.write_sandbox_output(
1110 memory,
1111 output_ptr,
1112 output_len_ptr,
1113 &output.data,
1114 true,
1115 |len| Some(RuntimeCosts::CopyToContract(len)),
1116 )?;
1117 }
1118 Ok(Runtime::<E>::exec_into_return_code(instantiate_outcome.map(|(_, retval)| retval))?)
1119 }
1120
1121 fn terminate(&mut self, memory: &[u8], beneficiary_ptr: u32) -> Result<(), TrapReason> {
1122 let count = self.ext.locked_delegate_dependencies_count() as _;
1123 self.charge_gas(RuntimeCosts::Terminate(count))?;
1124
1125 let beneficiary: <<E as Ext>::T as frame_system::Config>::AccountId =
1126 self.read_sandbox_memory_as(memory, beneficiary_ptr)?;
1127 self.ext.terminate(&beneficiary)?;
1128 Err(TrapReason::Termination)
1129 }
1130}
1131
1132#[define_env(doc)]
1140pub mod env {
1141
1142 #[cfg(feature = "runtime-benchmarks")]
1144 #[unstable]
1145 fn noop(ctx: _, memory: _) -> Result<(), TrapReason> {
1146 Ok(())
1147 }
1148
1149 #[prefixed_alias]
1152 #[mutating]
1153 fn set_storage(
1154 ctx: _,
1155 memory: _,
1156 key_ptr: u32,
1157 value_ptr: u32,
1158 value_len: u32,
1159 ) -> Result<(), TrapReason> {
1160 ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len).map(|_| ())
1161 }
1162
1163 #[version(1)]
1166 #[prefixed_alias]
1167 #[mutating]
1168 fn set_storage(
1169 ctx: _,
1170 memory: _,
1171 key_ptr: u32,
1172 value_ptr: u32,
1173 value_len: u32,
1174 ) -> Result<u32, TrapReason> {
1175 ctx.set_storage(memory, KeyType::Fix, key_ptr, value_ptr, value_len)
1176 }
1177
1178 #[version(2)]
1181 #[prefixed_alias]
1182 #[mutating]
1183 fn set_storage(
1184 ctx: _,
1185 memory: _,
1186 key_ptr: u32,
1187 key_len: u32,
1188 value_ptr: u32,
1189 value_len: u32,
1190 ) -> Result<u32, TrapReason> {
1191 ctx.set_storage(memory, KeyType::Var(key_len), key_ptr, value_ptr, value_len)
1192 }
1193
1194 #[prefixed_alias]
1197 #[mutating]
1198 fn clear_storage(ctx: _, memory: _, key_ptr: u32) -> Result<(), TrapReason> {
1199 ctx.clear_storage(memory, KeyType::Fix, key_ptr).map(|_| ())
1200 }
1201
1202 #[version(1)]
1205 #[prefixed_alias]
1206 #[mutating]
1207 fn clear_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
1208 ctx.clear_storage(memory, KeyType::Var(key_len), key_ptr)
1209 }
1210
1211 #[prefixed_alias]
1214 fn get_storage(
1215 ctx: _,
1216 memory: _,
1217 key_ptr: u32,
1218 out_ptr: u32,
1219 out_len_ptr: u32,
1220 ) -> Result<ReturnErrorCode, TrapReason> {
1221 ctx.get_storage(memory, KeyType::Fix, key_ptr, out_ptr, out_len_ptr)
1222 }
1223
1224 #[version(1)]
1227 #[prefixed_alias]
1228 fn get_storage(
1229 ctx: _,
1230 memory: _,
1231 key_ptr: u32,
1232 key_len: u32,
1233 out_ptr: u32,
1234 out_len_ptr: u32,
1235 ) -> Result<ReturnErrorCode, TrapReason> {
1236 ctx.get_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr)
1237 }
1238
1239 #[prefixed_alias]
1242 fn contains_storage(ctx: _, memory: _, key_ptr: u32) -> Result<u32, TrapReason> {
1243 ctx.contains_storage(memory, KeyType::Fix, key_ptr)
1244 }
1245
1246 #[version(1)]
1249 #[prefixed_alias]
1250 fn contains_storage(ctx: _, memory: _, key_ptr: u32, key_len: u32) -> Result<u32, TrapReason> {
1251 ctx.contains_storage(memory, KeyType::Var(key_len), key_ptr)
1252 }
1253
1254 #[prefixed_alias]
1257 #[mutating]
1258 fn take_storage(
1259 ctx: _,
1260 memory: _,
1261 key_ptr: u32,
1262 key_len: u32,
1263 out_ptr: u32,
1264 out_len_ptr: u32,
1265 ) -> Result<ReturnErrorCode, TrapReason> {
1266 let charged = ctx.charge_gas(RuntimeCosts::TakeStorage(ctx.ext.max_value_size()))?;
1267 ensure!(
1268 key_len <= <<E as Ext>::T as Config>::MaxStorageKeyLen::get(),
1269 Error::<E::T>::DecodingFailed
1270 );
1271 let key = ctx.read_sandbox_memory(memory, key_ptr, key_len)?;
1272 if let crate::storage::WriteOutcome::Taken(value) = ctx.ext.set_storage(
1273 &Key::<E::T>::try_from_var(key).map_err(|_| Error::<E::T>::DecodingFailed)?,
1274 None,
1275 true,
1276 )? {
1277 ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(value.len() as u32));
1278 ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &value, false, already_charged)?;
1279 Ok(ReturnErrorCode::Success)
1280 } else {
1281 ctx.adjust_gas(charged, RuntimeCosts::TakeStorage(0));
1282 Ok(ReturnErrorCode::KeyNotFound)
1283 }
1284 }
1285
1286 #[unstable]
1288 fn set_transient_storage(
1289 ctx: _,
1290 memory: _,
1291 key_ptr: u32,
1292 key_len: u32,
1293 value_ptr: u32,
1294 value_len: u32,
1295 ) -> Result<u32, TrapReason> {
1296 ctx.set_transient_storage(memory, KeyType::Var(key_len), key_ptr, value_ptr, value_len)
1297 }
1298
1299 #[unstable]
1301 fn clear_transient_storage(
1302 ctx: _,
1303 memory: _,
1304 key_ptr: u32,
1305 key_len: u32,
1306 ) -> Result<u32, TrapReason> {
1307 ctx.clear_transient_storage(memory, KeyType::Var(key_len), key_ptr)
1308 }
1309
1310 #[unstable]
1312 fn get_transient_storage(
1313 ctx: _,
1314 memory: _,
1315 key_ptr: u32,
1316 key_len: u32,
1317 out_ptr: u32,
1318 out_len_ptr: u32,
1319 ) -> Result<ReturnErrorCode, TrapReason> {
1320 ctx.get_transient_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr)
1321 }
1322
1323 #[unstable]
1325 fn contains_transient_storage(
1326 ctx: _,
1327 memory: _,
1328 key_ptr: u32,
1329 key_len: u32,
1330 ) -> Result<u32, TrapReason> {
1331 ctx.contains_transient_storage(memory, KeyType::Var(key_len), key_ptr)
1332 }
1333
1334 #[unstable]
1336 fn take_transient_storage(
1337 ctx: _,
1338 memory: _,
1339 key_ptr: u32,
1340 key_len: u32,
1341 out_ptr: u32,
1342 out_len_ptr: u32,
1343 ) -> Result<ReturnErrorCode, TrapReason> {
1344 ctx.take_transient_storage(memory, KeyType::Var(key_len), key_ptr, out_ptr, out_len_ptr)
1345 }
1346
1347 #[prefixed_alias]
1350 #[mutating]
1351 fn transfer(
1352 ctx: _,
1353 memory: _,
1354 account_ptr: u32,
1355 _account_len: u32,
1356 value_ptr: u32,
1357 _value_len: u32,
1358 ) -> Result<ReturnErrorCode, TrapReason> {
1359 ctx.charge_gas(RuntimeCosts::Transfer)?;
1360 let callee: <<E as Ext>::T as frame_system::Config>::AccountId =
1361 ctx.read_sandbox_memory_as(memory, account_ptr)?;
1362 let value: BalanceOf<<E as Ext>::T> = ctx.read_sandbox_memory_as(memory, value_ptr)?;
1363 let result = ctx.ext.transfer(&callee, value);
1364 match result {
1365 Ok(()) => Ok(ReturnErrorCode::Success),
1366 Err(err) => {
1367 let code = Runtime::<E>::err_into_return_code(err)?;
1368 Ok(code)
1369 },
1370 }
1371 }
1372
1373 #[prefixed_alias]
1381 fn call(
1382 ctx: _,
1383 memory: _,
1384 callee_ptr: u32,
1385 _callee_len: u32,
1386 gas: u64,
1387 value_ptr: u32,
1388 _value_len: u32,
1389 input_data_ptr: u32,
1390 input_data_len: u32,
1391 output_ptr: u32,
1392 output_len_ptr: u32,
1393 ) -> Result<ReturnErrorCode, TrapReason> {
1394 ctx.call(
1395 memory,
1396 CallFlags::ALLOW_REENTRY,
1397 CallType::Call {
1398 callee_ptr,
1399 value_ptr,
1400 deposit_ptr: SENTINEL,
1401 weight: Weight::from_parts(gas, 0),
1402 },
1403 input_data_ptr,
1404 input_data_len,
1405 output_ptr,
1406 output_len_ptr,
1407 )
1408 }
1409
1410 #[version(1)]
1413 #[prefixed_alias]
1414 fn call(
1415 ctx: _,
1416 memory: _,
1417 flags: u32,
1418 callee_ptr: u32,
1419 gas: u64,
1420 value_ptr: u32,
1421 input_data_ptr: u32,
1422 input_data_len: u32,
1423 output_ptr: u32,
1424 output_len_ptr: u32,
1425 ) -> Result<ReturnErrorCode, TrapReason> {
1426 ctx.call(
1427 memory,
1428 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
1429 CallType::Call {
1430 callee_ptr,
1431 value_ptr,
1432 deposit_ptr: SENTINEL,
1433 weight: Weight::from_parts(gas, 0),
1434 },
1435 input_data_ptr,
1436 input_data_len,
1437 output_ptr,
1438 output_len_ptr,
1439 )
1440 }
1441
1442 #[version(2)]
1445 fn call(
1446 ctx: _,
1447 memory: _,
1448 flags: u32,
1449 callee_ptr: u32,
1450 ref_time_limit: u64,
1451 proof_size_limit: u64,
1452 deposit_ptr: u32,
1453 value_ptr: u32,
1454 input_data_ptr: u32,
1455 input_data_len: u32,
1456 output_ptr: u32,
1457 output_len_ptr: u32,
1458 ) -> Result<ReturnErrorCode, TrapReason> {
1459 ctx.call(
1460 memory,
1461 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
1462 CallType::Call {
1463 callee_ptr,
1464 value_ptr,
1465 deposit_ptr,
1466 weight: Weight::from_parts(ref_time_limit, proof_size_limit),
1467 },
1468 input_data_ptr,
1469 input_data_len,
1470 output_ptr,
1471 output_len_ptr,
1472 )
1473 }
1474
1475 #[prefixed_alias]
1478 fn delegate_call(
1479 ctx: _,
1480 memory: _,
1481 flags: u32,
1482 code_hash_ptr: u32,
1483 input_data_ptr: u32,
1484 input_data_len: u32,
1485 output_ptr: u32,
1486 output_len_ptr: u32,
1487 ) -> Result<ReturnErrorCode, TrapReason> {
1488 ctx.call(
1489 memory,
1490 CallFlags::from_bits(flags).ok_or(Error::<E::T>::InvalidCallFlags)?,
1491 CallType::DelegateCall { code_hash_ptr },
1492 input_data_ptr,
1493 input_data_len,
1494 output_ptr,
1495 output_len_ptr,
1496 )
1497 }
1498
1499 #[prefixed_alias]
1508 #[mutating]
1509 fn instantiate(
1510 ctx: _,
1511 memory: _,
1512 code_hash_ptr: u32,
1513 _code_hash_len: u32,
1514 gas: u64,
1515 value_ptr: u32,
1516 _value_len: u32,
1517 input_data_ptr: u32,
1518 input_data_len: u32,
1519 address_ptr: u32,
1520 address_len_ptr: u32,
1521 output_ptr: u32,
1522 output_len_ptr: u32,
1523 salt_ptr: u32,
1524 salt_len: u32,
1525 ) -> Result<ReturnErrorCode, TrapReason> {
1526 ctx.instantiate(
1527 memory,
1528 code_hash_ptr,
1529 Weight::from_parts(gas, 0),
1530 SENTINEL,
1531 value_ptr,
1532 input_data_ptr,
1533 input_data_len,
1534 address_ptr,
1535 address_len_ptr,
1536 output_ptr,
1537 output_len_ptr,
1538 salt_ptr,
1539 salt_len,
1540 )
1541 }
1542
1543 #[version(1)]
1546 #[prefixed_alias]
1547 #[mutating]
1548 fn instantiate(
1549 ctx: _,
1550 memory: _,
1551 code_hash_ptr: u32,
1552 gas: u64,
1553 value_ptr: u32,
1554 input_data_ptr: u32,
1555 input_data_len: u32,
1556 address_ptr: u32,
1557 address_len_ptr: u32,
1558 output_ptr: u32,
1559 output_len_ptr: u32,
1560 salt_ptr: u32,
1561 salt_len: u32,
1562 ) -> Result<ReturnErrorCode, TrapReason> {
1563 ctx.instantiate(
1564 memory,
1565 code_hash_ptr,
1566 Weight::from_parts(gas, 0),
1567 SENTINEL,
1568 value_ptr,
1569 input_data_ptr,
1570 input_data_len,
1571 address_ptr,
1572 address_len_ptr,
1573 output_ptr,
1574 output_len_ptr,
1575 salt_ptr,
1576 salt_len,
1577 )
1578 }
1579
1580 #[version(2)]
1583 #[mutating]
1584 fn instantiate(
1585 ctx: _,
1586 memory: _,
1587 code_hash_ptr: u32,
1588 ref_time_limit: u64,
1589 proof_size_limit: u64,
1590 deposit_ptr: u32,
1591 value_ptr: u32,
1592 input_data_ptr: u32,
1593 input_data_len: u32,
1594 address_ptr: u32,
1595 address_len_ptr: u32,
1596 output_ptr: u32,
1597 output_len_ptr: u32,
1598 salt_ptr: u32,
1599 salt_len: u32,
1600 ) -> Result<ReturnErrorCode, TrapReason> {
1601 ctx.instantiate(
1602 memory,
1603 code_hash_ptr,
1604 Weight::from_parts(ref_time_limit, proof_size_limit),
1605 deposit_ptr,
1606 value_ptr,
1607 input_data_ptr,
1608 input_data_len,
1609 address_ptr,
1610 address_len_ptr,
1611 output_ptr,
1612 output_len_ptr,
1613 salt_ptr,
1614 salt_len,
1615 )
1616 }
1617
1618 #[prefixed_alias]
1627 #[mutating]
1628 fn terminate(
1629 ctx: _,
1630 memory: _,
1631 beneficiary_ptr: u32,
1632 _beneficiary_len: u32,
1633 ) -> Result<(), TrapReason> {
1634 ctx.terminate(memory, beneficiary_ptr)
1635 }
1636
1637 #[version(1)]
1640 #[prefixed_alias]
1641 #[mutating]
1642 fn terminate(ctx: _, memory: _, beneficiary_ptr: u32) -> Result<(), TrapReason> {
1643 ctx.terminate(memory, beneficiary_ptr)
1644 }
1645
1646 #[prefixed_alias]
1649 fn input(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1650 if let Some(input) = ctx.input_data.take() {
1651 ctx.write_sandbox_output(memory, out_ptr, out_len_ptr, &input, false, |len| {
1652 Some(RuntimeCosts::CopyToContract(len))
1653 })?;
1654 ctx.input_data = Some(input);
1655 Ok(())
1656 } else {
1657 Err(Error::<E::T>::InputForwarded.into())
1658 }
1659 }
1660
1661 fn seal_return(
1664 ctx: _,
1665 memory: _,
1666 flags: u32,
1667 data_ptr: u32,
1668 data_len: u32,
1669 ) -> Result<(), TrapReason> {
1670 ctx.charge_gas(RuntimeCosts::CopyFromContract(data_len))?;
1671 Err(TrapReason::Return(ReturnData {
1672 flags,
1673 data: ctx.read_sandbox_memory(memory, data_ptr, data_len)?,
1674 }))
1675 }
1676
1677 #[prefixed_alias]
1680 fn caller(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1681 ctx.charge_gas(RuntimeCosts::Caller)?;
1682 let caller = ctx.ext.caller().account_id()?.clone();
1683 Ok(ctx.write_sandbox_output(
1684 memory,
1685 out_ptr,
1686 out_len_ptr,
1687 &caller.encode(),
1688 false,
1689 already_charged,
1690 )?)
1691 }
1692
1693 #[prefixed_alias]
1696 fn is_contract(ctx: _, memory: _, account_ptr: u32) -> Result<u32, TrapReason> {
1697 ctx.charge_gas(RuntimeCosts::IsContract)?;
1698 let address: <<E as Ext>::T as frame_system::Config>::AccountId =
1699 ctx.read_sandbox_memory_as(memory, account_ptr)?;
1700
1701 Ok(ctx.ext.is_contract(&address) as u32)
1702 }
1703
1704 #[prefixed_alias]
1707 fn code_hash(
1708 ctx: _,
1709 memory: _,
1710 account_ptr: u32,
1711 out_ptr: u32,
1712 out_len_ptr: u32,
1713 ) -> Result<ReturnErrorCode, TrapReason> {
1714 ctx.charge_gas(RuntimeCosts::CodeHash)?;
1715 let address: <<E as Ext>::T as frame_system::Config>::AccountId =
1716 ctx.read_sandbox_memory_as(memory, account_ptr)?;
1717 if let Some(value) = ctx.ext.code_hash(&address) {
1718 ctx.write_sandbox_output(
1719 memory,
1720 out_ptr,
1721 out_len_ptr,
1722 &value.encode(),
1723 false,
1724 already_charged,
1725 )?;
1726 Ok(ReturnErrorCode::Success)
1727 } else {
1728 Ok(ReturnErrorCode::KeyNotFound)
1729 }
1730 }
1731
1732 #[prefixed_alias]
1735 fn own_code_hash(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1736 ctx.charge_gas(RuntimeCosts::OwnCodeHash)?;
1737 let code_hash_encoded = &ctx.ext.own_code_hash().encode();
1738 Ok(ctx.write_sandbox_output(
1739 memory,
1740 out_ptr,
1741 out_len_ptr,
1742 code_hash_encoded,
1743 false,
1744 already_charged,
1745 )?)
1746 }
1747
1748 #[prefixed_alias]
1751 fn caller_is_origin(ctx: _, _memory: _) -> Result<u32, TrapReason> {
1752 ctx.charge_gas(RuntimeCosts::CallerIsOrigin)?;
1753 Ok(ctx.ext.caller_is_origin() as u32)
1754 }
1755
1756 fn caller_is_root(ctx: _, _memory: _) -> Result<u32, TrapReason> {
1759 ctx.charge_gas(RuntimeCosts::CallerIsRoot)?;
1760 Ok(ctx.ext.caller_is_root() as u32)
1761 }
1762
1763 #[prefixed_alias]
1766 fn address(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1767 ctx.charge_gas(RuntimeCosts::Address)?;
1768 Ok(ctx.write_sandbox_output(
1769 memory,
1770 out_ptr,
1771 out_len_ptr,
1772 &ctx.ext.address().encode(),
1773 false,
1774 already_charged,
1775 )?)
1776 }
1777
1778 #[prefixed_alias]
1781 fn weight_to_fee(
1782 ctx: _,
1783 memory: _,
1784 gas: u64,
1785 out_ptr: u32,
1786 out_len_ptr: u32,
1787 ) -> Result<(), TrapReason> {
1788 let gas = Weight::from_parts(gas, 0);
1789 ctx.charge_gas(RuntimeCosts::WeightToFee)?;
1790 Ok(ctx.write_sandbox_output(
1791 memory,
1792 out_ptr,
1793 out_len_ptr,
1794 &ctx.ext.get_weight_price(gas).encode(),
1795 false,
1796 already_charged,
1797 )?)
1798 }
1799
1800 #[version(1)]
1803 #[unstable]
1804 fn weight_to_fee(
1805 ctx: _,
1806 memory: _,
1807 ref_time_limit: u64,
1808 proof_size_limit: u64,
1809 out_ptr: u32,
1810 out_len_ptr: u32,
1811 ) -> Result<(), TrapReason> {
1812 let weight = Weight::from_parts(ref_time_limit, proof_size_limit);
1813 ctx.charge_gas(RuntimeCosts::WeightToFee)?;
1814 Ok(ctx.write_sandbox_output(
1815 memory,
1816 out_ptr,
1817 out_len_ptr,
1818 &ctx.ext.get_weight_price(weight).encode(),
1819 false,
1820 already_charged,
1821 )?)
1822 }
1823
1824 #[prefixed_alias]
1827 fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1828 ctx.charge_gas(RuntimeCosts::GasLeft)?;
1829 let gas_left = &ctx.ext.gas_meter().gas_left().ref_time().encode();
1830 Ok(ctx.write_sandbox_output(
1831 memory,
1832 out_ptr,
1833 out_len_ptr,
1834 gas_left,
1835 false,
1836 already_charged,
1837 )?)
1838 }
1839
1840 #[version(1)]
1843 #[unstable]
1844 fn gas_left(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1845 ctx.charge_gas(RuntimeCosts::GasLeft)?;
1846 let gas_left = &ctx.ext.gas_meter().gas_left().encode();
1847 Ok(ctx.write_sandbox_output(
1848 memory,
1849 out_ptr,
1850 out_len_ptr,
1851 gas_left,
1852 false,
1853 already_charged,
1854 )?)
1855 }
1856
1857 #[prefixed_alias]
1860 fn balance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1861 ctx.charge_gas(RuntimeCosts::Balance)?;
1862 Ok(ctx.write_sandbox_output(
1863 memory,
1864 out_ptr,
1865 out_len_ptr,
1866 &ctx.ext.balance().encode(),
1867 false,
1868 already_charged,
1869 )?)
1870 }
1871
1872 #[prefixed_alias]
1875 fn value_transferred(
1876 ctx: _,
1877 memory: _,
1878 out_ptr: u32,
1879 out_len_ptr: u32,
1880 ) -> Result<(), TrapReason> {
1881 ctx.charge_gas(RuntimeCosts::ValueTransferred)?;
1882 Ok(ctx.write_sandbox_output(
1883 memory,
1884 out_ptr,
1885 out_len_ptr,
1886 &ctx.ext.value_transferred().encode(),
1887 false,
1888 already_charged,
1889 )?)
1890 }
1891
1892 #[prefixed_alias]
1901 #[deprecated]
1902 fn random(
1903 ctx: _,
1904 memory: _,
1905 subject_ptr: u32,
1906 subject_len: u32,
1907 out_ptr: u32,
1908 out_len_ptr: u32,
1909 ) -> Result<(), TrapReason> {
1910 ctx.charge_gas(RuntimeCosts::Random)?;
1911 if subject_len > ctx.ext.schedule().limits.subject_len {
1912 return Err(Error::<E::T>::RandomSubjectTooLong.into());
1913 }
1914 let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
1915 Ok(ctx.write_sandbox_output(
1916 memory,
1917 out_ptr,
1918 out_len_ptr,
1919 &ctx.ext.random(&subject_buf).0.encode(),
1920 false,
1921 already_charged,
1922 )?)
1923 }
1924
1925 #[version(1)]
1947 #[prefixed_alias]
1948 #[deprecated]
1949 fn random(
1950 ctx: _,
1951 memory: _,
1952 subject_ptr: u32,
1953 subject_len: u32,
1954 out_ptr: u32,
1955 out_len_ptr: u32,
1956 ) -> Result<(), TrapReason> {
1957 ctx.charge_gas(RuntimeCosts::Random)?;
1958 if subject_len > ctx.ext.schedule().limits.subject_len {
1959 return Err(Error::<E::T>::RandomSubjectTooLong.into());
1960 }
1961 let subject_buf = ctx.read_sandbox_memory(memory, subject_ptr, subject_len)?;
1962 Ok(ctx.write_sandbox_output(
1963 memory,
1964 out_ptr,
1965 out_len_ptr,
1966 &ctx.ext.random(&subject_buf).encode(),
1967 false,
1968 already_charged,
1969 )?)
1970 }
1971
1972 #[prefixed_alias]
1975 fn now(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
1976 ctx.charge_gas(RuntimeCosts::Now)?;
1977 Ok(ctx.write_sandbox_output(
1978 memory,
1979 out_ptr,
1980 out_len_ptr,
1981 &ctx.ext.now().encode(),
1982 false,
1983 already_charged,
1984 )?)
1985 }
1986
1987 #[prefixed_alias]
1990 fn minimum_balance(
1991 ctx: _,
1992 memory: _,
1993 out_ptr: u32,
1994 out_len_ptr: u32,
1995 ) -> Result<(), TrapReason> {
1996 ctx.charge_gas(RuntimeCosts::MinimumBalance)?;
1997 Ok(ctx.write_sandbox_output(
1998 memory,
1999 out_ptr,
2000 out_len_ptr,
2001 &ctx.ext.minimum_balance().encode(),
2002 false,
2003 already_charged,
2004 )?)
2005 }
2006
2007 #[prefixed_alias]
2018 #[deprecated]
2019 fn tombstone_deposit(
2020 ctx: _,
2021 memory: _,
2022 out_ptr: u32,
2023 out_len_ptr: u32,
2024 ) -> Result<(), TrapReason> {
2025 ctx.charge_gas(RuntimeCosts::Balance)?;
2026 let deposit = <BalanceOf<E::T>>::zero().encode();
2027 Ok(ctx.write_sandbox_output(
2028 memory,
2029 out_ptr,
2030 out_len_ptr,
2031 &deposit,
2032 false,
2033 already_charged,
2034 )?)
2035 }
2036
2037 #[prefixed_alias]
2044 #[deprecated]
2045 fn restore_to(
2046 ctx: _,
2047 memory: _,
2048 _dest_ptr: u32,
2049 _dest_len: u32,
2050 _code_hash_ptr: u32,
2051 _code_hash_len: u32,
2052 _rent_allowance_ptr: u32,
2053 _rent_allowance_len: u32,
2054 _delta_ptr: u32,
2055 _delta_count: u32,
2056 ) -> Result<(), TrapReason> {
2057 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2058 Ok(())
2059 }
2060
2061 #[version(1)]
2068 #[prefixed_alias]
2069 #[deprecated]
2070 fn restore_to(
2071 ctx: _,
2072 memory: _,
2073 _dest_ptr: u32,
2074 _code_hash_ptr: u32,
2075 _rent_allowance_ptr: u32,
2076 _delta_ptr: u32,
2077 _delta_count: u32,
2078 ) -> Result<(), TrapReason> {
2079 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2080 Ok(())
2081 }
2082
2083 #[prefixed_alias]
2090 #[deprecated]
2091 fn set_rent_allowance(
2092 ctx: _,
2093 memory: _,
2094 _value_ptr: u32,
2095 _value_len: u32,
2096 ) -> Result<(), TrapReason> {
2097 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2098 Ok(())
2099 }
2100
2101 #[version(1)]
2108 #[prefixed_alias]
2109 #[deprecated]
2110 fn set_rent_allowance(ctx: _, _memory: _, _value_ptr: u32) -> Result<(), TrapReason> {
2111 ctx.charge_gas(RuntimeCosts::DebugMessage(0))?;
2112 Ok(())
2113 }
2114
2115 #[prefixed_alias]
2122 #[deprecated]
2123 fn rent_allowance(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
2124 ctx.charge_gas(RuntimeCosts::Balance)?;
2125 let rent_allowance = <BalanceOf<E::T>>::max_value().encode();
2126 Ok(ctx.write_sandbox_output(
2127 memory,
2128 out_ptr,
2129 out_len_ptr,
2130 &rent_allowance,
2131 false,
2132 already_charged,
2133 )?)
2134 }
2135
2136 #[prefixed_alias]
2139 #[mutating]
2140 fn deposit_event(
2141 ctx: _,
2142 memory: _,
2143 topics_ptr: u32,
2144 topics_len: u32,
2145 data_ptr: u32,
2146 data_len: u32,
2147 ) -> Result<(), TrapReason> {
2148 let num_topic = topics_len
2149 .checked_div(core::mem::size_of::<TopicOf<E::T>>() as u32)
2150 .ok_or("Zero sized topics are not allowed")?;
2151 ctx.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len })?;
2152 if data_len > ctx.ext.max_value_size() {
2153 return Err(Error::<E::T>::ValueTooLarge.into());
2154 }
2155
2156 let topics: Vec<TopicOf<<E as Ext>::T>> = match topics_len {
2157 0 => Vec::new(),
2158 _ => ctx.read_sandbox_memory_as_unbounded(memory, topics_ptr, topics_len)?,
2159 };
2160
2161 if topics.len() > ctx.ext.schedule().limits.event_topics as usize {
2163 return Err(Error::<E::T>::TooManyTopics.into());
2164 }
2165
2166 let event_data = ctx.read_sandbox_memory(memory, data_ptr, data_len)?;
2167
2168 ctx.ext.deposit_event(topics, event_data);
2169
2170 Ok(())
2171 }
2172
2173 #[prefixed_alias]
2176 fn block_number(ctx: _, memory: _, out_ptr: u32, out_len_ptr: u32) -> Result<(), TrapReason> {
2177 ctx.charge_gas(RuntimeCosts::BlockNumber)?;
2178 Ok(ctx.write_sandbox_output(
2179 memory,
2180 out_ptr,
2181 out_len_ptr,
2182 &ctx.ext.block_number().encode(),
2183 false,
2184 already_charged,
2185 )?)
2186 }
2187
2188 #[prefixed_alias]
2191 fn hash_sha2_256(
2192 ctx: _,
2193 memory: _,
2194 input_ptr: u32,
2195 input_len: u32,
2196 output_ptr: u32,
2197 ) -> Result<(), TrapReason> {
2198 ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?;
2199 Ok(ctx.compute_hash_on_intermediate_buffer(
2200 memory, sha2_256, input_ptr, input_len, output_ptr,
2201 )?)
2202 }
2203
2204 #[prefixed_alias]
2207 fn hash_keccak_256(
2208 ctx: _,
2209 memory: _,
2210 input_ptr: u32,
2211 input_len: u32,
2212 output_ptr: u32,
2213 ) -> Result<(), TrapReason> {
2214 ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?;
2215 Ok(ctx.compute_hash_on_intermediate_buffer(
2216 memory, keccak_256, input_ptr, input_len, output_ptr,
2217 )?)
2218 }
2219
2220 #[prefixed_alias]
2223 fn hash_blake2_256(
2224 ctx: _,
2225 memory: _,
2226 input_ptr: u32,
2227 input_len: u32,
2228 output_ptr: u32,
2229 ) -> Result<(), TrapReason> {
2230 ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?;
2231 Ok(ctx.compute_hash_on_intermediate_buffer(
2232 memory, blake2_256, input_ptr, input_len, output_ptr,
2233 )?)
2234 }
2235
2236 #[prefixed_alias]
2239 fn hash_blake2_128(
2240 ctx: _,
2241 memory: _,
2242 input_ptr: u32,
2243 input_len: u32,
2244 output_ptr: u32,
2245 ) -> Result<(), TrapReason> {
2246 ctx.charge_gas(RuntimeCosts::HashBlake128(input_len))?;
2247 Ok(ctx.compute_hash_on_intermediate_buffer(
2248 memory, blake2_128, input_ptr, input_len, output_ptr,
2249 )?)
2250 }
2251
2252 #[prefixed_alias]
2255 fn call_chain_extension(
2256 ctx: _,
2257 memory: _,
2258 id: u32,
2259 input_ptr: u32,
2260 input_len: u32,
2261 output_ptr: u32,
2262 output_len_ptr: u32,
2263 ) -> Result<u32, TrapReason> {
2264 use crate::chain_extension::{ChainExtension, Environment, RetVal};
2265 if !<E::T as Config>::ChainExtension::enabled() {
2266 return Err(Error::<E::T>::NoChainExtension.into());
2267 }
2268 let mut chain_extension = ctx.chain_extension.take().expect(
2269 "Constructor initializes with `Some`. This is the only place where it is set to `None`.\
2270 It is always reset to `Some` afterwards. qed"
2271 );
2272 let env =
2273 Environment::new(ctx, memory, id, input_ptr, input_len, output_ptr, output_len_ptr);
2274 let ret = match chain_extension.call(env)? {
2275 RetVal::Converging(val) => Ok(val),
2276 RetVal::Diverging { flags, data } => {
2277 Err(TrapReason::Return(ReturnData { flags: flags.bits(), data }))
2278 },
2279 };
2280 ctx.chain_extension = Some(chain_extension);
2281 ret
2282 }
2283
2284 #[prefixed_alias]
2302 fn debug_message(
2303 ctx: _,
2304 memory: _,
2305 str_ptr: u32,
2306 str_len: u32,
2307 ) -> Result<ReturnErrorCode, TrapReason> {
2308 let str_len = str_len.min(DebugBufferVec::<E::T>::bound() as u32);
2309 ctx.charge_gas(RuntimeCosts::DebugMessage(str_len))?;
2310 if ctx.ext.append_debug_buffer("") {
2311 let data = ctx.read_sandbox_memory(memory, str_ptr, str_len)?;
2312 if let Some(msg) = core::str::from_utf8(&data).ok() {
2313 ctx.ext.append_debug_buffer(msg);
2314 }
2315 }
2316 Ok(ReturnErrorCode::Success)
2317 }
2318
2319 #[mutating]
2322 fn call_runtime(
2323 ctx: _,
2324 memory: _,
2325 call_ptr: u32,
2326 call_len: u32,
2327 ) -> Result<ReturnErrorCode, TrapReason> {
2328 use frame_support::dispatch::GetDispatchInfo;
2329 ctx.charge_gas(RuntimeCosts::CopyFromContract(call_len))?;
2330 let call: <E::T as Config>::RuntimeCall =
2331 ctx.read_sandbox_memory_as_unbounded(memory, call_ptr, call_len)?;
2332 ctx.call_dispatchable::<CallRuntimeFailed>(
2333 call.get_dispatch_info(),
2334 RuntimeCosts::CallRuntime,
2335 |ctx| ctx.ext.call_runtime(call),
2336 )
2337 }
2338
2339 #[mutating]
2342 fn xcm_execute(
2343 ctx: _,
2344 memory: _,
2345 msg_ptr: u32,
2346 msg_len: u32,
2347 ) -> Result<ReturnErrorCode, TrapReason> {
2348 use frame_support::dispatch::DispatchInfo;
2349 use xcm::VersionedXcm;
2350 use xcm_builder::{ExecuteController, ExecuteControllerWeightInfo};
2351
2352 ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
2353 let message: VersionedXcm<CallOf<E::T>> =
2354 ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
2355
2356 let execute_weight =
2357 <<E::T as Config>::Xcm as ExecuteController<_, _>>::WeightInfo::execute();
2358 let weight = ctx.ext.gas_meter().gas_left().max(execute_weight);
2359 let dispatch_info = DispatchInfo { call_weight: weight, ..Default::default() };
2360
2361 ctx.call_dispatchable::<XcmExecutionFailed>(
2362 dispatch_info,
2363 RuntimeCosts::CallXcmExecute,
2364 |ctx| {
2365 let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
2366 let weight_used = <<E::T as Config>::Xcm>::execute(
2367 origin,
2368 Box::new(message),
2369 weight.saturating_sub(execute_weight),
2370 )?;
2371
2372 Ok(Some(weight_used.saturating_add(execute_weight)).into())
2373 },
2374 )
2375 }
2376
2377 #[mutating]
2380 fn xcm_send(
2381 ctx: _,
2382 memory: _,
2383 dest_ptr: u32,
2384 msg_ptr: u32,
2385 msg_len: u32,
2386 output_ptr: u32,
2387 ) -> Result<ReturnErrorCode, TrapReason> {
2388 use xcm::{VersionedLocation, VersionedXcm};
2389 use xcm_builder::{SendController, SendControllerWeightInfo};
2390
2391 ctx.charge_gas(RuntimeCosts::CopyFromContract(msg_len))?;
2392 let dest: VersionedLocation = ctx.read_sandbox_memory_as(memory, dest_ptr)?;
2393
2394 let message: VersionedXcm<()> =
2395 ctx.read_sandbox_memory_as_unbounded(memory, msg_ptr, msg_len)?;
2396 let weight = <<E::T as Config>::Xcm as SendController<_>>::WeightInfo::send();
2397 ctx.charge_gas(RuntimeCosts::CallRuntime(weight))?;
2398 let origin = crate::RawOrigin::Signed(ctx.ext.address().clone()).into();
2399
2400 match <<E::T as Config>::Xcm>::send(origin, dest.into(), message.into()) {
2401 Ok(message_id) => {
2402 ctx.write_sandbox_memory(memory, output_ptr, &message_id.encode())?;
2403 Ok(ReturnErrorCode::Success)
2404 },
2405 Err(e) => {
2406 if ctx.ext.append_debug_buffer("") {
2407 ctx.ext.append_debug_buffer("seal0::xcm_send failed with: ");
2408 ctx.ext.append_debug_buffer(e.into());
2409 };
2410 Ok(ReturnErrorCode::XcmSendFailed)
2411 },
2412 }
2413 }
2414
2415 #[prefixed_alias]
2418 fn ecdsa_recover(
2419 ctx: _,
2420 memory: _,
2421 signature_ptr: u32,
2422 message_hash_ptr: u32,
2423 output_ptr: u32,
2424 ) -> Result<ReturnErrorCode, TrapReason> {
2425 ctx.charge_gas(RuntimeCosts::EcdsaRecovery)?;
2426
2427 let mut signature: [u8; 65] = [0; 65];
2428 ctx.read_sandbox_memory_into_buf(memory, signature_ptr, &mut signature)?;
2429 let mut message_hash: [u8; 32] = [0; 32];
2430 ctx.read_sandbox_memory_into_buf(memory, message_hash_ptr, &mut message_hash)?;
2431
2432 let result = ctx.ext.ecdsa_recover(&signature, &message_hash);
2433
2434 match result {
2435 Ok(pub_key) => {
2436 ctx.write_sandbox_memory(memory, output_ptr, pub_key.as_ref())?;
2439
2440 Ok(ReturnErrorCode::Success)
2441 },
2442 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
2443 }
2444 }
2445
2446 fn sr25519_verify(
2449 ctx: _,
2450 memory: _,
2451 signature_ptr: u32,
2452 pub_key_ptr: u32,
2453 message_len: u32,
2454 message_ptr: u32,
2455 ) -> Result<ReturnErrorCode, TrapReason> {
2456 ctx.charge_gas(RuntimeCosts::Sr25519Verify(message_len))?;
2457
2458 let mut signature: [u8; 64] = [0; 64];
2459 ctx.read_sandbox_memory_into_buf(memory, signature_ptr, &mut signature)?;
2460
2461 let mut pub_key: [u8; 32] = [0; 32];
2462 ctx.read_sandbox_memory_into_buf(memory, pub_key_ptr, &mut pub_key)?;
2463
2464 let message: Vec<u8> = ctx.read_sandbox_memory(memory, message_ptr, message_len)?;
2465
2466 if ctx.ext.sr25519_verify(&signature, &message, &pub_key) {
2467 Ok(ReturnErrorCode::Success)
2468 } else {
2469 Ok(ReturnErrorCode::Sr25519VerifyFailed)
2470 }
2471 }
2472
2473 #[prefixed_alias]
2476 #[mutating]
2477 fn set_code_hash(ctx: _, memory: _, code_hash_ptr: u32) -> Result<ReturnErrorCode, TrapReason> {
2478 ctx.charge_gas(RuntimeCosts::SetCodeHash)?;
2479 let code_hash: CodeHash<<E as Ext>::T> =
2480 ctx.read_sandbox_memory_as(memory, code_hash_ptr)?;
2481 match ctx.ext.set_code_hash(code_hash) {
2482 Err(err) => {
2483 let code = Runtime::<E>::err_into_return_code(err)?;
2484 Ok(code)
2485 },
2486 Ok(()) => Ok(ReturnErrorCode::Success),
2487 }
2488 }
2489
2490 #[prefixed_alias]
2493 fn ecdsa_to_eth_address(
2494 ctx: _,
2495 memory: _,
2496 key_ptr: u32,
2497 out_ptr: u32,
2498 ) -> Result<ReturnErrorCode, TrapReason> {
2499 ctx.charge_gas(RuntimeCosts::EcdsaToEthAddress)?;
2500 let mut compressed_key: [u8; 33] = [0; 33];
2501 ctx.read_sandbox_memory_into_buf(memory, key_ptr, &mut compressed_key)?;
2502 let result = ctx.ext.ecdsa_to_eth_address(&compressed_key);
2503 match result {
2504 Ok(eth_address) => {
2505 ctx.write_sandbox_memory(memory, out_ptr, eth_address.as_ref())?;
2506 Ok(ReturnErrorCode::Success)
2507 },
2508 Err(_) => Ok(ReturnErrorCode::EcdsaRecoveryFailed),
2509 }
2510 }
2511
2512 #[unstable]
2516 fn reentrance_count(ctx: _, memory: _) -> Result<u32, TrapReason> {
2517 ctx.charge_gas(RuntimeCosts::ReentranceCount)?;
2518 Ok(ctx.ext.reentrance_count())
2519 }
2520
2521 #[unstable]
2525 fn account_reentrance_count(ctx: _, memory: _, account_ptr: u32) -> Result<u32, TrapReason> {
2526 ctx.charge_gas(RuntimeCosts::AccountReentranceCount)?;
2527 let account_id: <<E as Ext>::T as frame_system::Config>::AccountId =
2528 ctx.read_sandbox_memory_as(memory, account_ptr)?;
2529 Ok(ctx.ext.account_reentrance_count(&account_id))
2530 }
2531
2532 fn instantiation_nonce(ctx: _, _memory: _) -> Result<u64, TrapReason> {
2535 ctx.charge_gas(RuntimeCosts::InstantiationNonce)?;
2536 Ok(ctx.ext.nonce())
2537 }
2538
2539 #[mutating]
2542 fn lock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> {
2543 ctx.charge_gas(RuntimeCosts::LockDelegateDependency)?;
2544 let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?;
2545 ctx.ext.lock_delegate_dependency(code_hash)?;
2546 Ok(())
2547 }
2548
2549 #[mutating]
2552 fn unlock_delegate_dependency(ctx: _, memory: _, code_hash_ptr: u32) -> Result<(), TrapReason> {
2553 ctx.charge_gas(RuntimeCosts::UnlockDelegateDependency)?;
2554 let code_hash = ctx.read_sandbox_memory_as(memory, code_hash_ptr)?;
2555 ctx.ext.unlock_delegate_dependency(&code_hash)?;
2556 Ok(())
2557 }
2558}