diff --git a/src/builtin.rs b/src/builtin.rs index 0c1e60d5f..85319c948 100644 --- a/src/builtin.rs +++ b/src/builtin.rs @@ -39,6 +39,12 @@ impl Builtin { }) } + /// Simple forwarder for cost. + pub fn cost(&self, s: usize) -> U256 { (*self.cost)(s) } + + /// Simple forwarder for execute. + pub fn execute(&self, input: &[u8], output: &mut[u8]) { (*self.execute)(input, output); } + /// Create a builtin from JSON. /// /// JSON must be of the form `{ "name": "identity", "linear": {"base": 10, "word": 20} }`. @@ -55,12 +61,6 @@ impl Builtin { } None } - - /// Simple forwarder for cost. - pub fn cost(&self, s: usize) -> U256 { (*self.cost)(s) } - - /// Simple forwarder for execute. - pub fn execute(&self, input: &[u8], output: &mut[u8]) { (*self.execute)(input, output); } } pub fn copy_to(src: &[u8], dest: &mut[u8]) { diff --git a/src/env_info.rs b/src/env_info.rs index c806f228d..964312449 100644 --- a/src/env_info.rs +++ b/src/env_info.rs @@ -36,15 +36,17 @@ impl EnvInfo { gas_used: x!(0), } } +} - pub fn from_json(json: &Json) -> EnvInfo { - let current_number = u64_from_json(&json["currentNumber"]); +impl FromJson for EnvInfo { + fn from_json(json: &Json) -> EnvInfo { + let current_number: u64 = xjson!(&json["currentNumber"]); EnvInfo { number: current_number, - author: address_from_json(&json["currentCoinbase"]), + author: xjson!(&json["currentCoinbase"]), difficulty: xjson!(&json["currentDifficulty"]), gas_limit: xjson!(&json["currentGasLimit"]), - timestamp: u64_from_json(&json["currentTimestamp"]), + timestamp: xjson!(&json["currentTimestamp"]), last_hashes: (1..257).map(|i| format!("{}", current_number - i).as_bytes().sha3()).collect(), gas_used: x!(0), } diff --git a/src/log_entry.rs b/src/log_entry.rs index b16dfe9fc..cd4353874 100644 --- a/src/log_entry.rs +++ b/src/log_entry.rs @@ -28,16 +28,6 @@ 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 @@ -59,6 +49,18 @@ impl LogEntry { } } +impl FromJson for LogEntry { + /// Convert given JSON object to a LogEntry. + fn from_json(json: &Json) -> LogEntry { + // TODO: check bloom. + LogEntry { + address: xjson!(&json["address"]), + topics: xjson!(&json["topics"]), + data: xjson!(&json["data"]), + } + } +} + #[cfg(test)] mod tests { use util::*; diff --git a/src/pod_state.rs b/src/pod_state.rs index ff456bda3..e3802c42a 100644 --- a/src/pod_state.rs +++ b/src/pod_state.rs @@ -8,13 +8,21 @@ impl PodState { /// Contruct a new object from the `m`. pub fn new(m: BTreeMap) -> PodState { PodState(m) } + /// Get the underlying map. + pub fn get(&self) -> &BTreeMap { &self.0 } + + /// Drain object to get the underlying map. + pub fn drain(self) -> BTreeMap { self.0 } +} + +impl FromJson for PodState { /// Translate the JSON object into a hash map of account information ready for insertion into State. - pub fn from_json(json: &Json) -> PodState { + 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); + let storage = acc.find("storage").map(&BTreeMap::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()), @@ -26,12 +34,6 @@ impl PodState { state })) } - - /// Get the underlying map. - pub fn get(&self) -> &BTreeMap { &self.0 } - - /// Drain object to get the underlying map. - pub fn drain(self) -> BTreeMap { self.0 } } impl fmt::Display for PodState { diff --git a/src/spec.rs b/src/spec.rs index acdfd2ecf..c9e3383eb 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -148,9 +148,11 @@ impl Spec { ret.append_raw(&empty_list, 1); ret.out() } +} +impl FromJson for Spec { /// Loads a chain-specification from a json data structure - pub fn from_json(json: Json) -> Spec { + fn from_json(json: &Json) -> Spec { // once we commit ourselves to some json parsing library (serde?) // move it to proper data structure let mut state = HashMap::new(); @@ -210,7 +212,9 @@ impl Spec { state_root_memo: RwLock::new(genesis.find("stateRoot").and_then(|_| genesis["stateRoot"].as_string()).map(|s| H256::from_str(&s[2..]).unwrap())), } } +} +impl Spec { /// Ensure that the given state DB has the trie nodes in for the genesis state. pub fn ensure_db_good(&self, db: &mut HashDB) { if !db.contains(&self.state_root()) { @@ -229,8 +233,7 @@ impl Spec { /// Create a new Spec from a JSON string. pub fn from_json_str(s: &str) -> Spec { - let json = Json::from_str(s).expect("Json is invalid"); - Self::from_json(json) + Self::from_json(&Json::from_str(s).expect("Json is invalid")) } /// Create a new Spec which conforms to the Morden chain except that it's a NullEngine consensus. diff --git a/src/tests/executive.rs b/src/tests/executive.rs index 1e95082ae..61c4df7ac 100644 --- a/src/tests/executive.rs +++ b/src/tests/executive.rs @@ -170,24 +170,19 @@ fn do_json_test(json_data: &[u8]) -> Vec { test.find("pre").map(|pre| for (addr, s) in pre.as_object().unwrap() { let address = Address::from(addr.as_ref()); let balance = xjson!(&s["balance"]); - let code = bytes_from_json(&s["code"]); + let code = xjson!(&s["code"]); let _nonce: U256 = xjson!(&s["nonce"]); state.new_contract(&address); state.add_balance(&address, &balance); state.init_code(&address, code); - - for (k, v) in s["storage"].as_object().unwrap() { - let key = H256::from(&u256_from_str(k)); - let val = H256::from(&U256::from_json(v)); - state.set_storage(&address, key, val); - } + BTreeMap::from_json(&s["storage"]).into_iter().foreach(|(k, v)| state.set_storage(&address, k, v)); }); let mut info = EnvInfo::new(); test.find("env").map(|env| { - info.author = address_from_json(&env["currentCoinbase"]); + info.author = xjson!(&env["currentCoinbase"]); info.difficulty = xjson!(&env["currentDifficulty"]); info.gas_limit = xjson!(&env["currentGasLimit"]); info.number = xjson!(&env["currentNumber"]); @@ -199,11 +194,11 @@ fn do_json_test(json_data: &[u8]) -> Vec { // params let mut params = ActionParams::new(); test.find("exec").map(|exec| { - params.address = address_from_json(&exec["address"]); - params.sender = address_from_json(&exec["caller"]); - params.origin = address_from_json(&exec["origin"]); - params.code = bytes_from_json(&exec["code"]); - params.data = bytes_from_json(&exec["data"]); + params.address = xjson!(&exec["address"]); + params.sender = xjson!(&exec["caller"]); + params.origin = xjson!(&exec["origin"]); + params.code = xjson!(&exec["code"]); + params.data = xjson!(&exec["data"]); params.gas = xjson!(&exec["gas"]); params.gas_price = xjson!(&exec["gasPrice"]); params.value = xjson!(&exec["value"]); @@ -231,23 +226,16 @@ fn do_json_test(json_data: &[u8]) -> Vec { //println!("name: {}, gas_left : {:?}, expected: {:?}", name, gas_left, U256::from(&test["gas"])); fail_unless(!out_of_gas, "expected to run out of gas."); fail_unless(gas_left == xjson!(&test["gas"]), "gas_left is incorrect"); - fail_unless(output == bytes_from_json(&test["out"]), "output is incorrect"); + fail_unless(output == Bytes::from_json(&test["out"]), "output is incorrect"); test.find("post").map(|pre| for (addr, s) in pre.as_object().unwrap() { let address = Address::from(addr.as_ref()); - //let balance = U256::from(&s["balance"]); - fail_unless(state.code(&address).unwrap_or(vec![]) == bytes_from_json(&s["code"]), "code is incorrect"); + fail_unless(state.code(&address).unwrap_or(vec![]) == Bytes::from_json(&s["code"]), "code is incorrect"); fail_unless(state.balance(&address) == xjson!(&s["balance"]), "balance is incorrect"); fail_unless(state.nonce(&address) == xjson!(&s["nonce"]), "nonce is incorrect"); - - for (k, v) in s["storage"].as_object().unwrap() { - let key = H256::from(&u256_from_str(k)); - let val = H256::from(&U256::from_json(v)); - - fail_unless(state.storage_at(&address, &key) == val, "storage is incorrect"); - } + BTreeMap::from_json(&s["storage"]).iter().foreach(|(k, v)| fail_unless(&state.storage_at(&address, &k) == v, "storage is incorrect")); }); let cc = test["callcreates"].as_array().unwrap(); @@ -255,8 +243,8 @@ fn do_json_test(json_data: &[u8]) -> Vec { for i in 0..cc.len() { let is = &callcreates[i]; let expected = &cc[i]; - fail_unless(is.data == bytes_from_json(&expected["data"]), "callcreates data is incorrect"); - fail_unless(is.destination == address_from_json(&expected["destination"]), "callcreates destination is incorrect"); + fail_unless(is.data == Bytes::from_json(&expected["data"]), "callcreates data is incorrect"); + fail_unless(is.destination == xjson!(&expected["destination"]), "callcreates destination is incorrect"); fail_unless(is.value == xjson!(&expected["value"]), "callcreates value is incorrect"); // TODO: call_gas is calculated in externalities and is not exposed to TestExt. diff --git a/src/tests/state.rs b/src/tests/state.rs index 58e57558c..7aa5b4882 100644 --- a/src/tests/state.rs +++ b/src/tests/state.rs @@ -16,8 +16,8 @@ fn do_json_test(json_data: &[u8]) -> Vec { let t = Transaction::from_json(&test["transaction"]); let env = EnvInfo::from_json(&test["env"]); - let _out = bytes_from_json(&test["out"]); - let post_state_root = h256_from_json(&test["postStateRoot"]); + 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(); diff --git a/src/tests/transaction.rs b/src/tests/transaction.rs index 0660b2345..d4836ca84 100644 --- a/src/tests/transaction.rs +++ b/src/tests/transaction.rs @@ -14,23 +14,23 @@ fn do_json_test(json_data: &[u8]) -> Vec { .and_then(|j| j.as_string()) .and_then(|s| BlockNumber::from_str(s).ok()) .unwrap_or(0) { x if x < 900000 => &old_schedule, _ => &new_schedule }; - let rlp = bytes_from_json(&test["rlp"]); + let rlp = Bytes::from_json(&test["rlp"]); let res = UntrustedRlp::new(&rlp).as_val().map_err(|e| From::from(e)).and_then(|t: Transaction| t.validate(schedule, schedule.have_delegate_call)); fail_unless(test.find("transaction").is_none() == res.is_err()); if let (Some(&Json::Object(ref tx)), Some(&Json::String(ref expect_sender))) = (test.find("transaction"), test.find("sender")) { let t = res.unwrap(); fail_unless(t.sender().unwrap() == address_from_hex(clean(expect_sender))); - fail_unless(t.data == bytes_from_json(&tx["data"])); + fail_unless(t.data == Bytes::from_json(&tx["data"])); fail_unless(t.gas == xjson!(&tx["gasLimit"])); fail_unless(t.gas_price == xjson!(&tx["gasPrice"])); fail_unless(t.nonce == xjson!(&tx["nonce"])); fail_unless(t.value == xjson!(&tx["value"])); if let Action::Call(ref to) = t.action { *ot.borrow_mut() = t.clone(); - fail_unless(to == &address_from_json(&tx["to"])); + fail_unless(to == &xjson!(&tx["to"])); } else { *ot.borrow_mut() = t.clone(); - fail_unless(bytes_from_json(&tx["to"]).len() == 0); + fail_unless(Bytes::from_json(&tx["to"]).len() == 0); } } } diff --git a/src/transaction.rs b/src/transaction.rs index f0441d774..56acf5ab7 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -79,32 +79,6 @@ impl Transaction { } } - pub fn from_json(json: &Json) -> Transaction { - let mut r = Transaction { - nonce: xjson!(&json["nonce"]), - gas_price: xjson!(&json["gasPrice"]), - gas: xjson!(&json["gasLimit"]), - action: match bytes_from_json(&json["to"]) { - ref x if x.len() == 0 => Action::Create, - ref x => Action::Call(Address::from_slice(x)), - }, - value: xjson!(&json["value"]), - data: bytes_from_json(&json["data"]), - v: match json.find("v") { Some(ref j) => u8_from_json(j), None => 0 }, - r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, - s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, - hash: RefCell::new(None), - sender: match json.find("sender") { - Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), - _ => RefCell::new(None), - }, - }; - if let Some(&Json::String(ref secret_key)) = json.find("secretKey") { - r.sign(&h256_from_hex(clean(secret_key))); - } - r - } - /// Get the nonce of the transaction. pub fn nonce(&self) -> &U256 { &self.nonce } /// Get the gas price of the transaction. @@ -144,6 +118,34 @@ impl Transaction { } } +impl FromJson for Transaction { + fn from_json(json: &Json) -> Transaction { + let mut r = Transaction { + nonce: xjson!(&json["nonce"]), + gas_price: xjson!(&json["gasPrice"]), + gas: xjson!(&json["gasLimit"]), + action: match Bytes::from_json(&json["to"]) { + ref x if x.len() == 0 => Action::Create, + ref x => Action::Call(Address::from_slice(x)), + }, + value: xjson!(&json["value"]), + data: xjson!(&json["data"]), + v: match json.find("v") { Some(ref j) => u16::from_json(j) as u8, None => 0 }, + r: match json.find("r") { Some(j) => xjson!(j), None => x!(0) }, + s: match json.find("s") { Some(j) => xjson!(j), None => x!(0) }, + hash: RefCell::new(None), + sender: match json.find("sender") { + Some(&Json::String(ref sender)) => RefCell::new(Some(address_from_hex(clean(sender)))), + _ => RefCell::new(None), + }, + }; + if let Some(&Json::String(ref secret_key)) = json.find("secretKey") { + r.sign(&h256_from_hex(clean(secret_key))); + } + r + } +} + impl RlpStandard for Transaction { fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_opt(s, Seal::With) } }