Supporting blockid in eth_call and trace_call/trace_raw (#1837)

* Supporting blockid in eth_call and trace_call/trace_raw

* Nicer state diff handling

* Purging deref.deref
This commit is contained in:
Tomasz Drwięga
2016-08-04 18:17:21 +02:00
committed by Gav Wood
parent 979f4e0617
commit 25aabe6e52
15 changed files with 154 additions and 117 deletions

View File

@@ -44,8 +44,7 @@ use self::ethash::SeedHashCompute;
use v1::traits::Eth;
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256};
use v1::helpers::CallRequest as CRequest;
use v1::impls::{default_gas_price, dispatch_transaction, error_codes};
use serde;
use v1::impls::{default_gas_price, dispatch_transaction, error_codes, from_params_default_second, from_params_default_third};
/// Eth RPC options
pub struct EthClientOptions {
@@ -215,27 +214,6 @@ pub fn pending_logs<M>(miner: &M, filter: &EthcoreFilter) -> Vec<Log> where M: M
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
fn params_len(params: &Params) -> usize {
match params {
&Params::Array(ref vec) => vec.len(),
_ => 0,
}
}
fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
match params_len(&params) {
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
_ => from_params::<(F, BlockNumber)>(params),
}
}
fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
match params_len(&params) {
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
_ => from_params::<(F1, F2, BlockNumber)>(params)
}
}
fn make_unsupported_err() -> Error {
Error {
code: ErrorCode::ServerError(error_codes::UNSUPPORTED_REQUEST_CODE),
@@ -656,8 +634,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
let signed = try!(self.sign_call(request));
let r = match block_number {
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
BlockNumber::Latest => take_weak!(self.client).call(&signed, Default::default()),
_ => panic!("{:?}", block_number),
block_number => take_weak!(self.client).call(&signed, block_number.into(), Default::default()),
};
to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![])))
})
@@ -671,8 +648,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
let signed = try!(self.sign_call(request));
let r = match block_number {
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
BlockNumber::Latest => take_weak!(self.client).call(&signed, Default::default()),
_ => return Err(Error::invalid_params()),
block => take_weak!(self.client).call(&signed, block.into(), Default::default()),
};
to_value(&RpcU256::from(r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))))
})

View File

@@ -53,8 +53,9 @@ pub use self::ethcore_set::EthcoreSetClient;
pub use self::traces::TracesClient;
pub use self::rpc::RpcClient;
use serde;
use v1::helpers::TransactionRequest;
use v1::types::{H256 as RpcH256, H520 as RpcH520};
use v1::types::{H256 as RpcH256, H520 as RpcH520, BlockNumber};
use ethcore::error::Error as EthcoreError;
use ethcore::miner::MinerService;
use ethcore::client::MiningBlockChainClient;
@@ -63,7 +64,7 @@ use ethcore::account_provider::{AccountProvider, Error as AccountError};
use util::numbers::*;
use util::rlp::encode;
use util::bytes::ToPretty;
use jsonrpc_core::{Error, ErrorCode, Value, to_value};
use jsonrpc_core::{Error, ErrorCode, Value, to_value, from_params, Params};
mod error_codes {
// NOTE [ToDr] Codes from [-32099, -32000]
@@ -79,6 +80,30 @@ mod error_codes {
pub const REQUEST_NOT_FOUND: i64 = -32041;
}
fn params_len(params: &Params) -> usize {
match params {
&Params::Array(ref vec) => vec.len(),
_ => 0,
}
}
/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
pub fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
match params_len(&params) {
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
_ => from_params::<(F, BlockNumber)>(params),
}
}
/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
pub fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
match params_len(&params) {
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
_ => from_params::<(F1, F2, BlockNumber)>(params)
}
}
fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
where C: MiningBlockChainClient, M: MinerService {
let hash = RpcH256::from(signed_transaction.hash());

View File

@@ -25,6 +25,7 @@ use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Act
use v1::traits::Traces;
use v1::helpers::CallRequest as CRequest;
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
use v1::impls::from_params_default_third;
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
CallAnalytics {
@@ -122,11 +123,11 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
fn call(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params(params)
.and_then(|(request, flags)| {
from_params_default_third(params)
.and_then(|(request, flags, block)| {
let request = CallRequest::into(request);
let signed = try!(self.sign_call(request));
match take_weak!(self.client).call(&signed, to_call_analytics(flags)) {
match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) {
Ok(e) => to_value(&TraceResults::from(e)),
_ => Ok(Value::Null),
}
@@ -135,11 +136,11 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
fn raw_transaction(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(Bytes, _)>(params)
.and_then(|(raw_transaction, flags)| {
let raw_transaction = raw_transaction.to_vec();
from_params_default_third(params)
.and_then(|(raw_transaction, flags, block)| {
let raw_transaction = Bytes::to_vec(raw_transaction);
match UntrustedRlp::new(&raw_transaction).as_val() {
Ok(signed) => match take_weak!(self.client).call(&signed, to_call_analytics(flags)) {
Ok(signed) => match take_weak!(self.client).call(&signed, block.into(), to_call_analytics(flags)) {
Ok(e) => to_value(&TraceResults::from(e)),
_ => Ok(Value::Null),
},

View File

@@ -18,7 +18,7 @@
use util::{Address, H256, Bytes, U256, FixedHash, Uint};
use util::standard::*;
use ethcore::error::{Error, ExecutionError};
use ethcore::error::{Error, CallError};
use ethcore::client::{MiningBlockChainClient, Executed, CallAnalytics};
use ethcore::block::{ClosedBlock, IsBlock};
use ethcore::transaction::SignedTransaction;
@@ -220,7 +220,7 @@ impl MinerService for TestMinerService {
self.latest_closed_block.lock().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone())
}
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
fn call(&self, _chain: &MiningBlockChainClient, _t: &SignedTransaction, _analytics: CallAnalytics) -> Result<Executed, CallError> {
unimplemented!();
}

View File

@@ -423,9 +423,9 @@ fn rpc_eth_code() {
}
#[test]
fn rpc_eth_call() {
fn rpc_eth_call_latest() {
let tester = EthTester::default();
tester.client.set_execution_result(Executed {
tester.client.set_execution_result(Ok(Executed {
gas: U256::zero(),
gas_used: U256::from(0xff30),
refunded: U256::from(0x5),
@@ -436,7 +436,7 @@ fn rpc_eth_call() {
trace: vec![],
vm_trace: None,
state_diff: None,
});
}));
let request = r#"{
"jsonrpc": "2.0",
@@ -458,9 +458,9 @@ fn rpc_eth_call() {
}
#[test]
fn rpc_eth_call_default_block() {
fn rpc_eth_call() {
let tester = EthTester::default();
tester.client.set_execution_result(Executed {
tester.client.set_execution_result(Ok(Executed {
gas: U256::zero(),
gas_used: U256::from(0xff30),
refunded: U256::from(0x5),
@@ -471,7 +471,42 @@ fn rpc_eth_call_default_block() {
trace: vec![],
vm_trace: None,
state_diff: None,
});
}));
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"gas": "0x76c0",
"gasPrice": "0x9184e72a000",
"value": "0x9184e72a",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
},
"0x0"],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x1234ff","id":1}"#;
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
}
#[test]
fn rpc_eth_call_default_block() {
let tester = EthTester::default();
tester.client.set_execution_result(Ok(Executed {
gas: U256::zero(),
gas_used: U256::from(0xff30),
refunded: U256::from(0x5),
cumulative_gas_used: U256::zero(),
logs: vec![],
contracts_created: vec![],
output: vec![0x12, 0x34, 0xff],
trace: vec![],
vm_trace: None,
state_diff: None,
}));
let request = r#"{
"jsonrpc": "2.0",
@@ -494,7 +529,7 @@ fn rpc_eth_call_default_block() {
#[test]
fn rpc_eth_estimate_gas() {
let tester = EthTester::default();
tester.client.set_execution_result(Executed {
tester.client.set_execution_result(Ok(Executed {
gas: U256::zero(),
gas_used: U256::from(0xff30),
refunded: U256::from(0x5),
@@ -505,7 +540,7 @@ fn rpc_eth_estimate_gas() {
trace: vec![],
vm_trace: None,
state_diff: None,
});
}));
let request = r#"{
"jsonrpc": "2.0",
@@ -529,7 +564,7 @@ fn rpc_eth_estimate_gas() {
#[test]
fn rpc_eth_estimate_gas_default_block() {
let tester = EthTester::default();
tester.client.set_execution_result(Executed {
tester.client.set_execution_result(Ok(Executed {
gas: U256::zero(),
gas_used: U256::from(0xff30),
refunded: U256::from(0x5),
@@ -540,7 +575,7 @@ fn rpc_eth_estimate_gas_default_block() {
trace: vec![],
vm_trace: None,
state_diff: None,
});
}));
let request = r#"{
"jsonrpc": "2.0",