1pub(crate) mod fork;
5pub(crate) mod fork_backend;
6pub(crate) mod in_memory_db;
7
8use alloy_primitives::{Address, U256};
9use anyhow::{anyhow, Result};
10use revm::{
11 interpreter::primitives::EnvWithHandlerCfg,
12 primitives::{
13 Account, AccountInfo, Bytecode, HashMap as Map, ResultAndState, B256, KECCAK_EMPTY,
14 },
15 Database, DatabaseCommit, DatabaseRef, EvmBuilder,
16};
17use std::time::{SystemTime, UNIX_EPOCH};
18
19use self::{fork::Fork, in_memory_db::MemDb};
20use crate::{errors::DatabaseError, snapshot::SnapShot};
21
22#[derive(Clone, Debug)]
24pub struct CreateFork {
25 pub url: String,
27 pub blocknumber: Option<u64>,
29}
30
31impl CreateFork {
32 pub fn new(url: String, blocknumber: Option<u64>) -> Self {
34 Self { url, blocknumber }
35 }
36
37 pub fn latest_block(url: String) -> Self {
39 Self {
40 url,
41 blocknumber: None,
42 }
43 }
44}
45
46pub struct StorageBackend {
51 mem_db: MemDb, forkdb: Option<Fork>,
53 pub block_number: u64, pub timestamp: u64,
55}
56
57impl Default for StorageBackend {
58 fn default() -> Self {
59 StorageBackend::new(None)
60 }
61}
62
63impl StorageBackend {
64 pub fn new(fork: Option<CreateFork>) -> Self {
65 if let Some(fork) = fork {
66 let backend = Fork::new(&fork.url, fork.blocknumber);
67 let block_number = backend.block_number;
68 let timestamp = backend.timestamp;
69 Self {
70 mem_db: MemDb::default(),
71 forkdb: Some(backend),
72 block_number,
73 timestamp,
74 }
75 } else {
76 let timestamp = SystemTime::now()
77 .duration_since(UNIX_EPOCH)
78 .expect("StorageBackend: failed to get unix epoch time")
79 .as_secs();
80 Self {
81 mem_db: MemDb::default(),
82 forkdb: None,
83 block_number: 1,
84 timestamp,
85 }
86 }
87 }
88
89 pub fn insert_account_info(&mut self, address: Address, info: AccountInfo) {
90 if let Some(fork) = self.forkdb.as_mut() {
91 fork.database_mut().insert_account_info(address, info)
92 } else {
93 self.mem_db.db.insert_account_info(address, info)
95 }
96 }
97
98 pub fn insert_account_storage(
99 &mut self,
100 address: Address,
101 slot: U256,
102 value: U256,
103 ) -> Result<(), DatabaseError> {
104 let ret = if let Some(fork) = self.forkdb.as_mut() {
105 fork.database_mut()
106 .insert_account_storage(address, slot, value)
107 } else {
108 self.mem_db.db.insert_account_storage(address, slot, value)
109 };
110 ret
111 }
112
113 pub fn replace_account_storage(
114 &mut self,
115 address: Address,
116 storage: Map<U256, U256>,
117 ) -> Result<(), DatabaseError> {
118 if let Some(fork) = self.forkdb.as_mut() {
119 fork.database_mut()
120 .replace_account_storage(address, storage)
121 } else {
122 self.mem_db.db.replace_account_storage(address, storage)
123 }
124 }
125
126 pub fn run_transact(&mut self, env: &mut EnvWithHandlerCfg) -> Result<ResultAndState> {
127 let mut evm = create_evm(self, env.clone());
128 let res = evm
129 .transact()
130 .map_err(|e| anyhow!("backend failed while executing transaction: {:?}", e))?;
131 env.env = evm.context.evm.inner.env;
132
133 Ok(res)
134 }
135
136 pub fn create_snapshot(&self) -> Result<SnapShot> {
139 if let Some(fork) = self.forkdb.as_ref() {
140 fork.create_snapshot(self.block_number, self.timestamp)
141 } else {
142 self.mem_db
143 .create_snapshot(self.block_number, self.timestamp)
144 }
145 }
146
147 pub fn load_snapshot(&mut self, snapshot: SnapShot) {
149 self.block_number = snapshot.block_num;
150 self.timestamp = snapshot.timestamp;
151
152 for (addr, account) in snapshot.accounts.into_iter() {
153 self.mem_db.db.insert_account_info(
155 addr,
156 AccountInfo {
157 balance: account.balance,
158 nonce: account.nonce,
159 code_hash: KECCAK_EMPTY,
160 code: if account.code.0.is_empty() {
161 None
162 } else {
163 Some(
164 Bytecode::new_raw(alloy_primitives::Bytes(account.code.0)).to_checked(),
165 )
166 },
167 },
168 );
169
170 for (k, v) in account.storage.into_iter() {
172 self.mem_db
173 .db
174 .accounts
175 .entry(addr)
176 .or_default()
177 .storage
178 .insert(k, v);
179 }
180 }
181 }
182
183 pub fn update_block_info(&mut self, interval: u64) {
185 self.block_number += 1;
186 self.timestamp += interval;
187 }
188}
189
190impl DatabaseRef for StorageBackend {
191 type Error = DatabaseError;
192
193 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
194 if let Some(db) = self.forkdb.as_ref() {
195 db.basic_ref(address)
196 } else {
197 Ok(self.mem_db.basic_ref(address)?)
198 }
199 }
200
201 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
202 if let Some(db) = self.forkdb.as_ref() {
203 db.code_by_hash_ref(code_hash)
204 } else {
205 Ok(self.mem_db.code_by_hash_ref(code_hash)?)
206 }
207 }
208
209 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
210 if let Some(db) = self.forkdb.as_ref() {
211 DatabaseRef::storage_ref(db, address, index)
212 } else {
213 Ok(DatabaseRef::storage_ref(&self.mem_db, address, index)?)
214 }
215 }
216
217 fn block_hash_ref(&self, number: U256) -> Result<B256, Self::Error> {
218 if let Some(db) = self.forkdb.as_ref() {
219 db.block_hash_ref(number)
220 } else {
221 Ok(self.mem_db.block_hash_ref(number)?)
222 }
223 }
224}
225
226impl Database for StorageBackend {
227 type Error = DatabaseError;
228 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
229 if let Some(db) = self.forkdb.as_mut() {
230 db.basic(address)
231 } else {
232 Ok(self.mem_db.basic(address)?)
233 }
234 }
235
236 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
237 if let Some(db) = self.forkdb.as_mut() {
238 db.code_by_hash(code_hash)
239 } else {
240 Ok(self.mem_db.code_by_hash(code_hash)?)
241 }
242 }
243
244 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
245 if let Some(db) = self.forkdb.as_mut() {
246 Database::storage(db, address, index)
247 } else {
248 Ok(Database::storage(&mut self.mem_db, address, index)?)
249 }
250 }
251
252 fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
253 if let Some(db) = self.forkdb.as_mut() {
254 db.block_hash(number)
255 } else {
256 Ok(self.mem_db.block_hash(number)?)
257 }
258 }
259}
260
261impl DatabaseCommit for StorageBackend {
262 fn commit(&mut self, changes: Map<Address, Account>) {
263 if let Some(db) = self.forkdb.as_mut() {
264 db.commit(changes)
265 } else {
266 self.mem_db.commit(changes)
267 }
268 }
269}
270
271fn create_evm<'a, DB: Database>(
272 db: DB,
273 env: revm::primitives::EnvWithHandlerCfg,
274) -> revm::Evm<'a, (), DB> {
275 EvmBuilder::default()
276 .with_db(db)
277 .with_env(env.env.clone())
278 .build()
279}