cfx_executor/state/state_object/
storage_entry.rs

1use 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    // System Storage shares the cache and checkpoint mechanisms with
15    // `OverlayAccount` storage entries. Similar to global statistic
16    // variables, it represents global variables of the blockchain system,
17    // operating without an owner during execution. As such, system storage
18    // doesn't generate collateral, nor is it recorded in receipts.
19
20    // While its access performance is slightly lower than global statistics due
21    // to the cache and checkpoint mechanism, it benefits code maintainability.
22    // New global variables are preferentially stored in system storage.
23    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        // The system storage contract does not have owner, and thus does not
31        // require actual storage owner and substate which records ownership
32        // changes.
33        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        // The espace does not have owner.
62        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    // In most cases, the ownership does not change if the set storage operation
136    // does not change the value. However, some implementations do not follow
137    // this rule. So we must deal with these special cases for backward
138    // compatible.
139    #[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    /// Get the value of storage at a specific checkpoint.
149    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            // outer checkpoints with state_checkpoint_id >=
180            // start_checkpoint_index
181            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                    // This key does not have a checkpoint entry.
203                    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                // in outer cache, the account may have a valid inner checkpoint
256                // if not breaked by further iter of outer checkpoints
257                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                // try to use cache
281                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                // do not use cache || fail to use cache
290                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}