1use crate::{
19 AccountInfo, AccountInfoOf, BalanceOf, BalanceWithDust, Code, CodeInfo, CodeInfoOf,
20 CodeRemoved, Config, ContractInfo, Error, Event, ImmutableData, ImmutableDataOf, LOG_TARGET,
21 Pallet as Contracts, RuntimeCosts, TrieId,
22 address::{self, AddressMapper},
23 deposit_payment::Deposit as _,
24 evm::{block_storage, fees::InfoT as _, transfer_with_dust},
25 limits,
26 metering::{ChargedAmount, Diff, FrameMeter, ResourceMeter, State, Token, TransactionMeter},
27 precompiles::{All as AllPrecompiles, Instance as PrecompileInstance, Precompiles},
28 primitives::{ExecConfig, ExecReturnValue, StorageDeposit},
29 runtime_decl_for_revive_api::{Decode, Encode, TypeInfo},
30 storage::{AccountIdOrAddress, WriteOutcome},
31 tracing::if_tracing,
32 transient_storage::TransientStorage,
33};
34use alloc::{
35 collections::{BTreeMap, BTreeSet},
36 vec::Vec,
37};
38use core::{cmp, fmt::Debug, marker::PhantomData, mem, ops::ControlFlow};
39use frame_support::{
40 Blake2_128Concat, BoundedVec, DebugNoBound, StorageHasher,
41 crypto::ecdsa::ECDSAExt,
42 dispatch::DispatchResult,
43 ensure,
44 storage::{TransactionOutcome, with_transaction},
45 traits::{
46 Time,
47 fungible::{Balanced as _, Inspect, Mutate},
48 tokens::Preservation,
49 },
50 weights::Weight,
51};
52use frame_system::{
53 Pallet as System, RawOrigin,
54 pallet_prelude::{BlockNumberFor, OriginFor},
55};
56use sp_core::{
57 ConstU32, Get, H160, H256, U256,
58 ecdsa::Public as ECDSAPublic,
59 sr25519::{Public as SR25519Public, Signature as SR25519Signature},
60};
61use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
62use sp_runtime::{
63 DispatchError, SaturatedConversion,
64 traits::{BadOrigin, Saturating, TrailingZeroInput, Zero},
65};
66
67#[cfg(test)]
68mod tests;
69
70#[cfg(test)]
71pub mod mock_ext;
72
73pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
74pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;
75pub type ExecResult = Result<ExecReturnValue, ExecError>;
76
77type VarSizedKey = BoundedVec<u8, ConstU32<{ limits::STORAGE_KEY_BYTES }>>;
79
80const FRAME_ALWAYS_EXISTS_ON_INSTANTIATE: &str = "The return value is only `None` if no contract exists at the specified address. This cannot happen on instantiate or delegate; qed";
81
82pub const EMPTY_CODE_HASH: H256 =
84 H256(sp_core::hex2array!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
85
86#[derive(Debug)]
88pub enum Key {
89 Fix([u8; 32]),
91 Var(VarSizedKey),
93}
94
95impl Key {
96 pub fn unhashed(&self) -> &[u8] {
98 match self {
99 Key::Fix(v) => v.as_ref(),
100 Key::Var(v) => v.as_ref(),
101 }
102 }
103
104 pub fn hash(&self) -> Vec<u8> {
106 match self {
107 Key::Fix(v) => blake2_256(v.as_slice()).to_vec(),
108 Key::Var(v) => Blake2_128Concat::hash(v.as_slice()),
109 }
110 }
111
112 pub fn from_fixed(v: [u8; 32]) -> Self {
113 Self::Fix(v)
114 }
115
116 pub fn try_from_var(v: Vec<u8>) -> Result<Self, ()> {
117 VarSizedKey::try_from(v).map(Self::Var).map_err(|_| ())
118 }
119}
120
121#[derive(Copy, Clone, PartialEq, Debug)]
127pub enum ReentrancyProtection {
128 AllowReentry,
130 Strict,
133 AllowNext,
141}
142
143#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)]
149pub enum ErrorOrigin {
150 Caller,
155 Callee,
157}
158
159#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)]
161pub struct ExecError {
162 pub error: DispatchError,
164 pub origin: ErrorOrigin,
166}
167
168impl<T: Into<DispatchError>> From<T> for ExecError {
169 fn from(error: T) -> Self {
170 Self { error: error.into(), origin: ErrorOrigin::Caller }
171 }
172}
173
174#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, DebugNoBound)]
176pub enum Origin<T: Config> {
177 Root,
178 Signed(T::AccountId),
179}
180
181impl<T: Config> Origin<T> {
182 pub fn from_account_id(account_id: T::AccountId) -> Self {
184 Origin::Signed(account_id)
185 }
186
187 pub fn from_runtime_origin(o: OriginFor<T>) -> Result<Self, DispatchError> {
189 match o.into() {
190 Ok(RawOrigin::Root) => Ok(Self::Root),
191 Ok(RawOrigin::Signed(t)) => Ok(Self::Signed(t)),
192 _ => Err(BadOrigin.into()),
193 }
194 }
195
196 pub fn account_id(&self) -> Result<&T::AccountId, DispatchError> {
198 match self {
199 Origin::Signed(id) => Ok(id),
200 Origin::Root => Err(DispatchError::RootNotAllowed),
201 }
202 }
203
204 fn ensure_mapped(&self) -> DispatchResult {
209 match self {
210 Self::Root => Ok(()),
211 Self::Signed(account_id) if T::AddressMapper::is_mapped(account_id) => Ok(()),
212 Self::Signed(_) => Err(<Error<T>>::AccountUnmapped.into()),
213 }
214 }
215}
216
217#[derive(DebugNoBound)]
220pub enum CallResources<T: Config> {
221 NoLimits,
223 WeightDeposit { weight: Weight, deposit_limit: BalanceOf<T> },
225 Ethereum { gas: BalanceOf<T>, add_stipend: bool },
227}
228
229impl<T: Config> CallResources<T> {
230 pub fn from_weight_and_deposit(weight: Weight, deposit_limit: U256) -> Self {
232 Self::WeightDeposit {
233 weight,
234 deposit_limit: deposit_limit.saturated_into::<BalanceOf<T>>(),
235 }
236 }
237
238 pub fn from_ethereum_gas(gas: U256, add_stipend: bool) -> Self {
240 Self::Ethereum { gas: gas.saturated_into::<BalanceOf<T>>(), add_stipend }
241 }
242}
243
244impl<T: Config> Default for CallResources<T> {
245 fn default() -> Self {
246 Self::WeightDeposit { weight: Default::default(), deposit_limit: Default::default() }
247 }
248}
249
250struct TerminateArgs<T: Config> {
252 beneficiary: T::AccountId,
254 trie_id: TrieId,
256 code_hash: H256,
258 only_if_same_tx: bool,
260}
261
262pub trait Ext: PrecompileWithInfoExt {
264 fn delegate_call(
268 &mut self,
269 call_resources: &CallResources<Self::T>,
270 address: H160,
271 input_data: Vec<u8>,
272 ) -> Result<(), ExecError>;
273
274 fn terminate_if_same_tx(&mut self, beneficiary: &H160) -> Result<CodeRemoved, DispatchError>;
281
282 #[allow(dead_code)]
284 fn own_code_hash(&mut self) -> &H256;
285
286 fn immutable_data_len(&mut self) -> u32;
291
292 fn get_immutable_data(&mut self) -> Result<ImmutableData, DispatchError>;
296
297 fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError>;
303}
304
305pub trait PrecompileWithInfoExt: PrecompileExt {
307 fn instantiate(
313 &mut self,
314 limits: &CallResources<Self::T>,
315 code: Code,
316 value: U256,
317 input_data: Vec<u8>,
318 salt: Option<&[u8; 32]>,
319 ) -> Result<H160, ExecError>;
320}
321
322pub trait PrecompileExt: sealing::Sealed {
324 type T: Config;
325
326 fn charge(&mut self, weight: Weight) -> Result<ChargedAmount, DispatchError> {
328 self.frame_meter_mut().charge_weight_token(RuntimeCosts::Precompile(weight))
329 }
330
331 fn adjust_gas(&mut self, charged: ChargedAmount, actual_weight: Weight) {
334 self.frame_meter_mut()
335 .adjust_weight(charged, RuntimeCosts::Precompile(actual_weight));
336 }
337
338 #[inline]
341 fn charge_or_halt<Tok: Token<Self::T>>(
342 &mut self,
343 token: Tok,
344 ) -> ControlFlow<crate::vm::evm::Halt, ChargedAmount> {
345 self.frame_meter_mut().charge_or_halt(token)
346 }
347
348 fn call(
350 &mut self,
351 call_resources: &CallResources<Self::T>,
352 to: &H160,
353 value: U256,
354 input_data: Vec<u8>,
355 reentrancy: ReentrancyProtection,
356 read_only: bool,
357 ) -> Result<(), ExecError>;
358
359 fn get_transient_storage(&self, key: &Key) -> Option<Vec<u8>>;
364
365 fn get_transient_storage_size(&self, key: &Key) -> Option<u32>;
370
371 fn set_transient_storage(
374 &mut self,
375 key: &Key,
376 value: Option<Vec<u8>>,
377 take_old: bool,
378 ) -> Result<WriteOutcome, DispatchError>;
379
380 fn caller(&self) -> Origin<Self::T>;
382
383 fn caller_of_caller(&self) -> Origin<Self::T>;
385
386 fn origin(&self) -> &Origin<Self::T>;
388
389 fn to_account_id(&self, address: &H160) -> AccountIdOf<Self::T>;
391
392 fn code_hash(&self, address: &H160) -> H256;
395
396 fn code_size(&self, address: &H160) -> u64;
398
399 fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool;
401
402 fn caller_is_root(&self, use_caller_of_caller: bool) -> bool;
404
405 fn origin_is_root(&self) -> bool;
410
411 fn account_id(&self) -> &AccountIdOf<Self::T>;
413
414 fn address(&self) -> H160 {
416 <Self::T as Config>::AddressMapper::to_address(self.account_id())
417 }
418
419 fn balance(&self) -> U256;
423
424 fn balance_of(&self, address: &H160) -> U256;
428
429 fn value_transferred(&self) -> U256;
431
432 fn now(&self) -> U256;
434
435 fn minimum_balance(&self) -> U256;
437
438 fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>);
442
443 fn block_number(&self) -> U256;
445
446 fn block_hash(&self, block_number: U256) -> Option<H256>;
449
450 fn block_author(&self) -> H160;
452
453 fn gas_limit(&self) -> u64;
455
456 fn chain_id(&self) -> u64;
458
459 #[deprecated(note = "Renamed to `frame_meter`; this alias will be removed in future versions")]
461 fn gas_meter(&self) -> &FrameMeter<Self::T>;
462
463 #[deprecated(
465 note = "Renamed to `frame_meter_mut`; this alias will be removed in future versions"
466 )]
467 fn gas_meter_mut(&mut self) -> &mut FrameMeter<Self::T>;
468
469 fn frame_meter(&self) -> &FrameMeter<Self::T>;
471
472 fn frame_meter_mut(&mut self) -> &mut FrameMeter<Self::T>;
474
475 fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>;
477
478 fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool;
480
481 fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], DispatchError>;
483
484 #[cfg(any(test, feature = "runtime-benchmarks"))]
486 fn contract_info(&mut self) -> &mut ContractInfo<Self::T>;
487
488 #[cfg(any(feature = "runtime-benchmarks", test))]
492 fn transient_storage(&mut self) -> &mut TransientStorage<Self::T>;
493
494 fn is_read_only(&self) -> bool;
496
497 fn is_delegate_call(&self) -> bool;
499
500 fn last_frame_output(&self) -> &ExecReturnValue;
502
503 fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue;
505
506 fn copy_code_slice(&mut self, buf: &mut [u8], address: &H160, code_offset: usize);
514
515 fn terminate_caller(&mut self, beneficiary: &H160) -> Result<(), DispatchError>;
524
525 fn effective_gas_price(&self) -> U256;
527
528 fn gas_left(&self) -> u64;
530
531 fn get_storage(&mut self, key: &Key) -> Option<Vec<u8>>;
536
537 fn get_storage_size(&mut self, key: &Key) -> Option<u32>;
542
543 fn set_storage(
546 &mut self,
547 key: &Key,
548 value: Option<Vec<u8>>,
549 take_old: bool,
550 ) -> Result<WriteOutcome, DispatchError>;
551
552 fn charge_storage(&mut self, diff: &Diff) -> DispatchResult;
554}
555
556#[derive(
558 Copy,
559 Clone,
560 PartialEq,
561 Eq,
562 Debug,
563 codec::Decode,
564 codec::Encode,
565 codec::MaxEncodedLen,
566 scale_info::TypeInfo,
567)]
568pub enum ExportedFunction {
569 Constructor,
571 Call,
573}
574
575pub trait Executable<T: Config>: Sized {
580 fn from_storage<S: State>(
585 code_hash: H256,
586 meter: &mut ResourceMeter<T, S>,
587 ) -> Result<Self, DispatchError>;
588
589 fn from_evm_init_code(code: Vec<u8>, owner: AccountIdOf<T>) -> Result<Self, DispatchError>;
591
592 fn execute<E: Ext<T = T>>(
602 self,
603 ext: &mut E,
604 function: ExportedFunction,
605 input_data: Vec<u8>,
606 ) -> ExecResult;
607
608 fn code_info(&self) -> &CodeInfo<T>;
610
611 fn code(&self) -> &[u8];
613
614 fn code_hash(&self) -> &H256;
616}
617
618pub struct Stack<'a, T: Config, E> {
624 origin: Origin<T>,
633 transaction_meter: &'a mut TransactionMeter<T>,
635 timestamp: MomentOf<T>,
637 block_number: BlockNumberFor<T>,
639 frames: BoundedVec<Frame<T>, ConstU32<{ limits::CALL_STACK_DEPTH }>>,
642 first_frame: Frame<T>,
644 transient_storage: TransientStorage<T>,
646 exec_config: &'a ExecConfig<T>,
648 _phantom: PhantomData<E>,
650}
651
652struct Frame<T: Config> {
657 account_id: T::AccountId,
659 contract_info: CachedContract<T>,
661 value_transferred: U256,
663 entry_point: ExportedFunction,
665 frame_meter: FrameMeter<T>,
667 allows_reentry: bool,
669 read_only: bool,
671 delegate: Option<DelegateInfo<T>>,
674 last_frame_output: ExecReturnValue,
676 contracts_created: BTreeSet<T::AccountId>,
678 contracts_to_be_destroyed: BTreeMap<T::AccountId, TerminateArgs<T>>,
680}
681
682#[derive(Clone, DebugNoBound)]
685pub struct DelegateInfo<T: Config> {
686 pub caller: Origin<T>,
688 pub callee: H160,
690}
691
692enum ExecutableOrPrecompile<T: Config, E: Executable<T>, Env> {
694 Executable(E),
696 Precompile { instance: PrecompileInstance<Env>, _phantom: PhantomData<T> },
698}
699
700impl<T: Config, E: Executable<T>, Env> ExecutableOrPrecompile<T, E, Env> {
701 fn as_executable(&self) -> Option<&E> {
702 if let Self::Executable(executable) = self { Some(executable) } else { None }
703 }
704
705 fn is_pvm(&self) -> bool {
706 match self {
707 Self::Executable(e) => e.code_info().is_pvm(),
708 _ => false,
709 }
710 }
711
712 fn as_precompile(&self) -> Option<&PrecompileInstance<Env>> {
713 if let Self::Precompile { instance, .. } = self { Some(instance) } else { None }
714 }
715
716 #[cfg(any(feature = "runtime-benchmarks", test))]
717 fn into_executable(self) -> Option<E> {
718 if let Self::Executable(executable) = self { Some(executable) } else { None }
719 }
720}
721
722enum FrameArgs<'a, T: Config, E> {
726 Call {
727 dest: T::AccountId,
729 cached_info: Option<ContractInfo<T>>,
731 delegated_call: Option<DelegateInfo<T>>,
735 },
736 Instantiate {
737 sender: T::AccountId,
739 executable: E,
741 salt: Option<&'a [u8; 32]>,
743 input_data: &'a [u8],
745 },
746}
747
748enum CachedContract<T: Config> {
750 Cached(ContractInfo<T>),
752 Invalidated,
756 None,
758}
759
760impl<T: Config> Frame<T> {
761 fn contract_info(&mut self) -> &mut ContractInfo<T> {
763 self.contract_info.get(&self.account_id)
764 }
765}
766
767macro_rules! get_cached_or_panic_after_load {
771 ($c:expr) => {{
772 if let CachedContract::Cached(contract) = $c {
773 contract
774 } else {
775 panic!(
776 "It is impossible to remove a contract that is on the call stack;\
777 See implementations of terminate;\
778 Therefore fetching a contract will never fail while using an account id
779 that is currently active on the call stack;\
780 qed"
781 );
782 }
783 }};
784}
785
786macro_rules! top_frame {
791 ($stack:expr) => {
792 $stack.frames.last().unwrap_or(&$stack.first_frame)
793 };
794}
795
796macro_rules! top_frame_mut {
801 ($stack:expr) => {
802 $stack.frames.last_mut().unwrap_or(&mut $stack.first_frame)
803 };
804}
805
806impl<T: Config> CachedContract<T> {
807 fn into_contract(self) -> Option<ContractInfo<T>> {
809 if let CachedContract::Cached(contract) = self { Some(contract) } else { None }
810 }
811
812 fn as_contract(&mut self) -> Option<&mut ContractInfo<T>> {
814 if let CachedContract::Cached(contract) = self { Some(contract) } else { None }
815 }
816
817 fn load(&mut self, account_id: &T::AccountId) {
819 if let CachedContract::Invalidated = self &&
820 let Some(contract) =
821 AccountInfo::<T>::load_contract(&T::AddressMapper::to_address(account_id))
822 {
823 *self = CachedContract::Cached(contract);
824 }
825 }
826
827 fn get(&mut self, account_id: &T::AccountId) -> &mut ContractInfo<T> {
829 self.load(account_id);
830 get_cached_or_panic_after_load!(self)
831 }
832
833 fn invalidate(&mut self) {
835 if matches!(self, CachedContract::Cached(_)) {
836 *self = CachedContract::Invalidated;
837 }
838 }
839}
840
841impl<'a, T, E> Stack<'a, T, E>
842where
843 T: Config,
844 E: Executable<T>,
845{
846 pub fn run_call(
852 origin: Origin<T>,
853 dest: H160,
854 transaction_meter: &'a mut TransactionMeter<T>,
855 value: U256,
856 input_data: Vec<u8>,
857 exec_config: &ExecConfig<T>,
858 ) -> ExecResult {
859 let dest = T::AddressMapper::to_account_id(&dest);
860 if let Some((mut stack, executable)) = Stack::<'_, T, E>::new(
861 FrameArgs::Call { dest: dest.clone(), cached_info: None, delegated_call: None },
862 origin.clone(),
863 transaction_meter,
864 value,
865 exec_config,
866 &input_data,
867 )? {
868 stack.run(executable, input_data).map(|_| stack.first_frame.last_frame_output)
869 } else {
870 if_tracing(|t| {
871 t.enter_child_span(
872 origin.account_id().map(T::AddressMapper::to_address).unwrap_or_default(),
873 T::AddressMapper::to_address(&dest),
874 None,
875 false,
876 value,
877 &input_data,
878 Default::default(),
879 );
880 });
881
882 let result = if let Some(mock_answer) =
883 exec_config.mock_handler.as_ref().and_then(|handler| {
884 handler.mock_call(T::AddressMapper::to_address(&dest), &input_data, value)
885 }) {
886 Ok(mock_answer)
887 } else {
888 Self::transfer_from_origin(
889 &origin,
890 &origin,
891 &dest,
892 value,
893 transaction_meter,
894 exec_config,
895 )
896 };
897
898 if_tracing(|t| {
899 let gas_used =
900 transaction_meter.total_consumed_gas().try_into().unwrap_or(u64::MAX);
901 let weight_consumed = transaction_meter.weight_consumed();
902 match result {
903 Ok(ref output) => t.exit_child_span(&output, gas_used, weight_consumed),
904 Err(e) => {
905 t.exit_child_span_with_error(e.error.into(), gas_used, weight_consumed)
906 },
907 }
908 });
909
910 log::trace!(target: LOG_TARGET, "call finished with: {result:?}");
911
912 result
913 }
914 }
915
916 pub fn run_instantiate(
922 origin: T::AccountId,
923 executable: E,
924 transaction_meter: &'a mut TransactionMeter<T>,
925 value: U256,
926 input_data: Vec<u8>,
927 salt: Option<&[u8; 32]>,
928 exec_config: &ExecConfig<T>,
929 ) -> Result<(H160, ExecReturnValue), ExecError> {
930 let deployer = T::AddressMapper::to_address(&origin);
931 let (mut stack, executable) = Stack::<'_, T, E>::new(
932 FrameArgs::Instantiate {
933 sender: origin.clone(),
934 executable,
935 salt,
936 input_data: input_data.as_ref(),
937 },
938 Origin::from_account_id(origin),
939 transaction_meter,
940 value,
941 exec_config,
942 &input_data,
943 )?
944 .expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE);
945 let address = T::AddressMapper::to_address(&stack.top_frame().account_id);
946 let result = stack
947 .run(executable, input_data)
948 .map(|_| (address, stack.first_frame.last_frame_output));
949 if let Ok((contract, output)) = &result &&
950 !output.did_revert()
951 {
952 Contracts::<T>::deposit_event(Event::Instantiated { deployer, contract: *contract });
953 }
954 log::trace!(target: LOG_TARGET, "instantiate finished with: {result:?}");
955 result
956 }
957
958 #[cfg(any(feature = "runtime-benchmarks", test))]
959 pub fn bench_new_call(
960 dest: H160,
961 origin: Origin<T>,
962 transaction_meter: &'a mut TransactionMeter<T>,
963 value: BalanceOf<T>,
964 exec_config: &'a ExecConfig<T>,
965 read_only: bool,
966 delegate_call: bool,
967 ) -> (Self, E) {
968 let call = Self::new(
969 FrameArgs::Call {
970 dest: T::AddressMapper::to_account_id(&dest),
971 cached_info: None,
972 delegated_call: None,
973 },
974 origin,
975 transaction_meter,
976 value.into(),
977 exec_config,
978 &Default::default(),
979 )
980 .unwrap()
981 .unwrap();
982 let mut stack = call.0;
983 if read_only {
984 stack.top_frame_mut().read_only = true;
985 }
986 if delegate_call {
987 let frame = stack.top_frame_mut();
988 frame.delegate = Some(DelegateInfo {
989 caller: Origin::from_account_id(frame.account_id.clone()),
990 callee: H160::zero(),
991 });
992 }
993 (stack, call.1.into_executable().unwrap())
994 }
995
996 fn new(
1001 args: FrameArgs<T, E>,
1002 origin: Origin<T>,
1003 transaction_meter: &'a mut TransactionMeter<T>,
1004 value: U256,
1005 exec_config: &'a ExecConfig<T>,
1006 input_data: &Vec<u8>,
1007 ) -> Result<Option<(Self, ExecutableOrPrecompile<T, E, Self>)>, ExecError> {
1008 origin.ensure_mapped()?;
1009 let Some((first_frame, executable)) = Self::new_frame(
1010 args,
1011 value,
1012 transaction_meter,
1013 &CallResources::NoLimits,
1014 false,
1015 true,
1016 input_data,
1017 exec_config,
1018 )?
1019 else {
1020 return Ok(None);
1021 };
1022
1023 let mut timestamp = T::Time::now();
1024 let mut block_number = <frame_system::Pallet<T>>::block_number();
1025 if let Some(timestamp_override) =
1027 exec_config.is_dry_run.as_ref().and_then(|cfg| cfg.timestamp_override)
1028 {
1029 block_number = block_number.saturating_add(1u32.into());
1030 let delta = 1000u32.into();
1032 timestamp = cmp::max(timestamp.saturating_add(delta), timestamp_override);
1033 }
1034
1035 let stack = Self {
1036 origin,
1037 transaction_meter,
1038 timestamp,
1039 block_number,
1040 first_frame,
1041 frames: Default::default(),
1042 transient_storage: TransientStorage::new(limits::TRANSIENT_STORAGE_BYTES),
1043 exec_config,
1044 _phantom: Default::default(),
1045 };
1046 Ok(Some((stack, executable)))
1047 }
1048
1049 fn new_frame<S: State>(
1054 frame_args: FrameArgs<T, E>,
1055 value_transferred: U256,
1056 meter: &mut ResourceMeter<T, S>,
1057 call_resources: &CallResources<T>,
1058 read_only: bool,
1059 origin_is_caller: bool,
1060 input_data: &[u8],
1061 exec_config: &ExecConfig<T>,
1062 ) -> Result<Option<(Frame<T>, ExecutableOrPrecompile<T, E, Self>)>, ExecError> {
1063 let (account_id, contract_info, executable, delegate, entry_point) = match frame_args {
1064 FrameArgs::Call { dest, cached_info, delegated_call } => {
1065 let address = T::AddressMapper::to_address(&dest);
1066 let precompile = <AllPrecompiles<T>>::get(address.as_fixed_bytes());
1067
1068 let mut contract = match (cached_info, &precompile) {
1071 (Some(info), _) => CachedContract::Cached(info),
1072 (None, None) => {
1073 if let Some(info) = AccountInfo::<T>::load_contract(&address) {
1074 CachedContract::Cached(info)
1075 } else {
1076 return Ok(None);
1077 }
1078 },
1079 (None, Some(precompile)) if precompile.has_contract_info() => {
1080 log::trace!(target: LOG_TARGET, "found precompile for address {address:?}");
1081 if let Some(info) = AccountInfo::<T>::load_contract(&address) {
1082 CachedContract::Cached(info)
1083 } else {
1084 let info = ContractInfo::new(&address, 0u32.into(), H256::zero())?;
1085 CachedContract::Cached(info)
1086 }
1087 },
1088 (None, Some(_)) => CachedContract::None,
1089 };
1090
1091 let delegated_call = delegated_call.or_else(|| {
1092 exec_config.mock_handler.as_ref().and_then(|mock_handler| {
1093 mock_handler.mock_delegated_caller(address, input_data)
1094 })
1095 });
1096 let executable = if let Some(delegated_call) = &delegated_call {
1098 if let Some(precompile) =
1099 <AllPrecompiles<T>>::get(delegated_call.callee.as_fixed_bytes())
1100 {
1101 ExecutableOrPrecompile::Precompile {
1102 instance: precompile,
1103 _phantom: Default::default(),
1104 }
1105 } else {
1106 let Some(info) = AccountInfo::<T>::load_contract(&delegated_call.callee)
1107 else {
1108 return Ok(None);
1109 };
1110 let executable = E::from_storage(info.code_hash, meter)?;
1111 ExecutableOrPrecompile::Executable(executable)
1112 }
1113 } else {
1114 if let Some(precompile) = precompile {
1115 ExecutableOrPrecompile::Precompile {
1116 instance: precompile,
1117 _phantom: Default::default(),
1118 }
1119 } else {
1120 let executable = E::from_storage(
1121 contract
1122 .as_contract()
1123 .expect("When not a precompile the contract was loaded above; qed")
1124 .code_hash,
1125 meter,
1126 )?;
1127 ExecutableOrPrecompile::Executable(executable)
1128 }
1129 };
1130
1131 (dest, contract, executable, delegated_call, ExportedFunction::Call)
1132 },
1133 FrameArgs::Instantiate { sender, executable, salt, input_data } => {
1134 let deployer = T::AddressMapper::to_address(&sender);
1135 let account_nonce = <System<T>>::account_nonce(&sender);
1136 let address = if let Some(salt) = salt {
1137 address::create2(&deployer, executable.code(), input_data, salt)
1138 } else {
1139 use sp_runtime::Saturating;
1140 address::create1(
1141 &deployer,
1142 if origin_is_caller {
1145 account_nonce.saturating_sub(1u32.into()).saturated_into()
1146 } else {
1147 account_nonce.saturated_into()
1148 },
1149 )
1150 };
1151 let contract = ContractInfo::new(
1152 &address,
1153 <System<T>>::account_nonce(&sender),
1154 *executable.code_hash(),
1155 )?;
1156 (
1157 T::AddressMapper::to_fallback_account_id(&address),
1158 CachedContract::Cached(contract),
1159 ExecutableOrPrecompile::Executable(executable),
1160 None,
1161 ExportedFunction::Constructor,
1162 )
1163 },
1164 };
1165
1166 let frame = Frame {
1167 delegate,
1168 value_transferred,
1169 contract_info,
1170 account_id,
1171 entry_point,
1172 frame_meter: meter.new_nested(call_resources)?,
1173 allows_reentry: true,
1174 read_only,
1175 last_frame_output: Default::default(),
1176 contracts_created: Default::default(),
1177 contracts_to_be_destroyed: Default::default(),
1178 };
1179
1180 Ok(Some((frame, executable)))
1181 }
1182
1183 fn push_frame(
1185 &mut self,
1186 frame_args: FrameArgs<T, E>,
1187 value_transferred: U256,
1188 call_resources: &CallResources<T>,
1189 read_only: bool,
1190 input_data: &[u8],
1191 ) -> Result<Option<ExecutableOrPrecompile<T, E, Self>>, ExecError> {
1192 if self.frames.len() as u32 == limits::CALL_STACK_DEPTH {
1193 return Err(Error::<T>::MaxCallDepthReached.into());
1194 }
1195
1196 let frame = self.top_frame();
1205 if let (CachedContract::Cached(contract), ExportedFunction::Call) =
1206 (&frame.contract_info, frame.entry_point)
1207 {
1208 let mut contract_with_pending_changes = contract.clone();
1209 frame
1210 .frame_meter
1211 .apply_pending_storage_changes(&mut contract_with_pending_changes);
1212 AccountInfo::<T>::insert_contract(
1213 &T::AddressMapper::to_address(&frame.account_id),
1214 contract_with_pending_changes,
1215 );
1216 }
1217
1218 let frame = top_frame_mut!(self);
1219 let meter = &mut frame.frame_meter;
1220 if let Some((frame, executable)) = Self::new_frame(
1221 frame_args,
1222 value_transferred,
1223 meter,
1224 call_resources,
1225 read_only,
1226 false,
1227 input_data,
1228 self.exec_config,
1229 )? {
1230 self.frames.try_push(frame).map_err(|_| Error::<T>::MaxCallDepthReached)?;
1231 Ok(Some(executable))
1232 } else {
1233 Ok(None)
1234 }
1235 }
1236
1237 fn run(
1241 &mut self,
1242 executable: ExecutableOrPrecompile<T, E, Self>,
1243 input_data: Vec<u8>,
1244 ) -> Result<(), ExecError> {
1245 let frame = self.top_frame();
1246 let entry_point = frame.entry_point;
1247 let is_pvm = executable.is_pvm();
1248
1249 if_tracing(|tracer| {
1250 let (from, to) = match frame.delegate.as_ref() {
1253 Some(delegate) => {
1254 (T::AddressMapper::to_address(&frame.account_id), delegate.callee)
1255 },
1256 None => (
1257 self.caller()
1258 .account_id()
1259 .map(T::AddressMapper::to_address)
1260 .unwrap_or_default(),
1261 T::AddressMapper::to_address(&frame.account_id),
1262 ),
1263 };
1264 tracer.enter_child_span(
1265 from,
1266 to,
1267 frame.delegate.as_ref().map(|delegate| delegate.callee),
1268 frame.read_only,
1269 frame.value_transferred,
1270 &input_data,
1271 frame
1272 .frame_meter
1273 .eth_gas_left()
1274 .unwrap_or_default()
1275 .try_into()
1276 .unwrap_or_default(),
1277 );
1278 });
1279 let mock_answer = self.exec_config.mock_handler.as_ref().and_then(|handler| {
1280 handler.mock_call(
1281 frame
1282 .delegate
1283 .as_ref()
1284 .map(|delegate| delegate.callee)
1285 .unwrap_or(T::AddressMapper::to_address(&frame.account_id)),
1286 &input_data,
1287 frame.value_transferred,
1288 )
1289 });
1290 let frames_len = self.frames.len();
1294 if let Some(caller_frame) = match frames_len {
1295 0 => None,
1296 1 => Some(&mut self.first_frame.last_frame_output),
1297 _ => self.frames.get_mut(frames_len - 2).map(|frame| &mut frame.last_frame_output),
1298 } {
1299 *caller_frame = Default::default();
1300 }
1301
1302 self.with_transient_storage_mut(|transient_storage| {
1303 transient_storage.start_transaction();
1304 });
1305 let is_first_frame = self.frames.is_empty();
1306
1307 let do_transaction = || -> ExecResult {
1308 let caller = self.caller();
1309 let bump_nonce = self.exec_config.bump_nonce;
1310 let frame = top_frame_mut!(self);
1311 let account_id = &frame.account_id.clone();
1312
1313 if u32::try_from(input_data.len())
1314 .map(|len| len > limits::CALLDATA_BYTES)
1315 .unwrap_or(true)
1316 {
1317 Err(<Error<T>>::CallDataTooLarge)?;
1318 }
1319
1320 if entry_point == ExportedFunction::Constructor {
1323 if !frame_system::Pallet::<T>::account_exists(&account_id) {
1324 T::Deposit::init_contract(account_id)?;
1325 }
1326
1327 <System<T>>::inc_consumers(account_id)?;
1332
1333 <System<T>>::inc_account_nonce(account_id);
1335
1336 if bump_nonce || !is_first_frame {
1337 <System<T>>::inc_account_nonce(caller.account_id()?);
1340 }
1341 if is_pvm {
1343 <CodeInfo<T>>::increment_refcount(
1344 *executable
1345 .as_executable()
1346 .expect("Precompiles cannot be instantiated; qed")
1347 .code_hash(),
1348 )?;
1349 }
1350 }
1351
1352 if frame.delegate.is_none() {
1356 Self::transfer_from_origin(
1357 &self.origin,
1358 &caller,
1359 account_id,
1360 frame.value_transferred,
1361 &mut frame.frame_meter,
1362 self.exec_config,
1363 )?;
1364 }
1365
1366 if let Some(precompile) = executable.as_precompile() &&
1373 precompile.has_contract_info() &&
1374 frame.delegate.is_none() &&
1375 !<System<T>>::account_exists(account_id)
1376 {
1377 T::Currency::mint_into(account_id, T::Currency::minimum_balance())?;
1380 <System<T>>::inc_consumers(account_id)?;
1382 }
1383
1384 let mut code_deposit = executable
1385 .as_executable()
1386 .map(|exec| exec.code_info().deposit())
1387 .unwrap_or_default();
1388
1389 let mut output = match executable {
1390 ExecutableOrPrecompile::Executable(executable) => {
1391 executable.execute(self, entry_point, input_data)
1392 },
1393 ExecutableOrPrecompile::Precompile { instance, .. } => {
1394 instance.call(input_data, self)
1395 },
1396 }
1397 .and_then(|output| {
1398 if u32::try_from(output.data.len())
1399 .map(|len| len > limits::CALLDATA_BYTES)
1400 .unwrap_or(true)
1401 {
1402 Err(<Error<T>>::ReturnDataTooLarge)?;
1403 }
1404 Ok(output)
1405 })
1406 .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?;
1407
1408 if output.did_revert() {
1410 return Ok(output);
1411 }
1412
1413 let frame = if entry_point == ExportedFunction::Constructor {
1416 let frame = top_frame_mut!(self);
1417 if !is_pvm {
1420 let data = if crate::tracing::if_tracing(|_| {}).is_none() &&
1424 self.exec_config.is_dry_run.is_none()
1425 {
1426 core::mem::replace(&mut output.data, Default::default())
1427 } else {
1428 output.data.clone()
1429 };
1430
1431 let mut module = match &self.origin {
1435 Origin::Signed(o) => {
1436 crate::ContractBlob::<T>::from_evm_runtime_code(data, o.clone())?
1437 },
1438 Origin::Root => {
1439 crate::ContractBlob::<T>::from_evm_runtime_code_with_deposit(
1440 data,
1441 crate::Pallet::<T>::account_id(),
1442 Zero::zero(),
1443 )?
1444 },
1445 };
1446 module.store_code(&self.exec_config, &mut frame.frame_meter)?;
1447 code_deposit = module.code_info().deposit();
1448
1449 let contract_info = frame.contract_info();
1450 contract_info.code_hash = *module.code_hash();
1451 <CodeInfo<T>>::increment_refcount(contract_info.code_hash)?;
1452 }
1453
1454 let deposit = frame.contract_info().update_base_deposit(code_deposit);
1455 frame.frame_meter.charge_contract_deposit_and_transfer(
1456 frame.account_id.clone(),
1457 StorageDeposit::Charge(deposit),
1458 )?;
1459 frame
1460 } else {
1461 self.top_frame_mut()
1462 };
1463
1464 let contract = frame.contract_info.as_contract();
1468 frame
1469 .frame_meter
1470 .finalize(contract)
1471 .map_err(|e| ExecError { error: e, origin: ErrorOrigin::Callee })?;
1472
1473 Ok(output)
1474 };
1475
1476 let transaction_outcome =
1483 with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
1484 let output = if let Some(mock_answer) = mock_answer {
1485 Ok(mock_answer)
1486 } else {
1487 do_transaction()
1488 };
1489 match &output {
1490 Ok(result) if !result.did_revert() => {
1491 TransactionOutcome::Commit(Ok((true, output)))
1492 },
1493 _ => TransactionOutcome::Rollback(Ok((false, output))),
1494 }
1495 });
1496
1497 let (success, output) = match transaction_outcome {
1498 Ok((success, output)) => {
1500 if_tracing(|tracer| {
1501 let frame_meter = &top_frame!(self).frame_meter;
1502
1503 let gas_consumed = if is_first_frame {
1506 frame_meter.total_consumed_gas()
1507 } else {
1508 frame_meter.eth_gas_consumed()
1509 };
1510
1511 let gas_consumed: u64 = gas_consumed.try_into().unwrap_or(u64::MAX);
1512 let weight_consumed = frame_meter.weight_consumed();
1513
1514 match &output {
1515 Ok(output) => {
1516 tracer.exit_child_span(&output, gas_consumed, weight_consumed)
1517 },
1518 Err(e) => tracer.exit_child_span_with_error(
1519 e.error.into(),
1520 gas_consumed,
1521 weight_consumed,
1522 ),
1523 }
1524 });
1525
1526 (success, output)
1527 },
1528 Err(error) => {
1531 if_tracing(|tracer| {
1532 let frame_meter = &top_frame!(self).frame_meter;
1533
1534 let gas_consumed = if is_first_frame {
1537 frame_meter.total_consumed_gas()
1538 } else {
1539 frame_meter.eth_gas_consumed()
1540 };
1541
1542 let gas_consumed: u64 = gas_consumed.try_into().unwrap_or(u64::MAX);
1543 let weight_consumed = frame_meter.weight_consumed();
1544 tracer.exit_child_span_with_error(error.into(), gas_consumed, weight_consumed);
1545 });
1546
1547 (false, Err(error.into()))
1548 },
1549 };
1550 self.with_transient_storage_mut(|transient_storage| {
1551 if success {
1552 transient_storage.commit_transaction();
1553 } else {
1554 transient_storage.rollback_transaction();
1555 }
1556 });
1557 log::trace!(target: LOG_TARGET, "frame finished with: {output:?}");
1558
1559 self.pop_frame(success);
1560 output.map(|output| {
1561 self.top_frame_mut().last_frame_output = output;
1562 })
1563 }
1564
1565 fn pop_frame(&mut self, persist: bool) {
1570 let frame = self.frames.pop();
1574
1575 if let Some(mut frame) = frame {
1578 let account_id = &frame.account_id;
1579 let prev = top_frame_mut!(self);
1580
1581 if !persist {
1583 prev.frame_meter.absorb_weight_meter_only(frame.frame_meter);
1584 return;
1585 }
1586
1587 frame.contract_info.load(account_id);
1592 let mut contract = frame.contract_info.into_contract();
1593 prev.frame_meter
1594 .absorb_all_meters(frame.frame_meter, account_id, contract.as_mut());
1595
1596 prev.contracts_created.extend(frame.contracts_created);
1598 prev.contracts_to_be_destroyed.extend(frame.contracts_to_be_destroyed);
1599
1600 if let Some(contract) = contract {
1601 AccountInfo::<T>::insert_contract(
1606 &T::AddressMapper::to_address(account_id),
1607 contract,
1608 );
1609 if let Some(f) = self.frames_mut().find(|f| f.account_id == *account_id) {
1610 f.contract_info.invalidate();
1611 }
1612 }
1613 } else {
1614 if !persist {
1615 self.transaction_meter
1616 .absorb_weight_meter_only(mem::take(&mut self.first_frame.frame_meter));
1617 return;
1618 }
1619
1620 let mut contract = self.first_frame.contract_info.as_contract();
1621 self.transaction_meter.absorb_all_meters(
1622 mem::take(&mut self.first_frame.frame_meter),
1623 &self.first_frame.account_id,
1624 contract.as_deref_mut(),
1625 );
1626
1627 if let Some(contract) = contract {
1628 AccountInfo::<T>::insert_contract(
1629 &T::AddressMapper::to_address(&self.first_frame.account_id),
1630 contract.clone(),
1631 );
1632 }
1633 let contracts_created = mem::take(&mut self.first_frame.contracts_created);
1635 let contracts_to_destroy = mem::take(&mut self.first_frame.contracts_to_be_destroyed);
1636 for (contract_account, args) in contracts_to_destroy {
1637 if args.only_if_same_tx && !contracts_created.contains(&contract_account) {
1638 continue;
1639 }
1640 Self::do_terminate(
1641 &mut self.transaction_meter,
1642 self.exec_config,
1643 &contract_account,
1644 &self.origin,
1645 &args,
1646 )
1647 .ok();
1648 }
1649 }
1650 }
1651
1652 fn transfer<S: State>(
1665 origin: &Origin<T>,
1666 from: &T::AccountId,
1667 to: &T::AccountId,
1668 value: U256,
1669 preservation: Preservation,
1670 meter: &mut ResourceMeter<T, S>,
1671 exec_config: &ExecConfig<T>,
1672 ) -> DispatchResult {
1673 let value = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(value)
1674 .map_err(|_| Error::<T>::BalanceConversionFailed)?;
1675 if value.is_zero() {
1676 return Ok(());
1677 }
1678
1679 if <System<T>>::account_exists(to) {
1680 return transfer_with_dust::<T>(from, to, value, preservation);
1681 }
1682
1683 let origin = origin.account_id()?;
1684 let ed = <T as Config>::Currency::minimum_balance();
1685 let is_eth_tx = exec_config.collect_deposit_from_hold.is_some();
1686 with_transaction(|| -> TransactionOutcome<DispatchResult> {
1687 match meter
1688 .charge_deposit(&StorageDeposit::Charge(ed))
1689 .and_then(|_| {
1690 if is_eth_tx {
1691 let credit = T::FeeInfo::withdraw_txfee(ed)
1692 .ok_or(Error::<T>::StorageDepositNotEnoughFunds)?;
1693 T::Currency::resolve(to, credit)
1694 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
1695 Ok(())
1696 } else {
1697 T::Currency::transfer(origin, to, ed, Preservation::Preserve)
1698 .map(|_| ())
1699 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds.into())
1700 }
1701 })
1702 .and_then(|_| transfer_with_dust::<T>(from, to, value, preservation))
1703 {
1704 Ok(_) => TransactionOutcome::Commit(Ok(())),
1705 Err(err) => TransactionOutcome::Rollback(Err(err)),
1706 }
1707 })
1708 }
1709
1710 fn transfer_from_origin<S: State>(
1712 origin: &Origin<T>,
1713 from: &Origin<T>,
1714 to: &T::AccountId,
1715 value: U256,
1716 meter: &mut ResourceMeter<T, S>,
1717 exec_config: &ExecConfig<T>,
1718 ) -> ExecResult {
1719 let from = match from {
1722 Origin::Signed(caller) => caller,
1723 Origin::Root if value.is_zero() => return Ok(Default::default()),
1724 Origin::Root => return Err(DispatchError::RootNotAllowed.into()),
1725 };
1726 Self::transfer(origin, from, to, value, Preservation::Preserve, meter, exec_config)
1727 .map(|_| Default::default())
1728 .map_err(Into::into)
1729 }
1730
1731 fn do_terminate(
1733 transaction_meter: &mut TransactionMeter<T>,
1734 exec_config: &ExecConfig<T>,
1735 contract_account: &T::AccountId,
1736 origin: &Origin<T>,
1737 args: &TerminateArgs<T>,
1738 ) -> Result<(), DispatchError> {
1739 let contract_address = T::AddressMapper::to_address(contract_account);
1740
1741 let origin: Origin<T> = match origin {
1744 Origin::Signed(o) => Origin::Signed(o.clone()),
1745 Origin::Root => Origin::from_account_id(crate::Pallet::<T>::account_id()),
1746 };
1747
1748 let mut delete_contract = |trie_id: &TrieId, code_hash: &H256| {
1749 let refund =
1751 T::Deposit::refund_all(&contract_account, exec_config.funds(origin.account_id()?))?;
1752
1753 System::<T>::dec_consumers(&contract_account);
1755
1756 T::Deposit::destroy_contract(contract_account)?;
1758
1759 let balance = <Contracts<T>>::convert_native_to_evm(<AccountInfo<T>>::total_balance(
1763 contract_address.into(),
1764 ));
1765 Self::transfer(
1766 &origin,
1767 contract_account,
1768 &args.beneficiary,
1769 balance,
1770 Preservation::Expendable,
1771 transaction_meter,
1772 exec_config,
1773 )?;
1774
1775 let _code_removed = <CodeInfo<T>>::decrement_refcount(*code_hash)?;
1777
1778 ContractInfo::<T>::queue_for_deletion(trie_id.clone(), contract_account.clone());
1780 AccountInfoOf::<T>::remove(contract_address);
1781 ImmutableDataOf::<T>::remove(contract_address);
1782
1783 transaction_meter.terminate(contract_account.clone(), refund);
1786
1787 Ok(())
1788 };
1789
1790 with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
1794 match delete_contract(&args.trie_id, &args.code_hash) {
1795 Ok(()) => {
1796 log::trace!(target: LOG_TARGET, "Terminated {contract_address:?}");
1797 TransactionOutcome::Commit(Ok(()))
1798 },
1799 Err(e) => {
1800 log::debug!(target: LOG_TARGET, "Contract at {contract_address:?} failed to terminate: {e:?}");
1801 TransactionOutcome::Rollback(Err(e))
1802 },
1803 }
1804 })
1805 }
1806
1807 fn top_frame(&self) -> &Frame<T> {
1809 top_frame!(self)
1810 }
1811
1812 fn top_frame_mut(&mut self) -> &mut Frame<T> {
1814 top_frame_mut!(self)
1815 }
1816
1817 fn frames(&self) -> impl Iterator<Item = &Frame<T>> {
1821 core::iter::once(&self.first_frame).chain(&self.frames).rev()
1822 }
1823
1824 fn frames_mut(&mut self) -> impl Iterator<Item = &mut Frame<T>> {
1826 core::iter::once(&mut self.first_frame).chain(&mut self.frames).rev()
1827 }
1828
1829 fn allows_reentry(&self, id: &T::AccountId) -> bool {
1831 !self.frames().any(|f| &f.account_id == id && !f.allows_reentry)
1832 }
1833
1834 fn account_balance(&self, who: &T::AccountId) -> U256 {
1836 let balance = AccountInfo::<T>::balance_of(AccountIdOrAddress::AccountId(who.clone()));
1837 crate::Pallet::<T>::convert_native_to_evm(balance)
1838 }
1839
1840 #[cfg(feature = "runtime-benchmarks")]
1843 pub(crate) fn override_export(&mut self, export: ExportedFunction) {
1844 self.top_frame_mut().entry_point = export;
1845 }
1846
1847 #[cfg(feature = "runtime-benchmarks")]
1848 pub(crate) fn set_block_number(&mut self, block_number: BlockNumberFor<T>) {
1849 self.block_number = block_number;
1850 }
1851
1852 fn block_hash(&self, block_number: U256) -> Option<H256> {
1853 let Ok(block_number) = BlockNumberFor::<T>::try_from(block_number) else {
1854 return None;
1855 };
1856 if block_number >= self.block_number {
1857 return None;
1858 }
1859 if block_number < self.block_number.saturating_sub(256u32.into()) {
1860 return None;
1861 }
1862
1863 match crate::Pallet::<T>::eth_block_hash_from_number(block_number.into()) {
1867 Some(hash) => Some(hash),
1868 None => {
1869 use codec::Decode;
1870 let block_hash = System::<T>::block_hash(&block_number);
1871 Decode::decode(&mut TrailingZeroInput::new(block_hash.as_ref())).ok()
1872 },
1873 }
1874 }
1875
1876 fn has_contract_info(&self) -> bool {
1879 let address = self.address();
1880 let precompile = <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes());
1881 if let Some(precompile) = precompile {
1882 return precompile.has_contract_info();
1883 }
1884 true
1885 }
1886
1887 fn with_transient_storage_mut<R, F: FnOnce(&mut TransientStorage<T>) -> R>(
1888 &mut self,
1889 f: F,
1890 ) -> R {
1891 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1892 f(&mut transient.borrow_mut())
1893 } else {
1894 f(&mut self.transient_storage)
1895 }
1896 }
1897 fn with_transient_storage<R, F: FnOnce(&TransientStorage<T>) -> R>(&self, f: F) -> R {
1898 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1899 f(&transient.borrow())
1900 } else {
1901 f(&self.transient_storage)
1902 }
1903 }
1904}
1905
1906impl<'a, T, E> Ext for Stack<'a, T, E>
1907where
1908 T: Config,
1909 E: Executable<T>,
1910{
1911 fn delegate_call(
1912 &mut self,
1913 call_resources: &CallResources<T>,
1914 address: H160,
1915 input_data: Vec<u8>,
1916 ) -> Result<(), ExecError> {
1917 *self.last_frame_output_mut() = Default::default();
1920
1921 let top_frame = self.top_frame_mut();
1922 let mut contract_info = top_frame.contract_info().clone();
1926 top_frame.frame_meter.apply_pending_storage_changes(&mut contract_info);
1927 let account_id = top_frame.account_id.clone();
1928 let value = top_frame.value_transferred;
1929 if let Some(executable) = self.push_frame(
1930 FrameArgs::Call {
1931 dest: account_id,
1932 cached_info: Some(contract_info),
1933 delegated_call: Some(DelegateInfo {
1934 caller: self.caller().clone(),
1935 callee: address,
1936 }),
1937 },
1938 value,
1939 call_resources,
1940 self.is_read_only(),
1941 &input_data,
1942 )? {
1943 self.run(executable, input_data)
1944 } else {
1945 Ok(())
1947 }
1948 }
1949
1950 fn terminate_if_same_tx(&mut self, beneficiary: &H160) -> Result<CodeRemoved, DispatchError> {
1951 if_tracing(|tracer| {
1952 let addr = T::AddressMapper::to_address(self.account_id());
1953 tracer.terminate(
1954 addr,
1955 *beneficiary,
1956 self.top_frame()
1957 .frame_meter
1958 .eth_gas_left()
1959 .unwrap_or_default()
1960 .try_into()
1961 .unwrap_or_default(),
1962 crate::Pallet::<T>::evm_balance(&addr),
1963 );
1964 });
1965 let frame = top_frame_mut!(self);
1966 let info = frame.contract_info();
1967 let trie_id = info.trie_id.clone();
1968 let code_hash = info.code_hash;
1969 let contract_address = T::AddressMapper::to_address(&frame.account_id);
1970 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
1971
1972 Self::transfer(
1974 &self.origin,
1975 &frame.account_id,
1976 &beneficiary,
1977 <Contracts<T>>::evm_balance(&contract_address),
1978 Preservation::Preserve,
1979 &mut frame.frame_meter,
1980 self.exec_config,
1981 )?;
1982
1983 let account_id = frame.account_id.clone();
1985 self.top_frame_mut().contracts_to_be_destroyed.insert(
1986 account_id,
1987 TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: true },
1988 );
1989 Ok(CodeRemoved::Yes)
1990 }
1991
1992 fn own_code_hash(&mut self) -> &H256 {
1993 &self.top_frame_mut().contract_info().code_hash
1994 }
1995
1996 fn immutable_data_len(&mut self) -> u32 {
1997 self.top_frame_mut().contract_info().immutable_data_len()
1998 }
1999
2000 fn get_immutable_data(&mut self) -> Result<ImmutableData, DispatchError> {
2001 if self.top_frame().entry_point == ExportedFunction::Constructor {
2002 return Err(Error::<T>::InvalidImmutableAccess.into());
2003 }
2004
2005 let address = self
2007 .top_frame()
2008 .delegate
2009 .as_ref()
2010 .map(|d| d.callee)
2011 .unwrap_or(T::AddressMapper::to_address(self.account_id()));
2012 Ok(<ImmutableDataOf<T>>::get(address).ok_or_else(|| Error::<T>::InvalidImmutableAccess)?)
2013 }
2014
2015 fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError> {
2016 let frame = self.top_frame_mut();
2017 if frame.entry_point == ExportedFunction::Call || data.is_empty() {
2018 return Err(Error::<T>::InvalidImmutableAccess.into());
2019 }
2020 frame.contract_info().set_immutable_data_len(data.len() as u32);
2021 <ImmutableDataOf<T>>::insert(T::AddressMapper::to_address(&frame.account_id), &data);
2022 Ok(())
2023 }
2024}
2025
2026impl<'a, T, E> PrecompileWithInfoExt for Stack<'a, T, E>
2027where
2028 T: Config,
2029 E: Executable<T>,
2030{
2031 fn instantiate(
2032 &mut self,
2033 call_resources: &CallResources<T>,
2034 mut code: Code,
2035 value: U256,
2036 input_data: Vec<u8>,
2037 salt: Option<&[u8; 32]>,
2038 ) -> Result<H160, ExecError> {
2039 *self.last_frame_output_mut() = Default::default();
2042
2043 let sender = self.top_frame().account_id.clone();
2044 let executable = {
2045 let executable = match &mut code {
2046 Code::Upload(initcode) => {
2047 if !T::AllowEVMBytecode::get() {
2048 return Err(<Error<T>>::CodeRejected.into());
2049 }
2050 ensure!(input_data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
2051 let initcode = crate::tracing::if_tracing(|_| initcode.clone())
2052 .unwrap_or_else(|| mem::take(initcode));
2053 E::from_evm_init_code(initcode, sender.clone())?
2054 },
2055 Code::Existing(hash) => {
2056 let executable = E::from_storage(*hash, self.frame_meter_mut())?;
2057 ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
2058 executable
2059 },
2060 };
2061 self.push_frame(
2062 FrameArgs::Instantiate {
2063 sender,
2064 executable,
2065 salt,
2066 input_data: input_data.as_ref(),
2067 },
2068 value,
2069 call_resources,
2070 self.is_read_only(),
2071 &input_data,
2072 )?
2073 };
2074 let executable = executable.expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE);
2075
2076 let account_id = self.top_frame().account_id.clone();
2078 self.top_frame_mut().contracts_created.insert(account_id);
2079
2080 let address = T::AddressMapper::to_address(&self.top_frame().account_id);
2081 if_tracing(|t| t.instantiate_code(&code, salt));
2082 self.run(executable, input_data).map(|_| address)
2083 }
2084}
2085
2086impl<'a, T, E> PrecompileExt for Stack<'a, T, E>
2087where
2088 T: Config,
2089 E: Executable<T>,
2090{
2091 type T = T;
2092
2093 fn call(
2094 &mut self,
2095 call_resources: &CallResources<T>,
2096 dest_addr: &H160,
2097 value: U256,
2098 input_data: Vec<u8>,
2099 allows_reentry: ReentrancyProtection,
2100 read_only: bool,
2101 ) -> Result<(), ExecError> {
2102 if allows_reentry == ReentrancyProtection::Strict {
2107 self.top_frame_mut().allows_reentry = false;
2108 }
2109
2110 *self.last_frame_output_mut() = Default::default();
2113
2114 let try_call = || {
2115 let is_read_only = read_only || self.is_read_only();
2117
2118 let dest = if <AllPrecompiles<T>>::get::<Self>(dest_addr.as_fixed_bytes()).is_some() {
2120 T::AddressMapper::to_fallback_account_id(dest_addr)
2121 } else {
2122 T::AddressMapper::to_account_id(dest_addr)
2123 };
2124
2125 if !self.allows_reentry(&dest) {
2126 return Err(<Error<T>>::ReentranceDenied.into());
2127 }
2128
2129 if allows_reentry == ReentrancyProtection::AllowNext {
2130 self.top_frame_mut().allows_reentry = false;
2131 }
2132
2133 let cached_info = self
2141 .frames()
2142 .find(|f| f.entry_point == ExportedFunction::Call && f.account_id == dest)
2143 .and_then(|f| match &f.contract_info {
2144 CachedContract::Cached(contract) => {
2145 let mut contract_with_pending = contract.clone();
2146 f.frame_meter.apply_pending_storage_changes(&mut contract_with_pending);
2147 Some(contract_with_pending)
2148 },
2149 _ => None,
2150 });
2151
2152 if let Some(executable) = self.push_frame(
2153 FrameArgs::Call { dest: dest.clone(), cached_info, delegated_call: None },
2154 value,
2155 call_resources,
2156 is_read_only,
2157 &input_data,
2158 )? {
2159 self.run(executable, input_data)
2160 } else {
2161 if_tracing(|t| {
2162 t.enter_child_span(
2163 T::AddressMapper::to_address(self.account_id()),
2164 T::AddressMapper::to_address(&dest),
2165 None,
2166 is_read_only,
2167 value,
2168 &input_data,
2169 Default::default(),
2170 );
2171 });
2172
2173 let snapshot = if_tracing(|_| top_frame!(self).frame_meter.snapshot());
2174
2175 let result = if let Some(mock_answer) =
2176 self.exec_config.mock_handler.as_ref().and_then(|handler| {
2177 handler.mock_call(T::AddressMapper::to_address(&dest), &input_data, value)
2178 }) {
2179 *self.last_frame_output_mut() = mock_answer.clone();
2180 Ok(mock_answer)
2181 } else if is_read_only && value.is_zero() {
2182 Ok(Default::default())
2183 } else if is_read_only {
2184 Err(Error::<T>::StateChangeDenied.into())
2185 } else {
2186 let account_id = self.account_id().clone();
2187 let frame = top_frame_mut!(self);
2188 Self::transfer_from_origin(
2189 &self.origin,
2190 &Origin::from_account_id(account_id),
2191 &dest,
2192 value,
2193 &mut frame.frame_meter,
2194 self.exec_config,
2195 )
2196 };
2197
2198 if_tracing(|t| {
2199 let snapshot = snapshot.as_ref().expect(
2200 "snapshot is taken inside if_tracing above; tracing state cannot \
2201 change mid-call, so it is Some whenever this closure runs; qed",
2202 );
2203 let (gas_used, weight_delta) =
2204 top_frame!(self).frame_meter.delta_since(snapshot);
2205 match result {
2206 Ok(ref output) => t.exit_child_span(&output, gas_used, weight_delta),
2207 Err(e) => {
2208 t.exit_child_span_with_error(e.error.into(), gas_used, weight_delta)
2209 },
2210 }
2211 });
2212
2213 result.map(|_| ())
2214 }
2215 };
2216
2217 let result = try_call();
2219
2220 self.top_frame_mut().allows_reentry = true;
2222
2223 result
2224 }
2225
2226 fn get_transient_storage(&self, key: &Key) -> Option<Vec<u8>> {
2227 self.with_transient_storage(|transient_storage| {
2228 transient_storage.read(self.account_id(), key)
2229 })
2230 }
2231
2232 fn get_transient_storage_size(&self, key: &Key) -> Option<u32> {
2233 self.with_transient_storage(|transient_storage| {
2234 transient_storage.read(self.account_id(), key).map(|value| value.len() as _)
2235 })
2236 }
2237
2238 fn set_transient_storage(
2239 &mut self,
2240 key: &Key,
2241 value: Option<Vec<u8>>,
2242 take_old: bool,
2243 ) -> Result<WriteOutcome, DispatchError> {
2244 let account_id = self.account_id().clone();
2245 self.with_transient_storage_mut(|transient_storage| {
2246 transient_storage.write(&account_id, key, value, take_old)
2247 })
2248 }
2249
2250 fn account_id(&self) -> &T::AccountId {
2251 &self.top_frame().account_id
2252 }
2253
2254 fn caller(&self) -> Origin<T> {
2255 if let Some(Ok(mock_caller)) = self
2256 .exec_config
2257 .mock_handler
2258 .as_ref()
2259 .and_then(|mock_handler| mock_handler.mock_caller(self.frames.len()))
2260 .map(|mock_caller| Origin::<T>::from_runtime_origin(mock_caller))
2261 {
2262 return mock_caller;
2263 }
2264
2265 if let Some(DelegateInfo { caller, .. }) = &self.top_frame().delegate {
2266 caller.clone()
2267 } else {
2268 self.frames()
2269 .nth(1)
2270 .map(|f| Origin::from_account_id(f.account_id.clone()))
2271 .unwrap_or(self.origin.clone())
2272 }
2273 }
2274
2275 fn caller_of_caller(&self) -> Origin<T> {
2276 let caller_of_caller_frame = match self.frames().nth(2) {
2278 None => return self.origin.clone(),
2279 Some(frame) => frame,
2280 };
2281 if let Some(DelegateInfo { caller, .. }) = &caller_of_caller_frame.delegate {
2282 caller.clone()
2283 } else {
2284 Origin::from_account_id(caller_of_caller_frame.account_id.clone())
2285 }
2286 }
2287
2288 fn origin(&self) -> &Origin<T> {
2289 if let Some(mock_origin) = self
2290 .exec_config
2291 .mock_handler
2292 .as_ref()
2293 .and_then(|mock_handler| mock_handler.mock_origin())
2294 {
2295 return mock_origin;
2296 }
2297
2298 &self.origin
2299 }
2300
2301 fn to_account_id(&self, address: &H160) -> T::AccountId {
2302 T::AddressMapper::to_account_id(address)
2303 }
2304
2305 fn code_hash(&self, address: &H160) -> H256 {
2306 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2307 self.exec_config
2308 .mock_handler
2309 .as_ref()
2310 .and_then(|handler| handler.mocked_code(*address))
2311 }) {
2312 return sp_io::hashing::keccak_256(code).into();
2313 }
2314
2315 <AccountInfo<T>>::load_contract(&address)
2316 .map(|contract| contract.code_hash)
2317 .unwrap_or_else(|| {
2318 if System::<T>::account_exists(&T::AddressMapper::to_account_id(address)) {
2319 return EMPTY_CODE_HASH;
2320 }
2321 H256::zero()
2322 })
2323 }
2324
2325 fn code_size(&self, address: &H160) -> u64 {
2326 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2327 self.exec_config
2328 .mock_handler
2329 .as_ref()
2330 .and_then(|handler| handler.mocked_code(*address))
2331 }) {
2332 return code.len() as u64;
2333 }
2334
2335 <AccountInfo<T>>::load_contract(&address)
2336 .and_then(|contract| CodeInfoOf::<T>::get(contract.code_hash))
2337 .map(|info| info.code_len())
2338 .unwrap_or_default()
2339 }
2340
2341 fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool {
2342 let caller = if use_caller_of_caller { self.caller_of_caller() } else { self.caller() };
2343 self.origin == caller
2344 }
2345
2346 fn caller_is_root(&self, use_caller_of_caller: bool) -> bool {
2347 self.caller_is_origin(use_caller_of_caller) && self.origin == Origin::Root
2349 }
2350
2351 fn origin_is_root(&self) -> bool {
2352 self.origin == Origin::Root
2353 }
2354
2355 fn balance(&self) -> U256 {
2356 self.account_balance(&self.top_frame().account_id)
2357 }
2358
2359 fn balance_of(&self, address: &H160) -> U256 {
2360 let balance =
2361 self.account_balance(&<Self::T as Config>::AddressMapper::to_account_id(address));
2362 if_tracing(|tracer| {
2363 tracer.balance_read(address, balance);
2364 });
2365 balance
2366 }
2367
2368 fn value_transferred(&self) -> U256 {
2369 self.top_frame().value_transferred.into()
2370 }
2371
2372 fn now(&self) -> U256 {
2373 (self.timestamp / 1000u32.into()).into()
2374 }
2375
2376 fn minimum_balance(&self) -> U256 {
2377 let min = T::Currency::minimum_balance();
2378 crate::Pallet::<T>::convert_native_to_evm(min)
2379 }
2380
2381 fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
2382 let contract = T::AddressMapper::to_address(self.account_id());
2383 if_tracing(|tracer| {
2384 tracer.log_event(contract, &topics, &data);
2385 });
2386
2387 block_storage::capture_ethereum_log(&contract, &data, &topics);
2389
2390 Contracts::<Self::T>::deposit_event(Event::ContractEmitted { contract, data, topics });
2391 }
2392
2393 fn block_number(&self) -> U256 {
2394 self.block_number.into()
2395 }
2396
2397 fn block_hash(&self, block_number: U256) -> Option<H256> {
2398 self.block_hash(block_number)
2399 }
2400
2401 fn block_author(&self) -> H160 {
2402 Contracts::<Self::T>::block_author()
2403 }
2404
2405 fn gas_limit(&self) -> u64 {
2406 <Contracts<T>>::evm_block_gas_limit().saturated_into()
2407 }
2408
2409 fn chain_id(&self) -> u64 {
2410 <T as Config>::ChainId::get()
2411 }
2412
2413 fn gas_meter(&self) -> &FrameMeter<Self::T> {
2414 &self.top_frame().frame_meter
2415 }
2416
2417 #[inline]
2418 fn gas_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2419 &mut self.top_frame_mut().frame_meter
2420 }
2421
2422 fn frame_meter(&self) -> &FrameMeter<Self::T> {
2423 &self.top_frame().frame_meter
2424 }
2425
2426 #[inline]
2427 fn frame_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2428 &mut self.top_frame_mut().frame_meter
2429 }
2430
2431 fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> {
2432 secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ())
2433 }
2434
2435 fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool {
2436 sp_io::crypto::sr25519_verify(
2437 &SR25519Signature::from(*signature),
2438 message,
2439 &SR25519Public::from(*pub_key),
2440 )
2441 }
2442
2443 fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], DispatchError> {
2444 Ok(ECDSAPublic::from(*pk)
2445 .to_eth_address()
2446 .or_else(|()| Err(Error::<T>::EcdsaRecoveryFailed))?)
2447 }
2448
2449 #[cfg(any(test, feature = "runtime-benchmarks"))]
2450 fn contract_info(&mut self) -> &mut ContractInfo<Self::T> {
2451 self.top_frame_mut().contract_info()
2452 }
2453
2454 #[cfg(any(feature = "runtime-benchmarks", test))]
2455 fn transient_storage(&mut self) -> &mut TransientStorage<Self::T> {
2456 &mut self.transient_storage
2457 }
2458
2459 fn is_read_only(&self) -> bool {
2460 self.top_frame().read_only
2461 }
2462
2463 fn is_delegate_call(&self) -> bool {
2464 self.top_frame().delegate.is_some()
2465 }
2466
2467 fn last_frame_output(&self) -> &ExecReturnValue {
2468 &self.top_frame().last_frame_output
2469 }
2470
2471 fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue {
2472 &mut self.top_frame_mut().last_frame_output
2473 }
2474
2475 fn copy_code_slice(&mut self, buf: &mut [u8], address: &H160, code_offset: usize) {
2476 let len = buf.len();
2477 if len == 0 {
2478 return;
2479 }
2480
2481 let code_hash = self.code_hash(address);
2482 let code = crate::PristineCode::<T>::get(&code_hash).unwrap_or_default();
2483
2484 let len = len.min(code.len().saturating_sub(code_offset));
2485 if len > 0 {
2486 buf[..len].copy_from_slice(&code[code_offset..code_offset + len]);
2487 }
2488
2489 buf[len..].fill(0);
2490 }
2491
2492 fn terminate_caller(&mut self, beneficiary: &H160) -> Result<(), DispatchError> {
2493 ensure!(self.top_frame().delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2494 let parent = self.frames_mut().nth(1).ok_or_else(|| Error::<T>::ContractNotFound)?;
2495 ensure!(parent.entry_point == ExportedFunction::Call, Error::<T>::TerminatedInConstructor);
2496 ensure!(parent.delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2497
2498 let info = parent.contract_info();
2499 let trie_id = info.trie_id.clone();
2500 let code_hash = info.code_hash;
2501 let contract_address = T::AddressMapper::to_address(&parent.account_id);
2502 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
2503
2504 let parent_account_id = parent.account_id.clone();
2505
2506 Self::transfer(
2508 &self.origin,
2509 &parent_account_id,
2510 &beneficiary,
2511 <Contracts<T>>::evm_balance(&contract_address),
2512 Preservation::Preserve,
2513 &mut top_frame_mut!(self).frame_meter,
2514 &self.exec_config,
2515 )?;
2516
2517 let args = TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: false };
2519 self.top_frame_mut().contracts_to_be_destroyed.insert(parent_account_id, args);
2520
2521 Ok(())
2522 }
2523
2524 fn effective_gas_price(&self) -> U256 {
2525 self.exec_config
2526 .effective_gas_price
2527 .unwrap_or_else(|| <Contracts<T>>::evm_base_fee())
2528 }
2529
2530 fn gas_left(&self) -> u64 {
2531 let frame = self.top_frame();
2532
2533 frame.frame_meter.eth_gas_left().unwrap_or_default().saturated_into::<u64>()
2534 }
2535
2536 fn get_storage(&mut self, key: &Key) -> Option<Vec<u8>> {
2537 assert!(self.has_contract_info());
2538 self.top_frame_mut().contract_info().read(key)
2539 }
2540
2541 fn get_storage_size(&mut self, key: &Key) -> Option<u32> {
2542 assert!(self.has_contract_info());
2543 self.top_frame_mut().contract_info().size(key.into())
2544 }
2545
2546 fn set_storage(
2547 &mut self,
2548 key: &Key,
2549 value: Option<Vec<u8>>,
2550 take_old: bool,
2551 ) -> Result<WriteOutcome, DispatchError> {
2552 assert!(self.has_contract_info());
2553 let frame = self.top_frame_mut();
2554 frame.contract_info.get(&frame.account_id).write(
2555 key.into(),
2556 value,
2557 Some(&mut frame.frame_meter),
2558 take_old,
2559 )
2560 }
2561
2562 fn charge_storage(&mut self, diff: &Diff) -> DispatchResult {
2563 assert!(self.has_contract_info());
2564 self.top_frame_mut().frame_meter.record_contract_storage_changes(diff)
2565 }
2566}
2567
2568pub fn is_precompile<T: Config, E: Executable<T>>(address: &H160) -> bool {
2570 <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes()).is_some()
2571}
2572
2573#[cfg(feature = "runtime-benchmarks")]
2574pub fn bench_do_terminate<T: Config>(
2575 transaction_meter: &mut TransactionMeter<T>,
2576 exec_config: &ExecConfig<T>,
2577 contract_account: &T::AccountId,
2578 origin: &Origin<T>,
2579 beneficiary: T::AccountId,
2580 trie_id: TrieId,
2581 code_hash: H256,
2582 only_if_same_tx: bool,
2583) -> Result<(), DispatchError> {
2584 Stack::<T, crate::ContractBlob<T>>::do_terminate(
2585 transaction_meter,
2586 exec_config,
2587 contract_account,
2588 origin,
2589 &TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx },
2590 )
2591}
2592
2593mod sealing {
2594 use super::*;
2595
2596 pub trait Sealed {}
2597 impl<'a, T: Config, E> Sealed for Stack<'a, T, E> {}
2598
2599 #[cfg(test)]
2600 impl<T: Config> sealing::Sealed for mock_ext::MockExt<T> {}
2601}