revm_context_interface/
host.rs

1//! Host interface for external blockchain state access.
2
3use crate::{
4    context::{SStoreResult, SelfDestructResult, StateLoad},
5    journaled_state::{AccountInfoLoad, AccountLoad},
6};
7use auto_impl::auto_impl;
8use primitives::{Address, Bytes, Log, StorageKey, StorageValue, B256, U256};
9use state::Bytecode;
10
11/// Error that can happen when loading account info.
12#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub enum LoadError {
15    /// Database error.
16    DBError,
17    /// Cold load skipped.
18    ColdLoadSkipped,
19}
20
21/// Host trait with all methods that are needed by the Interpreter.
22///
23/// This trait is implemented for all types that have `ContextTr` trait.
24///
25/// There are few groups of functions which are Block, Transaction, Config, Database and Journal functions.
26#[auto_impl(&mut, Box)]
27pub trait Host {
28    /* Block */
29
30    /// Block basefee, calls ContextTr::block().basefee()
31    fn basefee(&self) -> U256;
32    /// Block blob gasprice, calls `ContextTr::block().blob_gasprice()`
33    fn blob_gasprice(&self) -> U256;
34    /// Block gas limit, calls ContextTr::block().gas_limit()
35    fn gas_limit(&self) -> U256;
36    /// Block difficulty, calls ContextTr::block().difficulty()
37    fn difficulty(&self) -> U256;
38    /// Block prevrandao, calls ContextTr::block().prevrandao()
39    fn prevrandao(&self) -> Option<U256>;
40    /// Block number, calls ContextTr::block().number()
41    fn block_number(&self) -> U256;
42    /// Block timestamp, calls ContextTr::block().timestamp()
43    fn timestamp(&self) -> U256;
44    /// Block beneficiary, calls ContextTr::block().beneficiary()
45    fn beneficiary(&self) -> Address;
46    /// Chain id, calls ContextTr::cfg().chain_id()
47    fn chain_id(&self) -> U256;
48
49    /* Transaction */
50
51    /// Transaction effective gas price, calls `ContextTr::tx().effective_gas_price(basefee as u128)`
52    fn effective_gas_price(&self) -> U256;
53    /// Transaction caller, calls `ContextTr::tx().caller()`
54    fn caller(&self) -> Address;
55    /// Transaction blob hash, calls `ContextTr::tx().blob_hash(number)`
56    fn blob_hash(&self, number: usize) -> Option<U256>;
57
58    /* Config */
59
60    /// Max initcode size, calls `ContextTr::cfg().max_code_size().saturating_mul(2)`
61    fn max_initcode_size(&self) -> usize;
62
63    /* Database */
64
65    /// Block hash, calls `ContextTr::journal_mut().db().block_hash(number)`
66    fn block_hash(&mut self, number: u64) -> Option<B256>;
67
68    /* Journal */
69
70    /// Selfdestruct account, calls `ContextTr::journal_mut().selfdestruct(address, target)`
71    fn selfdestruct(
72        &mut self,
73        address: Address,
74        target: Address,
75    ) -> Option<StateLoad<SelfDestructResult>>;
76
77    /// Log, calls `ContextTr::journal_mut().log(log)`
78    fn log(&mut self, log: Log);
79
80    /// Sstore with optional fetch from database. Return none if the value is cold or if there is db error.
81    fn sstore_skip_cold_load(
82        &mut self,
83        address: Address,
84        key: StorageKey,
85        value: StorageValue,
86        skip_cold_load: bool,
87    ) -> Result<StateLoad<SStoreResult>, LoadError>;
88
89    /// Sstore, calls `ContextTr::journal_mut().sstore(address, key, value)`
90    fn sstore(
91        &mut self,
92        address: Address,
93        key: StorageKey,
94        value: StorageValue,
95    ) -> Option<StateLoad<SStoreResult>> {
96        self.sstore_skip_cold_load(address, key, value, false).ok()
97    }
98
99    /// Sload with optional fetch from database. Return none if the value is cold or if there is db error.
100    fn sload_skip_cold_load(
101        &mut self,
102        address: Address,
103        key: StorageKey,
104        skip_cold_load: bool,
105    ) -> Result<StateLoad<StorageValue>, LoadError>;
106
107    /// Sload, calls `ContextTr::journal_mut().sload(address, key)`
108    fn sload(&mut self, address: Address, key: StorageKey) -> Option<StateLoad<StorageValue>> {
109        self.sload_skip_cold_load(address, key, false).ok()
110    }
111
112    /// Tstore, calls `ContextTr::journal_mut().tstore(address, key, value)`
113    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
114
115    /// Tload, calls `ContextTr::journal_mut().tload(address, key)`
116    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
117
118    /// Main function to load account info.
119    ///
120    /// If load_code is true, it will load the code fetching it from the database if not done before.
121    ///
122    /// If skip_cold_load is true, it will not load the account if it is cold. This is needed to short circuit
123    /// the load if there is not enough gas.
124    ///
125    /// Returns AccountInfo, is_cold and is_empty.
126    fn load_account_info_skip_cold_load(
127        &mut self,
128        address: Address,
129        load_code: bool,
130        skip_cold_load: bool,
131    ) -> Result<AccountInfoLoad<'_>, LoadError>;
132
133    /// Balance, calls `ContextTr::journal_mut().load_account(address)`
134    #[inline]
135    fn balance(&mut self, address: Address) -> Option<StateLoad<U256>> {
136        self.load_account_info_skip_cold_load(address, false, false)
137            .ok()
138            .map(|load| load.into_state_load(|i| i.balance))
139    }
140
141    /// Load account delegated, calls `ContextTr::journal_mut().load_account_delegated(address)`
142    #[inline]
143    fn load_account_delegated(&mut self, address: Address) -> Option<StateLoad<AccountLoad>> {
144        let account = self
145            .load_account_info_skip_cold_load(address, true, false)
146            .ok()?;
147
148        let mut account_load = StateLoad::new(
149            AccountLoad {
150                is_delegate_account_cold: None,
151                is_empty: account.is_empty,
152            },
153            account.is_cold,
154        );
155
156        // load delegate code if account is EIP-7702
157        if let Some(Bytecode::Eip7702(code)) = &account.code {
158            let address = code.address();
159            let delegate_account = self
160                .load_account_info_skip_cold_load(address, true, false)
161                .ok()?;
162            account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
163            account_load.data.is_empty = delegate_account.is_empty;
164        }
165
166        Some(account_load)
167    }
168
169    /// Load account code, calls [`Host::load_account_info_skip_cold_load`] with `load_code` set to false.
170    #[inline]
171    fn load_account_code(&mut self, address: Address) -> Option<StateLoad<Bytes>> {
172        self.load_account_info_skip_cold_load(address, true, false)
173            .ok()
174            .map(|load| {
175                load.into_state_load(|i| {
176                    i.code
177                        .as_ref()
178                        .map(|b| b.original_bytes())
179                        .unwrap_or_default()
180                })
181            })
182    }
183
184    /// Load account code hash, calls [`Host::load_account_info_skip_cold_load`] with `load_code` set to false.
185    #[inline]
186    fn load_account_code_hash(&mut self, address: Address) -> Option<StateLoad<B256>> {
187        self.load_account_info_skip_cold_load(address, false, false)
188            .ok()
189            .map(|load| {
190                load.into_state_load(|i| {
191                    if i.is_empty() {
192                        B256::ZERO
193                    } else {
194                        i.code_hash
195                    }
196                })
197            })
198    }
199}
200
201/// Dummy host that implements [`Host`] trait and  returns all default values.
202#[derive(Debug)]
203pub struct DummyHost;
204
205impl Host for DummyHost {
206    fn basefee(&self) -> U256 {
207        U256::ZERO
208    }
209
210    fn blob_gasprice(&self) -> U256 {
211        U256::ZERO
212    }
213
214    fn gas_limit(&self) -> U256 {
215        U256::ZERO
216    }
217
218    fn difficulty(&self) -> U256 {
219        U256::ZERO
220    }
221
222    fn prevrandao(&self) -> Option<U256> {
223        None
224    }
225
226    fn block_number(&self) -> U256 {
227        U256::ZERO
228    }
229
230    fn timestamp(&self) -> U256 {
231        U256::ZERO
232    }
233
234    fn beneficiary(&self) -> Address {
235        Address::ZERO
236    }
237
238    fn chain_id(&self) -> U256 {
239        U256::ZERO
240    }
241
242    fn effective_gas_price(&self) -> U256 {
243        U256::ZERO
244    }
245
246    fn caller(&self) -> Address {
247        Address::ZERO
248    }
249
250    fn blob_hash(&self, _number: usize) -> Option<U256> {
251        None
252    }
253
254    fn max_initcode_size(&self) -> usize {
255        0
256    }
257
258    fn block_hash(&mut self, _number: u64) -> Option<B256> {
259        None
260    }
261
262    fn selfdestruct(
263        &mut self,
264        _address: Address,
265        _target: Address,
266    ) -> Option<StateLoad<SelfDestructResult>> {
267        None
268    }
269
270    fn log(&mut self, _log: Log) {}
271
272    fn tstore(&mut self, _address: Address, _key: StorageKey, _value: StorageValue) {}
273
274    fn tload(&mut self, _address: Address, _key: StorageKey) -> StorageValue {
275        StorageValue::ZERO
276    }
277
278    fn load_account_info_skip_cold_load(
279        &mut self,
280        _address: Address,
281        _load_code: bool,
282        _skip_cold_load: bool,
283    ) -> Result<AccountInfoLoad<'_>, LoadError> {
284        Err(LoadError::DBError)
285    }
286
287    fn sstore_skip_cold_load(
288        &mut self,
289        _address: Address,
290        _key: StorageKey,
291        _value: StorageValue,
292        _skip_cold_load: bool,
293    ) -> Result<StateLoad<SStoreResult>, LoadError> {
294        Err(LoadError::DBError)
295    }
296
297    fn sload_skip_cold_load(
298        &mut self,
299        _address: Address,
300        _key: StorageKey,
301        _skip_cold_load: bool,
302    ) -> Result<StateLoad<StorageValue>, LoadError> {
303        Err(LoadError::DBError)
304    }
305}