Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

snapshot: single byte for empty accounts #2625

Merged
merged 1 commit into from
Oct 14, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions ethcore/src/snapshot/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 = {
Expand Down Expand Up @@ -214,7 +231,7 @@ mod tests {

use std::collections::{HashSet, HashMap};

use super::Account;
use super::{ACC_EMPTY, Account};

#[test]
fn encoding_basic() {
Expand Down Expand Up @@ -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));
}
}