Trie query recording and AccountDB factory for no mangling (#1944)
* optionally use no mangling for accountdb * add the recorder module * get_recorded for tries, no virtual dispatch on readonly tries * add recording test
This commit is contained in:
committed by
Gav Wood
parent
33e0a234f2
commit
190e4db266
@@ -136,4 +136,4 @@ impl<T: HashDB> AsHashDB for T {
|
||||
fn as_hashdb_mut(&mut self) -> &mut HashDB {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
use hash::H256;
|
||||
use sha3::Hashable;
|
||||
use hashdb::HashDB;
|
||||
use super::{TrieDB, Trie, TrieDBIterator, TrieItem};
|
||||
use super::{TrieDB, Trie, TrieDBIterator, TrieItem, Recorder};
|
||||
|
||||
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
|
||||
/// Additionaly it stores inserted hash-key mappings for later retrieval.
|
||||
@@ -43,16 +43,11 @@ impl<'db> FatDB<'db> {
|
||||
pub fn db(&self) -> &HashDB {
|
||||
self.raw.db()
|
||||
}
|
||||
|
||||
/// Iterator over all key / vlaues in the trie.
|
||||
pub fn iter(&self) -> FatDBIterator {
|
||||
FatDBIterator::new(&self.raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Trie for FatDB<'db> {
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
||||
Box::new(FatDB::iter(self))
|
||||
Box::new(FatDBIterator::new(&self.raw))
|
||||
}
|
||||
|
||||
fn root(&self) -> &H256 {
|
||||
@@ -63,10 +58,10 @@ impl<'db> Trie for FatDB<'db> {
|
||||
self.raw.contains(&key.sha3())
|
||||
}
|
||||
|
||||
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
|
||||
where 'a: 'key
|
||||
fn get_recorded<'a, 'b, R: 'b>(&'a self, key: &'b [u8], rec: &'b mut R) -> super::Result<Option<&'a [u8]>>
|
||||
where 'a: 'b, R: Recorder
|
||||
{
|
||||
self.raw.get(&key.sha3())
|
||||
self.raw.get_recorded(&key.sha3(), rec)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,9 @@ pub mod triedbmut;
|
||||
pub mod sectriedb;
|
||||
/// Export the sectriedbmut module.
|
||||
pub mod sectriedbmut;
|
||||
/// Trie query recording.
|
||||
pub mod recorder;
|
||||
|
||||
|
||||
mod fatdb;
|
||||
mod fatdbmut;
|
||||
@@ -45,6 +48,7 @@ pub use self::sectriedbmut::SecTrieDBMut;
|
||||
pub use self::sectriedb::SecTrieDB;
|
||||
pub use self::fatdb::{FatDB, FatDBIterator};
|
||||
pub use self::fatdbmut::FatDBMut;
|
||||
pub use self::recorder::Recorder;
|
||||
|
||||
/// Trie Errors.
|
||||
///
|
||||
@@ -88,7 +92,14 @@ pub trait Trie {
|
||||
}
|
||||
|
||||
/// What is the value of the given key in this trie?
|
||||
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result<Option<&'a [u8]>> where 'a: 'key;
|
||||
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result<Option<&'a [u8]>> where 'a: 'key {
|
||||
self.get_recorded(key, &mut recorder::NoOp)
|
||||
}
|
||||
|
||||
/// Query the value of the given key in this trie while recording visited nodes
|
||||
/// to the given recorder. If the query fails, the nodes passed to the recorder are unspecified.
|
||||
fn get_recorded<'a, 'b, R: 'b>(&'a self, key: &'b [u8], rec: &'b mut R) -> Result<Option<&'a [u8]>>
|
||||
where 'a: 'b, R: Recorder;
|
||||
|
||||
/// Returns an iterator over elements of trie.
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a>;
|
||||
@@ -119,7 +130,6 @@ pub trait TrieMut {
|
||||
fn remove(&mut self, key: &[u8]) -> Result<()>;
|
||||
}
|
||||
|
||||
|
||||
/// Trie types
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum TrieSpec {
|
||||
@@ -143,6 +153,51 @@ pub struct TrieFactory {
|
||||
spec: TrieSpec,
|
||||
}
|
||||
|
||||
/// All different kinds of tries.
|
||||
/// This is used to prevent a heap allocation for every created trie.
|
||||
pub enum TrieKinds<'db> {
|
||||
/// A generic trie db.
|
||||
Generic(TrieDB<'db>),
|
||||
/// A secure trie db.
|
||||
Secure(SecTrieDB<'db>),
|
||||
/// A fat trie db.
|
||||
Fat(FatDB<'db>),
|
||||
}
|
||||
|
||||
// wrapper macro for making the match easier to deal with.
|
||||
macro_rules! wrapper {
|
||||
($me: ident, $f_name: ident, $($param: ident),*) => {
|
||||
match *$me {
|
||||
TrieKinds::Generic(ref t) => t.$f_name($($param),*),
|
||||
TrieKinds::Secure(ref t) => t.$f_name($($param),*),
|
||||
TrieKinds::Fat(ref t) => t.$f_name($($param),*),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Trie for TrieKinds<'db> {
|
||||
fn root(&self) -> &H256 {
|
||||
wrapper!(self, root,)
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
wrapper!(self, is_empty,)
|
||||
}
|
||||
|
||||
fn contains(&self, key: &[u8]) -> Result<bool> {
|
||||
wrapper!(self, contains, key)
|
||||
}
|
||||
|
||||
fn get_recorded<'a, 'b, R: 'b>(&'a self, key: &'b [u8], r: &'b mut R) -> Result<Option<&'a [u8]>>
|
||||
where 'a: 'b, R: Recorder {
|
||||
wrapper!(self, get_recorded, key, r)
|
||||
}
|
||||
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
||||
wrapper!(self, iter,)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature="dev", allow(wrong_self_convention))]
|
||||
impl TrieFactory {
|
||||
/// Creates new factory.
|
||||
@@ -153,11 +208,11 @@ impl TrieFactory {
|
||||
}
|
||||
|
||||
/// Create new immutable instance of Trie.
|
||||
pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result<Box<Trie + 'db>> {
|
||||
pub fn readonly<'db>(&self, db: &'db HashDB, root: &'db H256) -> Result<TrieKinds<'db>> {
|
||||
match self.spec {
|
||||
TrieSpec::Generic => Ok(Box::new(try!(TrieDB::new(db, root)))),
|
||||
TrieSpec::Secure => Ok(Box::new(try!(SecTrieDB::new(db, root)))),
|
||||
TrieSpec::Fat => Ok(Box::new(try!(FatDB::new(db, root)))),
|
||||
TrieSpec::Generic => Ok(TrieKinds::Generic(try!(TrieDB::new(db, root)))),
|
||||
TrieSpec::Secure => Ok(TrieKinds::Secure(try!(SecTrieDB::new(db, root)))),
|
||||
TrieSpec::Fat => Ok(TrieKinds::Fat(try!(FatDB::new(db, root)))),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
236
util/src/trie/recorder.rs
Normal file
236
util/src/trie/recorder.rs
Normal file
@@ -0,0 +1,236 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sha3::Hashable;
|
||||
use {Bytes, H256};
|
||||
|
||||
/// A record of a visited node.
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct Record {
|
||||
/// The depth of this node.
|
||||
pub depth: u32,
|
||||
|
||||
/// The raw data of the node.
|
||||
pub data: Bytes,
|
||||
|
||||
/// The hash of the data.
|
||||
pub hash: H256,
|
||||
}
|
||||
|
||||
/// Trie node recorder.
|
||||
///
|
||||
/// These are used to record which nodes are visited during a trie query.
|
||||
/// Inline nodes are not to be recorded, as they are contained within their parent.
|
||||
pub trait Recorder {
|
||||
|
||||
/// Record that the given node has been visited.
|
||||
///
|
||||
/// The depth parameter is the depth of the visited node, with the root node having depth 0.
|
||||
fn record(&mut self, hash: &H256, data: &[u8], depth: u32);
|
||||
|
||||
/// Drain all accepted records from the recorder in ascending order by depth.
|
||||
fn drain(&mut self) -> Vec<Record> where Self: Sized;
|
||||
}
|
||||
|
||||
/// A no-op trie recorder. This ignores everything which is thrown at it.
|
||||
pub struct NoOp;
|
||||
|
||||
impl Recorder for NoOp {
|
||||
#[inline]
|
||||
fn record(&mut self, _hash: &H256, _data: &[u8], _depth: u32) {}
|
||||
|
||||
#[inline]
|
||||
fn drain(&mut self) -> Vec<Record> { Vec::new() }
|
||||
}
|
||||
|
||||
/// A simple recorder. Does nothing fancy but fulfills the `Recorder` interface
|
||||
/// properly.
|
||||
pub struct BasicRecorder {
|
||||
nodes: Vec<Record>,
|
||||
min_depth: u32,
|
||||
}
|
||||
|
||||
impl BasicRecorder {
|
||||
/// Create a new `BasicRecorder` which records all given nodes.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
BasicRecorder::with_depth(0)
|
||||
}
|
||||
|
||||
/// Create a `BasicRecorder` which only records nodes beyond a given depth.
|
||||
pub fn with_depth(depth: u32) -> Self {
|
||||
BasicRecorder {
|
||||
nodes: Vec::new(),
|
||||
min_depth: depth,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Recorder for BasicRecorder {
|
||||
fn record(&mut self, hash: &H256, data: &[u8], depth: u32) {
|
||||
debug_assert_eq!(data.sha3(), *hash);
|
||||
|
||||
if depth >= self.min_depth {
|
||||
self.nodes.push(Record {
|
||||
depth: depth,
|
||||
data: data.into(),
|
||||
hash: *hash,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn drain(&mut self) -> Vec<Record> {
|
||||
::std::mem::replace(&mut self.nodes, Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use sha3::Hashable;
|
||||
use ::H256;
|
||||
|
||||
#[test]
|
||||
fn no_op_does_nothing() {
|
||||
let mut no_op = NoOp;
|
||||
let (node1, node2) = (&[1], &[2]);
|
||||
let (hash1, hash2) = (node1.sha3(), node2.sha3());
|
||||
no_op.record(&hash1, node1, 1);
|
||||
no_op.record(&hash2, node2, 2);
|
||||
|
||||
assert_eq!(no_op.drain(), Vec::new());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_recorder() {
|
||||
let mut basic = BasicRecorder::new();
|
||||
|
||||
let node1 = vec![1, 2, 3, 4];
|
||||
let node2 = vec![4, 5, 6, 7, 8, 9, 10];
|
||||
|
||||
let (hash1, hash2) = (node1.sha3(), node2.sha3());
|
||||
basic.record(&hash1, &node1, 0);
|
||||
basic.record(&hash2, &node2, 456);
|
||||
|
||||
let record1 = Record {
|
||||
data: node1,
|
||||
hash: hash1,
|
||||
depth: 0,
|
||||
};
|
||||
|
||||
let record2 = Record {
|
||||
data: node2,
|
||||
hash: hash2,
|
||||
depth: 456
|
||||
};
|
||||
|
||||
assert_eq!(basic.drain(), vec![record1, record2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_recorder_min_depth() {
|
||||
let mut basic = BasicRecorder::with_depth(400);
|
||||
|
||||
let node1 = vec![1, 2, 3, 4];
|
||||
let node2 = vec![4, 5, 6, 7, 8, 9, 10];
|
||||
|
||||
let hash1 = node1.sha3();
|
||||
let hash2 = node2.sha3();
|
||||
basic.record(&hash1, &node1, 0);
|
||||
basic.record(&hash2, &node2, 456);
|
||||
|
||||
let records = basic.drain();
|
||||
|
||||
assert_eq!(records.len(), 1);
|
||||
|
||||
assert_eq!(records[0].clone(), Record {
|
||||
data: node2,
|
||||
hash: hash2,
|
||||
depth: 456,
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trie_record() {
|
||||
use trie::{TrieDB, TrieDBMut, Trie, TrieMut};
|
||||
use memorydb::MemoryDB;
|
||||
|
||||
let mut db = MemoryDB::new();
|
||||
|
||||
let mut root = H256::default();
|
||||
|
||||
{
|
||||
let mut x = TrieDBMut::new(&mut db, &mut root);
|
||||
|
||||
x.insert(b"dog", b"cat").unwrap();
|
||||
x.insert(b"lunch", b"time").unwrap();
|
||||
x.insert(b"notdog", b"notcat").unwrap();
|
||||
x.insert(b"hotdog", b"hotcat").unwrap();
|
||||
x.insert(b"letter", b"confusion").unwrap();
|
||||
x.insert(b"insert", b"remove").unwrap();
|
||||
x.insert(b"pirate", b"aargh!").unwrap();
|
||||
x.insert(b"yo ho ho", b"and a bottle of rum").unwrap();
|
||||
}
|
||||
|
||||
let trie = TrieDB::new(&db, &root).unwrap();
|
||||
let mut recorder = BasicRecorder::new();
|
||||
|
||||
trie.get_recorded(b"pirate", &mut recorder).unwrap().unwrap();
|
||||
|
||||
let nodes: Vec<_> = recorder.drain().into_iter().map(|r| r.data).collect();
|
||||
assert_eq!(nodes, vec![
|
||||
vec![
|
||||
248, 81, 128, 128, 128, 128, 128, 128, 160, 50, 19, 71, 57, 213, 63, 125, 149,
|
||||
92, 119, 88, 96, 80, 126, 59, 11, 160, 142, 98, 229, 237, 200, 231, 224, 79, 118,
|
||||
215, 93, 144, 246, 179, 176, 160, 118, 211, 171, 199, 172, 136, 136, 240, 221, 59,
|
||||
110, 82, 86, 54, 23, 95, 48, 108, 71, 125, 59, 51, 253, 210, 18, 116, 79, 0, 236,
|
||||
102, 142, 48, 128, 128, 128, 128, 128, 128, 128, 128, 128
|
||||
],
|
||||
vec![
|
||||
248, 60, 206, 134, 32, 105, 114, 97, 116, 101, 134, 97, 97, 114, 103, 104, 33,
|
||||
128, 128, 128, 128, 128, 128, 128, 128, 221, 136, 32, 111, 32, 104, 111, 32, 104,
|
||||
111, 147, 97, 110, 100, 32, 97, 32, 98, 111, 116, 116, 108, 101, 32, 111, 102,
|
||||
32, 114, 117, 109, 128, 128, 128, 128, 128, 128, 128
|
||||
]
|
||||
]);
|
||||
|
||||
trie.get_recorded(b"letter", &mut recorder).unwrap().unwrap();
|
||||
|
||||
let nodes: Vec<_> = recorder.drain().into_iter().map(|r| r.data).collect();
|
||||
assert_eq!(nodes, vec![
|
||||
vec![
|
||||
248, 81, 128, 128, 128, 128, 128, 128, 160, 50, 19, 71, 57, 213, 63, 125, 149,
|
||||
92, 119, 88, 96, 80, 126, 59, 11, 160, 142, 98, 229, 237, 200, 231, 224, 79, 118,
|
||||
215, 93, 144, 246, 179, 176, 160, 118, 211, 171, 199, 172, 136, 136, 240, 221,
|
||||
59, 110, 82, 86, 54, 23, 95, 48, 108, 71, 125, 59, 51, 253, 210, 18, 116, 79,
|
||||
0, 236, 102, 142, 48, 128, 128, 128, 128, 128, 128, 128, 128, 128
|
||||
],
|
||||
vec![
|
||||
248, 99, 128, 128, 128, 128, 200, 131, 32, 111, 103, 131, 99, 97, 116, 128, 128,
|
||||
128, 206, 134, 32, 111, 116, 100, 111, 103, 134, 104, 111, 116, 99, 97, 116, 206,
|
||||
134, 32, 110, 115, 101, 114, 116, 134, 114, 101, 109, 111, 118, 101, 128, 128,
|
||||
160, 202, 250, 252, 153, 229, 63, 255, 13, 100, 197, 80, 120, 190, 186, 92, 5,
|
||||
255, 135, 245, 205, 180, 213, 161, 8, 47, 107, 13, 105, 218, 1, 9, 5, 128,
|
||||
206, 134, 32, 111, 116, 100, 111, 103, 134, 110, 111, 116, 99, 97, 116, 128, 128
|
||||
],
|
||||
vec![
|
||||
235, 128, 128, 128, 128, 128, 128, 208, 133, 53, 116, 116, 101, 114, 137, 99,
|
||||
111, 110, 102, 117, 115, 105, 111, 110, 202, 132, 53, 110, 99, 104, 132, 116,
|
||||
105, 109, 101, 128, 128, 128, 128, 128, 128, 128, 128, 128
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ use hash::H256;
|
||||
use sha3::Hashable;
|
||||
use hashdb::HashDB;
|
||||
use super::triedb::TrieDB;
|
||||
use super::{Trie, TrieItem};
|
||||
use super::{Trie, TrieItem, Recorder};
|
||||
|
||||
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
|
||||
///
|
||||
@@ -59,10 +59,10 @@ impl<'db> Trie for SecTrieDB<'db> {
|
||||
self.raw.contains(&key.sha3())
|
||||
}
|
||||
|
||||
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
|
||||
where 'a: 'key
|
||||
fn get_recorded<'a, 'b, R: 'b>(&'a self, key: &'b [u8], rec: &'b mut R) -> super::Result<Option<&'a [u8]>>
|
||||
where 'a: 'b, R: Recorder
|
||||
{
|
||||
self.raw.get(&key.sha3())
|
||||
self.raw.get_recorded(&key.sha3(), rec)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ use hashdb::*;
|
||||
use nibbleslice::*;
|
||||
use rlp::*;
|
||||
use super::node::Node;
|
||||
use super::recorder::{Recorder, NoOp};
|
||||
use super::{Trie, TrieItem, TrieError};
|
||||
|
||||
/// A `Trie` implementation using a generic `HashDB` backing database.
|
||||
@@ -79,7 +80,7 @@ impl<'db> TrieDB<'db> {
|
||||
pub fn keys(&self) -> super::Result<Vec<H256>> {
|
||||
let mut ret: Vec<H256> = Vec::new();
|
||||
ret.push(self.root.clone());
|
||||
try!(self.accumulate_keys(try!(self.root_node()), &mut ret));
|
||||
try!(self.accumulate_keys(try!(self.root_node(&mut NoOp)), &mut ret));
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
@@ -114,7 +115,7 @@ impl<'db> TrieDB<'db> {
|
||||
acc.push(p.as_val());
|
||||
}
|
||||
|
||||
self.accumulate_keys(try!(self.get_node(payload)), acc)
|
||||
self.accumulate_keys(try!(self.get_node(payload, &mut NoOp, 0)), acc)
|
||||
};
|
||||
|
||||
match node {
|
||||
@@ -127,18 +128,19 @@ impl<'db> TrieDB<'db> {
|
||||
}
|
||||
|
||||
/// Get the root node's RLP.
|
||||
fn root_node(&self) -> super::Result<Node> {
|
||||
self.root_data().map(Node::decoded)
|
||||
fn root_node<'a, R: 'a + Recorder>(&self, r: &'a mut R) -> super::Result<Node> {
|
||||
self.root_data(r).map(Node::decoded)
|
||||
}
|
||||
|
||||
/// Get the data of the root node.
|
||||
fn root_data(&self) -> super::Result<&[u8]> {
|
||||
fn root_data<'a, R: 'a + Recorder>(&self, r: &'a mut R) -> super::Result<&[u8]> {
|
||||
self.db.get(self.root).ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root)))
|
||||
.map(|node| { r.record(self.root, node, 0); node })
|
||||
}
|
||||
|
||||
/// Get the root node as a `Node`.
|
||||
fn get_node(&'db self, node: &'db [u8]) -> super::Result<Node> {
|
||||
self.get_raw_or_lookup(node).map(Node::decoded)
|
||||
fn get_node<'a, R: 'a + Recorder>(&'db self, node: &'db [u8], r: &'a mut R, depth: u32) -> super::Result<Node> {
|
||||
self.get_raw_or_lookup(node, r, depth).map(Node::decoded)
|
||||
}
|
||||
|
||||
/// Indentation helper for `formal_all`.
|
||||
@@ -155,7 +157,7 @@ impl<'db> TrieDB<'db> {
|
||||
Node::Leaf(slice, value) => try!(writeln!(f, "'{:?}: {:?}.", slice, value.pretty())),
|
||||
Node::Extension(ref slice, item) => {
|
||||
try!(write!(f, "'{:?} ", slice));
|
||||
if let Ok(node) = self.get_node(item) {
|
||||
if let Ok(node) = self.get_node(item, &mut NoOp, 0) {
|
||||
try!(self.fmt_all(node, f, deepness));
|
||||
}
|
||||
},
|
||||
@@ -166,7 +168,7 @@ impl<'db> TrieDB<'db> {
|
||||
try!(writeln!(f, "=: {:?}", v.pretty()))
|
||||
}
|
||||
for i in 0..16 {
|
||||
match self.get_node(nodes[i]) {
|
||||
match self.get_node(nodes[i], &mut NoOp, 0) {
|
||||
Ok(Node::Empty) => {},
|
||||
Ok(n) => {
|
||||
try!(self.fmt_indent(f, deepness + 1));
|
||||
@@ -188,29 +190,36 @@ impl<'db> TrieDB<'db> {
|
||||
}
|
||||
|
||||
/// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists.
|
||||
fn do_lookup<'key>(&'db self, key: &NibbleSlice<'key>) -> super::Result<Option<&'db [u8]>>
|
||||
where 'db: 'key
|
||||
fn do_lookup<'key, R: 'key>(&'db self, key: &NibbleSlice<'key>, r: &'key mut R) -> super::Result<Option<&'db [u8]>>
|
||||
where 'db: 'key, R: Recorder
|
||||
{
|
||||
let root_rlp = try!(self.root_data());
|
||||
self.get_from_node(root_rlp, key)
|
||||
let root_rlp = try!(self.root_data(r));
|
||||
self.get_from_node(root_rlp, key, r, 1)
|
||||
}
|
||||
|
||||
/// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no
|
||||
/// value exists for the key.
|
||||
///
|
||||
/// Note: Not a public API; use Trie trait functions.
|
||||
fn get_from_node<'key>(&'db self, node: &'db [u8], key: &NibbleSlice<'key>) -> super::Result<Option<&'db [u8]>>
|
||||
where 'db: 'key
|
||||
{
|
||||
fn get_from_node<'key, R: 'key>(
|
||||
&'db self,
|
||||
node: &'db [u8],
|
||||
key: &NibbleSlice<'key>,
|
||||
r: &'key mut R,
|
||||
d: u32
|
||||
) -> super::Result<Option<&'db [u8]>> where 'db: 'key, R: Recorder {
|
||||
match Node::decoded(node) {
|
||||
Node::Leaf(ref slice, value) if key == slice => Ok(Some(value)),
|
||||
Node::Extension(ref slice, item) if key.starts_with(slice) => {
|
||||
let data = try!(self.get_raw_or_lookup(item));
|
||||
self.get_from_node(data, &key.mid(slice.len()))
|
||||
let data = try!(self.get_raw_or_lookup(item, r, d));
|
||||
self.get_from_node(data, &key.mid(slice.len()), r, d + 1)
|
||||
},
|
||||
Node::Branch(ref nodes, value) => match key.is_empty() {
|
||||
true => Ok(value),
|
||||
false => self.get_from_node(try!(self.get_raw_or_lookup(nodes[key.at(0) as usize])), &key.mid(1))
|
||||
false => {
|
||||
let node = try!(self.get_raw_or_lookup(nodes[key.at(0) as usize], r, d));
|
||||
self.get_from_node(node, &key.mid(1), r, d + 1)
|
||||
}
|
||||
},
|
||||
_ => Ok(None)
|
||||
}
|
||||
@@ -219,13 +228,14 @@ impl<'db> TrieDB<'db> {
|
||||
/// Given some node-describing data `node`, return the actual node RLP.
|
||||
/// This could be a simple identity operation in the case that the node is sufficiently small, but
|
||||
/// may require a database lookup.
|
||||
fn get_raw_or_lookup(&'db self, node: &'db [u8]) -> super::Result<&'db [u8]> {
|
||||
fn get_raw_or_lookup<R: Recorder>(&'db self, node: &'db [u8], rec: &mut R, d: u32) -> super::Result<&'db [u8]> {
|
||||
// check if its sha3 + len
|
||||
let r = Rlp::new(node);
|
||||
match r.is_data() && r.size() == 32 {
|
||||
true => {
|
||||
let key = r.as_val::<H256>();
|
||||
self.db.get(&key).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(key)))
|
||||
.map(|raw| { rec.record(&key, raw, d); raw })
|
||||
}
|
||||
false => Ok(node)
|
||||
}
|
||||
@@ -275,7 +285,7 @@ impl<'a> TrieDBIterator<'a> {
|
||||
trail: vec![],
|
||||
key_nibbles: Vec::new(),
|
||||
};
|
||||
r.descend(db.root_data().unwrap());
|
||||
r.descend(db.root_data(&mut NoOp).unwrap());
|
||||
r
|
||||
}
|
||||
|
||||
@@ -283,7 +293,7 @@ impl<'a> TrieDBIterator<'a> {
|
||||
fn descend(&mut self, d: &'a [u8]) {
|
||||
self.trail.push(Crumb {
|
||||
status: Status::Entering,
|
||||
node: self.db.get_node(d).unwrap(),
|
||||
node: self.db.get_node(d, &mut NoOp, 0).unwrap(),
|
||||
});
|
||||
match self.trail.last().unwrap().node {
|
||||
Node::Leaf(n, _) | Node::Extension(n, _) => { self.key_nibbles.extend(n.iter()); },
|
||||
@@ -341,24 +351,17 @@ impl<'a> Iterator for TrieDBIterator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> TrieDB<'db> {
|
||||
/// Get all keys/values stored in the trie.
|
||||
pub fn iter(&self) -> TrieDBIterator {
|
||||
TrieDBIterator::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> Trie for TrieDB<'db> {
|
||||
fn iter<'a>(&'a self) -> Box<Iterator<Item = TrieItem> + 'a> {
|
||||
Box::new(TrieDB::iter(self))
|
||||
Box::new(TrieDBIterator::new(self))
|
||||
}
|
||||
|
||||
fn root(&self) -> &H256 { self.root }
|
||||
|
||||
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> super::Result<Option<&'a [u8]>>
|
||||
where 'a: 'key
|
||||
fn get_recorded<'a, 'b, R: 'b>(&'a self, key: &'b [u8], rec: &'b mut R) -> super::Result<Option<&'a [u8]>>
|
||||
where 'a: 'b, R: Recorder
|
||||
{
|
||||
self.do_lookup(&NibbleSlice::new(key))
|
||||
self.do_lookup(&NibbleSlice::new(key), rec)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,6 +390,8 @@ fn iterator() {
|
||||
t.insert(x, x).unwrap();
|
||||
}
|
||||
}
|
||||
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), TrieDB::new(&memdb, &root).unwrap().iter().map(|x|x.0).collect::<Vec<_>>());
|
||||
assert_eq!(d, TrieDB::new(&memdb, &root).unwrap().iter().map(|x|x.1).collect::<Vec<_>>());
|
||||
|
||||
let t = TrieDB::new(&memdb, &root).unwrap();
|
||||
assert_eq!(d.iter().map(|i|i.to_vec()).collect::<Vec<_>>(), t.iter().map(|x|x.0).collect::<Vec<_>>());
|
||||
assert_eq!(d, t.iter().map(|x|x.1).collect::<Vec<_>>());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user