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 if frame.entry_point == ExportedFunction::Constructor &&
1241 self.frames().any(|f| {
1242 f.entry_point == ExportedFunction::Constructor &&
1243 f.account_id == frame.account_id
1244 }) {
1245 return Err(Error::<T>::DuplicateContract.into());
1246 }
1247 self.frames.try_push(frame).map_err(|_| Error::<T>::MaxCallDepthReached)?;
1248 Ok(Some(executable))
1249 } else {
1250 Ok(None)
1251 }
1252 }
1253
1254 fn run(
1258 &mut self,
1259 executable: ExecutableOrPrecompile<T, E, Self>,
1260 input_data: Vec<u8>,
1261 ) -> Result<(), ExecError> {
1262 let frame = self.top_frame();
1263 let entry_point = frame.entry_point;
1264 let is_pvm = executable.is_pvm();
1265
1266 if_tracing(|tracer| {
1267 let (from, to) = match frame.delegate.as_ref() {
1270 Some(delegate) => {
1271 (T::AddressMapper::to_address(&frame.account_id), delegate.callee)
1272 },
1273 None => (
1274 self.caller()
1275 .account_id()
1276 .map(T::AddressMapper::to_address)
1277 .unwrap_or_default(),
1278 T::AddressMapper::to_address(&frame.account_id),
1279 ),
1280 };
1281 tracer.enter_child_span(
1282 from,
1283 to,
1284 frame.delegate.as_ref().map(|delegate| delegate.callee),
1285 frame.read_only,
1286 frame.value_transferred,
1287 &input_data,
1288 frame
1289 .frame_meter
1290 .eth_gas_left()
1291 .unwrap_or_default()
1292 .try_into()
1293 .unwrap_or_default(),
1294 );
1295 });
1296 let mock_answer = self.exec_config.mock_handler.as_ref().and_then(|handler| {
1297 handler.mock_call(
1298 frame
1299 .delegate
1300 .as_ref()
1301 .map(|delegate| delegate.callee)
1302 .unwrap_or(T::AddressMapper::to_address(&frame.account_id)),
1303 &input_data,
1304 frame.value_transferred,
1305 )
1306 });
1307 let frames_len = self.frames.len();
1311 if let Some(caller_frame) = match frames_len {
1312 0 => None,
1313 1 => Some(&mut self.first_frame.last_frame_output),
1314 _ => self.frames.get_mut(frames_len - 2).map(|frame| &mut frame.last_frame_output),
1315 } {
1316 *caller_frame = Default::default();
1317 }
1318
1319 self.with_transient_storage_mut(|transient_storage| {
1320 transient_storage.start_transaction();
1321 });
1322 let is_first_frame = self.frames.is_empty();
1323 if !is_first_frame {
1327 self.access_list.enter_frame();
1328 }
1329
1330 let do_transaction = || -> ExecResult {
1331 let caller = self.caller();
1332 let bump_nonce = self.exec_config.bump_nonce;
1333 let frame = top_frame_mut!(self);
1334 let account_id = &frame.account_id.clone();
1335
1336 if u32::try_from(input_data.len())
1337 .map(|len| len > limits::CALLDATA_BYTES)
1338 .unwrap_or(true)
1339 {
1340 Err(<Error<T>>::CallDataTooLarge)?;
1341 }
1342
1343 if entry_point == ExportedFunction::Constructor {
1346 if !frame_system::Pallet::<T>::account_exists(&account_id) {
1347 T::Deposit::init_contract(account_id)?;
1348 }
1349
1350 <System<T>>::inc_consumers(account_id)?;
1355
1356 <System<T>>::inc_account_nonce(account_id);
1358
1359 if bump_nonce || !is_first_frame {
1360 <System<T>>::inc_account_nonce(caller.account_id()?);
1363 }
1364 if is_pvm {
1366 <CodeInfo<T>>::increment_refcount(
1367 *executable
1368 .as_executable()
1369 .expect("Precompiles cannot be instantiated; qed")
1370 .code_hash(),
1371 )?;
1372 }
1373 }
1374
1375 if frame.delegate.is_none() {
1379 Self::transfer_from_origin(
1380 &self.origin,
1381 &caller,
1382 account_id,
1383 frame.value_transferred,
1384 &mut frame.frame_meter,
1385 self.exec_config,
1386 )?;
1387 }
1388
1389 if let Some(precompile) = executable.as_precompile() &&
1396 precompile.has_contract_info() &&
1397 frame.delegate.is_none() &&
1398 !<System<T>>::account_exists(account_id)
1399 {
1400 T::Currency::mint_into(account_id, T::Currency::minimum_balance())?;
1403 <System<T>>::inc_consumers(account_id)?;
1405 }
1406
1407 let mut code_deposit = executable
1408 .as_executable()
1409 .map(|exec| exec.code_info().deposit())
1410 .unwrap_or_default();
1411
1412 let mut output = match executable {
1413 ExecutableOrPrecompile::Executable(executable) => {
1414 executable.execute(self, entry_point, input_data)
1415 },
1416 ExecutableOrPrecompile::Precompile { instance, .. } => {
1417 instance.call(input_data, self)
1418 },
1419 }
1420 .and_then(|output| {
1421 if u32::try_from(output.data.len())
1422 .map(|len| len > limits::CALLDATA_BYTES)
1423 .unwrap_or(true)
1424 {
1425 Err(<Error<T>>::ReturnDataTooLarge)?;
1426 }
1427 Ok(output)
1428 })
1429 .map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?;
1430
1431 if output.did_revert() {
1433 return Ok(output);
1434 }
1435
1436 let frame = if entry_point == ExportedFunction::Constructor {
1439 let frame = top_frame_mut!(self);
1440 if !is_pvm {
1443 let data = if crate::tracing::if_tracing(|_| {}).is_none() &&
1447 self.exec_config.is_dry_run.is_none()
1448 {
1449 core::mem::replace(&mut output.data, Default::default())
1450 } else {
1451 output.data.clone()
1452 };
1453
1454 let mut module = match &self.origin {
1458 Origin::Signed(o) => {
1459 crate::ContractBlob::<T>::from_evm_runtime_code(data, o.clone())?
1460 },
1461 Origin::Root => {
1462 crate::ContractBlob::<T>::from_evm_runtime_code_with_deposit(
1463 data,
1464 crate::Pallet::<T>::account_id(),
1465 Zero::zero(),
1466 )?
1467 },
1468 };
1469 module.store_code(&self.exec_config, &mut frame.frame_meter)?;
1470 code_deposit = module.code_info().deposit();
1471
1472 let contract_info = frame.contract_info();
1473 contract_info.code_hash = *module.code_hash();
1474 <CodeInfo<T>>::increment_refcount(contract_info.code_hash)?;
1475 }
1476
1477 let deposit = frame.contract_info().update_base_deposit(code_deposit);
1478 frame.frame_meter.charge_contract_deposit_and_transfer(
1479 frame.account_id.clone(),
1480 StorageDeposit::Charge(deposit),
1481 )?;
1482 frame
1483 } else {
1484 self.top_frame_mut()
1485 };
1486
1487 let contract = frame.contract_info.as_contract();
1491 frame
1492 .frame_meter
1493 .finalize(contract)
1494 .map_err(|e| ExecError { error: e, origin: ErrorOrigin::Callee })?;
1495
1496 Ok(output)
1497 };
1498
1499 let transaction_outcome =
1506 with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
1507 let output = if let Some(mock_answer) = mock_answer {
1508 Ok(mock_answer)
1509 } else {
1510 do_transaction()
1511 };
1512 match &output {
1513 Ok(result) if !result.did_revert() => {
1514 TransactionOutcome::Commit(Ok((true, output)))
1515 },
1516 _ => TransactionOutcome::Rollback(Ok((false, output))),
1517 }
1518 });
1519
1520 let (success, output) = match transaction_outcome {
1521 Ok((success, output)) => {
1523 if_tracing(|tracer| {
1524 let frame_meter = &top_frame!(self).frame_meter;
1525
1526 let gas_consumed = if is_first_frame {
1529 frame_meter.total_consumed_gas()
1530 } else {
1531 frame_meter.eth_gas_consumed()
1532 };
1533
1534 let gas_consumed: u64 = gas_consumed.try_into().unwrap_or(u64::MAX);
1535 let weight_consumed = frame_meter.weight_consumed();
1536
1537 match &output {
1538 Ok(output) => {
1539 tracer.exit_child_span(&output, gas_consumed, weight_consumed)
1540 },
1541 Err(e) => tracer.exit_child_span_with_error(
1542 e.error.into(),
1543 gas_consumed,
1544 weight_consumed,
1545 ),
1546 }
1547 });
1548
1549 (success, output)
1550 },
1551 Err(error) => {
1554 if_tracing(|tracer| {
1555 let frame_meter = &top_frame!(self).frame_meter;
1556
1557 let gas_consumed = if is_first_frame {
1560 frame_meter.total_consumed_gas()
1561 } else {
1562 frame_meter.eth_gas_consumed()
1563 };
1564
1565 let gas_consumed: u64 = gas_consumed.try_into().unwrap_or(u64::MAX);
1566 let weight_consumed = frame_meter.weight_consumed();
1567 tracer.exit_child_span_with_error(error.into(), gas_consumed, weight_consumed);
1568 });
1569
1570 (false, Err(error.into()))
1571 },
1572 };
1573 self.with_transient_storage_mut(|transient_storage| {
1574 if success {
1575 transient_storage.commit_transaction();
1576 } else {
1577 transient_storage.rollback_transaction();
1578 }
1579 });
1580 if is_first_frame {
1583 let m = self.access_list.metrics();
1584 log::trace!(
1585 target: LOG_TARGET,
1586 "access list metrics: size={size} cold={cold} hot={hot}",
1587 size = m.size, cold = m.cold, hot = m.hot,
1588 );
1589 } else if success {
1590 self.access_list.commit_frame();
1591 } else {
1592 self.access_list.rollback_frame();
1593 }
1594 log::trace!(target: LOG_TARGET, "frame finished with: {output:?}");
1595
1596 self.pop_frame(success);
1597 output.map(|output| {
1598 self.top_frame_mut().last_frame_output = output;
1599 })
1600 }
1601
1602 fn pop_frame(&mut self, persist: bool) {
1607 fn bank_pending_changes_and_invalidate<T: Config>(f: &mut Frame<T>) {
1614 let contract = f.account_id.clone();
1615 f.contract_info.load(&f.account_id);
1616 if let Some(info) = f.contract_info.as_contract() {
1617 f.frame_meter.bank_pending_storage_changes(contract, info);
1618 }
1619 f.contract_info.invalidate();
1626 }
1627
1628 let frame = self.frames.pop();
1632
1633 if let Some(mut frame) = frame {
1636 let account_id = &frame.account_id;
1637 let prev = top_frame_mut!(self);
1638
1639 if !persist {
1641 prev.frame_meter.absorb_weight_meter_only(frame.frame_meter);
1642 return;
1643 }
1644
1645 frame.contract_info.load(account_id);
1650 let mut contract = frame.contract_info.into_contract();
1651 prev.frame_meter
1652 .absorb_all_meters(frame.frame_meter, account_id, contract.as_mut());
1653
1654 prev.contracts_created.extend(frame.contracts_created);
1656 prev.contracts_to_be_destroyed.extend(frame.contracts_to_be_destroyed);
1657
1658 if let Some(contract) = contract {
1659 AccountInfo::<T>::insert_contract(
1664 &T::AddressMapper::to_address(account_id),
1665 contract,
1666 );
1667 if let Some(f) = self.frames_mut().find(|f| f.account_id == *account_id) {
1668 bank_pending_changes_and_invalidate(f);
1670 }
1671 }
1672 } else {
1673 if !persist {
1674 self.transaction_meter
1675 .absorb_weight_meter_only(mem::take(&mut self.first_frame.frame_meter));
1676 return;
1677 }
1678
1679 let mut contract = self.first_frame.contract_info.as_contract();
1680 self.transaction_meter.absorb_all_meters(
1681 mem::take(&mut self.first_frame.frame_meter),
1682 &self.first_frame.account_id,
1683 contract.as_deref_mut(),
1684 );
1685
1686 if let Some(contract) = contract {
1687 AccountInfo::<T>::insert_contract(
1688 &T::AddressMapper::to_address(&self.first_frame.account_id),
1689 contract.clone(),
1690 );
1691 }
1692 let contracts_created = mem::take(&mut self.first_frame.contracts_created);
1694 let contracts_to_destroy = mem::take(&mut self.first_frame.contracts_to_be_destroyed);
1695 for (contract_account, args) in contracts_to_destroy {
1696 if args.only_if_same_tx && !contracts_created.contains(&contract_account) {
1697 continue;
1698 }
1699 Self::do_terminate(
1700 &mut self.transaction_meter,
1701 self.exec_config,
1702 &contract_account,
1703 &self.origin,
1704 &args,
1705 )
1706 .ok();
1707 }
1708 }
1709 }
1710
1711 fn transfer<S: State>(
1724 origin: &Origin<T>,
1725 from: &T::AccountId,
1726 to: &T::AccountId,
1727 value: U256,
1728 preservation: Preservation,
1729 meter: &mut ResourceMeter<T, S>,
1730 exec_config: &ExecConfig<T>,
1731 ) -> DispatchResult {
1732 let value = BalanceWithDust::<BalanceOf<T>>::from_value::<T>(value)
1733 .map_err(|_| Error::<T>::BalanceConversionFailed)?;
1734 if value.is_zero() {
1735 return Ok(());
1736 }
1737
1738 if <System<T>>::account_exists(to) {
1739 return transfer_with_dust::<T>(from, to, value, preservation);
1740 }
1741
1742 let origin = origin.account_id()?;
1743 let ed = <T as Config>::Currency::minimum_balance();
1744 let is_eth_tx = exec_config.collect_deposit_from_hold.is_some();
1745 with_transaction(|| -> TransactionOutcome<DispatchResult> {
1746 match Ok::<(), DispatchError>(())
1749 .and_then(|_| {
1750 if is_eth_tx {
1751 let credit = T::FeeInfo::withdraw_txfee(ed)
1752 .ok_or(Error::<T>::StorageDepositNotEnoughFunds)?;
1753 T::Currency::resolve(to, credit)
1754 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds)?;
1755 Ok(())
1756 } else {
1757 T::Currency::transfer(origin, to, ed, Preservation::Preserve)
1758 .map(|_| ())
1759 .map_err(|_| Error::<T>::StorageDepositNotEnoughFunds.into())
1760 }
1761 })
1762 .and_then(|_| transfer_with_dust::<T>(from, to, value, preservation))
1763 .and_then(|_| meter.charge_deposit(&StorageDeposit::Charge(ed)))
1764 {
1765 Ok(_) => TransactionOutcome::Commit(Ok(())),
1766 Err(err) => TransactionOutcome::Rollback(Err(err)),
1767 }
1768 })
1769 }
1770
1771 fn transfer_from_origin<S: State>(
1773 origin: &Origin<T>,
1774 from: &Origin<T>,
1775 to: &T::AccountId,
1776 value: U256,
1777 meter: &mut ResourceMeter<T, S>,
1778 exec_config: &ExecConfig<T>,
1779 ) -> ExecResult {
1780 let from = match from {
1783 Origin::Signed(caller) => caller,
1784 Origin::Root if value.is_zero() => return Ok(Default::default()),
1785 Origin::Root => return Err(DispatchError::RootNotAllowed.into()),
1786 };
1787 Self::transfer(origin, from, to, value, Preservation::Preserve, meter, exec_config)
1788 .map(|_| Default::default())
1789 .map_err(Into::into)
1790 }
1791
1792 fn do_terminate(
1794 transaction_meter: &mut TransactionMeter<T>,
1795 exec_config: &ExecConfig<T>,
1796 contract_account: &T::AccountId,
1797 origin: &Origin<T>,
1798 args: &TerminateArgs<T>,
1799 ) -> Result<(), DispatchError> {
1800 let contract_address = T::AddressMapper::to_address(contract_account);
1801
1802 let origin: Origin<T> = match origin {
1805 Origin::Signed(o) => Origin::Signed(o.clone()),
1806 Origin::Root => Origin::from_account_id(crate::Pallet::<T>::account_id()),
1807 };
1808
1809 let mut delete_contract = |trie_id: &TrieId, code_hash: &H256| {
1810 let refund =
1812 T::Deposit::refund_all(&contract_account, exec_config.funds(origin.account_id()?))?;
1813
1814 System::<T>::dec_consumers(&contract_account);
1816
1817 T::Deposit::destroy_contract(contract_account)?;
1819
1820 let balance = <Contracts<T>>::convert_native_to_evm(<AccountInfo<T>>::total_balance(
1824 contract_address.into(),
1825 ));
1826 Self::transfer(
1827 &origin,
1828 contract_account,
1829 &args.beneficiary,
1830 balance,
1831 Preservation::Expendable,
1832 transaction_meter,
1833 exec_config,
1834 )?;
1835
1836 let _code_removed = <CodeInfo<T>>::decrement_refcount(*code_hash)?;
1838
1839 ContractInfo::<T>::queue_for_deletion(trie_id.clone(), contract_account.clone());
1841 AccountInfoOf::<T>::remove(contract_address);
1842 ImmutableDataOf::<T>::remove(contract_address);
1843
1844 transaction_meter.terminate(contract_account.clone(), refund);
1847
1848 Ok(())
1849 };
1850
1851 with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
1855 match delete_contract(&args.trie_id, &args.code_hash) {
1856 Ok(()) => {
1857 log::trace!(target: LOG_TARGET, "Terminated {contract_address:?}");
1858 TransactionOutcome::Commit(Ok(()))
1859 },
1860 Err(e) => {
1861 log::debug!(target: LOG_TARGET, "Contract at {contract_address:?} failed to terminate: {e:?}");
1862 TransactionOutcome::Rollback(Err(e))
1863 },
1864 }
1865 })
1866 }
1867
1868 fn top_frame(&self) -> &Frame<T> {
1870 top_frame!(self)
1871 }
1872
1873 fn top_frame_mut(&mut self) -> &mut Frame<T> {
1875 top_frame_mut!(self)
1876 }
1877
1878 fn frames(&self) -> impl Iterator<Item = &Frame<T>> {
1882 core::iter::once(&self.first_frame).chain(&self.frames).rev()
1883 }
1884
1885 fn frames_mut(&mut self) -> impl Iterator<Item = &mut Frame<T>> {
1887 core::iter::once(&mut self.first_frame).chain(&mut self.frames).rev()
1888 }
1889
1890 fn allows_reentry(&self, id: &T::AccountId) -> bool {
1892 !self.frames().any(|f| &f.account_id == id && !f.allows_reentry)
1893 }
1894
1895 fn account_balance(&self, who: &T::AccountId) -> U256 {
1897 let balance = AccountInfo::<T>::balance_of(AccountIdOrAddress::AccountId(who.clone()));
1898 crate::Pallet::<T>::convert_native_to_evm(balance)
1899 }
1900
1901 #[cfg(feature = "runtime-benchmarks")]
1904 pub(crate) fn override_export(&mut self, export: ExportedFunction) {
1905 self.top_frame_mut().entry_point = export;
1906 }
1907
1908 #[cfg(feature = "runtime-benchmarks")]
1909 pub(crate) fn set_block_number(&mut self, block_number: BlockNumberFor<T>) {
1910 self.block_number = block_number;
1911 }
1912
1913 fn block_hash(&self, block_number: U256) -> Option<H256> {
1914 let Ok(block_number) = BlockNumberFor::<T>::try_from(block_number) else {
1915 return None;
1916 };
1917 if block_number >= self.block_number {
1918 return None;
1919 }
1920 if block_number < self.block_number.saturating_sub(256u32.into()) {
1921 return None;
1922 }
1923
1924 match crate::Pallet::<T>::eth_block_hash_from_number(block_number.into()) {
1928 Some(hash) => Some(hash),
1929 None => {
1930 use codec::Decode;
1931 let block_hash = System::<T>::block_hash(&block_number);
1932 Decode::decode(&mut TrailingZeroInput::new(block_hash.as_ref())).ok()
1933 },
1934 }
1935 }
1936
1937 fn has_contract_info(&self) -> bool {
1940 let address = self.address();
1941 let precompile = <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes());
1942 if let Some(precompile) = precompile {
1943 return precompile.has_contract_info();
1944 }
1945 true
1946 }
1947
1948 fn with_transient_storage_mut<R, F: FnOnce(&mut TransientStorage<T>) -> R>(
1949 &mut self,
1950 f: F,
1951 ) -> R {
1952 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1953 f(&mut transient.borrow_mut())
1954 } else {
1955 f(&mut self.transient_storage)
1956 }
1957 }
1958 fn with_transient_storage<R, F: FnOnce(&TransientStorage<T>) -> R>(&self, f: F) -> R {
1959 if let Some(transient) = &self.exec_config.test_env_transient_storage {
1960 f(&transient.borrow())
1961 } else {
1962 f(&self.transient_storage)
1963 }
1964 }
1965}
1966
1967impl<'a, T, E> Ext for Stack<'a, T, E>
1968where
1969 T: Config,
1970 E: Executable<T>,
1971{
1972 fn delegate_call(
1973 &mut self,
1974 call_resources: &CallResources<T>,
1975 address: H160,
1976 input_data: Vec<u8>,
1977 ) -> Result<(), ExecError> {
1978 *self.last_frame_output_mut() = Default::default();
1981
1982 let top_frame = self.top_frame_mut();
1983 let mut contract_info = top_frame.contract_info().clone();
1987 top_frame.frame_meter.apply_pending_storage_changes(&mut contract_info);
1988 let account_id = top_frame.account_id.clone();
1989 let value = top_frame.value_transferred;
1990 if let Some(executable) = self.push_frame(
1991 FrameArgs::Call {
1992 dest: account_id,
1993 cached_info: Some(contract_info),
1994 delegated_call: Some(DelegateInfo {
1995 caller: self.caller().clone(),
1996 callee: address,
1997 }),
1998 },
1999 value,
2000 call_resources,
2001 self.is_read_only(),
2002 &input_data,
2003 )? {
2004 self.run(executable, input_data)
2005 } else {
2006 Ok(())
2008 }
2009 }
2010
2011 fn terminate_if_same_tx(&mut self, beneficiary: &H160) -> Result<CodeRemoved, DispatchError> {
2012 if_tracing(|tracer| {
2013 let addr = T::AddressMapper::to_address(self.account_id());
2014 tracer.terminate(
2015 addr,
2016 *beneficiary,
2017 self.top_frame()
2018 .frame_meter
2019 .eth_gas_left()
2020 .unwrap_or_default()
2021 .try_into()
2022 .unwrap_or_default(),
2023 crate::Pallet::<T>::evm_balance(&addr),
2024 );
2025 });
2026 let frame = top_frame_mut!(self);
2027 let info = frame.contract_info();
2028 let trie_id = info.trie_id.clone();
2029 let code_hash = info.code_hash;
2030 let contract_address = T::AddressMapper::to_address(&frame.account_id);
2031 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
2032
2033 Self::transfer(
2035 &self.origin,
2036 &frame.account_id,
2037 &beneficiary,
2038 <Contracts<T>>::evm_balance(&contract_address),
2039 Preservation::Preserve,
2040 &mut frame.frame_meter,
2041 self.exec_config,
2042 )?;
2043
2044 let account_id = frame.account_id.clone();
2046 self.top_frame_mut().contracts_to_be_destroyed.insert(
2047 account_id,
2048 TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: true },
2049 );
2050 Ok(CodeRemoved::Yes)
2051 }
2052
2053 fn own_code_hash(&mut self) -> &H256 {
2054 &self.top_frame_mut().contract_info().code_hash
2055 }
2056
2057 fn immutable_data_len(&mut self) -> u32 {
2058 self.top_frame_mut().contract_info().immutable_data_len()
2059 }
2060
2061 fn get_immutable_data(&mut self) -> Result<ImmutableData, DispatchError> {
2062 if self.top_frame().entry_point == ExportedFunction::Constructor {
2063 return Err(Error::<T>::InvalidImmutableAccess.into());
2064 }
2065
2066 let address = self
2068 .top_frame()
2069 .delegate
2070 .as_ref()
2071 .map(|d| d.callee)
2072 .unwrap_or(T::AddressMapper::to_address(self.account_id()));
2073 Ok(<ImmutableDataOf<T>>::get(address).ok_or_else(|| Error::<T>::InvalidImmutableAccess)?)
2074 }
2075
2076 fn set_immutable_data(&mut self, data: ImmutableData) -> Result<(), DispatchError> {
2077 let frame = self.top_frame_mut();
2078 if frame.entry_point == ExportedFunction::Call || data.is_empty() {
2079 return Err(Error::<T>::InvalidImmutableAccess.into());
2080 }
2081 frame.contract_info().set_immutable_data_len(data.len() as u32);
2082 <ImmutableDataOf<T>>::insert(T::AddressMapper::to_address(&frame.account_id), &data);
2083 Ok(())
2084 }
2085}
2086
2087impl<'a, T, E> PrecompileWithInfoExt for Stack<'a, T, E>
2088where
2089 T: Config,
2090 E: Executable<T>,
2091{
2092 fn instantiate(
2093 &mut self,
2094 call_resources: &CallResources<T>,
2095 mut code: Code,
2096 value: U256,
2097 input_data: Vec<u8>,
2098 salt: Option<&[u8; 32]>,
2099 ) -> Result<H160, ExecError> {
2100 *self.last_frame_output_mut() = Default::default();
2103
2104 let sender = self.top_frame().account_id.clone();
2105 let executable = {
2106 let executable = match &mut code {
2107 Code::Upload(initcode) => {
2108 if !T::AllowEVMBytecode::get() {
2109 return Err(<Error<T>>::CodeRejected.into());
2110 }
2111 ensure!(input_data.is_empty(), <Error<T>>::EvmConstructorNonEmptyData);
2112 let initcode = crate::tracing::if_tracing(|_| initcode.clone())
2113 .unwrap_or_else(|| mem::take(initcode));
2114 E::from_evm_init_code(initcode, sender.clone())?
2115 },
2116 Code::Existing(hash) => {
2117 let executable = E::from_storage(*hash, self.frame_meter_mut())?;
2118 ensure!(executable.code_info().is_pvm(), <Error<T>>::EvmConstructedFromHash);
2119 executable
2120 },
2121 };
2122 self.push_frame(
2123 FrameArgs::Instantiate {
2124 sender,
2125 executable,
2126 salt,
2127 input_data: input_data.as_ref(),
2128 },
2129 value,
2130 call_resources,
2131 self.is_read_only(),
2132 &input_data,
2133 )?
2134 };
2135 let executable = executable.expect(FRAME_ALWAYS_EXISTS_ON_INSTANTIATE);
2136
2137 let account_id = self.top_frame().account_id.clone();
2139 self.top_frame_mut().contracts_created.insert(account_id);
2140
2141 let address = T::AddressMapper::to_address(&self.top_frame().account_id);
2142 if_tracing(|t| t.instantiate_code(&code, salt));
2143 self.run(executable, input_data).map(|_| address)
2144 }
2145}
2146
2147impl<'a, T, E> PrecompileExt for Stack<'a, T, E>
2148where
2149 T: Config,
2150 E: Executable<T>,
2151{
2152 type T = T;
2153
2154 fn call(
2155 &mut self,
2156 call_resources: &CallResources<T>,
2157 dest_addr: &H160,
2158 value: U256,
2159 input_data: Vec<u8>,
2160 allows_reentry: ReentrancyProtection,
2161 read_only: bool,
2162 ) -> Result<(), ExecError> {
2163 if allows_reentry == ReentrancyProtection::Strict {
2168 self.top_frame_mut().allows_reentry = false;
2169 }
2170
2171 *self.last_frame_output_mut() = Default::default();
2174
2175 let try_call = || {
2176 let is_read_only = read_only || self.is_read_only();
2178
2179 let dest = if <AllPrecompiles<T>>::get::<Self>(dest_addr.as_fixed_bytes()).is_some() {
2181 T::AddressMapper::to_fallback_account_id(dest_addr)
2182 } else {
2183 T::AddressMapper::to_account_id(dest_addr)
2184 };
2185
2186 if !self.allows_reentry(&dest) {
2187 return Err(<Error<T>>::ReentranceDenied.into());
2188 }
2189
2190 if allows_reentry == ReentrancyProtection::AllowNext {
2191 self.top_frame_mut().allows_reentry = false;
2192 }
2193
2194 let cached_info = self
2202 .frames()
2203 .find(|f| f.entry_point == ExportedFunction::Call && f.account_id == dest)
2204 .and_then(|f| match &f.contract_info {
2205 CachedContract::Cached(contract) => {
2206 let mut contract_with_pending = contract.clone();
2207 f.frame_meter.apply_pending_storage_changes(&mut contract_with_pending);
2208 Some(contract_with_pending)
2209 },
2210 _ => None,
2211 });
2212
2213 if let Some(executable) = self.push_frame(
2214 FrameArgs::Call { dest: dest.clone(), cached_info, delegated_call: None },
2215 value,
2216 call_resources,
2217 is_read_only,
2218 &input_data,
2219 )? {
2220 self.run(executable, input_data)
2221 } else {
2222 if_tracing(|t| {
2223 t.enter_child_span(
2224 T::AddressMapper::to_address(self.account_id()),
2225 T::AddressMapper::to_address(&dest),
2226 None,
2227 is_read_only,
2228 value,
2229 &input_data,
2230 Default::default(),
2231 );
2232 });
2233
2234 let snapshot = if_tracing(|_| top_frame!(self).frame_meter.snapshot());
2235
2236 let result = if let Some(mock_answer) =
2237 self.exec_config.mock_handler.as_ref().and_then(|handler| {
2238 handler.mock_call(T::AddressMapper::to_address(&dest), &input_data, value)
2239 }) {
2240 *self.last_frame_output_mut() = mock_answer.clone();
2241 Ok(mock_answer)
2242 } else if is_read_only && value.is_zero() {
2243 Ok(Default::default())
2244 } else if is_read_only {
2245 Err(Error::<T>::StateChangeDenied.into())
2246 } else {
2247 let account_id = self.account_id().clone();
2248 let frame = top_frame_mut!(self);
2249 Self::transfer_from_origin(
2250 &self.origin,
2251 &Origin::from_account_id(account_id),
2252 &dest,
2253 value,
2254 &mut frame.frame_meter,
2255 self.exec_config,
2256 )
2257 };
2258
2259 if_tracing(|t| {
2260 let snapshot = snapshot.as_ref().expect(
2261 "snapshot is taken inside if_tracing above; tracing state cannot \
2262 change mid-call, so it is Some whenever this closure runs; qed",
2263 );
2264 let (gas_used, weight_delta) =
2265 top_frame!(self).frame_meter.delta_since(snapshot);
2266 match result {
2267 Ok(ref output) => t.exit_child_span(&output, gas_used, weight_delta),
2268 Err(e) => {
2269 t.exit_child_span_with_error(e.error.into(), gas_used, weight_delta)
2270 },
2271 }
2272 });
2273
2274 result.map(|_| ())
2275 }
2276 };
2277
2278 let result = try_call();
2280
2281 self.top_frame_mut().allows_reentry = true;
2283
2284 result
2285 }
2286
2287 fn get_transient_storage(&self, key: &Key) -> Option<Vec<u8>> {
2288 self.with_transient_storage(|transient_storage| {
2289 transient_storage.read(self.account_id(), key)
2290 })
2291 }
2292
2293 fn get_transient_storage_size(&self, key: &Key) -> Option<u32> {
2294 self.with_transient_storage(|transient_storage| {
2295 transient_storage.read(self.account_id(), key).map(|value| value.len() as _)
2296 })
2297 }
2298
2299 fn set_transient_storage(
2300 &mut self,
2301 key: &Key,
2302 value: Option<Vec<u8>>,
2303 take_old: bool,
2304 ) -> Result<WriteOutcome, DispatchError> {
2305 let account_id = self.account_id().clone();
2306 self.with_transient_storage_mut(|transient_storage| {
2307 transient_storage.write(&account_id, key, value, take_old)
2308 })
2309 }
2310
2311 fn account_id(&self) -> &T::AccountId {
2312 &self.top_frame().account_id
2313 }
2314
2315 fn caller(&self) -> Origin<T> {
2316 if let Some(Ok(mock_caller)) = self
2317 .exec_config
2318 .mock_handler
2319 .as_ref()
2320 .and_then(|mock_handler| mock_handler.mock_caller(self.frames.len()))
2321 .map(|mock_caller| Origin::<T>::from_runtime_origin(mock_caller))
2322 {
2323 return mock_caller;
2324 }
2325
2326 if let Some(DelegateInfo { caller, .. }) = &self.top_frame().delegate {
2327 caller.clone()
2328 } else {
2329 self.frames()
2330 .nth(1)
2331 .map(|f| Origin::from_account_id(f.account_id.clone()))
2332 .unwrap_or(self.origin.clone())
2333 }
2334 }
2335
2336 fn caller_of_caller(&self) -> Origin<T> {
2337 let caller_of_caller_frame = match self.frames().nth(2) {
2339 None => return self.origin.clone(),
2340 Some(frame) => frame,
2341 };
2342 if let Some(DelegateInfo { caller, .. }) = &caller_of_caller_frame.delegate {
2343 caller.clone()
2344 } else {
2345 Origin::from_account_id(caller_of_caller_frame.account_id.clone())
2346 }
2347 }
2348
2349 fn origin(&self) -> &Origin<T> {
2350 if let Some(mock_origin) = self
2351 .exec_config
2352 .mock_handler
2353 .as_ref()
2354 .and_then(|mock_handler| mock_handler.mock_origin())
2355 {
2356 return mock_origin;
2357 }
2358
2359 &self.origin
2360 }
2361
2362 fn to_account_id(&self, address: &H160) -> T::AccountId {
2363 T::AddressMapper::to_account_id(address)
2364 }
2365
2366 fn code_hash(&self, address: &H160) -> H256 {
2367 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2368 self.exec_config
2369 .mock_handler
2370 .as_ref()
2371 .and_then(|handler| handler.mocked_code(*address))
2372 }) {
2373 return sp_io::hashing::keccak_256(code).into();
2374 }
2375
2376 <AccountInfo<T>>::load_contract(&address)
2377 .map(|contract| contract.code_hash)
2378 .unwrap_or_else(|| {
2379 if System::<T>::account_exists(&T::AddressMapper::to_account_id(address)) {
2380 return EMPTY_CODE_HASH;
2381 }
2382 H256::zero()
2383 })
2384 }
2385
2386 fn code_size(&self, address: &H160) -> u64 {
2387 if let Some(code) = <AllPrecompiles<T>>::code(address.as_fixed_bytes()).or_else(|| {
2388 self.exec_config
2389 .mock_handler
2390 .as_ref()
2391 .and_then(|handler| handler.mocked_code(*address))
2392 }) {
2393 return code.len() as u64;
2394 }
2395
2396 <AccountInfo<T>>::load_contract(&address)
2397 .and_then(|contract| CodeInfoOf::<T>::get(contract.code_hash))
2398 .map(|info| info.code_len())
2399 .unwrap_or_default()
2400 }
2401
2402 fn caller_is_origin(&self, use_caller_of_caller: bool) -> bool {
2403 let caller = if use_caller_of_caller { self.caller_of_caller() } else { self.caller() };
2404 self.origin == caller
2405 }
2406
2407 fn caller_is_root(&self, use_caller_of_caller: bool) -> bool {
2408 self.caller_is_origin(use_caller_of_caller) && self.origin == Origin::Root
2410 }
2411
2412 fn balance(&self) -> U256 {
2413 self.account_balance(&self.top_frame().account_id)
2414 }
2415
2416 fn balance_of(&self, address: &H160) -> U256 {
2417 let balance =
2418 self.account_balance(&<Self::T as Config>::AddressMapper::to_account_id(address));
2419 if_tracing(|tracer| {
2420 tracer.balance_read(address, balance);
2421 });
2422 balance
2423 }
2424
2425 fn value_transferred(&self) -> U256 {
2426 self.top_frame().value_transferred.into()
2427 }
2428
2429 fn now(&self) -> U256 {
2430 (self.timestamp / 1000u32.into()).into()
2431 }
2432
2433 fn minimum_balance(&self) -> U256 {
2434 let min = T::Currency::minimum_balance();
2435 crate::Pallet::<T>::convert_native_to_evm(min)
2436 }
2437
2438 fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
2439 let contract = T::AddressMapper::to_address(self.account_id());
2440 if_tracing(|tracer| {
2441 let log_index = frame_system::Pallet::<Self::T>::event_count();
2442 tracer.log_event(contract, &topics, &data, log_index);
2443 });
2444
2445 block_storage::capture_ethereum_log(&contract, &data, &topics);
2447
2448 Contracts::<Self::T>::deposit_event(Event::ContractEmitted { contract, data, topics });
2449 }
2450
2451 fn block_number(&self) -> U256 {
2452 self.block_number.into()
2453 }
2454
2455 fn block_hash(&self, block_number: U256) -> Option<H256> {
2456 self.block_hash(block_number)
2457 }
2458
2459 fn block_author(&self) -> H160 {
2460 Contracts::<Self::T>::block_author()
2461 }
2462
2463 fn gas_limit(&self) -> u64 {
2464 <Contracts<T>>::evm_block_gas_limit().saturated_into()
2465 }
2466
2467 fn chain_id(&self) -> u64 {
2468 <T as Config>::ChainId::get()
2469 }
2470
2471 fn gas_meter(&self) -> &FrameMeter<Self::T> {
2472 &self.top_frame().frame_meter
2473 }
2474
2475 #[inline]
2476 fn gas_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2477 &mut self.top_frame_mut().frame_meter
2478 }
2479
2480 fn frame_meter(&self) -> &FrameMeter<Self::T> {
2481 &self.top_frame().frame_meter
2482 }
2483
2484 #[inline]
2485 fn frame_meter_mut(&mut self) -> &mut FrameMeter<Self::T> {
2486 &mut self.top_frame_mut().frame_meter
2487 }
2488
2489 fn ecdsa_recover(&self, signature: &[u8; 65], message_hash: &[u8; 32]) -> Result<[u8; 33], ()> {
2490 secp256k1_ecdsa_recover_compressed(signature, message_hash).map_err(|_| ())
2491 }
2492
2493 fn sr25519_verify(&self, signature: &[u8; 64], message: &[u8], pub_key: &[u8; 32]) -> bool {
2494 sp_io::crypto::sr25519_verify(
2495 &SR25519Signature::from(*signature),
2496 message,
2497 &SR25519Public::from(*pub_key),
2498 )
2499 }
2500
2501 fn ecdsa_to_eth_address(&self, pk: &[u8; 33]) -> Result<[u8; 20], DispatchError> {
2502 Ok(ECDSAPublic::from(*pk)
2503 .to_eth_address()
2504 .or_else(|()| Err(Error::<T>::EcdsaRecoveryFailed))?)
2505 }
2506
2507 #[cfg(any(test, feature = "runtime-benchmarks"))]
2508 fn contract_info(&mut self) -> &mut ContractInfo<Self::T> {
2509 self.top_frame_mut().contract_info()
2510 }
2511
2512 #[cfg(any(feature = "runtime-benchmarks", test))]
2513 fn transient_storage(&mut self) -> &mut TransientStorage<Self::T> {
2514 &mut self.transient_storage
2515 }
2516
2517 fn is_read_only(&self) -> bool {
2518 self.top_frame().read_only
2519 }
2520
2521 fn is_delegate_call(&self) -> bool {
2522 self.top_frame().delegate.is_some()
2523 }
2524
2525 fn last_frame_output(&self) -> &ExecReturnValue {
2526 &self.top_frame().last_frame_output
2527 }
2528
2529 fn last_frame_output_mut(&mut self) -> &mut ExecReturnValue {
2530 &mut self.top_frame_mut().last_frame_output
2531 }
2532
2533 fn copy_code_slice(&mut self, buf: &mut [u8], address: &H160, code_offset: usize) {
2534 let len = buf.len();
2535 if len == 0 {
2536 return;
2537 }
2538
2539 let code_hash = self.code_hash(address);
2540 let code = crate::PristineCode::<T>::get(&code_hash).unwrap_or_default();
2541
2542 let len = len.min(code.len().saturating_sub(code_offset));
2543 if len > 0 {
2544 buf[..len].copy_from_slice(&code[code_offset..code_offset + len]);
2545 }
2546
2547 buf[len..].fill(0);
2548 }
2549
2550 fn terminate_caller(&mut self, beneficiary: &H160) -> Result<(), DispatchError> {
2551 ensure!(self.top_frame().delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2552 let parent = self.frames_mut().nth(1).ok_or_else(|| Error::<T>::ContractNotFound)?;
2553 ensure!(parent.entry_point == ExportedFunction::Call, Error::<T>::TerminatedInConstructor);
2554 ensure!(parent.delegate.is_none(), Error::<T>::PrecompileDelegateDenied);
2555
2556 let info = parent.contract_info();
2557 let trie_id = info.trie_id.clone();
2558 let code_hash = info.code_hash;
2559 let contract_address = T::AddressMapper::to_address(&parent.account_id);
2560 let beneficiary = T::AddressMapper::to_account_id(beneficiary);
2561
2562 let parent_account_id = parent.account_id.clone();
2563
2564 Self::transfer(
2566 &self.origin,
2567 &parent_account_id,
2568 &beneficiary,
2569 <Contracts<T>>::evm_balance(&contract_address),
2570 Preservation::Preserve,
2571 &mut top_frame_mut!(self).frame_meter,
2572 &self.exec_config,
2573 )?;
2574
2575 let args = TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx: false };
2577 self.top_frame_mut().contracts_to_be_destroyed.insert(parent_account_id, args);
2578
2579 Ok(())
2580 }
2581
2582 fn effective_gas_price(&self) -> U256 {
2583 self.exec_config
2584 .effective_gas_price
2585 .unwrap_or_else(|| <Contracts<T>>::evm_base_fee())
2586 }
2587
2588 fn gas_left(&self) -> u64 {
2589 let frame = self.top_frame();
2590
2591 frame.frame_meter.eth_gas_left().unwrap_or_default().saturated_into::<u64>()
2592 }
2593
2594 fn get_storage(&mut self, key: &Key) -> Option<Vec<u8>> {
2595 assert!(self.has_contract_info());
2596 self.top_frame_mut().contract_info().read(key)
2597 }
2598
2599 fn get_storage_size(&mut self, key: &Key) -> Option<u32> {
2600 assert!(self.has_contract_info());
2601 self.top_frame_mut().contract_info().size(key.into())
2602 }
2603
2604 fn set_storage(
2605 &mut self,
2606 key: &Key,
2607 value: Option<Vec<u8>>,
2608 take_old: bool,
2609 ) -> Result<WriteOutcome, DispatchError> {
2610 assert!(self.has_contract_info());
2611 let frame = self.top_frame_mut();
2612 frame.contract_info.get(&frame.account_id).write(
2613 key.into(),
2614 value,
2615 Some(&mut frame.frame_meter),
2616 take_old,
2617 )
2618 }
2619
2620 fn touch_storage_access(&mut self, transient: bool, key: &Key) -> StorageAccessKind {
2621 if transient {
2622 return StorageAccessKind::Transient;
2623 }
2624 let address = self.address();
2625 StorageAccessKind::Persistent(
2626 self.access_list.touch(AccessEntry { address, slot: key.into() }),
2627 )
2628 }
2629
2630 fn peek_storage_access(&self, transient: bool, key: &Key) -> StorageAccessKind {
2631 if transient {
2632 return StorageAccessKind::Transient;
2633 }
2634 let address = self.address();
2635 StorageAccessKind::Persistent(
2636 self.access_list.peek(&AccessEntry { address, slot: key.into() }),
2637 )
2638 }
2639
2640 fn charge_storage(&mut self, diff: &Diff) -> DispatchResult {
2641 assert!(self.has_contract_info());
2642 self.top_frame_mut().frame_meter.record_contract_storage_changes(diff)
2643 }
2644}
2645
2646pub fn is_precompile<T: Config, E: Executable<T>>(address: &H160) -> bool {
2648 <AllPrecompiles<T>>::get::<Stack<'_, T, E>>(address.as_fixed_bytes()).is_some()
2649}
2650
2651#[cfg(feature = "runtime-benchmarks")]
2652pub fn bench_do_terminate<T: Config>(
2653 transaction_meter: &mut TransactionMeter<T>,
2654 exec_config: &ExecConfig<T>,
2655 contract_account: &T::AccountId,
2656 origin: &Origin<T>,
2657 beneficiary: T::AccountId,
2658 trie_id: TrieId,
2659 code_hash: H256,
2660 only_if_same_tx: bool,
2661) -> Result<(), DispatchError> {
2662 Stack::<T, crate::ContractBlob<T>>::do_terminate(
2663 transaction_meter,
2664 exec_config,
2665 contract_account,
2666 origin,
2667 &TerminateArgs { beneficiary, trie_id, code_hash, only_if_same_tx },
2668 )
2669}
2670
2671mod sealing {
2672 use super::*;
2673
2674 pub trait Sealed {}
2675 impl<'a, T: Config, E> Sealed for Stack<'a, T, E> {}
2676
2677 #[cfg(test)]
2678 impl<T: Config> sealing::Sealed for mock_ext::MockExt<T> {}
2679}