Merge remote-tracking branch 'origin/master' into bettermining
This commit is contained in:
		
						commit
						d150529730
					
				@ -19,6 +19,7 @@ use tests::helpers::*;
 | 
			
		||||
use pod_state::*;
 | 
			
		||||
use state_diff::*;
 | 
			
		||||
use ethereum;
 | 
			
		||||
use ethjson;
 | 
			
		||||
 | 
			
		||||
fn do_json_test(json_data: &[u8]) -> Vec<String> {
 | 
			
		||||
	json_chain_test(json_data, ChainEra::Frontier)
 | 
			
		||||
@ -26,18 +27,14 @@ fn do_json_test(json_data: &[u8]) -> Vec<String> {
 | 
			
		||||
 | 
			
		||||
pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
 | 
			
		||||
	init_log();
 | 
			
		||||
 | 
			
		||||
	let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
 | 
			
		||||
	let tests = ethjson::state::Test::load(json_data).unwrap();
 | 
			
		||||
	let mut failed = Vec::new();
 | 
			
		||||
 | 
			
		||||
	let engine = match era {
 | 
			
		||||
		ChainEra::Frontier => ethereum::new_mainnet_like(),
 | 
			
		||||
		ChainEra::Homestead => ethereum::new_homestead_test(),
 | 
			
		||||
	}.to_engine().unwrap();
 | 
			
		||||
 | 
			
		||||
	flushln!("");
 | 
			
		||||
 | 
			
		||||
	for (name, test) in json.as_object().unwrap() {
 | 
			
		||||
	for (name, test) in tests.into_iter() {
 | 
			
		||||
		let mut fail = false;
 | 
			
		||||
		{
 | 
			
		||||
			let mut fail_unless = |cond: bool| if !cond && !fail {
 | 
			
		||||
@ -49,16 +46,13 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
 | 
			
		||||
 | 
			
		||||
			flush!("   - {}...", name);
 | 
			
		||||
 | 
			
		||||
			let t = SignedTransaction::from_json(&test["transaction"]);
 | 
			
		||||
			let env = EnvInfo::from_json(&test["env"]);
 | 
			
		||||
			let _out = Bytes::from_json(&test["out"]);
 | 
			
		||||
			let post_state_root = xjson!(&test["postStateRoot"]);
 | 
			
		||||
			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();
 | 
			
		||||
			let transaction = test.transaction.into();
 | 
			
		||||
			let post_state_root = test.post_state_root.into();
 | 
			
		||||
			let env = test.env.into();
 | 
			
		||||
			let pre: PodState = test.pre_state.into();
 | 
			
		||||
			let post: PodState = test.post_state.into();
 | 
			
		||||
			let logs: Vec<LogEntry> = test.logs.into_iter().map(Into::into).collect();
 | 
			
		||||
 | 
			
		||||
			//println!("Transaction: {:?}", t);
 | 
			
		||||
			//println!("Env: {:?}", env);
 | 
			
		||||
			let calc_post = sec_trie_root(post.get().iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect());
 | 
			
		||||
 | 
			
		||||
			if fail_unless(post_state_root == calc_post) {
 | 
			
		||||
@ -69,7 +63,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
 | 
			
		||||
				let mut state = state_result.reference_mut();
 | 
			
		||||
				state.populate_from(pre);
 | 
			
		||||
				state.commit();
 | 
			
		||||
				let res = state.apply(&env, engine.deref(), &t, false);
 | 
			
		||||
				let res = state.apply(&env, engine.deref(), &transaction, false);
 | 
			
		||||
 | 
			
		||||
				if fail_unless(state.root() == &post_state_root) {
 | 
			
		||||
					println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root);
 | 
			
		||||
@ -88,12 +82,12 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if !fail {
 | 
			
		||||
			flushln!("ok");
 | 
			
		||||
		}
 | 
			
		||||
		// TODO: Add extra APIs for output
 | 
			
		||||
		//if fail_unless(out == r.)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	println!("!!! {:?} tests from failed.", failed.len());
 | 
			
		||||
	failed
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@
 | 
			
		||||
use util::*;
 | 
			
		||||
use basic_types::LogBloom;
 | 
			
		||||
use header::BlockNumber;
 | 
			
		||||
use ethjson;
 | 
			
		||||
 | 
			
		||||
/// A record of execution for a `LOG` operation.
 | 
			
		||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
@ -65,6 +66,16 @@ impl LogEntry {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ethjson::state::Log> for LogEntry {
 | 
			
		||||
	fn from(l: ethjson::state::Log) -> Self {
 | 
			
		||||
		LogEntry {
 | 
			
		||||
			address: l.address.into(),
 | 
			
		||||
			topics: l.topics.into_iter().map(Into::into).collect(),
 | 
			
		||||
			data: l.data.into(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FromJson for LogEntry {
 | 
			
		||||
	/// Convert given JSON object to a LogEntry.
 | 
			
		||||
	fn from_json(json: &Json) -> LogEntry {
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@ use util::*;
 | 
			
		||||
use error::*;
 | 
			
		||||
use evm::Schedule;
 | 
			
		||||
use header::BlockNumber;
 | 
			
		||||
use ethjson;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
/// Transaction action type.
 | 
			
		||||
@ -79,6 +80,23 @@ impl Transaction {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<ethjson::state::Transaction> for SignedTransaction {
 | 
			
		||||
	fn from(t: ethjson::state::Transaction) -> Self {
 | 
			
		||||
		let to: Option<_> = t.to.into();
 | 
			
		||||
		Transaction {
 | 
			
		||||
			nonce: t.nonce.into(),
 | 
			
		||||
			gas_price: t.gas_price.into(),
 | 
			
		||||
			gas: t.gas_limit.into(),
 | 
			
		||||
			action: match to {
 | 
			
		||||
				Some(to) => Action::Call(to.into()),
 | 
			
		||||
				None => Action::Create
 | 
			
		||||
			},
 | 
			
		||||
			value: t.value.into(),
 | 
			
		||||
			data: t.data.into(),
 | 
			
		||||
		}.sign(&t.secret.into())
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl FromJson for SignedTransaction {
 | 
			
		||||
	#[cfg_attr(feature="dev", allow(single_char_pattern))]
 | 
			
		||||
	fn from_json(json: &Json) -> SignedTransaction {
 | 
			
		||||
 | 
			
		||||
@ -26,3 +26,4 @@ pub mod blockchain;
 | 
			
		||||
pub mod spec;
 | 
			
		||||
pub mod vm;
 | 
			
		||||
pub mod maybe;
 | 
			
		||||
pub mod state;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										52
									
								
								json/src/state/log.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								json/src/state/log.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! State test log deserialization.
 | 
			
		||||
use hash::{Address, H256, Bloom};
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
 | 
			
		||||
/// State test log deserialization.
 | 
			
		||||
#[derive(Debug, PartialEq, Deserialize)]
 | 
			
		||||
pub struct Log {
 | 
			
		||||
	/// Address.
 | 
			
		||||
	pub address: Address,
 | 
			
		||||
	/// Topics.
 | 
			
		||||
	pub topics: Vec<H256>,
 | 
			
		||||
	/// Data.
 | 
			
		||||
	pub data: Bytes,
 | 
			
		||||
	/// Bloom.
 | 
			
		||||
	pub bloom: Bloom,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
	use serde_json;
 | 
			
		||||
	use state::Log;
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn log_deserialization() {
 | 
			
		||||
		let s = r#"{
 | 
			
		||||
			"address" : "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
 | 
			
		||||
			"bloom" : "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008800000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000",
 | 
			
		||||
			"data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
 | 
			
		||||
			"topics" : [
 | 
			
		||||
				"0000000000000000000000000000000000000000000000000000000000000000"
 | 
			
		||||
			]
 | 
			
		||||
		}"#;
 | 
			
		||||
		let _deserialized: Log = serde_json::from_str(s).unwrap();
 | 
			
		||||
		// TODO: validate all fields
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								json/src/state/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								json/src/state/mod.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! State test deserialization.
 | 
			
		||||
 | 
			
		||||
pub mod state;
 | 
			
		||||
pub mod transaction;
 | 
			
		||||
pub mod test;
 | 
			
		||||
pub mod log;
 | 
			
		||||
 | 
			
		||||
pub use self::state::State;
 | 
			
		||||
pub use self::transaction::Transaction;
 | 
			
		||||
pub use self::test::Test;
 | 
			
		||||
pub use self::log::Log;
 | 
			
		||||
pub use vm::Env as Env;
 | 
			
		||||
pub use blockchain::State as AccountState;
 | 
			
		||||
							
								
								
									
										156
									
								
								json/src/state/state.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								json/src/state/state.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,156 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! State test deserialization.
 | 
			
		||||
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
use hash::H256;
 | 
			
		||||
use state::{Env, AccountState, Transaction, Log};
 | 
			
		||||
 | 
			
		||||
/// State test deserialization.
 | 
			
		||||
#[derive(Debug, PartialEq, Deserialize)]
 | 
			
		||||
pub struct State {
 | 
			
		||||
	/// Environment.
 | 
			
		||||
	pub env: Env,
 | 
			
		||||
	/// Output.
 | 
			
		||||
	#[serde(rename="out")]
 | 
			
		||||
	pub output: Bytes,
 | 
			
		||||
	/// Pre state.
 | 
			
		||||
	#[serde(rename="pre")]
 | 
			
		||||
	pub pre_state: AccountState,
 | 
			
		||||
	/// Post state.
 | 
			
		||||
	#[serde(rename="post")]
 | 
			
		||||
	pub post_state: AccountState,
 | 
			
		||||
	/// Post state root.
 | 
			
		||||
	#[serde(rename="postStateRoot")]
 | 
			
		||||
	pub post_state_root: H256,
 | 
			
		||||
	/// Transaction.
 | 
			
		||||
	pub transaction: Transaction,
 | 
			
		||||
	/// Logs.
 | 
			
		||||
	pub logs: Vec<Log>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
	use serde_json;
 | 
			
		||||
	use state::State;
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn state_deserialization() {
 | 
			
		||||
		let s = r#"{
 | 
			
		||||
			"env" : {
 | 
			
		||||
				"currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
 | 
			
		||||
				"currentDifficulty" : "0x0100",
 | 
			
		||||
				"currentGasLimit" : "0x01c9c380",
 | 
			
		||||
				"currentNumber" : "0x00",
 | 
			
		||||
				"currentTimestamp" : "0x01",
 | 
			
		||||
				"previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
 | 
			
		||||
			},
 | 
			
		||||
			"logs" : [
 | 
			
		||||
			],
 | 
			
		||||
			"out" : "0x",
 | 
			
		||||
			"post" : {
 | 
			
		||||
				"1000000000000000000000000000000000000000" : {
 | 
			
		||||
					"balance" : "0x0de0b6b3a763ffff",
 | 
			
		||||
					"code" : "0x6040600060406000600173100000000000000000000000000000000000000162055730f1600055",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
						"0x00" : "0x01"
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"1000000000000000000000000000000000000001" : {
 | 
			
		||||
					"balance" : "0x0de0b6b3a763ffff",
 | 
			
		||||
					"code" : "0x604060006040600060027310000000000000000000000000000000000000026203d090f1600155",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
						"0x01" : "0x01"
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"1000000000000000000000000000000000000002" : {
 | 
			
		||||
					"balance" : "0x02",
 | 
			
		||||
					"code" : "0x600160025533600455346007553060e6553260e8553660ec553860ee553a60f055",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
						"0x02" : "0x01",
 | 
			
		||||
						"0x04" : "0x1000000000000000000000000000000000000001",
 | 
			
		||||
						"0x07" : "0x02",
 | 
			
		||||
						"0xe6" : "0x1000000000000000000000000000000000000002",
 | 
			
		||||
						"0xe8" : "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
 | 
			
		||||
						"0xec" : "0x40",
 | 
			
		||||
						"0xee" : "0x21",
 | 
			
		||||
						"0xf0" : "0x01"
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" : {
 | 
			
		||||
					"balance" : "0x039455",
 | 
			
		||||
					"code" : "0x",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
 | 
			
		||||
					"balance" : "0x0de0b6b3a7606bab",
 | 
			
		||||
					"code" : "0x",
 | 
			
		||||
					"nonce" : "0x01",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			"postStateRoot" : "8f8ed2aed2973e159fa5486f47c6ebf15c5058f8e2350286b84b569bc6ce2d25",
 | 
			
		||||
			"pre" : {
 | 
			
		||||
				"1000000000000000000000000000000000000000" : {
 | 
			
		||||
					"balance" : "0x0de0b6b3a7640000",
 | 
			
		||||
					"code" : "0x6040600060406000600173100000000000000000000000000000000000000162055730f1600055",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"1000000000000000000000000000000000000001" : {
 | 
			
		||||
					"balance" : "0x0de0b6b3a7640000",
 | 
			
		||||
					"code" : "0x604060006040600060027310000000000000000000000000000000000000026203d090f1600155",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"1000000000000000000000000000000000000002" : {
 | 
			
		||||
					"balance" : "0x00",
 | 
			
		||||
					"code" : "0x600160025533600455346007553060e6553260e8553660ec553860ee553a60f055",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				"a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
 | 
			
		||||
					"balance" : "0x0de0b6b3a7640000",
 | 
			
		||||
					"code" : "0x",
 | 
			
		||||
					"nonce" : "0x00",
 | 
			
		||||
					"storage" : {
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
			"transaction" : {
 | 
			
		||||
				"data" : "",
 | 
			
		||||
				"gasLimit" : "0x2dc6c0",
 | 
			
		||||
				"gasPrice" : "0x01",
 | 
			
		||||
				"nonce" : "0x00",
 | 
			
		||||
				"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
 | 
			
		||||
				"to" : "1000000000000000000000000000000000000000",
 | 
			
		||||
				"value" : "0x00"
 | 
			
		||||
			}
 | 
			
		||||
		}"#;
 | 
			
		||||
		let _deserialized: State = serde_json::from_str(s).unwrap();
 | 
			
		||||
		// TODO: validate all fields
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								json/src/state/test.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								json/src/state/test.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! State test deserializer.
 | 
			
		||||
 | 
			
		||||
use std::collections::BTreeMap;
 | 
			
		||||
use std::io::Read;
 | 
			
		||||
use serde_json;
 | 
			
		||||
use serde_json::Error;
 | 
			
		||||
use state::State;
 | 
			
		||||
 | 
			
		||||
/// State test deserializer.
 | 
			
		||||
#[derive(Debug, PartialEq, Deserialize)]
 | 
			
		||||
pub struct Test(BTreeMap<String, State>);
 | 
			
		||||
 | 
			
		||||
impl IntoIterator for Test {
 | 
			
		||||
	type Item = <BTreeMap<String, State> as IntoIterator>::Item;
 | 
			
		||||
	type IntoIter = <BTreeMap<String, State> as IntoIterator>::IntoIter;
 | 
			
		||||
 | 
			
		||||
	fn into_iter(self) -> Self::IntoIter {
 | 
			
		||||
		self.0.into_iter()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Test {
 | 
			
		||||
	/// Loads test from json.
 | 
			
		||||
	pub fn load<R>(reader: R) -> Result<Self, Error> where R: Read {
 | 
			
		||||
		serde_json::from_reader(reader)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										65
									
								
								json/src/state/transaction.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								json/src/state/transaction.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
 | 
			
		||||
// This file is part of Parity.
 | 
			
		||||
 | 
			
		||||
// Parity is free software: you can redistribute it and/or modify
 | 
			
		||||
// it under the terms of the GNU General Public License as published by
 | 
			
		||||
// the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
// (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
// Parity is distributed in the hope that it will be useful,
 | 
			
		||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
// GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
// You should have received a copy of the GNU General Public License
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! State test transaction deserialization.
 | 
			
		||||
 | 
			
		||||
use uint::Uint;
 | 
			
		||||
use bytes::Bytes;
 | 
			
		||||
use hash::{Address, H256};
 | 
			
		||||
use maybe::MaybeEmpty;
 | 
			
		||||
 | 
			
		||||
/// State test transaction deserialization.
 | 
			
		||||
#[derive(Debug, PartialEq, Deserialize)]
 | 
			
		||||
pub struct Transaction {
 | 
			
		||||
	/// Transaction data.
 | 
			
		||||
	pub data: Bytes,
 | 
			
		||||
	/// Gas limit.
 | 
			
		||||
	#[serde(rename="gasLimit")]
 | 
			
		||||
	pub gas_limit: Uint,
 | 
			
		||||
	/// Gas price.
 | 
			
		||||
	#[serde(rename="gasPrice")]
 | 
			
		||||
	pub gas_price: Uint,
 | 
			
		||||
	/// Nonce.
 | 
			
		||||
	pub nonce: Uint,
 | 
			
		||||
	/// Secret key.
 | 
			
		||||
	#[serde(rename="secretKey")]
 | 
			
		||||
	pub secret: H256,
 | 
			
		||||
	/// To.
 | 
			
		||||
	pub to: MaybeEmpty<Address>,
 | 
			
		||||
	/// Value.
 | 
			
		||||
	pub value: Uint
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
	use serde_json;
 | 
			
		||||
	use state::Transaction;
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn transaction_deserialization() {
 | 
			
		||||
		let s = r#"{
 | 
			
		||||
			"data" : "",
 | 
			
		||||
			"gasLimit" : "0x2dc6c0",
 | 
			
		||||
			"gasPrice" : "0x01",
 | 
			
		||||
			"nonce" : "0x00",
 | 
			
		||||
			"secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8",
 | 
			
		||||
			"to" : "1000000000000000000000000000000000000000",
 | 
			
		||||
			"value" : "0x00"
 | 
			
		||||
		}"#;
 | 
			
		||||
		let _deserialized: Transaction = serde_json::from_str(s).unwrap();
 | 
			
		||||
		// TODO: validate all fields
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -104,6 +104,9 @@ pub trait MinerService : Send + Sync {
 | 
			
		||||
 | 
			
		||||
	/// Get the sealing work package and if `Some`, apply some transform.
 | 
			
		||||
	fn map_sealing_work<F, T>(&self, chain: &BlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T;
 | 
			
		||||
 | 
			
		||||
	/// Query pending transactions for hash
 | 
			
		||||
	fn transaction(&self, hash: &H256) -> Option<SignedTransaction>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Mining status
 | 
			
		||||
 | 
			
		||||
@ -217,6 +217,11 @@ impl MinerService for Miner {
 | 
			
		||||
		transaction_queue.pending_hashes()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
 | 
			
		||||
		let queue = self.transaction_queue.lock().unwrap();
 | 
			
		||||
		queue.find(hash)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn update_sealing(&self, chain: &BlockChainClient) {
 | 
			
		||||
		if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
 | 
			
		||||
			let current_no = chain.chain_info().best_block_number;
 | 
			
		||||
 | 
			
		||||
@ -504,6 +504,11 @@ impl TransactionQueue {
 | 
			
		||||
			.collect()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Finds transaction in the queue by hash (if any)
 | 
			
		||||
	pub fn find(&self, hash: &H256) -> Option<SignedTransaction> {
 | 
			
		||||
		match self.by_hash.get(hash) { Some(transaction_ref) => Some(transaction_ref.transaction.clone()), None => None }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Removes all elements (in any state) from the queue
 | 
			
		||||
	pub fn clear(&mut self) {
 | 
			
		||||
		self.current.clear();
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,8 @@ extern crate rpassword;
 | 
			
		||||
#[cfg(feature = "rpc")]
 | 
			
		||||
extern crate ethcore_rpc as rpc;
 | 
			
		||||
 | 
			
		||||
use std::io::{BufRead, BufReader};
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::net::{SocketAddr, IpAddr};
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::process::exit;
 | 
			
		||||
@ -89,6 +91,11 @@ Protocol Options:
 | 
			
		||||
                           [default: $HOME/.web3/keys].
 | 
			
		||||
  --identity NAME          Specify your node's name.
 | 
			
		||||
 | 
			
		||||
Account Options:
 | 
			
		||||
  --unlock ACCOUNT         Unlock ACCOUNT for the duration of the execution.
 | 
			
		||||
  --password FILE          Provide a file containing a password for unlocking
 | 
			
		||||
                           an account.
 | 
			
		||||
 | 
			
		||||
Networking Options:
 | 
			
		||||
  --port PORT              Override the port on which the node should listen
 | 
			
		||||
                           [default: 30303].
 | 
			
		||||
@ -176,6 +183,8 @@ struct Args {
 | 
			
		||||
	flag_chain: String,
 | 
			
		||||
	flag_db_path: String,
 | 
			
		||||
	flag_identity: String,
 | 
			
		||||
	flag_unlock: Vec<String>,
 | 
			
		||||
	flag_password: Vec<String>,
 | 
			
		||||
	flag_cache: Option<usize>,
 | 
			
		||||
	flag_keys_path: String,
 | 
			
		||||
	flag_bootnodes: Option<String>,
 | 
			
		||||
@ -490,6 +499,28 @@ impl Configuration {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn account_service(&self) -> AccountService {
 | 
			
		||||
		// Secret Store
 | 
			
		||||
		let passwords = self.args.flag_password.iter().flat_map(|filename| {
 | 
			
		||||
			BufReader::new(&File::open(filename).unwrap_or_else(|_| die!("{} Unable to read password file. Ensure it exists and permissions are correct.", filename)))
 | 
			
		||||
				.lines()
 | 
			
		||||
				.map(|l| l.unwrap())
 | 
			
		||||
				.collect::<Vec<_>>()
 | 
			
		||||
				.into_iter()
 | 
			
		||||
		}).collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
		let account_service = AccountService::new();
 | 
			
		||||
		for d in &self.args.flag_unlock {
 | 
			
		||||
			let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| {
 | 
			
		||||
				die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d)
 | 
			
		||||
			});
 | 
			
		||||
			if passwords.iter().find(|p| account_service.unlock_account_no_expire(&a, p).is_ok()).is_none() {
 | 
			
		||||
				die!("No password given to unlock account {}. Pass the password using `--password`.", a);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		account_service
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[cfg_attr(feature="dev", allow(useless_format))]
 | 
			
		||||
	fn execute_client(&self) {
 | 
			
		||||
		// Setup panic handler
 | 
			
		||||
@ -504,6 +535,9 @@ impl Configuration {
 | 
			
		||||
		let net_settings = self.net_settings(&spec);
 | 
			
		||||
		let sync_config = self.sync_config(&spec);
 | 
			
		||||
 | 
			
		||||
		// Secret Store
 | 
			
		||||
		let account_service = Arc::new(self.account_service());
 | 
			
		||||
 | 
			
		||||
		// Build client
 | 
			
		||||
		let mut service = ClientService::start(self.client_config(), spec, net_settings, &Path::new(&self.path())).unwrap();
 | 
			
		||||
		panic_handler.forward_from(&service);
 | 
			
		||||
@ -519,9 +553,6 @@ impl Configuration {
 | 
			
		||||
		// Sync
 | 
			
		||||
		let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone());
 | 
			
		||||
 | 
			
		||||
		// Secret Store
 | 
			
		||||
		let account_service = Arc::new(AccountService::new());
 | 
			
		||||
 | 
			
		||||
		// Setup rpc
 | 
			
		||||
		if self.args.flag_jsonrpc || self.args.flag_rpc {
 | 
			
		||||
			let url = format!("{}:{}",
 | 
			
		||||
 | 
			
		||||
@ -348,7 +348,13 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
 | 
			
		||||
 | 
			
		||||
	fn transaction_by_hash(&self, params: Params) -> Result<Value, Error> {
 | 
			
		||||
		from_params::<(H256,)>(params)
 | 
			
		||||
			.and_then(|(hash,)| self.transaction(TransactionId::Hash(hash)))
 | 
			
		||||
			.and_then(|(hash,)| {
 | 
			
		||||
				let miner = take_weak!(self.miner);
 | 
			
		||||
				match miner.transaction(&hash) {
 | 
			
		||||
					Some(pending_tx) => to_value(&Transaction::from(pending_tx)),
 | 
			
		||||
					None => self.transaction(TransactionId::Hash(hash))
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn transaction_by_block_hash_and_index(&self, params: Params) -> Result<Value, Error> {
 | 
			
		||||
@ -471,11 +477,11 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
 | 
			
		||||
							Ok(_) => to_value(&hash),
 | 
			
		||||
							Err(e) => {
 | 
			
		||||
								warn!("Error sending transaction: {:?}", e);
 | 
			
		||||
								to_value(&U256::zero())
 | 
			
		||||
								to_value(&H256::zero())
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					},
 | 
			
		||||
					Err(_) => { to_value(&U256::zero()) }
 | 
			
		||||
					Err(_) => { to_value(&H256::zero()) }
 | 
			
		||||
				}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
@ -498,11 +504,11 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
 | 
			
		||||
							Ok(_) => to_value(&hash),
 | 
			
		||||
							Err(e) => {
 | 
			
		||||
								warn!("Error sending transaction: {:?}", e);
 | 
			
		||||
								to_value(&U256::zero())
 | 
			
		||||
								to_value(&H256::zero())
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					},
 | 
			
		||||
					Err(_) => { to_value(&U256::zero()) }
 | 
			
		||||
					Err(_) => { to_value(&H256::zero()) }
 | 
			
		||||
				}
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ struct EthTester {
 | 
			
		||||
	pub client: Arc<TestBlockChainClient>,
 | 
			
		||||
	pub sync: Arc<TestSyncProvider>,
 | 
			
		||||
	_accounts_provider: Arc<TestAccountProvider>,
 | 
			
		||||
	_miner: Arc<TestMinerService>,
 | 
			
		||||
	miner: Arc<TestMinerService>,
 | 
			
		||||
	hashrates: Arc<RwLock<HashMap<H256, U256>>>,
 | 
			
		||||
	pub io: IoHandler,
 | 
			
		||||
}
 | 
			
		||||
@ -73,7 +73,7 @@ impl Default for EthTester {
 | 
			
		||||
			client: client,
 | 
			
		||||
			sync: sync,
 | 
			
		||||
			_accounts_provider: ap,
 | 
			
		||||
			_miner: miner,
 | 
			
		||||
			miner: miner,
 | 
			
		||||
			io: io,
 | 
			
		||||
			hashrates: hashrates,
 | 
			
		||||
		}
 | 
			
		||||
@ -258,6 +258,27 @@ fn rpc_eth_transaction_count_by_number_pending() {
 | 
			
		||||
	assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_eth_pending_transaction_by_hash() {
 | 
			
		||||
	use util::*;
 | 
			
		||||
	use ethcore::transaction::*;
 | 
			
		||||
 | 
			
		||||
	let tester = EthTester::default();
 | 
			
		||||
	{
 | 
			
		||||
		let tx: SignedTransaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap());
 | 
			
		||||
		tester.miner.pending_transactions.lock().unwrap().insert(H256::zero(), tx);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let response = r#"{"jsonrpc":"2.0","result":{"blockHash":null,"blockNumber":null,"from":"0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e","gas":"0x5208","gasPrice":"0x01","hash":"0x41df922fd0d4766fcc02e161f8295ec28522f329ae487f14d811e4b64c8d6e31","input":"0x","nonce":"0x00","to":"0x095e7baea6a6c7c4c2dfeb977efac326af552d87","transactionIndex":null,"value":"0x0a"},"id":1}"#;
 | 
			
		||||
	let request = r#"{
 | 
			
		||||
		"jsonrpc": "2.0",
 | 
			
		||||
		"method": "eth_getTransactionByHash",
 | 
			
		||||
		"params": ["0x0000000000000000000000000000000000000000000000000000000000000000"],
 | 
			
		||||
		"id": 1
 | 
			
		||||
	}"#;
 | 
			
		||||
	assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn rpc_eth_uncle_count_by_block_hash() {
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,8 @@ pub struct TestMinerService {
 | 
			
		||||
	pub imported_transactions: RwLock<Vec<H256>>,
 | 
			
		||||
	/// Latest closed block.
 | 
			
		||||
	pub latest_closed_block: Mutex<Option<ClosedBlock>>,
 | 
			
		||||
	/// Pre-existed pending transactions
 | 
			
		||||
	pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for TestMinerService {
 | 
			
		||||
@ -37,6 +39,7 @@ impl Default for TestMinerService {
 | 
			
		||||
		TestMinerService {
 | 
			
		||||
			imported_transactions: RwLock::new(Vec::new()),
 | 
			
		||||
			latest_closed_block: Mutex::new(None),
 | 
			
		||||
			pending_transactions: Mutex::new(HashMap::new()),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -70,6 +73,10 @@ impl MinerService for TestMinerService {
 | 
			
		||||
 | 
			
		||||
	fn map_sealing_work<F, T>(&self, _chain: &BlockChainClient, _f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T { unimplemented!(); }
 | 
			
		||||
 | 
			
		||||
	fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
 | 
			
		||||
		self.pending_transactions.lock().unwrap().get(hash).and_then(|tx_ref| Some(tx_ref.clone()))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Submit `seal` as a valid solution for the header of `pow_hash`.
 | 
			
		||||
	/// Will check the seal, but not actually insert the block into the chain.
 | 
			
		||||
	fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> { unimplemented!(); }
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@
 | 
			
		||||
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
use util::numbers::*;
 | 
			
		||||
use ethcore::transaction::{LocalizedTransaction, Action};
 | 
			
		||||
use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction};
 | 
			
		||||
use v1::types::{Bytes, OptionalValue};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default, Serialize)]
 | 
			
		||||
@ -58,6 +58,27 @@ impl From<LocalizedTransaction> for Transaction {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<SignedTransaction> for Transaction {
 | 
			
		||||
	fn from(t: SignedTransaction) -> Transaction {
 | 
			
		||||
		Transaction {
 | 
			
		||||
			hash: t.hash(),
 | 
			
		||||
			nonce: t.nonce,
 | 
			
		||||
			block_hash: OptionalValue::Null,
 | 
			
		||||
			block_number: OptionalValue::Null,
 | 
			
		||||
			transaction_index: OptionalValue::Null,
 | 
			
		||||
			from: t.sender().unwrap(),
 | 
			
		||||
			to: match t.action {
 | 
			
		||||
				Action::Create => OptionalValue::Null,
 | 
			
		||||
				Action::Call(ref address) => OptionalValue::Value(address.clone())
 | 
			
		||||
			},
 | 
			
		||||
			value: t.value,
 | 
			
		||||
			gas_price: t.gas_price,
 | 
			
		||||
			gas: t.gas,
 | 
			
		||||
			input: Bytes::new(t.data.clone())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
	use super::*;
 | 
			
		||||
 | 
			
		||||
@ -102,4 +102,27 @@ mod tests {
 | 
			
		||||
			nonce: None,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	#[test]
 | 
			
		||||
	fn transaction_request_deserialize_test() {
 | 
			
		||||
		let s = r#"{
 | 
			
		||||
			"from":"0xb5f7502a2807cb23615c7456055e1d65b2508625",
 | 
			
		||||
			"to":"0x895d32f2db7d01ebb50053f9e48aacf26584fe40",
 | 
			
		||||
			"data":"0x8595bab1",
 | 
			
		||||
			"gas":"0x2fd618",
 | 
			
		||||
			"gasPrice":"0x0ba43b7400"
 | 
			
		||||
		}"#;
 | 
			
		||||
 | 
			
		||||
		let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
 | 
			
		||||
 | 
			
		||||
		assert_eq!(deserialized, TransactionRequest {
 | 
			
		||||
			from: Address::from_str("b5f7502a2807cb23615c7456055e1d65b2508625").unwrap(),
 | 
			
		||||
			to: Some(Address::from_str("895d32f2db7d01ebb50053f9e48aacf26584fe40").unwrap()),
 | 
			
		||||
			gas_price: Some(U256::from_str("0ba43b7400").unwrap()),
 | 
			
		||||
			gas: Some(U256::from_str("2fd618").unwrap()),
 | 
			
		||||
			value: None,
 | 
			
		||||
			data: Some(Bytes::new(vec![0x85, 0x95, 0xba, 0xb1])),
 | 
			
		||||
			nonce: None,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -75,7 +75,8 @@ pub struct SecretStore {
 | 
			
		||||
 | 
			
		||||
struct AccountUnlock {
 | 
			
		||||
	secret: H256,
 | 
			
		||||
	expires: DateTime<UTC>,
 | 
			
		||||
	/// expiration datetime (None - never)
 | 
			
		||||
	expires: Option<DateTime<UTC>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Basic account management trait
 | 
			
		||||
@ -148,6 +149,11 @@ impl AccountService {
 | 
			
		||||
	pub fn tick(&self) {
 | 
			
		||||
		self.secret_store.write().unwrap().collect_garbage();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    /// Unlocks account for use (no expiration of unlock)
 | 
			
		||||
	pub fn unlock_account_no_expire(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> {
 | 
			
		||||
		self.secret_store.write().unwrap().unlock_account_with_expiration(account, pass, None)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -226,14 +232,23 @@ impl SecretStore {
 | 
			
		||||
 | 
			
		||||
	/// Unlocks account for use
 | 
			
		||||
	pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> {
 | 
			
		||||
		self.unlock_account_with_expiration(account, pass, Some(UTC::now() + Duration::minutes(20)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Unlocks account for use (no expiration of unlock)
 | 
			
		||||
	pub fn unlock_account_no_expire(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> {
 | 
			
		||||
		self.unlock_account_with_expiration(account, pass, None)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fn unlock_account_with_expiration(&self, account: &Address, pass: &str, expiration: Option<DateTime<UTC>>) -> Result<(), EncryptedHashMapError> {
 | 
			
		||||
		let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier));
 | 
			
		||||
		let secret = try!(self.get(&secret_id, pass));
 | 
			
		||||
		{
 | 
			
		||||
			let mut write_lock = self.unlocks.write().unwrap();
 | 
			
		||||
			let mut unlock = write_lock.entry(*account)
 | 
			
		||||
				.or_insert_with(|| AccountUnlock { secret: secret, expires: UTC::now() });
 | 
			
		||||
				.or_insert_with(|| AccountUnlock { secret: secret, expires: Some(UTC::now()) });
 | 
			
		||||
			unlock.secret = secret;
 | 
			
		||||
			unlock.expires = UTC::now() + Duration::minutes(20);
 | 
			
		||||
			unlock.expires = expiration;
 | 
			
		||||
		}
 | 
			
		||||
		Ok(())
 | 
			
		||||
	}
 | 
			
		||||
@ -277,7 +292,7 @@ impl SecretStore {
 | 
			
		||||
		self.directory.collect_garbage();
 | 
			
		||||
		let utc = UTC::now();
 | 
			
		||||
		let expired_addresses = garbage_lock.iter()
 | 
			
		||||
			.filter(|&(_, unlock)| unlock.expires < utc)
 | 
			
		||||
			.filter(|&(_, unlock)| match unlock.expires { Some(ref expire_val) => expire_val < &utc, _ => false })
 | 
			
		||||
			.map(|(address, _)| address.clone()).collect::<Vec<Address>>();
 | 
			
		||||
 | 
			
		||||
		for expired in expired_addresses { garbage_lock.remove(&expired); }
 | 
			
		||||
@ -629,7 +644,7 @@ mod tests {
 | 
			
		||||
			let ss_rw = svc.secret_store.write().unwrap();
 | 
			
		||||
			let mut ua_rw = ss_rw.unlocks.write().unwrap();
 | 
			
		||||
			let entry = ua_rw.entry(address);
 | 
			
		||||
			if let Entry::Occupied(mut occupied) = entry { occupied.get_mut().expires = UTC::now() - Duration::minutes(1); }
 | 
			
		||||
			if let Entry::Occupied(mut occupied) = entry { occupied.get_mut().expires = Some(UTC::now() - Duration::minutes(1)) }
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		svc.tick();
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user