diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index e1074c598..955d927bd 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -49,6 +49,7 @@ mod codes { pub const COMPILATION_ERROR: i64 = -32050; pub const ENCRYPTION_ERROR: i64 = -32055; pub const FETCH_ERROR: i64 = -32060; + pub const ON_DEMAND_ERROR: i64 = -32065; } pub fn unimplemented(details: Option) -> Error { @@ -308,3 +309,11 @@ pub fn unknown_block() -> Error { data: None, } } + +pub fn from_on_demand_error(error: ::light::on_demand::Error) -> Error { + Error { + code: ErrorCode::ServerError(codes::ON_DEMAND_ERROR), + message: "Failed to fetch on-demand data".into(), + data: Some(Value::String(format!("{:?}", error))) + } +} diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 16ad89dae..5db254a74 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -22,7 +22,7 @@ use std::thread; use std::time::{Instant, Duration}; use std::sync::{Arc, Weak}; -use futures::{self, BoxFuture, Future}; +use futures::{self, future, BoxFuture, Future}; use rlp::{self, UntrustedRlp, View}; use time::get_time; use util::{H160, H256, Address, FixedHash, U256, H64, Uint}; @@ -386,130 +386,161 @@ impl Eth for EthClient where } fn balance(&self, address: RpcH160, num: Trailing) -> BoxFuture { - self.active()?; - let address = address.into(); - match num.0 { - BlockNumber::Pending => Ok(take_weak!(self.miner).balance(&*take_weak!(self.client), &address).into()), - id => { - let client = take_weak!(self.client); - check_known(&*client, id.clone())?; - match client.balance(&address, id.into()) { - Some(balance) => Ok(balance.into()), - None => Err(errors::state_pruned()), + let inner = || { + self.active()?; + match num.0.clone() { + BlockNumber::Pending => Ok(take_weak!(self.miner).balance(&*take_weak!(self.client), &address).into()), + id => { + let client = take_weak!(self.client); + + check_known(&*client, id.clone())?; + match client.balance(&address, id.into()) { + Some(balance) => Ok(balance.into()), + None => Err(errors::state_pruned()), + } } } - } + }; + + future::done(inner()).boxed() } - fn storage_at(&self, address: RpcH160, pos: RpcU256, num: Trailing) -> Result { - self.active()?; + fn storage_at(&self, address: RpcH160, pos: RpcU256, num: Trailing) -> BoxFuture { let address: Address = RpcH160::into(address); let position: U256 = RpcU256::into(pos); - match num.0 { - BlockNumber::Pending => Ok(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position)).into()), - id => { - let client = take_weak!(self.client); - check_known(&*client, id.clone())?; - match client.storage_at(&address, &H256::from(position), id.into()) { - Some(s) => Ok(s.into()), - None => Err(errors::state_pruned()), + let inner = || { + self.active()?; + match num.0.clone() { + BlockNumber::Pending => Ok(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position)).into()), + id => { + let client = take_weak!(self.client); + + check_known(&*client, id.clone())?; + match client.storage_at(&address, &H256::from(position), id.into()) { + Some(s) => Ok(s.into()), + None => Err(errors::state_pruned()), + } } } - } + }; + + future::done(inner()).boxed() } - fn transaction_count(&self, address: RpcH160, num: Trailing) -> Result { - self.active()?; - + fn transaction_count(&self, address: RpcH160, num: Trailing) -> BoxFuture { let address: Address = RpcH160::into(address); - match num.0 { - BlockNumber::Pending => Ok(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address).into()), - id => { - let client = take_weak!(self.client); + let inner = move || { + self.active()?; + match num.0.clone() { + BlockNumber::Pending => Ok(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address).into()), + id => { + let client = take_weak!(self.client); - check_known(&*client, id.clone())?; - match client.nonce(&address, id.into()) { - Some(nonce) => Ok(nonce.into()), - None => Err(errors::state_pruned()), + check_known(&*client, id.clone())?; + match client.nonce(&address, id.into()) { + Some(nonce) => Ok(nonce.into()), + None => Err(errors::state_pruned()), + } } } - } + }; + + future::done(inner()).boxed() } - fn block_transaction_count_by_hash(&self, hash: RpcH256) -> Result, Error> { - self.active()?; - Ok( - take_weak!(self.client).block(BlockId::Hash(hash.into())) - .map(|block| block.transactions_count().into()) - ) + fn block_transaction_count_by_hash(&self, hash: RpcH256) -> BoxFuture, Error> { + let inner = || { + self.active()?; + Ok(take_weak!(self.client).block(BlockId::Hash(hash.into())) + .map(|block| block.transactions_count().into())) + }; + + future::done(inner()).boxed() } - fn block_transaction_count_by_number(&self, num: BlockNumber) -> Result, Error> { - self.active()?; + fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture, Error> { + let inner = || { + self.active()?; + match num { + BlockNumber::Pending => Ok(Some( + take_weak!(self.miner).status().transactions_in_pending_block.into() + )), + _ => Ok( + take_weak!(self.client).block(num.into()) + .map(|block| block.transactions_count().into()) + ) + } + }; - match num { - BlockNumber::Pending => Ok(Some( - take_weak!(self.miner).status().transactions_in_pending_block.into() - )), - _ => Ok( - take_weak!(self.client).block(num.into()) - .map(|block| block.transactions_count().into()) - ) - } + future::done(inner()).boxed() } - fn block_uncles_count_by_hash(&self, hash: RpcH256) -> Result, Error> { - self.active()?; + fn block_uncles_count_by_hash(&self, hash: RpcH256) -> BoxFuture, Error> { + let inner = || { + self.active()?; + Ok(take_weak!(self.client).block(BlockId::Hash(hash.into())) + .map(|block| block.uncles_count().into())) + }; - Ok( - take_weak!(self.client).block(BlockId::Hash(hash.into())) - .map(|block| block.uncles_count().into()) - ) + future::done(inner()).boxed() } - fn block_uncles_count_by_number(&self, num: BlockNumber) -> Result, Error> { - self.active()?; + fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture, Error> { + let inner = || { + self.active()?; + match num { + BlockNumber::Pending => Ok(Some(0.into())), + _ => Ok( + take_weak!(self.client).block(num.into()) + .map(|block| block.uncles_count().into()) + ), + } + }; - match num { - BlockNumber::Pending => Ok(Some(0.into())), - _ => Ok( - take_weak!(self.client).block(num.into()) - .map(|block| block.uncles_count().into()) - ), - } + future::done(inner()).boxed() } - fn code_at(&self, address: RpcH160, num: Trailing) -> Result { - self.active()?; - + fn code_at(&self, address: RpcH160, num: Trailing) -> BoxFuture { let address: Address = RpcH160::into(address); - match num.0 { - BlockNumber::Pending => Ok(take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)), - id => { - let client = take_weak!(self.client); - check_known(&*client, id.clone())?; - match client.code(&address, id.into()) { - Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), - None => Err(errors::state_pruned()), + let inner = || { + self.active()?; + match num.0.clone() { + BlockNumber::Pending => Ok(take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)), + id => { + let client = take_weak!(self.client); + + check_known(&*client, id.clone())?; + match client.code(&address, id.into()) { + Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), + None => Err(errors::state_pruned()), + } } } - } + }; + + future::done(inner()).boxed() } - fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> Result, Error> { - self.active()?; + fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> BoxFuture, Error> { + let inner = || { + self.active()?; + self.block(BlockId::Hash(hash.into()), include_txs) + }; - self.block(BlockId::Hash(hash.into()), include_txs) + future::done(inner()).boxed() } - fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> Result, Error> { - self.active()?; + fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture, Error> { + let inner = || { + self.active()?; + self.block(num.into(), include_txs) + }; - self.block(num.into(), include_txs) + future::done(inner()).boxed() } fn transaction_by_hash(&self, hash: RpcH256) -> Result, Error> { diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 4c2f34d20..9b48131ce 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -26,12 +26,12 @@ use light::cht; use light::on_demand::{request, OnDemand}; use light::net::LightProtocol; -use ethcore::account_provider::AccountProvider; +use ethcore::account_provider::{AccountProvider, DappId}; use ethcore::encoded; use ethcore::ids::BlockId; use ethsync::LightSync; -use futures::{future, BoxFuture}; +use futures::{future, Future, BoxFuture}; use v1::helpers::{CallRequest as CRequest, errors, limit_logs}; use v1::helpers::dispatch::{dispatch_transaction, default_gas_price}; @@ -52,6 +52,11 @@ pub struct EthClient { accounts: Arc, } +// helper for a specific kind of internal error. +fn err_no_context() -> Error { + errors::internal("network service detached", "") +} + 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. @@ -77,7 +82,7 @@ impl EthClient { 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)); + let cht_root = cht::block_to_cht_number(n).and_then(|cn| self.client.cht_root(cn as usize)); match cht_root { None => return future::err(errors::unknown_block()).boxed(), Some(root) => { @@ -86,19 +91,19 @@ impl EthClient { cht_root: root, }; - self.sync.with_context(|ctx| self.on_demand.header_by_number(req)) + self.sync.with_context(|ctx| self.on_demand.header_by_number(ctx, req)) } } } BlockId::Hash(h) => { - self.sync.with_context(|ctx| self.on_demand.header_by_hash(request::HeaderByHash(h))) + self.sync.with_context(|ctx| self.on_demand.header_by_hash(ctx, 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() + Some(recv) => recv.map_err(errors::from_on_demand_error).boxed(), + None => future::err(err_no_context()).boxed() } } } @@ -115,7 +120,7 @@ impl Eth for EthClient { } fn author(&self, _meta: Self::Metadata) -> BoxFuture { - future::ok(Default::default()) + future::ok(Default::default()).boxed() } fn is_mining(&self) -> Result { @@ -131,12 +136,13 @@ impl Eth for EthClient { } fn accounts(&self, meta: Metadata) -> BoxFuture, Error> { - let dapp = meta.dapp_id.unwrap_or_default(); + let dapp: DappId = meta.dapp_id.unwrap_or_default().into(); 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)); + .map_err(|e| errors::internal("Could not fetch accounts.", e)) + .map(|accs| accs.into_iter().map(Into::::into).collect()); future::done(accounts).boxed() } @@ -151,11 +157,121 @@ impl Eth for EthClient { let sync = self.sync.clone(); let on_demand = self.on_demand.clone(); - self.header(num.0.into()).then(move |header| { + self.header(num.0.into()).and_then(move |header| { sync.with_context(|ctx| on_demand.account(ctx, request::Account { header: header, address: address, })) - }) + .map(|x| x.map_err(errors::from_on_demand_error).boxed()) + .unwrap_or_else(|| future::err(err_no_context()).boxed()) + }).map(|acc| acc.balance.into()).boxed() + } + + fn storage_at(&self, address: RpcH160, key: RpcU256, num: Trailing) -> BoxFuture { + future::err(errors::unimplemented(None)).boxed() + } + + fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> BoxFuture, Error> { + future::err(errors::unimplemented(None)).boxed() + } + + fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture, Error> { + future::err(errors::unimplemented(None)).boxed() + } + + fn transaction_count(&self, address: RpcH160, num: Trailing) -> BoxFuture { + future::err(errors::unimplemented(None)).boxed() + } + + fn block_transaction_count_by_hash(&self, hash: RpcH256) -> BoxFuture, Error> { + future::err(errors::unimplemented(None)).boxed() + } + + fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture, Error> { + future::err(errors::unimplemented(None)).boxed() + } + + fn block_uncles_count_by_hash(&self, hash: RpcH256) -> BoxFuture, Error> { + future::err(errors::unimplemented(None)).boxed() + } + + fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture, Error> { + future::err(errors::unimplemented(None)).boxed() + } + + fn code_at(&self, address: RpcH160, num: Trailing) -> BoxFuture { + future::err(errors::unimplemented(None)).boxed() + } + + fn send_raw_transaction(&self, raw: Bytes) -> Result { + Err(errors::unimplemented(None)) + } + + fn submit_transaction(&self, raw: Bytes) -> Result { + Err(errors::unimplemented(None)) + } + + fn call(&self, req: CallRequest, num: Trailing) -> Result { + Err(errors::unimplemented(None)) + } + + fn estimate_gas(&self, req: CallRequest, num: Trailing) -> Result { + Err(errors::unimplemented(None)) + } + + fn transaction_by_hash(&self, hash: RpcH256) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn transaction_by_block_hash_and_index(&self, hash: RpcH256, idx: Index) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn transaction_receipt(&self, hash: RpcH256) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn uncle_by_block_hash_and_index(&self, hash: RpcH256, idx: Index) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn uncle_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn compilers(&self) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn compile_lll(&self, _code: String) -> Result { + Err(errors::unimplemented(None)) + } + + fn compile_solidity(&self, _code: String) -> Result { + Err(errors::unimplemented(None)) + } + + fn compile_serpent(&self, _code: String) -> Result { + Err(errors::unimplemented(None)) + } + + fn logs(&self, _filter: Filter) -> Result, Error> { + Err(errors::unimplemented(None)) + } + + fn work(&self, _timeout: Trailing) -> Result { + Err(errors::unimplemented(None)) + } + + fn submit_work(&self, _nonce: RpcH64, _pow_hash: RpcH256, _mix_hash: RpcH256) -> Result { + Err(errors::unimplemented(None)) + } + + fn submit_hashrate(&self, _rate: RpcU256, _id: RpcH256) -> Result { + Err(errors::unimplemented(None)) } } diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index cdc4f95c5..a50188bf0 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -62,44 +62,44 @@ build_rpc_trait! { fn block_number(&self) -> Result; /// Returns balance of the given account. - #[rpc(name = "eth_getBalance")] + #[rpc(async, name = "eth_getBalance")] fn balance(&self, H160, Trailing) -> BoxFuture; /// Returns content of the storage at given address. - #[rpc(name = "eth_getStorageAt")] - fn storage_at(&self, H160, U256, Trailing) -> Result; + #[rpc(async, name = "eth_getStorageAt")] + fn storage_at(&self, H160, U256, Trailing) -> BoxFuture; /// Returns block with given hash. - #[rpc(name = "eth_getBlockByHash")] - fn block_by_hash(&self, H256, bool) -> Result, Error>; + #[rpc(async, name = "eth_getBlockByHash")] + fn block_by_hash(&self, H256, bool) -> BoxFuture, Error>; /// Returns block with given number. - #[rpc(name = "eth_getBlockByNumber")] - fn block_by_number(&self, BlockNumber, bool) -> Result, Error>; + #[rpc(async, name = "eth_getBlockByNumber")] + fn block_by_number(&self, BlockNumber, bool) -> BoxFuture, Error>; /// Returns the number of transactions sent from given address at given time (block number). - #[rpc(name = "eth_getTransactionCount")] - fn transaction_count(&self, H160, Trailing) -> Result; + #[rpc(async, name = "eth_getTransactionCount")] + fn transaction_count(&self, H160, Trailing) -> BoxFuture; /// Returns the number of transactions in a block with given hash. - #[rpc(name = "eth_getBlockTransactionCountByHash")] - fn block_transaction_count_by_hash(&self, H256) -> Result, Error>; + #[rpc(async, name = "eth_getBlockTransactionCountByHash")] + fn block_transaction_count_by_hash(&self, H256) -> BoxFuture, Error>; /// Returns the number of transactions in a block with given block number. - #[rpc(name = "eth_getBlockTransactionCountByNumber")] - fn block_transaction_count_by_number(&self, BlockNumber) -> Result, Error>; + #[rpc(async, name = "eth_getBlockTransactionCountByNumber")] + fn block_transaction_count_by_number(&self, BlockNumber) -> BoxFuture, Error>; /// Returns the number of uncles in a block with given hash. - #[rpc(name = "eth_getUncleCountByBlockHash")] - fn block_uncles_count_by_hash(&self, H256) -> Result, Error>; + #[rpc(async, name = "eth_getUncleCountByBlockHash")] + fn block_uncles_count_by_hash(&self, H256) -> BoxFuture, Error>; /// Returns the number of uncles in a block with given block number. - #[rpc(name = "eth_getUncleCountByBlockNumber")] - fn block_uncles_count_by_number(&self, BlockNumber) -> Result, Error>; + #[rpc(async, name = "eth_getUncleCountByBlockNumber")] + fn block_uncles_count_by_number(&self, BlockNumber) -> BoxFuture, Error>; /// Returns the code at given address at given time (block number). - #[rpc(name = "eth_getCode")] - fn code_at(&self, H160, Trailing) -> Result; + #[rpc(async, name = "eth_getCode")] + fn code_at(&self, H160, Trailing) -> BoxFuture; /// Sends signed transaction, returning its hash. #[rpc(name = "eth_sendRawTransaction")]