Skip to main content

trie_db/
fatdb.rs

1// Copyright 2017, 2021 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::{
16	CError, DBValue, Query, Result, Trie, TrieDB, TrieDBIterator, TrieDBKeyIterator, TrieHash,
17	TrieItem, TrieIterator, TrieKeyItem, TrieLayout,
18};
19use hash_db::{HashDBRef, Hasher};
20
21use crate::{rstd::boxed::Box, TrieDBBuilder};
22
23/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
24/// Additionaly it stores inserted hash-key mappings for later retrieval.
25///
26/// Use it as a `Trie` or `TrieMut` trait object.
27pub struct FatDB<'db, 'cache, L>
28where
29	L: TrieLayout,
30{
31	raw: TrieDB<'db, 'cache, L>,
32}
33
34impl<'db, 'cache, L> FatDB<'db, 'cache, L>
35where
36	L: TrieLayout,
37{
38	/// Create a new trie with the backing database `db` and empty `root`
39	/// Initialise to the state entailed by the genesis block.
40	/// This guarantees the trie is built correctly.
41	pub fn new(db: &'db dyn HashDBRef<L::Hash, DBValue>, root: &'db TrieHash<L>) -> Self {
42		FatDB { raw: TrieDBBuilder::new(db, root).build() }
43	}
44
45	/// Get the backing database.
46	pub fn db(&self) -> &dyn HashDBRef<L::Hash, DBValue> {
47		self.raw.db()
48	}
49}
50
51impl<'db, 'cache, L> Trie<L> for FatDB<'db, 'cache, L>
52where
53	L: TrieLayout,
54{
55	fn root(&self) -> &TrieHash<L> {
56		self.raw.root()
57	}
58
59	fn contains(&self, key: &[u8]) -> Result<bool, TrieHash<L>, CError<L>> {
60		self.raw.contains(L::Hash::hash(key).as_ref())
61	}
62
63	fn get_hash(&self, key: &[u8]) -> Result<Option<TrieHash<L>>, TrieHash<L>, CError<L>> {
64		self.raw.get_hash(key)
65	}
66
67	fn get_with<Q: Query<L::Hash>>(
68		&self,
69		key: &[u8],
70		query: Q,
71	) -> Result<Option<Q::Item>, TrieHash<L>, CError<L>> {
72		self.raw.get_with(L::Hash::hash(key).as_ref(), query)
73	}
74
75	fn iter<'a>(
76		&'a self,
77	) -> Result<
78		Box<dyn TrieIterator<L, Item = TrieItem<TrieHash<L>, CError<L>>> + 'a>,
79		TrieHash<L>,
80		CError<L>,
81	> {
82		FatDBIterator::<L>::new(&self.raw).map(|iter| Box::new(iter) as Box<_>)
83	}
84
85	fn key_iter<'a>(
86		&'a self,
87	) -> Result<
88		Box<dyn TrieIterator<L, Item = TrieKeyItem<TrieHash<L>, CError<L>>> + 'a>,
89		TrieHash<L>,
90		CError<L>,
91	> {
92		FatDBKeyIterator::<L>::new(&self.raw).map(|iter| Box::new(iter) as Box<_>)
93	}
94}
95
96/// Iterator over inserted pairs of key values.
97pub struct FatDBIterator<'db, 'cache, L>
98where
99	L: TrieLayout,
100{
101	trie_iterator: TrieDBIterator<'db, 'cache, L>,
102	trie: &'db TrieDB<'db, 'cache, L>,
103}
104
105impl<'db, 'cache, L> FatDBIterator<'db, 'cache, L>
106where
107	L: TrieLayout,
108{
109	/// Creates new iterator.
110	pub fn new(trie: &'db TrieDB<'db, 'cache, L>) -> Result<Self, TrieHash<L>, CError<L>> {
111		Ok(FatDBIterator { trie_iterator: TrieDBIterator::new(trie)?, trie })
112	}
113}
114
115impl<'db, 'cache, L> TrieIterator<L> for FatDBIterator<'db, 'cache, L>
116where
117	L: TrieLayout,
118{
119	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
120		let hashed_key = L::Hash::hash(key);
121		self.trie_iterator.seek(hashed_key.as_ref())
122	}
123}
124
125impl<'db, 'cache, L> Iterator for FatDBIterator<'db, 'cache, L>
126where
127	L: TrieLayout,
128{
129	type Item = TrieItem<TrieHash<L>, CError<L>>;
130
131	fn next(&mut self) -> Option<Self::Item> {
132		self.trie_iterator.next().map(|res| {
133			res.map(|(hash, value)| {
134				let aux_hash = L::Hash::hash(&hash);
135				(
136					self.trie.db().get(&aux_hash, Default::default()).expect("Missing fatdb hash"),
137					value,
138				)
139			})
140		})
141	}
142}
143
144/// Iterator over inserted keys.
145pub struct FatDBKeyIterator<'db, 'cache, L>
146where
147	L: TrieLayout,
148{
149	trie_iterator: TrieDBKeyIterator<'db, 'cache, L>,
150	trie: &'db TrieDB<'db, 'cache, L>,
151}
152
153impl<'db, 'cache, L> FatDBKeyIterator<'db, 'cache, L>
154where
155	L: TrieLayout,
156{
157	/// Creates new iterator.
158	pub fn new(trie: &'db TrieDB<'db, 'cache, L>) -> Result<Self, TrieHash<L>, CError<L>> {
159		Ok(FatDBKeyIterator { trie_iterator: TrieDBKeyIterator::new(trie)?, trie })
160	}
161}
162
163impl<'db, 'cache, L> TrieIterator<L> for FatDBKeyIterator<'db, 'cache, L>
164where
165	L: TrieLayout,
166{
167	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
168		let hashed_key = L::Hash::hash(key);
169		self.trie_iterator.seek(hashed_key.as_ref())
170	}
171}
172
173impl<'db, 'cache, L> Iterator for FatDBKeyIterator<'db, 'cache, L>
174where
175	L: TrieLayout,
176{
177	type Item = TrieKeyItem<TrieHash<L>, CError<L>>;
178
179	fn next(&mut self) -> Option<Self::Item> {
180		self.trie_iterator.next().map(|res| {
181			res.map(|hash| {
182				let aux_hash = L::Hash::hash(&hash);
183				self.trie.db().get(&aux_hash, Default::default()).expect("Missing fatdb hash")
184			})
185		})
186	}
187}