Multi-call RPC (#6195)
* Removing duplicated pending state accessors in miner. * Merge miner+client call. * Multicall & multicall RPC. * Sensible defaults. * Fix tests.
This commit is contained in:
committed by
Marek Kotewicz
parent
62153b1ff0
commit
f157461ee1
@@ -264,6 +264,7 @@ fn check_known<C>(client: &C, number: BlockNumber) -> Result<(), Error> where C:
|
||||
|
||||
match client.block_status(number.into()) {
|
||||
BlockStatus::InChain => Ok(()),
|
||||
BlockStatus::Pending => Ok(()),
|
||||
_ => Err(errors::unknown_block()),
|
||||
}
|
||||
}
|
||||
@@ -361,20 +362,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256, Error> {
|
||||
let address = address.into();
|
||||
|
||||
let res = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.balance(&*self.client, &address) {
|
||||
Some(balance) => Ok(balance.into()),
|
||||
None => Err(errors::database("latest balance missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.balance(&address, id.into()) {
|
||||
Some(balance) => Ok(balance.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
let id = num.unwrap_or_default();
|
||||
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
let res = match self.client.balance(&address, id.into()) {
|
||||
Some(balance) => Ok(balance.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
};
|
||||
|
||||
future::done(res).boxed()
|
||||
@@ -384,20 +377,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
let address: Address = RpcH160::into(address);
|
||||
let position: U256 = RpcU256::into(pos);
|
||||
|
||||
let res = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.storage_at(&*self.client, &address, &H256::from(position)) {
|
||||
Some(s) => Ok(s.into()),
|
||||
None => Err(errors::database("latest storage missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.storage_at(&address, &H256::from(position), id.into()) {
|
||||
Some(s) => Ok(s.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
let id = num.unwrap_or_default();
|
||||
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
let res = match self.client.storage_at(&address, &H256::from(position), id.into()) {
|
||||
Some(s) => Ok(s.into()),
|
||||
None => Err(errors::state_pruned()),
|
||||
};
|
||||
|
||||
future::done(res).boxed()
|
||||
@@ -410,18 +395,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
BlockNumber::Pending if self.options.pending_nonce_from_queue => {
|
||||
let nonce = self.miner.last_nonce(&address)
|
||||
.map(|n| n + 1.into())
|
||||
.or_else(|| self.miner.nonce(&*self.client, &address));
|
||||
.or_else(|| self.client.nonce(&address, BlockNumber::Pending.into()));
|
||||
match nonce {
|
||||
Some(nonce) => Ok(nonce.into()),
|
||||
None => Err(errors::database("latest nonce missing"))
|
||||
}
|
||||
}
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.nonce(&*self.client, &address) {
|
||||
Some(nonce) => Ok(nonce.into()),
|
||||
None => Err(errors::database("latest nonce missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.nonce(&address, id.into()) {
|
||||
@@ -468,20 +447,12 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes, Error> {
|
||||
let address: Address = RpcH160::into(address);
|
||||
|
||||
let res = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => {
|
||||
match self.miner.code(&*self.client, &address) {
|
||||
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::database("latest code missing"))
|
||||
}
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.code(&address, id.into()) {
|
||||
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
let id = num.unwrap_or_default();
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
|
||||
let res = match self.client.code(&address, id.into()) {
|
||||
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::state_pruned()),
|
||||
};
|
||||
|
||||
future::done(res).boxed()
|
||||
@@ -648,10 +619,8 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
|
||||
Err(e) => return future::err(e).boxed(),
|
||||
};
|
||||
|
||||
let result = match num.unwrap_or_default() {
|
||||
BlockNumber::Pending => self.miner.call(&*self.client, &signed, Default::default()),
|
||||
num => self.client.call(&signed, num.into(), Default::default()),
|
||||
};
|
||||
let num = num.unwrap_or_default();
|
||||
let result = self.client.call(&signed, Default::default(), num.into());
|
||||
|
||||
future::done(result
|
||||
.map(|b| b.output.into())
|
||||
|
||||
@@ -39,7 +39,7 @@ use v1::helpers::light_fetch::LightFetch;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::Parity;
|
||||
use v1::types::{
|
||||
Bytes, U256, H160, H256, H512,
|
||||
Bytes, U256, H160, H256, H512, CallRequest,
|
||||
Peers, Transaction, RpcSettings, Histogram,
|
||||
TransactionStats, LocalTransactionStatus,
|
||||
BlockNumber, ConsensusCapability, VersionInfo,
|
||||
@@ -389,4 +389,8 @@ impl Parity for ParityClient {
|
||||
fn ipfs_cid(&self, content: Bytes) -> Result<String, Error> {
|
||||
ipfs::cid(content)
|
||||
}
|
||||
|
||||
fn call(&self, _requests: Vec<CallRequest>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> {
|
||||
future::err(errors::light_unimplemented(None)).boxed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::traits::Traces;
|
||||
use v1::helpers::errors;
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256};
|
||||
|
||||
/// Traces api implementation.
|
||||
// TODO: all calling APIs should be possible w. proved remote TX execution.
|
||||
@@ -43,15 +43,19 @@ impl Traces for TracesClient {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
|
||||
fn call(&self, _request: CallRequest, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
fn call(&self, _request: CallRequest, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, _raw_transaction: Bytes, _flags: Vec<String>, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
fn call_many(&self, _request: Vec<(CallRequest, TraceOptions)>, _block: Trailing<BlockNumber>) -> Result<Vec<TraceResults>, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
|
||||
fn replay_transaction(&self, _transaction_hash: H256, _flags: Vec<String>) -> Result<TraceResults, Error> {
|
||||
fn raw_transaction(&self, _raw_transaction: Bytes, _flags: TraceOptions, _block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
|
||||
fn replay_transaction(&self, _transaction_hash: H256, _flags: TraceOptions) -> Result<TraceResults, Error> {
|
||||
Err(errors::light_unimplemented(None))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,22 +28,23 @@ use crypto::ecies;
|
||||
use ethkey::{Brain, Generator};
|
||||
use ethstore::random_phrase;
|
||||
use ethsync::{SyncProvider, ManageNetwork};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::client::{MiningBlockChainClient};
|
||||
use ethcore::ids::BlockId;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::client::{MiningBlockChainClient};
|
||||
use ethcore::mode::Mode;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::transaction::SignedTransaction;
|
||||
use updater::{Service as UpdateService};
|
||||
use crypto::DEFAULT_MAC;
|
||||
|
||||
use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::helpers::{self, errors, ipfs, SigningQueue, SignerService, NetworkSettings};
|
||||
use v1::helpers::{self, errors, fake_sign, ipfs, SigningQueue, SignerService, NetworkSettings};
|
||||
use v1::helpers::accounts::unwrap_provider;
|
||||
use v1::metadata::Metadata;
|
||||
use v1::traits::Parity;
|
||||
use v1::types::{
|
||||
Bytes, U256, H160, H256, H512,
|
||||
Bytes, U256, H160, H256, H512, CallRequest,
|
||||
Peers, Transaction, RpcSettings, Histogram,
|
||||
TransactionStats, LocalTransactionStatus,
|
||||
BlockNumber, ConsensusCapability, VersionInfo,
|
||||
@@ -409,4 +410,23 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
|
||||
fn ipfs_cid(&self, content: Bytes) -> Result<String, Error> {
|
||||
ipfs::cid(content)
|
||||
}
|
||||
|
||||
fn call(&self, requests: Vec<CallRequest>, block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> {
|
||||
let requests: Result<Vec<(SignedTransaction, _)>, Error> = requests
|
||||
.into_iter()
|
||||
.map(|request| Ok((
|
||||
fake_sign::sign_call(&self.client, &self.miner, request.into())?,
|
||||
Default::default()
|
||||
)))
|
||||
.collect();
|
||||
|
||||
let block = block.unwrap_or_default();
|
||||
let requests = try_bf!(requests);
|
||||
|
||||
let result = self.client.call_many(&requests, block.into())
|
||||
.map(|res| res.into_iter().map(|res| res.output.into()).collect())
|
||||
.map_err(errors::call);
|
||||
|
||||
future::done(result).boxed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ use jsonrpc_core::Error;
|
||||
use jsonrpc_macros::Trailing;
|
||||
use v1::traits::Traces;
|
||||
use v1::helpers::{errors, fake_sign};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256};
|
||||
|
||||
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
|
||||
fn to_call_analytics(flags: TraceOptions) -> CallAnalytics {
|
||||
CallAnalytics {
|
||||
transaction_tracing: flags.contains(&("trace".to_owned())),
|
||||
vm_tracing: flags.contains(&("vmTrace".to_owned())),
|
||||
@@ -79,29 +79,45 @@ impl<C, M> Traces for TracesClient<C, M> where C: MiningBlockChainClient + 'stat
|
||||
.map(LocalizedTrace::from))
|
||||
}
|
||||
|
||||
fn call(&self, request: CallRequest, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
fn call(&self, request: CallRequest, flags: TraceOptions, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let request = CallRequest::into(request);
|
||||
let signed = fake_sign::sign_call(&self.client, &self.miner, request)?;
|
||||
|
||||
self.client.call(&signed, block.into(), to_call_analytics(flags))
|
||||
self.client.call(&signed, to_call_analytics(flags), block.into())
|
||||
.map(TraceResults::from)
|
||||
.map_err(errors::call)
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
fn call_many(&self, requests: Vec<(CallRequest, TraceOptions)>, block: Trailing<BlockNumber>) -> Result<Vec<TraceResults>, Error> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let requests = requests.into_iter()
|
||||
.map(|(request, flags)| {
|
||||
let request = CallRequest::into(request);
|
||||
let signed = fake_sign::sign_call(&self.client, &self.miner, request)?;
|
||||
Ok((signed, to_call_analytics(flags)))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
self.client.call_many(&requests, block.into())
|
||||
.map(|results| results.into_iter().map(TraceResults::from).collect())
|
||||
.map_err(errors::call)
|
||||
}
|
||||
|
||||
fn raw_transaction(&self, raw_transaction: Bytes, flags: TraceOptions, block: Trailing<BlockNumber>) -> Result<TraceResults, Error> {
|
||||
let block = block.unwrap_or_default();
|
||||
|
||||
let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
|
||||
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
||||
|
||||
self.client.call(&signed, block.into(), to_call_analytics(flags))
|
||||
self.client.call(&signed, to_call_analytics(flags), block.into())
|
||||
.map(TraceResults::from)
|
||||
.map_err(errors::call)
|
||||
}
|
||||
|
||||
fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<TraceResults, Error> {
|
||||
fn replay_transaction(&self, transaction_hash: H256, flags: TraceOptions) -> Result<TraceResults, Error> {
|
||||
self.client.replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags))
|
||||
.map(TraceResults::from)
|
||||
.map_err(errors::call)
|
||||
|
||||
Reference in New Issue
Block a user