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 access_list::{AccessEntry, AccessList, StorageAccessKind},
23 address::{self, AddressMapper},
24 deposit_payment::Deposit as _,
25 evm::{block_storage, fees::InfoT as _, transfer_with_dust},
26 limits,
27 metering::{ChargedAmount, Diff, FrameMeter, ResourceMeter, State, Token, TransactionMeter},
28 precompiles::{All as AllPrecompiles, Instance as PrecompileInstance, Precompiles},
29 primitives::{ExecConfig, ExecReturnValue, StorageDeposit},
30 runtime_decl_for_revive_api::{Decode, Encode, TypeInfo},
31 storage::{AccountIdOrAddress, WriteOutcome},
32 tracing::if_tracing,
33 transient_storage::TransientStorage,
34};
35use alloc::{
36 collections::{BTreeMap, BTreeSet},
37 vec::Vec,
38};
39use core::{cmp, fmt::Debug, marker::PhantomData, mem, ops::ControlFlow};
40use frame_support::{
41 Blake2_128Concat, BoundedVec, DebugNoBound, StorageHasher,
42 crypto::ecdsa::ECDSAExt,
43 dispatch::DispatchResult,
44 ensure,
45 storage::{TransactionOutcome, with_transaction},
46 traits::{
47 Time,
48 fungible::{Balanced as _, Inspect, Mutate},
49 tokens::Preservation,
50 },
51 weights::Weight,
52};
53use frame_system::{
54 Pallet as System, RawOrigin,
55 pallet_prelude::{BlockNumberFor, OriginFor},
56};
57use sp_core::{
58 ConstU32, Get, H160, H256, U256,
59 ecdsa::Public as ECDSAPublic,
60 sr25519::{Public as SR25519Public, Signature as SR25519Signature},
61};
62use sp_io::{crypto::secp256k1_ecdsa_recover_compressed, hashing::blake2_256};
63use sp_runtime::{
64 DispatchError, SaturatedConversion,
65 traits::{BadOrigin, Saturating, TrailingZeroInput, Zero},
66};
67
68#[cfg(test)]
69mod tests;
70
71#[cfg(test)]
72pub mod mock_ext;
73
74pub type AccountIdOf<T> = <T as frame_system::Config>::AccountId;
75pub type MomentOf<T> = <<T as Config>::Time as Time>::Moment;
76pub type ExecResult = Result<ExecReturnValue, ExecError>;
77
78type VarSizedKey = BoundedVec<u8, ConstU32<{ limits::STORAGE_KEY_BYTES }>>;
80
81const 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";
82
83pub const EMPTY_CODE_HASH: H256 =
85 H256(sp_core::hex2array!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"));
86
87#[derive(Debug)]
89pub enum Key {
90 Fix([u8; 32]),
92 Var(VarSizedKey),
94}
95
96impl Key {
97 pub fn unhashed(&self) -> &[u8] {
99 match self {
100 Key::Fix(v) => v.as_ref(),
101 Key::Var(v) => v.as_ref(),
102 }
103 }
104
105 pub fn hash(&self) -> Vec<u8> {
107 match self {
108 Key::Fix(v) => blake2_256(v.as_slice()).to_vec(),
109 Key::Var(v) => Blake2_128Concat::hash(v.as_slice()),
110 }
111 }
112
113 pub fn from_fixed(v: [u8; 32]) -> Self {
114 Self::Fix(v)
115 }
116
117 pub fn try_from_var(v: Vec<u8>) -> Result<Self, ()> {
118 VarSizedKey::try_from(v).map(Self::Var).map_err(|_| ())
119 }
120}
121
122#[derive(Copy, Clone, PartialEq, Debug)]
128pub enum ReentrancyProtection {
129 AllowReentry,
131 Strict,
134 AllowNext,
142}
143
144#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)]
150pub enum ErrorOrigin {
151 Caller,
156 Callee,
158}
159
160#[derive(Copy, Clone, PartialEq, Eq, Debug, codec::Decode, codec::Encode)]
162pub struct ExecError {
163 pub error: DispatchError,
165 pub origin: ErrorOrigin,
167}
168
169impl<T: Into<DispatchError>> From<T> for ExecError {
170 fn from(error: T) -> Self {
171 Self { error: error.into(), origin: ErrorOrigin::Caller }
172 }
173}
174
175#[derive(Clone, Encode, Decode, PartialEq, TypeInfo, DebugNoBound)]
177pub enum Origin<T: Config> {
178 Root,
179 Signed(T::AccountId),
180}
181
182impl<T: Config> Origin<T> {
183 pub fn from_account_id(account_id: T::AccountId) -> Self {
185 Origin::Signed(account_id)
186 }
187
188 pub fn from_runtime_origin(o: OriginFor<T>) -> Result<Self, DispatchError> {
190 match o.into() {
191 Ok(RawOrigin::Root) => Ok(Self::Root),
192 Ok(RawOrigin::Signed(t)) => Ok(Self::Signed(t)),
193 _ => Err(BadOrigin.into()),
194 }
195 }
196
197 pub fn account_id(&self) -> Result<&T::AccountId, DispatchError> {
199 match self {
200 Origin::Signed(id) => Ok(id),
201 Origin::Root => Err(DispatchError::RootNotAllowed),
202 }
203 }
204
205 fn ensure_mapped(&self) -> DispatchResult {
210 match self {
211 Self::Root => Ok(()),
212 Self::Signed(account_id) if T::AddressMapper::is_mapped(account_id) => Ok(()),
213 Self::Signed(_) => Err(<Error<T>>::AccountUnmapped.into()),
214 }
215 }
216}
217
218#[derive(DebugNoBound)]
221pub enum CallResources<T: Config> {
222 NoLimits,
224 WeightDeposit { weight: Weight, deposit_limit: BalanceOf<T> },
226 Ethereum { gas: BalanceOf<T>, add_stipend: bool },
228}
229
230impl<T: Config> CallResources<T> {
231 pub fn from_weight_and_deposit(weight: Weight, deposit_limit: U256) -> Self {
233 Self::WeightDeposit {
234 weight,
235 deposit_limit: deposit_limit.saturated_into::<BalanceOf<T>>(),
236 }
237 }
238
239 pub fn from_ethereum_gas(gas: U256, add_stipend: bool) -> Self {
241 Self::Ethereum { gas: gas.saturated_into::<BalanceOf<T>>(), add_stipend }
242 }
243}
244
245impl<T: Config> Default for CallResources<T> {
246 fn default() -> Self {
247 Self::WeightDeposit { weight: Default::default(), deposit_limit: Default::default() }
248 }
249}
250
251struct TerminateArgs<T: Config> {
253 beneficiary: T::AccountId,
255 trie_id: TrieId,
257 code_hash: H256,
259 only_if_same_tx: bool,
261}
262
263pub trait Ext: PrecompileWithInfoExt {
265 fn delegate_call(
269 &mut self,
270 call_resources: &CallResources<Self::T>,
271 address: H160,
272 input_data: Vec<u8>,
273 ) -> Result<(), ExecError>;
274
275 fn terminate_if_same_tx(&mut self, beneficiary: &H160) -> Result<CodeRemoved, DispatchError>;
282
283 #[allow(dead_code)]
285 fn own_code_hash(&mut self) -> &H256;
286
287 fn immutable_data_len(&mut self) -> u32;
292
293 fn get_immutable_data(&mut self) -> Result<ImmutableData, DispatchError>;
297
298 fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError>;
304}
305
306pub trait PrecompileWithInfoExt: PrecompileExt {
308 fn instantiate(
314 &mut self,
315 limits: &CallResources<Self::T>,
316 code: Code,
317 value: U256,
318 input_data: Vec<u8>,
319 salt: Option<&[u8; 32]>,
320 ) -> Result<H160, ExecError>;
321}
322
323pub trait PrecompileExt: sealing::Sealed {
325 type T: Config;
326
327 fn charge(&mut self, weight: Weight) -> Result<ChargedAmount, DispatchError> {
329 self.frame_meter_mut().charge_weight_token(RuntimeCosts::Precompile(weight))
330 }
331
332 fn adjust_gas(&mut self, charged: ChargedAmount, actual_weight: Weight) {
335 self.frame_meter_mut()
336 .adjust_weight(charged, RuntimeCosts::Precompile(actual_weight));
337 }
338
339 #[inline]
342 fn charge_or_halt<Tok: Token<Self::T>>(
343 &mut self,
344 token: Tok,
345 ) -> ControlFlow<crate::vm::evm::Halt, ChargedAmount> {
346 self.frame_meter_mut().charge_or_halt(token)
347 }
348
349 fn call(
351 &mut self,
352 call_resources: &CallResources<Self::T>,
353 to: &H160,
354 value: U256,
355 input_data: Vec<u8>,
356 reentrancy: ReentrancyProtection,
357 read_only: bool,
358 ) -> Result<(), ExecError>;
359
360 fn get_transient_storage(&self, key: &Key) -> Option<Vec<u8>>;
365
366 fn get_transient_storage_size(&self, key: &Key) -> Option<u32>;
371
372 fn set_transient_storage(
375 &mut self,
376 key: &Key,
377 value: Option<Vec<u8>>,
378 take_old: bool,
379 ) -> Result<WriteOutcome, DispatchError>;
380
381 fn caller(&self) -> Origin<Self::T>;
383
384 fn caller_of_caller(&self) -> Origin<Self::T>;
386
387 fn origin(&self) -> &Origin<Self::T>;
389
390 fn to_account_id(&self, address: &H160) -> AccountIdOf<Self::T>;
392
393 fn code_hash(&self, address: &H160) -> H256;
396
397 fn code_size(&self, address: &H160) -> u64;
399
400 fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool;
402
403 fn caller_is_root(&self, use_caller_of_caller: bool) -> bool;
405
406 fn account_id(&self) -> &AccountIdOf<Self::T>;
408
409 fn address(&self) -> H160 {
411 <Self::T as Config>::AddressMapper::to_address(self.account_id())
412 }
413
414 fn balance(&self) -> U256;
418
419 fn balance_of(&self, address: &H160) -> U256;
423
424 fn value_transferred(&self) -> U256;
426
427 fn now(&self) -> U256;
429
430 fn minimum_balance(&self) -> U256;
432
433 fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>);
437
438 fn block_number(&self) -> U256;
440
441 fn block_hash(&self, block_number: U256) -> Option<H256>;
444
445 fn block_author(&self) -> H160;
447
448 fn gas_limit(&self) -> u64;
450
451 fn chain_id(&self) -> u64;
453
454 #[deprecated(note = "Renamed to `frame_meter`; this alias will be removed in future versions")]
456 fn gas_meter(&self) -> &FrameMeter<Self::T>;
457
458 #[deprecated(
460 note = "Renamed to `frame_meter_mut`; this alias will be removed in future versions"
461 )]
462 fn gas_meter_mut(&mut self) -> &mut FrameMeter<Self::T>;
463
464 fn frame_meter(&self) -> &FrameMeter<Self::T>;
466
467 fn frame_meter_mut(&mut self) -> &mut FrameMeter<Self::T>;
469
470 fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()>;
472
473 fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool;
475
476 fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], DispatchError>;
478
479 #[cfg(any(test, feature = "runtime-benchmarks"))]
481 fn contract_info(&mut self) -> &mut ContractInfo<Self::T>;
482
483 #[cfg(any(feature = "runtime-benchmarks", test))]
487 fn transient_storage(&mut self) -> &mut TransientStorage<Self::T>;
488
489 fn is_read_only(&self) -> bool;
491
492 fn is_delegate_call(&self) -> bool;
494
495 fn last_frame_output(&self) -> &ExecReturnValue;
497
498 fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue;
500
501 fn copy_code_slice(&mut self, buf: &mut [u8], address: &H160, code_offset: usize);
509
510 fn terminate_caller(&mut self, beneficiary: &H160) -> Result<(), DispatchError>;
519
520 fn effective_gas_price(&self) -> U256;
522
523 fn gas_left(&self) -> u64;
525
526 fn get_storage(&mut self, key: &Key) -> Option<Vec<u8>>;
531
532 fn get_storage_size(&mut self, key: &Key) -> Option<u32>;
537
538 fn set_storage(
541 &mut self,
542 key: &Key,
543 value: Option<Vec<u8>>,
544 take_old: bool,
545 ) -> Result<WriteOutcome, DispatchError>;
546
547 fn touch_storage_access(&mut self, transient: bool, key: &Key) -> StorageAccessKind;
553
554 fn peek_storage_access(&self, transient: bool, key: &Key) -> StorageAccessKind;
556
557 fn charge_storage(&mut self, diff: &Diff) -> DispatchResult;
559}
560
561#[derive(
563 Copy,
564 Clone,
565 PartialEq,
566 Eq,
567 Debug,
568 codec::Decode,
569 codec::Encode,
570 codec::MaxEncodedLen,
571 scale_info::TypeInfo,
572)]
573pub enum ExportedFunction {
574 Constructor,
576 Call,
578}
579
580pub trait Executable<T: Config>: Sized {
585 fn from_storage<S: State>(
590 code_hash: H256,
591 meter: &mut ResourceMeter<T, S>,
592 ) -> Result<Self, DispatchError>;
593
594 fn from_evm_init_code(code: Vec<u8>, owner: AccountIdOf<T>) -> Result<Self, DispatchError>;
596
597 fn execute<E: Ext<T = T>>(
607 self,
608 ext: &mut E,
609 function: ExportedFunction,
610 input_data: Vec<u8>,
611 ) -> ExecResult;
612
613 fn code_info(&self) -> &CodeInfo<T>;
615
616 fn code(&self) -> &[u8];
618
619 fn code_hash(&self) -> &H256;
621}
622
623pub struct Stack<'a, T: Config, E> {
629 origin: Origin<T>,
638 transaction_meter: &'a mut TransactionMeter<T>,
640 timestamp: MomentOf<T>,
642 block_number: BlockNumberFor<T>,
644 frames: BoundedVec<Frame<T>, ConstU32<{ limits::CALL_STACK_DEPTH }>>,
647 first_frame: Frame<T>,
649 transient_storage: TransientStorage<T>,
651 access_list: AccessList,
653 exec_config: &'a ExecConfig<T>,
655 _phantom: PhantomData<E>,
657}
658
659struct Frame<T: Config> {
664 account_id: T::AccountId,
666 contract_info: CachedContract<T>,
668 value_transferred: U256,
670 entry_point: ExportedFunction,
672 frame_meter: FrameMeter<T>,
674 allows_reentry: bool,
676 read_only: bool,
678 delegate: Option<DelegateInfo<T>>,
681 last_frame_output: ExecReturnValue,
683 contracts_created: BTreeSet<T::AccountId>,
685 contracts_to_be_destroyed: BTreeMap<T::AccountId, TerminateArgs<T>>,
687}
688
689#[derive(Clone, DebugNoBound)]
692pub struct DelegateInfo<T: Config> {
693 pub caller: Origin<T>,
695 pub callee: H160,
697}
698
699enum ExecutableOrPrecompile<T: Config, E: Executable<T>, Env> {
701 Executable(E),
703 Precompile { instance: PrecompileInstance<Env>, _phantom: PhantomData<T> },
705}
706
707impl<T: Config, E: Executable<T>, Env> ExecutableOrPrecompile<T, E, Env> {
708 fn as_executable(&self) -> Option<&E> {
709 if let Self::Executable(executable) = self { Some(executable) } else { None }
710 }
711
712 fn is_pvm(&self) -> bool {
713 match self {
714 Self::Executable(e) => e.code_info().is_pvm(),
715 _ => false,
716 }
717 }
718
719 fn as_precompile(&self) -> Option<&PrecompileInstance<Env>> {
720 if let Self::Precompile { instance, .. } = self { Some(instance) } else { None }
721 }
722
723 #[cfg(any(feature = "runtime-benchmarks", test))]
724 fn into_executable(self) -> Option<E> {
725 if let Self::Executable(executable) = self { Some(executable) } else { None }
726 }
727}
728
729enum FrameArgs<'a, T: Config, E> {
733 Call {
734 dest: T::AccountId,
736 cached_info: Option<ContractInfo<T>>,
738 delegated_call: Option<DelegateInfo<T>>,
742 },
743 Instantiate {
744 sender: T::AccountId,
746 executable: E,
748 salt: Option<&'a [u8; 32]>,
750 input_data: &'a [u8],
752 },
753}
754
755enum CachedContract<T: Config> {
757 Cached(ContractInfo<T>),
759 Invalidated,
763 None,
765}
766
767impl<T: Config> Frame<T> {
768 fn contract_info(&mut self) -> &mut ContractInfo<T> {
770 self.contract_info.get(&self.account_id)
771 }
772}
773
774macro_rules! get_cached_or_panic_after_load {
778 ($c:expr) => {{
779 if let CachedContract::Cached(contract) = $c {
780 contract
781 } else {
782 panic!(
783 "It is impossible to remove a contract that is on the call stack;\
784 See implementations of terminate;\
785 Therefore fetching a contract will never fail while using an account id
786 that is currently active on the call stack;\
787 qed"
788 );
789 }
790 }};
791}
792
793macro_rules! top_frame {
798 ($stack:expr) => {
799 $stack.frames.last().unwrap_or(&$stack.first_frame)
800 };
801}
802
803macro_rules! top_frame_mut {
808 ($stack:expr) => {
809 $stack.frames.last_mut().unwrap_or(&mut $stack.first_frame)
810 };
811}
812
813impl<T: Config> CachedContract<T> {
814 fn into_contract(self) -> Option<ContractInfo<T>> {
816 if let CachedContract::Cached(contract) = self { Some(contract) } else { None }
817 }
818
819 fn as_contract(&mut self) -> Option<&mut ContractInfo<T>> {
821 if let CachedContract::Cached(contract) = self { Some(contract) } else { None }
822 }
823
824 fn load(&mut self, account_id: &T::AccountId) {
826 if let CachedContract::Invalidated = self &&
827 let Some(contract) =
828 AccountInfo::<T>::load_contract(&T::AddressMapper::to_address(account_id))
829 {
830 *self = CachedContract::Cached(contract);
831 }
832 }
833
834 fn get(&mut self, account_id: &T::AccountId) -> &mut ContractInfo<T> {
836 self.load(account_id);
837 get_cached_or_panic_after_load!(self)
838 }
839
840 fn invalidate(&mut self) {
842 if matches!(self, CachedContract::Cached(_)) {
843 *self = CachedContract::Invalidated;
844 }
845 }
846}
847
848impl<'a, T, E> Stack<'a, T, E>
849where
850 T: Config,
851 E: Executable<T>,
852{
853 pub fn run_call(
859 origin: Origin<T>,
860 dest: H160,
861 transaction_meter: &'a mut TransactionMeter<T>,
862 value: U256,
863 input_data: Vec<u8>,
864 exec_config: &ExecConfig<T>,
865 ) -> ExecResult {
866 let dest = T::AddressMapper::to_account_id(&dest);
867 if let Some((mut stack, executable)) = Stack::<'_, T, E>::new(
868 FrameArgs::Call { dest: dest.clone(), cached_info: None, delegated_call: None },
869 origin.clone(),
870 transaction_meter,
871 value,
872 exec_config,
873 &input_data,
874 )? {
875 stack.run(executable, input_data).map(|_| stack.first_frame.last_frame_output)
876 } else {
877 if_tracing(|t| {
878 t.enter_child_span(
879 origin.account_id().map(T::AddressMapper::to_address).unwrap_or_default(),
880 T::AddressMapper::to_address(&dest),
881 None,
882 false,
883 value,
884 &input_data,
885 Default::default(),
886 );
887 });
888
889 let result = if let Some(mock_answer) =
890 exec_config.mock_handler.as_ref().and_then(|handler| {
891 handler.mock_call(T::AddressMapper::to_address(&dest), &input_data, value)
892 }) {
893 Ok(mock_answer)
894 } else {
895 Self::transfer_from_origin(
896 &origin,
897 &origin,
898 &dest,
899 value,
900 transaction_meter,
901 exec_config,
902 )
903 };
904
905 if_tracing(|t| {
906 let gas_used =
907 transaction_meter.total_consumed_gas().try_into().unwrap_or(u64::MAX);
908 let weight_consumed = transaction_meter.weight_consumed();
909 match result {
910 Ok(ref output) => t.exit_child_span(&output, gas_used, weight_consumed),
911 Err(e) => {
912 t.exit_child_span_with_error(e.error.into(), gas_used, weight_consumed)
913 },
914 }
915 });
916
917 log::trace!(target: LOG_TARGET, "call finished with: {result:?}");
918
919 result
920 }
921 }
922
923 pub fn run_instantiate(
929 origin: T::AccountId,
930 executable: E,
931 transaction_meter: &'a mut TransactionMeter<T>,
932 value: U256,
933 input_data: Vec<u8>,
934 salt: Option<&[u8; 32]>,
935 exec_config: &ExecConfig<T>,
936 ) -> Result<(H160, ExecReturnValue), ExecError> {
937 let deployer = T::AddressMapper::to_address(&origin);
938 let (mut stack, executable) = Stack::<'_, T, E>::new(
939 FrameArgs::Instantiate {
940 sender: origin.clone(),
941 executable,
942 salt,
943 input_data: input_data.as_ref(),
944 },
945 Origin::from_account_id(origin),
946 transaction_meter,
947 value,
948 exec_config,
949 &input_data,
950 )?
951 .expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE);
952 let address = T::AddressMapper::to_address(&stack.top_frame().account_id);
953 let result = stack
954 .run(executable, input_data)
955 .map(|_| (address, stack.first_frame.last_frame_output));
956 if let Ok((contract, output)) = &result &&
957 !output.did_revert()
958 {
959 Contracts::<T>::deposit_event(Event::Instantiated { deployer, contract: *contract });
960 }
961 log::trace!(target: LOG_TARGET, "instantiate finished with: {result:?}");
962 result
963 }
964
965 #[cfg(any(feature = "runtime-benchmarks", test))]
966 pub fn bench_new_call(
967 dest: H160,
968 origin: Origin<T>,
969 transaction_meter: &'a mut TransactionMeter<T>,
970 value: BalanceOf<T>,
971 exec_config: &'a ExecConfig<T>,
972 read_only: bool,
973 delegate_call: bool,
974 ) -> (Self, E) {
975 let call = Self::new(
976 FrameArgs::Call {
977 dest: T::AddressMapper::to_account_id(&dest),
978 cached_info: None,
979 delegated_call: None,
980 },
981 origin,
982 transaction_meter,
983 value.into(),
984 exec_config,
985 &Default::default(),
986 )
987 .unwrap()
988 .unwrap();
989 let mut stack = call.0;
990 if read_only {
991 stack.top_frame_mut().read_only = true;
992 }
993 if delegate_call {
994 let frame = stack.top_frame_mut();
995 frame.delegate = Some(DelegateInfo {
996 caller: Origin::from_account_id(frame.account_id.clone()),
997 callee: H160::zero(),
998 });
999 }
1000 (stack, call.1.into_executable().unwrap())
1001 }
1002
1003 fn new(
1008 args: FrameArgs<T, E>,
1009 origin: Origin<T>,
1010 transaction_meter: &'a mut TransactionMeter<T>,
1011 value: U256,
1012 exec_config: &'a ExecConfig<T>,
1013 input_data: &Vec<u8>,
1014 ) -> Result<Option<(Self, ExecutableOrPrecompile<T, E, Self>)>, ExecError> {
1015 origin.ensure_mapped()?;
1016 let Some((first_frame, executable)) = Self::new_frame(
1017 args,
1018 value,
1019 transaction_meter,
1020 &CallResources::NoLimits,
1021 false,
1022 true,
1023 input_data,
1024 exec_config,
1025 )?
1026 else {
1027 return Ok(None);
1028 };
1029
1030 let mut timestamp = T::Time::now();
1031 let mut block_number = <frame_system::Pallet<T>>::block_number();
1032 if let Some(timestamp_override) =
1034 exec_config.is_dry_run.as_ref().and_then(|cfg| cfg.timestamp_override)
1035 {
1036 block_number = block_number.saturating_add(1u32.into());
1037 let delta = 1000u32.into();
1039 timestamp = cmp::max(timestamp.saturating_add(delta), timestamp_override);
1040 }
1041
1042 let stack = Self {
1043 origin,
1044 transaction_meter,
1045 timestamp,
1046 block_number,
1047 first_frame,
1048 frames: Default::default(),
1049 transient_storage: TransientStorage::new(limits::TRANSIENT_STORAGE_BYTES),
1050 access_list: AccessList::new(),
1051 exec_config,
1052 _phantom: Default::default(),
1053 };
1054 Ok(Some((stack, executable)))
1055 }
1056
1057 fn new_frame<S: State>(
1062 frame_args: FrameArgs<T, E>,
1063 value_transferred: U256,
1064 meter: &mut ResourceMeter<T, S>,
1065 call_resources: &CallResources<T>,
1066 read_only: bool,
1067 origin_is_caller: bool,
1068 input_data: &[u8],
1069 exec_config: &ExecConfig<T>,
1070 ) -> Result<Option<(Frame<T>, ExecutableOrPrecompile<T, E, Self>)>, ExecError> {
1071 let (account_id, contract_info, executable, delegate, entry_point) = match frame_args {
1072 FrameArgs::Call { dest, cached_info, delegated_call } => {
1073 let address = T::AddressMapper::to_address(&dest);
1074 let precompile = <AllPrecompiles<T>>::get(address.as_fixed_bytes());
1075
1076 let mut contract = match (cached_info, &precompile) {
1079 (Some(info), _) => CachedContract::Cached(info),
1080 (None, None) => {
1081 if let Some(info) = AccountInfo::<T>::load_contract(&address) {
1082 CachedContract::Cached(info)
1083 } else {
1084 return Ok(None);
1085 }
1086 },
1087 (None, Some(precompile)) if precompile.has_contract_info() => {
1088 log::trace!(target: LOG_TARGET, "found precompile for address {address:?}");
1089 if let Some(info) = AccountInfo::<T>::load_contract(&address) {
1090 CachedContract::Cached(info)
1091 } else {
1092 let info = ContractInfo::new(&address, 0u32.into(), H256::zero())?;
1093 CachedContract::Cached(info)
1094 }
1095 },
1096 (None, Some(_)) => CachedContract::None,
1097 };
1098
1099 let delegated_call = delegated_call.or_else(|| {
1100 exec_config.mock_handler.as_ref().and_then(|mock_handler| {
1101 mock_handler.mock_delegated_caller(address, input_data)
1102 })
1103 });
1104 let executable = if let Some(delegated_call) = &delegated_call {
1106 if let Some(precompile) =
1107 <AllPrecompiles<T>>::get(delegated_call.callee.as_fixed_bytes())
1108 {
1109 ExecutableOrPrecompile::Precompile {
1110 instance: precompile,
1111 _phantom: Default::default(),
1112 }
1113 } else {
1114 let Some(info) = AccountInfo::<T>::load_contract(&delegated_call.callee)
1115 else {
1116 return Ok(None);
1117 };
1118 let executable = E::from_storage(info.code_hash, meter)?;
1119 ExecutableOrPrecompile::Executable(executable)
1120 }
1121 } else {
1122 if let Some(precompile) = precompile {
1123 ExecutableOrPrecompile::Precompile {
1124 instance: precompile,
1125 _phantom: Default::default(),
1126 }
1127 } else {
1128 let executable = E::from_storage(
1129 contract
1130 .as_contract()
1131 .expect("When not a precompile the contract was loaded above; qed")
1132 .code_hash,
1133 meter,
1134 )?;
1135 ExecutableOrPrecompile::Executable(executable)
1136 }
1137 };
1138
1139 (dest, contract, executable, delegated_call, ExportedFunction::Call)
1140 },
1141 FrameArgs::Instantiate { sender, executable, salt, input_data } => {
1142 let deployer = T::AddressMapper::to_address(&sender);
1143 let account_nonce = <System<T>>::account_nonce(&sender);
1144 let address = if let Some(salt) = salt {
1145 address::create2(&deployer, executable.code(), input_data, salt)
1146 } else {
1147 use sp_runtime::Saturating;
1148 address::create1(
1149 &deployer,
1150 if origin_is_caller {
1153 account_nonce.saturating_sub(1u32.into()).saturated_into()
1154 } else {
1155 account_nonce.saturated_into()
1156 },
1157 )
1158 };
1159 let contract = ContractInfo::new(
1160 &address,
1161 <System<T>>::account_nonce(&sender),
1162 *executable.code_hash(),
1163 )?;
1164 (
1165 T::AddressMapper::to_fallback_account_id(&address),
1166 CachedContract::Cached(contract),
1167 ExecutableOrPrecompile::Executable(executable),
1168 None,
1169 ExportedFunction::Constructor,
1170 )
1171 },
1172 };
1173
1174 let frame = Frame {
1175 delegate,
1176 value_transferred,
1177 contract_info,
1178 account_id,
1179 entry_point,
1180 frame_meter: meter.new_nested(call_resources)?,
1181 allows_reentry: true,
1182 read_only,
1183 last_frame_output: Default::default(),
1184 contracts_created: Default::default(),
1185 contracts_to_be_destroyed: Default::default(),
1186 };
1187
1188 Ok(Some((frame, executable)))
1189 }
1190
1191 fn push_frame(
1193 &mut self,
1194 frame_args: FrameArgs<T, E>,
1195 value_transferred: U256,
1196 call_resources: &CallResources<T>,
1197 read_only: bool,
1198 input_data: &[u8],
1199 ) -> Result<Option<ExecutableOrPrecompile<T, E, Self>>, ExecError> {
1200 if self.frames.len() as u32 == limits::CALL_STACK_DEPTH {
1201 return Err(Error::<T>::MaxCallDepthReached.into());
1202 }
1203
1204 let frame = self.top_frame();
1213 if let (CachedContract::Cached(contract), ExportedFunction::Call) =
1214 (&frame.contract_info, frame.entry_point)
1215 {
1216 let mut contract_with_pending_changes = contract.clone();
1217 frame
1218 .frame_meter
1219 .apply_pending_storage_changes(&mut contract_with_pending_changes);
1220 AccountInfo::<T>::insert_contract(
1221 &T::AddressMapper::to_address(&frame.account_id),
1222 contract_with_pending_changes,
1223 );
1224 }
1225
1226 let frame = top_frame_mut!(self);
1227 let meter = &mut frame.frame_meter;
1228 if let Some((frame, executable)) = Self::new_frame(
1229 frame_args,
1230 value_transferred,
1231 meter,
1232 call_resources,
1233 read_only,
1234 false,
1235 input_data,
1236 self.exec_config,
1237 )? {
1238 self.frames.try_push(frame).map_err(|_| Error::<T>::MaxCallDepthReached)?;
1239 Ok(Some(executable))
1240 } else {
1241 Ok(None)
1242 }
1243 }
1244
1245 fn run(
1249 &mut self,
1250 executable: ExecutableOrPrecompile<T, E, Self>,
1251 input_data: Vec<u8>,
1252 ) -> Result<(), ExecError> {
1253 let frame = self.top_frame();
1254 let entry_point = frame.entry_point;
1255 let is_pvm = executable.is_pvm();
1256
1257 if_tracing(|tracer| {
1258 let (from, to) = match frame.delegate.as_ref() {
1261 Some(delegate) => {
1262 (T::AddressMapper::to_address(&frame.account_id), delegate.callee)
1263 },
1264 None => (
1265 self.caller()
1266 .account_id()
1267 .map(T::AddressMapper::to_address)
1268 .unwrap_or_default(),
1269 T::AddressMapper::to_address(&frame.account_id),
1270 ),
1271 };
1272 tracer.enter_child_span(
1273 from,
1274 to,
1275 frame.delegate.as_ref().map(|delegate| delegate.callee),
1276 frame.read_only,
1277 frame.value_transferred,
1278 &input_data,
1279 frame
1280 .frame_meter
1281 .eth_gas_left()
1282 .unwrap_or_default()
1283 .try_into()
1284 .unwrap_or_default(),
1285 );
1286 });
1287 let mock_answer = self.exec_config.mock_handler.as_ref().and_then(|handler| {
1288 handler.mock_call(
1289 frame
1290 .delegate
1291 .as_ref()
1292 .map(|delegate| delegate.callee)
1293 .unwrap_or(T::AddressMapper::to_address(&frame.account_id)),
1294 &input_data,
1295 frame.value_transferred,
1296 )
1297 });
1298 let frames_len = self.frames.len();
1302 if let Some(caller_frame) = match frames_len {
1303 0 => None,
1304 1 => Some(&mut self.first_frame.last_frame_output),
1305 _ => self.frames.get_mut(frames_len - 2).map(|frame| &mut frame.last_frame_output),
1306 } {
1307 *caller_frame = Default::default();
1308 }
1309
1310 self.with_transient_storage_mut(|transient_storage| {
1311 transient_storage.start_transaction();
1312 });
1313 let is_first_frame = self.frames.is_empty();
1314 if !is_first_frame {
1318 self.access_list.enter_frame();
1319 }
1320
1321 let do_transaction = || -> ExecResult {
1322 let caller = self.caller();
1323 let bump_nonce = self.exec_config.bump_nonce;
1324 let frame = top_frame_mut!(self);
1325 let account_id = &frame.account_id.clone();
1326
1327 if u32::try_from(input_data.len())
1328 .map(|len| len > limits::CALLDATA_BYTES)
1329 .unwrap_or(true)
1330 {
1331 Err(<Error<T>>::CallDataTooLarge)?;
1332 }
1333
1334 if entry_point == ExportedFunction::Constructor {
1337 if !frame_system::Pallet::<T>::account_exists(&account_id) {
1338 T::Deposit::init_contract(account_id)?;
1339 }
1340
1341 <System<T>>::inc_consumers(account_id)?;
1346
1347 <System<T>>::inc_account_nonce(account_id);
1349
1350 if bump_nonce || !is_first_frame {
1351 <System<T>>::inc_account_nonce(caller.account_id()?);
1354 }
1355 if is_pvm {
1357 <CodeInfo<T>>::increment_refcount(
1358 *executable
1359 .as_executable()
1360 .expect("Precompiles cannot be instantiated; qed")
1361 .code_hash(),
1362 )?;
1363 }
1364 }
1365
1366 if frame.delegate.is_none() {
1370 Self::transfer_from_origin(
1371 &self.origin,
1372 &caller,
1373 account_id,
1374 frame.value_transferred,
1375 &mut frame.frame_meter,
1376 self.exec_config,
1377 )?;
1378 }
1379
1380 if let Some(precompile) = executable.as_precompile() &&
1387 precompile.has_contract_info() &&
1388 frame.delegate.is_none() &&
1389 !<System<T>>::account_exists(account_id)
1390 {
1391 T::Currency::mint_into(account_id, T::Currency::minimum_balance())?;
1394 <System<T>>::inc_consumers(account_id)?;
1396 }
1397
1398 let mut code_deposit = executable
1399 .as_executable()
1400 .map(|exec| exec.code_info().deposit())
1401 .unwrap_or_default();
1402
1403 let mut output = match executable {
1404 ExecutableOrPrecompile::Executable(executable) => {
1405 executable.execute(self, entry_point, input_data)
1406 },
1407 ExecutableOrPrecompile::Precompile { instance, .. } => {
1408 instance.call(input_data, self)
1409 },
1410 }
1411 .and_then(|output| {
1412 if u32::try_from(output.data.len())
1413 .map(|len| len > limits::CALLDATA_BYTES)
1414 .unwrap_or(true)
1415 {
1416 Err(<Error<T>>::ReturnDataTooLarge)?;
1417 }
1418 Ok(output)
1419 })
1420 .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?;
1421
1422 if output.did_revert() {
1424 return Ok(output);
1425 }
1426
1427 let frame = if entry_point == ExportedFunction::Constructor {
1430 let frame = top_frame_mut!(self);
1431 if !is_pvm {
1434 let data = if crate::tracing::if_tracing(|_| {}).is_none() &&
1438 self.exec_config.is_dry_run.is_none()
1439 {
1440 core::mem::replace(&mut output.data, Default::default())
1441 } else {
1442 output.data.clone()
1443 };
1444
1445 let mut module = match &self.origin {
1449 Origin::Signed(o) => {
1450 crate::ContractBlob::<T>::from_evm_runtime_code(data, o.clone())?
1451 },
1452 Origin::Root => {
1453 crate::ContractBlob::<T>::from_evm_runtime_code_with_deposit(
1454 data,
1455 crate::Pallet::<T>::account_id(),
1456 Zero::zero(),
1457 )?
1458 },
1459 };
1460 module.store_code(&self.exec_config, &mut frame.frame_meter)?;
1461 code_deposit = module.code_info().deposit();
1462
1463 let contract_info = frame.contract_info();
1464 contract_info.code_hash = *module.code_hash();
1465 <CodeInfo<T>>::increment_refcount(contract_info.code_hash)?;
1466 }
1467
1468 let deposit = frame.contract_info().update_base_deposit(code_deposit);
1469 frame.frame_meter.charge_contract_deposit_and_transfer(
1470 frame.account_id.clone(),
1471 StorageDeposit::Charge(deposit),
1472 )?;
1473 frame
1474 } else {
1475 self.top_frame_mut()
1476 };
1477
1478 let contract = frame.contract_info.as_contract();
1482 frame
1483 .frame_meter
1484 .finalize(contract)
1485 .map_err(|e| ExecError { error: e, origin: ErrorOrigin::Callee })?;
1486
1487 Ok(output)
1488 };
1489
1490 let transaction_outcome =
1497 with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
1498 let output = if let Some(mock_answer) = mock_answer {
1499 Ok(mock_answer)
1500 } else {
1501 do_transaction()
1502 };
1503 match &output {
1504 Ok(result) if !result.did_revert() => {
1505 TransactionOutcome::Commit(Ok((true, output)))
1506 },
1507 _ => TransactionOutcome::Rollback(Ok((false, output))),
1508 }
1509 });
1510
1511 let (success, output) = match transaction_outcome {
1512 Ok((success, output)) => {
1514 if_tracing(|tracer| {
1515 let frame_meter = &top_frame!(self).frame_meter;
1516
1517 let gas_consumed = if is_first_frame {
1520 frame_meter.total_consumed_gas()
1521 } else {
1522 frame_meter.eth_gas_consumed()
1523 };
1524
1525 let gas_consumed: u64 = gas_consumed.try_into().unwrap_or(u64::MAX);
1526 let weight_consumed = frame_meter.weight_consumed();
1527
1528 match &output {
1529 Ok(output) => {
1530 tracer.exit_child_span(&output, gas_consumed, weight_consumed)
1531 },
1532 Err(e) => tracer.exit_child_span_with_error(
1533 e.error.into(),
1534 gas_consumed,
1535 weight_consumed,
1536 ),
1537 }
1538 });
1539
1540 (success, output)
1541 },
1542 Err(error) => {
1545 if_tracing(|tracer| {
1546 let frame_meter = &top_frame!(self).frame_meter;
1547
1548 let gas_consumed = if is_first_frame {
1551 frame_meter.total_consumed_gas()
1552 } else {
1553 frame_meter.eth_gas_consumed()
1554 };
1555
1556 let gas_consumed: u64 = gas_consumed.try_into().unwrap_or(u64::MAX);
1557 let weight_consumed = frame_meter.weight_consumed();
1558 tracer.exit_child_span_with_error(error.into(), gas_consumed, weight_consumed);
1559 });
1560
1561 (false, Err(error.into()))
1562 },
1563 };
1564 self.with_transient_storage_mut(|transient_storage| {
1565 if success {
1566 transient_storage.commit_transaction();
1567 } else {
1568 transient_storage.rollback_transaction();
1569 }
1570 });
1571 if is_first_frame {
1574 let m = self.access_list.metrics();
1575 log::trace!(
1576 target: LOG_TARGET,
1577 "access list metrics: size={size} cold={cold} hot={hot}",
1578 size = m.size, cold = m.cold, hot = m.hot,
1579 );
1580 } else if success {
1581 self.access_list.commit_frame();
1582 } else {
1583 self.access_list.rollback_frame();
1584 }
1585 log::trace!(target: LOG_TARGET, "frame finished with: {output:?}");
1586
1587 self.pop_frame(success);
1588 output.map(|output| {
1589 self.top_frame_mut().last_frame_output = output;
1590 })
1591 }
1592
1593 fn pop_frame(&mut self, persist: bool) {
1598 let frame = self.frames.pop();
1602
1603 if let Some(mut frame) = frame {
1606 let account_id = &frame.account_id;
1607 let prev = top_frame_mut!(self);
1608
1609 if !persist {
1611 prev.frame_meter.absorb_weight_meter_only(frame.frame_meter);
1612 return;
1613 }
1614
1615 frame.contract_info.load(account_id);
1620 let mut contract = frame.contract_info.into_contract();
1621 prev.frame_meter
1622 .absorb_all_meters(frame.frame_meter, account_id, contract.as_mut());
1623
1624 prev.contracts_created.extend(frame.contracts_created);
1626 prev.contracts_to_be_destroyed.extend(frame.contracts_to_be_destroyed);
1627
1628 if let Some(contract) = contract {
1629 AccountInfo::<T>::insert_contract(
1634 &T::AddressMapper::to_address(account_id),
1635 contract,
1636 );
1637 if let Some(f) = self.frames_mut().find(|f| f.account_id == *account_id) {
1638 f.contract_info.invalidate();
1639 }
1640 }
1641 } else {
1642 if !persist {
1643 self.transaction_meter
1644 .absorb_weight_meter_only(mem::take(&mut self.first_frame.frame_meter));
1645 return;
1646 }
1647
1648 let mut contract = self.first_frame.contract_info.as_contract();
1649 self.transaction_meter.absorb_all_meters(
1650 mem::take(&mut self.first_frame.frame_meter),
1651 &self.first_frame.account_id,
1652 contract.as_deref_mut(),
1653 );
1654
1655 if let Some(contract) = contract {
1656 AccountInfo::<T>::insert_contract(
1657 &T::AddressMapper::to_address(&self.first_frame.account_id),
1658 contract.clone(),
1659 );
1660 }
1661 let contracts_created = mem::take(&mut self.first_frame.contracts_created);
1663 let contracts_to_destroy = mem::take(&mut self.first_frame.contracts_to_be_destroyed);
1664 for (contract_account, args) in contracts_to_destroy {
1665 if args.only_if_same_tx && !contracts_created.contains(&contract_account) {
1666 continue;
1667 }
1668 Self::do_terminate(
1669 &mut self.transaction_meter,
1670 self.exec_config,
1671 &contract_account,
1672 &self.origin,
1673 &args,
1674 )
1675 .ok();
1676 }
1677 }
1678 }
1679
1680 fn transfer<S: State>(
1693 origin: &Origin<T>,
1694 from: &T::AccountId,
1695 to: &T::AccountId,
1696 value: U256,
1697 preservation: Preservation,
1698 meter: &mut ResourceMeter<T, S>,
1699 exec_config: &ExecConfig<T>,
1700 ) -> DispatchResult {
1701 let value = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(value)
1702 .map_err(|_| Error::<T>::BalanceConversionFailed)?;
1703 if value.is_zero() {
1704 return Ok(());
1705 }
1706
1707 if <System<T>>::account_exists(to) {
1708 return transfer_with_dust::<T>(from, to, value, preservation);
1709 }
1710
1711 let origin = origin.account_id()?;
1712 let ed = <T as Config>::Currency::minimum_balance();
1713 let is_eth_tx = exec_config.collect_deposit_from_hold.is_some();
1714 with_transaction(|| -> TransactionOutcome<DispatchResult> {
1715 match Ok::<(), DispatchError>(())
1718 .and_then(|_| {
1719 if is_eth_tx {
1720 let credit = T::FeeInfo::withdraw_txfee(ed)
1721 .ok_or(Error::<T>::StorageDepositNotEnoughFunds)?;
1722 T::Currency::resolve(to, credit)
1723 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
1724 Ok(())
1725 } else {
1726 T::Currency::transfer(origin, to, ed, Preservation::Preserve)
1727 .map(|_| ())
1728 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds.into())
1729 }
1730 })
1731 .and_then(|_| transfer_with_dust::<T>(from, to, value, preservation))
1732 .and_then(|_| meter.charge_deposit(&StorageDeposit::Charge(ed)))
1733 {
1734 Ok(_) => TransactionOutcome::Commit(Ok(())),
1735 Err(err) => TransactionOutcome::Rollback(Err(err)),
1736 }
1737 })
1738 }
1739
1740 fn transfer_from_origin<S: State>(
1742 origin: &Origin<T>,
1743 from: &Origin<T>,
1744 to: &T::AccountId,
1745 value: U256,
1746 meter: &mut ResourceMeter<T, S>,
1747 exec_config: &ExecConfig<T>,
1748 ) -> ExecResult {
1749 let from = match from {
1752 Origin::Signed(caller) => caller,
1753 Origin::Root if value.is_zero() => return Ok(Default::default()),
1754 Origin::Root => return Err(DispatchError::RootNotAllowed.into()),
1755 };
1756 Self::transfer(origin, from, to, value, Preservation::Preserve, meter, exec_config)
1757 .map(|_| Default::default())
1758 .map_err(Into::into)
1759 }
1760
1761 fn do_terminate(
1763 transaction_meter: &mut TransactionMeter<T>,
1764 exec_config: &ExecConfig<T>,
1765 contract_account: &T::AccountId,
1766 origin: &Origin<T>,
1767 args: &TerminateArgs<T>,
1768 ) -> Result<(), DispatchError> {
1769 let contract_address = T::AddressMapper::to_address(contract_account);
1770
1771 let origin: Origin<T> = match origin {
1774 Origin::Signed(o) => Origin::Signed(o.clone()),
1775 Origin::Root => Origin::from_account_id(crate::Pallet::<T>::account_id()),
1776 };
1777
1778 let mut delete_contract = |trie_id: &TrieId, code_hash: &H256| {
1779 let refund =
1781 T::Deposit::refund_all(&contract_account, exec_config.funds(origin.account_id()?))?;
1782
1783 System::<T>::dec_consumers(&contract_account);
1785
1786 T::Deposit::destroy_contract(contract_account)?;
1788
1789 let balance = <Contracts<T>>::convert_native_to_evm(<AccountInfo<T>>::total_balance(
1793 contract_address.into(),
1794 ));
1795 Self::transfer(
1796 &origin,
1797 contract_account,
1798 &args.beneficiary,
1799 balance,
1800 Preservation::Expendable,
1801 transaction_meter,
1802 exec_config,
1803 )?;
1804
1805 let _code_removed = <CodeInfo<T>>::decrement_refcount(*code_hash)?;
1807
1808 ContractInfo::<T>::queue_for_deletion(trie_id.clone(), contract_account.clone());
1810 AccountInfoOf::<T>::remove(contract_address);
1811 ImmutableDataOf::<T>::remove(contract_address);
1812
1813 transaction_meter.terminate(contract_account.clone(), refund);
1816
1817 Ok(())
1818 };
1819
1820 with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
1824 match delete_contract(&args.trie_id, &args.code_hash) {
1825 Ok(()) => {
1826 log::trace!(target: LOG_TARGET, "Terminated {contract_address:?}");
1827 TransactionOutcome::Commit(Ok(()))
1828 },
1829 Err(e) => {
1830 log::debug!(target: LOG_TARGET, "Contract at {contract_address:?} failed to terminate: {e:?}");
1831 TransactionOutcome::Rollback(Err(e))
1832 },
1833 }
1834 })
1835 }
1836
1837 fn top_frame(&self) -> &Frame<T> {
1839 top_frame!(self)
1840 }
1841
1842 fn top_frame_mut(&mut self) -> &mut Frame<T> {
1844 top_frame_mut!(self)
1845 }
1846
1847 fn frames(&self) -> impl Iterator<Item = &Frame<T>> {
1851 core::iter::once(&self.first_frame).chain(&self.frames).rev()
1852 }
1853
1854 fn frames_mut(&mut self) -> impl Iterator<Item = &mut Frame<T>> {
1856 core::iter::once(&mut self.first_frame).chain(&mut self.frames).rev()
1857 }
1858
1859 fn allows_reentry(&self, id: &T::AccountId) -> bool {
1861 !self.frames().any(|f| &f.account_id == id && !f.allows_reentry)
1862 }
1863
1864 fn account_balance(&self, who: &T::AccountId) -> U256 {
1866 let balance = AccountInfo::<T>::balance_of(AccountIdOrAddress::AccountId(who.clone()));
1867 crate::Pallet::<T>::convert_native_to_evm(balance)
1868 }
1869
1870 #[cfg(feature = "runtime-benchmarks")]
1873 pub(crate) fn override_export(&mut self, export: ExportedFunction) {
1874 self.top_frame_mut().entry_point = export;
1875 }
1876
1877 #[cfg(feature = "runtime-benchmarks")]
1878 pub(crate) fn set_block_number(&mut self, block_number: BlockNumberFor<T>) {
1879 self.block_number = block_number;
1880 }
1881
1882 fn block_hash(&self, block_number: U256) -> Option<H256> {
1883 let Ok(block_number) = BlockNumberFor::<T>::try_from(block_number) else {
1884 return None;
1885 };
1886 if block_number >= self.block_number {
1887 return None;
1888 }
1889 if block_number < self.block_number.saturating_sub(256u32.into()) {
1890 return None;
1891 }
1892
1893 match crate::Pallet::<T>::eth_block_hash_from_number(block_number.into()) {
1897 Some(hash) => Some(hash),
1898 None => {
1899 use codec::Decode;
1900 let block_hash = System::<T>::block_hash(&block_number);
1901 Decode::decode(&mut TrailingZeroInput::new(block_hash.as_ref())).ok()
1902 },
1903 }
1904 }
1905
1906 fn has_contract_info(&self) -> bool {
1909 let address = self.address();
1910 let precompile = <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes());
1911 if let Some(precompile) = precompile {
1912 return precompile.has_contract_info();
1913 }
1914 true
1915 }
1916
1917 fn with_transient_storage_mut<R, F: FnOnce(&mut TransientStorage<T>) -> R>(
1918 &mut self,
1919 f: F,
1920 ) -> R {
1921 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1922 f(&mut transient.borrow_mut())
1923 } else {
1924 f(&mut self.transient_storage)
1925 }
1926 }
1927 fn with_transient_storage<R, F: FnOnce(&TransientStorage<T>) -> R>(&self, f: F) -> R {
1928 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1929 f(&transient.borrow())
1930 } else {
1931 f(&self.transient_storage)
1932 }
1933 }
1934}
1935
1936impl<'a, T, E> Ext for Stack<'a, T, E>
1937where
1938 T: Config,
1939 E: Executable<T>,
1940{
1941 fn delegate_call(
1942 &mut self,
1943 call_resources: &CallResources<T>,
1944 address: H160,
1945 input_data: Vec<u8>,
1946 ) -> Result<(), ExecError> {
1947 *self.last_frame_output_mut() = Default::default();
1950
1951 let top_frame = self.top_frame_mut();
1952 let mut contract_info = top_frame.contract_info().clone();
1956 top_frame.frame_meter.apply_pending_storage_changes(&mut contract_info);
1957 let account_id = top_frame.account_id.clone();
1958 let value = top_frame.value_transferred;
1959 if let Some(executable) = self.push_frame(
1960 FrameArgs::Call {
1961 dest: account_id,
1962 cached_info: Some(contract_info),
1963 delegated_call: Some(DelegateInfo {
1964 caller: self.caller().clone(),
1965 callee: address,
1966 }),
1967 },
1968 value,
1969 call_resources,
1970 self.is_read_only(),
1971 &input_data,
1972 )? {
1973 self.run(executable, input_data)
1974 } else {
1975 Ok(())
1977 }
1978 }
1979
1980 fn terminate_if_same_tx(&mut self, beneficiary: &H160) -> Result<CodeRemoved, DispatchError> {
1981 if_tracing(|tracer| {
1982 let addr = T::AddressMapper::to_address(self.account_id());
1983 tracer.terminate(
1984 addr,
1985 *beneficiary,
1986 self.top_frame()
1987 .frame_meter
1988 .eth_gas_left()
1989 .unwrap_or_default()
1990 .try_into()
1991 .unwrap_or_default(),
1992 crate::Pallet::<T>::evm_balance(&addr),
1993 );
1994 });
1995 let frame = top_frame_mut!(self);
1996 let info = frame.contract_info();
1997 let trie_id = info.trie_id.clone();
1998 let code_hash = info.code_hash;
1999 let contract_address = T::AddressMapper::to_address(&frame.account_id);
2000 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
2001
2002 Self::transfer(
2004 &self.origin,
2005 &frame.account_id,
2006 &beneficiary,
2007 <Contracts<T>>::evm_balance(&contract_address),
2008 Preservation::Preserve,
2009 &mut frame.frame_meter,
2010 self.exec_config,
2011 )?;
2012
2013 let account_id = frame.account_id.clone();
2015 self.top_frame_mut().contracts_to_be_destroyed.insert(
2016 account_id,
2017 TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: true },
2018 );
2019 Ok(CodeRemoved::Yes)
2020 }
2021
2022 fn own_code_hash(&mut self) -> &H256 {
2023 &self.top_frame_mut().contract_info().code_hash
2024 }
2025
2026 fn immutable_data_len(&mut self) -> u32 {
2027 self.top_frame_mut().contract_info().immutable_data_len()
2028 }
2029
2030 fn get_immutable_data(&mut self) -> Result<ImmutableData, DispatchError> {
2031 if self.top_frame().entry_point == ExportedFunction::Constructor {
2032 return Err(Error::<T>::InvalidImmutableAccess.into());
2033 }
2034
2035 let address = self
2037 .top_frame()
2038 .delegate
2039 .as_ref()
2040 .map(|d| d.callee)
2041 .unwrap_or(T::AddressMapper::to_address(self.account_id()));
2042 Ok(<ImmutableDataOf<T>>::get(address).ok_or_else(|| Error::<T>::InvalidImmutableAccess)?)
2043 }
2044
2045 fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError> {
2046 let frame = self.top_frame_mut();
2047 if frame.entry_point == ExportedFunction::Call || data.is_empty() {
2048 return Err(Error::<T>::InvalidImmutableAccess.into());
2049 }
2050 frame.contract_info().set_immutable_data_len(data.len() as u32);
2051 <ImmutableDataOf<T>>::insert(T::AddressMapper::to_address(&frame.account_id), &data);
2052 Ok(())
2053 }
2054}
2055
2056impl<'a, T, E> PrecompileWithInfoExt for Stack<'a, T, E>
2057where
2058 T: Config,
2059 E: Executable<T>,
2060{
2061 fn instantiate(
2062 &mut self,
2063 call_resources: &CallResources<T>,
2064 mut code: Code,
2065 value: U256,
2066 input_data: Vec<u8>,
2067 salt: Option<&[u8; 32]>,
2068 ) -> Result<H160, ExecError> {
2069 *self.last_frame_output_mut() = Default::default();
2072
2073 let sender = self.top_frame().account_id.clone();
2074 let executable = {
2075 let executable = match &mut code {
2076 Code::Upload(initcode) => {
2077 if !T::AllowEVMBytecode::get() {
2078 return Err(<Error<T>>::CodeRejected.into());
2079 }
2080 ensure!(input_data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
2081 let initcode = crate::tracing::if_tracing(|_| initcode.clone())
2082 .unwrap_or_else(|| mem::take(initcode));
2083 E::from_evm_init_code(initcode, sender.clone())?
2084 },
2085 Code::Existing(hash) => {
2086 let executable = E::from_storage(*hash, self.frame_meter_mut())?;
2087 ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
2088 executable
2089 },
2090 };
2091 self.push_frame(
2092 FrameArgs::Instantiate {
2093 sender,
2094 executable,
2095 salt,
2096 input_data: input_data.as_ref(),
2097 },
2098 value,
2099 call_resources,
2100 self.is_read_only(),
2101 &input_data,
2102 )?
2103 };
2104 let executable = executable.expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE);
2105
2106 let account_id = self.top_frame().account_id.clone();
2108 self.top_frame_mut().contracts_created.insert(account_id);
2109
2110 let address = T::AddressMapper::to_address(&self.top_frame().account_id);
2111 if_tracing(|t| t.instantiate_code(&code, salt));
2112 self.run(executable, input_data).map(|_| address)
2113 }
2114}
2115
2116impl<'a, T, E> PrecompileExt for Stack<'a, T, E>
2117where
2118 T: Config,
2119 E: Executable<T>,
2120{
2121 type T = T;
2122
2123 fn call(
2124 &mut self,
2125 call_resources: &CallResources<T>,
2126 dest_addr: &H160,
2127 value: U256,
2128 input_data: Vec<u8>,
2129 allows_reentry: ReentrancyProtection,
2130 read_only: bool,
2131 ) -> Result<(), ExecError> {
2132 if allows_reentry == ReentrancyProtection::Strict {
2137 self.top_frame_mut().allows_reentry = false;
2138 }
2139
2140 *self.last_frame_output_mut() = Default::default();
2143
2144 let try_call = || {
2145 let is_read_only = read_only || self.is_read_only();
2147
2148 let dest = if <AllPrecompiles<T>>::get::<Self>(dest_addr.as_fixed_bytes()).is_some() {
2150 T::AddressMapper::to_fallback_account_id(dest_addr)
2151 } else {
2152 T::AddressMapper::to_account_id(dest_addr)
2153 };
2154
2155 if !self.allows_reentry(&dest) {
2156 return Err(<Error<T>>::ReentranceDenied.into());
2157 }
2158
2159 if allows_reentry == ReentrancyProtection::AllowNext {
2160 self.top_frame_mut().allows_reentry = false;
2161 }
2162
2163 let cached_info = self
2171 .frames()
2172 .find(|f| f.entry_point == ExportedFunction::Call && f.account_id == dest)
2173 .and_then(|f| match &f.contract_info {
2174 CachedContract::Cached(contract) => {
2175 let mut contract_with_pending = contract.clone();
2176 f.frame_meter.apply_pending_storage_changes(&mut contract_with_pending);
2177 Some(contract_with_pending)
2178 },
2179 _ => None,
2180 });
2181
2182 if let Some(executable) = self.push_frame(
2183 FrameArgs::Call { dest: dest.clone(), cached_info, delegated_call: None },
2184 value,
2185 call_resources,
2186 is_read_only,
2187 &input_data,
2188 )? {
2189 self.run(executable, input_data)
2190 } else {
2191 if_tracing(|t| {
2192 t.enter_child_span(
2193 T::AddressMapper::to_address(self.account_id()),
2194 T::AddressMapper::to_address(&dest),
2195 None,
2196 is_read_only,
2197 value,
2198 &input_data,
2199 Default::default(),
2200 );
2201 });
2202
2203 let snapshot = if_tracing(|_| top_frame!(self).frame_meter.snapshot());
2204
2205 let result = if let Some(mock_answer) =
2206 self.exec_config.mock_handler.as_ref().and_then(|handler| {
2207 handler.mock_call(T::AddressMapper::to_address(&dest), &input_data, value)
2208 }) {
2209 *self.last_frame_output_mut() = mock_answer.clone();
2210 Ok(mock_answer)
2211 } else if is_read_only && value.is_zero() {
2212 Ok(Default::default())
2213 } else if is_read_only {
2214 Err(Error::<T>::StateChangeDenied.into())
2215 } else {
2216 let account_id = self.account_id().clone();
2217 let frame = top_frame_mut!(self);
2218 Self::transfer_from_origin(
2219 &self.origin,
2220 &Origin::from_account_id(account_id),
2221 &dest,
2222 value,
2223 &mut frame.frame_meter,
2224 self.exec_config,
2225 )
2226 };
2227
2228 if_tracing(|t| {
2229 let snapshot = snapshot.as_ref().expect(
2230 "snapshot is taken inside if_tracing above; tracing state cannot \
2231 change mid-call, so it is Some whenever this closure runs; qed",
2232 );
2233 let (gas_used, weight_delta) =
2234 top_frame!(self).frame_meter.delta_since(snapshot);
2235 match result {
2236 Ok(ref output) => t.exit_child_span(&output, gas_used, weight_delta),
2237 Err(e) => {
2238 t.exit_child_span_with_error(e.error.into(), gas_used, weight_delta)
2239 },
2240 }
2241 });
2242
2243 result.map(|_| ())
2244 }
2245 };
2246
2247 let result = try_call();
2249
2250 self.top_frame_mut().allows_reentry = true;
2252
2253 result
2254 }
2255
2256 fn get_transient_storage(&self, key: &Key) -> Option<Vec<u8>> {
2257 self.with_transient_storage(|transient_storage| {
2258 transient_storage.read(self.account_id(), key)
2259 })
2260 }
2261
2262 fn get_transient_storage_size(&self, key: &Key) -> Option<u32> {
2263 self.with_transient_storage(|transient_storage| {
2264 transient_storage.read(self.account_id(), key).map(|value| value.len() as _)
2265 })
2266 }
2267
2268 fn set_transient_storage(
2269 &mut self,
2270 key: &Key,
2271 value: Option<Vec<u8>>,
2272 take_old: bool,
2273 ) -> Result<WriteOutcome, DispatchError> {
2274 let account_id = self.account_id().clone();
2275 self.with_transient_storage_mut(|transient_storage| {
2276 transient_storage.write(&account_id, key, value, take_old)
2277 })
2278 }
2279
2280 fn account_id(&self) -> &T::AccountId {
2281 &self.top_frame().account_id
2282 }
2283
2284 fn caller(&self) -> Origin<T> {
2285 if let Some(Ok(mock_caller)) = self
2286 .exec_config
2287 .mock_handler
2288 .as_ref()
2289 .and_then(|mock_handler| mock_handler.mock_caller(self.frames.len()))
2290 .map(|mock_caller| Origin::<T>::from_runtime_origin(mock_caller))
2291 {
2292 return mock_caller;
2293 }
2294
2295 if let Some(DelegateInfo { caller, .. }) = &self.top_frame().delegate {
2296 caller.clone()
2297 } else {
2298 self.frames()
2299 .nth(1)
2300 .map(|f| Origin::from_account_id(f.account_id.clone()))
2301 .unwrap_or(self.origin.clone())
2302 }
2303 }
2304
2305 fn caller_of_caller(&self) -> Origin<T> {
2306 let caller_of_caller_frame = match self.frames().nth(2) {
2308 None => return self.origin.clone(),
2309 Some(frame) => frame,
2310 };
2311 if let Some(DelegateInfo { caller, .. }) = &caller_of_caller_frame.delegate {
2312 caller.clone()
2313 } else {
2314 Origin::from_account_id(caller_of_caller_frame.account_id.clone())
2315 }
2316 }
2317
2318 fn origin(&self) -> &Origin<T> {
2319 if let Some(mock_origin) = self
2320 .exec_config
2321 .mock_handler
2322 .as_ref()
2323 .and_then(|mock_handler| mock_handler.mock_origin())
2324 {
2325 return mock_origin;
2326 }
2327
2328 &self.origin
2329 }
2330
2331 fn to_account_id(&self, address: &H160) -> T::AccountId {
2332 T::AddressMapper::to_account_id(address)
2333 }
2334
2335 fn code_hash(&self, address: &H160) -> H256 {
2336 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2337 self.exec_config
2338 .mock_handler
2339 .as_ref()
2340 .and_then(|handler| handler.mocked_code(*address))
2341 }) {
2342 return sp_io::hashing::keccak_256(code).into();
2343 }
2344
2345 <AccountInfo<T>>::load_contract(&address)
2346 .map(|contract| contract.code_hash)
2347 .unwrap_or_else(|| {
2348 if System::<T>::account_exists(&T::AddressMapper::to_account_id(address)) {
2349 return EMPTY_CODE_HASH;
2350 }
2351 H256::zero()
2352 })
2353 }
2354
2355 fn code_size(&self, address: &H160) -> u64 {
2356 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2357 self.exec_config
2358 .mock_handler
2359 .as_ref()
2360 .and_then(|handler| handler.mocked_code(*address))
2361 }) {
2362 return code.len() as u64;
2363 }
2364
2365 <AccountInfo<T>>::load_contract(&address)
2366 .and_then(|contract| CodeInfoOf::<T>::get(contract.code_hash))
2367 .map(|info| info.code_len())
2368 .unwrap_or_default()
2369 }
2370
2371 fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool {
2372 let caller = if use_caller_of_caller { self.caller_of_caller() } else { self.caller() };
2373 self.origin == caller
2374 }
2375
2376 fn caller_is_root(&self, use_caller_of_caller: bool) -> bool {
2377 self.caller_is_origin(use_caller_of_caller) && self.origin == Origin::Root
2379 }
2380
2381 fn balance(&self) -> U256 {
2382 self.account_balance(&self.top_frame().account_id)
2383 }
2384
2385 fn balance_of(&self, address: &H160) -> U256 {
2386 let balance =
2387 self.account_balance(&<Self::T as Config>::AddressMapper::to_account_id(address));
2388 if_tracing(|tracer| {
2389 tracer.balance_read(address, balance);
2390 });
2391 balance
2392 }
2393
2394 fn value_transferred(&self) -> U256 {
2395 self.top_frame().value_transferred.into()
2396 }
2397
2398 fn now(&self) -> U256 {
2399 (self.timestamp / 1000u32.into()).into()
2400 }
2401
2402 fn minimum_balance(&self) -> U256 {
2403 let min = T::Currency::minimum_balance();
2404 crate::Pallet::<T>::convert_native_to_evm(min)
2405 }
2406
2407 fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
2408 let contract = T::AddressMapper::to_address(self.account_id());
2409 if_tracing(|tracer| {
2410 let log_index = frame_system::Pallet::<Self::T>::event_count();
2411 tracer.log_event(contract, &topics, &data, log_index);
2412 });
2413
2414 block_storage::capture_ethereum_log(&contract, &data, &topics);
2416
2417 Contracts::<Self::T>::deposit_event(Event::ContractEmitted { contract, data, topics });
2418 }
2419
2420 fn block_number(&self) -> U256 {
2421 self.block_number.into()
2422 }
2423
2424 fn block_hash(&self, block_number: U256) -> Option<H256> {
2425 self.block_hash(block_number)
2426 }
2427
2428 fn block_author(&self) -> H160 {
2429 Contracts::<Self::T>::block_author()
2430 }
2431
2432 fn gas_limit(&self) -> u64 {
2433 <Contracts<T>>::evm_block_gas_limit().saturated_into()
2434 }
2435
2436 fn chain_id(&self) -> u64 {
2437 <T as Config>::ChainId::get()
2438 }
2439
2440 fn gas_meter(&self) -> &FrameMeter<Self::T> {
2441 &self.top_frame().frame_meter
2442 }
2443
2444 #[inline]
2445 fn gas_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2446 &mut self.top_frame_mut().frame_meter
2447 }
2448
2449 fn frame_meter(&self) -> &FrameMeter<Self::T> {
2450 &self.top_frame().frame_meter
2451 }
2452
2453 #[inline]
2454 fn frame_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2455 &mut self.top_frame_mut().frame_meter
2456 }
2457
2458 fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> {
2459 secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ())
2460 }
2461
2462 fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool {
2463 sp_io::crypto::sr25519_verify(
2464 &SR25519Signature::from(*signature),
2465 message,
2466 &SR25519Public::from(*pub_key),
2467 )
2468 }
2469
2470 fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], DispatchError> {
2471 Ok(ECDSAPublic::from(*pk)
2472 .to_eth_address()
2473 .or_else(|()| Err(Error::<T>::EcdsaRecoveryFailed))?)
2474 }
2475
2476 #[cfg(any(test, feature = "runtime-benchmarks"))]
2477 fn contract_info(&mut self) -> &mut ContractInfo<Self::T> {
2478 self.top_frame_mut().contract_info()
2479 }
2480
2481 #[cfg(any(feature = "runtime-benchmarks", test))]
2482 fn transient_storage(&mut self) -> &mut TransientStorage<Self::T> {
2483 &mut self.transient_storage
2484 }
2485
2486 fn is_read_only(&self) -> bool {
2487 self.top_frame().read_only
2488 }
2489
2490 fn is_delegate_call(&self) -> bool {
2491 self.top_frame().delegate.is_some()
2492 }
2493
2494 fn last_frame_output(&self) -> &ExecReturnValue {
2495 &self.top_frame().last_frame_output
2496 }
2497
2498 fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue {
2499 &mut self.top_frame_mut().last_frame_output
2500 }
2501
2502 fn copy_code_slice(&mut self, buf: &mut [u8], address: &H160, code_offset: usize) {
2503 let len = buf.len();
2504 if len == 0 {
2505 return;
2506 }
2507
2508 let code_hash = self.code_hash(address);
2509 let code = crate::PristineCode::<T>::get(&code_hash).unwrap_or_default();
2510
2511 let len = len.min(code.len().saturating_sub(code_offset));
2512 if len > 0 {
2513 buf[..len].copy_from_slice(&code[code_offset..code_offset + len]);
2514 }
2515
2516 buf[len..].fill(0);
2517 }
2518
2519 fn terminate_caller(&mut self, beneficiary: &H160) -> Result<(), DispatchError> {
2520 ensure!(self.top_frame().delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2521 let parent = self.frames_mut().nth(1).ok_or_else(|| Error::<T>::ContractNotFound)?;
2522 ensure!(parent.entry_point == ExportedFunction::Call, Error::<T>::TerminatedInConstructor);
2523 ensure!(parent.delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2524
2525 let info = parent.contract_info();
2526 let trie_id = info.trie_id.clone();
2527 let code_hash = info.code_hash;
2528 let contract_address = T::AddressMapper::to_address(&parent.account_id);
2529 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
2530
2531 let parent_account_id = parent.account_id.clone();
2532
2533 Self::transfer(
2535 &self.origin,
2536 &parent_account_id,
2537 &beneficiary,
2538 <Contracts<T>>::evm_balance(&contract_address),
2539 Preservation::Preserve,
2540 &mut top_frame_mut!(self).frame_meter,
2541 &self.exec_config,
2542 )?;
2543
2544 let args = TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: false };
2546 self.top_frame_mut().contracts_to_be_destroyed.insert(parent_account_id, args);
2547
2548 Ok(())
2549 }
2550
2551 fn effective_gas_price(&self) -> U256 {
2552 self.exec_config
2553 .effective_gas_price
2554 .unwrap_or_else(|| <Contracts<T>>::evm_base_fee())
2555 }
2556
2557 fn gas_left(&self) -> u64 {
2558 let frame = self.top_frame();
2559
2560 frame.frame_meter.eth_gas_left().unwrap_or_default().saturated_into::<u64>()
2561 }
2562
2563 fn get_storage(&mut self, key: &Key) -> Option<Vec<u8>> {
2564 assert!(self.has_contract_info());
2565 self.top_frame_mut().contract_info().read(key)
2566 }
2567
2568 fn get_storage_size(&mut self, key: &Key) -> Option<u32> {
2569 assert!(self.has_contract_info());
2570 self.top_frame_mut().contract_info().size(key.into())
2571 }
2572
2573 fn set_storage(
2574 &mut self,
2575 key: &Key,
2576 value: Option<Vec<u8>>,
2577 take_old: bool,
2578 ) -> Result<WriteOutcome, DispatchError> {
2579 assert!(self.has_contract_info());
2580 let frame = self.top_frame_mut();
2581 frame.contract_info.get(&frame.account_id).write(
2582 key.into(),
2583 value,
2584 Some(&mut frame.frame_meter),
2585 take_old,
2586 )
2587 }
2588
2589 fn touch_storage_access(&mut self, transient: bool, key: &Key) -> StorageAccessKind {
2590 if transient {
2591 return StorageAccessKind::Transient;
2592 }
2593 let address = self.address();
2594 StorageAccessKind::Persistent(
2595 self.access_list.touch(AccessEntry { address, slot: key.into() }),
2596 )
2597 }
2598
2599 fn peek_storage_access(&self, transient: bool, key: &Key) -> StorageAccessKind {
2600 if transient {
2601 return StorageAccessKind::Transient;
2602 }
2603 let address = self.address();
2604 StorageAccessKind::Persistent(
2605 self.access_list.peek(&AccessEntry { address, slot: key.into() }),
2606 )
2607 }
2608
2609 fn charge_storage(&mut self, diff: &Diff) -> DispatchResult {
2610 assert!(self.has_contract_info());
2611 self.top_frame_mut().frame_meter.record_contract_storage_changes(diff)
2612 }
2613}
2614
2615pub fn is_precompile<T: Config, E: Executable<T>>(address: &H160) -> bool {
2617 <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes()).is_some()
2618}
2619
2620#[cfg(feature = "runtime-benchmarks")]
2621pub fn bench_do_terminate<T: Config>(
2622 transaction_meter: &mut TransactionMeter<T>,
2623 exec_config: &ExecConfig<T>,
2624 contract_account: &T::AccountId,
2625 origin: &Origin<T>,
2626 beneficiary: T::AccountId,
2627 trie_id: TrieId,
2628 code_hash: H256,
2629 only_if_same_tx: bool,
2630) -> Result<(), DispatchError> {
2631 Stack::<T, crate::ContractBlob<T>>::do_terminate(
2632 transaction_meter,
2633 exec_config,
2634 contract_account,
2635 origin,
2636 &TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx },
2637 )
2638}
2639
2640mod sealing {
2641 use super::*;
2642
2643 pub trait Sealed {}
2644 impl<'a, T: Config, E> Sealed for Stack<'a, T, E> {}
2645
2646 #[cfg(test)]
2647 impl<T: Config> sealing::Sealed for mock_ext::MockExt<T> {}
2648}