diff --git a/src/account.rs b/src/account.rs index 16b621bb8..8a51d9b97 100644 --- a/src/account.rs +++ b/src/account.rs @@ -3,26 +3,14 @@ use util::*; pub const SHA3_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] ); #[derive(Debug)] -/// Genesis account data. Does no thave a DB overlay cache +/// Genesis account data. Does not have a DB overlay cache. pub struct PodAccount { // Balance of the account. pub balance: U256, // Nonce of the account. pub nonce: U256, pub code: Bytes, - pub storage: HashMap, -} - -impl PodAccount { - pub fn rlp(&self) -> Bytes { - let mut stream = RlpStream::new_list(4); - stream.append(&self.nonce); - stream.append(&self.balance); - // TODO. - stream.append(&SHA3_NULL_RLP); - stream.append(&self.code.sha3()); - stream.out() - } + pub storage: BTreeMap, } /// Single account in the system. @@ -42,6 +30,29 @@ pub struct Account { code_cache: Bytes, } +impl PodAccount { + /// Convert Account to a PodAccount. + /// NOTE: This will silently fail unless the account is fully cached. + pub fn from_account(acc: &Account) -> PodAccount { + PodAccount { + balance: acc.balance.clone(), + nonce: acc.nonce.clone(), + storage: acc.storage_overlay.borrow().iter().fold(BTreeMap::new(), |mut m, (k, v)| {m.insert(k.clone(), v.clone()); m}), + code: acc.code_cache.clone() + } + } + + pub fn rlp(&self) -> Bytes { + let mut stream = RlpStream::new_list(4); + stream.append(&self.nonce); + stream.append(&self.balance); + // TODO. + stream.append(&SHA3_NULL_RLP); + stream.append(&self.code.sha3()); + stream.out() + } +} + impl Account { /// General constructor. pub fn new(balance: U256, nonce: U256, storage: HashMap, code: Bytes) -> Account { @@ -61,7 +72,7 @@ impl Account { balance: pod.balance, nonce: pod.nonce, storage_root: SHA3_NULL_RLP, - storage_overlay: RefCell::new(pod.storage), + storage_overlay: RefCell::new(pod.storage.into_iter().fold(HashMap::new(), |mut m, (k, v)| {m.insert(k, v); m})), code_hash: Some(pod.code.sha3()), code_cache: pod.code } @@ -242,7 +253,7 @@ impl Account { impl fmt::Debug for Account { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", PodAccount{balance: self.balance.clone(), nonce: self.nonce.clone(), storage: self.storage_overlay.borrow().clone(), code: self.code_cache.clone()}) + write!(f, "{:?}", PodAccount::from_account(self)) } } diff --git a/src/state.rs b/src/state.rs index d286d7da5..a236e08c5 100644 --- a/src/state.rs +++ b/src/state.rs @@ -181,12 +181,34 @@ impl State { } /// Populate the state from `accounts`. - pub fn populate_from(&mut self, accounts: HashMap) { + pub fn populate_from(&mut self, accounts: BTreeMap) { for (add, acc) in accounts.into_iter() { self.cache.borrow_mut().insert(add, Some(Account::from_pod(acc))); } } + /// Populate a PodAccount map from this state. + pub fn to_hashmap_pod(&self) -> HashMap { + // TODO: handle database rather than just the cache. + self.cache.borrow().iter().fold(HashMap::new(), |mut m, (add, opt)| { + if let &Some(ref acc) = opt { + m.insert(add.clone(), PodAccount::from_account(acc)); + } + m + }) + } + + /// Populate a PodAccount map from this state. + pub fn to_pod_map(&self) -> BTreeMap { + // TODO: handle database rather than just the cache. + self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| { + if let &Some(ref acc) = opt { + m.insert(add.clone(), PodAccount::from_account(acc)); + } + m + }) + } + /// Pull account `a` in our cache from the trie DB and return it. /// `require_code` requires that the code be cached, too. fn get(&self, a: &Address, require_code: bool) -> Ref> { diff --git a/src/tests/state.rs b/src/tests/state.rs index 5a84cf65e..02f5b9cfd 100644 --- a/src/tests/state.rs +++ b/src/tests/state.rs @@ -9,18 +9,25 @@ pub fn hashmap_h256_h256_from_json(json: &Json) -> HashMap { }) } +pub fn map_h256_h256_from_json(json: &Json) -> BTreeMap { + json.as_object().unwrap().iter().fold(BTreeMap::new(), |mut m, (key, value)| { + m.insert(H256::from(&u256_from_hex(key)), H256::from(&u256_from_json(value))); + m + }) +} + /// Translate the JSON object into a hash map of account information ready for insertion into State. -pub fn pod_account_map_from_json(json: &Json) -> HashMap { - json.as_object().unwrap().iter().fold(HashMap::new(), |mut state, (address, acc)| { +pub fn pod_map_from_json(json: &Json) -> BTreeMap { + json.as_object().unwrap().iter().fold(BTreeMap::new(), |mut state, (address, acc)| { let balance = acc.find("balance").map(&u256_from_json); let nonce = acc.find("nonce").map(&u256_from_json); - let storage: Option> = acc.find("storage").map(&hashmap_h256_h256_from_json);; + let storage = acc.find("storage").map(&map_h256_h256_from_json);; let code = acc.find("code").map(&bytes_from_json); - if balance.is_some() || nonce.is_some() { + if balance.is_some() || nonce.is_some() || storage.is_some() || code.is_some() { state.insert(address_from_hex(address), PodAccount{ balance: balance.unwrap_or(U256::zero()), nonce: nonce.unwrap_or(U256::zero()), - storage: storage.unwrap_or(HashMap::new()), + storage: storage.unwrap_or(BTreeMap::new()), code: code.unwrap_or(Vec::new()) }); } @@ -42,8 +49,8 @@ fn do_json_test(json_data: &[u8]) -> Vec { let env = EnvInfo::from_json(&test["env"]); let out = bytes_from_json(&test["out"]); let post_state_root = h256_from_json(&test["postStateRoot"]); - let pre = pod_account_map_from_json(&test["pre"]); - let post = pod_account_map_from_json(&test["post"]); + let pre = pod_map_from_json(&test["pre"]); + let post = pod_map_from_json(&test["post"]); // TODO: read test["logs"] println!("Transaction: {:?}", t); @@ -55,12 +62,11 @@ fn do_json_test(json_data: &[u8]) -> Vec { let mut s = State::new_temp(); s.populate_from(pre); s.apply(&env, engine.deref(), &t).unwrap(); - - println!("{:?} ? {:?}", s.root(), post_state_root); + let our_post = s.to_pod_map(); if fail_unless(s.root() == &post_state_root) { println!("EXPECTED:\n{:?}", post); - println!("GOT:\n{:?}", s); + println!("GOT:\n{:?}", our_post); } // TODO: Compare logs.