Support 'pending' block in RPC (#1007)
* Support `pending` block in RPC * Forward calls from miner to client in case no pending block is available
This commit is contained in:
committed by
Gav Wood
parent
ea669ac6b6
commit
8f7624f5cb
@@ -200,17 +200,17 @@ fn params_len(params: &Params) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
fn from_params_discard_second<F>(params: Params) -> Result<(F,), Error> where F: serde::de::Deserialize {
|
||||
fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
1 => from_params::<(F, )>(params),
|
||||
_ => from_params::<(F, BlockNumber)>(params).map(|(f, _block_number)| (f, )),
|
||||
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
|
||||
_ => from_params::<(F, BlockNumber)>(params),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_params_discard_third<F1, F2>(params: Params) -> Result<(F1, F2,), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
|
||||
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(¶ms) {
|
||||
2 => from_params::<(F1, F2, )>(params),
|
||||
_ => from_params::<(F1, F2, BlockNumber)>(params).map(|(f1, f2, _block_number)| (f1, f2, )),
|
||||
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
|
||||
_ => from_params::<(F1, F2, BlockNumber)>(params)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,18 +293,30 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
||||
}
|
||||
|
||||
fn balance(&self, params: Params) -> Result<Value, Error> {
|
||||
from_params_discard_second(params).and_then(|(address, )|
|
||||
to_value(&take_weak!(self.client).balance(&address)))
|
||||
from_params_default_second(params)
|
||||
.and_then(|(address, block_number,)| match block_number {
|
||||
BlockNumber::Latest => to_value(&take_weak!(self.client).balance(&address)),
|
||||
BlockNumber::Pending => to_value(&take_weak!(self.miner).balance(take_weak!(self.client).deref(), &address)),
|
||||
_ => Err(Error::invalid_params()),
|
||||
})
|
||||
}
|
||||
|
||||
fn storage_at(&self, params: Params) -> Result<Value, Error> {
|
||||
from_params_discard_third::<Address, U256>(params).and_then(|(address, position, )|
|
||||
to_value(&U256::from(take_weak!(self.client).storage_at(&address, &H256::from(position)))))
|
||||
from_params_default_third::<Address, U256>(params)
|
||||
.and_then(|(address, position, block_number,)| match block_number {
|
||||
BlockNumber::Pending => to_value(&U256::from(take_weak!(self.miner).storage_at(take_weak!(self.client).deref(), &address, &H256::from(position)))),
|
||||
BlockNumber::Latest => to_value(&U256::from(take_weak!(self.client).storage_at(&address, &H256::from(position)))),
|
||||
_ => Err(Error::invalid_params()),
|
||||
})
|
||||
}
|
||||
|
||||
fn transaction_count(&self, params: Params) -> Result<Value, Error> {
|
||||
from_params_discard_second(params).and_then(|(address, )|
|
||||
to_value(&take_weak!(self.client).nonce(&address)))
|
||||
from_params_default_second(params)
|
||||
.and_then(|(address, block_number,)| match block_number {
|
||||
BlockNumber::Pending => to_value(&take_weak!(self.miner).nonce(take_weak!(self.client).deref(), &address)),
|
||||
BlockNumber::Latest => to_value(&take_weak!(self.client).nonce(&address)),
|
||||
_ => Err(Error::invalid_params()),
|
||||
})
|
||||
}
|
||||
|
||||
fn block_transaction_count_by_hash(&self, params: Params) -> Result<Value, Error> {
|
||||
@@ -341,10 +353,13 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: do not ignore block number param
|
||||
fn code_at(&self, params: Params) -> Result<Value, Error> {
|
||||
from_params_discard_second(params).and_then(|(address, )|
|
||||
to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new)))
|
||||
from_params_default_second(params)
|
||||
.and_then(|(address, block_number,)| match block_number {
|
||||
BlockNumber::Pending => to_value(&take_weak!(self.miner).code(take_weak!(self.client).deref(), &address).map_or_else(Bytes::default, Bytes::new)),
|
||||
BlockNumber::Latest => to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new)),
|
||||
_ => Err(Error::invalid_params()),
|
||||
})
|
||||
}
|
||||
|
||||
fn block_by_hash(&self, params: Params) -> Result<Value, Error> {
|
||||
@@ -502,21 +517,29 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
||||
|
||||
fn call(&self, params: Params) -> Result<Value, Error> {
|
||||
trace!(target: "jsonrpc", "call: {:?}", params);
|
||||
from_params_discard_second(params).and_then(|(request, )| {
|
||||
let signed = try!(self.sign_call(request));
|
||||
let client = take_weak!(self.client);
|
||||
let output = client.call(&signed).map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![]));
|
||||
to_value(&output)
|
||||
})
|
||||
from_params_default_second(params)
|
||||
.and_then(|(request, block_number,)| {
|
||||
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),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed),
|
||||
_ => panic!("{:?}", block_number),
|
||||
};
|
||||
to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![])))
|
||||
})
|
||||
}
|
||||
|
||||
fn estimate_gas(&self, params: Params) -> Result<Value, Error> {
|
||||
from_params_discard_second(params).and_then(|(request, )| {
|
||||
let signed = try!(self.sign_call(request));
|
||||
let client = take_weak!(self.client);
|
||||
let used = client.call(&signed).map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0));
|
||||
to_value(&used)
|
||||
})
|
||||
from_params_default_second(params)
|
||||
.and_then(|(request, block_number,)| {
|
||||
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),
|
||||
BlockNumber::Latest => take_weak!(self.client).call(&signed),
|
||||
_ => return Err(Error::invalid_params()),
|
||||
};
|
||||
to_value(&r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0)))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -192,6 +192,22 @@ fn rpc_eth_balance() {
|
||||
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[ignore] //TODO: propert test
|
||||
#[test]
|
||||
fn rpc_eth_balance_pending() {
|
||||
let tester = EthTester::default();
|
||||
|
||||
let request = r#"{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "eth_getBalance",
|
||||
"params": ["0x0000000000000000000000000000000000000001", "latest"],
|
||||
"id": 1
|
||||
}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x","id":1}"#;
|
||||
|
||||
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_eth_storage_at() {
|
||||
let tester = EthTester::default();
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
//! Test implementation of miner service.
|
||||
|
||||
use util::{Address, H256, Bytes, U256, FixedHash};
|
||||
use util::{Address, H256, Bytes, U256, FixedHash, Uint};
|
||||
use util::standard::*;
|
||||
use ethcore::error::Error;
|
||||
use ethcore::client::BlockChainClient;
|
||||
use ethcore::block::ClosedBlock;
|
||||
use ethcore::client::{BlockChainClient, Executed};
|
||||
use ethcore::block::{ClosedBlock, IsBlock};
|
||||
use ethcore::transaction::SignedTransaction;
|
||||
use ethminer::{MinerService, MinerStatus, AccountDetails, TransactionImportResult};
|
||||
|
||||
@@ -174,4 +174,25 @@ impl MinerService for TestMinerService {
|
||||
fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn balance(&self, _chain: &BlockChainClient, address: &Address) -> U256 {
|
||||
self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.balance(address).clone())
|
||||
}
|
||||
|
||||
fn call(&self, _chain: &BlockChainClient, _t: &SignedTransaction) -> Result<Executed, Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn storage_at(&self, _chain: &BlockChainClient, address: &Address, position: &H256) -> H256 {
|
||||
self.latest_closed_block.lock().unwrap().as_ref().map_or_else(H256::default, |b| b.block().fields().state.storage_at(address, position).clone())
|
||||
}
|
||||
|
||||
fn nonce(&self, _chain: &BlockChainClient, address: &Address) -> U256 {
|
||||
self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.nonce(address).clone())
|
||||
}
|
||||
|
||||
fn code(&self, _chain: &BlockChainClient, address: &Address) -> Option<Bytes> {
|
||||
self.latest_closed_block.lock().unwrap().as_ref().map_or(None, |b| b.block().fields().state.code(address).clone())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user