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 fn bank_pending_changes_and_invalidate<T: Config>(f: &mut Frame<T>) {
1605 let contract = f.account_id.clone();
1606 f.contract_info.load(&f.account_id);
1607 if let Some(info) = f.contract_info.as_contract() {
1608 f.frame_meter.bank_pending_storage_changes(contract, info);
1609 }
1610 f.contract_info.invalidate();
1617 }
1618
1619 let frame = self.frames.pop();
1623
1624 if let Some(mut frame) = frame {
1627 let account_id = &frame.account_id;
1628 let prev = top_frame_mut!(self);
1629
1630 if !persist {
1632 prev.frame_meter.absorb_weight_meter_only(frame.frame_meter);
1633 return;
1634 }
1635
1636 frame.contract_info.load(account_id);
1641 let mut contract = frame.contract_info.into_contract();
1642 prev.frame_meter
1643 .absorb_all_meters(frame.frame_meter, account_id, contract.as_mut());
1644
1645 prev.contracts_created.extend(frame.contracts_created);
1647 prev.contracts_to_be_destroyed.extend(frame.contracts_to_be_destroyed);
1648
1649 if let Some(contract) = contract {
1650 AccountInfo::<T>::insert_contract(
1655 &T::AddressMapper::to_address(account_id),
1656 contract,
1657 );
1658 if let Some(f) = self.frames_mut().find(|f| f.account_id == *account_id) {
1659 bank_pending_changes_and_invalidate(f);
1661 }
1662 }
1663 } else {
1664 if !persist {
1665 self.transaction_meter
1666 .absorb_weight_meter_only(mem::take(&mut self.first_frame.frame_meter));
1667 return;
1668 }
1669
1670 let mut contract = self.first_frame.contract_info.as_contract();
1671 self.transaction_meter.absorb_all_meters(
1672 mem::take(&mut self.first_frame.frame_meter),
1673 &self.first_frame.account_id,
1674 contract.as_deref_mut(),
1675 );
1676
1677 if let Some(contract) = contract {
1678 AccountInfo::<T>::insert_contract(
1679 &T::AddressMapper::to_address(&self.first_frame.account_id),
1680 contract.clone(),
1681 );
1682 }
1683 let contracts_created = mem::take(&mut self.first_frame.contracts_created);
1685 let contracts_to_destroy = mem::take(&mut self.first_frame.contracts_to_be_destroyed);
1686 for (contract_account, args) in contracts_to_destroy {
1687 if args.only_if_same_tx && !contracts_created.contains(&contract_account) {
1688 continue;
1689 }
1690 Self::do_terminate(
1691 &mut self.transaction_meter,
1692 self.exec_config,
1693 &contract_account,
1694 &self.origin,
1695 &args,
1696 )
1697 .ok();
1698 }
1699 }
1700 }
1701
1702 fn transfer<S: State>(
1715 origin: &Origin<T>,
1716 from: &T::AccountId,
1717 to: &T::AccountId,
1718 value: U256,
1719 preservation: Preservation,
1720 meter: &mut ResourceMeter<T, S>,
1721 exec_config: &ExecConfig<T>,
1722 ) -> DispatchResult {
1723 let value = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(value)
1724 .map_err(|_| Error::<T>::BalanceConversionFailed)?;
1725 if value.is_zero() {
1726 return Ok(());
1727 }
1728
1729 if <System<T>>::account_exists(to) {
1730 return transfer_with_dust::<T>(from, to, value, preservation);
1731 }
1732
1733 let origin = origin.account_id()?;
1734 let ed = <T as Config>::Currency::minimum_balance();
1735 let is_eth_tx = exec_config.collect_deposit_from_hold.is_some();
1736 with_transaction(|| -> TransactionOutcome<DispatchResult> {
1737 match Ok::<(), DispatchError>(())
1740 .and_then(|_| {
1741 if is_eth_tx {
1742 let credit = T::FeeInfo::withdraw_txfee(ed)
1743 .ok_or(Error::<T>::StorageDepositNotEnoughFunds)?;
1744 T::Currency::resolve(to, credit)
1745 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
1746 Ok(())
1747 } else {
1748 T::Currency::transfer(origin, to, ed, Preservation::Preserve)
1749 .map(|_| ())
1750 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds.into())
1751 }
1752 })
1753 .and_then(|_| transfer_with_dust::<T>(from, to, value, preservation))
1754 .and_then(|_| meter.charge_deposit(&StorageDeposit::Charge(ed)))
1755 {
1756 Ok(_) => TransactionOutcome::Commit(Ok(())),
1757 Err(err) => TransactionOutcome::Rollback(Err(err)),
1758 }
1759 })
1760 }
1761
1762 fn transfer_from_origin<S: State>(
1764 origin: &Origin<T>,
1765 from: &Origin<T>,
1766 to: &T::AccountId,
1767 value: U256,
1768 meter: &mut ResourceMeter<T, S>,
1769 exec_config: &ExecConfig<T>,
1770 ) -> ExecResult {
1771 let from = match from {
1774 Origin::Signed(caller) => caller,
1775 Origin::Root if value.is_zero() => return Ok(Default::default()),
1776 Origin::Root => return Err(DispatchError::RootNotAllowed.into()),
1777 };
1778 Self::transfer(origin, from, to, value, Preservation::Preserve, meter, exec_config)
1779 .map(|_| Default::default())
1780 .map_err(Into::into)
1781 }
1782
1783 fn do_terminate(
1785 transaction_meter: &mut TransactionMeter<T>,
1786 exec_config: &ExecConfig<T>,
1787 contract_account: &T::AccountId,
1788 origin: &Origin<T>,
1789 args: &TerminateArgs<T>,
1790 ) -> Result<(), DispatchError> {
1791 let contract_address = T::AddressMapper::to_address(contract_account);
1792
1793 let origin: Origin<T> = match origin {
1796 Origin::Signed(o) => Origin::Signed(o.clone()),
1797 Origin::Root => Origin::from_account_id(crate::Pallet::<T>::account_id()),
1798 };
1799
1800 let mut delete_contract = |trie_id: &TrieId, code_hash: &H256| {
1801 let refund =
1803 T::Deposit::refund_all(&contract_account, exec_config.funds(origin.account_id()?))?;
1804
1805 System::<T>::dec_consumers(&contract_account);
1807
1808 T::Deposit::destroy_contract(contract_account)?;
1810
1811 let balance = <Contracts<T>>::convert_native_to_evm(<AccountInfo<T>>::total_balance(
1815 contract_address.into(),
1816 ));
1817 Self::transfer(
1818 &origin,
1819 contract_account,
1820 &args.beneficiary,
1821 balance,
1822 Preservation::Expendable,
1823 transaction_meter,
1824 exec_config,
1825 )?;
1826
1827 let _code_removed = <CodeInfo<T>>::decrement_refcount(*code_hash)?;
1829
1830 ContractInfo::<T>::queue_for_deletion(trie_id.clone(), contract_account.clone());
1832 AccountInfoOf::<T>::remove(contract_address);
1833 ImmutableDataOf::<T>::remove(contract_address);
1834
1835 transaction_meter.terminate(contract_account.clone(), refund);
1838
1839 Ok(())
1840 };
1841
1842 with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
1846 match delete_contract(&args.trie_id, &args.code_hash) {
1847 Ok(()) => {
1848 log::trace!(target: LOG_TARGET, "Terminated {contract_address:?}");
1849 TransactionOutcome::Commit(Ok(()))
1850 },
1851 Err(e) => {
1852 log::debug!(target: LOG_TARGET, "Contract at {contract_address:?} failed to terminate: {e:?}");
1853 TransactionOutcome::Rollback(Err(e))
1854 },
1855 }
1856 })
1857 }
1858
1859 fn top_frame(&self) -> &Frame<T> {
1861 top_frame!(self)
1862 }
1863
1864 fn top_frame_mut(&mut self) -> &mut Frame<T> {
1866 top_frame_mut!(self)
1867 }
1868
1869 fn frames(&self) -> impl Iterator<Item = &Frame<T>> {
1873 core::iter::once(&self.first_frame).chain(&self.frames).rev()
1874 }
1875
1876 fn frames_mut(&mut self) -> impl Iterator<Item = &mut Frame<T>> {
1878 core::iter::once(&mut self.first_frame).chain(&mut self.frames).rev()
1879 }
1880
1881 fn allows_reentry(&self, id: &T::AccountId) -> bool {
1883 !self.frames().any(|f| &f.account_id == id && !f.allows_reentry)
1884 }
1885
1886 fn account_balance(&self, who: &T::AccountId) -> U256 {
1888 let balance = AccountInfo::<T>::balance_of(AccountIdOrAddress::AccountId(who.clone()));
1889 crate::Pallet::<T>::convert_native_to_evm(balance)
1890 }
1891
1892 #[cfg(feature = "runtime-benchmarks")]
1895 pub(crate) fn override_export(&mut self, export: ExportedFunction) {
1896 self.top_frame_mut().entry_point = export;
1897 }
1898
1899 #[cfg(feature = "runtime-benchmarks")]
1900 pub(crate) fn set_block_number(&mut self, block_number: BlockNumberFor<T>) {
1901 self.block_number = block_number;
1902 }
1903
1904 fn block_hash(&self, block_number: U256) -> Option<H256> {
1905 let Ok(block_number) = BlockNumberFor::<T>::try_from(block_number) else {
1906 return None;
1907 };
1908 if block_number >= self.block_number {
1909 return None;
1910 }
1911 if block_number < self.block_number.saturating_sub(256u32.into()) {
1912 return None;
1913 }
1914
1915 match crate::Pallet::<T>::eth_block_hash_from_number(block_number.into()) {
1919 Some(hash) => Some(hash),
1920 None => {
1921 use codec::Decode;
1922 let block_hash = System::<T>::block_hash(&block_number);
1923 Decode::decode(&mut TrailingZeroInput::new(block_hash.as_ref())).ok()
1924 },
1925 }
1926 }
1927
1928 fn has_contract_info(&self) -> bool {
1931 let address = self.address();
1932 let precompile = <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes());
1933 if let Some(precompile) = precompile {
1934 return precompile.has_contract_info();
1935 }
1936 true
1937 }
1938
1939 fn with_transient_storage_mut<R, F: FnOnce(&mut TransientStorage<T>) -> R>(
1940 &mut self,
1941 f: F,
1942 ) -> R {
1943 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1944 f(&mut transient.borrow_mut())
1945 } else {
1946 f(&mut self.transient_storage)
1947 }
1948 }
1949 fn with_transient_storage<R, F: FnOnce(&TransientStorage<T>) -> R>(&self, f: F) -> R {
1950 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1951 f(&transient.borrow())
1952 } else {
1953 f(&self.transient_storage)
1954 }
1955 }
1956}
1957
1958impl<'a, T, E> Ext for Stack<'a, T, E>
1959where
1960 T: Config,
1961 E: Executable<T>,
1962{
1963 fn delegate_call(
1964 &mut self,
1965 call_resources: &CallResources<T>,
1966 address: H160,
1967 input_data: Vec<u8>,
1968 ) -> Result<(), ExecError> {
1969 *self.last_frame_output_mut() = Default::default();
1972
1973 let top_frame = self.top_frame_mut();
1974 let mut contract_info = top_frame.contract_info().clone();
1978 top_frame.frame_meter.apply_pending_storage_changes(&mut contract_info);
1979 let account_id = top_frame.account_id.clone();
1980 let value = top_frame.value_transferred;
1981 if let Some(executable) = self.push_frame(
1982 FrameArgs::Call {
1983 dest: account_id,
1984 cached_info: Some(contract_info),
1985 delegated_call: Some(DelegateInfo {
1986 caller: self.caller().clone(),
1987 callee: address,
1988 }),
1989 },
1990 value,
1991 call_resources,
1992 self.is_read_only(),
1993 &input_data,
1994 )? {
1995 self.run(executable, input_data)
1996 } else {
1997 Ok(())
1999 }
2000 }
2001
2002 fn terminate_if_same_tx(&mut self, beneficiary: &H160) -> Result<CodeRemoved, DispatchError> {
2003 if_tracing(|tracer| {
2004 let addr = T::AddressMapper::to_address(self.account_id());
2005 tracer.terminate(
2006 addr,
2007 *beneficiary,
2008 self.top_frame()
2009 .frame_meter
2010 .eth_gas_left()
2011 .unwrap_or_default()
2012 .try_into()
2013 .unwrap_or_default(),
2014 crate::Pallet::<T>::evm_balance(&addr),
2015 );
2016 });
2017 let frame = top_frame_mut!(self);
2018 let info = frame.contract_info();
2019 let trie_id = info.trie_id.clone();
2020 let code_hash = info.code_hash;
2021 let contract_address = T::AddressMapper::to_address(&frame.account_id);
2022 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
2023
2024 Self::transfer(
2026 &self.origin,
2027 &frame.account_id,
2028 &beneficiary,
2029 <Contracts<T>>::evm_balance(&contract_address),
2030 Preservation::Preserve,
2031 &mut frame.frame_meter,
2032 self.exec_config,
2033 )?;
2034
2035 let account_id = frame.account_id.clone();
2037 self.top_frame_mut().contracts_to_be_destroyed.insert(
2038 account_id,
2039 TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: true },
2040 );
2041 Ok(CodeRemoved::Yes)
2042 }
2043
2044 fn own_code_hash(&mut self) -> &H256 {
2045 &self.top_frame_mut().contract_info().code_hash
2046 }
2047
2048 fn immutable_data_len(&mut self) -> u32 {
2049 self.top_frame_mut().contract_info().immutable_data_len()
2050 }
2051
2052 fn get_immutable_data(&mut self) -> Result<ImmutableData, DispatchError> {
2053 if self.top_frame().entry_point == ExportedFunction::Constructor {
2054 return Err(Error::<T>::InvalidImmutableAccess.into());
2055 }
2056
2057 let address = self
2059 .top_frame()
2060 .delegate
2061 .as_ref()
2062 .map(|d| d.callee)
2063 .unwrap_or(T::AddressMapper::to_address(self.account_id()));
2064 Ok(<ImmutableDataOf<T>>::get(address).ok_or_else(|| Error::<T>::InvalidImmutableAccess)?)
2065 }
2066
2067 fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError> {
2068 let frame = self.top_frame_mut();
2069 if frame.entry_point == ExportedFunction::Call || data.is_empty() {
2070 return Err(Error::<T>::InvalidImmutableAccess.into());
2071 }
2072 frame.contract_info().set_immutable_data_len(data.len() as u32);
2073 <ImmutableDataOf<T>>::insert(T::AddressMapper::to_address(&frame.account_id), &data);
2074 Ok(())
2075 }
2076}
2077
2078impl<'a, T, E> PrecompileWithInfoExt for Stack<'a, T, E>
2079where
2080 T: Config,
2081 E: Executable<T>,
2082{
2083 fn instantiate(
2084 &mut self,
2085 call_resources: &CallResources<T>,
2086 mut code: Code,
2087 value: U256,
2088 input_data: Vec<u8>,
2089 salt: Option<&[u8; 32]>,
2090 ) -> Result<H160, ExecError> {
2091 *self.last_frame_output_mut() = Default::default();
2094
2095 let sender = self.top_frame().account_id.clone();
2096 let executable = {
2097 let executable = match &mut code {
2098 Code::Upload(initcode) => {
2099 if !T::AllowEVMBytecode::get() {
2100 return Err(<Error<T>>::CodeRejected.into());
2101 }
2102 ensure!(input_data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
2103 let initcode = crate::tracing::if_tracing(|_| initcode.clone())
2104 .unwrap_or_else(|| mem::take(initcode));
2105 E::from_evm_init_code(initcode, sender.clone())?
2106 },
2107 Code::Existing(hash) => {
2108 let executable = E::from_storage(*hash, self.frame_meter_mut())?;
2109 ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
2110 executable
2111 },
2112 };
2113 self.push_frame(
2114 FrameArgs::Instantiate {
2115 sender,
2116 executable,
2117 salt,
2118 input_data: input_data.as_ref(),
2119 },
2120 value,
2121 call_resources,
2122 self.is_read_only(),
2123 &input_data,
2124 )?
2125 };
2126 let executable = executable.expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE);
2127
2128 let account_id = self.top_frame().account_id.clone();
2130 self.top_frame_mut().contracts_created.insert(account_id);
2131
2132 let address = T::AddressMapper::to_address(&self.top_frame().account_id);
2133 if_tracing(|t| t.instantiate_code(&code, salt));
2134 self.run(executable, input_data).map(|_| address)
2135 }
2136}
2137
2138impl<'a, T, E> PrecompileExt for Stack<'a, T, E>
2139where
2140 T: Config,
2141 E: Executable<T>,
2142{
2143 type T = T;
2144
2145 fn call(
2146 &mut self,
2147 call_resources: &CallResources<T>,
2148 dest_addr: &H160,
2149 value: U256,
2150 input_data: Vec<u8>,
2151 allows_reentry: ReentrancyProtection,
2152 read_only: bool,
2153 ) -> Result<(), ExecError> {
2154 if allows_reentry == ReentrancyProtection::Strict {
2159 self.top_frame_mut().allows_reentry = false;
2160 }
2161
2162 *self.last_frame_output_mut() = Default::default();
2165
2166 let try_call = || {
2167 let is_read_only = read_only || self.is_read_only();
2169
2170 let dest = if <AllPrecompiles<T>>::get::<Self>(dest_addr.as_fixed_bytes()).is_some() {
2172 T::AddressMapper::to_fallback_account_id(dest_addr)
2173 } else {
2174 T::AddressMapper::to_account_id(dest_addr)
2175 };
2176
2177 if !self.allows_reentry(&dest) {
2178 return Err(<Error<T>>::ReentranceDenied.into());
2179 }
2180
2181 if allows_reentry == ReentrancyProtection::AllowNext {
2182 self.top_frame_mut().allows_reentry = false;
2183 }
2184
2185 let cached_info = self
2193 .frames()
2194 .find(|f| f.entry_point == ExportedFunction::Call && f.account_id == dest)
2195 .and_then(|f| match &f.contract_info {
2196 CachedContract::Cached(contract) => {
2197 let mut contract_with_pending = contract.clone();
2198 f.frame_meter.apply_pending_storage_changes(&mut contract_with_pending);
2199 Some(contract_with_pending)
2200 },
2201 _ => None,
2202 });
2203
2204 if let Some(executable) = self.push_frame(
2205 FrameArgs::Call { dest: dest.clone(), cached_info, delegated_call: None },
2206 value,
2207 call_resources,
2208 is_read_only,
2209 &input_data,
2210 )? {
2211 self.run(executable, input_data)
2212 } else {
2213 if_tracing(|t| {
2214 t.enter_child_span(
2215 T::AddressMapper::to_address(self.account_id()),
2216 T::AddressMapper::to_address(&dest),
2217 None,
2218 is_read_only,
2219 value,
2220 &input_data,
2221 Default::default(),
2222 );
2223 });
2224
2225 let snapshot = if_tracing(|_| top_frame!(self).frame_meter.snapshot());
2226
2227 let result = if let Some(mock_answer) =
2228 self.exec_config.mock_handler.as_ref().and_then(|handler| {
2229 handler.mock_call(T::AddressMapper::to_address(&dest), &input_data, value)
2230 }) {
2231 *self.last_frame_output_mut() = mock_answer.clone();
2232 Ok(mock_answer)
2233 } else if is_read_only && value.is_zero() {
2234 Ok(Default::default())
2235 } else if is_read_only {
2236 Err(Error::<T>::StateChangeDenied.into())
2237 } else {
2238 let account_id = self.account_id().clone();
2239 let frame = top_frame_mut!(self);
2240 Self::transfer_from_origin(
2241 &self.origin,
2242 &Origin::from_account_id(account_id),
2243 &dest,
2244 value,
2245 &mut frame.frame_meter,
2246 self.exec_config,
2247 )
2248 };
2249
2250 if_tracing(|t| {
2251 let snapshot = snapshot.as_ref().expect(
2252 "snapshot is taken inside if_tracing above; tracing state cannot \
2253 change mid-call, so it is Some whenever this closure runs; qed",
2254 );
2255 let (gas_used, weight_delta) =
2256 top_frame!(self).frame_meter.delta_since(snapshot);
2257 match result {
2258 Ok(ref output) => t.exit_child_span(&output, gas_used, weight_delta),
2259 Err(e) => {
2260 t.exit_child_span_with_error(e.error.into(), gas_used, weight_delta)
2261 },
2262 }
2263 });
2264
2265 result.map(|_| ())
2266 }
2267 };
2268
2269 let result = try_call();
2271
2272 self.top_frame_mut().allows_reentry = true;
2274
2275 result
2276 }
2277
2278 fn get_transient_storage(&self, key: &Key) -> Option<Vec<u8>> {
2279 self.with_transient_storage(|transient_storage| {
2280 transient_storage.read(self.account_id(), key)
2281 })
2282 }
2283
2284 fn get_transient_storage_size(&self, key: &Key) -> Option<u32> {
2285 self.with_transient_storage(|transient_storage| {
2286 transient_storage.read(self.account_id(), key).map(|value| value.len() as _)
2287 })
2288 }
2289
2290 fn set_transient_storage(
2291 &mut self,
2292 key: &Key,
2293 value: Option<Vec<u8>>,
2294 take_old: bool,
2295 ) -> Result<WriteOutcome, DispatchError> {
2296 let account_id = self.account_id().clone();
2297 self.with_transient_storage_mut(|transient_storage| {
2298 transient_storage.write(&account_id, key, value, take_old)
2299 })
2300 }
2301
2302 fn account_id(&self) -> &T::AccountId {
2303 &self.top_frame().account_id
2304 }
2305
2306 fn caller(&self) -> Origin<T> {
2307 if let Some(Ok(mock_caller)) = self
2308 .exec_config
2309 .mock_handler
2310 .as_ref()
2311 .and_then(|mock_handler| mock_handler.mock_caller(self.frames.len()))
2312 .map(|mock_caller| Origin::<T>::from_runtime_origin(mock_caller))
2313 {
2314 return mock_caller;
2315 }
2316
2317 if let Some(DelegateInfo { caller, .. }) = &self.top_frame().delegate {
2318 caller.clone()
2319 } else {
2320 self.frames()
2321 .nth(1)
2322 .map(|f| Origin::from_account_id(f.account_id.clone()))
2323 .unwrap_or(self.origin.clone())
2324 }
2325 }
2326
2327 fn caller_of_caller(&self) -> Origin<T> {
2328 let caller_of_caller_frame = match self.frames().nth(2) {
2330 None => return self.origin.clone(),
2331 Some(frame) => frame,
2332 };
2333 if let Some(DelegateInfo { caller, .. }) = &caller_of_caller_frame.delegate {
2334 caller.clone()
2335 } else {
2336 Origin::from_account_id(caller_of_caller_frame.account_id.clone())
2337 }
2338 }
2339
2340 fn origin(&self) -> &Origin<T> {
2341 if let Some(mock_origin) = self
2342 .exec_config
2343 .mock_handler
2344 .as_ref()
2345 .and_then(|mock_handler| mock_handler.mock_origin())
2346 {
2347 return mock_origin;
2348 }
2349
2350 &self.origin
2351 }
2352
2353 fn to_account_id(&self, address: &H160) -> T::AccountId {
2354 T::AddressMapper::to_account_id(address)
2355 }
2356
2357 fn code_hash(&self, address: &H160) -> H256 {
2358 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2359 self.exec_config
2360 .mock_handler
2361 .as_ref()
2362 .and_then(|handler| handler.mocked_code(*address))
2363 }) {
2364 return sp_io::hashing::keccak_256(code).into();
2365 }
2366
2367 <AccountInfo<T>>::load_contract(&address)
2368 .map(|contract| contract.code_hash)
2369 .unwrap_or_else(|| {
2370 if System::<T>::account_exists(&T::AddressMapper::to_account_id(address)) {
2371 return EMPTY_CODE_HASH;
2372 }
2373 H256::zero()
2374 })
2375 }
2376
2377 fn code_size(&self, address: &H160) -> u64 {
2378 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2379 self.exec_config
2380 .mock_handler
2381 .as_ref()
2382 .and_then(|handler| handler.mocked_code(*address))
2383 }) {
2384 return code.len() as u64;
2385 }
2386
2387 <AccountInfo<T>>::load_contract(&address)
2388 .and_then(|contract| CodeInfoOf::<T>::get(contract.code_hash))
2389 .map(|info| info.code_len())
2390 .unwrap_or_default()
2391 }
2392
2393 fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool {
2394 let caller = if use_caller_of_caller { self.caller_of_caller() } else { self.caller() };
2395 self.origin == caller
2396 }
2397
2398 fn caller_is_root(&self, use_caller_of_caller: bool) -> bool {
2399 self.caller_is_origin(use_caller_of_caller) && self.origin == Origin::Root
2401 }
2402
2403 fn balance(&self) -> U256 {
2404 self.account_balance(&self.top_frame().account_id)
2405 }
2406
2407 fn balance_of(&self, address: &H160) -> U256 {
2408 let balance =
2409 self.account_balance(&<Self::T as Config>::AddressMapper::to_account_id(address));
2410 if_tracing(|tracer| {
2411 tracer.balance_read(address, balance);
2412 });
2413 balance
2414 }
2415
2416 fn value_transferred(&self) -> U256 {
2417 self.top_frame().value_transferred.into()
2418 }
2419
2420 fn now(&self) -> U256 {
2421 (self.timestamp / 1000u32.into()).into()
2422 }
2423
2424 fn minimum_balance(&self) -> U256 {
2425 let min = T::Currency::minimum_balance();
2426 crate::Pallet::<T>::convert_native_to_evm(min)
2427 }
2428
2429 fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
2430 let contract = T::AddressMapper::to_address(self.account_id());
2431 if_tracing(|tracer| {
2432 let log_index = frame_system::Pallet::<Self::T>::event_count();
2433 tracer.log_event(contract, &topics, &data, log_index);
2434 });
2435
2436 block_storage::capture_ethereum_log(&contract, &data, &topics);
2438
2439 Contracts::<Self::T>::deposit_event(Event::ContractEmitted { contract, data, topics });
2440 }
2441
2442 fn block_number(&self) -> U256 {
2443 self.block_number.into()
2444 }
2445
2446 fn block_hash(&self, block_number: U256) -> Option<H256> {
2447 self.block_hash(block_number)
2448 }
2449
2450 fn block_author(&self) -> H160 {
2451 Contracts::<Self::T>::block_author()
2452 }
2453
2454 fn gas_limit(&self) -> u64 {
2455 <Contracts<T>>::evm_block_gas_limit().saturated_into()
2456 }
2457
2458 fn chain_id(&self) -> u64 {
2459 <T as Config>::ChainId::get()
2460 }
2461
2462 fn gas_meter(&self) -> &FrameMeter<Self::T> {
2463 &self.top_frame().frame_meter
2464 }
2465
2466 #[inline]
2467 fn gas_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2468 &mut self.top_frame_mut().frame_meter
2469 }
2470
2471 fn frame_meter(&self) -> &FrameMeter<Self::T> {
2472 &self.top_frame().frame_meter
2473 }
2474
2475 #[inline]
2476 fn frame_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2477 &mut self.top_frame_mut().frame_meter
2478 }
2479
2480 fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> {
2481 secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ())
2482 }
2483
2484 fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool {
2485 sp_io::crypto::sr25519_verify(
2486 &SR25519Signature::from(*signature),
2487 message,
2488 &SR25519Public::from(*pub_key),
2489 )
2490 }
2491
2492 fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], DispatchError> {
2493 Ok(ECDSAPublic::from(*pk)
2494 .to_eth_address()
2495 .or_else(|()| Err(Error::<T>::EcdsaRecoveryFailed))?)
2496 }
2497
2498 #[cfg(any(test, feature = "runtime-benchmarks"))]
2499 fn contract_info(&mut self) -> &mut ContractInfo<Self::T> {
2500 self.top_frame_mut().contract_info()
2501 }
2502
2503 #[cfg(any(feature = "runtime-benchmarks", test))]
2504 fn transient_storage(&mut self) -> &mut TransientStorage<Self::T> {
2505 &mut self.transient_storage
2506 }
2507
2508 fn is_read_only(&self) -> bool {
2509 self.top_frame().read_only
2510 }
2511
2512 fn is_delegate_call(&self) -> bool {
2513 self.top_frame().delegate.is_some()
2514 }
2515
2516 fn last_frame_output(&self) -> &ExecReturnValue {
2517 &self.top_frame().last_frame_output
2518 }
2519
2520 fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue {
2521 &mut self.top_frame_mut().last_frame_output
2522 }
2523
2524 fn copy_code_slice(&mut self, buf: &mut [u8], address: &H160, code_offset: usize) {
2525 let len = buf.len();
2526 if len == 0 {
2527 return;
2528 }
2529
2530 let code_hash = self.code_hash(address);
2531 let code = crate::PristineCode::<T>::get(&code_hash).unwrap_or_default();
2532
2533 let len = len.min(code.len().saturating_sub(code_offset));
2534 if len > 0 {
2535 buf[..len].copy_from_slice(&code[code_offset..code_offset + len]);
2536 }
2537
2538 buf[len..].fill(0);
2539 }
2540
2541 fn terminate_caller(&mut self, beneficiary: &H160) -> Result<(), DispatchError> {
2542 ensure!(self.top_frame().delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2543 let parent = self.frames_mut().nth(1).ok_or_else(|| Error::<T>::ContractNotFound)?;
2544 ensure!(parent.entry_point == ExportedFunction::Call, Error::<T>::TerminatedInConstructor);
2545 ensure!(parent.delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2546
2547 let info = parent.contract_info();
2548 let trie_id = info.trie_id.clone();
2549 let code_hash = info.code_hash;
2550 let contract_address = T::AddressMapper::to_address(&parent.account_id);
2551 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
2552
2553 let parent_account_id = parent.account_id.clone();
2554
2555 Self::transfer(
2557 &self.origin,
2558 &parent_account_id,
2559 &beneficiary,
2560 <Contracts<T>>::evm_balance(&contract_address),
2561 Preservation::Preserve,
2562 &mut top_frame_mut!(self).frame_meter,
2563 &self.exec_config,
2564 )?;
2565
2566 let args = TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: false };
2568 self.top_frame_mut().contracts_to_be_destroyed.insert(parent_account_id, args);
2569
2570 Ok(())
2571 }
2572
2573 fn effective_gas_price(&self) -> U256 {
2574 self.exec_config
2575 .effective_gas_price
2576 .unwrap_or_else(|| <Contracts<T>>::evm_base_fee())
2577 }
2578
2579 fn gas_left(&self) -> u64 {
2580 let frame = self.top_frame();
2581
2582 frame.frame_meter.eth_gas_left().unwrap_or_default().saturated_into::<u64>()
2583 }
2584
2585 fn get_storage(&mut self, key: &Key) -> Option<Vec<u8>> {
2586 assert!(self.has_contract_info());
2587 self.top_frame_mut().contract_info().read(key)
2588 }
2589
2590 fn get_storage_size(&mut self, key: &Key) -> Option<u32> {
2591 assert!(self.has_contract_info());
2592 self.top_frame_mut().contract_info().size(key.into())
2593 }
2594
2595 fn set_storage(
2596 &mut self,
2597 key: &Key,
2598 value: Option<Vec<u8>>,
2599 take_old: bool,
2600 ) -> Result<WriteOutcome, DispatchError> {
2601 assert!(self.has_contract_info());
2602 let frame = self.top_frame_mut();
2603 frame.contract_info.get(&frame.account_id).write(
2604 key.into(),
2605 value,
2606 Some(&mut frame.frame_meter),
2607 take_old,
2608 )
2609 }
2610
2611 fn touch_storage_access(&mut self, transient: bool, key: &Key) -> StorageAccessKind {
2612 if transient {
2613 return StorageAccessKind::Transient;
2614 }
2615 let address = self.address();
2616 StorageAccessKind::Persistent(
2617 self.access_list.touch(AccessEntry { address, slot: key.into() }),
2618 )
2619 }
2620
2621 fn peek_storage_access(&self, transient: bool, key: &Key) -> StorageAccessKind {
2622 if transient {
2623 return StorageAccessKind::Transient;
2624 }
2625 let address = self.address();
2626 StorageAccessKind::Persistent(
2627 self.access_list.peek(&AccessEntry { address, slot: key.into() }),
2628 )
2629 }
2630
2631 fn charge_storage(&mut self, diff: &Diff) -> DispatchResult {
2632 assert!(self.has_contract_info());
2633 self.top_frame_mut().frame_meter.record_contract_storage_changes(diff)
2634 }
2635}
2636
2637pub fn is_precompile<T: Config, E: Executable<T>>(address: &H160) -> bool {
2639 <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes()).is_some()
2640}
2641
2642#[cfg(feature = "runtime-benchmarks")]
2643pub fn bench_do_terminate<T: Config>(
2644 transaction_meter: &mut TransactionMeter<T>,
2645 exec_config: &ExecConfig<T>,
2646 contract_account: &T::AccountId,
2647 origin: &Origin<T>,
2648 beneficiary: T::AccountId,
2649 trie_id: TrieId,
2650 code_hash: H256,
2651 only_if_same_tx: bool,
2652) -> Result<(), DispatchError> {
2653 Stack::<T, crate::ContractBlob<T>>::do_terminate(
2654 transaction_meter,
2655 exec_config,
2656 contract_account,
2657 origin,
2658 &TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx },
2659 )
2660}
2661
2662mod sealing {
2663 use super::*;
2664
2665 pub trait Sealed {}
2666 impl<'a, T: Config, E> Sealed for Stack<'a, T, E> {}
2667
2668 #[cfg(test)]
2669 impl<T: Config> sealing::Sealed for mock_ext::MockExt<T> {}
2670}