arbiter_core/database/
fork.rs

1//! This module contains the [`Fork`] struct which is used to store the data
2//! that will be loaded into an [`Environment`] and be used in `arbiter-core`.
3//! [`Fork`] contains a [`CacheDB`] and [`ContractMetadata`] so
4//! that the [`Environment`] can be initialized with a forked database and the
5//! end-user still has access to the relevant metadata.
6
7use std::{env, fs};
8
9use super::*;
10
11/// A [`ContractMetadata`] is used to store the metadata of a contract that will
12/// be loaded into a [`Fork`].
13#[derive(Clone, Debug, Deserialize, Serialize)]
14pub struct ContractMetadata {
15    /// The address of the contract.
16    pub address: eAddress,
17
18    /// The path to the contract artifacts.
19    pub artifacts_path: String,
20
21    /// The mappings that are part of the contract's storage.
22    pub mappings: HashMap<String, Vec<String>>,
23}
24
25/// A [`Fork`] is used to store the data that will be loaded into an
26/// [`Environment`] and be used in `arbiter-core`. It is a wrapper around a
27/// [`CacheDB`] and a [`HashMap`] of [`ContractMetadata`] so that the
28/// [`environment::Environment`] can be initialized with the data and the
29/// end-user still has access to the relevant metadata.
30#[derive(Clone, Debug)]
31pub struct Fork {
32    /// The [`CacheDB`] that will be loaded into the [`Environment`].
33    pub db: CacheDB<EmptyDB>,
34
35    /// The [`HashMap`] of [`ContractMetadata`] that will be used by the
36    /// end-user.
37    pub contracts_meta: HashMap<String, ContractMetadata>,
38    /// The [`HashMap`] of [`Address`] that will be used by the end-user.
39    pub eoa: HashMap<String, eAddress>,
40}
41
42impl Fork {
43    /// Creates a new [`Fork`] from serialized [`DiskData`] stored on disk.
44    pub fn from_disk(path: &str) -> Result<Self, ArbiterCoreError> {
45        // Read the file
46        let mut cwd = env::current_dir().unwrap();
47        cwd.push(path);
48        print!("Reading db from: {:?}", cwd);
49        let data = fs::read_to_string(cwd).unwrap();
50
51        // Deserialize the JSON data to your OutputData type
52        let disk_data: DiskData = serde_json::from_str(&data).unwrap();
53
54        // Create a CacheDB instance
55        let mut db = CacheDB::new(EmptyDB::default());
56
57        // Populate the CacheDB from the OutputData
58        for (address, (info, storage_map)) in disk_data.raw {
59            // Convert the string address back to its original type
60            let address = address.as_fixed_bytes().into(); // You'd need to define this
61
62            // Insert account info into the DB
63            db.insert_account_info(address, info);
64
65            // Insert storage data into the DB
66            for (key_str, value_str) in storage_map {
67                let key = U256::from_str_radix(&key_str, 10).unwrap();
68                let value = U256::from_str_radix(&value_str, 10).unwrap();
69
70                db.insert_account_storage(address, key, value).unwrap();
71            }
72        }
73
74        Ok(Self {
75            db,
76            contracts_meta: disk_data.meta,
77            eoa: disk_data.externally_owned_accounts,
78        })
79    }
80}
81
82impl From<Fork> for CacheDB<EmptyDB> {
83    fn from(val: Fork) -> Self {
84        val.db
85    }
86}
87
88type Storage = HashMap<String, String>;
89
90/// This is the data that will be written to and loaded from disk to generate a
91/// [`Fork`].
92#[derive(Debug, Serialize, Deserialize)]
93pub struct DiskData {
94    /// This is the metadata for the contracts that will be loaded into the
95    /// [`Fork`].
96    pub meta: HashMap<String, ContractMetadata>,
97
98    /// This is the raw data that will be loaded into the [`Fork`].
99    pub raw: HashMap<eAddress, (AccountInfo, Storage)>,
100
101    /// This is the eoa data that will be loaded into the [`Fork`].
102    pub externally_owned_accounts: HashMap<String, eAddress>,
103}