use super::{Result, TrieError, TrieMut};
use super::lookup::Lookup;
use super::node::Node as EncodedNode;
use node_codec::NodeCodec;
use super::{DBValue, node::NodeKey};
use hash_db::{HashDB, Hasher};
use nibbleslice::{self, NibbleSlice, combine_encoded};
use ::core_::marker::PhantomData;
use ::core_::mem;
use ::core_::ops::Index;
use ::core_::hash::Hash;
#[cfg(feature = "std")]
use ::std::collections::{HashSet, VecDeque};
#[cfg(not(feature = "std"))]
use ::alloc::collections::vec_deque::VecDeque;
#[cfg(not(feature = "std"))]
use ::hashmap_core::HashSet;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[derive(Debug)]
struct StorageHandle(usize);
#[derive(Debug)]
enum NodeHandle<H> {
InMemory(StorageHandle),
Hash(H),
}
impl<H> From<StorageHandle> for NodeHandle<H> {
fn from(handle: StorageHandle) -> Self {
NodeHandle::InMemory(handle)
}
}
fn empty_children<H>() -> Box<[Option<NodeHandle<H>>; 16]> {
Box::new([
None, None, None, None, None, None, None, None,
None, None, None, None, None, None, None, None,
])
}
struct Partial<'key> {
key: NibbleSlice<'key>,
split: usize,
}
impl<'key> Partial<'key> {
fn new(key: NibbleSlice) -> Partial {
Partial {
key,
split: 0,
}
}
fn advance(&mut self, by: usize) {
self.split += by;
}
fn mid(&self) -> NibbleSlice<'key> {
self.key.mid(self.split)
}
fn encoded_prefix(&self) -> NodeKey {
self.key.encoded_leftmost(self.split, false)
}
}
#[derive(Debug)]
enum Node<H> {
Empty,
Leaf(NodeKey, DBValue),
Extension(NodeKey, NodeHandle<H>),
Branch(Box<[Option<NodeHandle<H>>; 16]>, Option<DBValue>)
}
impl<O> Node<O>
where
O: AsRef<[u8]> + AsMut<[u8]> + Default + crate::MaybeDebug + PartialEq + Eq + Hash + Send + Sync + Clone + Copy
{
fn inline_or_hash<C, H>(
node: &[u8],
db: &HashDB<H, DBValue>,
storage: &mut NodeStorage<H::Out>
) -> NodeHandle<H::Out>
where
C: NodeCodec<H>,
H: Hasher<Out = O>,
{
C::try_decode_hash(&node)
.map(NodeHandle::Hash)
.unwrap_or_else(|| {
let child = Node::from_encoded::<C, H>(node, db, storage);
NodeHandle::InMemory(storage.alloc(Stored::New(child)))
})
}
fn from_encoded<C, H>(data: &[u8], db: &HashDB<H, DBValue>, storage: &mut NodeStorage<H::Out>) -> Self
where C: NodeCodec<H>, H: Hasher<Out = O>,
{
match C::decode(data).unwrap_or(EncodedNode::Empty) {
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::<C, H>(cb, db, storage))
}
EncodedNode::Branch(ref encoded_children, val) => {
let mut child = |i:usize| {
encoded_children[i].map(|data|
Self::inline_or_hash::<C, H>(data, db, storage)
)
};
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))
}
}
}
fn into_encoded<F, C, H>(self, mut child_cb: F) -> Vec<u8>
where
C: NodeCodec<H>,
F: FnMut(NodeHandle<H::Out>, &NodeKey) -> ChildReference<H::Out>,
H: Hasher<Out = O>,
{
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, &partial)),
Node::Branch(mut children, value) => {
C::branch_node(
children.iter_mut()
.map(Option::take)
.enumerate()
.map(|(i, maybe_child)|
maybe_child.map(|child| child_cb(child, &NibbleSlice::new_offset(&[i as u8], 1).encoded(false)))
),
value
)
}
}
}
}
enum Action<H> {
Replace(Node<H>),
Restore(Node<H>),
Delete,
}
enum InsertAction<H> {
Replace(Node<H>),
Restore(Node<H>),
}
impl<H> InsertAction<H> {
fn into_action(self) -> Action<H> {
match self {
InsertAction::Replace(n) => Action::Replace(n),
InsertAction::Restore(n) => Action::Restore(n),
}
}
fn unwrap_node(self) -> Node<H> {
match self {
InsertAction::Replace(n) | InsertAction::Restore(n) => n,
}
}
}
enum Stored<H> {
New(Node<H>),
Cached(Node<H>, H),
}
pub enum ChildReference<HO> {
Hash(HO),
Inline(HO, usize),
}
struct NodeStorage<H> {
nodes: Vec<Stored<H>>,
free_indices: VecDeque<usize>,
}
impl<H> NodeStorage<H> {
fn empty() -> Self {
NodeStorage {
nodes: Vec::new(),
free_indices: VecDeque::new(),
}
}
fn alloc(&mut self, stored: Stored<H>) -> 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)
}
}
fn destroy(&mut self, handle: StorageHandle) -> Stored<H> {
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<H> {
type Output = Node<H>;
fn index(&self, handle: &'a StorageHandle) -> &Node<H> {
match self.nodes[handle.0] {
Stored::New(ref node) => node,
Stored::Cached(ref node, _) => node,
}
}
}
pub struct TrieDBMut<'a, H, C>
where
H: Hasher + 'a,
C: NodeCodec<H>
{
storage: NodeStorage<H::Out>,
db: &'a mut HashDB<H, DBValue>,
root: &'a mut H::Out,
root_handle: NodeHandle<H::Out>,
death_row: HashSet<(H::Out, NodeKey)>,
hash_count: usize,
marker: PhantomData<C>,
}
impl<'a, H, C> TrieDBMut<'a, H, C>
where
H: Hasher,
C: NodeCodec<H>
{
pub fn new(db: &'a mut HashDB<H, DBValue>, 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,
}
}
pub fn from_existing(db: &'a mut HashDB<H, DBValue>, root: &'a mut H::Out) -> Result<Self, H::Out, C::Error> {
if !db.contains(root, nibbleslice::EMPTY_ENCODED) {
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,
})
}
pub fn db(&self) -> &HashDB<H, DBValue> {
self.db
}
pub fn db_mut(&mut self) -> &mut HashDB<H, DBValue> {
self.db
}
fn cache(&mut self, hash: H::Out, key: &[u8]) -> Result<StorageHandle, H::Out, C::Error> {
let node_encoded = self.db.get(&hash, key).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash)))?;
let node = Node::from_encoded::<C, H>(
&node_encoded,
&*self.db,
&mut self.storage
);
Ok(self.storage.alloc(Stored::Cached(node, hash)))
}
fn inspect<F>(&mut self, stored: Stored<H::Out>, key: &mut Partial, inspector: F) -> Result<Option<(Stored<H::Out>, bool)>, H::Out, C::Error>
where F: FnOnce(&mut Self, Node<H::Out>, &mut Partial) -> Result<Action<H::Out>, H::Out, C::Error> {
Ok(match stored {
Stored::New(node) => match inspector(self, node, key)? {
Action::Restore(node) => Some((Stored::New(node), false)),
Action::Replace(node) => Some((Stored::New(node), true)),
Action::Delete => None,
},
Stored::Cached(node, hash) => match inspector(self, node, key)? {
Action::Restore(node) => Some((Stored::Cached(node, hash), false)),
Action::Replace(node) => {
self.death_row.insert((hash, key.encoded_prefix()));
Some((Stored::New(node), true))
}
Action::Delete => {
self.death_row.insert((hash, key.encoded_prefix()));
None
}
},
})
}
fn lookup<'x, 'key>(&'x self, mut partial: NibbleSlice<'key>, handle: &NodeHandle<H::Out>) -> Result<Option<DBValue>, H::Out, C::Error>
where 'x: 'key
{
let mut handle = handle;
loop {
let (mid, child) = match *handle {
NodeHandle::Hash(ref hash) => return Lookup {
db: &self.db,
query: DBValue::from_slice,
hash: hash.clone(),
marker: PhantomData::<C>,
}.look_up(partial),
NodeHandle::InMemory(ref handle) => match self.storage[handle] {
Node::Empty => return Ok(None),
Node::Leaf(ref key, ref value) => {
if NibbleSlice::from_encoded(key).0 == partial {
return Ok(Some(DBValue::from_slice(value)));
} else {
return Ok(None);
}
}
Node::Extension(ref slice, ref child) => {
let slice = NibbleSlice::from_encoded(slice).0;
if partial.starts_with(&slice) {
(slice.len(), child)
} else {
return Ok(None);
}
}
Node::Branch(ref children, ref value) => {
if partial.is_empty() {
return Ok(value.as_ref().map(|v| DBValue::from_slice(v)));
} else {
let idx = partial.at(0);
match children[idx as usize].as_ref() {
Some(child) => (1, child),
None => return Ok(None),
}
}
}
}
};
partial = partial.mid(mid);
handle = child;
}
}
fn insert_at(&mut self, handle: NodeHandle<H::Out>, key: &mut Partial, value: DBValue, old_val: &mut Option<DBValue>) -> Result<(StorageHandle, bool), H::Out, C::Error> {
let h = match handle {
NodeHandle::InMemory(h) => h,
NodeHandle::Hash(h) => self.cache(h, &key.encoded_prefix())?,
};
let stored = self.storage.destroy(h);
let (new_stored, changed) = self.inspect(stored, key, move |trie, stored, key| {
trie.insert_inspector(stored, key, value, old_val).map(|a| a.into_action())
})?.expect("Insertion never deletes.");
Ok((self.storage.alloc(new_stored), changed))
}
fn insert_inspector(&mut self, node: Node<H::Out>, key: &mut Partial, value: DBValue, old_val: &mut Option<DBValue>) -> Result<InsertAction<H::Out>, H::Out, C::Error> {
let partial = key.mid();
trace!(target: "trie", "augmented (partial: {:?}, value: {:#x?})", partial, value);
Ok(match node {
Node::Empty => {
trace!(target: "trie", "empty: COMPOSE");
InsertAction::Replace(Node::Leaf(partial.encoded(true), value))
}
Node::Branch(mut children, stored_value) => {
trace!(target: "trie", "branch: ROUTE,AUGMENT");
if partial.is_empty() {
let unchanged = stored_value.as_ref() == Some(&value);
let branch = Node::Branch(children, Some(value));
*old_val = stored_value;
match unchanged {
true => InsertAction::Restore(branch),
false => InsertAction::Replace(branch),
}
} else {
let idx = partial.at(0) as usize;
key.advance(1);
if let Some(child) = children[idx].take() {
let (new_child, changed) = self.insert_at(child, key, value, old_val)?;
children[idx] = Some(new_child.into());
if !changed {
return Ok(InsertAction::Restore(Node::Branch(children, stored_value)));
}
} else {
let leaf = self.storage.alloc(Stored::New(Node::Leaf(key.mid().encoded(true), value)));
children[idx] = Some(leaf.into());
}
InsertAction::Replace(Node::Branch(children, stored_value))
}
}
Node::Leaf(encoded, stored_value) => {
let existing_key = NibbleSlice::from_encoded(&encoded).0;
let cp = partial.common_prefix(&existing_key);
if cp == existing_key.len() && cp == partial.len() {
trace!(target: "trie", "equivalent-leaf: REPLACE");
let unchanged = stored_value == value;
*old_val = Some(stored_value);
match unchanged {
true => InsertAction::Restore(Node::Leaf(encoded.clone(), value)),
false => InsertAction::Replace(Node::Leaf(encoded.clone(), value)),
}
} else if cp == 0 {
trace!(target: "trie", "no-common-prefix, not-both-empty (exist={:?}; new={:?}): TRANSMUTE,AUGMENT", existing_key.len(), partial.len());
let mut children = empty_children();
let branch = if existing_key.is_empty() {
Node::Branch(children, Some(stored_value))
} else {
let idx = existing_key.at(0) as usize;
let new_leaf = Node::Leaf(existing_key.mid(1).encoded(true), stored_value);
children[idx] = Some(self.storage.alloc(Stored::New(new_leaf)).into());
Node::Branch(children, None)
};
let branch_action = self.insert_inspector(branch, key, value, old_val)?.unwrap_node();
InsertAction::Replace(branch_action)
} else if cp == existing_key.len() {
trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp);
let branch = Node::Branch(empty_children(), Some(stored_value));
key.advance(cp);
let branch = self.insert_inspector(branch, key, value, old_val)?.unwrap_node();
let branch_handle = self.storage.alloc(Stored::New(branch)).into();
InsertAction::Replace(Node::Extension(existing_key.encoded(false), branch_handle))
} else {
trace!(target: "trie", "partially-shared-prefix (exist={:?}; new={:?}; cp={:?}): AUGMENT-AT-END", existing_key.len(), partial.len(), cp);
let low = Node::Leaf(existing_key.mid(cp).encoded(true), stored_value);
key.advance(cp);
let augmented_low = self.insert_inspector(low, key, value, old_val)?.unwrap_node();
InsertAction::Replace(Node::Extension(
existing_key.encoded_leftmost(cp, false),
self.storage.alloc(Stored::New(augmented_low)).into()
))
}
}
Node::Extension(encoded, child_branch) => {
let existing_key = NibbleSlice::from_encoded(&encoded).0;
let cp = partial.common_prefix(&existing_key);
if cp == 0 {
trace!(target: "trie", "no-common-prefix, not-both-empty (exist={:?}; new={:?}): TRANSMUTE,AUGMENT", existing_key.len(), partial.len());
assert!(!existing_key.is_empty());
let idx = existing_key.at(0) as usize;
let mut children = empty_children();
children[idx] = if existing_key.len() == 1 {
Some(child_branch)
} else {
let ext = Node::Extension(existing_key.mid(1).encoded(false), child_branch);
Some(self.storage.alloc(Stored::New(ext)).into())
};
let branch_action = self.insert_inspector(Node::Branch(children, None), key, value, old_val)?.unwrap_node();
InsertAction::Replace(branch_action)
} else if cp == existing_key.len() {
trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp);
key.advance(cp);
let (new_child, changed) = self.insert_at(child_branch, key, value, old_val)?;
let new_ext = Node::Extension(existing_key.encoded(false), new_child.into());
match changed {
true => InsertAction::Replace(new_ext),
false => InsertAction::Restore(new_ext),
}
} else {
trace!(target: "trie", "partially-shared-prefix (exist={:?}; new={:?}; cp={:?}): AUGMENT-AT-END", existing_key.len(), partial.len(), cp);
let low = Node::Extension(existing_key.mid(cp).encoded(false), child_branch);
key.advance(cp);
let augmented_low = self.insert_inspector(low, key, value, old_val)?.unwrap_node();
InsertAction::Replace(Node::Extension(
existing_key.encoded_leftmost(cp, false),
self.storage.alloc(Stored::New(augmented_low)).into()
))
}
}
})
}
fn remove_at(&mut self, handle: NodeHandle<H::Out>, key: &mut Partial, old_val: &mut Option<DBValue>) -> Result<Option<(StorageHandle, bool)>, H::Out, C::Error> {
let stored = match handle {
NodeHandle::InMemory(h) => self.storage.destroy(h),
NodeHandle::Hash(h) => {
let handle = self.cache(h, &key.encoded_prefix())?;
self.storage.destroy(handle)
}
};
let opt = self.inspect(stored, key, move |trie, node, key| trie.remove_inspector(node, key, old_val))?;
Ok(opt.map(|(new, changed)| (self.storage.alloc(new), changed)))
}
fn remove_inspector(&mut self, node: Node<H::Out>, key: &mut Partial, old_val: &mut Option<DBValue>) -> Result<Action<H::Out>, H::Out, C::Error> {
let partial = key.mid();
Ok(match (node, partial.is_empty()) {
(Node::Empty, _) => Action::Delete,
(Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)),
(Node::Branch(children, Some(val)), true) => {
*old_val = Some(val);
Action::Replace(self.fix(Node::Branch(children, None), key.encoded_prefix())?)
}
(Node::Branch(mut children, value), false) => {
let idx = partial.at(0) as usize;
if let Some(child) = children[idx].take() {
trace!(target: "trie", "removing value out of branch child, partial={:?}", partial);
let prefix = key.encoded_prefix();
key.advance(1);
match self.remove_at(child, key, old_val)? {
Some((new, changed)) => {
children[idx] = Some(new.into());
let branch = Node::Branch(children, value);
match changed {
true => Action::Replace(branch),
false => Action::Restore(branch),
}
}
None => {
trace!(target: "trie", "branch child deleted, partial={:?}", partial);
Action::Replace(self.fix(Node::Branch(children, value), prefix)?)
}
}
} else {
Action::Restore(Node::Branch(children, value))
}
}
(Node::Leaf(encoded, value), _) => {
if NibbleSlice::from_encoded(&encoded).0 == partial {
*old_val = Some(value);
Action::Delete
} else {
trace!(target: "trie", "restoring leaf wrong partial, partial={:?}, existing={:?}", partial, NibbleSlice::from_encoded(&encoded).0);
Action::Restore(Node::Leaf(encoded, value))
}
}
(Node::Extension(encoded, child_branch), _) => {
let (cp, existing_len) = {
let existing_key = NibbleSlice::from_encoded(&encoded).0;
(existing_key.common_prefix(&partial), existing_key.len())
};
if cp == existing_len {
trace!(target: "trie", "removing from extension child, partial={:?}", partial);
let prefix = key.encoded_prefix();
key.advance(cp);
match self.remove_at(child_branch, key, old_val)? {
Some((new_child, changed)) => {
let new_child = new_child.into();
match changed {
true => Action::Replace(self.fix(Node::Extension(encoded, new_child), prefix)?),
false => Action::Restore(Node::Extension(encoded, new_child)),
}
}
None => {
Action::Delete
}
}
} else {
Action::Restore(Node::Extension(encoded, child_branch))
}
}
})
}
fn fix(&mut self, node: Node<H::Out>, key: NodeKey) -> Result<Node<H::Out>, H::Out, C::Error> {
match node {
Node::Branch(mut children, value) => {
#[derive(Debug)]
enum UsedIndex {
None,
One(u8),
Many,
};
let mut used_index = UsedIndex::None;
for i in 0..16 {
match (children[i].is_none(), &used_index) {
(false, &UsedIndex::None) => used_index = UsedIndex::One(i as u8),
(false, &UsedIndex::One(_)) => {
used_index = UsedIndex::Many;
break;
}
_ => continue,
}
}
match (used_index, value) {
(UsedIndex::None, None) => panic!("Branch with no subvalues. Something went wrong."),
(UsedIndex::One(a), None) => {
let new_partial = NibbleSlice::new_offset(&[a], 1).encoded(false);
let child = children[a as usize].take().expect("used_index only set if occupied; qed");
let new_node = Node::Extension(new_partial, child);
self.fix(new_node, key)
}
(UsedIndex::None, Some(value)) => {
trace!(target: "trie", "fixing: branch -> leaf");
Ok(Node::Leaf(NibbleSlice::new(&[]).encoded(true), value))
}
(_, value) => {
trace!(target: "trie", "fixing: restoring branch");
Ok(Node::Branch(children, value))
}
}
}
Node::Extension(partial, child) => {
let stored = match child {
NodeHandle::InMemory(h) => self.storage.destroy(h),
NodeHandle::Hash(h) => {
let handle = self.cache(h, &combine_encoded(&key, &partial))?;
self.storage.destroy(handle)
}
};
let (child_node, maybe_hash) = match stored {
Stored::New(node) => (node, None),
Stored::Cached(node, hash) => (node, Some(hash))
};
match child_node {
Node::Extension(sub_partial, sub_child) => {
if let Some(hash) = maybe_hash {
self.death_row.insert((hash, key.clone()));
}
let partial = NibbleSlice::from_encoded(&partial).0;
let sub_partial = NibbleSlice::from_encoded(&sub_partial).0;
let new_partial = NibbleSlice::new_composed(&partial, &sub_partial);
trace!(target: "trie", "fixing: extension combination. new_partial={:?}", new_partial);
let new_partial = new_partial.encoded(false);
self.fix(Node::Extension(new_partial, sub_child), key)
}
Node::Leaf(sub_partial, value) => {
if let Some(hash) = maybe_hash {
self.death_row.insert((hash, key));
}
let partial = NibbleSlice::from_encoded(&partial).0;
let sub_partial = NibbleSlice::from_encoded(&sub_partial).0;
let new_partial = NibbleSlice::new_composed(&partial, &sub_partial);
trace!(target: "trie", "fixing: extension -> leaf. new_partial={:?}", new_partial);
Ok(Node::Leaf(new_partial.encoded(true), value))
}
child_node => {
trace!(target: "trie", "fixing: restoring extension");
let stored = if let Some(hash) = maybe_hash {
Stored::Cached(child_node, hash)
} else {
Stored::New(child_node)
};
Ok(Node::Extension(partial, self.storage.alloc(stored).into()))
}
}
}
other => Ok(other),
}
}
pub fn commit(&mut self) {
trace!(target: "trie", "Committing trie changes to db.");
trace!(target: "trie", "{:?} nodes to remove from db", self.death_row.len());
for (hash, prefix) in self.death_row.drain() {
self.db.remove(&hash, &prefix);
}
let handle = match self.root_handle() {
NodeHandle::Hash(_) => return,
NodeHandle::InMemory(h) => h,
};
match self.storage.destroy(handle) {
Stored::New(node) => {
let encoded_root = node.into_encoded::<_, C, H>(|child, k| {
let combined = combine_encoded(nibbleslice::EMPTY_ENCODED, k);
self.commit_child(child, &combined)
});
trace!(target: "trie", "encoded root node: {:#x?}", &encoded_root[..]);
*self.root = self.db.insert(nibbleslice::EMPTY_ENCODED, &encoded_root[..]);
self.hash_count += 1;
self.root_handle = NodeHandle::Hash(*self.root);
}
Stored::Cached(node, hash) => {
*self.root = hash;
self.root_handle = NodeHandle::InMemory(self.storage.alloc(Stored::Cached(node, hash)));
}
}
}
fn commit_child(&mut self, handle: NodeHandle<H::Out>, prefix: &NodeKey) -> ChildReference<H::Out> {
match handle {
NodeHandle::Hash(hash) => ChildReference::Hash(hash),
NodeHandle::InMemory(storage_handle) => {
match self.storage.destroy(storage_handle) {
Stored::Cached(_, hash) => ChildReference::Hash(hash),
Stored::New(node) => {
let encoded = {
let commit_child = |node_handle, partial: &NodeKey| {
let combined = combine_encoded(&prefix, partial);
self.commit_child(node_handle, &combined)
};
node.into_encoded::<_, C, H>(commit_child)
};
if encoded.len() >= H::LENGTH {
let hash = self.db.insert(&prefix, &encoded[..]);
self.hash_count +=1;
ChildReference::Hash(hash)
} else {
let mut h = H::Out::default();
let len = encoded.len();
h.as_mut()[..len].copy_from_slice(&encoded[..len]);
ChildReference::Inline(h, len)
}
}
}
}
}
}
fn root_handle(&self) -> NodeHandle<H::Out> {
match self.root_handle {
NodeHandle::Hash(h) => NodeHandle::Hash(h),
NodeHandle::InMemory(StorageHandle(x)) => NodeHandle::InMemory(StorageHandle(x)),
}
}
}
impl<'a, H, C> TrieMut<H, C> for TrieDBMut<'a, H, C>
where
H: Hasher,
C: NodeCodec<H>
{
fn root(&mut self) -> &H::Out {
self.commit();
self.root
}
fn is_empty(&self) -> bool {
match self.root_handle {
NodeHandle::Hash(h) => h == C::hashed_null_node(),
NodeHandle::InMemory(ref h) => match self.storage[h] {
Node::Empty => true,
_ => false,
}
}
}
fn get<'x, 'key>(&'x self, key: &'key [u8]) -> Result<Option<DBValue>, H::Out, C::Error>
where 'x: 'key
{
self.lookup(NibbleSlice::new(key), &self.root_handle)
}
fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<Option<DBValue>, H::Out, C::Error> {
if value.is_empty() { return self.remove(key) }
let mut old_val = None;
trace!(target: "trie", "insert: key={:#x?}, value={:#x?}", key, value);
let root_handle = self.root_handle();
let (new_handle, changed) = self.insert_at(
root_handle,
&mut Partial::new(NibbleSlice::new(key)),
DBValue::from_slice(value),
&mut old_val,
)?;
trace!(target: "trie", "insert: altered trie={}", changed);
self.root_handle = NodeHandle::InMemory(new_handle);
Ok(old_val)
}
fn remove(&mut self, key: &[u8]) -> Result<Option<DBValue>, H::Out, C::Error> {
trace!(target: "trie", "remove: key={:#x?}", key);
let root_handle = self.root_handle();
let mut key = Partial::new(NibbleSlice::new(key));
let mut old_val = None;
match self.remove_at(root_handle, &mut key, &mut old_val)? {
Some((handle, changed)) => {
trace!(target: "trie", "remove: altered trie={}", changed);
self.root_handle = NodeHandle::InMemory(handle);
}
None => {
trace!(target: "trie", "remove: obliterated trie");
self.root_handle = NodeHandle::Hash(C::hashed_null_node());
*self.root = C::hashed_null_node();
}
}
Ok(old_val)
}
}
impl<'a, H, C> Drop for TrieDBMut<'a, H, C>
where
H: Hasher,
C: NodeCodec<H>
{
fn drop(&mut self) {
self.commit();
}
}
#[cfg(test)]
mod tests {
use env_logger;
use standardmap::*;
use DBValue;
use memory_db::{MemoryDB, PrefixedKey};
use hash_db::{Hasher, HashDB};
use keccak_hasher::KeccakHasher;
use reference_trie::{RefTrieDBMut, TrieMut, NodeCodec,
ReferenceNodeCodec, ref_trie_root};
fn populate_trie<'db>(
db: &'db mut HashDB<KeccakHasher, DBValue>,
root: &'db mut <KeccakHasher as Hasher>::Out,
v: &[(Vec<u8>, Vec<u8>)]
) -> RefTrieDBMut<'db> {
let mut t = RefTrieDBMut::new(db, root);
for i in 0..v.len() {
let key: &[u8]= &v[i].0;
let val: &[u8] = &v[i].1;
t.insert(key, val).unwrap();
}
t
}
fn unpopulate_trie<'db>(t: &mut RefTrieDBMut<'db>, v: &[(Vec<u8>, Vec<u8>)]) {
for i in v {
let key: &[u8]= &i.0;
t.remove(key).unwrap();
}
}
#[test]
fn playpen() {
env_logger::init();
let mut seed = Default::default();
for test_i in 0..10 {
if test_i % 50 == 0 {
debug!("{:?} of 10000 stress tests done", test_i);
}
let x = StandardMap {
alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()),
min_key: 5,
journal_key: 0,
value_mode: ValueMode::Index,
count: 100,
}.make_with(&mut seed);
let real = ref_trie_root(x.clone());
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut memtrie = populate_trie(&mut memdb, &mut root, &x);
memtrie.commit();
if *memtrie.root() != real {
println!("TRIE MISMATCH");
println!("");
println!("{:?} vs {:?}", memtrie.root(), real);
for i in &x {
println!("{:#x?} -> {:#x?}", i.0, i.1);
}
}
assert_eq!(*memtrie.root(), real);
unpopulate_trie(&mut memtrie, &x);
memtrie.commit();
if *memtrie.root() != ReferenceNodeCodec::hashed_null_node() {
println!("- TRIE MISMATCH");
println!("");
println!("{:#x?} vs {:#x?}", memtrie.root(), ReferenceNodeCodec::hashed_null_node());
for i in &x {
println!("{:#x?} -> {:#x?}", i.0, i.1);
}
}
assert_eq!(*memtrie.root(), ReferenceNodeCodec::hashed_null_node());
}
}
#[test]
fn init() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
assert_eq!(*t.root(), ReferenceNodeCodec::hashed_null_node());
}
#[test]
fn insert_on_empty() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ]));
}
#[test]
fn remove_to_empty() {
let big_value = b"00000000000000000000000000000000";
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t1 = RefTrieDBMut::new(&mut memdb, &mut root);
t1.insert(&[0x01, 0x23], big_value).unwrap();
t1.insert(&[0x01, 0x34], big_value).unwrap();
let mut memdb2 = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root2 = Default::default();
let mut t2 = RefTrieDBMut::new(&mut memdb2, &mut root2);
t2.insert(&[0x01], big_value).unwrap();
t2.insert(&[0x01, 0x23], big_value).unwrap();
t2.insert(&[0x01, 0x34], big_value).unwrap();
t2.remove(&[0x01]).unwrap();
}
#[test]
fn insert_replace_root() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ]));
}
#[test]
fn insert_make_branch_root() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x11u8, 0x23], vec![0x11u8, 0x23])
]));
}
#[test]
fn insert_into_branch_root() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap();
t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
]));
}
#[test]
fn insert_value_into_branch_root() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[], &[0x0]).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![
(vec![], vec![0x0]),
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
]));
}
#[test]
fn insert_split_leaf() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x01u8, 0x34], vec![0x01u8, 0x34]),
]));
}
#[test]
fn insert_split_extenstion() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01, 0x23, 0x45], &[0x01]).unwrap();
t.insert(&[0x01, 0xf3, 0x45], &[0x02]).unwrap();
t.insert(&[0x01, 0xf3, 0xf5], &[0x03]).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![
(vec![0x01, 0x23, 0x45], vec![0x01]),
(vec![0x01, 0xf3, 0x45], vec![0x02]),
(vec![0x01, 0xf3, 0xf5], vec![0x03]),
]));
}
#[test]
fn insert_big_value() {
let big_value0 = b"00000000000000000000000000000000";
let big_value1 = b"11111111111111111111111111111111";
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], big_value0).unwrap();
t.insert(&[0x11u8, 0x23], big_value1).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![
(vec![0x01u8, 0x23], big_value0.to_vec()),
(vec![0x11u8, 0x23], big_value1.to_vec())
]));
}
#[test]
fn insert_duplicate_value() {
let big_value = b"00000000000000000000000000000000";
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], big_value).unwrap();
t.insert(&[0x11u8, 0x23], big_value).unwrap();
assert_eq!(*t.root(), ref_trie_root(vec![
(vec![0x01u8, 0x23], big_value.to_vec()),
(vec![0x11u8, 0x23], big_value.to_vec())
]));
}
#[test]
fn test_at_empty() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let t = RefTrieDBMut::new(&mut memdb, &mut root);
assert_eq!(t.get(&[0x5]).unwrap(), None);
}
#[test]
fn test_at_one() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x1u8, 0x23]));
t.commit();
assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x1u8, 0x23]));
}
#[test]
fn test_at_three() {
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap();
t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap();
assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23]));
assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0xf1u8, 0x23]));
assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x81u8, 0x23]));
assert_eq!(t.get(&[0x82, 0x23]).unwrap(), None);
t.commit();
assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23]));
assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0xf1u8, 0x23]));
assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x81u8, 0x23]));
assert_eq!(t.get(&[0x82, 0x23]).unwrap(), None);
}
#[test]
fn stress() {
let mut seed = Default::default();
for _ in 0..50 {
let x = StandardMap {
alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()),
min_key: 5,
journal_key: 0,
value_mode: ValueMode::Index,
count: 4,
}.make_with(&mut seed);
let real = ref_trie_root(x.clone());
let mut memdb = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut memtrie = populate_trie(&mut memdb, &mut root, &x);
let mut y = x.clone();
y.sort_by(|ref a, ref b| a.0.cmp(&b.0));
let mut memdb2 = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root2 = Default::default();
let mut memtrie_sorted = populate_trie(&mut memdb2, &mut root2, &y);
if *memtrie.root() != real || *memtrie_sorted.root() != real {
println!("TRIE MISMATCH");
println!("");
println!("ORIGINAL... {:#x?}", memtrie.root());
for i in &x {
println!("{:#x?} -> {:#x?}", i.0, i.1);
}
println!("SORTED... {:#x?}", memtrie_sorted.root());
for i in &y {
println!("{:#x?} -> {:#x?}", i.0, i.1);
}
}
assert_eq!(*memtrie.root(), real);
assert_eq!(*memtrie_sorted.root(), real);
}
}
#[test]
fn test_trie_existing() {
let mut db = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
{
let mut t = RefTrieDBMut::new(&mut db, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap();
}
{
let _ = RefTrieDBMut::from_existing(&mut db, &mut root);
}
}
#[test]
fn insert_empty() {
let mut seed = Default::default();
let x = StandardMap {
alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()),
min_key: 5,
journal_key: 0,
value_mode: ValueMode::Index,
count: 4,
}.make_with(&mut seed);
let mut db = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut db, &mut root);
for &(ref key, ref value) in &x {
t.insert(key, value).unwrap();
}
assert_eq!(*t.root(), ref_trie_root(x.clone()));
for &(ref key, _) in &x {
t.insert(key, &[]).unwrap();
}
assert!(t.is_empty());
assert_eq!(*t.root(), ReferenceNodeCodec::hashed_null_node());
}
#[test]
fn return_old_values() {
let mut seed = Default::default();
let x = StandardMap {
alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()),
min_key: 5,
journal_key: 0,
value_mode: ValueMode::Index,
count: 4,
}.make_with(&mut seed);
let mut db = MemoryDB::<KeccakHasher, PrefixedKey<_>, DBValue>::default();
let mut root = Default::default();
let mut t = RefTrieDBMut::new(&mut db, &mut root);
for &(ref key, ref value) in &x {
assert!(t.insert(key, value).unwrap().is_none());
assert_eq!(t.insert(key, value).unwrap(), Some(DBValue::from_slice(value)));
}
for (key, value) in x {
assert_eq!(t.remove(&key).unwrap(), Some(DBValue::from_slice(&value)));
assert!(t.remove(&key).unwrap().is_none());
}
}
}