1use alloy_primitives::{keccak256, Address, B256, U256};
2use revm::Database;
3
4use crate::{
5 slot::{storage_key_map, storage_key_map_b256},
6 state_ops::{read_storage_at, write_storage_at, ARBOS_STATE_ADDRESS},
7};
8
9pub struct Storage<D> {
14 pub state: *mut revm::database::State<D>,
15 pub base_key: B256,
16 pub account: Address,
17}
18
19impl<D: Database> Storage<D> {
20 pub fn new(state: *mut revm::database::State<D>, base_key: B256) -> Self {
22 Self {
23 state,
24 base_key,
25 account: ARBOS_STATE_ADDRESS,
26 }
27 }
28
29 pub fn new_with_account(
31 state: *mut revm::database::State<D>,
32 base_key: B256,
33 account: Address,
34 ) -> Self {
35 Self {
36 state,
37 base_key,
38 account,
39 }
40 }
41
42 pub fn open_sub_storage(&self, sub_key: &[u8]) -> Storage<D> {
44 let base_slice: &[u8] = if self.base_key == B256::ZERO {
45 &[]
46 } else {
47 self.base_key.as_slice()
48 };
49 let mut combined = Vec::with_capacity(base_slice.len() + sub_key.len());
50 combined.extend_from_slice(base_slice);
51 combined.extend_from_slice(sub_key);
52 let new_key = keccak256(&combined);
53 Storage::new_with_account(self.state, new_key, self.account)
54 }
55
56 pub fn get_by_uint64(&self, offset: u64) -> Result<B256, ()> {
58 let slot = self.compute_slot(offset);
59 unsafe {
60 let state = &mut *self.state;
61 Ok(B256::from(read_storage_at(state, self.account, slot)))
62 }
63 }
64
65 pub fn set_by_uint64(&self, offset: u64, value: B256) -> Result<(), ()> {
67 let slot = self.compute_slot(offset);
68 let value_u256 = U256::from_be_bytes(value.0);
69 unsafe {
70 let state = &mut *self.state;
71 write_storage_at(state, self.account, slot, value_u256);
72 Ok(())
73 }
74 }
75
76 pub fn get_uint64_by_uint64(&self, offset: u64) -> Result<u64, ()> {
78 let slot = self.compute_slot(offset);
79 unsafe {
80 let state = &mut *self.state;
81 let value = read_storage_at(state, self.account, slot);
82 Ok(value.try_into().unwrap_or(0))
83 }
84 }
85
86 pub fn set_uint64_by_uint64(&self, offset: u64, value: u64) -> Result<(), ()> {
88 let slot = self.compute_slot(offset);
89 unsafe {
90 let state = &mut *self.state;
91 write_storage_at(state, self.account, slot, U256::from(value));
92 Ok(())
93 }
94 }
95
96 pub fn get(&self, key: B256) -> Result<B256, ()> {
98 let slot = self.compute_slot_for_key(key);
99 unsafe {
100 let state = &mut *self.state;
101 Ok(B256::from(read_storage_at(state, self.account, slot)))
102 }
103 }
104
105 pub fn set(&self, key: B256, value: B256) -> Result<(), ()> {
107 let slot = self.compute_slot_for_key(key);
108 let value_u256 = U256::from_be_bytes(value.0);
109 unsafe {
110 let state = &mut *self.state;
111 write_storage_at(state, self.account, slot, value_u256);
112 Ok(())
113 }
114 }
115
116 fn storage_key(&self) -> &[u8] {
117 if self.base_key == B256::ZERO {
118 &[]
119 } else {
120 self.base_key.as_slice()
121 }
122 }
123
124 fn compute_slot(&self, offset: u64) -> U256 {
125 storage_key_map(self.storage_key(), offset)
126 }
127
128 fn compute_slot_for_key(&self, key: B256) -> U256 {
129 storage_key_map_b256(self.storage_key(), &key.0)
130 }
131
132 pub fn new_slot(&self, offset: u64) -> U256 {
134 self.compute_slot(offset)
135 }
136
137 pub fn state_ptr(&self) -> *mut revm::database::State<D> {
139 self.state
140 }
141
142 pub fn base_key(&self) -> B256 {
144 self.base_key
145 }
146}
147
148impl<D> Clone for Storage<D> {
149 fn clone(&self) -> Self {
150 Self {
151 state: self.state,
152 base_key: self.base_key,
153 account: self.account,
154 }
155 }
156}
157
158unsafe impl<D: Send> Send for Storage<D> {}
161unsafe impl<D: Sync> Sync for Storage<D> {}