evm_interpreter/
runtime.rs

1//! Runtime state and related traits.
2
3use alloc::{rc::Rc, vec::Vec};
4
5use primitive_types::{H160, H256, U256};
6use sha3::{Digest, Keccak256};
7
8use crate::error::ExitError;
9
10/// Gas state.
11pub trait GasState {
12	/// Left gas.
13	fn gas(&self) -> U256;
14}
15
16/// Runtime state.
17#[derive(Clone, Debug)]
18pub struct RuntimeState {
19	/// Runtime context.
20	pub context: Context,
21	/// Transaction context.
22	pub transaction_context: Rc<TransactionContext>,
23	/// Return data buffer.
24	pub retbuf: Vec<u8>,
25}
26
27/// Runtime config.
28#[derive(Clone, Debug)]
29#[non_exhaustive]
30pub struct RuntimeConfig {
31	/// EIP-161: new rules about empty accounts.
32	pub eip161_empty_check: bool,
33	/// EIP-7610: check whether storage is empty in create collision logic.
34	pub eip7610_create_check_storage: bool,
35	/// EIP-6780: selfdestruct deletet contract only if called in the same tx as creation
36	pub eip6780_suicide_only_in_same_tx: bool,
37	/// EIP-3651
38	pub eip3651_warm_coinbase_address: bool,
39}
40
41impl RuntimeConfig {
42	/// Create a new Runtime config with default settings.
43	pub const fn new() -> Self {
44		Self {
45			eip161_empty_check: true,
46			eip7610_create_check_storage: true,
47			eip6780_suicide_only_in_same_tx: false,
48			eip3651_warm_coinbase_address: false,
49		}
50	}
51
52	/// Create a new Runtime config with Frontier settings (everything disabled).
53	pub const fn frontier() -> Self {
54		Self {
55			eip161_empty_check: false,
56			eip6780_suicide_only_in_same_tx: false,
57			eip7610_create_check_storage: true,
58			eip3651_warm_coinbase_address: false,
59		}
60	}
61}
62
63impl Default for RuntimeConfig {
64	fn default() -> Self {
65		Self::new()
66	}
67}
68
69/// Runtime state and config.
70#[derive(Clone, Debug)]
71pub struct RuntimeStateAndConfig<'config> {
72	/// Runtime state.
73	pub state: RuntimeState,
74	/// RuntimeConfig,
75	pub config: &'config RuntimeConfig,
76}
77
78static DEFAULT_RUNTIME_CONFIG: RuntimeConfig = RuntimeConfig::new();
79
80impl RuntimeStateAndConfig<'static> {
81	/// Used for testing.
82	pub fn with_default_config(state: RuntimeState) -> Self {
83		Self {
84			state,
85			config: &DEFAULT_RUNTIME_CONFIG,
86		}
87	}
88}
89
90impl AsRef<RuntimeState> for RuntimeState {
91	fn as_ref(&self) -> &RuntimeState {
92		self
93	}
94}
95
96impl<'config> AsRef<RuntimeState> for RuntimeStateAndConfig<'config> {
97	fn as_ref(&self) -> &RuntimeState {
98		&self.state
99	}
100}
101
102impl AsMut<RuntimeState> for RuntimeState {
103	fn as_mut(&mut self) -> &mut RuntimeState {
104		self
105	}
106}
107
108impl<'config> AsMut<RuntimeState> for RuntimeStateAndConfig<'config> {
109	fn as_mut(&mut self) -> &mut RuntimeState {
110		&mut self.state
111	}
112}
113
114impl<'config> AsRef<RuntimeConfig> for RuntimeStateAndConfig<'config> {
115	fn as_ref(&self) -> &RuntimeConfig {
116		self.config
117	}
118}
119
120impl GasState for RuntimeState {
121	fn gas(&self) -> U256 {
122		U256::zero()
123	}
124}
125
126impl<'config> GasState for RuntimeStateAndConfig<'config> {
127	fn gas(&self) -> U256 {
128		U256::zero()
129	}
130}
131
132/// Context of the runtime.
133#[derive(Clone, Debug)]
134pub struct Context {
135	/// Execution address.
136	pub address: H160,
137	/// Caller of the EVM.
138	pub caller: H160,
139	/// Apparent value of the EVM.
140	pub apparent_value: U256,
141}
142
143/// Context of the transaction.
144#[derive(Clone, Debug)]
145pub struct TransactionContext {
146	/// Gas price.
147	pub gas_price: U256,
148	/// Origin.
149	pub origin: H160,
150}
151
152/// Transfer from source to target, with given value.
153#[derive(Clone, Debug)]
154pub struct Transfer {
155	/// Source address.
156	pub source: H160,
157	/// Target address.
158	pub target: H160,
159	/// Transfer value.
160	pub value: U256,
161}
162
163/// Log
164#[derive(Clone, Debug)]
165pub struct Log {
166	/// Address
167	pub address: H160,
168	/// Topics
169	pub topics: Vec<H256>,
170	/// Log data
171	pub data: Vec<u8>,
172}
173
174/// Identify if the origin of set_code() comes from a transaction or subcall.
175#[derive(Clone, Debug)]
176pub enum SetCodeOrigin {
177	/// Comes from a transaction.
178	Transaction,
179	/// Comes from a subcall.
180	Subcall(H160),
181}
182
183/// Runtime environment.
184#[auto_impl::auto_impl(&, Box)]
185pub trait RuntimeEnvironment {
186	/// Get environmental block hash.
187	fn block_hash(&self, number: U256) -> H256;
188	/// Get environmental block number.
189	fn block_number(&self) -> U256;
190	/// Get environmental coinbase.
191	fn block_coinbase(&self) -> H160;
192	/// Get environmental block timestamp.
193	fn block_timestamp(&self) -> U256;
194	/// Get environmental block difficulty.
195	fn block_difficulty(&self) -> U256;
196	/// Get environmental block randomness.
197	fn block_randomness(&self) -> Option<H256>;
198	/// Get environmental gas limit.
199	fn block_gas_limit(&self) -> U256;
200	/// Environmental block base fee.
201	fn block_base_fee_per_gas(&self) -> U256;
202	/// Blob hash.
203	fn blob_versioned_hash(&self, index: U256) -> H256;
204	/// Blob base fee per gas.
205	fn blob_base_fee_per_gas(&self) -> U256;
206	/// Get environmental chain ID.
207	fn chain_id(&self) -> U256;
208}
209
210/// Runtime base backend. The immutable and limited part of [RuntimeBackend].
211#[auto_impl::auto_impl(&, Box)]
212pub trait RuntimeBaseBackend {
213	/// Get balance of address.
214	fn balance(&self, address: H160) -> U256;
215	/// Get code size of address.
216	fn code_size(&self, address: H160) -> U256 {
217		U256::from(self.code(address).len())
218	}
219	/// Get code hash of address.
220	///
221	/// The caller is responsible for checking whether the account is empty.
222	fn code_hash(&self, address: H160) -> H256 {
223		if self.exists(address) {
224			H256::from_slice(&Keccak256::digest(&self.code(address)[..]))
225		} else {
226			H256::default()
227		}
228	}
229	/// Get code of address.
230	fn code(&self, address: H160) -> Vec<u8>;
231	/// Get storage value of address at index.
232	fn storage(&self, address: H160, index: H256) -> H256;
233	/// Get transient storage value of address at index.
234	fn transient_storage(&self, address: H160, index: H256) -> H256;
235
236	/// Check whether an address exists.
237	///
238	/// If you are running Rust EVM on Ethereum mainnet, set the Backend to pre-EIP161 rule,
239	/// and the Overlay with config for post-EIP161 rule.
240	fn exists(&self, address: H160) -> bool;
241	/// Detect for create collision. Note EIP-7610.
242	fn can_create(&self, address: H160) -> bool {
243		self.code_size(address) == U256::zero() && self.nonce(address) == U256::zero()
244	}
245
246	/// Get the current nonce of an account.
247	fn nonce(&self, address: H160) -> U256;
248}
249
250/// For what reason is the address marked hot.
251#[derive(Debug, Clone, Eq, PartialEq)]
252pub enum TouchKind {
253	/// State change according to EIP-161.
254	StateChange,
255	/// Coinbase address.
256	Coinbase,
257	/// A normal access.
258	Access,
259}
260
261/// The distinguish between `RuntimeBaseBackend` and `RuntimeBackend` is for the implementation of
262/// overlays.
263pub trait RuntimeBackend: RuntimeBaseBackend {
264	/// Get original storage value of address at index.
265	fn original_storage(&self, address: H160, index: H256) -> H256;
266	/// Check whether an address has already been deleted.
267	fn deleted(&self, address: H160) -> bool;
268	/// Check whether an address has already been created in the transaction.
269	fn created(&self, address: H160) -> bool;
270	/// Checks if the address or (address, index) pair has been previously accessed.
271	fn is_cold(&self, address: H160, index: Option<H256>) -> bool;
272	/// Checks if the address is hot. Opposite of [RuntimeBackend::is_cold].
273	fn is_hot(&self, address: H160, index: Option<H256>) -> bool {
274		!self.is_cold(address, index)
275	}
276
277	/// Mark an address as hot.
278	fn mark_hot(&mut self, address: H160, kind: TouchKind);
279	/// Mark an (address, index) pair as hot.
280	fn mark_storage_hot(&mut self, address: H160, index: H256);
281	/// Set storage value of address at index.
282	fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError>;
283	/// Set transient storage value of address at index, transient storage gets discarded after every transaction. (see EIP-1153)
284	fn set_transient_storage(
285		&mut self,
286		address: H160,
287		index: H256,
288		value: H256,
289	) -> Result<(), ExitError>;
290	/// Create a log owned by address with given topics and data.
291	fn log(&mut self, log: Log) -> Result<(), ExitError>;
292	/// Mark an address to be deleted and its balance to be reset.
293	fn mark_delete_reset(&mut self, address: H160);
294	/// Mark an address as created in the current transaction.
295	fn mark_create(&mut self, address: H160);
296	/// Fully delete storages of an account.
297	fn reset_storage(&mut self, address: H160);
298	/// Set code of an account.
299	fn set_code(
300		&mut self,
301		address: H160,
302		code: Vec<u8>,
303		origin: SetCodeOrigin,
304	) -> Result<(), ExitError>;
305	/// Deposit value into the target.
306	fn deposit(&mut self, target: H160, value: U256);
307	/// Withdrawal value from the source.
308	fn withdrawal(&mut self, source: H160, value: U256) -> Result<(), ExitError>;
309	/// Initiate a transfer.
310	fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> {
311		self.withdrawal(transfer.source, transfer.value)?;
312		self.deposit(transfer.target, transfer.value);
313		Ok(())
314	}
315	/// Increase the nonce value.
316	fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError>;
317}