1use alloy_primitives::{Address, B256, U256};
2use revm::Database;
3
4use crate::{
5 slot::{derive_sub_key, 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 new_key = derive_sub_key(self.base_key, sub_key);
45 Storage::new_with_account(self.state, new_key, self.account)
46 }
47
48 pub fn open_sub_storage_with_key(&self, key: B256) -> Storage<D> {
50 Storage::new_with_account(self.state, key, self.account)
51 }
52
53 pub fn get_by_uint64(&self, offset: u64) -> Result<B256, ()> {
55 let slot = self.compute_slot(offset);
56 unsafe {
57 let state = &mut *self.state;
58 Ok(B256::from(read_storage_at(state, self.account, slot)))
59 }
60 }
61
62 pub fn set_by_uint64(&self, offset: u64, value: B256) -> Result<(), ()> {
64 let slot = self.compute_slot(offset);
65 let value_u256 = U256::from_be_bytes(value.0);
66 unsafe {
67 let state = &mut *self.state;
68 write_storage_at(state, self.account, slot, value_u256);
69 Ok(())
70 }
71 }
72
73 pub fn get_uint64_by_uint64(&self, offset: u64) -> Result<u64, ()> {
75 let slot = self.compute_slot(offset);
76 unsafe {
77 let state = &mut *self.state;
78 let value = read_storage_at(state, self.account, slot);
79 Ok(value.try_into().unwrap_or(0))
80 }
81 }
82
83 pub fn set_uint64_by_uint64(&self, offset: u64, value: u64) -> Result<(), ()> {
85 let slot = self.compute_slot(offset);
86 unsafe {
87 let state = &mut *self.state;
88 write_storage_at(state, self.account, slot, U256::from(value));
89 Ok(())
90 }
91 }
92
93 pub fn get(&self, key: B256) -> Result<B256, ()> {
95 let slot = self.compute_slot_for_key(key);
96 unsafe {
97 let state = &mut *self.state;
98 Ok(B256::from(read_storage_at(state, self.account, slot)))
99 }
100 }
101
102 pub fn set(&self, key: B256, value: B256) -> Result<(), ()> {
104 let slot = self.compute_slot_for_key(key);
105 let value_u256 = U256::from_be_bytes(value.0);
106 unsafe {
107 let state = &mut *self.state;
108 write_storage_at(state, self.account, slot, value_u256);
109 Ok(())
110 }
111 }
112
113 fn storage_key(&self) -> &[u8] {
114 if self.base_key == B256::ZERO {
115 &[]
116 } else {
117 self.base_key.as_slice()
118 }
119 }
120
121 fn compute_slot(&self, offset: u64) -> U256 {
122 storage_key_map(self.storage_key(), offset)
123 }
124
125 fn compute_slot_for_key(&self, key: B256) -> U256 {
126 storage_key_map_b256(self.storage_key(), &key.0)
127 }
128
129 pub fn new_slot(&self, offset: u64) -> U256 {
131 self.compute_slot(offset)
132 }
133
134 pub fn state_ptr(&self) -> *mut revm::database::State<D> {
136 self.state
137 }
138
139 pub fn base_key(&self) -> B256 {
141 self.base_key
142 }
143}
144
145impl<D> Clone for Storage<D> {
146 fn clone(&self) -> Self {
147 Self {
148 state: self.state,
149 base_key: self.base_key,
150 account: self.account,
151 }
152 }
153}
154
155unsafe impl<D: Send> Send for Storage<D> {}
158unsafe impl<D: Sync> Sync for Storage<D> {}