2019-01-07 11:33:07 +01:00
|
|
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
|
|
// This file is part of Parity Ethereum.
|
2017-02-03 16:20:43 +01:00
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
2017-02-03 16:20:43 +01:00
|
|
|
// 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.
|
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
2017-02-03 16:20:43 +01:00
|
|
|
// 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
|
2019-01-07 11:33:07 +01:00
|
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2017-02-03 16:20:43 +01:00
|
|
|
|
|
|
|
//! Eth RPC interface for the light client.
|
|
|
|
|
2018-07-04 17:37:55 +02:00
|
|
|
use std::collections::BTreeSet;
|
2017-02-03 16:20:43 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
use jsonrpc_core::{Result, BoxFuture};
|
2017-10-05 12:35:01 +02:00
|
|
|
use jsonrpc_core::futures::{future, Future};
|
|
|
|
use jsonrpc_core::futures::future::Either;
|
2017-02-03 16:20:43 +01:00
|
|
|
|
2017-02-26 15:05:33 +01:00
|
|
|
use light::cache::Cache as LightDataCache;
|
2017-09-05 17:54:05 +02:00
|
|
|
use light::client::LightChainClient;
|
2017-02-09 19:17:37 +01:00
|
|
|
use light::{cht, TransactionQueue};
|
2017-02-07 23:25:17 +01:00
|
|
|
use light::on_demand::{request, OnDemand};
|
2017-02-03 16:20:43 +01:00
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
use ethereum_types::{Address, H64, H160, H256, U64, U256};
|
2019-01-04 14:05:46 +01:00
|
|
|
use hash::{KECCAK_NULL_RLP, KECCAK_EMPTY_LIST_RLP};
|
2017-09-02 20:09:13 +02:00
|
|
|
use parking_lot::{RwLock, Mutex};
|
2018-04-16 15:52:12 +02:00
|
|
|
use rlp::Rlp;
|
2019-01-04 14:05:46 +01:00
|
|
|
use types::transaction::SignedTransaction;
|
|
|
|
use types::encoded;
|
|
|
|
use types::filter::Filter as EthcoreFilter;
|
|
|
|
use types::ids::BlockId;
|
2017-02-03 16:20:43 +01:00
|
|
|
|
2017-03-28 15:42:23 +02:00
|
|
|
use v1::impls::eth_filter::Filterable;
|
2017-10-05 12:35:01 +02:00
|
|
|
use v1::helpers::{errors, limit_logs};
|
2018-07-04 17:37:55 +02:00
|
|
|
use v1::helpers::{SyncPollFilter, PollManager};
|
2019-02-07 14:34:24 +01:00
|
|
|
use v1::helpers::deprecated::{self, DeprecationNotice};
|
2017-10-08 18:19:27 +02:00
|
|
|
use v1::helpers::light_fetch::{self, LightFetch};
|
2017-02-03 16:20:43 +01:00
|
|
|
use v1::traits::Eth;
|
|
|
|
use v1::types::{
|
2019-02-25 14:27:28 +01:00
|
|
|
RichBlock, Block, BlockTransactions, BlockNumber, LightBlockNumber, Bytes, SyncStatus as RpcSyncStatus,
|
|
|
|
SyncInfo as RpcSyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, Work, EthAccount
|
2017-02-03 16:20:43 +01:00
|
|
|
};
|
|
|
|
use v1::metadata::Metadata;
|
|
|
|
|
2019-02-11 11:33:16 +01:00
|
|
|
use sync::{LightSyncInfo, LightSyncProvider, LightNetworkDispatcher, ManageNetwork};
|
|
|
|
|
2018-09-06 15:44:40 +02:00
|
|
|
const NO_INVALID_BACK_REFS: &str = "Fails only on invalid back-references; back-references here known to be valid; qed";
|
2017-05-23 12:39:25 +02:00
|
|
|
|
2017-03-28 15:42:23 +02:00
|
|
|
/// Light client `ETH` (and filter) RPC.
|
2019-02-11 11:33:16 +01:00
|
|
|
pub struct EthClient<C, S: LightSyncProvider + LightNetworkDispatcher + 'static> {
|
|
|
|
sync: Arc<S>,
|
|
|
|
client: Arc<C>,
|
2017-02-03 16:20:43 +01:00
|
|
|
on_demand: Arc<OnDemand>,
|
2017-02-09 19:17:37 +01:00
|
|
|
transaction_queue: Arc<RwLock<TransactionQueue>>,
|
2019-02-07 14:34:24 +01:00
|
|
|
accounts: Arc<Fn() -> Vec<Address> + Send + Sync>,
|
2017-02-26 15:05:33 +01:00
|
|
|
cache: Arc<Mutex<LightDataCache>>,
|
2018-07-04 17:37:55 +02:00
|
|
|
polls: Mutex<PollManager<SyncPollFilter>>,
|
2018-06-18 13:42:54 +02:00
|
|
|
poll_lifetime: u32,
|
2018-01-09 12:43:36 +01:00
|
|
|
gas_price_percentile: usize,
|
2019-02-07 14:34:24 +01:00
|
|
|
deprecation_notice: DeprecationNotice,
|
2017-03-28 15:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-02-11 11:33:16 +01:00
|
|
|
impl<C, S> Clone for EthClient<C, S>
|
|
|
|
where
|
|
|
|
S: LightSyncProvider + LightNetworkDispatcher + 'static
|
|
|
|
{
|
2017-03-28 15:42:23 +02:00
|
|
|
fn clone(&self) -> Self {
|
|
|
|
// each instance should have its own poll manager.
|
|
|
|
EthClient {
|
|
|
|
sync: self.sync.clone(),
|
|
|
|
client: self.client.clone(),
|
|
|
|
on_demand: self.on_demand.clone(),
|
|
|
|
transaction_queue: self.transaction_queue.clone(),
|
|
|
|
accounts: self.accounts.clone(),
|
|
|
|
cache: self.cache.clone(),
|
2018-06-18 13:42:54 +02:00
|
|
|
polls: Mutex::new(PollManager::new(self.poll_lifetime)),
|
|
|
|
poll_lifetime: self.poll_lifetime,
|
2018-01-09 12:43:36 +01:00
|
|
|
gas_price_percentile: self.gas_price_percentile,
|
2019-02-07 14:34:24 +01:00
|
|
|
deprecation_notice: Default::default(),
|
2017-03-28 15:42:23 +02:00
|
|
|
}
|
|
|
|
}
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-11 11:33:16 +01:00
|
|
|
impl<C, S> EthClient<C, S>
|
|
|
|
where
|
|
|
|
C: LightChainClient + 'static,
|
|
|
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
|
|
|
{
|
2017-02-03 16:20:43 +01:00
|
|
|
/// Create a new `EthClient` with a handle to the light sync instance, client,
|
|
|
|
/// and on-demand request service, which is assumed to be attached as a handler.
|
|
|
|
pub fn new(
|
2019-02-11 11:33:16 +01:00
|
|
|
sync: Arc<S>,
|
|
|
|
client: Arc<C>,
|
2017-02-03 16:20:43 +01:00
|
|
|
on_demand: Arc<OnDemand>,
|
2017-02-09 19:17:37 +01:00
|
|
|
transaction_queue: Arc<RwLock<TransactionQueue>>,
|
2019-02-07 14:34:24 +01:00
|
|
|
accounts: Arc<Fn() -> Vec<Address> + Send + Sync>,
|
2017-02-26 15:05:33 +01:00
|
|
|
cache: Arc<Mutex<LightDataCache>>,
|
2018-01-09 12:43:36 +01:00
|
|
|
gas_price_percentile: usize,
|
2018-06-18 13:42:54 +02:00
|
|
|
poll_lifetime: u32
|
2017-02-03 16:20:43 +01:00
|
|
|
) -> Self {
|
|
|
|
EthClient {
|
2018-01-09 12:43:36 +01:00
|
|
|
sync,
|
|
|
|
client,
|
|
|
|
on_demand,
|
|
|
|
transaction_queue,
|
|
|
|
accounts,
|
|
|
|
cache,
|
2018-06-18 13:42:54 +02:00
|
|
|
polls: Mutex::new(PollManager::new(poll_lifetime)),
|
|
|
|
poll_lifetime,
|
2018-01-09 12:43:36 +01:00
|
|
|
gas_price_percentile,
|
2019-02-07 14:34:24 +01:00
|
|
|
deprecation_notice: Default::default(),
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-03 11:37:07 +02:00
|
|
|
/// Create a light data fetcher instance.
|
2019-02-11 11:33:16 +01:00
|
|
|
fn fetcher(&self) -> LightFetch<S>
|
|
|
|
{
|
2017-04-03 11:37:07 +02:00
|
|
|
LightFetch {
|
|
|
|
client: self.client.clone(),
|
|
|
|
on_demand: self.on_demand.clone(),
|
|
|
|
sync: self.sync.clone(),
|
|
|
|
cache: self.cache.clone(),
|
2018-01-09 12:43:36 +01:00
|
|
|
gas_price_percentile: self.gas_price_percentile,
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
}
|
2017-02-03 17:53:48 +01:00
|
|
|
|
2017-04-06 17:44:31 +02:00
|
|
|
// get a "rich" block structure. Fails on unknown block.
|
2017-11-14 11:38:17 +01:00
|
|
|
fn rich_block(&self, id: BlockId, include_txs: bool) -> BoxFuture<RichBlock> {
|
2017-03-28 17:15:36 +02:00
|
|
|
let (on_demand, sync) = (self.on_demand.clone(), self.sync.clone());
|
|
|
|
let (client, engine) = (self.client.clone(), self.client.engine().clone());
|
|
|
|
|
|
|
|
// helper for filling out a rich block once we've got a block and a score.
|
|
|
|
let fill_rich = move |block: encoded::Block, score: Option<U256>| {
|
|
|
|
let header = block.decode_header();
|
|
|
|
let extra_info = engine.extra_info(&header);
|
|
|
|
RichBlock {
|
2017-04-06 17:59:55 +02:00
|
|
|
inner: Block {
|
2019-03-22 12:01:11 +01:00
|
|
|
hash: Some(header.hash()),
|
2017-03-28 17:15:36 +02:00
|
|
|
size: Some(block.rlp().as_raw().len().into()),
|
2019-03-22 12:01:11 +01:00
|
|
|
parent_hash: *header.parent_hash(),
|
|
|
|
uncles_hash: *header.uncles_hash(),
|
|
|
|
author: *header.author(),
|
|
|
|
miner: *header.author(),
|
|
|
|
state_root: *header.state_root(),
|
|
|
|
transactions_root: *header.transactions_root(),
|
|
|
|
receipts_root: *header.receipts_root(),
|
2017-03-28 17:15:36 +02:00
|
|
|
number: Some(header.number().into()),
|
2019-03-22 12:01:11 +01:00
|
|
|
gas_used: *header.gas_used(),
|
|
|
|
gas_limit: *header.gas_limit(),
|
|
|
|
logs_bloom: Some(*header.log_bloom()),
|
2017-03-28 17:15:36 +02:00
|
|
|
timestamp: header.timestamp().into(),
|
2019-03-22 12:01:11 +01:00
|
|
|
difficulty: *header.difficulty(),
|
2017-03-28 17:15:36 +02:00
|
|
|
total_difficulty: score.map(Into::into),
|
2019-03-22 12:01:11 +01:00
|
|
|
seal_fields: header.seal().iter().cloned().map(Into::into).collect(),
|
2017-03-28 17:15:36 +02:00
|
|
|
uncles: block.uncle_hashes().into_iter().map(Into::into).collect(),
|
|
|
|
transactions: match include_txs {
|
2018-09-06 15:44:40 +02:00
|
|
|
true => BlockTransactions::Full(block.view().localized_transactions().into_iter().map(Transaction::from_localized).collect()),
|
2017-04-19 14:30:00 +02:00
|
|
|
_ => BlockTransactions::Hashes(block.transaction_hashes().into_iter().map(Into::into).collect()),
|
2017-03-28 17:15:36 +02:00
|
|
|
},
|
2017-06-28 14:16:53 +02:00
|
|
|
extra_data: Bytes::new(header.extra_data().clone()),
|
2017-03-28 17:15:36 +02:00
|
|
|
},
|
2019-03-22 12:01:11 +01:00
|
|
|
extra_info,
|
2017-03-28 17:15:36 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// get the block itself.
|
2017-10-05 12:35:01 +02:00
|
|
|
Box::new(self.fetcher().block(id).and_then(move |block| {
|
2017-04-06 17:44:31 +02:00
|
|
|
// then fetch the total difficulty (this is much easier after getting the block).
|
|
|
|
match client.score(id) {
|
2017-10-05 12:35:01 +02:00
|
|
|
Some(score) => Either::A(future::ok(fill_rich(block, Some(score)))),
|
2017-04-06 17:44:31 +02:00
|
|
|
None => {
|
|
|
|
// make a CHT request to fetch the chain score.
|
|
|
|
let req = cht::block_to_cht_number(block.number())
|
|
|
|
.and_then(|num| client.cht_root(num as usize))
|
|
|
|
.and_then(|root| request::HeaderProof::new(block.number(), root));
|
|
|
|
|
|
|
|
let req = match req {
|
|
|
|
Some(req) => req,
|
|
|
|
None => {
|
|
|
|
// somehow the genesis block slipped past other checks.
|
|
|
|
// return it now.
|
|
|
|
let score = client.block_header(BlockId::Number(0))
|
|
|
|
.expect("genesis always stored; qed")
|
|
|
|
.difficulty();
|
|
|
|
|
2017-10-05 12:35:01 +02:00
|
|
|
return Either::A(future::ok(fill_rich(block, Some(score))))
|
2017-03-28 17:15:36 +02:00
|
|
|
}
|
2017-04-06 17:44:31 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// three possible outcomes:
|
|
|
|
// - network is down.
|
|
|
|
// - we get a score, but our hash is non-canonical.
|
2017-05-12 17:16:38 +02:00
|
|
|
// - we get a score, and our hash is canonical.
|
2017-05-23 12:39:25 +02:00
|
|
|
let maybe_fut = sync.with_context(move |ctx| on_demand.request(ctx, req).expect(NO_INVALID_BACK_REFS));
|
2017-04-06 17:44:31 +02:00
|
|
|
match maybe_fut {
|
2017-10-05 12:35:01 +02:00
|
|
|
Some(fut) => Either::B(fut
|
2017-05-23 12:39:25 +02:00
|
|
|
.map(move |(hash, score)| {
|
2017-04-06 17:44:31 +02:00
|
|
|
let score = if hash == block.hash() {
|
|
|
|
Some(score)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2017-10-05 12:35:01 +02:00
|
|
|
fill_rich(block, score)
|
2018-09-12 11:47:01 +02:00
|
|
|
}).map_err(errors::on_demand_error)),
|
2017-10-05 12:35:01 +02:00
|
|
|
None => Either::A(future::err(errors::network_disabled())),
|
2017-03-28 17:15:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-05 12:35:01 +02:00
|
|
|
}))
|
2017-03-28 17:15:36 +02:00
|
|
|
}
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-11 11:33:16 +01:00
|
|
|
impl<C, S> Eth for EthClient<C, S>
|
|
|
|
where
|
|
|
|
C: LightChainClient + 'static,
|
|
|
|
S: LightSyncInfo + LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
|
|
|
{
|
2017-02-03 16:20:43 +01:00
|
|
|
type Metadata = Metadata;
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn protocol_version(&self) -> Result<String> {
|
2017-02-03 16:20:43 +01:00
|
|
|
Ok(format!("{}", ::light::net::MAX_PROTOCOL_VERSION))
|
|
|
|
}
|
|
|
|
|
2019-02-11 11:33:16 +01:00
|
|
|
fn syncing(&self) -> Result<RpcSyncStatus> {
|
2017-03-23 03:23:53 +01:00
|
|
|
if self.sync.is_major_importing() {
|
|
|
|
let chain_info = self.client.chain_info();
|
|
|
|
let current_block = U256::from(chain_info.best_block_number);
|
|
|
|
let highest_block = self.sync.highest_block().map(U256::from)
|
2018-09-06 15:44:40 +02:00
|
|
|
.unwrap_or_else(|| current_block);
|
2017-03-23 03:23:53 +01:00
|
|
|
|
2019-02-11 11:33:16 +01:00
|
|
|
Ok(RpcSyncStatus::Info(RpcSyncInfo {
|
2019-03-22 12:01:11 +01:00
|
|
|
starting_block: U256::from(self.sync.start_block()),
|
|
|
|
current_block,
|
|
|
|
highest_block,
|
2017-03-23 03:23:53 +01:00
|
|
|
warp_chunks_amount: None,
|
|
|
|
warp_chunks_processed: None,
|
|
|
|
}))
|
|
|
|
} else {
|
2019-02-11 11:33:16 +01:00
|
|
|
Ok(RpcSyncStatus::None)
|
2017-03-23 03:23:53 +01:00
|
|
|
}
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn author(&self) -> Result<H160> {
|
2019-02-07 14:34:24 +01:00
|
|
|
(self.accounts)()
|
|
|
|
.first()
|
|
|
|
.cloned()
|
2018-09-05 19:21:08 +02:00
|
|
|
.map(From::from)
|
|
|
|
.ok_or_else(|| errors::account("No accounts were found", ""))
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn is_mining(&self) -> Result<bool> {
|
2017-02-03 16:20:43 +01:00
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn chain_id(&self) -> Result<Option<U64>> {
|
|
|
|
Ok(self.client.signing_chain_id().map(U64::from))
|
2018-10-20 21:13:23 +02:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn hashrate(&self) -> Result<U256> {
|
2017-02-03 16:20:43 +01:00
|
|
|
Ok(Default::default())
|
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn gas_price(&self) -> Result<U256> {
|
2017-03-28 17:15:36 +02:00
|
|
|
Ok(self.cache.lock().gas_price_corpus()
|
2018-01-09 12:43:36 +01:00
|
|
|
.and_then(|c| c.percentile(self.gas_price_percentile).cloned())
|
2019-02-25 14:27:28 +01:00
|
|
|
.map(U256::from)
|
2017-03-28 17:15:36 +02:00
|
|
|
.unwrap_or_else(Default::default))
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn accounts(&self) -> Result<Vec<H160>> {
|
2019-02-07 14:34:24 +01:00
|
|
|
self.deprecation_notice.print("eth_accounts", deprecated::msgs::ACCOUNTS);
|
|
|
|
|
|
|
|
Ok((self.accounts)()
|
|
|
|
.into_iter()
|
|
|
|
.map(Into::into)
|
|
|
|
.collect())
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn block_number(&self) -> Result<U256> {
|
2017-02-03 16:20:43 +01:00
|
|
|
Ok(self.client.chain_info().best_block_number.into())
|
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn balance(&self, address: H160, num: Option<BlockNumber>) -> BoxFuture<U256> {
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.fetcher().account(address, num.unwrap_or_default().to_block_id())
|
|
|
|
.map(|acc| acc.map_or(0.into(), |a| a.balance)))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn storage_at(&self, _address: H160, _key: U256, _num: Option<BlockNumber>) -> BoxFuture<H256> {
|
2017-10-05 12:35:01 +02:00
|
|
|
Box::new(future::err(errors::unimplemented(None)))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn block_by_hash(&self, hash: H256, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.rich_block(BlockId::Hash(hash), include_txs).map(Some))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
|
2018-09-25 19:06:14 +02:00
|
|
|
Box::new(self.rich_block(num.to_block_id(), include_txs).map(Some))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn transaction_count(&self, address: H160, num: Option<BlockNumber>) -> BoxFuture<U256> {
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.fetcher().account(address, num.unwrap_or_default().to_block_id())
|
|
|
|
.map(|acc| acc.map_or(0.into(), |a| a.nonce)))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn block_transaction_count_by_hash(&self, hash: H256) -> BoxFuture<Option<U256>> {
|
2017-02-07 14:45:48 +01:00
|
|
|
let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone());
|
|
|
|
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.fetcher().header(BlockId::Hash(hash)).and_then(move |hdr| {
|
2017-08-31 11:35:41 +02:00
|
|
|
if hdr.transactions_root() == KECCAK_NULL_RLP {
|
2019-03-22 12:01:11 +01:00
|
|
|
Either::A(future::ok(Some(U256::from(0))))
|
2017-02-07 14:45:48 +01:00
|
|
|
} else {
|
2017-05-23 12:39:25 +02:00
|
|
|
sync.with_context(|ctx| on_demand.request(ctx, request::Body(hdr.into())))
|
|
|
|
.map(|x| x.expect(NO_INVALID_BACK_REFS))
|
2019-03-22 12:01:11 +01:00
|
|
|
.map(|x| x.map(|b| Some(U256::from(b.transactions_count()))))
|
2018-09-12 11:47:01 +02:00
|
|
|
.map(|x| Either::B(x.map_err(errors::on_demand_error)))
|
2017-10-05 12:35:01 +02:00
|
|
|
.unwrap_or_else(|| Either::A(future::err(errors::network_disabled())))
|
2017-02-07 14:45:48 +01:00
|
|
|
}
|
2017-10-05 12:35:01 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<U256>> {
|
2017-02-07 14:45:48 +01:00
|
|
|
let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone());
|
|
|
|
|
2018-09-25 19:06:14 +02:00
|
|
|
Box::new(self.fetcher().header(num.to_block_id()).and_then(move |hdr| {
|
2017-08-31 11:35:41 +02:00
|
|
|
if hdr.transactions_root() == KECCAK_NULL_RLP {
|
2019-03-22 12:01:11 +01:00
|
|
|
Either::A(future::ok(Some(U256::from(0))))
|
2017-02-07 14:45:48 +01:00
|
|
|
} else {
|
2017-05-23 12:39:25 +02:00
|
|
|
sync.with_context(|ctx| on_demand.request(ctx, request::Body(hdr.into())))
|
|
|
|
.map(|x| x.expect(NO_INVALID_BACK_REFS))
|
2019-03-22 12:01:11 +01:00
|
|
|
.map(|x| x.map(|b| Some(U256::from(b.transactions_count()))))
|
2018-09-12 11:47:01 +02:00
|
|
|
.map(|x| Either::B(x.map_err(errors::on_demand_error)))
|
2017-10-05 12:35:01 +02:00
|
|
|
.unwrap_or_else(|| Either::A(future::err(errors::network_disabled())))
|
2017-02-07 14:45:48 +01:00
|
|
|
}
|
2017-10-05 12:35:01 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn block_uncles_count_by_hash(&self, hash: H256) -> BoxFuture<Option<U256>> {
|
2017-02-07 14:45:48 +01:00
|
|
|
let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone());
|
|
|
|
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.fetcher().header(BlockId::Hash(hash)).and_then(move |hdr| {
|
2017-08-31 11:35:41 +02:00
|
|
|
if hdr.uncles_hash() == KECCAK_EMPTY_LIST_RLP {
|
2019-03-22 12:01:11 +01:00
|
|
|
Either::A(future::ok(Some(U256::from(0))))
|
2017-02-07 14:45:48 +01:00
|
|
|
} else {
|
2017-05-23 12:39:25 +02:00
|
|
|
sync.with_context(|ctx| on_demand.request(ctx, request::Body(hdr.into())))
|
|
|
|
.map(|x| x.expect(NO_INVALID_BACK_REFS))
|
2019-03-22 12:01:11 +01:00
|
|
|
.map(|x| x.map(|b| Some(U256::from(b.uncles_count()))))
|
2018-09-12 11:47:01 +02:00
|
|
|
.map(|x| Either::B(x.map_err(errors::on_demand_error)))
|
2017-10-05 12:35:01 +02:00
|
|
|
.unwrap_or_else(|| Either::A(future::err(errors::network_disabled())))
|
2017-02-07 14:45:48 +01:00
|
|
|
}
|
2017-10-05 12:35:01 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<U256>> {
|
2017-02-07 14:45:48 +01:00
|
|
|
let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone());
|
|
|
|
|
2018-09-25 19:06:14 +02:00
|
|
|
Box::new(self.fetcher().header(num.to_block_id()).and_then(move |hdr| {
|
2017-08-31 11:35:41 +02:00
|
|
|
if hdr.uncles_hash() == KECCAK_EMPTY_LIST_RLP {
|
2019-03-22 12:01:11 +01:00
|
|
|
Either::B(future::ok(Some(U256::from(0))))
|
2017-02-07 14:45:48 +01:00
|
|
|
} else {
|
2017-05-23 12:39:25 +02:00
|
|
|
sync.with_context(|ctx| on_demand.request(ctx, request::Body(hdr.into())))
|
|
|
|
.map(|x| x.expect(NO_INVALID_BACK_REFS))
|
2019-03-22 12:01:11 +01:00
|
|
|
.map(|x| x.map(|b| Some(U256::from(b.uncles_count()))))
|
2018-09-12 11:47:01 +02:00
|
|
|
.map(|x| Either::A(x.map_err(errors::on_demand_error)))
|
2017-10-05 12:35:01 +02:00
|
|
|
.unwrap_or_else(|| Either::B(future::err(errors::network_disabled())))
|
2017-02-07 14:45:48 +01:00
|
|
|
}
|
2017-10-05 12:35:01 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn code_at(&self, address: H160, num: Option<BlockNumber>) -> BoxFuture<Bytes> {
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.fetcher().code(address, num.unwrap_or_default().to_block_id()).map(Into::into))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn send_raw_transaction(&self, raw: Bytes) -> Result<H256> {
|
2018-05-09 12:05:56 +02:00
|
|
|
let best_header = self.client.best_block_header().decode().map_err(errors::decode)?;
|
2017-02-09 19:58:29 +01:00
|
|
|
|
2018-04-16 15:52:12 +02:00
|
|
|
Rlp::new(&raw.into_vec()).as_val()
|
2017-07-04 17:01:06 +02:00
|
|
|
.map_err(errors::rlp)
|
2017-02-09 19:58:29 +01:00
|
|
|
.and_then(|tx| {
|
|
|
|
self.client.engine().verify_transaction_basic(&tx, &best_header)
|
2017-07-04 17:01:06 +02:00
|
|
|
.map_err(errors::transaction)?;
|
2017-02-09 19:58:29 +01:00
|
|
|
|
2017-07-04 17:01:06 +02:00
|
|
|
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
2017-02-09 19:17:37 +01:00
|
|
|
let hash = signed.hash();
|
2017-02-09 19:58:29 +01:00
|
|
|
|
2017-02-09 19:17:37 +01:00
|
|
|
self.transaction_queue.write().import(signed.into())
|
|
|
|
.map(|_| hash)
|
2017-07-04 17:01:06 +02:00
|
|
|
.map_err(errors::transaction)
|
2017-02-09 19:17:37 +01:00
|
|
|
})
|
|
|
|
.map(Into::into)
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn submit_transaction(&self, raw: Bytes) -> Result<H256> {
|
2017-02-09 19:17:37 +01:00
|
|
|
self.send_raw_transaction(raw)
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-05 14:31:19 +01:00
|
|
|
fn call(&self, req: CallRequest, num: Option<BlockNumber>) -> BoxFuture<Bytes> {
|
2018-10-08 21:30:46 +02:00
|
|
|
Box::new(self.fetcher().proved_read_only_execution(req, num).and_then(|res| {
|
2017-02-26 13:48:56 +01:00
|
|
|
match res {
|
2017-02-26 15:05:33 +01:00
|
|
|
Ok(exec) => Ok(exec.output.into()),
|
2017-02-26 13:48:56 +01:00
|
|
|
Err(e) => Err(errors::execution(e)),
|
|
|
|
}
|
2017-10-05 12:35:01 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn estimate_gas(&self, req: CallRequest, num: Option<BlockNumber>) -> BoxFuture<U256> {
|
2017-02-26 13:48:56 +01:00
|
|
|
// TODO: binary chop for more accurate estimates.
|
2018-10-08 21:30:46 +02:00
|
|
|
Box::new(self.fetcher().proved_read_only_execution(req, num).and_then(|res| {
|
2017-02-26 13:48:56 +01:00
|
|
|
match res {
|
2019-03-22 12:01:11 +01:00
|
|
|
Ok(exec) => Ok(exec.refunded + exec.gas_used),
|
2017-02-26 13:48:56 +01:00
|
|
|
Err(e) => Err(errors::execution(e)),
|
|
|
|
}
|
2017-10-05 12:35:01 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn transaction_by_hash(&self, hash: H256) -> BoxFuture<Option<Transaction>> {
|
2017-10-24 07:09:48 +02:00
|
|
|
{
|
|
|
|
let tx_queue = self.transaction_queue.read();
|
|
|
|
if let Some(tx) = tx_queue.get(&hash) {
|
|
|
|
return Box::new(future::ok(Some(Transaction::from_pending(
|
|
|
|
tx.clone(),
|
|
|
|
))));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-01 13:17:04 +02:00
|
|
|
Box::new(self.fetcher().transaction_by_hash(hash).map(|x| x.map(|(tx, _)| tx)))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn transaction_by_block_hash_and_index(&self, hash: H256, idx: Index) -> BoxFuture<Option<Transaction>> {
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.fetcher().block(BlockId::Hash(hash)).map(move |block| {
|
2018-08-01 13:17:04 +02:00
|
|
|
light_fetch::extract_transaction_at_index(block, idx.value())
|
2017-10-08 18:19:27 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<Transaction>> {
|
2018-09-25 19:06:14 +02:00
|
|
|
Box::new(self.fetcher().block(num.to_block_id()).map(move |block| {
|
2018-08-01 13:17:04 +02:00
|
|
|
light_fetch::extract_transaction_at_index(block, idx.value())
|
2017-10-08 18:19:27 +02:00
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn transaction_receipt(&self, hash: H256) -> BoxFuture<Option<Receipt>> {
|
2017-10-08 18:19:27 +02:00
|
|
|
let fetcher = self.fetcher();
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(fetcher.transaction_by_hash(hash).and_then(move |tx| {
|
2017-10-08 18:19:27 +02:00
|
|
|
// the block hash included in the transaction object here has
|
|
|
|
// already been checked for canonicality and whether it contains
|
|
|
|
// the transaction.
|
|
|
|
match tx {
|
2019-03-22 12:01:11 +01:00
|
|
|
Some((tx, index)) => match tx.block_hash {
|
2017-10-08 18:19:27 +02:00
|
|
|
Some(block_hash) => {
|
2019-03-22 12:01:11 +01:00
|
|
|
let extract_receipt = fetcher.receipts(BlockId::Hash(block_hash))
|
2017-10-08 18:19:27 +02:00
|
|
|
.and_then(move |mut receipts| future::ok(receipts.swap_remove(index)))
|
|
|
|
.map(Receipt::from)
|
|
|
|
.map(move |mut receipt| {
|
|
|
|
receipt.transaction_hash = Some(hash);
|
|
|
|
receipt.transaction_index = Some(index.into());
|
|
|
|
receipt.block_hash = Some(block_hash);
|
|
|
|
receipt.block_number = tx.block_number;
|
|
|
|
receipt
|
|
|
|
})
|
|
|
|
.map(Some);
|
|
|
|
|
|
|
|
Either::B(extract_receipt)
|
|
|
|
}
|
|
|
|
None => Either::A(future::err(errors::unknown_block())),
|
|
|
|
},
|
|
|
|
None => Either::A(future::ok(None)),
|
|
|
|
}
|
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn uncle_by_block_hash_and_index(&self, hash: H256, idx: Index) -> BoxFuture<Option<RichBlock>> {
|
2017-10-08 18:19:27 +02:00
|
|
|
let client = self.client.clone();
|
2019-03-22 12:01:11 +01:00
|
|
|
Box::new(self.fetcher().block(BlockId::Hash(hash)).map(move |block| {
|
2017-10-08 18:19:27 +02:00
|
|
|
extract_uncle_at_index(block, idx, client)
|
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn uncle_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<RichBlock>> {
|
2017-10-08 18:19:27 +02:00
|
|
|
let client = self.client.clone();
|
2018-09-25 19:06:14 +02:00
|
|
|
Box::new(self.fetcher().block(num.to_block_id()).map(move |block| {
|
2017-10-08 18:19:27 +02:00
|
|
|
extract_uncle_at_index(block, idx, client)
|
|
|
|
}))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn proof(&self, _address: H160, _values:Vec<H256>, _num: Option<BlockNumber>) -> BoxFuture<EthAccount> {
|
2018-11-21 20:09:33 +01:00
|
|
|
Box::new(future::err(errors::unimplemented(None)))
|
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn compilers(&self) -> Result<Vec<String>> {
|
2017-02-26 13:48:56 +01:00
|
|
|
Err(errors::deprecated("Compilation functionality is deprecated.".to_string()))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn compile_lll(&self, _: String) -> Result<Bytes> {
|
2017-02-26 13:48:56 +01:00
|
|
|
Err(errors::deprecated("Compilation of LLL via RPC is deprecated".to_string()))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn compile_serpent(&self, _: String) -> Result<Bytes> {
|
2017-02-26 13:48:56 +01:00
|
|
|
Err(errors::deprecated("Compilation of Serpent via RPC is deprecated".to_string()))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn compile_solidity(&self, _: String) -> Result<Bytes> {
|
2017-02-26 13:48:56 +01:00
|
|
|
Err(errors::deprecated("Compilation of Solidity via RPC is deprecated".to_string()))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn logs(&self, filter: Filter) -> BoxFuture<Vec<Log>> {
|
2017-03-28 15:42:23 +02:00
|
|
|
let limit = filter.limit;
|
|
|
|
|
2018-08-13 09:47:10 +02:00
|
|
|
Box::new(
|
|
|
|
Filterable::logs(self, match filter.try_into() {
|
|
|
|
Ok(value) => value,
|
|
|
|
Err(err) => return Box::new(future::err(err)),
|
|
|
|
}).map(move |logs| limit_logs(logs, limit)))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-05 14:31:19 +01:00
|
|
|
fn work(&self, _timeout: Option<u64>) -> Result<Work> {
|
2017-03-28 15:42:23 +02:00
|
|
|
Err(errors::light_unimplemented(None))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn submit_work(&self, _nonce: H64, _pow_hash: H256, _mix_hash: H256) -> Result<bool> {
|
2017-03-28 15:42:23 +02:00
|
|
|
Err(errors::light_unimplemented(None))
|
2017-02-03 17:41:25 +01:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn submit_hashrate(&self, _rate: U256, _id: H256) -> Result<bool> {
|
2017-03-28 15:42:23 +02:00
|
|
|
Err(errors::light_unimplemented(None))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This trait implementation triggers a blanked impl of `EthFilter`.
|
2019-02-11 11:33:16 +01:00
|
|
|
impl<C, S> Filterable for EthClient<C, S>
|
|
|
|
where
|
|
|
|
C: LightChainClient + 'static,
|
|
|
|
S: LightSyncProvider + LightNetworkDispatcher + ManageNetwork + 'static
|
|
|
|
{
|
2017-03-28 15:42:23 +02:00
|
|
|
fn best_block_number(&self) -> u64 { self.client.chain_info().best_block_number }
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn block_hash(&self, id: BlockId) -> Option<H256> {
|
2018-06-13 13:39:27 +02:00
|
|
|
self.client.block_hash(id)
|
2017-03-28 15:42:23 +02:00
|
|
|
}
|
|
|
|
|
2019-02-25 14:27:28 +01:00
|
|
|
fn pending_transaction_hashes(&self) -> BTreeSet<H256> {
|
2018-07-04 17:37:55 +02:00
|
|
|
BTreeSet::new()
|
2017-03-28 15:42:23 +02:00
|
|
|
}
|
|
|
|
|
2017-11-14 11:38:17 +01:00
|
|
|
fn logs(&self, filter: EthcoreFilter) -> BoxFuture<Vec<Log>> {
|
2018-05-24 04:39:52 +02:00
|
|
|
Box::new(self.fetcher().logs(filter)) as BoxFuture<_>
|
2017-03-28 15:42:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pending_logs(&self, _block_number: u64, _filter: &EthcoreFilter) -> Vec<Log> {
|
|
|
|
Vec::new() // light clients don't mine.
|
|
|
|
}
|
|
|
|
|
2018-07-04 17:37:55 +02:00
|
|
|
fn polls(&self) -> &Mutex<PollManager<SyncPollFilter>> {
|
2017-03-28 15:42:23 +02:00
|
|
|
&self.polls
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
2018-06-13 13:39:27 +02:00
|
|
|
|
|
|
|
fn removed_logs(&self, _block_hash: ::ethereum_types::H256, _filter: &EthcoreFilter) -> (Vec<Log>, u64) {
|
|
|
|
(Default::default(), 0)
|
|
|
|
}
|
2017-02-03 16:20:43 +01:00
|
|
|
}
|
2017-10-08 18:19:27 +02:00
|
|
|
|
|
|
|
fn extract_uncle_at_index<T: LightChainClient>(block: encoded::Block, index: Index, client: Arc<T>) -> Option<RichBlock> {
|
|
|
|
let uncle = match block.uncles().into_iter().nth(index.value()) {
|
|
|
|
Some(u) => u,
|
|
|
|
None => return None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let extra_info = client.engine().extra_info(&uncle);
|
|
|
|
Some(RichBlock {
|
|
|
|
inner: Block {
|
2019-03-22 12:01:11 +01:00
|
|
|
hash: Some(uncle.hash()),
|
2017-10-08 18:19:27 +02:00
|
|
|
size: None,
|
2019-03-22 12:01:11 +01:00
|
|
|
parent_hash: *uncle.parent_hash(),
|
|
|
|
uncles_hash: *uncle.uncles_hash(),
|
|
|
|
author: *uncle.author(),
|
|
|
|
miner: *uncle.author(),
|
|
|
|
state_root: *uncle.state_root(),
|
|
|
|
transactions_root: *uncle.transactions_root(),
|
2017-10-08 18:19:27 +02:00
|
|
|
number: Some(uncle.number().into()),
|
2019-03-22 12:01:11 +01:00
|
|
|
gas_used: *uncle.gas_used(),
|
|
|
|
gas_limit: *uncle.gas_limit(),
|
|
|
|
logs_bloom: Some(*uncle.log_bloom()),
|
2017-10-08 18:19:27 +02:00
|
|
|
timestamp: uncle.timestamp().into(),
|
2019-03-22 12:01:11 +01:00
|
|
|
difficulty: *uncle.difficulty(),
|
2017-10-08 18:19:27 +02:00
|
|
|
total_difficulty: None,
|
2019-03-22 12:01:11 +01:00
|
|
|
receipts_root: *uncle.receipts_root(),
|
2017-10-08 18:19:27 +02:00
|
|
|
extra_data: uncle.extra_data().clone().into(),
|
2019-03-22 12:01:11 +01:00
|
|
|
seal_fields: uncle.seal().iter().cloned().map(Into::into).collect(),
|
2017-10-08 18:19:27 +02:00
|
|
|
uncles: vec![],
|
|
|
|
transactions: BlockTransactions::Hashes(vec![]),
|
|
|
|
},
|
2019-03-22 12:01:11 +01:00
|
|
|
extra_info,
|
2017-10-08 18:19:27 +02:00
|
|
|
})
|
|
|
|
}
|