commit
						8511d08a19
					
				| @ -36,6 +36,58 @@ pub struct PodAccount { | ||||
| 	pub storage: BTreeMap<H256, H256>, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for PodAccount { | ||||
| 	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
| 		write!(f, "(bal={}; nonce={}; code={} bytes, #{}; storage={} items)", self.balance, self.nonce, self.code.len(), self.code.sha3(), self.storage.len()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug,Clone,PartialEq,Eq)] | ||||
| pub struct PodState (BTreeMap<Address, PodAccount>); | ||||
| 
 | ||||
| pub fn map_h256_h256_from_json(json: &Json) -> BTreeMap<H256, H256> { | ||||
| 	json.as_object().unwrap().iter().fold(BTreeMap::new(), |mut m, (key, value)| { | ||||
| 		m.insert(H256::from(&u256_from_str(key)), H256::from(&u256_from_json(value))); | ||||
| 		m | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| impl PodState { | ||||
| 	/// Contruct a new object from the `m`.
 | ||||
| 	pub fn from(m: BTreeMap<Address, PodAccount>) -> PodState { PodState(m) } | ||||
| 
 | ||||
| 	/// Translate the JSON object into a hash map of account information ready for insertion into State.
 | ||||
| 	pub fn from_json(json: &Json) -> PodState { | ||||
| 		PodState(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 = 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() || 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(BTreeMap::new()), | ||||
| 					code: code.unwrap_or(Vec::new()) | ||||
| 				}); | ||||
| 			} | ||||
| 			state | ||||
| 		})) | ||||
| 	} | ||||
| 
 | ||||
| 	/// Drain object to get the underlying map.
 | ||||
| 	pub fn drain(self) -> BTreeMap<Address, PodAccount> { self.0 } | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for PodState { | ||||
| 	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
| 		for (add, acc) in &self.0 { | ||||
| 			try!(writeln!(f, "{} => {}", add, acc)); | ||||
| 		} | ||||
| 		Ok(()) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug,Clone,PartialEq,Eq)] | ||||
| pub struct AccountDiff { | ||||
| 	pub balance: Diff<U256>,				// Allowed to be Same
 | ||||
| @ -156,21 +208,21 @@ pub fn pod_diff(pre: Option<&PodAccount>, post: Option<&PodAccount>) -> Option<A | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn pod_map_diff(pre: &BTreeMap<Address, PodAccount>, post: &BTreeMap<Address, PodAccount>) -> StateDiff { | ||||
| 	StateDiff(pre.keys().merge(post.keys()).filter_map(|acc| pod_diff(pre.get(acc), post.get(acc)).map(|d|(acc.clone(), d))).collect()) | ||||
| pub fn pod_state_diff(pre: &PodState, post: &PodState) -> StateDiff { | ||||
| 	StateDiff(pre.0.keys().merge(post.0.keys()).filter_map(|acc| pod_diff(pre.0.get(acc), post.0.get(acc)).map(|d|(acc.clone(), d))).collect()) | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn state_diff_create_delete() { | ||||
| 	let a = map![ | ||||
| 	let a = PodState(map![ | ||||
| 		x!(1) => PodAccount{ | ||||
| 			balance: x!(69), | ||||
| 			nonce: x!(0), | ||||
| 			code: vec![], | ||||
| 			storage: map![] | ||||
| 		} | ||||
| 	]; | ||||
| 	assert_eq!(pod_map_diff(&a, &map![]), StateDiff(map![ | ||||
| 	]); | ||||
| 	assert_eq!(pod_state_diff(&a, &PodState(map![])), StateDiff(map![ | ||||
| 		x!(1) => AccountDiff{ | ||||
| 			balance: Diff::Died(x!(69)), | ||||
| 			nonce: Diff::Died(x!(0)), | ||||
| @ -178,7 +230,7 @@ fn state_diff_create_delete() { | ||||
| 			storage: map![], | ||||
| 		} | ||||
| 	])); | ||||
| 	assert_eq!(pod_map_diff(&map![], &a), StateDiff(map![ | ||||
| 	assert_eq!(pod_state_diff(&PodState(map![]), &a), StateDiff(map![ | ||||
| 		x!(1) => AccountDiff{ | ||||
| 			balance: Diff::Born(x!(69)), | ||||
| 			nonce: Diff::Born(x!(0)), | ||||
| @ -190,15 +242,15 @@ fn state_diff_create_delete() { | ||||
| 
 | ||||
| #[test] | ||||
| fn state_diff_cretae_delete_with_unchanged() { | ||||
| 	let a = map![ | ||||
| 	let a = PodState(map![ | ||||
| 		x!(1) => PodAccount{ | ||||
| 			balance: x!(69), | ||||
| 			nonce: x!(0), | ||||
| 			code: vec![], | ||||
| 			storage: map![] | ||||
| 		} | ||||
| 	]; | ||||
| 	let b = map![ | ||||
| 	]); | ||||
| 	let b = PodState(map![ | ||||
| 		x!(1) => PodAccount{ | ||||
| 			balance: x!(69), | ||||
| 			nonce: x!(0), | ||||
| @ -211,8 +263,8 @@ fn state_diff_cretae_delete_with_unchanged() { | ||||
| 			code: vec![], | ||||
| 			storage: map![] | ||||
| 		} | ||||
| 	]; | ||||
| 	assert_eq!(pod_map_diff(&a, &b), StateDiff(map![ | ||||
| 	]); | ||||
| 	assert_eq!(pod_state_diff(&a, &b), StateDiff(map![ | ||||
| 		x!(2) => AccountDiff{ | ||||
| 			balance: Diff::Born(x!(69)), | ||||
| 			nonce: Diff::Born(x!(0)), | ||||
| @ -220,7 +272,7 @@ fn state_diff_cretae_delete_with_unchanged() { | ||||
| 			storage: map![], | ||||
| 		} | ||||
| 	])); | ||||
| 	assert_eq!(pod_map_diff(&b, &a), StateDiff(map![ | ||||
| 	assert_eq!(pod_state_diff(&b, &a), StateDiff(map![ | ||||
| 		x!(2) => AccountDiff{ | ||||
| 			balance: Diff::Died(x!(69)), | ||||
| 			nonce: Diff::Died(x!(0)), | ||||
| @ -232,7 +284,7 @@ fn state_diff_cretae_delete_with_unchanged() { | ||||
| 
 | ||||
| #[test] | ||||
| fn state_diff_change_with_unchanged() { | ||||
| 	let a = map![ | ||||
| 	let a = PodState(map![ | ||||
| 		x!(1) => PodAccount{ | ||||
| 			balance: x!(69), | ||||
| 			nonce: x!(0), | ||||
| @ -245,8 +297,8 @@ fn state_diff_change_with_unchanged() { | ||||
| 			code: vec![], | ||||
| 			storage: map![] | ||||
| 		} | ||||
| 	]; | ||||
| 	let b = map![ | ||||
| 	]); | ||||
| 	let b = PodState(map![ | ||||
| 		x!(1) => PodAccount{ | ||||
| 			balance: x!(69), | ||||
| 			nonce: x!(1), | ||||
| @ -259,8 +311,8 @@ fn state_diff_change_with_unchanged() { | ||||
| 			code: vec![], | ||||
| 			storage: map![] | ||||
| 		} | ||||
| 	]; | ||||
| 	assert_eq!(pod_map_diff(&a, &b), StateDiff(map![ | ||||
| 	]); | ||||
| 	assert_eq!(pod_state_diff(&a, &b), StateDiff(map![ | ||||
| 		x!(1) => AccountDiff{ | ||||
| 			balance: Diff::Same, | ||||
| 			nonce: Diff::Changed(x!(0), x!(1)), | ||||
|  | ||||
| @ -2,7 +2,7 @@ use util::*; | ||||
| use basic_types::LogBloom; | ||||
| 
 | ||||
| /// A single log's entry.
 | ||||
| #[derive(Debug)] | ||||
| #[derive(Debug,PartialEq,Eq)] | ||||
| pub struct LogEntry { | ||||
| 	pub address: Address, | ||||
| 	pub topics: Vec<H256>, | ||||
| @ -19,10 +19,6 @@ impl RlpStandard for LogEntry { | ||||
| } | ||||
| 
 | ||||
| impl LogEntry { | ||||
| 	pub fn bloom(&self) -> LogBloom { | ||||
| 		self.topics.iter().fold(LogBloom::from_bloomed(&self.address.sha3()), |b, t| b.with_bloomed(&t.sha3())) | ||||
| 	} | ||||
| 
 | ||||
| 	/// Create a new log entry.
 | ||||
| 	pub fn new(address: Address, topics: Vec<H256>, data: Bytes) -> LogEntry { | ||||
| 		LogEntry { | ||||
| @ -32,6 +28,16 @@ impl LogEntry { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Convert given JSON object to a LogEntry.
 | ||||
| 	pub fn from_json(json: &Json) -> LogEntry { | ||||
| 		// TODO: check bloom.
 | ||||
| 		LogEntry { | ||||
| 			address: address_from_json(&json["address"]), | ||||
| 			topics: vec_h256_from_json(&json["topics"]), | ||||
| 			data: bytes_from_json(&json["data"]), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/// Returns reference to address.
 | ||||
| 	pub fn address(&self) -> &Address { | ||||
| 		&self.address | ||||
| @ -46,6 +52,11 @@ impl LogEntry { | ||||
| 	pub fn data(&self) -> &Bytes { | ||||
| 		&self.data | ||||
| 	} | ||||
| 
 | ||||
| 	/// Calculates the bloom of this log entry.
 | ||||
| 	pub fn bloom(&self) -> LogBloom { | ||||
| 		self.topics.iter().fold(LogBloom::from_bloomed(&self.address.sha3()), |b, t| b.with_bloomed(&t.sha3())) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
|  | ||||
							
								
								
									
										10
									
								
								src/state.rs
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								src/state.rs
									
									
									
									
									
								
							| @ -181,8 +181,8 @@ impl State { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Populate the state from `accounts`.
 | ||||
| 	pub fn populate_from(&mut self, accounts: BTreeMap<Address, PodAccount>) { | ||||
| 		for (add, acc) in accounts.into_iter() { | ||||
| 	pub fn populate_from(&mut self, accounts: PodState) { | ||||
| 		for (add, acc) in accounts.drain().into_iter() { | ||||
| 			self.cache.borrow_mut().insert(add, Some(Account::from_pod(acc))); | ||||
| 		} | ||||
| 	} | ||||
| @ -199,14 +199,14 @@ impl State { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Populate a PodAccount map from this state.
 | ||||
| 	pub fn to_pod_map(&self) -> BTreeMap<Address, PodAccount> { | ||||
| 	pub fn to_pod(&self) -> PodState { | ||||
| 		// TODO: handle database rather than just the cache.
 | ||||
| 		self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| { | ||||
| 		PodState::from(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.
 | ||||
|  | ||||
| @ -3,32 +3,6 @@ use state::*; | ||||
| use executive::*; | ||||
| use ethereum; | ||||
| 
 | ||||
| pub fn map_h256_h256_from_json(json: &Json) -> BTreeMap<H256, H256> { | ||||
| 	json.as_object().unwrap().iter().fold(BTreeMap::new(), |mut m, (key, value)| { | ||||
| 		m.insert(H256::from(&u256_from_str(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_map_from_json(json: &Json) -> BTreeMap<Address, PodAccount> { | ||||
| 	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 = 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() || 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(BTreeMap::new()), | ||||
| 				code: code.unwrap_or(Vec::new()) | ||||
| 			}); | ||||
| 		} | ||||
| 		state | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| fn do_json_test(json_data: &[u8]) -> Vec<String> { | ||||
| 	let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid"); | ||||
| 	let mut failed = Vec::new(); | ||||
| @ -43,9 +17,9 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> { | ||||
| 		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_map_from_json(&test["pre"]); | ||||
| 		let post = pod_map_from_json(&test["post"]); | ||||
| 		// TODO: read test["logs"]
 | ||||
| 		let pre = PodState::from_json(&test["pre"]); | ||||
| 		let post = PodState::from_json(&test["post"]); | ||||
| 		let logs: Vec<_> = test["logs"].as_array().unwrap().iter().map(&LogEntry::from_json).collect(); | ||||
| 
 | ||||
| 		//println!("Transaction: {:?}", t);
 | ||||
| 		//println!("Env: {:?}", env);
 | ||||
| @ -59,20 +33,28 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> { | ||||
| 
 | ||||
| 		let mut s = State::new_temp(); | ||||
| 		s.populate_from(pre); | ||||
| 		let r = s.apply(&env, engine.deref(), &t).unwrap(); | ||||
| 
 | ||||
| 		s.apply(&env, engine.deref(), &t).unwrap(); | ||||
| 		let our_post = s.to_pod_map(); | ||||
| 
 | ||||
| 		if fail_unless(s.root() == &post_state_root) { | ||||
| 			println!("FAILED {}.   Diff:\n{}", name, pod_map_diff(&post, &our_post)); | ||||
| 		if fail_unless(&r.state_root == &post_state_root) { | ||||
| 			println!("!!! {}: State mismatch (got: {}, expect: {}):", name, r.state_root, post_state_root); | ||||
| 			let our_post = s.to_pod(); | ||||
| 			println!("Got:\n{}", our_post); | ||||
| 			println!("Expect:\n{}", post); | ||||
| 			println!("Diff ---expect -> +++got:\n{}", pod_state_diff(&post, &our_post)); | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO: Compare logs.
 | ||||
| 	} | ||||
| 	for f in failed.iter() { | ||||
| 		println!("FAILED: {:?}", f); | ||||
| 		if fail_unless(logs == r.logs) { | ||||
| 			println!("!!! {}: Logs mismatch:", name); | ||||
| 			println!("Got:\n{:?}", r.logs); | ||||
| 			println!("Expect:\n{:?}", logs); | ||||
| 		} | ||||
| 
 | ||||
| 		// TODO: Add extra APIs for output
 | ||||
| 		//if fail_unless(out == r.)
 | ||||
| 	} | ||||
| 	println!("!!! {:?} tests from failed.", failed.len()); | ||||
| 	failed | ||||
| } | ||||
| 
 | ||||
| declare_test!{StateTests_stExample, "StateTests/stExample"} | ||||
| declare_test!{StateTests_stLogTests, "StateTests/stLogTests"} | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user