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        skip_cold_load: bool,
76    ) -> Result<StateLoad<SelfDestructResult>, LoadError>;
77
78    /// Log, calls `ContextTr::journal_mut().log(log)`
79    fn log(&mut self, log: Log);
80
81    /// Sstore with optional fetch from database. Return none if the value is cold or if there is db error.
82    fn sstore_skip_cold_load(
83        &mut self,
84        address: Address,
85        key: StorageKey,
86        value: StorageValue,
87        skip_cold_load: bool,
88    ) -> Result<StateLoad<SStoreResult>, LoadError>;
89
90    /// Sstore, calls `ContextTr::journal_mut().sstore(address, key, value)`
91    fn sstore(
92        &mut self,
93        address: Address,
94        key: StorageKey,
95        value: StorageValue,
96    ) -> Option<StateLoad<SStoreResult>> {
97        self.sstore_skip_cold_load(address, key, value, false).ok()
98    }
99
100    /// Sload with optional fetch from database. Return none if the value is cold or if there is db error.
101    fn sload_skip_cold_load(
102        &mut self,
103        address: Address,
104        key: StorageKey,
105        skip_cold_load: bool,
106    ) -> Result<StateLoad<StorageValue>, LoadError>;
107
108    /// Sload, calls `ContextTr::journal_mut().sload(address, key)`
109    fn sload(&mut self, address: Address, key: StorageKey) -> Option<StateLoad<StorageValue>> {
110        self.sload_skip_cold_load(address, key, false).ok()
111    }
112
113    /// Tstore, calls `ContextTr::journal_mut().tstore(address, key, value)`
114    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
115
116    /// Tload, calls `ContextTr::journal_mut().tload(address, key)`
117    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
118
119    /// Main function to load account info.
120    ///
121    /// If load_code is true, it will load the code fetching it from the database if not done before.
122    ///
123    /// If skip_cold_load is true, it will not load the account if it is cold. This is needed to short circuit
124    /// the load if there is not enough gas.
125    ///
126    /// Returns AccountInfo, is_cold and is_empty.
127    fn load_account_info_skip_cold_load(
128        &mut self,
129        address: Address,
130        load_code: bool,
131        skip_cold_load: bool,
132    ) -> Result<AccountInfoLoad<'_>, LoadError>;
133
134    /// Balance, calls `ContextTr::journal_mut().load_account(address)`
135    #[inline]
136    fn balance(&mut self, address: Address) -> Option<StateLoad<U256>> {
137        self.load_account_info_skip_cold_load(address, false, false)
138            .ok()
139            .map(|load| load.into_state_load(|i| i.balance))
140    }
141
142    /// Load account delegated, calls `ContextTr::journal_mut().load_account_delegated(address)`
143    #[inline]
144    fn load_account_delegated(&mut self, address: Address) -> Option<StateLoad<AccountLoad>> {
145        let account = self
146            .load_account_info_skip_cold_load(address, true, false)
147            .ok()?;
148
149        let mut account_load = StateLoad::new(
150            AccountLoad {
151                is_delegate_account_cold: None,
152                is_empty: account.is_empty,
153            },
154            account.is_cold,
155        );
156
157        // load delegate code if account is EIP-7702
158        if let Some(Bytecode::Eip7702(code)) = &account.code {
159            let address = code.address();
160            let delegate_account = self
161                .load_account_info_skip_cold_load(address, true, false)
162                .ok()?;
163            account_load.data.is_delegate_account_cold = Some(delegate_account.is_cold);
164            account_load.data.is_empty = delegate_account.is_empty;
165        }
166
167        Some(account_load)
168    }
169
170    /// Load account code, calls [`Host::load_account_info_skip_cold_load`] with `load_code` set to false.
171    #[inline]
172    fn load_account_code(&mut self, address: Address) -> Option<StateLoad<Bytes>> {
173        self.load_account_info_skip_cold_load(address, true, false)
174            .ok()
175            .map(|load| {
176                load.into_state_load(|i| {
177                    i.code
178                        .as_ref()
179                        .map(|b| b.original_bytes())
180                        .unwrap_or_default()
181                })
182            })
183    }
184
185    /// Load account code hash, calls [`Host::load_account_info_skip_cold_load`] with `load_code` set to false.
186    #[inline]
187    fn load_account_code_hash(&mut self, address: Address) -> Option<StateLoad<B256>> {
188        self.load_account_info_skip_cold_load(address, false, false)
189            .ok()
190            .map(|load| {
191                load.into_state_load(|i| {
192                    if i.is_empty() {
193                        B256::ZERO
194                    } else {
195                        i.code_hash
196                    }
197                })
198            })
199    }
200}
201
202/// Dummy host that implements [`Host`] trait and  returns all default values.
203#[derive(Debug)]
204pub struct DummyHost;
205
206impl Host for DummyHost {
207    fn basefee(&self) -> U256 {
208        U256::ZERO
209    }
210
211    fn blob_gasprice(&self) -> U256 {
212        U256::ZERO
213    }
214
215    fn gas_limit(&self) -> U256 {
216        U256::ZERO
217    }
218
219    fn difficulty(&self) -> U256 {
220        U256::ZERO
221    }
222
223    fn prevrandao(&self) -> Option<U256> {
224        None
225    }
226
227    fn block_number(&self) -> U256 {
228        U256::ZERO
229    }
230
231    fn timestamp(&self) -> U256 {
232        U256::ZERO
233    }
234
235    fn beneficiary(&self) -> Address {
236        Address::ZERO
237    }
238
239    fn chain_id(&self) -> U256 {
240        U256::ZERO
241    }
242
243    fn effective_gas_price(&self) -> U256 {
244        U256::ZERO
245    }
246
247    fn caller(&self) -> Address {
248        Address::ZERO
249    }
250
251    fn blob_hash(&self, _number: usize) -> Option<U256> {
252        None
253    }
254
255    fn max_initcode_size(&self) -> usize {
256        0
257    }
258
259    fn block_hash(&mut self, _number: u64) -> Option<B256> {
260        None
261    }
262
263    fn selfdestruct(
264        &mut self,
265        _address: Address,
266        _target: Address,
267        _skip_cold_load: bool,
268    ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
269        Err(LoadError::ColdLoadSkipped)
270    }
271
272    fn log(&mut self, _log: Log) {}
273
274    fn tstore(&mut self, _address: Address, _key: StorageKey, _value: StorageValue) {}
275
276    fn tload(&mut self, _address: Address, _key: StorageKey) -> StorageValue {
277        StorageValue::ZERO
278    }
279
280    fn load_account_info_skip_cold_load(
281        &mut self,
282        _address: Address,
283        _load_code: bool,
284        _skip_cold_load: bool,
285    ) -> Result<AccountInfoLoad<'_>, LoadError> {
286        Err(LoadError::DBError)
287    }
288
289    fn sstore_skip_cold_load(
290        &mut self,
291        _address: Address,
292        _key: StorageKey,
293        _value: StorageValue,
294        _skip_cold_load: bool,
295    ) -> Result<StateLoad<SStoreResult>, LoadError> {
296        Err(LoadError::DBError)
297    }
298
299    fn sload_skip_cold_load(
300        &mut self,
301        _address: Address,
302        _key: StorageKey,
303        _skip_cold_load: bool,
304    ) -> Result<StateLoad<StorageValue>, LoadError> {
305        Err(LoadError::DBError)
306    }
307}