Add Error message when sync is still in progress. (#9475)

* closes #9188

* check_for_unavailable_block in
eth_getTransactionByHash
eth_getTransactionByBlockHashAndIndex
eth_getTransactionByBlockNumberAndIndex
eth_getTransactionReceipt

* check for unavailable block in eth_getBlockByNumber

* corrected checks for unavailable_block

* check for block gaps in db

* corrected error messages

* corrected error information

* added allow-empty-block-result cli flag

* address grumbles

* --jsonrpc-allow-missing-blocks

* fix tests

* added checks to
    block_transaction_count_by_hash
    block_transaction_count_by_number
    block_uncles_count_by_hash
    block_uncles_count_by_number
    uncle_by_block_hash_and_index
    uncle_by_block_number_and_index
fix PR grumbles

* Update parity/cli/mod.rs

revert config name

Co-Authored-By: seunlanlege <seunlanlege@gmail.com>

* Update parity/cli/mod.rs

revert cli arg

Co-Authored-By: seunlanlege <seunlanlege@gmail.com>

* Apply suggestions from code review

revert config name

Co-Authored-By: seunlanlege <seunlanlege@gmail.com>

* fix PR grumbles

* fix more PR grumbles
This commit is contained in:
Seun LanLege 2018-11-26 19:58:27 +01:00 committed by Wei Tang
parent 18a2e6265d
commit f2281dc38a
8 changed files with 489 additions and 210 deletions

View File

@ -463,6 +463,10 @@ usage! {
["API and Console Options HTTP JSON-RPC"] ["API and Console Options HTTP JSON-RPC"]
FLAG flag_jsonrpc_allow_missing_blocks: (bool) = false, or |c: &Config| c.rpc.as_ref()?.allow_missing_blocks.clone(),
"--jsonrpc-allow-missing-blocks",
"RPC calls will return 'null' instead of an error if ancient block sync is still in progress and the block information requested could not be found",
FLAG flag_no_jsonrpc: (bool) = false, or |c: &Config| c.rpc.as_ref()?.disable.clone(), FLAG flag_no_jsonrpc: (bool) = false, or |c: &Config| c.rpc.as_ref()?.disable.clone(),
"--no-jsonrpc", "--no-jsonrpc",
"Disable the HTTP JSON-RPC API server.", "Disable the HTTP JSON-RPC API server.",
@ -1230,6 +1234,7 @@ struct Rpc {
keep_alive: Option<bool>, keep_alive: Option<bool>,
experimental_rpcs: Option<bool>, experimental_rpcs: Option<bool>,
poll_lifetime: Option<u32>, poll_lifetime: Option<u32>,
allow_missing_blocks: Option<bool>,
} }
#[derive(Default, Debug, PartialEq, Deserialize)] #[derive(Default, Debug, PartialEq, Deserialize)]
@ -1697,6 +1702,7 @@ mod tests {
arg_jsonrpc_threads: 4, arg_jsonrpc_threads: 4,
arg_jsonrpc_max_payload: None, arg_jsonrpc_max_payload: None,
arg_poll_lifetime: 60u32, arg_poll_lifetime: 60u32,
flag_jsonrpc_allow_missing_blocks: false,
// WS // WS
flag_no_ws: false, flag_no_ws: false,
@ -1973,6 +1979,7 @@ mod tests {
keep_alive: None, keep_alive: None,
experimental_rpcs: None, experimental_rpcs: None,
poll_lifetime: None, poll_lifetime: None,
allow_missing_blocks: None
}), }),
ipc: Some(Ipc { ipc: Some(Ipc {
disable: None, disable: None,

View File

@ -64,6 +64,7 @@ interface = "local"
cors = ["null"] cors = ["null"]
apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"] apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"]
hosts = ["none"] hosts = ["none"]
allow_missing_blocks = false
[websockets] [websockets]
disable = false disable = false

View File

@ -370,6 +370,7 @@ impl Configuration {
miner_extras: self.miner_extras()?, miner_extras: self.miner_extras()?,
stratum: self.stratum_options()?, stratum: self.stratum_options()?,
update_policy: update_policy, update_policy: update_policy,
allow_missing_blocks: self.args.flag_jsonrpc_allow_missing_blocks,
mode: mode, mode: mode,
tracing: tracing, tracing: tracing,
fat_db: fat_db, fat_db: fat_db,
@ -1390,6 +1391,7 @@ mod tests {
let args = vec!["parity"]; let args = vec!["parity"];
let conf = parse(&args); let conf = parse(&args);
let mut expected = RunCmd { let mut expected = RunCmd {
allow_missing_blocks: false,
cache_config: Default::default(), cache_config: Default::default(),
dirs: Default::default(), dirs: Default::default(),
spec: Default::default(), spec: Default::default(),

View File

@ -21,24 +21,24 @@ use std::sync::{Arc, Weak};
pub use parity_rpc::signer::SignerService; pub use parity_rpc::signer::SignerService;
use ethcore_service::PrivateTxService;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use ethcore::client::Client; use ethcore::client::Client;
use ethcore::miner::Miner; use ethcore::miner::Miner;
use ethcore::snapshot::SnapshotService; use ethcore::snapshot::SnapshotService;
use ethcore_logger::RotatingLogger; use ethcore_logger::RotatingLogger;
use sync::{ManageNetwork, SyncProvider, LightSync}; use ethcore_private_tx::Provider as PrivateTransactionManager;
use ethcore_service::PrivateTxService;
use hash_fetch::fetch::Client as FetchClient; use hash_fetch::fetch::Client as FetchClient;
use jsonrpc_core::{self as core, MetaIoHandler}; use jsonrpc_core::{self as core, MetaIoHandler};
use light::client::LightChainClient; use light::client::LightChainClient;
use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache}; use light::{Cache as LightDataCache, TransactionQueue as LightTransactionQueue};
use miner::external::ExternalMiner; use miner::external::ExternalMiner;
use parity_runtime::Executor;
use parity_rpc::dispatch::{FullDispatcher, LightDispatcher}; use parity_rpc::dispatch::{FullDispatcher, LightDispatcher};
use parity_rpc::informant::{ActivityNotifier, ClientNotifier}; use parity_rpc::informant::{ActivityNotifier, ClientNotifier};
use parity_rpc::{Metadata, NetworkSettings, Host}; use parity_rpc::{Host, Metadata, NetworkSettings};
use parity_runtime::Executor;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use ethcore_private_tx::Provider as PrivateTransactionManager; use sync::{LightSync, ManageNetwork, SyncProvider};
use updater::Updater; use updater::Updater;
#[derive(Debug, PartialEq, Clone, Eq, Hash)] #[derive(Debug, PartialEq, Clone, Eq, Hash)]
@ -106,7 +106,7 @@ impl FromStr for Api {
"signer" => Ok(Signer), "signer" => Ok(Signer),
"traces" => Ok(Traces), "traces" => Ok(Traces),
"web3" => Ok(Web3), "web3" => Ok(Web3),
api => Err(format!("Unknown api: {}", api)) api => Err(format!("Unknown api: {}", api)),
} }
} }
} }
@ -149,20 +149,20 @@ impl FromStr for ApiSet {
match api { match api {
"all" => { "all" => {
apis.extend(ApiSet::All.list_apis()); apis.extend(ApiSet::All.list_apis());
}, }
"safe" => { "safe" => {
// Safe APIs are those that are safe even in UnsafeContext. // Safe APIs are those that are safe even in UnsafeContext.
apis.extend(ApiSet::UnsafeContext.list_apis()); apis.extend(ApiSet::UnsafeContext.list_apis());
}, }
// Remove the API // Remove the API
api if api.starts_with("-") => { api if api.starts_with("-") => {
let api = api[1..].parse()?; let api = api[1..].parse()?;
apis.remove(&api); apis.remove(&api);
}, }
api => { api => {
let api = api.parse()?; let api = api.parse()?;
apis.insert(api); apis.insert(api);
}, }
} }
} }
@ -205,11 +205,9 @@ pub trait Dependencies {
fn activity_notifier(&self) -> Self::Notifier; fn activity_notifier(&self) -> Self::Notifier;
/// Extend the given I/O handler with endpoints for each API. /// Extend the given I/O handler with endpoints for each API.
fn extend_with_set<S>( fn extend_with_set<S>(&self, handler: &mut MetaIoHandler<Metadata, S>, apis: &HashSet<Api>)
&self, where
handler: &mut MetaIoHandler<Metadata, S>, S: core::Middleware<Metadata>;
apis: &HashSet<Api>,
) where S: core::Middleware<Metadata>;
} }
/// RPC dependencies for a full node. /// RPC dependencies for a full node.
@ -235,6 +233,7 @@ pub struct FullDependencies {
pub whisper_rpc: Option<::whisper::RpcFactory>, pub whisper_rpc: Option<::whisper::RpcFactory>,
pub gas_price_percentile: usize, pub gas_price_percentile: usize,
pub poll_lifetime: u32, pub poll_lifetime: u32,
pub allow_missing_blocks: bool,
} }
impl FullDependencies { impl FullDependencies {
@ -243,24 +242,39 @@ impl FullDependencies {
handler: &mut MetaIoHandler<Metadata, S>, handler: &mut MetaIoHandler<Metadata, S>,
apis: &HashSet<Api>, apis: &HashSet<Api>,
for_generic_pubsub: bool, for_generic_pubsub: bool,
) where S: core::Middleware<Metadata> { ) where
S: core::Middleware<Metadata>,
{
use parity_rpc::v1::*; use parity_rpc::v1::*;
macro_rules! add_signing_methods { macro_rules! add_signing_methods {
($namespace:ident, $handler:expr, $deps:expr, $nonces:expr) => { ($namespace:ident, $handler:expr, $deps:expr, $nonces:expr) => {{
{ let deps = &$deps;
let deps = &$deps; let dispatcher = FullDispatcher::new(
let dispatcher = FullDispatcher::new(deps.client.clone(), deps.miner.clone(), $nonces, deps.gas_price_percentile); deps.client.clone(),
if deps.signer_service.is_enabled() { deps.miner.clone(),
$handler.extend_with($namespace::to_delegate(SigningQueueClient::new(&deps.signer_service, dispatcher, deps.executor.clone(), &deps.secret_store))) $nonces,
} else { deps.gas_price_percentile,
$handler.extend_with($namespace::to_delegate(SigningUnsafeClient::new(&deps.secret_store, dispatcher))) );
} if deps.signer_service.is_enabled() {
$handler.extend_with($namespace::to_delegate(SigningQueueClient::new(
&deps.signer_service,
dispatcher,
deps.executor.clone(),
&deps.secret_store,
)))
} else {
$handler.extend_with($namespace::to_delegate(SigningUnsafeClient::new(
&deps.secret_store,
dispatcher,
)))
} }
} }};
} }
let nonces = Arc::new(Mutex::new(dispatch::Reservations::new(self.executor.clone()))); let nonces = Arc::new(Mutex::new(dispatch::Reservations::new(
self.executor.clone(),
)));
let dispatcher = FullDispatcher::new( let dispatcher = FullDispatcher::new(
self.client.clone(), self.client.clone(),
self.miner.clone(), self.miner.clone(),
@ -271,13 +285,13 @@ impl FullDependencies {
match *api { match *api {
Api::Debug => { Api::Debug => {
handler.extend_with(DebugClient::new(self.client.clone()).to_delegate()); handler.extend_with(DebugClient::new(self.client.clone()).to_delegate());
}, }
Api::Web3 => { Api::Web3 => {
handler.extend_with(Web3Client::new().to_delegate()); handler.extend_with(Web3Client::new().to_delegate());
}, }
Api::Net => { Api::Net => {
handler.extend_with(NetClient::new(&self.sync).to_delegate()); handler.extend_with(NetClient::new(&self.sync).to_delegate());
}, }
Api::Eth => { Api::Eth => {
let client = EthClient::new( let client = EthClient::new(
&self.client, &self.client,
@ -291,91 +305,119 @@ impl FullDependencies {
allow_pending_receipt_query: !self.geth_compatibility, allow_pending_receipt_query: !self.geth_compatibility,
send_block_number_in_get_work: !self.geth_compatibility, send_block_number_in_get_work: !self.geth_compatibility,
gas_price_percentile: self.gas_price_percentile, gas_price_percentile: self.gas_price_percentile,
allow_missing_blocks: self.allow_missing_blocks,
allow_experimental_rpcs: self.experimental_rpcs, allow_experimental_rpcs: self.experimental_rpcs,
} }
); );
handler.extend_with(client.to_delegate()); handler.extend_with(client.to_delegate());
if !for_generic_pubsub { if !for_generic_pubsub {
let filter_client = EthFilterClient::new(self.client.clone(), self.miner.clone(), self.poll_lifetime); let filter_client = EthFilterClient::new(
self.client.clone(),
self.miner.clone(),
self.poll_lifetime,
);
handler.extend_with(filter_client.to_delegate()); handler.extend_with(filter_client.to_delegate());
add_signing_methods!(EthSigning, handler, self, nonces.clone()); add_signing_methods!(EthSigning, handler, self, nonces.clone());
} }
}, }
Api::EthPubSub => { Api::EthPubSub => {
if !for_generic_pubsub { if !for_generic_pubsub {
let client = EthPubSubClient::new(self.client.clone(), self.executor.clone()); let client =
EthPubSubClient::new(self.client.clone(), self.executor.clone());
let h = client.handler(); let h = client.handler();
self.miner.add_transactions_listener(Box::new(move |hashes| if let Some(h) = h.upgrade() { self.miner
h.notify_new_transactions(hashes); .add_transactions_listener(Box::new(move |hashes| {
})); if let Some(h) = h.upgrade() {
h.notify_new_transactions(hashes);
}
}));
if let Some(h) = client.handler().upgrade() { if let Some(h) = client.handler().upgrade() {
self.client.add_notify(h); self.client.add_notify(h);
} }
handler.extend_with(client.to_delegate()); handler.extend_with(client.to_delegate());
} }
}, }
Api::Personal => { Api::Personal => {
handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility, self.experimental_rpcs).to_delegate()); handler.extend_with(
}, PersonalClient::new(
&self.secret_store,
dispatcher.clone(),
self.geth_compatibility,
self.experimental_rpcs,
).to_delegate(),
);
}
Api::Signer => { Api::Signer => {
handler.extend_with(SignerClient::new(&self.secret_store, dispatcher.clone(), &self.signer_service, self.executor.clone()).to_delegate()); handler.extend_with(
}, SignerClient::new(
&self.secret_store,
dispatcher.clone(),
&self.signer_service,
self.executor.clone(),
).to_delegate(),
);
}
Api::Parity => { Api::Parity => {
let signer = match self.signer_service.is_enabled() { let signer = match self.signer_service.is_enabled() {
true => Some(self.signer_service.clone()), true => Some(self.signer_service.clone()),
false => None, false => None,
}; };
handler.extend_with(ParityClient::new( handler.extend_with(
self.client.clone(), ParityClient::new(
self.miner.clone(), self.client.clone(),
self.sync.clone(), self.miner.clone(),
self.updater.clone(), self.sync.clone(),
self.net_service.clone(), self.updater.clone(),
self.secret_store.clone(), self.net_service.clone(),
self.logger.clone(), self.secret_store.clone(),
self.settings.clone(), self.logger.clone(),
signer, self.settings.clone(),
self.ws_address.clone(), signer,
self.snapshot.clone().into(), self.ws_address.clone(),
).to_delegate()); self.snapshot.clone().into(),
).to_delegate(),
);
if !for_generic_pubsub { if !for_generic_pubsub {
add_signing_methods!(ParitySigning, handler, self, nonces.clone()); add_signing_methods!(ParitySigning, handler, self, nonces.clone());
} }
}, }
Api::ParityPubSub => { Api::ParityPubSub => {
if !for_generic_pubsub { if !for_generic_pubsub {
let mut rpc = MetaIoHandler::default(); let mut rpc = MetaIoHandler::default();
let apis = ApiSet::List(apis.clone()).retain(ApiSet::PubSub).list_apis(); let apis = ApiSet::List(apis.clone())
.retain(ApiSet::PubSub)
.list_apis();
self.extend_api(&mut rpc, &apis, true); self.extend_api(&mut rpc, &apis, true);
handler.extend_with(PubSubClient::new(rpc, self.executor.clone()).to_delegate()); handler.extend_with(
PubSubClient::new(rpc, self.executor.clone()).to_delegate(),
);
} }
}, }
Api::ParityAccounts => { Api::ParityAccounts => {
handler.extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate()); handler
}, .extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate());
Api::ParitySet => { }
handler.extend_with(ParitySetClient::new( Api::ParitySet => handler.extend_with(
ParitySetClient::new(
&self.client, &self.client,
&self.miner, &self.miner,
&self.updater, &self.updater,
&self.net_service, &self.net_service,
self.fetch.clone(), self.fetch.clone(),
).to_delegate()) ).to_delegate(),
}, ),
Api::Traces => { Api::Traces => handler.extend_with(TracesClient::new(&self.client).to_delegate()),
handler.extend_with(TracesClient::new(&self.client).to_delegate())
},
Api::Rpc => { Api::Rpc => {
let modules = to_modules(&apis); let modules = to_modules(&apis);
handler.extend_with(RpcClient::new(modules).to_delegate()); handler.extend_with(RpcClient::new(modules).to_delegate());
}, }
Api::SecretStore => { Api::SecretStore => {
handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate()); handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate());
}, }
Api::Whisper => { Api::Whisper => {
if let Some(ref whisper_rpc) = self.whisper_rpc { if let Some(ref whisper_rpc) = self.whisper_rpc {
let whisper = whisper_rpc.make_handler(self.net.clone()); let whisper = whisper_rpc.make_handler(self.net.clone());
@ -386,15 +428,18 @@ impl FullDependencies {
if !for_generic_pubsub { if !for_generic_pubsub {
if let Some(ref whisper_rpc) = self.whisper_rpc { if let Some(ref whisper_rpc) = self.whisper_rpc {
let whisper = whisper_rpc.make_handler(self.net.clone()); let whisper = whisper_rpc.make_handler(self.net.clone());
handler.extend_with( handler.extend_with(::parity_whisper::rpc::WhisperPubSub::to_delegate(
::parity_whisper::rpc::WhisperPubSub::to_delegate(whisper) whisper,
); ));
} }
} }
}, }
Api::Private => { Api::Private => {
handler.extend_with(PrivateClient::new(self.private_tx_service.as_ref().map(|p| p.provider())).to_delegate()); handler.extend_with(
}, PrivateClient::new(self.private_tx_service.as_ref().map(|p| p.provider()))
.to_delegate(),
);
}
} }
} }
} }
@ -409,11 +454,10 @@ impl Dependencies for FullDependencies {
} }
} }
fn extend_with_set<S>( fn extend_with_set<S>(&self, handler: &mut MetaIoHandler<Metadata, S>, apis: &HashSet<Api>)
&self, where
handler: &mut MetaIoHandler<Metadata, S>, S: core::Middleware<Metadata>,
apis: &HashSet<Api>, {
) where S: core::Middleware<Metadata> {
self.extend_api(handler, apis, false) self.extend_api(handler, apis, false)
} }
} }
@ -463,40 +507,44 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
self.on_demand.clone(), self.on_demand.clone(),
self.cache.clone(), self.cache.clone(),
self.transaction_queue.clone(), self.transaction_queue.clone(),
Arc::new(Mutex::new(dispatch::Reservations::new(self.executor.clone()))), Arc::new(Mutex::new(dispatch::Reservations::new(
self.executor.clone(),
))),
self.gas_price_percentile, self.gas_price_percentile,
); );
macro_rules! add_signing_methods { macro_rules! add_signing_methods {
($namespace:ident, $handler:expr, $deps:expr) => { ($namespace:ident, $handler:expr, $deps:expr) => {{
{ let deps = &$deps;
let deps = &$deps; let dispatcher = dispatcher.clone();
let dispatcher = dispatcher.clone(); let secret_store = deps.secret_store.clone();
let secret_store = deps.secret_store.clone(); if deps.signer_service.is_enabled() {
if deps.signer_service.is_enabled() { $handler.extend_with($namespace::to_delegate(SigningQueueClient::new(
$handler.extend_with($namespace::to_delegate( &deps.signer_service,
SigningQueueClient::new(&deps.signer_service, dispatcher, deps.executor.clone(), &secret_store) dispatcher,
)) deps.executor.clone(),
} else { &secret_store,
$handler.extend_with( )))
$namespace::to_delegate(SigningUnsafeClient::new(&secret_store, dispatcher)) } else {
) $handler.extend_with($namespace::to_delegate(SigningUnsafeClient::new(
&secret_store,
dispatcher,
)))
} }
} }};
}
} }
for api in apis { for api in apis {
match *api { match *api {
Api::Debug => { Api::Debug => {
warn!(target: "rpc", "Debug API is not available in light client mode.") warn!(target: "rpc", "Debug API is not available in light client mode.")
}, }
Api::Web3 => { Api::Web3 => {
handler.extend_with(Web3Client::new().to_delegate()); handler.extend_with(Web3Client::new().to_delegate());
}, }
Api::Net => { Api::Net => {
handler.extend_with(light::NetClient::new(self.sync.clone()).to_delegate()); handler.extend_with(light::NetClient::new(self.sync.clone()).to_delegate());
}, }
Api::Eth => { Api::Eth => {
let client = light::EthClient::new( let client = light::EthClient::new(
self.sync.clone(), self.sync.clone(),
@ -514,7 +562,7 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
handler.extend_with(EthFilter::to_delegate(client)); handler.extend_with(EthFilter::to_delegate(client));
add_signing_methods!(EthSigning, handler, self); add_signing_methods!(EthSigning, handler, self);
} }
}, }
Api::EthPubSub => { Api::EthPubSub => {
let client = EthPubSubClient::light( let client = EthPubSubClient::light(
self.client.clone(), self.client.clone(),
@ -526,77 +574,98 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
); );
self.client.add_listener(client.handler() as Weak<_>); self.client.add_listener(client.handler() as Weak<_>);
let h = client.handler(); let h = client.handler();
self.transaction_queue.write().add_listener(Box::new(move |transactions| { self.transaction_queue
if let Some(h) = h.upgrade() { .write()
h.notify_new_transactions(transactions); .add_listener(Box::new(move |transactions| {
} if let Some(h) = h.upgrade() {
})); h.notify_new_transactions(transactions);
}
}));
handler.extend_with(EthPubSub::to_delegate(client)); handler.extend_with(EthPubSub::to_delegate(client));
}, }
Api::Personal => { Api::Personal => {
handler.extend_with(PersonalClient::new(&self.secret_store, dispatcher.clone(), self.geth_compatibility, self.experimental_rpcs).to_delegate()); handler.extend_with(
}, PersonalClient::new(
&self.secret_store,
dispatcher.clone(),
self.geth_compatibility,
self.experimental_rpcs,
).to_delegate(),
);
}
Api::Signer => { Api::Signer => {
handler.extend_with(SignerClient::new(&self.secret_store, dispatcher.clone(), &self.signer_service, self.executor.clone()).to_delegate()); handler.extend_with(
}, SignerClient::new(
&self.secret_store,
dispatcher.clone(),
&self.signer_service,
self.executor.clone(),
).to_delegate(),
);
}
Api::Parity => { Api::Parity => {
let signer = match self.signer_service.is_enabled() { let signer = match self.signer_service.is_enabled() {
true => Some(self.signer_service.clone()), true => Some(self.signer_service.clone()),
false => None, false => None,
}; };
handler.extend_with(light::ParityClient::new( handler.extend_with(
Arc::new(dispatcher.clone()), light::ParityClient::new(
self.secret_store.clone(), Arc::new(dispatcher.clone()),
self.logger.clone(), self.secret_store.clone(),
self.settings.clone(), self.logger.clone(),
signer, self.settings.clone(),
self.ws_address.clone(), signer,
self.gas_price_percentile, self.ws_address.clone(),
).to_delegate()); self.gas_price_percentile,
).to_delegate(),
);
if !for_generic_pubsub { if !for_generic_pubsub {
add_signing_methods!(ParitySigning, handler, self); add_signing_methods!(ParitySigning, handler, self);
} }
}, }
Api::ParityPubSub => { Api::ParityPubSub => {
if !for_generic_pubsub { if !for_generic_pubsub {
let mut rpc = MetaIoHandler::default(); let mut rpc = MetaIoHandler::default();
let apis = ApiSet::List(apis.clone()).retain(ApiSet::PubSub).list_apis(); let apis = ApiSet::List(apis.clone())
.retain(ApiSet::PubSub)
.list_apis();
self.extend_api(&mut rpc, &apis, true); self.extend_api(&mut rpc, &apis, true);
handler.extend_with(PubSubClient::new(rpc, self.executor.clone()).to_delegate()); handler.extend_with(
PubSubClient::new(rpc, self.executor.clone()).to_delegate(),
);
} }
}, }
Api::ParityAccounts => { Api::ParityAccounts => {
handler.extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate()); handler
}, .extend_with(ParityAccountsClient::new(&self.secret_store).to_delegate());
Api::ParitySet => { }
handler.extend_with(light::ParitySetClient::new( Api::ParitySet => handler.extend_with(
self.sync.clone(), light::ParitySetClient::new(self.sync.clone(), self.fetch.clone())
self.fetch.clone(), .to_delegate(),
).to_delegate()) ),
}, Api::Traces => handler.extend_with(light::TracesClient.to_delegate()),
Api::Traces => {
handler.extend_with(light::TracesClient.to_delegate())
},
Api::Rpc => { Api::Rpc => {
let modules = to_modules(&apis); let modules = to_modules(&apis);
handler.extend_with(RpcClient::new(modules).to_delegate()); handler.extend_with(RpcClient::new(modules).to_delegate());
}, }
Api::SecretStore => { Api::SecretStore => {
handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate()); handler.extend_with(SecretStoreClient::new(&self.secret_store).to_delegate());
}, }
Api::Whisper => { Api::Whisper => {
if let Some(ref whisper_rpc) = self.whisper_rpc { if let Some(ref whisper_rpc) = self.whisper_rpc {
let whisper = whisper_rpc.make_handler(self.net.clone()); let whisper = whisper_rpc.make_handler(self.net.clone());
handler.extend_with(::parity_whisper::rpc::Whisper::to_delegate(whisper)); handler.extend_with(::parity_whisper::rpc::Whisper::to_delegate(whisper));
} }
}, }
Api::WhisperPubSub => { Api::WhisperPubSub => {
if let Some(ref whisper_rpc) = self.whisper_rpc { if let Some(ref whisper_rpc) = self.whisper_rpc {
let whisper = whisper_rpc.make_handler(self.net.clone()); let whisper = whisper_rpc.make_handler(self.net.clone());
handler.extend_with(::parity_whisper::rpc::WhisperPubSub::to_delegate(whisper)); handler.extend_with(::parity_whisper::rpc::WhisperPubSub::to_delegate(
whisper,
));
} }
}, }
Api::Private => { Api::Private => {
if let Some(ref tx_manager) = self.private_tx_service { if let Some(ref tx_manager) = self.private_tx_service {
let private_tx_service = Some(tx_manager.clone()); let private_tx_service = Some(tx_manager.clone());
@ -611,13 +680,14 @@ impl<C: LightChainClient + 'static> LightDependencies<C> {
impl<T: LightChainClient + 'static> Dependencies for LightDependencies<T> { impl<T: LightChainClient + 'static> Dependencies for LightDependencies<T> {
type Notifier = LightClientNotifier; type Notifier = LightClientNotifier;
fn activity_notifier(&self) -> Self::Notifier { LightClientNotifier } fn activity_notifier(&self) -> Self::Notifier {
LightClientNotifier
}
fn extend_with_set<S>( fn extend_with_set<S>(&self, handler: &mut MetaIoHandler<Metadata, S>, apis: &HashSet<Api>)
&self, where
handler: &mut MetaIoHandler<Metadata, S>, S: core::Middleware<Metadata>,
apis: &HashSet<Api>, {
) where S: core::Middleware<Metadata> {
self.extend_api(handler, apis, false) self.extend_api(handler, apis, false)
} }
} }
@ -639,7 +709,10 @@ impl ApiSet {
Api::Whisper, Api::Whisper,
Api::WhisperPubSub, Api::WhisperPubSub,
Api::Private, Api::Private,
].into_iter().cloned().collect(); ]
.into_iter()
.cloned()
.collect();
match *self { match *self {
ApiSet::List(ref apis) => apis.clone(), ApiSet::List(ref apis) => apis.clone(),
@ -647,13 +720,13 @@ impl ApiSet {
public_list.insert(Api::Traces); public_list.insert(Api::Traces);
public_list.insert(Api::ParityPubSub); public_list.insert(Api::ParityPubSub);
public_list public_list
}, }
ApiSet::IpcContext => { ApiSet::IpcContext => {
public_list.insert(Api::Traces); public_list.insert(Api::Traces);
public_list.insert(Api::ParityPubSub); public_list.insert(Api::ParityPubSub);
public_list.insert(Api::ParityAccounts); public_list.insert(Api::ParityAccounts);
public_list public_list
}, }
ApiSet::SafeContext => { ApiSet::SafeContext => {
public_list.insert(Api::Debug); public_list.insert(Api::Debug);
public_list.insert(Api::Traces); public_list.insert(Api::Traces);
@ -663,7 +736,7 @@ impl ApiSet {
public_list.insert(Api::Signer); public_list.insert(Api::Signer);
public_list.insert(Api::SecretStore); public_list.insert(Api::SecretStore);
public_list public_list
}, }
ApiSet::All => { ApiSet::All => {
public_list.insert(Api::Debug); public_list.insert(Api::Debug);
public_list.insert(Api::Traces); public_list.insert(Api::Traces);
@ -674,14 +747,17 @@ impl ApiSet {
public_list.insert(Api::Personal); public_list.insert(Api::Personal);
public_list.insert(Api::SecretStore); public_list.insert(Api::SecretStore);
public_list public_list
}, }
ApiSet::PubSub => [ ApiSet::PubSub => [
Api::Eth, Api::Eth,
Api::Parity, Api::Parity,
Api::ParityAccounts, Api::ParityAccounts,
Api::ParitySet, Api::ParitySet,
Api::Traces, Api::Traces,
].into_iter().cloned().collect() ]
.into_iter()
.cloned()
.collect(),
} }
} }
} }
@ -718,15 +794,29 @@ mod test {
#[test] #[test]
fn test_api_set_parsing() { fn test_api_set_parsing() {
assert_eq!(ApiSet::List(vec![Api::Web3, Api::Eth].into_iter().collect()), "web3,eth".parse().unwrap()); assert_eq!(
ApiSet::List(vec![Api::Web3, Api::Eth].into_iter().collect()),
"web3,eth".parse().unwrap()
);
} }
#[test] #[test]
fn test_api_set_unsafe_context() { fn test_api_set_unsafe_context() {
let expected = vec![ let expected = vec![
// make sure this list contains only SAFE methods // make sure this list contains only SAFE methods
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, Api::Private, Api::Web3,
].into_iter().collect(); Api::Net,
Api::Eth,
Api::EthPubSub,
Api::Parity,
Api::ParityPubSub,
Api::Traces,
Api::Rpc,
Api::Whisper,
Api::WhisperPubSub,
Api::Private,
].into_iter()
.collect();
assert_eq!(ApiSet::UnsafeContext.list_apis(), expected); assert_eq!(ApiSet::UnsafeContext.list_apis(), expected);
} }
@ -734,10 +824,21 @@ mod test {
fn test_api_set_ipc_context() { fn test_api_set_ipc_context() {
let expected = vec![ let expected = vec![
// safe // safe
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, Api::Private, Api::Web3,
Api::Net,
Api::Eth,
Api::EthPubSub,
Api::Parity,
Api::ParityPubSub,
Api::Traces,
Api::Rpc,
Api::Whisper,
Api::WhisperPubSub,
Api::Private,
// semi-safe // semi-safe
Api::ParityAccounts Api::ParityAccounts,
].into_iter().collect(); ].into_iter()
.collect();
assert_eq!(ApiSet::IpcContext.list_apis(), expected); assert_eq!(ApiSet::IpcContext.list_apis(), expected);
} }
@ -745,41 +846,106 @@ mod test {
fn test_api_set_safe_context() { fn test_api_set_safe_context() {
let expected = vec![ let expected = vec![
// safe // safe
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub, Api::Private, Api::Web3,
Api::Net,
Api::Eth,
Api::EthPubSub,
Api::Parity,
Api::ParityPubSub,
Api::Traces,
Api::Rpc,
Api::SecretStore,
Api::Whisper,
Api::WhisperPubSub,
Api::Private,
// semi-safe // semi-safe
Api::ParityAccounts, Api::ParityAccounts,
// Unsafe // Unsafe
Api::ParitySet, Api::Signer, Api::Debug Api::ParitySet,
].into_iter().collect(); Api::Signer,
Api::Debug,
].into_iter()
.collect();
assert_eq!(ApiSet::SafeContext.list_apis(), expected); assert_eq!(ApiSet::SafeContext.list_apis(), expected);
} }
#[test] #[test]
fn test_all_apis() { fn test_all_apis() {
assert_eq!("all".parse::<ApiSet>().unwrap(), ApiSet::List(vec![ assert_eq!(
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub, "all".parse::<ApiSet>().unwrap(),
Api::ParityAccounts, ApiSet::List(
Api::ParitySet, Api::Signer, vec![
Api::Personal, Api::Web3,
Api::Private, Api::Net,
Api::Debug, Api::Eth,
].into_iter().collect())); Api::EthPubSub,
Api::Parity,
Api::ParityPubSub,
Api::Traces,
Api::Rpc,
Api::SecretStore,
Api::Whisper,
Api::WhisperPubSub,
Api::ParityAccounts,
Api::ParitySet,
Api::Signer,
Api::Personal,
Api::Private,
Api::Debug,
].into_iter()
.collect()
)
);
} }
#[test] #[test]
fn test_all_without_personal_apis() { fn test_all_without_personal_apis() {
assert_eq!("personal,all,-personal".parse::<ApiSet>().unwrap(), ApiSet::List(vec![ assert_eq!(
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::SecretStore, Api::Whisper, Api::WhisperPubSub, "personal,all,-personal".parse::<ApiSet>().unwrap(),
Api::ParityAccounts, ApiSet::List(
Api::ParitySet, Api::Signer, vec![
Api::Private, Api::Debug, Api::Web3,
].into_iter().collect())); Api::Net,
Api::Eth,
Api::EthPubSub,
Api::Parity,
Api::ParityPubSub,
Api::Traces,
Api::Rpc,
Api::SecretStore,
Api::Whisper,
Api::WhisperPubSub,
Api::ParityAccounts,
Api::ParitySet,
Api::Signer,
Api::Private,
Api::Debug,
].into_iter()
.collect()
)
);
} }
#[test] #[test]
fn test_safe_parsing() { fn test_safe_parsing() {
assert_eq!("safe".parse::<ApiSet>().unwrap(), ApiSet::List(vec![ assert_eq!(
Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity, Api::ParityPubSub, Api::Traces, Api::Rpc, Api::Whisper, Api::WhisperPubSub, Api::Private, "safe".parse::<ApiSet>().unwrap(),
].into_iter().collect())); ApiSet::List(
vec![
Api::Web3,
Api::Net,
Api::Eth,
Api::EthPubSub,
Api::Parity,
Api::ParityPubSub,
Api::Traces,
Api::Rpc,
Api::Whisper,
Api::WhisperPubSub,
Api::Private,
].into_iter()
.collect()
)
);
} }
} }

View File

@ -127,6 +127,7 @@ pub struct RunCmd {
pub stratum: Option<stratum::Options>, pub stratum: Option<stratum::Options>,
pub snapshot_conf: SnapshotConfiguration, pub snapshot_conf: SnapshotConfiguration,
pub check_seal: bool, pub check_seal: bool,
pub allow_missing_blocks: bool,
pub download_old_blocks: bool, pub download_old_blocks: bool,
pub verifier_settings: VerifierSettings, pub verifier_settings: VerifierSettings,
pub serve_light: bool, pub serve_light: bool,
@ -717,6 +718,7 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
private_tx_service: Some(private_tx_service.clone()), private_tx_service: Some(private_tx_service.clone()),
gas_price_percentile: cmd.gas_price_percentile, gas_price_percentile: cmd.gas_price_percentile,
poll_lifetime: cmd.poll_lifetime, poll_lifetime: cmd.poll_lifetime,
allow_missing_blocks: cmd.allow_missing_blocks,
}); });
let dependencies = rpc::Dependencies { let dependencies = rpc::Dependencies {

View File

@ -18,15 +18,18 @@
use std::fmt; use std::fmt;
use ethcore::account_provider::{SignError as AccountError}; use ethcore::account_provider::SignError as AccountError;
use ethcore::error::{Error as EthcoreError, ErrorKind, CallError}; use ethcore::error::{Error as EthcoreError, ErrorKind, CallError};
use ethcore::client::BlockId; use ethcore::client::BlockId;
use jsonrpc_core::{futures, Error, ErrorCode, Value}; use jsonrpc_core::{futures, Result as RpcResult, Error, ErrorCode, Value};
use rlp::DecoderError; use rlp::DecoderError;
use transaction::Error as TransactionError; use transaction::Error as TransactionError;
use ethcore_private_tx::Error as PrivateTransactionError; use ethcore_private_tx::Error as PrivateTransactionError;
use vm::Error as VMError; use vm::Error as VMError;
use light::on_demand::error::{Error as OnDemandError, ErrorKind as OnDemandErrorKind}; use light::on_demand::error::{Error as OnDemandError, ErrorKind as OnDemandErrorKind};
use ethcore::client::BlockChainClient;
use ethcore::blockchain_info::BlockChainInfo;
use v1::types::BlockNumber;
mod codes { mod codes {
// NOTE [ToDr] Codes from [-32099, -32000] // NOTE [ToDr] Codes from [-32099, -32000]
@ -208,6 +211,60 @@ pub fn cannot_submit_work(err: EthcoreError) -> Error {
} }
} }
pub fn unavailable_block() -> Error {
Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "Ancient block sync is still in progress".into(),
data: None,
}
}
pub fn check_block_number_existence<'a, T, C>(
client: &'a C,
num: BlockNumber,
allow_missing_blocks: bool,
) ->
impl Fn(Option<T>) -> RpcResult<Option<T>> + 'a
where C: BlockChainClient,
{
move |response| {
if response.is_none() {
if let BlockNumber::Num(block_number) = num {
// tried to fetch block number and got nothing even though the block number is
// less than the latest block number
if block_number < client.chain_info().best_block_number && !allow_missing_blocks {
return Err(unavailable_block());
}
}
}
Ok(response)
}
}
pub fn check_block_gap<'a, T, C>(
client: &'a C,
allow_missing_blocks: bool,
) -> impl Fn(Option<T>) -> RpcResult<Option<T>> + 'a
where C: BlockChainClient,
{
move |response| {
if response.is_none() && !allow_missing_blocks {
let BlockChainInfo { ancient_block_hash, .. } = client.chain_info();
// block information was requested, but unfortunately we couldn't find it and there
// are gaps in the database ethcore/src/blockchain/blockchain.rs
if ancient_block_hash.is_some() {
return Err(Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
message: "Block information is incomplete while ancient block sync is still in progress, before \
it's finished we can't determine the existence of requested item.".into(),
data: None,
})
}
}
Ok(response)
}
}
pub fn not_enough_data() -> Error { pub fn not_enough_data() -> Error {
Error { Error {
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
@ -328,22 +385,22 @@ pub fn transaction_message(error: &TransactionError) -> String {
Old => "Transaction nonce is too low. Try incrementing the nonce.".into(), Old => "Transaction nonce is too low. Try incrementing the nonce.".into(),
TooCheapToReplace => { TooCheapToReplace => {
"Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce.".into() "Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce.".into()
}, }
LimitReached => { LimitReached => {
"There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into() "There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into()
}, }
InsufficientGas { minimal, got } => { InsufficientGas { minimal, got } => {
format!("Transaction gas is too low. There is not enough gas to cover minimal cost of the transaction (minimal: {}, got: {}). Try increasing supplied gas.", minimal, got) format!("Transaction gas is too low. There is not enough gas to cover minimal cost of the transaction (minimal: {}, got: {}). Try increasing supplied gas.", minimal, got)
}, }
InsufficientGasPrice { minimal, got } => { InsufficientGasPrice { minimal, got } => {
format!("Transaction gas price is too low. It does not satisfy your node's minimal gas price (minimal: {}, got: {}). Try increasing the gas price.", minimal, got) format!("Transaction gas price is too low. It does not satisfy your node's minimal gas price (minimal: {}, got: {}). Try increasing the gas price.", minimal, got)
}, }
InsufficientBalance { balance, cost } => { InsufficientBalance { balance, cost } => {
format!("Insufficient funds. The account you tried to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance) format!("Insufficient funds. The account you tried to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
}, }
GasLimitExceeded { limit, got } => { GasLimitExceeded { limit, got } => {
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got) format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
}, }
InvalidSignature(ref sig) => format!("Invalid signature: {}", sig), InvalidSignature(ref sig) => format!("Invalid signature: {}", sig),
InvalidChainId => "Invalid chain id.".into(), InvalidChainId => "Invalid chain id.".into(),
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(), InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
@ -382,7 +439,6 @@ pub fn decode<T: Into<EthcoreError>>(error: T) -> Error {
message: "decoding error".into(), message: "decoding error".into(),
data: None, data: None,
} }
} }
} }

View File

@ -65,6 +65,9 @@ pub struct EthClientOptions {
pub send_block_number_in_get_work: bool, pub send_block_number_in_get_work: bool,
/// Gas Price Percentile used as default gas price. /// Gas Price Percentile used as default gas price.
pub gas_price_percentile: usize, pub gas_price_percentile: usize,
/// Return 'null' instead of an error if ancient block sync is still in
/// progress and the block information requested could not be found.
pub allow_missing_blocks: bool,
/// Enable Experimental RPC-Calls /// Enable Experimental RPC-Calls
pub allow_experimental_rpcs: bool, pub allow_experimental_rpcs: bool,
} }
@ -86,6 +89,7 @@ impl Default for EthClientOptions {
allow_pending_receipt_query: true, allow_pending_receipt_query: true,
send_block_number_in_get_work: true, send_block_number_in_get_work: true,
gas_price_percentile: 50, gas_price_percentile: 50,
allow_missing_blocks: false,
allow_experimental_rpcs: false, allow_experimental_rpcs: false,
} }
} }
@ -645,30 +649,51 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
} }
fn block_transaction_count_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<RpcU256>> { fn block_transaction_count_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<RpcU256>> {
Box::new(future::ok(self.client.block(BlockId::Hash(hash.into())) let trx_count = self.client.block(BlockId::Hash(hash.into()))
.map(|block| block.transactions_count().into()))) .map(|block| block.transactions_count().into());
let result = Ok(trx_count)
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> { fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
Box::new(future::ok(match num { Box::new(future::done(match num {
BlockNumber::Pending => BlockNumber::Pending =>
Some(self.miner.pending_transaction_hashes(&*self.client).len().into()), Ok(Some(self.miner.pending_transaction_hashes(&*self.client).len().into())),
_ => _ => {
self.client.block(block_number_to_id(num)).map(|block| block.transactions_count().into()) let trx_count = self.client.block(block_number_to_id(num.clone()))
.map(|block| block.transactions_count().into());
Ok(trx_count)
.and_then(errors::check_block_number_existence(
&*self.client,
num,
self.options.allow_missing_blocks
))
}
})) }))
} }
fn block_uncles_count_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<RpcU256>> { fn block_uncles_count_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<RpcU256>> {
Box::new(future::ok(self.client.block(BlockId::Hash(hash.into())) let uncle_count = self.client.block(BlockId::Hash(hash.into()))
.map(|block| block.uncles_count().into()))) .map(|block| block.uncles_count().into());
let result = Ok(uncle_count)
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> { fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
Box::new(future::ok(match num { Box::new(future::done(match num {
BlockNumber::Pending => Some(0.into()), BlockNumber::Pending => Ok(Some(0.into())),
_ => self.client.block(block_number_to_id(num)) _ => {
.map(|block| block.uncles_count().into() let uncles_count = self.client.block(block_number_to_id(num.clone()))
), .map(|block| block.uncles_count().into());
Ok(uncles_count)
.and_then(errors::check_block_number_existence(
&*self.client,
num,
self.options.allow_missing_blocks
))
}
})) }))
} }
@ -687,11 +712,15 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
} }
fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> BoxFuture<Option<RichBlock>> { fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.rich_block(BlockId::Hash(hash.into()).into(), include_txs))) let result = self.rich_block(BlockId::Hash(hash.into()).into(), include_txs)
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> { fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.rich_block(num.into(), include_txs))) let result = self.rich_block(num.clone().into(), include_txs).and_then(
errors::check_block_number_existence(&*self.client, num, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<Transaction>> { fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<Transaction>> {
@ -700,13 +729,16 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
self.miner.transaction(&hash) self.miner.transaction(&hash)
.map(|t| Transaction::from_pending(t.pending().clone())) .map(|t| Transaction::from_pending(t.pending().clone()))
}); });
let result = Ok(tx).and_then(
Box::new(future::ok(tx)) errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn transaction_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<Transaction>> { fn transaction_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<Transaction>> {
let id = PendingTransactionId::Location(PendingOrBlock::Block(BlockId::Hash(hash.into())), index.value()); let id = PendingTransactionId::Location(PendingOrBlock::Block(BlockId::Hash(hash.into())), index.value());
Box::new(future::done(self.transaction(id))) let result = self.transaction(id).and_then(
errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<Transaction>> { fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<Transaction>> {
@ -718,7 +750,9 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
}; };
let transaction_id = PendingTransactionId::Location(block_id, index.value()); let transaction_id = PendingTransactionId::Location(block_id, index.value());
Box::new(future::done(self.transaction(transaction_id))) let result = self.transaction(transaction_id).and_then(
errors::check_block_number_existence(&*self.client, num, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture<Option<Receipt>> { fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture<Option<Receipt>> {
@ -732,14 +766,17 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
} }
let receipt = self.client.transaction_receipt(TransactionId::Hash(hash)); let receipt = self.client.transaction_receipt(TransactionId::Hash(hash));
Box::new(future::ok(receipt.map(Into::into))) let result = Ok(receipt.map(Into::into))
.and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<RichBlock>> { fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.uncle(PendingUncleId { let result = self.uncle(PendingUncleId {
id: PendingOrBlock::Block(BlockId::Hash(hash.into())), id: PendingOrBlock::Block(BlockId::Hash(hash.into())),
position: index.value() position: index.value()
}))) }).and_then(errors::check_block_gap(&*self.client, self.options.allow_missing_blocks));
Box::new(future::done(result))
} }
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<RichBlock>> { fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<RichBlock>> {
@ -751,7 +788,14 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
BlockNumber::Pending => PendingUncleId { id: PendingOrBlock::Pending, position: index.value() }, BlockNumber::Pending => PendingUncleId { id: PendingOrBlock::Pending, position: index.value() },
}; };
Box::new(future::done(self.uncle(id))) let result = self.uncle(id)
.and_then(errors::check_block_number_existence(
&*self.client,
num,
self.options.allow_missing_blocks
));
Box::new(future::done(result))
} }
fn compilers(&self) -> Result<Vec<String>> { fn compilers(&self) -> Result<Vec<String>> {

View File

@ -146,6 +146,7 @@ impl EthTester {
send_block_number_in_get_work: true, send_block_number_in_get_work: true,
gas_price_percentile: 50, gas_price_percentile: 50,
allow_experimental_rpcs: true, allow_experimental_rpcs: true,
allow_missing_blocks: false
}, },
); );