From 3adfebdc2039a50f7c5d1a1dca4efaefb8d1e1f3 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 8 Feb 2016 10:58:08 +0100 Subject: [PATCH] jsonrpc eth_getCode method --- ethcore/src/client.rs | 7 ++++ rpc/Cargo.toml | 2 +- rpc/src/lib.rs | 1 + rpc/src/v1/impls/eth.rs | 10 ++++- rpc/src/v1/types/block_number.rs | 68 ++++++++++++++++++++++++++++++++ rpc/src/v1/types/bytes.rs | 37 +++++++++++++++++ rpc/src/v1/types/mod.rs | 4 ++ 7 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 rpc/src/v1/types/block_number.rs create mode 100644 rpc/src/v1/types/bytes.rs diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 3a0309c1c..28181f5fa 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -86,6 +86,9 @@ pub trait BlockChainClient : Sync + Send { /// Get block total difficulty. fn block_total_difficulty(&self, hash: &H256) -> Option; + /// Get address code. + fn code(&self, address: &Address) -> Option; + /// Get raw block header data by block number. fn block_header_at(&self, n: BlockNumber) -> Option; @@ -357,6 +360,10 @@ impl BlockChainClient for Client { self.chain.read().unwrap().block_details(hash).map(|d| d.total_difficulty) } + fn code(&self, address: &Address) -> Option { + self.state().code(address) + } + fn block_header_at(&self, n: BlockNumber) -> Option { self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_header(&h)) } diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index bea85a74f..66688466c 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -18,4 +18,4 @@ ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } clippy = "0.0.37" target_info = "0.1.0" - +rustc-serialize = "0.3" diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index bf82a64a0..0b148c983 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,6 +20,7 @@ #![plugin(serde_macros)] #![plugin(clippy)] +extern crate rustc_serialize; extern crate target_info; extern crate serde; extern crate serde_json; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 72687e03c..d8bcf9540 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,7 +23,7 @@ use util::sha3::*; use ethcore::client::*; use ethcore::views::*; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, SyncStatus}; +use v1::types::{Block, BlockNumber, Bytes, SyncStatus}; /// Eth rpc implementation. pub struct EthClient { @@ -115,6 +115,14 @@ impl Eth for EthClient { } } + // TODO: do not ignore block number param + fn code_at(&self, params: Params) -> Result { + match from_params::<(Address, BlockNumber)>(params) { + Ok((address, _block_number)) => to_value(&Bytes::new(self.client.code(&address).unwrap_or_else(|| vec![]))), + Err(err) => Err(err) + } + } + fn block(&self, params: Params) -> Result { match from_params::<(H256, bool)>(params) { Ok((hash, _include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) { diff --git a/rpc/src/v1/types/block_number.rs b/rpc/src/v1/types/block_number.rs new file mode 100644 index 000000000..bfe20f177 --- /dev/null +++ b/rpc/src/v1/types/block_number.rs @@ -0,0 +1,68 @@ +// 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 . + +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; + +/// Represents rpc api block number param. +#[derive(Debug, PartialEq)] +pub enum BlockNumber { + Num(u64), + Latest, + Earliest, + Pending +} + +impl Deserialize for BlockNumber { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.visit(BlockNumberVisitor) + } +} + +struct BlockNumberVisitor; + +impl Visitor for BlockNumberVisitor { + type Value = BlockNumber; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + match value { + "latest" => Ok(BlockNumber::Latest), + "earliest" => Ok(BlockNumber::Earliest), + "pending" => Ok(BlockNumber::Pending), + _ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")), + _ => value.parse::().map(BlockNumber::Num).map_err(|_| Error::syntax("invalid block number")) + } + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn block_number_deserialization() { + let s = r#"["0xa", "10", "latest", "earliest", "pending"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![BlockNumber::Num(10), BlockNumber::Num(10), BlockNumber::Latest, BlockNumber::Earliest, BlockNumber::Pending]) + } +} + diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs new file mode 100644 index 000000000..51cb7f333 --- /dev/null +++ b/rpc/src/v1/types/bytes.rs @@ -0,0 +1,37 @@ +use rustc_serialize::hex::ToHex; +use serde::{Serialize, Serializer}; + +/// Wrapper structure around vector of bytes. +pub struct Bytes(Vec); + +impl Bytes { + /// Simple constructor. + pub fn new(bytes: Vec) -> Bytes { + Bytes(bytes) + } +} + +impl Serialize for Bytes { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: Serializer { + let mut serialized = "0x".to_owned(); + serialized.push_str(self.0.to_hex().as_ref()); + serializer.visit_str(serialized.as_ref()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + use rustc_serialize::hex::FromHex; + + #[test] + fn test_bytes_serialize() { + let bytes = Bytes("0123456789abcdef".from_hex().unwrap()); + let serialized = serde_json::to_string(&bytes).unwrap(); + assert_eq!(serialized, r#""0x0123456789abcdef""#); + } +} + + diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 1b03485ab..0b8582910 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -15,7 +15,11 @@ // along with Parity. If not, see . mod block; +mod block_number; +mod bytes; mod sync; pub use self::block::Block; +pub use self::block_number::BlockNumber; +pub use self::bytes::Bytes; pub use self::sync::SyncStatus;