// This file is part of Substrate. // Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Trie-based state machine backend. use crate::{ trie_backend_essence::{TrieBackendEssence, TrieBackendStorage}, Backend, StorageKey, StorageValue, }; use codec::Codec; use hash_db::Hasher; use sp_core::storage::{ChildInfo, StateVersion}; use sp_std::vec::Vec; /// Patricia trie-based backend. Transaction type is an overlay of changes to commit. pub struct TrieBackend, H: Hasher> { pub(crate) essence: TrieBackendEssence, } impl, H: Hasher> TrieBackend where H::Out: Codec, { /// Create new trie-based backend. pub fn new(storage: S, root: H::Out) -> Self { TrieBackend { essence: TrieBackendEssence::new(storage, root) } } /// Get backend essence reference. pub fn essence(&self) -> &TrieBackendEssence { &self.essence } /// Get backend storage reference. pub fn backend_storage(&self) -> &S { self.essence.backend_storage() } /// Get trie root. pub fn root(&self) -> &H::Out { self.essence.root() } /// Consumes self and returns underlying storage. pub fn into_storage(self) -> S { self.essence.into_storage() } } impl, H: Hasher> sp_std::fmt::Debug for TrieBackend { fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result { write!(f, "TrieBackend") } } impl, H: Hasher> Backend for TrieBackend where H::Out: Ord + Codec, { type Error = crate::DefaultError; type Transaction = S::Overlay; type TrieBackendStorage = S; fn storage(&self, key: &[u8]) -> Result, Self::Error> { self.essence.storage(key) } fn child_storage( &self, child_info: &ChildInfo, key: &[u8], ) -> Result, Self::Error> { self.essence.child_storage(child_info, key) } fn next_storage_key(&self, key: &[u8]) -> Result, Self::Error> { self.essence.next_storage_key(key) } fn next_child_storage_key( &self, child_info: &ChildInfo, key: &[u8], ) -> Result, Self::Error> { self.essence.next_child_storage_key(child_info, key) } fn for_keys_with_prefix(&self, prefix: &[u8], f: F) { self.essence.for_keys_with_prefix(prefix, f) } fn for_key_values_with_prefix(&self, prefix: &[u8], f: F) { self.essence.for_key_values_with_prefix(prefix, f) } fn apply_to_key_values_while, Vec) -> bool>( &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, start_at: Option<&[u8]>, f: F, allow_missing: bool, ) -> Result { self.essence .apply_to_key_values_while(child_info, prefix, start_at, f, allow_missing) } fn apply_to_keys_while bool>( &self, child_info: Option<&ChildInfo>, prefix: Option<&[u8]>, f: F, ) { self.essence.apply_to_keys_while(child_info, prefix, f) } fn for_child_keys_with_prefix( &self, child_info: &ChildInfo, prefix: &[u8], f: F, ) { self.essence.for_child_keys_with_prefix(child_info, prefix, f) } fn pairs(&self) -> Vec<(StorageKey, StorageValue)> { self.essence.pairs() } fn keys(&self, prefix: &[u8]) -> Vec { self.essence.keys(prefix) } fn storage_root<'a>( &self, delta: impl Iterator)>, state_version: StateVersion, ) -> (H::Out, Self::Transaction) where H::Out: Ord, { self.essence.storage_root(delta, state_version) } fn child_storage_root<'a>( &self, child_info: &ChildInfo, delta: impl Iterator)>, state_version: StateVersion, ) -> (H::Out, bool, Self::Transaction) where H::Out: Ord, { self.essence.child_storage_root(child_info, delta, state_version) } fn as_trie_backend(&self) -> Option<&TrieBackend> { Some(self) } fn register_overlay_stats(&self, _stats: &crate::stats::StateMachineStats) {} fn usage_info(&self) -> crate::UsageInfo { crate::UsageInfo::empty() } fn wipe(&self) -> Result<(), Self::Error> { Ok(()) } } #[cfg(test)] pub mod tests { use super::*; use codec::Encode; use sp_core::H256; use sp_runtime::traits::BlakeTwo256; use sp_trie::{ trie_types::{TrieDBMutV0, TrieDBMutV1}, KeySpacedDBMut, PrefixedMemoryDB, TrieMut, }; use std::{collections::HashSet, iter}; const CHILD_KEY_1: &[u8] = b"sub1"; pub(crate) fn test_db(state_version: StateVersion) -> (PrefixedMemoryDB, H256) { let child_info = ChildInfo::new_default(CHILD_KEY_1); let mut root = H256::default(); let mut mdb = PrefixedMemoryDB::::default(); { let mut mdb = KeySpacedDBMut::new(&mut mdb, child_info.keyspace()); match state_version { StateVersion::V0 => { let mut trie = TrieDBMutV0::new(&mut mdb, &mut root); trie.insert(b"value3", &[142; 33]).expect("insert failed"); trie.insert(b"value4", &[124; 33]).expect("insert failed"); }, StateVersion::V1 => { let mut trie = TrieDBMutV1::new(&mut mdb, &mut root); trie.insert(b"value3", &[142; 33]).expect("insert failed"); trie.insert(b"value4", &[124; 33]).expect("insert failed"); }, }; }; { let mut sub_root = Vec::new(); root.encode_to(&mut sub_root); fn build( mut trie: sp_trie::TrieDBMut, child_info: &ChildInfo, sub_root: &[u8], ) { trie.insert(child_info.prefixed_storage_key().as_slice(), sub_root) .expect("insert failed"); trie.insert(b"key", b"value").expect("insert failed"); trie.insert(b"value1", &[42]).expect("insert failed"); trie.insert(b"value2", &[24]).expect("insert failed"); trie.insert(b":code", b"return 42").expect("insert failed"); for i in 128u8..255u8 { trie.insert(&[i], &[i]).unwrap(); } } match state_version { StateVersion::V0 => { let trie = TrieDBMutV0::new(&mut mdb, &mut root); build(trie, &child_info, &sub_root[..]) }, StateVersion::V1 => { let trie = TrieDBMutV1::new(&mut mdb, &mut root); build(trie, &child_info, &sub_root[..]) }, }; } (mdb, root) } pub(crate) fn test_trie( hashed_value: StateVersion, ) -> TrieBackend, BlakeTwo256> { let (mdb, root) = test_db(hashed_value); TrieBackend::new(mdb, root) } #[test] fn read_from_storage_returns_some() { read_from_storage_returns_some_inner(StateVersion::V0); read_from_storage_returns_some_inner(StateVersion::V1); } fn read_from_storage_returns_some_inner(state_version: StateVersion) { assert_eq!(test_trie(state_version).storage(b"key").unwrap(), Some(b"value".to_vec())); } #[test] fn read_from_child_storage_returns_some() { read_from_child_storage_returns_some_inner(StateVersion::V0); read_from_child_storage_returns_some_inner(StateVersion::V1); } fn read_from_child_storage_returns_some_inner(state_version: StateVersion) { let test_trie = test_trie(state_version); assert_eq!( test_trie .child_storage(&ChildInfo::new_default(CHILD_KEY_1), b"value3") .unwrap(), Some(vec![142u8; 33]), ); // Change cache entry to check that caching is active. test_trie .essence .cache .write() .child_root .entry(b"sub1".to_vec()) .and_modify(|value| { *value = None; }); assert_eq!( test_trie .child_storage(&ChildInfo::new_default(CHILD_KEY_1), b"value3") .unwrap(), None, ); } #[test] fn read_from_storage_returns_none() { read_from_storage_returns_none_inner(StateVersion::V0); read_from_storage_returns_none_inner(StateVersion::V1); } fn read_from_storage_returns_none_inner(state_version: StateVersion) { assert_eq!(test_trie(state_version).storage(b"non-existing-key").unwrap(), None); } #[test] fn pairs_are_not_empty_on_non_empty_storage() { pairs_are_not_empty_on_non_empty_storage_inner(StateVersion::V0); pairs_are_not_empty_on_non_empty_storage_inner(StateVersion::V1); } fn pairs_are_not_empty_on_non_empty_storage_inner(state_version: StateVersion) { assert!(!test_trie(state_version).pairs().is_empty()); } #[test] fn pairs_are_empty_on_empty_storage() { assert!(TrieBackend::, BlakeTwo256>::new( PrefixedMemoryDB::default(), Default::default(), ) .pairs() .is_empty()); } #[test] fn storage_root_is_non_default() { storage_root_is_non_default_inner(StateVersion::V0); storage_root_is_non_default_inner(StateVersion::V1); } fn storage_root_is_non_default_inner(state_version: StateVersion) { assert!( test_trie(state_version).storage_root(iter::empty(), state_version).0 != H256::repeat_byte(0) ); } #[test] fn storage_root_transaction_is_non_empty() { storage_root_transaction_is_non_empty_inner(StateVersion::V0); storage_root_transaction_is_non_empty_inner(StateVersion::V1); } fn storage_root_transaction_is_non_empty_inner(state_version: StateVersion) { let (new_root, mut tx) = test_trie(state_version) .storage_root(iter::once((&b"new-key"[..], Some(&b"new-value"[..]))), state_version); assert!(!tx.drain().is_empty()); assert!(new_root != test_trie(state_version).storage_root(iter::empty(), state_version).0); } #[test] fn prefix_walking_works() { prefix_walking_works_inner(StateVersion::V0); prefix_walking_works_inner(StateVersion::V1); } fn prefix_walking_works_inner(state_version: StateVersion) { let trie = test_trie(state_version); let mut seen = HashSet::new(); trie.for_keys_with_prefix(b"value", |key| { let for_first_time = seen.insert(key.to_vec()); assert!(for_first_time, "Seen key '{:?}' more than once", key); }); let mut expected = HashSet::new(); expected.insert(b"value1".to_vec()); expected.insert(b"value2".to_vec()); assert_eq!(seen, expected); } }