1use std::{
10 fs,
11 io::{self, Read, Write},
12};
13
14use revm::{
15 primitives::{db::DatabaseRef, keccak256, Bytecode, B256},
16 DatabaseCommit,
17};
18use serde_json;
19
20use super::*;
21pub mod fork;
22pub mod inspector;
23
24#[derive(Debug, Serialize, Deserialize)]
30pub struct ArbiterDB {
31 pub state: Arc<RwLock<CacheDB<EmptyDB>>>,
34
35 pub logs: Arc<RwLock<HashMap<U256, Vec<eLog>>>>,
38}
39
40impl Clone for ArbiterDB {
42 fn clone(&self) -> Self {
43 Self {
44 state: self.state.clone(),
45 logs: self.logs.clone(),
46 }
47 }
48}
49
50impl ArbiterDB {
51 pub fn new() -> Self {
53 Self {
54 state: Arc::new(RwLock::new(CacheDB::new(EmptyDB::new()))),
55 logs: Arc::new(RwLock::new(HashMap::new())),
56 }
57 }
58
59 pub fn write_to_file(&self, path: &str) -> io::Result<()> {
61 let serialized = serde_json::to_string(self)?;
63 let mut file = fs::File::create(path)?;
65 file.write_all(serialized.as_bytes())?;
66 Ok(())
67 }
68
69 pub fn read_from_file(path: &str) -> io::Result<Self> {
71 let mut file = fs::File::open(path)?;
73 let mut contents = String::new();
74 file.read_to_string(&mut contents)?;
75
76 #[derive(Deserialize)]
78 struct TempDB {
79 state: Option<CacheDB<EmptyDB>>,
80 logs: Option<HashMap<U256, Vec<eLog>>>,
81 }
82 let temp_db: TempDB = serde_json::from_str(&contents)?;
83 Ok(Self {
84 state: Arc::new(RwLock::new(temp_db.state.unwrap_or_default())),
85 logs: Arc::new(RwLock::new(temp_db.logs.unwrap_or_default())),
86 })
87 }
88}
89
90impl Default for ArbiterDB {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96impl PartialEq for ArbiterDB {
100 fn eq(&self, _other: &Self) -> bool {
101 true
102 }
103}
104
105impl Database for ArbiterDB {
106 type Error = Infallible; fn basic(
109 &mut self,
110 address: revm::primitives::Address,
111 ) -> Result<Option<AccountInfo>, Self::Error> {
112 self.state.write().unwrap().basic(address)
113 }
114
115 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
116 self.state.write().unwrap().code_by_hash(code_hash)
117 }
118
119 fn storage(
120 &mut self,
121 address: revm::primitives::Address,
122 index: U256,
123 ) -> Result<U256, Self::Error> {
124 self.state.write().unwrap().storage(address, index)
125 }
126
127 fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
128 self.state.write().unwrap().block_hash(number)
129 }
130}
131
132impl DatabaseRef for ArbiterDB {
133 type Error = Infallible; fn basic_ref(
136 &self,
137 address: revm::primitives::Address,
138 ) -> Result<Option<AccountInfo>, Self::Error> {
139 self.state.read().unwrap().basic_ref(address)
140 }
141
142 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
143 self.state.read().unwrap().code_by_hash_ref(code_hash)
144 }
145
146 fn storage_ref(
147 &self,
148 address: revm::primitives::Address,
149 index: U256,
150 ) -> Result<U256, Self::Error> {
151 self.state.read().unwrap().storage_ref(address, index)
152 }
153
154 fn block_hash_ref(&self, number: U256) -> Result<B256, Self::Error> {
155 self.state.read().unwrap().block_hash_ref(number)
156 }
157}
158
159impl DatabaseCommit for ArbiterDB {
160 fn commit(
161 &mut self,
162 changes: revm_primitives::HashMap<revm::primitives::Address, revm::primitives::Account>,
163 ) {
164 self.state.write().unwrap().commit(changes)
165 }
166}
167
168#[derive(Clone, Debug, Serialize, Deserialize)]
170pub struct AnvilDump {
171 pub accounts: BTreeMap<Address, AccountRecord>,
174}
175
176#[derive(Clone, Debug, Serialize, Deserialize)]
178pub struct AccountRecord {
179 pub nonce: u64,
181 pub balance: U256,
183 pub code: Bytes,
185 pub storage: revm_primitives::HashMap<U256, U256>,
187}
188
189impl TryFrom<AnvilDump> for CacheDB<EmptyDB> {
190 type Error = <CacheDB<EmptyDB> as Database>::Error;
191
192 fn try_from(dump: AnvilDump) -> Result<Self, Self::Error> {
193 let mut db = CacheDB::default();
194
195 dump.accounts
196 .into_iter()
197 .try_for_each(|(address, account_record)| {
198 db.insert_account_info(
199 address,
200 AccountInfo {
201 balance: account_record.balance,
202 nonce: account_record.nonce,
203 code_hash: keccak256(account_record.code.as_ref()),
204 code: (!account_record.code.is_empty())
205 .then(|| Bytecode::new_raw(account_record.code)),
206 },
207 );
208 db.replace_account_storage(address, account_record.storage)
209 })?;
210
211 Ok(db)
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use revm_primitives::{address, bytes};
218
219 use super::*;
220
221 #[test]
222 fn read_write_to_file() {
223 let db = ArbiterDB::new();
224 db.write_to_file("test.json").unwrap();
225 let db = ArbiterDB::read_from_file("test.json").unwrap();
226 assert_eq!(db, ArbiterDB::new());
227 fs::remove_file("test.json").unwrap();
228 }
229
230 #[test]
231 fn load_anvil_dump_cachedb() {
232 const RAW_DUMP: &str = r#"
233 {
234 "accounts": {
235 "0x0000000000000000000000000000000000000000": {
236 "nonce": 1234,
237 "balance": "0xfacade",
238 "code": "0x",
239 "storage": {}
240 },
241 "0x0000000000000000000000000000000000000001": {
242 "nonce": 555,
243 "balance": "0xc0ffee",
244 "code": "0xbadc0de0",
245 "storage": {
246 "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000000000000000000000000000000000000000deAD",
247 "0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000000000000000000000000000000000000000babe"
248 }
249 }
250 }
251 }
252 "#;
253
254 let dump: AnvilDump = serde_json::from_str(RAW_DUMP).unwrap();
255 let mut db: CacheDB<EmptyDB> = dump.try_into().unwrap();
256
257 let account_a = db
258 .load_account(address!("0000000000000000000000000000000000000000"))
259 .unwrap();
260 assert_eq!(account_a.info.nonce, 1234);
261 assert_eq!(account_a.info.balance, U256::from(0xfacade));
262 assert_eq!(account_a.info.code, None);
263 assert_eq!(account_a.info.code_hash, keccak256([]));
264
265 let account_b = db
266 .load_account(address!("0000000000000000000000000000000000000001"))
267 .unwrap();
268 let b_bytecode = bytes!("badc0de0");
269 assert_eq!(account_b.info.nonce, 555);
270 assert_eq!(account_b.info.balance, U256::from(0xc0ffee));
271 assert_eq!(account_b.info.code_hash, keccak256(b_bytecode.as_ref()));
272 assert_eq!(account_b.info.code, Some(Bytecode::new_raw(b_bytecode)));
273 assert_eq!(
274 account_b.storage.get(&U256::ZERO),
275 Some(&U256::from(0xdead))
276 );
277 assert_eq!(
278 account_b.storage.get(&U256::from(1)),
279 Some(&U256::from(0xbabe))
280 );
281 }
282}