tempo_precompiles/storage/
hashmap.rs

1use alloy::primitives::{Address, LogData, U256};
2use revm::state::{AccountInfo, Bytecode};
3use std::collections::HashMap;
4use tempo_chainspec::hardfork::TempoHardfork;
5
6use crate::{error::TempoPrecompileError, storage::PrecompileStorageProvider};
7
8pub struct HashMapStorageProvider {
9    internals: HashMap<(Address, U256), U256>,
10    transient: HashMap<(Address, U256), U256>,
11    accounts: HashMap<Address, AccountInfo>,
12    pub events: HashMap<Address, Vec<LogData>>,
13    chain_id: u64,
14    timestamp: U256,
15    beneficiary: Address,
16    spec: TempoHardfork,
17}
18
19impl HashMapStorageProvider {
20    pub fn new(chain_id: u64) -> Self {
21        Self::new_with_spec(chain_id, TempoHardfork::default())
22    }
23
24    pub fn new_with_spec(chain_id: u64, spec: TempoHardfork) -> Self {
25        Self {
26            internals: HashMap::new(),
27            transient: HashMap::new(),
28            accounts: HashMap::new(),
29            events: HashMap::new(),
30            chain_id,
31            #[expect(clippy::disallowed_methods)]
32            timestamp: U256::from(
33                std::time::SystemTime::now()
34                    .duration_since(std::time::UNIX_EPOCH)
35                    .unwrap()
36                    .as_secs(),
37            ),
38            beneficiary: Address::ZERO,
39            spec,
40        }
41    }
42
43    pub fn with_spec(mut self, spec: TempoHardfork) -> Self {
44        self.spec = spec;
45        self
46    }
47}
48
49impl PrecompileStorageProvider for HashMapStorageProvider {
50    fn chain_id(&self) -> u64 {
51        self.chain_id
52    }
53
54    fn timestamp(&self) -> U256 {
55        self.timestamp
56    }
57
58    fn beneficiary(&self) -> Address {
59        self.beneficiary
60    }
61
62    fn set_code(&mut self, address: Address, code: Bytecode) -> Result<(), TempoPrecompileError> {
63        let account = self.accounts.entry(address).or_default();
64        account.code_hash = code.hash_slow();
65        account.code = Some(code);
66        Ok(())
67    }
68
69    fn with_account_info(
70        &mut self,
71        address: Address,
72        f: &mut dyn FnMut(&AccountInfo),
73    ) -> Result<(), TempoPrecompileError> {
74        let account = self.accounts.entry(address).or_default();
75        f(&*account);
76        Ok(())
77    }
78
79    fn sstore(
80        &mut self,
81        address: Address,
82        key: U256,
83        value: U256,
84    ) -> Result<(), TempoPrecompileError> {
85        self.internals.insert((address, key), value);
86        Ok(())
87    }
88
89    fn tstore(
90        &mut self,
91        address: Address,
92        key: U256,
93        value: U256,
94    ) -> Result<(), TempoPrecompileError> {
95        self.transient.insert((address, key), value);
96        Ok(())
97    }
98
99    fn emit_event(&mut self, address: Address, event: LogData) -> Result<(), TempoPrecompileError> {
100        self.events.entry(address).or_default().push(event);
101        Ok(())
102    }
103
104    fn sload(&mut self, address: Address, key: U256) -> Result<U256, TempoPrecompileError> {
105        Ok(self
106            .internals
107            .get(&(address, key))
108            .copied()
109            .unwrap_or(U256::ZERO))
110    }
111
112    fn tload(&mut self, address: Address, key: U256) -> Result<U256, TempoPrecompileError> {
113        Ok(self
114            .transient
115            .get(&(address, key))
116            .copied()
117            .unwrap_or(U256::ZERO))
118    }
119
120    fn deduct_gas(&mut self, _gas: u64) -> Result<(), TempoPrecompileError> {
121        Ok(())
122    }
123
124    fn refund_gas(&mut self, _gas: i64) {
125        // No-op
126    }
127
128    fn gas_used(&self) -> u64 {
129        0
130    }
131
132    fn gas_refunded(&self) -> i64 {
133        0
134    }
135
136    fn spec(&self) -> TempoHardfork {
137        self.spec
138    }
139}
140
141#[cfg(any(test, feature = "test-utils"))]
142impl HashMapStorageProvider {
143    pub fn get_account_info(&self, address: Address) -> Option<&AccountInfo> {
144        self.accounts.get(&address)
145    }
146
147    pub fn get_events(&self, address: Address) -> &Vec<LogData> {
148        static EMPTY: Vec<LogData> = Vec::new();
149        self.events.get(&address).unwrap_or(&EMPTY)
150    }
151
152    pub fn set_nonce(&mut self, address: Address, nonce: u64) {
153        let account = self.accounts.entry(address).or_default();
154        account.nonce = nonce;
155    }
156
157    pub fn set_timestamp(&mut self, timestamp: U256) {
158        self.timestamp = timestamp;
159    }
160
161    pub fn set_beneficiary(&mut self, beneficiary: Address) {
162        self.beneficiary = beneficiary;
163    }
164
165    pub fn set_spec(&mut self, spec: TempoHardfork) {
166        self.spec = spec;
167    }
168
169    pub fn clear_transient(&mut self) {
170        self.transient.clear();
171    }
172}