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, triedb::TrieDBDoubleEndedIterator, MerkleValue, 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 lookup_first_descendant(
76		&self,
77		key: &[u8],
78	) -> Result<Option<MerkleValue<TrieHash<L>>>, TrieHash<L>, CError<L>> {
79		self.raw.lookup_first_descendant(key)
80	}
81
82	fn iter<'a>(
83		&'a self,
84	) -> Result<
85		Box<dyn TrieIterator<L, Item = TrieItem<TrieHash<L>, CError<L>>> + 'a>,
86		TrieHash<L>,
87		CError<L>,
88	> {
89		FatDBIterator::<L>::new(&self.raw).map(|iter| Box::new(iter) as Box<_>)
90	}
91
92	fn key_iter<'a>(
93		&'a self,
94	) -> Result<
95		Box<dyn TrieIterator<L, Item = TrieKeyItem<TrieHash<L>, CError<L>>> + 'a>,
96		TrieHash<L>,
97		CError<L>,
98	> {
99		FatDBKeyIterator::<L>::new(&self.raw).map(|iter| Box::new(iter) as Box<_>)
100	}
101}
102
103/// Iterator over inserted pairs of key values.
104pub struct FatDBIterator<'db, 'cache, L>
105where
106	L: TrieLayout,
107{
108	trie_iterator: TrieDBIterator<'db, 'cache, L>,
109	trie: &'db TrieDB<'db, 'cache, L>,
110}
111
112/// Double ended iterator over inserted pairs of key values.
113pub struct FatDBDoubleEndedIterator<'db, 'cache, L>
114where
115	L: TrieLayout,
116{
117	trie_iterator: TrieDBDoubleEndedIterator<'db, 'cache, L>,
118	trie: &'db TrieDB<'db, 'cache, L>,
119}
120
121impl<'a, 'cache, L: TrieLayout> FatDBDoubleEndedIterator<'a, 'cache, L> {
122	/// Create a new double ended iterator.
123	pub fn new(db: &'a TrieDB<'a, 'cache, L>) -> Result<Self, TrieHash<L>, CError<L>> {
124		Ok(Self { trie_iterator: TrieDBDoubleEndedIterator::new(db)?, trie: db })
125	}
126}
127
128impl<'db, 'cache, L> FatDBIterator<'db, 'cache, L>
129where
130	L: TrieLayout,
131{
132	/// Creates new iterator.
133	pub fn new(trie: &'db TrieDB<'db, 'cache, L>) -> Result<Self, TrieHash<L>, CError<L>> {
134		Ok(FatDBIterator { trie_iterator: TrieDBIterator::new(trie)?, trie })
135	}
136}
137
138impl<'db, 'cache, L> TrieIterator<L> for FatDBIterator<'db, 'cache, L>
139where
140	L: TrieLayout,
141{
142	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
143		let hashed_key = L::Hash::hash(key);
144		self.trie_iterator.seek(hashed_key.as_ref())
145	}
146}
147
148impl<'db, 'cache, L> Iterator for FatDBIterator<'db, 'cache, L>
149where
150	L: TrieLayout,
151{
152	type Item = TrieItem<TrieHash<L>, CError<L>>;
153
154	fn next(&mut self) -> Option<Self::Item> {
155		self.trie_iterator.next().map(|res| {
156			res.map(|(hash, value)| {
157				let aux_hash = L::Hash::hash(&hash);
158				(
159					self.trie.db().get(&aux_hash, Default::default()).expect("Missing fatdb hash"),
160					value,
161				)
162			})
163		})
164	}
165}
166
167impl<'db, 'cache, L> TrieIterator<L> for FatDBDoubleEndedIterator<'db, 'cache, L>
168where
169	L: TrieLayout,
170{
171	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
172		let hashed_key = L::Hash::hash(key);
173		self.trie_iterator.seek(hashed_key.as_ref())
174	}
175}
176
177impl<'db, 'cache, L> Iterator for FatDBDoubleEndedIterator<'db, 'cache, L>
178where
179	L: TrieLayout,
180{
181	type Item = TrieItem<TrieHash<L>, CError<L>>;
182
183	fn next(&mut self) -> Option<Self::Item> {
184		self.trie_iterator.next().map(|res| {
185			res.map(|(hash, value)| {
186				let aux_hash = L::Hash::hash(&hash);
187				(
188					self.trie.db().get(&aux_hash, Default::default()).expect("Missing fatdb hash"),
189					value,
190				)
191			})
192		})
193	}
194}
195
196impl<'db, 'cache, L> DoubleEndedIterator for FatDBDoubleEndedIterator<'db, 'cache, L>
197where
198	L: TrieLayout,
199{
200	fn next_back(&mut self) -> Option<Self::Item> {
201		self.trie_iterator.next_back().map(|res| {
202			res.map(|(hash, value)| {
203				let aux_hash = L::Hash::hash(&hash);
204				(
205					self.trie.db().get(&aux_hash, Default::default()).expect("Missing fatdb hash"),
206					value,
207				)
208			})
209		})
210	}
211}
212
213/// Iterator over inserted keys.
214pub struct FatDBKeyIterator<'db, 'cache, L>
215where
216	L: TrieLayout,
217{
218	trie_iterator: TrieDBKeyIterator<'db, 'cache, L>,
219	trie: &'db TrieDB<'db, 'cache, L>,
220}
221
222impl<'db, 'cache, L> FatDBKeyIterator<'db, 'cache, L>
223where
224	L: TrieLayout,
225{
226	/// Creates new iterator.
227	pub fn new(trie: &'db TrieDB<'db, 'cache, L>) -> Result<Self, TrieHash<L>, CError<L>> {
228		Ok(FatDBKeyIterator { trie_iterator: TrieDBKeyIterator::new(trie)?, trie })
229	}
230}
231
232impl<'db, 'cache, L> TrieIterator<L> for FatDBKeyIterator<'db, 'cache, L>
233where
234	L: TrieLayout,
235{
236	fn seek(&mut self, key: &[u8]) -> Result<(), TrieHash<L>, CError<L>> {
237		let hashed_key = L::Hash::hash(key);
238		self.trie_iterator.seek(hashed_key.as_ref())
239	}
240}
241
242impl<'db, 'cache, L> Iterator for FatDBKeyIterator<'db, 'cache, L>
243where
244	L: TrieLayout,
245{
246	type Item = TrieKeyItem<TrieHash<L>, CError<L>>;
247
248	fn next(&mut self) -> Option<Self::Item> {
249		self.trie_iterator.next().map(|res| {
250			res.map(|hash| {
251				let aux_hash = L::Hash::hash(&hash);
252				self.trie.db().get(&aux_hash, Default::default()).expect("Missing fatdb hash")
253			})
254		})
255	}
256}