// Copyright 2015-2018 Parity Technologies (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 .
//! In-memory trie representation.
use super::{Result, TrieError, TrieMut};
use super::lookup::Lookup;
use super::node::Node as EncodedNode;
use node_codec::NodeCodec;
use super::node::NodeKey;
use bytes::ToPretty;
use hashdb::{HashDB, Hasher, DBValue};
use nibbleslice::NibbleSlice;
use elastic_array::ElasticArray1024;
use std::collections::{HashSet, VecDeque};
use std::marker::PhantomData;
use std::mem;
use std::ops::Index;
use heapsize::HeapSizeOf;
use std::{fmt::Debug, hash::Hash};
// For lookups into the Node storage buffer.
// This is deliberately non-copyable.
#[derive(Debug)]
struct StorageHandle(usize);
// Handles to nodes in the trie.
#[derive(Debug)]
enum NodeHandle {
/// Loaded into memory.
InMemory(StorageHandle),
/// Either a hash or an inline node
Hash(H),
}
impl From for NodeHandle {
fn from(handle: StorageHandle) -> Self {
NodeHandle::InMemory(handle)
}
}
fn empty_children() -> Box<[Option>; 16]> {
Box::new([
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
])
}
/// Node types in the Trie.
#[derive(Debug)]
enum Node {
/// Empty node.
Empty,
/// A leaf node contains the end of a key and a value.
/// This key is encoded from a `NibbleSlice`, meaning it contains
/// a flag indicating it is a leaf.
Leaf(NodeKey, DBValue),
/// An extension contains a shared portion of a key and a child node.
/// The shared portion is encoded from a `NibbleSlice` meaning it contains
/// a flag indicating it is an extension.
/// The child node is always a branch.
Extension(NodeKey, NodeHandle),
/// A branch has up to 16 children and an optional value.
Branch(Box<[Option>; 16]>, Option)
}
impl Node where O: AsRef<[u8]> + AsMut<[u8]> + Default + HeapSizeOf + Debug + PartialEq + Eq + Hash + Send + Sync + Clone + Copy {
// load an inline node into memory or get the hash to do the lookup later.
fn inline_or_hash(node: &[u8], db: &HashDB, storage: &mut NodeStorage) -> NodeHandle
where C: NodeCodec,
H: Hasher,
{
C::try_decode_hash(&node)
.map(NodeHandle::Hash)
.unwrap_or_else(|| {
let child = Node::from_encoded::(node, db, storage);
NodeHandle::InMemory(storage.alloc(Stored::New(child)))
})
}
// decode a node from encoded bytes without getting its children.
fn from_encoded(data: &[u8], db: &HashDB, storage: &mut NodeStorage) -> Self
where C: NodeCodec,
H: Hasher,
{
match C::decode(data).expect("encoded bytes read from db; qed") {
EncodedNode::Empty => Node::Empty,
EncodedNode::Leaf(k, v) => Node::Leaf(k.encoded(true), DBValue::from_slice(&v)),
EncodedNode::Extension(key, cb) => {
Node::Extension(
key.encoded(false),
Self::inline_or_hash::(cb, db, storage))
}
EncodedNode::Branch(ref encoded_children, val) => {
let mut child = |i:usize| {
let raw = encoded_children[i];
if !C::is_empty_node(raw) {
Some(Self::inline_or_hash::(raw, db, storage))
} else {
None
}
};
let children = Box::new([
child(0), child(1), child(2), child(3),
child(4), child(5), child(6), child(7),
child(8), child(9), child(10), child(11),
child(12), child(13), child(14), child(15),
]);
Node::Branch(children, val.map(DBValue::from_slice))
}
}
}
// TODO: parallelize
fn into_encoded(self, mut child_cb: F) -> ElasticArray1024
where
C: NodeCodec,
F: FnMut(NodeHandle) -> ChildReference,
H: Hasher,
{
match self {
Node::Empty => C::empty_node(),
Node::Leaf(partial, value) => C::leaf_node(&partial, &value),
Node::Extension(partial, child) => C::ext_node(&partial, child_cb(child)),
Node::Branch(mut children, value) => {
C::branch_node(
// map the `NodeHandle`s from the Branch to `ChildReferences`
children.iter_mut()
.map(Option::take)
.map(|maybe_child|
maybe_child.map(|child| child_cb(child))
),
value
)
}
}
}
}
// post-inspect action.
enum Action {
// Replace a node with a new one.
Replace(Node),
// Restore the original node. This trusts that the node is actually the original.
Restore(Node),
// if it is a new node, just clears the storage.
Delete,
}
// post-insert action. Same as action without delete
enum InsertAction {
// Replace a node with a new one.
Replace(Node),
// Restore the original node.
Restore(Node),
}
impl InsertAction {
fn into_action(self) -> Action {
match self {
InsertAction::Replace(n) => Action::Replace(n),
InsertAction::Restore(n) => Action::Restore(n),
}
}
// unwrap the node, disregarding replace or restore state.
fn unwrap_node(self) -> Node {
match self {
InsertAction::Replace(n) | InsertAction::Restore(n) => n,
}
}
}
// What kind of node is stored here.
enum Stored {
// A new node.
New(Node),
// A cached node, loaded from the DB.
Cached(Node, H),
}
/// Used to build a collection of child nodes from a collection of `NodeHandle`s
pub enum ChildReference { // `HO` is e.g. `H256`, i.e. the output of a `Hasher`
Hash(HO),
Inline(HO, usize), // usize is the length of the node data we store in the `H::Out`
}
/// Compact and cache-friendly storage for Trie nodes.
struct NodeStorage {
nodes: Vec>,
free_indices: VecDeque,
}
impl NodeStorage {
/// Create a new storage.
fn empty() -> Self {
NodeStorage {
nodes: Vec::new(),
free_indices: VecDeque::new(),
}
}
/// Allocate a new node in the storage.
fn alloc(&mut self, stored: Stored) -> StorageHandle {
if let Some(idx) = self.free_indices.pop_front() {
self.nodes[idx] = stored;
StorageHandle(idx)
} else {
self.nodes.push(stored);
StorageHandle(self.nodes.len() - 1)
}
}
/// Remove a node from the storage, consuming the handle and returning the node.
fn destroy(&mut self, handle: StorageHandle) -> Stored {
let idx = handle.0;
self.free_indices.push_back(idx);
mem::replace(&mut self.nodes[idx], Stored::New(Node::Empty))
}
}
impl<'a, H> Index<&'a StorageHandle> for NodeStorage {
type Output = Node;
fn index(&self, handle: &'a StorageHandle) -> &Node {
match self.nodes[handle.0] {
Stored::New(ref node) => node,
Stored::Cached(ref node, _) => node,
}
}
}
/// A `Trie` implementation using a generic `HashDB` backing database.
///
/// Use it as a `TrieMut` trait object. You can use `db()` to get the backing database object.
/// Note that changes are not committed to the database until `commit` is called.
/// Querying the root or dropping the trie will commit automatically.
///
/// # Example
/// ```
/// extern crate patricia_trie as trie;
/// extern crate patricia_trie_ethereum as ethtrie;
/// extern crate hashdb;
/// extern crate keccak_hash;
/// extern crate keccak_hasher;
/// extern crate memorydb;
/// extern crate ethereum_types;
///
/// use keccak_hash::KECCAK_NULL_RLP;
/// use ethtrie::{TrieDBMut, trie::TrieMut};
/// use hashdb::DBValue;
/// use keccak_hasher::KeccakHasher;
/// use memorydb::*;
/// use ethereum_types::H256;
///
/// fn main() {
/// let mut memdb = MemoryDB::::new();
/// let mut root = H256::new();
/// let mut t = TrieDBMut::new(&mut memdb, &mut root);
/// assert!(t.is_empty());
/// assert_eq!(*t.root(), KECCAK_NULL_RLP);
/// t.insert(b"foo", b"bar").unwrap();
/// assert!(t.contains(b"foo").unwrap());
/// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar"));
/// t.remove(b"foo").unwrap();
/// assert!(!t.contains(b"foo").unwrap());
/// }
/// ```
pub struct TrieDBMut<'a, H, C>
where
H: Hasher + 'a,
C: NodeCodec
{
storage: NodeStorage,
db: &'a mut HashDB,
root: &'a mut H::Out,
root_handle: NodeHandle,
death_row: HashSet,
/// The number of hash operations this trie has performed.
/// Note that none are performed until changes are committed.
hash_count: usize,
marker: PhantomData, // TODO: rpheimer: "we could have the NodeCodec trait take &self to its methods and then we don't need PhantomData. we can just store an instance of C: NodeCodec in the trie struct. If it's a ZST it won't have any additional overhead anyway"
}
impl<'a, H, C> TrieDBMut<'a, H, C>
where
H: Hasher,
C: NodeCodec
{
/// Create a new trie with backing database `db` and empty `root`.
pub fn new(db: &'a mut HashDB, root: &'a mut H::Out) -> Self {
*root = C::HASHED_NULL_NODE;
let root_handle = NodeHandle::Hash(C::HASHED_NULL_NODE);
TrieDBMut {
storage: NodeStorage::empty(),
db: db,
root: root,
root_handle: root_handle,
death_row: HashSet::new(),
hash_count: 0,
marker: PhantomData,
}
}
/// Create a new trie with the backing database `db` and `root.
/// Returns an error if `root` does not exist.
pub fn from_existing(db: &'a mut HashDB, root: &'a mut H::Out) -> Result {
if !db.contains(root) {
return Err(Box::new(TrieError::InvalidStateRoot(*root)));
}
let root_handle = NodeHandle::Hash(*root);
Ok(TrieDBMut {
storage: NodeStorage::empty(),
db: db,
root: root,
root_handle: root_handle,
death_row: HashSet::new(),
hash_count: 0,
marker: PhantomData,
})
}
/// Get the backing database.
pub fn db(&self) -> &HashDB {
self.db
}
/// Get the backing database mutably.
pub fn db_mut(&mut self) -> &mut HashDB {
self.db
}
// cache a node by hash
fn cache(&mut self, hash: H::Out) -> Result {
let node_encoded = self.db.get(&hash).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash)))?;
let node = Node::from_encoded::(
&node_encoded,
&*self.db,
&mut self.storage
);
Ok(self.storage.alloc(Stored::Cached(node, hash)))
}
// inspect a node, choosing either to replace, restore, or delete it.
// if restored or replaced, returns the new node along with a flag of whether it was changed.
fn inspect(&mut self, stored: Stored, inspector: F) -> Result