diff --git a/Cargo.lock b/Cargo.lock index 76254eca6..480e6208b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,6 +570,7 @@ dependencies = [ "ethcore-devtools 1.6.0", "ethcore-io 1.6.0", "ethcore-ipc 1.6.0", + "ethcore-light 1.6.0", "ethcore-util 1.6.0", "ethcrypto 0.1.0", "ethjson 0.1.0", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index a11112032..d4ab5d97d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -32,6 +32,7 @@ ethash = { path = "../ethash" } ethsync = { path = "../sync" } ethjson = { path = "../json" } ethcore-devtools = { path = "../devtools" } +ethcore-light = { path = "../ethcore/light" } parity-updater = { path = "../updater" } rlp = { path = "../util/rlp" } fetch = { path = "../util/fetch" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index d50ee7cfd..ab7ff87fe 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -33,6 +33,7 @@ extern crate ethcrypto as crypto; extern crate ethstore; extern crate ethsync; extern crate ethash; +extern crate ethcore_light as light; extern crate transient_hashmap; extern crate jsonrpc_ipc_server as ipc; extern crate ethcore_ipc; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 5270e417d..16ad89dae 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -385,7 +385,7 @@ impl Eth for EthClient where Ok(RpcU256::from(take_weak!(self.client).chain_info().best_block_number)) } - fn balance(&self, address: RpcH160, num: Trailing) -> Result { + fn balance(&self, address: RpcH160, num: Trailing) -> BoxFuture { self.active()?; let address = address.into(); diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs new file mode 100644 index 000000000..4c2f34d20 --- /dev/null +++ b/rpc/src/v1/impls/light/eth.rs @@ -0,0 +1,161 @@ +// Copyright 2015-2017 Parity Technologies (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 . + +//! Eth RPC interface for the light client. + +use std::sync::Arc; + +use jsonrpc_core::Error; +use jsonrpc_macros::Trailing; + +use light::client::Client as LightClient; +use light::cht; +use light::on_demand::{request, OnDemand}; +use light::net::LightProtocol; + +use ethcore::account_provider::AccountProvider; +use ethcore::encoded; +use ethcore::ids::BlockId; +use ethsync::LightSync; + +use futures::{future, BoxFuture}; + +use v1::helpers::{CallRequest as CRequest, errors, limit_logs}; +use v1::helpers::dispatch::{dispatch_transaction, default_gas_price}; +use v1::helpers::block_import::is_major_importing; +use v1::traits::Eth; +use v1::types::{ + RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, + Transaction, CallRequest, Index, Filter, Log, Receipt, Work, + H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256, +}; +use v1::metadata::Metadata; + +/// Light client `ETH` RPC. +pub struct EthClient { + sync: Arc, + client: Arc, + on_demand: Arc, + accounts: Arc, +} + +impl EthClient { + /// 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( + sync: Arc, + client: Arc, + on_demand: Arc, + accounts: Arc, + ) -> Self { + EthClient { + sync: sync, + client: client, + on_demand: on_demand, + accounts: accounts, + } + } + + /// Get a block header from the on demand service or client, or error. + fn header(&self, id: BlockId) -> BoxFuture { + if let Some(h) = self.client.get_header(id) { + return future::ok(h).boxed() + } + + let maybe_future = match id { + BlockId::Number(n) => { + let cht_root = cht::block_to_cht_number(n).and_then(|cn| self.client.cht_root(cn)); + match cht_root { + None => return future::err(errors::unknown_block()).boxed(), + Some(root) => { + let req = request::HeaderByNumber { + num: n, + cht_root: root, + }; + + self.sync.with_context(|ctx| self.on_demand.header_by_number(req)) + } + } + } + BlockId::Hash(h) => { + self.sync.with_context(|ctx| self.on_demand.header_by_hash(request::HeaderByHash(h))) + } + _ => None, // latest, earliest, and pending will have all already returned. + }; + + match maybe_future { + Some(recv) => recv.boxed(), + None => future::err(errors::internal("network service detached", "")).boxed() + } + } +} + +impl Eth for EthClient { + type Metadata = Metadata; + + fn protocol_version(&self) -> Result { + Ok(format!("{}", ::light::net::MAX_PROTOCOL_VERSION)) + } + + fn syncing(&self) -> Result { + rpc_unimplemented!() + } + + fn author(&self, _meta: Self::Metadata) -> BoxFuture { + future::ok(Default::default()) + } + + fn is_mining(&self) -> Result { + Ok(false) + } + + fn hashrate(&self) -> Result { + Ok(Default::default()) + } + + fn gas_price(&self) -> Result { + Ok(Default::default()) + } + + fn accounts(&self, meta: Metadata) -> BoxFuture, Error> { + let dapp = meta.dapp_id.unwrap_or_default(); + + let accounts = self.accounts + .note_dapp_used(dapp.clone()) + .and_then(|_| self.accounts.dapps_addresses(dapp)) + .map_err(|e| errors::internal("Could not fetch accounts.", e)); + + future::done(accounts).boxed() + } + + fn block_number(&self) -> Result { + Ok(self.client.chain_info().best_block_number.into()) + } + + fn balance(&self, address: RpcH160, num: Trailing) -> BoxFuture { + let address = address.into(); + + let sync = self.sync.clone(); + let on_demand = self.on_demand.clone(); + + self.header(num.0.into()).then(move |header| { + sync.with_context(|ctx| on_demand.account(ctx, request::Account { + header: header, + address: address, + })) + }) + } +} diff --git a/rpc/src/v1/impls/light/mod.rs b/rpc/src/v1/impls/light/mod.rs new file mode 100644 index 000000000..6aa15c22d --- /dev/null +++ b/rpc/src/v1/impls/light/mod.rs @@ -0,0 +1,19 @@ +// Copyright 2015-2017 Parity Technologies (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 . + +//! RPC implementations for the light client. + +mod eth; diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 72829c2b5..719699d8f 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -32,6 +32,7 @@ mod parity; mod parity_accounts; mod parity_set; mod personal; +mod light; mod signer; mod signing; mod signing_unsafe; diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 877a18a1d..cdc4f95c5 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -63,7 +63,7 @@ build_rpc_trait! { /// Returns balance of the given account. #[rpc(name = "eth_getBalance")] - fn balance(&self, H160, Trailing) -> Result; + fn balance(&self, H160, Trailing) -> BoxFuture; /// Returns content of the storage at given address. #[rpc(name = "eth_getStorageAt")]