From 23fbe394081cdde8f8460cf32c40959d48c2f5fa Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 15 Jan 2016 04:02:24 +0100 Subject: [PATCH] Fix for assumption that empty trie root RLP can always be looked up. --- src/hash.rs | 1 - src/memorydb.rs | 31 +++++++++++++++++++++++++++---- src/trie/triedb.rs | 2 +- src/trie/triedbmut.rs | 12 +++++------- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/hash.rs b/src/hash.rs index c17b706db..8c1772b2c 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -195,7 +195,6 @@ macro_rules! impl_hash { fn from_json(json: &Json) -> Self { match json { &Json::String(ref s) => { - println!("s: {}", s); match s.len() % 2 { 0 => FromStr::from_str(clean_0x(s)).unwrap(), _ => FromStr::from_str(&("0".to_string() + &(clean_0x(s).to_string()))[..]).unwrap() diff --git a/src/memorydb.rs b/src/memorydb.rs index 680129670..6f2b2e603 100644 --- a/src/memorydb.rs +++ b/src/memorydb.rs @@ -2,6 +2,7 @@ use hash::*; use bytes::*; +use rlp::*; use sha3::*; use hashdb::*; use std::mem; @@ -53,13 +54,15 @@ use std::collections::HashMap; /// ``` pub struct MemoryDB { data: HashMap, + static_null_rlp: (Bytes, i32), } impl MemoryDB { /// Create a new instance of the memory DB. pub fn new() -> MemoryDB { MemoryDB { - data: HashMap::new() + data: HashMap::new(), + static_null_rlp: (vec![0x80u8; 1], 1), } } @@ -98,6 +101,9 @@ impl MemoryDB { /// Even when Some is returned, the data is only guaranteed to be useful /// when the refs > 0. pub fn raw(&self, key: &H256) -> Option<&(Bytes, i32)> { + if key == &SHA3_NULL_RLP { + return Some(&self.static_null_rlp); + } self.data.get(key) } @@ -108,18 +114,23 @@ impl MemoryDB { } pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) { - if self.data.get(&key) == None { + if self.raw(key) == None { unsafe { let p = &self.data as *const HashMap as *mut HashMap; (*p).insert(key.clone(), (value, 0)); } } - self.data.get(key).unwrap() + self.raw(key).unwrap() } } +static NULL_RLP_STATIC: [u8; 1] = [0x80; 1]; + impl HashDB for MemoryDB { fn lookup(&self, key: &H256) -> Option<&[u8]> { + if key == &SHA3_NULL_RLP { + return Some(&NULL_RLP_STATIC); + } match self.data.get(key) { Some(&(ref d, rc)) if rc > 0 => Some(d), _ => None @@ -127,10 +138,13 @@ impl HashDB for MemoryDB { } fn keys(&self) -> HashMap { - self.data.iter().filter_map(|(k, v)| if v.1 != 0 {Some((k.clone(), v.1))} else {None}).collect::>() + self.data.iter().filter_map(|(k, v)| if v.1 != 0 {Some((k.clone(), v.1))} else {None}).collect() } fn exists(&self, key: &H256) -> bool { + if key == &SHA3_NULL_RLP { + return true; + } match self.data.get(key) { Some(&(_, x)) if x > 0 => true, _ => false @@ -138,6 +152,9 @@ impl HashDB for MemoryDB { } fn insert(&mut self, value: &[u8]) -> H256 { + if value == &NULL_RLP { + return SHA3_NULL_RLP.clone(); + } let key = value.sha3(); if match self.data.get_mut(&key) { Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => { @@ -154,6 +171,9 @@ impl HashDB for MemoryDB { } fn emplace(&mut self, key: H256, value: Bytes) { + if value == &NULL_RLP { + return; + } match self.data.get_mut(&key) { Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => { *old_value = value; @@ -168,6 +188,9 @@ impl HashDB for MemoryDB { } fn kill(&mut self, key: &H256) { + if key == &SHA3_NULL_RLP { + return; + } if match self.data.get_mut(key) { Some(&mut (_, ref mut x)) => { *x -= 1; false } None => true diff --git a/src/trie/triedb.rs b/src/trie/triedb.rs index ef07fd47d..862bbb96c 100644 --- a/src/trie/triedb.rs +++ b/src/trie/triedb.rs @@ -81,7 +81,7 @@ impl<'db> TrieDB<'db> { let mut ret = self.db.keys(); for (k, v) in Self::to_map(self.keys()).into_iter() { let keycount = *ret.get(&k).unwrap_or(&0); - match keycount == v as i32 { + match keycount <= v as i32 { true => ret.remove(&k), _ => ret.insert(k, keycount - v as i32), }; diff --git a/src/trie/triedbmut.rs b/src/trie/triedbmut.rs index d205dc8e0..c6f47fa5e 100644 --- a/src/trie/triedbmut.rs +++ b/src/trie/triedbmut.rs @@ -64,16 +64,13 @@ impl<'db> TrieDBMut<'db> { }; // set root rlp - *r.root = r.db.insert(&NULL_RLP); + *r.root = SHA3_NULL_RLP.clone(); r } /// Create a new trie with the backing database `db` and `root` /// Panics, if `root` does not exist pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self { - if !db.exists(root) && root == &SHA3_NULL_RLP { - *root = db.insert(&NULL_RLP); - } assert!(db.exists(root)); TrieDBMut { db: db, @@ -111,7 +108,7 @@ impl<'db> TrieDBMut<'db> { let mut ret = self.db.keys(); for (k, v) in Self::to_map(self.keys()).into_iter() { let keycount = *ret.get(&k).unwrap_or(&0); - match keycount == v as i32 { + match keycount <= v as i32 { true => ret.remove(&k), _ => ret.insert(k, keycount - v as i32), }; @@ -771,8 +768,9 @@ mod tests { assert!(memtrie.db_items_remaining().is_empty()); unpopulate_trie(&mut memtrie, &x); if *memtrie.root() != SHA3_NULL_RLP || !memtrie.db_items_remaining().is_empty() { - println!("TRIE MISMATCH"); + println!("- TRIE MISMATCH"); println!(""); + println!("remaining: {:?}", memtrie.db_items_remaining()); println!("{:?} vs {:?}", memtrie.root(), real); for i in x.iter() { println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); @@ -811,7 +809,7 @@ mod tests { let mut t1 = TrieDBMut::new(&mut memdb, &mut root); t1.insert(&[0x01, 0x23], &big_value.to_vec()); t1.insert(&[0x01, 0x34], &big_value.to_vec()); - trace!("keys remaining {:?}", t1.db_items_remaining()); + println!("********************** keys remaining {:?}", t1.db_items_remaining()); assert!(t1.db_items_remaining().is_empty()); let mut memdb2 = MemoryDB::new(); let mut root2 = H256::new();