Fix for assumption that empty trie root RLP can always be looked up.
This commit is contained in:
parent
ab399badf6
commit
23fbe39408
@ -195,7 +195,6 @@ macro_rules! impl_hash {
|
|||||||
fn from_json(json: &Json) -> Self {
|
fn from_json(json: &Json) -> Self {
|
||||||
match json {
|
match json {
|
||||||
&Json::String(ref s) => {
|
&Json::String(ref s) => {
|
||||||
println!("s: {}", s);
|
|
||||||
match s.len() % 2 {
|
match s.len() % 2 {
|
||||||
0 => FromStr::from_str(clean_0x(s)).unwrap(),
|
0 => FromStr::from_str(clean_0x(s)).unwrap(),
|
||||||
_ => FromStr::from_str(&("0".to_string() + &(clean_0x(s).to_string()))[..]).unwrap()
|
_ => FromStr::from_str(&("0".to_string() + &(clean_0x(s).to_string()))[..]).unwrap()
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use hash::*;
|
use hash::*;
|
||||||
use bytes::*;
|
use bytes::*;
|
||||||
|
use rlp::*;
|
||||||
use sha3::*;
|
use sha3::*;
|
||||||
use hashdb::*;
|
use hashdb::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@ -53,13 +54,15 @@ use std::collections::HashMap;
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct MemoryDB {
|
pub struct MemoryDB {
|
||||||
data: HashMap<H256, (Bytes, i32)>,
|
data: HashMap<H256, (Bytes, i32)>,
|
||||||
|
static_null_rlp: (Bytes, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryDB {
|
impl MemoryDB {
|
||||||
/// Create a new instance of the memory DB.
|
/// Create a new instance of the memory DB.
|
||||||
pub fn new() -> MemoryDB {
|
pub fn new() -> MemoryDB {
|
||||||
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
|
/// Even when Some is returned, the data is only guaranteed to be useful
|
||||||
/// when the refs > 0.
|
/// when the refs > 0.
|
||||||
pub fn raw(&self, key: &H256) -> Option<&(Bytes, i32)> {
|
pub fn raw(&self, key: &H256) -> Option<&(Bytes, i32)> {
|
||||||
|
if key == &SHA3_NULL_RLP {
|
||||||
|
return Some(&self.static_null_rlp);
|
||||||
|
}
|
||||||
self.data.get(key)
|
self.data.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,18 +114,23 @@ impl MemoryDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) {
|
pub fn denote(&self, key: &H256, value: Bytes) -> &(Bytes, i32) {
|
||||||
if self.data.get(&key) == None {
|
if self.raw(key) == None {
|
||||||
unsafe {
|
unsafe {
|
||||||
let p = &self.data as *const HashMap<H256, (Bytes, i32)> as *mut HashMap<H256, (Bytes, i32)>;
|
let p = &self.data as *const HashMap<H256, (Bytes, i32)> as *mut HashMap<H256, (Bytes, i32)>;
|
||||||
(*p).insert(key.clone(), (value, 0));
|
(*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 {
|
impl HashDB for MemoryDB {
|
||||||
fn lookup(&self, key: &H256) -> Option<&[u8]> {
|
fn lookup(&self, key: &H256) -> Option<&[u8]> {
|
||||||
|
if key == &SHA3_NULL_RLP {
|
||||||
|
return Some(&NULL_RLP_STATIC);
|
||||||
|
}
|
||||||
match self.data.get(key) {
|
match self.data.get(key) {
|
||||||
Some(&(ref d, rc)) if rc > 0 => Some(d),
|
Some(&(ref d, rc)) if rc > 0 => Some(d),
|
||||||
_ => None
|
_ => None
|
||||||
@ -127,10 +138,13 @@ impl HashDB for MemoryDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn keys(&self) -> HashMap<H256, i32> {
|
fn keys(&self) -> HashMap<H256, i32> {
|
||||||
self.data.iter().filter_map(|(k, v)| if v.1 != 0 {Some((k.clone(), v.1))} else {None}).collect::<HashMap<H256, i32>>()
|
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 {
|
fn exists(&self, key: &H256) -> bool {
|
||||||
|
if key == &SHA3_NULL_RLP {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
match self.data.get(key) {
|
match self.data.get(key) {
|
||||||
Some(&(_, x)) if x > 0 => true,
|
Some(&(_, x)) if x > 0 => true,
|
||||||
_ => false
|
_ => false
|
||||||
@ -138,6 +152,9 @@ impl HashDB for MemoryDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, value: &[u8]) -> H256 {
|
fn insert(&mut self, value: &[u8]) -> H256 {
|
||||||
|
if value == &NULL_RLP {
|
||||||
|
return SHA3_NULL_RLP.clone();
|
||||||
|
}
|
||||||
let key = value.sha3();
|
let key = value.sha3();
|
||||||
if match self.data.get_mut(&key) {
|
if match self.data.get_mut(&key) {
|
||||||
Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => {
|
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) {
|
fn emplace(&mut self, key: H256, value: Bytes) {
|
||||||
|
if value == &NULL_RLP {
|
||||||
|
return;
|
||||||
|
}
|
||||||
match self.data.get_mut(&key) {
|
match self.data.get_mut(&key) {
|
||||||
Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => {
|
Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => {
|
||||||
*old_value = value;
|
*old_value = value;
|
||||||
@ -168,6 +188,9 @@ impl HashDB for MemoryDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn kill(&mut self, key: &H256) {
|
fn kill(&mut self, key: &H256) {
|
||||||
|
if key == &SHA3_NULL_RLP {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if match self.data.get_mut(key) {
|
if match self.data.get_mut(key) {
|
||||||
Some(&mut (_, ref mut x)) => { *x -= 1; false }
|
Some(&mut (_, ref mut x)) => { *x -= 1; false }
|
||||||
None => true
|
None => true
|
||||||
|
@ -81,7 +81,7 @@ impl<'db> TrieDB<'db> {
|
|||||||
let mut ret = self.db.keys();
|
let mut ret = self.db.keys();
|
||||||
for (k, v) in Self::to_map(self.keys()).into_iter() {
|
for (k, v) in Self::to_map(self.keys()).into_iter() {
|
||||||
let keycount = *ret.get(&k).unwrap_or(&0);
|
let keycount = *ret.get(&k).unwrap_or(&0);
|
||||||
match keycount == v as i32 {
|
match keycount <= v as i32 {
|
||||||
true => ret.remove(&k),
|
true => ret.remove(&k),
|
||||||
_ => ret.insert(k, keycount - v as i32),
|
_ => ret.insert(k, keycount - v as i32),
|
||||||
};
|
};
|
||||||
|
@ -64,16 +64,13 @@ impl<'db> TrieDBMut<'db> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// set root rlp
|
// set root rlp
|
||||||
*r.root = r.db.insert(&NULL_RLP);
|
*r.root = SHA3_NULL_RLP.clone();
|
||||||
r
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new trie with the backing database `db` and `root`
|
/// Create a new trie with the backing database `db` and `root`
|
||||||
/// Panics, if `root` does not exist
|
/// Panics, if `root` does not exist
|
||||||
pub fn from_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
|
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));
|
assert!(db.exists(root));
|
||||||
TrieDBMut {
|
TrieDBMut {
|
||||||
db: db,
|
db: db,
|
||||||
@ -111,7 +108,7 @@ impl<'db> TrieDBMut<'db> {
|
|||||||
let mut ret = self.db.keys();
|
let mut ret = self.db.keys();
|
||||||
for (k, v) in Self::to_map(self.keys()).into_iter() {
|
for (k, v) in Self::to_map(self.keys()).into_iter() {
|
||||||
let keycount = *ret.get(&k).unwrap_or(&0);
|
let keycount = *ret.get(&k).unwrap_or(&0);
|
||||||
match keycount == v as i32 {
|
match keycount <= v as i32 {
|
||||||
true => ret.remove(&k),
|
true => ret.remove(&k),
|
||||||
_ => ret.insert(k, keycount - v as i32),
|
_ => ret.insert(k, keycount - v as i32),
|
||||||
};
|
};
|
||||||
@ -771,8 +768,9 @@ mod tests {
|
|||||||
assert!(memtrie.db_items_remaining().is_empty());
|
assert!(memtrie.db_items_remaining().is_empty());
|
||||||
unpopulate_trie(&mut memtrie, &x);
|
unpopulate_trie(&mut memtrie, &x);
|
||||||
if *memtrie.root() != SHA3_NULL_RLP || !memtrie.db_items_remaining().is_empty() {
|
if *memtrie.root() != SHA3_NULL_RLP || !memtrie.db_items_remaining().is_empty() {
|
||||||
println!("TRIE MISMATCH");
|
println!("- TRIE MISMATCH");
|
||||||
println!("");
|
println!("");
|
||||||
|
println!("remaining: {:?}", memtrie.db_items_remaining());
|
||||||
println!("{:?} vs {:?}", memtrie.root(), real);
|
println!("{:?} vs {:?}", memtrie.root(), real);
|
||||||
for i in x.iter() {
|
for i in x.iter() {
|
||||||
println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty());
|
println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty());
|
||||||
@ -811,7 +809,7 @@ mod tests {
|
|||||||
let mut t1 = TrieDBMut::new(&mut memdb, &mut root);
|
let mut t1 = TrieDBMut::new(&mut memdb, &mut root);
|
||||||
t1.insert(&[0x01, 0x23], &big_value.to_vec());
|
t1.insert(&[0x01, 0x23], &big_value.to_vec());
|
||||||
t1.insert(&[0x01, 0x34], &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());
|
assert!(t1.db_items_remaining().is_empty());
|
||||||
let mut memdb2 = MemoryDB::new();
|
let mut memdb2 = MemoryDB::new();
|
||||||
let mut root2 = H256::new();
|
let mut root2 = H256::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user