account_db/
lib.rs

1// Copyright 2015-2020 Parity Technologies (UK) Ltd.
2// This file is part of Tetsy Vapory.
3
4// Tetsy Vapory is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Tetsy Vapory is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Tetsy Vapory.  If not, see <http://www.gnu.org/licenses/>.
16
17//! DB backend wrapper for Account trie
18use vapory_types::H256;
19use tetsy_keccak_hash::{KECCAK_NULL_RLP, keccak};
20use tetsy_hash_db::{HashDB, AsHashDB, Prefix};
21use tetsy_keccak_hasher::KeccakHasher;
22use tetsy_kvdb::DBValue;
23use tetsy_rlp::NULL_RLP;
24
25// Combines a key with an address hash to ensure uniqueness.
26// leaves the first 96 bits untouched in order to support partial key lookup.
27#[inline]
28fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 {
29	let mut dst = key.clone();
30	{
31		let last_src: &[u8] = address_hash.as_bytes();
32		let last_dst: &mut [u8] = dst.as_bytes_mut();
33		for (k, a) in last_dst[12..].iter_mut().zip(&last_src[12..]) {
34			*k ^= *a
35		}
36	}
37
38	dst
39}
40
41/// A factory for different kinds of account dbs.
42#[derive(Debug, Clone)]
43pub enum Factory {
44	/// Mangle hashes based on address. This is the default.
45	Mangled,
46	/// Don't mangle hashes.
47	Plain,
48}
49
50impl Default for Factory {
51	fn default() -> Self { Factory::Mangled }
52}
53
54impl Factory {
55	/// Create a read-only accountdb.
56	/// This will panic when write operations are called.
57	pub fn readonly<'db>(&self, db: &'db dyn HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Box<dyn HashDB<KeccakHasher, DBValue> + 'db> {
58		match *self {
59			Factory::Mangled => Box::new(AccountDB::from_hash(db, address_hash)),
60			Factory::Plain => Box::new(Wrapping(db)),
61		}
62	}
63
64	/// Create a new mutable hashdb.
65	pub fn create<'db>(&self, db: &'db mut dyn HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Box<dyn HashDB<KeccakHasher, DBValue> + 'db> {
66		match *self {
67			Factory::Mangled => Box::new(AccountDBMut::from_hash(db, address_hash)),
68			Factory::Plain => Box::new(WrappingMut(db)),
69		}
70	}
71}
72
73// TODO: introduce HashDBMut?
74/// DB backend wrapper for Account trie
75/// Transforms trie node keys for the database
76pub struct AccountDB<'db> {
77	db: &'db dyn HashDB<KeccakHasher, DBValue>,
78	address_hash: H256,
79}
80
81impl<'db> AccountDB<'db> {
82	/// Create a new AccountDB from an address' hash.
83	pub fn from_hash(db: &'db dyn HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Self {
84		AccountDB { db, address_hash }
85	}
86}
87
88impl<'db> AsHashDB<KeccakHasher, DBValue> for AccountDB<'db> {
89	fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
90	fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
91}
92
93impl<'db> HashDB<KeccakHasher, DBValue> for AccountDB<'db> {
94	fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
95		if key == &KECCAK_NULL_RLP {
96			return Some(NULL_RLP.to_vec());
97		}
98		self.db.get(&combine_key(&self.address_hash, key), prefix)
99	}
100
101	fn contains(&self, key: &H256, prefix: Prefix) -> bool {
102		if key == &KECCAK_NULL_RLP {
103			return true;
104		}
105		self.db.contains(&combine_key(&self.address_hash, key), prefix)
106	}
107
108	fn insert(&mut self, _prefix: Prefix, _value: &[u8]) -> H256 {
109		unimplemented!()
110	}
111
112	fn emplace(&mut self, _key: H256, _prefix: Prefix, _value: DBValue) {
113		unimplemented!()
114	}
115
116	fn remove(&mut self, _key: &H256, _prefix: Prefix) {
117		unimplemented!()
118	}
119}
120
121/// DB backend wrapper for Account trie
122pub struct AccountDBMut<'db> {
123	db: &'db mut dyn HashDB<KeccakHasher, DBValue>,
124	address_hash: H256,
125}
126
127impl<'db> AccountDBMut<'db> {
128	/// Create a new `AccountDBMut` from an address' hash.
129	pub fn from_hash(db: &'db mut dyn HashDB<KeccakHasher, DBValue>, address_hash: H256) -> Self {
130		AccountDBMut { db, address_hash }
131	}
132
133	/// Create an `AccountDB` from an `AccountDBMut` (used in tests).
134	pub fn immutable(&'db self) -> AccountDB<'db> {
135		AccountDB { db: self.db, address_hash: self.address_hash.clone() }
136	}
137}
138
139impl<'db> HashDB<KeccakHasher, DBValue> for AccountDBMut<'db>{
140	fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
141		if key == &KECCAK_NULL_RLP {
142			return Some(NULL_RLP.to_vec());
143		}
144		self.db.get(&combine_key(&self.address_hash, key), prefix)
145	}
146
147	fn contains(&self, key: &H256, prefix: Prefix) -> bool {
148		if key == &KECCAK_NULL_RLP {
149			return true;
150		}
151		self.db.contains(&combine_key(&self.address_hash, key), prefix)
152	}
153
154	fn insert(&mut self, prefix: Prefix, value: &[u8]) -> H256 {
155		if value == &NULL_RLP {
156			return KECCAK_NULL_RLP.clone();
157		}
158		let k = keccak(value);
159		let ak = combine_key(&self.address_hash, &k);
160		self.db.emplace(ak, prefix, value.to_vec());
161		k
162	}
163
164	fn emplace(&mut self, key: H256, prefix: Prefix, value: DBValue) {
165		if key == KECCAK_NULL_RLP {
166			return;
167		}
168		let key = combine_key(&self.address_hash, &key);
169		self.db.emplace(key, prefix, value)
170	}
171
172	fn remove(&mut self, key: &H256, prefix: Prefix) {
173		if key == &KECCAK_NULL_RLP {
174			return;
175		}
176		let key = combine_key(&self.address_hash, key);
177		self.db.remove(&key, prefix)
178	}
179}
180
181impl<'db> AsHashDB<KeccakHasher, DBValue> for AccountDBMut<'db> {
182	fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
183	fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
184}
185
186struct Wrapping<'db>(&'db dyn HashDB<KeccakHasher, DBValue>);
187
188impl<'db> AsHashDB<KeccakHasher, DBValue> for Wrapping<'db> {
189	fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
190	fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
191}
192
193impl<'db> HashDB<KeccakHasher, DBValue> for Wrapping<'db> {
194	fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
195		if key == &KECCAK_NULL_RLP {
196			return Some(NULL_RLP.to_vec());
197		}
198		self.0.get(key, prefix)
199	}
200
201	fn contains(&self, key: &H256, prefix: Prefix) -> bool {
202		if key == &KECCAK_NULL_RLP {
203			return true;
204		}
205		self.0.contains(key, prefix)
206	}
207
208	fn insert(&mut self, _prefix: Prefix, _value: &[u8]) -> H256 {
209		unimplemented!()
210	}
211
212	fn emplace(&mut self, _key: H256, _prefix: Prefix, _value: DBValue) {
213		unimplemented!()
214	}
215
216	fn remove(&mut self, _key: &H256, _prefix: Prefix) {
217		unimplemented!()
218	}
219}
220
221struct WrappingMut<'db>(&'db mut dyn HashDB<KeccakHasher, DBValue>);
222impl<'db> AsHashDB<KeccakHasher, DBValue> for WrappingMut<'db> {
223	fn as_hash_db(&self) -> &dyn HashDB<KeccakHasher, DBValue> { self }
224	fn as_hash_db_mut(&mut self) -> &mut dyn HashDB<KeccakHasher, DBValue> { self }
225}
226
227impl<'db> HashDB<KeccakHasher, DBValue> for WrappingMut<'db>{
228	fn get(&self, key: &H256, prefix: Prefix) -> Option<DBValue> {
229		if key == &KECCAK_NULL_RLP {
230			return Some(NULL_RLP.to_vec());
231		}
232		self.0.get(key, prefix)
233	}
234
235	fn contains(&self, key: &H256, prefix: Prefix) -> bool {
236		if key == &KECCAK_NULL_RLP {
237			return true;
238		}
239		self.0.contains(key, prefix)
240	}
241
242	fn insert(&mut self, prefix: Prefix, value: &[u8]) -> H256 {
243		if value == &NULL_RLP {
244			return KECCAK_NULL_RLP.clone();
245		}
246		self.0.insert(prefix, value)
247	}
248
249	fn emplace(&mut self, key: H256, prefix: Prefix, value: DBValue) {
250		if key == KECCAK_NULL_RLP {
251			return;
252		}
253		self.0.emplace(key, prefix, value)
254	}
255
256	fn remove(&mut self, key: &H256, prefix: Prefix) {
257		if key == &KECCAK_NULL_RLP {
258			return;
259		}
260		self.0.remove(key, prefix)
261	}
262}