snapshot: single byte for empty accounts (#2625)

This commit is contained in:
Robert Habermeier 2016-10-14 14:45:45 +02:00 committed by Gav Wood
parent f28b8352c1
commit 8263bd4be2
1 changed files with 29 additions and 2 deletions

View File

@ -19,12 +19,20 @@
use account_db::{AccountDB, AccountDBMut};
use snapshot::Error;
use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY};
use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY, SHA3_NULL_RLP};
use util::trie::{TrieDB, Trie};
use rlp::{Rlp, RlpStream, Stream, UntrustedRlp, View};
use std::collections::{HashMap, HashSet};
// An empty account -- these are replaced with RLP null data for a space optimization.
const ACC_EMPTY: Account = Account {
nonce: U256([0, 0, 0, 0]),
balance: U256([0, 0, 0, 0]),
storage_root: SHA3_NULL_RLP,
code_hash: SHA3_EMPTY,
};
// whether an encoded account has code and how it is referred to.
#[repr(u8)]
enum CodeState {
@ -88,6 +96,10 @@ impl Account {
// walk the account's storage trie, returning an RLP item containing the
// account properties and the storage.
pub fn to_fat_rlp(&self, acct_db: &AccountDB, used_code: &mut HashSet<H256>) -> Result<Bytes, Error> {
if self == &ACC_EMPTY {
return Ok(::rlp::NULL_RLP.to_vec());
}
let db = try!(TrieDB::new(acct_db, &self.storage_root));
let mut pairs = Vec::new();
@ -142,6 +154,11 @@ impl Account {
) -> Result<(Self, Option<Bytes>), Error> {
use util::{TrieDBMut, TrieMut};
// check for special case of empty account.
if rlp.is_empty() {
return Ok((ACC_EMPTY, None));
}
let nonce = try!(rlp.val_at(0));
let balance = try!(rlp.val_at(1));
let code_state: CodeState = {
@ -214,7 +231,7 @@ mod tests {
use std::collections::{HashSet, HashMap};
use super::Account;
use super::{ACC_EMPTY, Account};
#[test]
fn encoding_basic() {
@ -310,4 +327,14 @@ mod tests {
assert_eq!(maybe_code, Some(b"this is definitely code".to_vec()));
assert_eq!(acc, account1);
}
#[test]
fn encoding_empty_acc() {
let mut db = get_temp_state_db();
let mut used_code = HashSet::new();
let code_map = HashMap::new();
assert_eq!(ACC_EMPTY.to_fat_rlp(&AccountDB::new(db.as_hashdb(), &Address::default()), &mut used_code).unwrap(), ::rlp::NULL_RLP.to_vec());
assert_eq!(Account::from_fat_rlp(&mut AccountDBMut::new(db.as_hashdb_mut(), &Address::default()), UntrustedRlp::new(&::rlp::NULL_RLP), &code_map).unwrap(), (ACC_EMPTY, None));
}
}