edb_common/
context.rs

1// EDB - Ethereum Debugger
2// Copyright (C) 2024 Zhuo Zhang and Wuqi Zhang
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU Affero General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU Affero General Public License for more details.
13//
14// You should have received a copy of the GNU Affero General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17//! Context-related types and traits
18//! This module provides types and traits for working with the EVM context.
19
20use revm::{
21    context::{BlockEnv, CfgEnv, TxEnv},
22    database::CacheDB,
23    database_interface::DBErrorMarker,
24    primitives::{Address, HashMap, B256, U256},
25    state::{Account, AccountInfo, Bytecode},
26    Context, Database, DatabaseCommit, DatabaseRef,
27};
28use std::{fmt, sync::Arc};
29
30/// Type alias for the EDB context in terms of revm's Context
31pub type EdbContext<DB> = Context<BlockEnv, TxEnv, CfgEnv, CacheDB<DB>>;
32
33/// Type alias for the derived context with Arc-wrapped CacheDB.
34/// This context is used for those derived EVM instances at each snapshot.
35pub type DerivedContext<DB> = EdbContext<CacheDB<Arc<CacheDB<DB>>>>;
36
37/// Relax the constraints for EVM execution in the given context and transaction
38pub fn relax_evm_constraints<DB: Database + DatabaseRef>(
39    context: &mut EdbContext<DB>,
40    tx: &mut TxEnv,
41) {
42    relax_evm_context_constraints(context);
43    relax_evm_tx_constraints(tx);
44}
45
46/// Relax the constraints for EVM execution in the given context
47pub fn relax_evm_context_constraints<DB: Database + DatabaseRef>(context: &mut EdbContext<DB>) {
48    let cfg = &mut context.cfg;
49    cfg.disable_base_fee = true;
50    cfg.disable_block_gas_limit = true;
51    cfg.tx_gas_limit_cap = Some(u64::MAX);
52    cfg.limit_contract_initcode_size = Some(usize::MAX);
53    cfg.limit_contract_code_size = Some(usize::MAX);
54}
55
56/// Disable nonce check in the given context
57pub fn disable_nonce_check<DB: Database + DatabaseRef>(context: &mut EdbContext<DB>) {
58    context.cfg.disable_nonce_check = true;
59}
60
61/// Relax the constraints for EVM execution in the given transaction
62pub fn relax_evm_tx_constraints(tx: &mut TxEnv) {
63    tx.gas_limit = u64::MAX; // Relax gas limit for execution
64    tx.gas_price = 0; // Relax gas price for execution
65    tx.gas_priority_fee = Some(0); // Relax gas priority fee for execution
66}
67
68/// A cloneable error type for EdbDB
69#[derive(Clone, Debug)]
70pub struct EdbDBError {
71    message: String,
72}
73
74impl EdbDBError {
75    /// Create a new error with a message
76    pub fn new(message: impl Into<String>) -> Self {
77        Self { message: message.into() }
78    }
79
80    /// Create from any error type
81    pub fn from_error<E: std::error::Error>(err: E) -> Self {
82        Self::new(err.to_string())
83    }
84}
85
86impl fmt::Display for EdbDBError {
87    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88        write!(f, "EdbDB Error: {}", self.message)
89    }
90}
91
92impl std::error::Error for EdbDBError {}
93
94impl DBErrorMarker for EdbDBError {}
95
96/// A wrapper database that provides a cloneable error type
97/// This allows the database to be used in contexts requiring Clone
98#[derive(Clone)]
99pub struct EdbDB<DB> {
100    inner: DB,
101}
102
103impl<DB> EdbDB<DB> {
104    /// Create a new EdbDB wrapping an inner database
105    pub fn new(inner: DB) -> Self {
106        Self { inner }
107    }
108
109    /// Get a reference to the inner database
110    pub fn inner(&self) -> &DB {
111        &self.inner
112    }
113
114    /// Get a mutable reference to the inner database
115    pub fn inner_mut(&mut self) -> &mut DB {
116        &mut self.inner
117    }
118
119    /// Consume self and return the inner database
120    pub fn into_inner(self) -> DB {
121        self.inner
122    }
123}
124
125impl<DB> Database for EdbDB<DB>
126where
127    DB: Database,
128    <DB as Database>::Error: std::error::Error,
129{
130    type Error = EdbDBError;
131
132    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
133        self.inner.basic(address).map_err(EdbDBError::from_error)
134    }
135
136    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
137        self.inner.code_by_hash(code_hash).map_err(EdbDBError::from_error)
138    }
139
140    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
141        self.inner.storage(address, index).map_err(EdbDBError::from_error)
142    }
143
144    fn block_hash(&mut self, block: u64) -> Result<B256, Self::Error> {
145        self.inner.block_hash(block).map_err(EdbDBError::from_error)
146    }
147}
148
149impl<DB> DatabaseCommit for EdbDB<DB>
150where
151    DB: DatabaseCommit + Database,
152    <DB as Database>::Error: std::error::Error,
153{
154    fn commit(&mut self, changes: HashMap<Address, Account>) {
155        self.inner.commit(changes)
156    }
157}
158
159impl<DB> DatabaseRef for EdbDB<DB>
160where
161    DB: DatabaseRef + Database,
162    <DB as Database>::Error: std::error::Error,
163{
164    type Error = EdbDBError;
165
166    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
167        self.inner.basic_ref(address).map_err(EdbDBError::from_error)
168    }
169
170    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
171        self.inner.code_by_hash_ref(code_hash).map_err(EdbDBError::from_error)
172    }
173
174    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
175        self.inner.storage_ref(address, index).map_err(EdbDBError::from_error)
176    }
177
178    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
179        self.inner.block_hash_ref(number).map_err(EdbDBError::from_error)
180    }
181}