cfx_executor/state/state_object/
storage_entry.rs1use super::{State, Substate};
2use crate::{return_if, try_loaded};
3use cfx_parameters::internal_contract_addresses::{
4 SPONSOR_WHITELIST_CONTROL_CONTRACT_ADDRESS, SYSTEM_STORAGE_ADDRESS,
5};
6use cfx_statedb::Result as DbResult;
7use cfx_types::{
8 Address, AddressSpaceUtil, AddressWithSpace, BigEndianHash, Space, H256,
9 U256,
10};
11use primitives::StorageValue;
12
13impl State {
14 pub fn get_system_storage(&self, key: &[u8]) -> DbResult<U256> {
24 self.storage_at(&SYSTEM_STORAGE_ADDRESS.with_native_space(), key)
25 }
26
27 pub fn set_system_storage(
28 &mut self, key: Vec<u8>, value: U256,
29 ) -> DbResult<()> {
30 self.set_storage(
34 &SYSTEM_STORAGE_ADDRESS.with_native_space(),
35 key,
36 value,
37 Address::zero(),
38 &mut Substate::new(),
39 )
40 }
41
42 pub fn set_eip2935_storage(
43 &mut self, block_height: u64, block_hash: H256,
44 ) -> DbResult<()> {
45 use cfx_types::H160;
46 use hex_literal::hex;
47
48 pub const EIP2935_ADDRESS: AddressWithSpace = AddressWithSpace {
49 address: H160(hex!("0000F90827F1C53a10cb7A02335B175320002935")),
50 space: Space::Ethereum,
51 };
52 pub const HISTORY_SERVE_WINDOW: usize = 8191;
53
54 if self.has_no_code(&EIP2935_ADDRESS)? {
55 return Ok(());
56 }
57
58 let slot_index = U256::from(block_height % HISTORY_SERVE_WINDOW as u64);
59 let key: H256 = BigEndianHash::from_uint(&slot_index);
60
61 self.set_storage(
63 &EIP2935_ADDRESS,
64 key.0.to_vec(),
65 block_hash.into_uint(),
66 Address::zero(),
67 &mut Substate::new(),
68 )
69 }
70
71 #[inline]
72 pub fn storage_at(
73 &self, address: &AddressWithSpace, key: &[u8],
74 ) -> DbResult<U256> {
75 let acc = try_loaded!(self.read_account_lock(address));
76 acc.storage_at(&self.db, key)
77 }
78
79 #[inline]
80 pub fn origin_storage_at(
81 &self, address: &AddressWithSpace, key: &[u8],
82 ) -> DbResult<Option<U256>> {
83 let acc = try_loaded!(self.read_account_lock(address));
84 Ok(acc.origin_storage_at(key))
85 }
86
87 #[inline]
88 pub fn transient_storage_at(
89 &self, address: &AddressWithSpace, key: &[u8],
90 ) -> DbResult<U256> {
91 let acc = try_loaded!(self.read_account_lock(address));
92 Ok(acc.transient_storage_at(key))
93 }
94
95 #[inline]
96 pub fn storage_entry_at(
97 &self, address: &AddressWithSpace, key: &[u8],
98 ) -> DbResult<StorageValue> {
99 let acc = try_loaded!(self.read_account_lock(address));
100 acc.storage_entry_at(&self.db, key)
101 }
102
103 #[inline]
104 pub fn set_storage(
105 &mut self, address: &AddressWithSpace, key: Vec<u8>, value: U256,
106 owner: Address, substate: &mut Substate,
107 ) -> DbResult<()> {
108 let old_value = self.storage_entry_at(address, &key)?;
109 return_if!(
110 old_value.value == value && !Self::force_reset_owner(address)
111 );
112
113 self.write_account_lock(address)?
114 .set_storage(key, value, old_value, owner, substate)?;
115
116 Ok(())
117 }
118
119 #[inline]
120 pub fn transient_set_storage(
121 &mut self, address: &AddressWithSpace, key: Vec<u8>, value: U256,
122 ) -> DbResult<()> {
123 Ok(self
124 .write_account_lock(address)?
125 .transient_set_storage(key, value))
126 }
127
128 pub fn is_fresh_storage(
129 &self, address: &AddressWithSpace,
130 ) -> DbResult<bool> {
131 let acc = try_loaded!(self.read_account_lock(address));
132 Ok(acc.fresh_storage())
133 }
134
135 #[inline]
140 fn force_reset_owner(address: &AddressWithSpace) -> bool {
141 address.space == Space::Native
142 && address.address == SPONSOR_WHITELIST_CONTROL_CONTRACT_ADDRESS
143 }
144}
145
146#[cfg(test)]
147impl State {
148 pub fn checkpoint_storage_at(
150 &self, start_checkpoint_index: usize, address: &AddressWithSpace,
151 key: &Vec<u8>,
152 ) -> DbResult<Option<U256>> {
153 use super::super::checkpoints::CheckpointEntry::*;
154 use crate::state::{
155 checkpoints::CheckpointLayerTrait,
156 overlay_account::{
157 AccountEntry, AccountEntryWithWarm, OverlayAccount,
158 },
159 };
160 use cfx_statedb::StateDbExt;
161 use primitives::StorageKey;
162
163 #[derive(Debug)]
164 enum ReturnKind {
165 OriginalAt,
166 SameAsNext,
167 }
168
169 let kind = {
170 let checkpoints = self.checkpoints.read();
171
172 if start_checkpoint_index >= checkpoints.len() {
173 return Ok(None);
174 }
175
176 let mut kind = None;
177
178 let mut first_account: Option<&OverlayAccount> = None;
179 let mut checkpoints_iter =
182 checkpoints.elements_from_index(start_checkpoint_index);
183 for checkpoint in &mut checkpoints_iter {
184 match checkpoint.as_hash_map().get(address) {
185 Some(Recorded(AccountEntryWithWarm {
186 entry: AccountEntry::Cached(ref account, _),
187 ..
188 })) => {
189 first_account = Some(account);
190 break;
191 }
192 Some(Recorded(AccountEntryWithWarm {
193 entry: AccountEntry::DbAbsent,
194 ..
195 })) => {
196 return Ok(Some(U256::zero()));
197 }
198 Some(Unchanged) => {
199 kind = Some(ReturnKind::OriginalAt);
200 break;
201 }
202 None => {
204 kind = Some(ReturnKind::SameAsNext);
205 }
206 }
207 }
208
209 let require_further_iter = {
210 if first_account.is_none() {
211 false
212 } else {
213 match first_account
214 .unwrap()
215 .cached_value_at_checkpoint(key, start_checkpoint_index)
216 {
217 Some(Recorded(value)) => return Ok(Some(value)),
218 Some(Unchanged) => {
219 kind = Some(ReturnKind::OriginalAt);
220 false
221 }
222 None => true,
223 }
224 }
225 };
226
227 if require_further_iter {
228 assert!(first_account.is_some());
229 let mut account_changed = false;
230 let mut require_cache = true;
231 for checkpoint in checkpoints_iter {
232 if let Some(Recorded(AccountEntryWithWarm {
233 entry: AccountEntry::Cached(ref account, _),
234 ..
235 })) = checkpoint.as_hash_map().get(address)
236 {
237 if !first_account.unwrap().eq_write_cache(account) {
238 account_changed = true;
239 break;
240 }
241 match account.cached_value_at_checkpoint(
242 key,
243 start_checkpoint_index,
244 ) {
245 Some(Recorded(value)) => return Ok(Some(value)),
246 Some(Unchanged) => {
247 require_cache = false;
248 break;
249 }
250 None => {}
251 }
252 }
253 }
254
255 if !account_changed && require_cache {
258 let outer_cache = self.cache.read();
259 if let Some(AccountEntryWithWarm {
260 entry: AccountEntry::Cached(ref account, _),
261 ..
262 }) = outer_cache.get(address)
263 {
264 if !first_account.unwrap().eq_write_cache(account) {
265 account_changed = true;
266 }
267 match account.cached_value_at_checkpoint(
268 key,
269 start_checkpoint_index,
270 ) {
271 Some(Recorded(value)) => return Ok(Some(value)),
272 Some(Unchanged) => {
273 require_cache = false;
274 }
275 None => {}
276 }
277 }
278 }
279
280 if account_changed || require_cache {
282 let first_cached_value =
283 first_account.unwrap().cached_value_at_cache(key);
284 if let Some(value) = first_cached_value {
285 return Ok(Some(value));
286 }
287 }
288
289 if first_account.unwrap().is_newly_created_contract() {
291 return Ok(Some(U256::zero()));
292 } else {
293 kind = Some(ReturnKind::OriginalAt);
294 }
295 }
296
297 kind.expect("start_checkpoint_index is checked to be below checkpoints_len; for loop above must have been executed at least once; it will either early return, or set the kind value to Some; qed")
298 };
299
300 match kind {
301 ReturnKind::SameAsNext => Ok(Some(self.storage_at(address, key)?)),
302 ReturnKind::OriginalAt => {
303 match self.db.get::<StorageValue>(
304 StorageKey::new_storage_key(&address.address, key.as_ref())
305 .with_space(address.space),
306 )? {
307 Some(storage_value) => Ok(Some(storage_value.value)),
308 None => Ok(Some(U256::zero())),
309 }
310 }
311 }
312 }
313}