cfx_statedb/
lib.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5#[macro_use]
6extern crate cfx_util_macros;
7#[macro_use]
8extern crate log;
9
10pub mod global_params;
11#[cfg(feature = "testonly_code")]
12mod in_memory_storage;
13mod statedb_ext;
14use cfx_types::H256;
15use primitives::StorageValue;
16
17use cfx_db_errors::statedb as error;
18
19#[cfg(test)]
20mod tests;
21
22pub use self::{
23    error::{Error, Result},
24    impls::StateDb as StateDbGeneric,
25    statedb_ext::StateDbExt,
26};
27pub use cfx_storage::utils::access_mode;
28pub type StateDb = StateDbGeneric;
29
30// Put StateDb in mod to make sure that methods from statedb_ext don't access
31// its fields directly.
32mod impls {
33    type Key = Vec<u8>;
34    type Value = Option<Arc<[u8]>>;
35
36    // Use BTreeMap so that we can delete ranges efficiently
37    // see `delete_all`
38    type AccessedEntries = BTreeMap<Key, EntryValue>;
39
40    // Use generic type for better test-ability.
41    pub struct StateDb {
42        /// Contains the original storage key values for all loaded and
43        /// modified key values.
44        accessed_entries: RwLock<AccessedEntries>,
45
46        /// The underlying storage, The storage is updated only upon fn
47        /// commit().
48        storage: Box<dyn StorageStateTrait>,
49    }
50
51    impl StateDb {
52        pub fn new(storage: Box<dyn StorageStateTrait>) -> Self {
53            StateDb {
54                accessed_entries: Default::default(),
55                storage,
56            }
57        }
58
59        #[cfg(feature = "testonly_code")]
60        pub fn new_for_unit_test() -> Self {
61            use self::in_memory_storage::InmemoryStorage;
62
63            Self::new(Box::new(InmemoryStorage::default()))
64        }
65
66        #[cfg(feature = "testonly_code")]
67        pub fn new_for_unit_test_with_epoch(epoch_id: &EpochId) -> Self {
68            use self::in_memory_storage::InmemoryStorage;
69
70            Self::new(Box::new(
71                InmemoryStorage::from_epoch_id(epoch_id).unwrap(),
72            ))
73        }
74
75        #[cfg(test)]
76        pub fn get_from_cache(&self, key: &Vec<u8>) -> Value {
77            self.accessed_entries
78                .read()
79                .get(key)
80                .and_then(|v| v.current_value.clone())
81        }
82
83        /// Update the accessed_entries while getting the value.
84        pub(crate) fn get_raw(
85            &self, key: StorageKeyWithSpace,
86        ) -> Result<Option<Arc<[u8]>>> {
87            let key_bytes = key.to_key_bytes();
88            let r;
89            let accessed_entries_read_guard = self.accessed_entries.read();
90            if let Some(v) = accessed_entries_read_guard.get(&key_bytes) {
91                r = v.current_value.clone();
92            } else {
93                drop(accessed_entries_read_guard);
94                let mut accessed_entries = self.accessed_entries.write();
95                let entry = accessed_entries.entry(key_bytes);
96                if let Occupied(o) = &entry {
97                    r = o.get().current_value.clone();
98                } else {
99                    r = self.storage.get(key)?.map(Into::into);
100                    entry.or_insert(EntryValue::new(r.clone()));
101                };
102            };
103            trace!("get_raw key={:?}, value={:?}", key, r);
104            Ok(r)
105        }
106
107        #[cfg(feature = "testonly_code")]
108        pub fn get_raw_test(
109            &self, key: StorageKeyWithSpace,
110        ) -> Result<Option<Arc<[u8]>>> {
111            self.get_raw(key)
112        }
113
114        /// Set the value under `key` to `value` in `accessed_entries`.
115        /// This method will read from db if `key` is not present.
116        /// This method will also update the latest checkpoint if necessary.
117        fn modify_single_value(
118            &mut self, key: StorageKeyWithSpace, value: Option<Box<[u8]>>,
119        ) -> Result<()> {
120            let key_bytes = key.to_key_bytes();
121            let mut entry =
122                self.accessed_entries.get_mut().entry(key_bytes.clone());
123            let value = value.map(Into::into);
124
125            match &mut entry {
126                Occupied(o) => {
127                    // set `current_value` to `value` and keep the old value
128                    Some(std::mem::replace(
129                        &mut o.get_mut().current_value,
130                        value,
131                    ))
132                }
133
134                // Vacant
135                &mut Vacant(_) => {
136                    let original_value = self.storage.get(key)?.map(Into::into);
137
138                    entry.or_insert(EntryValue::new_modified(
139                        original_value,
140                        value,
141                    ));
142
143                    None
144                }
145            };
146
147            Ok(())
148        }
149
150        pub(crate) fn set_raw(
151            &mut self, key: StorageKeyWithSpace, value: Box<[u8]>,
152            debug_record: Option<&mut ComputeEpochDebugRecord>,
153        ) -> Result<()> {
154            if let Some(record) = debug_record {
155                record.state_ops.push(StateOp::StorageLevelOp {
156                    op_name: "set".into(),
157                    key: key.to_key_bytes(),
158                    maybe_value: Some(value.clone().into()),
159                })
160            }
161
162            self.modify_single_value(key, Some(value))
163        }
164
165        pub fn delete(
166            &mut self, key: StorageKeyWithSpace,
167            debug_record: Option<&mut ComputeEpochDebugRecord>,
168        ) -> Result<()> {
169            if let Some(record) = debug_record {
170                record.state_ops.push(StateOp::StorageLevelOp {
171                    op_name: "delete".into(),
172                    key: key.to_key_bytes(),
173                    maybe_value: None,
174                })
175            }
176
177            self.modify_single_value(key, None)
178        }
179
180        pub fn read_all(
181            &mut self, key_prefix: StorageKeyWithSpace,
182            debug_record: Option<&mut ComputeEpochDebugRecord>,
183        ) -> Result<Vec<MptKeyValue>> {
184            self.delete_all::<access_mode::Read>(key_prefix, debug_record)
185        }
186
187        pub fn read_all_with_callback(
188            &mut self, access_key_prefix: StorageKeyWithSpace,
189            callback: &mut dyn FnMut(MptKeyValue), only_account_key: bool,
190        ) -> Result<()> {
191            self.storage
192                .read_all_with_callback(
193                    access_key_prefix,
194                    callback,
195                    only_account_key,
196                )
197                .map_err(|err| err.into())
198        }
199
200        pub fn delete_all<AM: access_mode::AccessMode>(
201            &mut self, key_prefix: StorageKeyWithSpace,
202            debug_record: Option<&mut ComputeEpochDebugRecord>,
203        ) -> Result<Vec<MptKeyValue>> {
204            let key_bytes = key_prefix.to_key_bytes();
205            if let Some(record) = debug_record {
206                record.state_ops.push(StateOp::StorageLevelOp {
207                    op_name: if AM::READ_ONLY {
208                        "iterate"
209                    } else {
210                        "delete_all"
211                    }
212                    .into(),
213                    key: key_bytes.clone(),
214                    maybe_value: None,
215                })
216            }
217            let accessed_entries = self.accessed_entries.get_mut();
218            // First, all new keys in the subtree shall be deleted.
219            let iter_range_upper_bound =
220                to_key_prefix_iter_upper_bound(&key_bytes);
221            let iter_range = match &iter_range_upper_bound {
222                None => accessed_entries
223                    .range_mut::<[u8], _>((Included(&*key_bytes), Unbounded)),
224
225                // delete_all will not delete any key which doesn't exist before
226                // the operation. Therefore we don't need to
227                // check the accessed_entries prior to the
228                // operation.
229                Some(upper_bound) => accessed_entries.range_mut::<[u8], _>((
230                    Included(&*key_bytes),
231                    Excluded(&**upper_bound),
232                )),
233            };
234            let mut deleted_kvs = vec![];
235            for (k, v) in iter_range {
236                if v.current_value != None {
237                    deleted_kvs.push((
238                        k.clone(),
239                        (&**v.current_value.as_ref().unwrap()).into(),
240                    ));
241                    if !AM::READ_ONLY {
242                        v.current_value = None;
243                    }
244                }
245            }
246            // Then, remove all un-modified existing keys.
247            let deleted = self.storage.read_all(key_prefix)?;
248            // We must update the accessed_entries.
249            if let Some(storage_deleted) = &deleted {
250                for (k, v) in storage_deleted {
251                    let entry = accessed_entries.entry(k.clone());
252                    let was_vacant = if let Occupied(_) = &entry {
253                        // Nothing to do for existing entry, because we have
254                        // already scanned through accessed_entries.
255                        false
256                    } else {
257                        true
258                    };
259                    if was_vacant {
260                        deleted_kvs.push((k.clone(), v.clone()));
261                        if !AM::READ_ONLY {
262                            entry.or_insert(EntryValue::new_modified(
263                                Some((&**v).into()),
264                                None,
265                            ));
266                        }
267                    }
268                }
269            }
270
271            Ok(deleted_kvs)
272        }
273
274        pub fn get_account_storage_entries(
275            &mut self, address: &AddressWithSpace,
276            debug_record: Option<&mut ComputeEpochDebugRecord>,
277        ) -> Result<BTreeMap<cfx_types::StorageKey, cfx_types::StorageValue>>
278        {
279            let mut storage = BTreeMap::new();
280
281            let storage_prefix =
282                StorageKey::new_storage_root_key(&address.address)
283                    .with_space(address.space);
284
285            let kv_pairs = self.read_all(storage_prefix, debug_record)?;
286            for (key, value) in kv_pairs {
287                let storage_key_with_space =
288                    StorageKeyWithSpace::from_key_bytes::<SkipInputCheck>(&key);
289                if let StorageKey::StorageKey {
290                    address_bytes: _,
291                    storage_key,
292                } = storage_key_with_space.key
293                {
294                    let h256_storage_key = H256::from_slice(storage_key);
295                    let storage_value_with_owner: StorageValue =
296                        rlp::decode(&value)?;
297                    storage.insert(
298                        h256_storage_key,
299                        storage_value_with_owner.value,
300                    );
301                } else {
302                    trace!("Not an storage key: {:?}", storage_key_with_space);
303                    continue;
304                }
305            }
306
307            Ok(storage)
308        }
309
310        /// Load the storage layout for state commits.
311        /// Modification to storage layout is the same as modification of
312        /// any other key-values. But as required by MPT structure we
313        /// must commit storage layout for any storage changes under the
314        /// same account. To load the storage layout, we first load from
315        /// the local changes (i.e. accessed_entries), then from the
316        /// storage if it's untouched.
317        fn load_storage_layout(
318            storage_layouts_to_rewrite: &mut HashMap<
319                (Vec<u8>, Space),
320                StorageLayout,
321            >,
322            accept_account_deletion: bool, address: &[u8], space: Space,
323            storage: &dyn StorageStateTrait,
324            accessed_entries: &AccessedEntries,
325        ) -> Result<()> {
326            if storage_layouts_to_rewrite
327                .contains_key(&(address.to_vec(), space))
328            {
329                return Ok(());
330            }
331            let storage_layout_key =
332                StorageKey::StorageRootKey(address).with_space(space);
333            let current_storage_layout = match accessed_entries
334                .get(&storage_layout_key.to_key_bytes())
335            {
336                Some(entry) => match &entry.current_value {
337                    // We don't rewrite storage layout for account to
338                    // delete.
339                    None => {
340                        if accept_account_deletion {
341                            return Ok(());
342                        } else {
343                            // This is defensive checking, against certain
344                            // cases when we are not deleting the account
345                            // for sure.
346                            bail!(Error::IncompleteDatabase(
347                                Address::from_slice(address)
348                            ));
349                        }
350                    }
351
352                    Some(value_ref) => StorageLayout::from_bytes(&*value_ref)?,
353                },
354                None => match storage.get(storage_layout_key)? {
355                    // A new account must set StorageLayout before accessing
356                    // the storage.
357                    None => bail!(Error::IncompleteDatabase(
358                        Address::from_slice(address)
359                    )),
360                    Some(raw) => StorageLayout::from_bytes(raw.as_ref())?,
361                },
362            };
363            storage_layouts_to_rewrite
364                .insert((address.into(), space), current_storage_layout);
365
366            Ok(())
367        }
368
369        pub fn set_storage_layout(
370            &mut self, address: &AddressWithSpace,
371            storage_layout: StorageLayout,
372            debug_record: Option<&mut ComputeEpochDebugRecord>,
373        ) -> Result<()> {
374            self.set_raw(
375                StorageKey::new_storage_root_key(&address.address)
376                    .with_space(address.space),
377                storage_layout.to_bytes().into_boxed_slice(),
378                debug_record,
379            )
380        }
381
382        /// storage_layout is special, because it must always present if there
383        /// is any storage value changed.
384        fn commit_storage_layout(
385            &mut self, address: &[u8], space: Space, layout: &StorageLayout,
386            debug_record: Option<&mut ComputeEpochDebugRecord>,
387        ) -> Result<()> {
388            let key = StorageKey::StorageRootKey(address).with_space(space);
389            let value = layout.to_bytes().into_boxed_slice();
390            if let Some(record) = debug_record {
391                record.state_ops.push(StateOp::StorageLevelOp {
392                    op_name: "commit_storage_layout".into(),
393                    key: key.to_key_bytes(),
394                    maybe_value: Some(value.clone().into()),
395                })
396            };
397            Ok(self.storage.set(key, value)?)
398        }
399
400        fn apply_changes_to_storage(
401            &mut self, mut debug_record: Option<&mut ComputeEpochDebugRecord>,
402        ) -> Result<()> {
403            let mut storage_layouts_to_rewrite = Default::default();
404            let accessed_entries = &*self.accessed_entries.get_mut();
405            // First of all, apply all changes to the underlying storage.
406            for (k, v) in accessed_entries {
407                if !v.is_modified() {
408                    continue;
409                }
410
411                let storage_key =
412                    StorageKeyWithSpace::from_key_bytes::<SkipInputCheck>(k);
413                match &v.current_value {
414                    Some(v) => {
415                        self.storage.set(storage_key, (&**v).into())?;
416                    }
417                    None => {
418                        self.storage.delete(storage_key)?;
419                    }
420                }
421
422                match &storage_key.key {
423                    StorageKey::StorageKey { address_bytes, .. } => {
424                        Self::load_storage_layout(
425                            &mut storage_layouts_to_rewrite,
426                            /* accept_account_deletion = */
427                            v.current_value.is_none(),
428                            address_bytes,
429                            storage_key.space,
430                            self.storage.as_ref(),
431                            &accessed_entries,
432                        )?;
433                    }
434                    StorageKey::AccountKey(address_bytes)
435                        if (address_bytes.is_builtin_address()
436                            || address_bytes.is_contract_address()
437                            || storage_key.space == Space::Ethereum)
438                            && v.original_value.is_none() =>
439                    {
440                        let result = Self::load_storage_layout(
441                            &mut storage_layouts_to_rewrite,
442                            /* accept_account_deletion = */ false,
443                            address_bytes,
444                            storage_key.space,
445                            self.storage.as_ref(),
446                            &accessed_entries,
447                        );
448                        if result.is_err() {
449                            debug!(
450                                "Contract address {:?} (space {:?}) is created without storage_layout. \
451                                It's probably created by a balance transfer.",
452                                Address::from_slice(address_bytes), storage_key.space
453                            );
454                        }
455                    }
456                    StorageKey::CodeKey { address_bytes, .. }
457                        if v.original_value.is_none() =>
458                    {
459                        Self::load_storage_layout(
460                            &mut storage_layouts_to_rewrite,
461                            /* accept_account_deletion = */ false,
462                            address_bytes,
463                            storage_key.space,
464                            self.storage.as_ref(),
465                            &accessed_entries,
466                        )?;
467                    }
468                    _ => {}
469                }
470            }
471            // Set storage layout for contracts with storage modification or
472            // contracts with storage_layout initialization or modification.
473            for ((k, space), v) in &storage_layouts_to_rewrite {
474                self.commit_storage_layout(
475                    k,
476                    *space,
477                    v,
478                    debug_record.as_deref_mut(),
479                )?;
480            }
481            // Mark all modification applied.
482            self.accessed_entries = Default::default();
483            Ok(())
484        }
485
486        /// This method is only used for genesis block because state root is
487        /// required to compute genesis epoch_id. For other blocks there are
488        /// deferred execution so the state root computation is merged inside
489        /// commit method.
490        pub fn compute_state_root(
491            &mut self, debug_record: Option<&mut ComputeEpochDebugRecord>,
492        ) -> Result<StateRootWithAuxInfo> {
493            self.apply_changes_to_storage(debug_record)?;
494            Ok(self.storage.compute_state_root()?)
495        }
496
497        pub fn commit(
498            &mut self, epoch_id: EpochId,
499            mut debug_record: Option<&mut ComputeEpochDebugRecord>,
500        ) -> Result<StateRootWithAuxInfo> {
501            self.apply_changes_to_storage(debug_record.as_deref_mut())?;
502
503            let result = match self.storage.get_state_root() {
504                Ok(r) => r,
505                Err(_) => self.compute_state_root(debug_record)?,
506            };
507
508            self.storage.commit(epoch_id)?;
509
510            Ok(result)
511        }
512    }
513
514    struct EntryValue {
515        original_value: Value,
516        current_value: Value,
517    }
518
519    impl EntryValue {
520        fn new(value: Value) -> Self {
521            let value_clone = value.clone();
522            Self {
523                original_value: value,
524                current_value: value_clone,
525            }
526        }
527
528        fn new_modified(original_value: Value, current_value: Value) -> Self {
529            Self {
530                original_value,
531                current_value,
532            }
533        }
534
535        fn is_modified(&self) -> bool {
536            self.original_value.ne(&self.current_value)
537        }
538    }
539
540    use super::*;
541    use cfx_internal_common::{
542        debug::{ComputeEpochDebugRecord, StateOp},
543        StateRootWithAuxInfo,
544    };
545    use cfx_storage::{
546        utils::{access_mode, to_key_prefix_iter_upper_bound},
547        MptKeyValue, StorageStateTrait,
548    };
549    use cfx_types::{
550        address_util::AddressUtil, Address, AddressWithSpace, Space,
551    };
552    use hashbrown::HashMap;
553    use parking_lot::RwLock;
554    use primitives::{
555        EpochId, SkipInputCheck, StorageKey, StorageKeyWithSpace, StorageLayout,
556    };
557    use std::{
558        collections::{
559            btree_map::Entry::{Occupied, Vacant},
560            BTreeMap,
561        },
562        ops::Bound::{Excluded, Included, Unbounded},
563        sync::Arc,
564    };
565}