cfx_executor/state/overlay_account/
storage.rs

1use super::Substate;
2
3#[cfg(test)]
4use super::StorageLayout;
5use cfx_parameters::{
6    internal_contract_addresses::SYSTEM_STORAGE_ADDRESS,
7    staking::COLLATERAL_UNITS_PER_STORAGE_KEY,
8};
9use cfx_statedb::{Result as DbResult, StateDbExt, StateDbGeneric};
10use cfx_types::{Address, Space, U256};
11
12use primitives::{
13    storage::WriteCacheItem, SkipInputCheck, StorageKey, StorageKeyWithSpace,
14    StorageValue,
15};
16use std::collections::{hash_map::Entry::*, HashSet};
17
18use super::OverlayAccount;
19
20#[cfg(test)]
21use super::super::checkpoints::CheckpointEntry;
22
23impl OverlayAccount {
24    pub fn set_storage(
25        &mut self, key: Vec<u8>, value: U256, old_value: StorageValue,
26        owner: Address, substate: &mut Substate,
27    ) -> DbResult<()> {
28        // Refund the collateral of old value
29        if let Some(old_owner) = old_value.owner {
30            substate.record_storage_release(
31                &old_owner,
32                COLLATERAL_UNITS_PER_STORAGE_KEY,
33            );
34        }
35
36        // Settle the collateral of new value
37        let new_owner = if self.should_have_owner(&key) && !value.is_zero() {
38            substate.record_storage_occupy(
39                &owner,
40                COLLATERAL_UNITS_PER_STORAGE_KEY,
41            );
42            Some(owner)
43        } else {
44            None
45        };
46
47        self.insert_storage_write_cache(
48            key,
49            StorageValue {
50                owner: new_owner,
51                value,
52            },
53        );
54        Ok(())
55    }
56
57    #[cfg(test)]
58    pub fn set_storage_simple(&mut self, key: Vec<u8>, value: U256) {
59        self.insert_storage_write_cache(
60            key,
61            StorageValue { owner: None, value },
62        );
63    }
64
65    pub fn delete_storage_range(
66        &mut self, db_deletion_log: impl Iterator<Item = (Vec<u8>, Box<[u8]>)>,
67        key_prefix: &[u8], substate: &mut Substate,
68    ) -> DbResult<()> {
69        assert_eq!(self.address.space, Space::Native);
70        let delete_all = key_prefix.is_empty();
71
72        // Its strong count should be 1 and will not cause memory copy,
73        // unless in test and gas estimation.
74        assert!(self.storage_write_checkpoint.is_none());
75        let write_cache = &mut self.storage_write_cache.write();
76        let commit_cache = &mut self.storage_committed_cache.write();
77
78        let mut read_keys = HashSet::new();
79        // Must have no checkpoint in range deletion
80        for (k, item) in write_cache.iter_mut() {
81            let WriteCacheItem::Write(v) = item else {
82                read_keys.insert(k.clone());
83                continue;
84            };
85            if k.starts_with(key_prefix) && !v.value.is_zero() {
86                if let Some(old_owner) = v.owner {
87                    substate.record_storage_release(
88                        &old_owner,
89                        COLLATERAL_UNITS_PER_STORAGE_KEY,
90                    );
91                };
92                *v = StorageValue::default();
93            }
94        }
95
96        for k in read_keys {
97            write_cache.remove(&k);
98        }
99
100        for (k, v) in commit_cache.iter_mut() {
101            if write_cache.get(k).is_some() {
102                continue;
103            }
104            if k.starts_with(key_prefix) && !v.value.is_zero() {
105                if let Some(old_owner) = v.owner {
106                    substate.record_storage_release(
107                        &old_owner,
108                        COLLATERAL_UNITS_PER_STORAGE_KEY,
109                    );
110                };
111                write_cache.insert(
112                    k.clone(),
113                    WriteCacheItem::Write(StorageValue::default()),
114                );
115            }
116        }
117
118        let read_cache = self.storage_read_cache.read();
119        for (key, raw_value) in db_deletion_log
120            .into_iter()
121            .filter_map(|(k, v)| Some((decode_storage_key(&k)?, v)))
122        {
123            match write_cache.entry(key.clone()) {
124                Vacant(entry) => {
125                    // Propogate the db changes to cache
126                    // However, if all keys are removed, we don't update
127                    // cache since it will be cleared later.
128                    if !delete_all {
129                        entry.insert(WriteCacheItem::Write(
130                            StorageValue::default(),
131                        ));
132                    }
133
134                    if !delete_all && !read_cache.contains_key(&key) {
135                        // Backward compatible with an existing bug
136                        // When remove whitelist entries, if the entry does not
137                        // appear in the cache, the collateral is not refunded
138                        // correctly.
139                        continue;
140                    }
141                }
142                Occupied(_) => {
143                    // The key has been modified in cache, and the db holds
144                    // a deprecated version.
145                    // So we do nothing here.
146                    continue;
147                }
148            }
149            // Decode owner
150            let StorageValue { owner, value } =
151                rlp::decode::<StorageValue>(&raw_value)?;
152            assert!(!value.is_zero());
153            let owner = owner.unwrap_or(self.address.address);
154            substate.record_storage_release(
155                &owner,
156                COLLATERAL_UNITS_PER_STORAGE_KEY,
157            );
158        }
159        std::mem::drop(read_cache);
160
161        if delete_all {
162            write_cache.clear();
163            self.storage_read_cache.write().clear();
164            self.pending_db_clear = true;
165        }
166        Ok(())
167    }
168
169    fn cached_entry_at(&self, key: &[u8]) -> Option<StorageValue> {
170        if let Some(WriteCacheItem::Write(entry)) =
171            self.storage_write_cache.read().get(key)
172        {
173            return Some(*entry);
174        }
175        if let Some(entry) = self.storage_committed_cache.read().get(key) {
176            return Some(*entry);
177        }
178        if let Some(entry) = self.storage_read_cache.read().get(key) {
179            return Some(*entry);
180        }
181        None
182    }
183
184    #[cfg(test)]
185    pub fn cached_value_at_cache(&self, key: &[u8]) -> Option<U256> {
186        self.cached_entry_at(key).map(|e| e.value)
187    }
188
189    #[cfg(test)]
190    fn cached_entry_at_checkpoint(
191        &self, key: &[u8], state_checkpoint_id: usize,
192    ) -> Option<CheckpointEntry<StorageValue>> {
193        use CheckpointEntry::*;
194        if self.storage_write_checkpoint.is_none() {
195            return None;
196        }
197        if self
198            .storage_write_checkpoint
199            .as_ref()
200            .unwrap()
201            .read()
202            .get_state_cp_id()
203            < state_checkpoint_id
204        {
205            return None;
206        }
207        let res = self
208            .storage_write_checkpoint
209            .as_ref()
210            .unwrap()
211            .read()
212            .get(key)?;
213        Some(match res {
214            Unchanged => Unchanged,
215            Recorded(WriteCacheItem::Read) => Unchanged,
216            Recorded(WriteCacheItem::Write(v)) => Recorded(v),
217        })
218    }
219
220    #[cfg(test)]
221    pub fn cached_value_at_checkpoint(
222        &self, key: &[u8], state_checkpoint_id: usize,
223    ) -> Option<CheckpointEntry<U256>> {
224        self.cached_entry_at_checkpoint(key, state_checkpoint_id)
225            .map(|e: CheckpointEntry<StorageValue>| match e {
226                CheckpointEntry::Unchanged => CheckpointEntry::Unchanged,
227                CheckpointEntry::Recorded(sv) => {
228                    CheckpointEntry::Recorded(sv.value)
229                }
230            })
231    }
232
233    // If a contract is removed, and then some one transfer balance to it,
234    // `storage_at` will return incorrect value. But this case should never
235    // happens.
236    pub fn storage_at(
237        &self, db: &StateDbGeneric, key: &[u8],
238    ) -> DbResult<U256> {
239        Ok(self.storage_entry_at(db, key)?.value)
240    }
241
242    pub fn origin_storage_at(&self, key: &[u8]) -> Option<U256> {
243        if let Some(value) = self.storage_committed_cache.read().get(key) {
244            return Some(value.value);
245        }
246        if self.fresh_storage() && !self.storage_overrided {
247            return Some(U256::zero());
248        }
249        if let Some(value) = self.storage_read_cache.read().get(key) {
250            return Some(value.value);
251        }
252        if self.storage_overrided {
253            return Some(U256::zero());
254        }
255        None
256    }
257
258    // If a contract is removed, and then some one transfer balance to it,
259    // `storage_at` will return incorrect value. But this case should never
260    // happens.
261    pub fn storage_entry_at(
262        &self, db: &StateDbGeneric, key: &[u8],
263    ) -> DbResult<StorageValue> {
264        self.mark_storage_warm(key);
265        Ok(if let Some(value) = self.cached_entry_at(key) {
266            value
267        } else if self.fresh_storage() {
268            StorageValue::default()
269        } else {
270            self.get_and_cache_storage(db, key)?
271        })
272    }
273
274    pub fn transient_storage_at(&self, key: &[u8]) -> U256 {
275        self.transient_storage_cache
276            .read()
277            .get(key)
278            .cloned()
279            .unwrap_or_default()
280    }
281
282    fn get_and_cache_storage(
283        &self, db: &StateDbGeneric, key: &[u8],
284    ) -> DbResult<StorageValue> {
285        let storage_key =
286            StorageKey::new_storage_key(&self.address.address, key.as_ref())
287                .with_space(self.address.space);
288        let StorageValue { mut owner, value } =
289            db.get::<StorageValue>(storage_key)?.unwrap_or_default();
290        if !value.is_zero() && owner.is_none() && self.should_have_owner(key) {
291            owner = Some(self.address.address)
292        }
293        let storage_value = StorageValue { owner, value };
294        self.storage_read_cache
295            .write()
296            .insert(key.to_vec(), storage_value.clone());
297        Ok(storage_value)
298    }
299
300    pub fn transient_set_storage(&mut self, key: Vec<u8>, value: U256) {
301        self.insert_transient_write_cache(key, value);
302    }
303
304    pub(super) fn should_have_owner(&self, _key: &[u8]) -> bool {
305        self.address.space == Space::Native
306            && self.address.address != SYSTEM_STORAGE_ADDRESS
307    }
308
309    pub fn change_storage_value(
310        &mut self, db: &StateDbGeneric, key: &[u8], value: U256,
311    ) -> DbResult<()> {
312        let mut entry = self.storage_entry_at(db, key)?;
313        if !entry.value.is_zero() {
314            entry.value = value;
315            self.insert_storage_write_cache(key.to_vec(), entry);
316        } else {
317            warn!("Change storage value outside transaction fails: current value is zero, tx {:?}, key {:?}", self.address, key);
318        }
319        Ok(())
320    }
321
322    pub fn is_warm_storage_entry(&self, key: &[u8]) -> bool {
323        self.storage_write_cache.read().get(key).is_some()
324    }
325
326    #[cfg(test)]
327    pub fn storage_layout_change(&self) -> Option<&StorageLayout> {
328        self.storage_layout_change.as_ref()
329    }
330
331    #[cfg(test)]
332    pub fn set_storage_layout(&mut self, layout: StorageLayout) {
333        self.storage_layout_change = Some(layout);
334    }
335}
336
337fn decode_storage_key(key: &Vec<u8>) -> Option<Vec<u8>> {
338    if let StorageKeyWithSpace {
339        key: StorageKey::StorageKey { storage_key, .. },
340        ..
341    } = StorageKeyWithSpace::from_key_bytes::<SkipInputCheck>(&key[..])
342    {
343        Some(storage_key.to_vec())
344    } else {
345        // Should be unreachable
346        None
347    }
348}