diff --git a/ethcore/src/client/bad_blocks.rs b/ethcore/src/client/bad_blocks.rs
new file mode 100644
index 00000000000..e003066721d
--- /dev/null
+++ b/ethcore/src/client/bad_blocks.rs
@@ -0,0 +1,81 @@
+// Copyright 2015-2018 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 .
+
+//! Stores recently seen bad blocks.
+
+use bytes::{Bytes, ToPretty};
+use ethereum_types::H256;
+use itertools::Itertools;
+use memory_cache::MemoryLruCache;
+use parking_lot::RwLock;
+use verification::queue::kind::blocks::Unverified;
+
+/// Recently seen bad blocks.
+pub struct BadBlocks {
+ last_blocks: RwLock>,
+}
+
+impl Default for BadBlocks {
+ fn default() -> Self {
+ BadBlocks {
+ last_blocks: RwLock::new(MemoryLruCache::new(8 * 1024 * 1024)),
+ }
+ }
+}
+
+impl BadBlocks {
+ /// Reports given RLP as invalid block.
+ pub fn report(&self, raw: Bytes, message: String) {
+ match Unverified::from_rlp(raw) {
+ Ok(unverified) => {
+ error!(
+ target: "client",
+ "\nBad block detected: {}\nRLP: {}\nHeader: {:?}\nUncles: {}\nTransactions:{}\n",
+ message,
+ unverified.bytes.to_hex(),
+ unverified.header,
+ unverified.uncles
+ .iter()
+ .enumerate()
+ .map(|(index, uncle)| format!("[Uncle {}] {:?}", index, uncle))
+ .join("\n"),
+ unverified.transactions
+ .iter()
+ .enumerate()
+ .map(|(index, tx)| format!("[Tx {}] {:?}", index, tx))
+ .join("\n"),
+ );
+ self.last_blocks.write().insert(unverified.header.hash(), (unverified, message));
+ },
+ Err(err) => {
+ error!(target: "client", "Bad undecodable block detected: {}\n{:?}", message, err);
+ },
+ }
+ }
+
+ /// Returns a list of recently detected bad blocks with error descriptions.
+ pub fn bad_blocks(&self) -> Vec<(Unverified, String)> {
+ self.last_blocks.read()
+ .backstore()
+ .iter()
+ .map(|(_k, (unverified, message))| (
+ Unverified::from_rlp(unverified.bytes.clone())
+ .expect("Bytes coming from UnverifiedBlock so decodable; qed"),
+ message.clone(),
+ ))
+ .collect()
+ }
+}
diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs
index e8707d6eb7c..0cff55b0065 100644
--- a/ethcore/src/client/client.rs
+++ b/ethcore/src/client/client.rs
@@ -39,14 +39,15 @@ use client::{
RegistryInfo, ReopenBlock, PrepareOpenBlock, ScheduleInfo, ImportSealedBlock,
BroadcastProposalBlock, ImportBlock, StateOrBlock, StateInfo, StateClient, Call,
AccountData, BlockChain as BlockChainTrait, BlockProducer, SealedBlockImporter,
- ClientIoMessage
+ ClientIoMessage,
};
use client::{
BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
TraceFilter, CallAnalytics, BlockImportError, Mode,
ChainNotify, ChainRoute, PruningInfo, ProvingBlockChainClient, EngineInfo, ChainMessageType,
- IoClient,
+ IoClient, BadBlocks,
};
+use client::bad_blocks;
use encoded;
use engines::{EthEngine, EpochTransition, ForkChoice};
use error::{
@@ -163,6 +164,9 @@ struct Importer {
/// Ethereum engine to be used during import
pub engine: Arc,
+
+ /// A lru cache of recently detected bad blocks
+ pub bad_blocks: bad_blocks::BadBlocks,
}
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
@@ -254,6 +258,7 @@ impl Importer {
miner,
ancient_verifier: AncientVerifier::new(engine.clone()),
engine,
+ bad_blocks: Default::default(),
})
}
@@ -291,22 +296,27 @@ impl Importer {
continue;
}
- if let Ok(closed_block) = self.check_and_lock_block(block, client) {
- if self.engine.is_proposal(&header) {
- self.block_queue.mark_as_good(&[hash]);
- proposed_blocks.push(bytes);
- } else {
- imported_blocks.push(hash);
+ let raw = block.bytes.clone();
+ match self.check_and_lock_block(block, client) {
+ Ok(closed_block) => {
+ if self.engine.is_proposal(&header) {
+ self.block_queue.mark_as_good(&[hash]);
+ proposed_blocks.push(bytes);
+ } else {
+ imported_blocks.push(hash);
- let transactions_len = closed_block.transactions().len();
+ let transactions_len = closed_block.transactions().len();
- let route = self.commit_block(closed_block, &header, encoded::Block::new(bytes), client);
- import_results.push(route);
+ let route = self.commit_block(closed_block, &header, encoded::Block::new(bytes), client);
+ import_results.push(route);
- client.report.write().accrue_block(&header, transactions_len);
- }
- } else {
- invalid_blocks.insert(header.hash());
+ client.report.write().accrue_block(&header, transactions_len);
+ }
+ },
+ Err(err) => {
+ self.bad_blocks.report(raw, format!("{:?}", err));
+ invalid_blocks.insert(header.hash());
+ },
}
}
@@ -1390,12 +1400,22 @@ impl ImportBlock for Client {
if self.chain.read().is_known(&unverified.hash()) {
bail!(BlockImportErrorKind::Import(ImportErrorKind::AlreadyInChain));
}
+
let status = self.block_status(BlockId::Hash(unverified.parent_hash()));
if status == BlockStatus::Unknown || status == BlockStatus::Pending {
bail!(BlockImportErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash())));
}
- Ok(self.importer.block_queue.import(unverified)?)
+ let raw = unverified.bytes.clone();
+ match self.importer.block_queue.import(unverified).map_err(Into::into) {
+ Ok(res) => Ok(res),
+ // we only care about block errors (not import errors)
+ Err(BlockImportError(BlockImportErrorKind::Block(err), _))=> {
+ self.importer.bad_blocks.report(raw, format!("{:?}", err));
+ bail!(BlockImportErrorKind::Block(err))
+ },
+ Err(e) => Err(e),
+ }
}
}
@@ -1532,6 +1552,12 @@ impl EngineInfo for Client {
}
}
+impl BadBlocks for Client {
+ fn bad_blocks(&self) -> Vec<(Unverified, String)> {
+ self.importer.bad_blocks.bad_blocks()
+ }
+}
+
impl BlockChainClient for Client {
fn replay(&self, id: TransactionId, analytics: CallAnalytics) -> Result {
let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs
index ffd303c1277..964a56f53c3 100644
--- a/ethcore/src/client/mod.rs
+++ b/ethcore/src/client/mod.rs
@@ -17,6 +17,7 @@
//! Blockchain database client.
mod ancient_import;
+mod bad_blocks;
mod client;
mod config;
#[cfg(any(test, feature = "test-helpers"))]
@@ -36,7 +37,7 @@ pub use self::test_client::{TestBlockChainClient, EachBlockWith};
pub use self::chain_notify::{ChainNotify, ChainRoute, ChainRouteType, ChainMessageType};
pub use self::traits::{
Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock,
- StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter
+ StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, BadBlocks,
};
pub use state::StateInfo;
pub use self::traits::{BlockChainClient, EngineClient, ProvingBlockChainClient, IoClient};
diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs
index 9981f8d2cb7..54cadc286ee 100644
--- a/ethcore/src/client/test_client.rs
+++ b/ethcore/src/client/test_client.rs
@@ -39,7 +39,8 @@ use client::{
PrepareOpenBlock, BlockChainClient, BlockChainInfo, BlockStatus, BlockId, Mode,
TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError,
ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock,
- Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, IoClient
+ Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter, IoClient,
+ BadBlocks,
};
use db::{NUM_COLUMNS, COL_STATE};
use header::{Header as BlockHeader, BlockNumber};
@@ -615,6 +616,19 @@ impl EngineInfo for TestBlockChainClient {
}
}
+impl BadBlocks for TestBlockChainClient {
+ fn bad_blocks(&self) -> Vec<(Unverified, String)> {
+ vec![
+ (Unverified {
+ header: Default::default(),
+ transactions: vec![],
+ uncles: vec![],
+ bytes: vec![1, 2, 3],
+ }, "Invalid block".into())
+ ]
+ }
+}
+
impl BlockChainClient for TestBlockChainClient {
fn replay(&self, _id: TransactionId, _analytics: CallAnalytics) -> Result {
self.execution_result.read().clone().unwrap()
diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs
index 189ca67f48b..8ac8111b31c 100644
--- a/ethcore/src/client/traits.rs
+++ b/ethcore/src/client/traits.rs
@@ -211,9 +211,15 @@ pub trait IoClient: Sync + Send {
fn queue_consensus_message(&self, message: Bytes);
}
+/// Provides recently seen bad blocks.
+pub trait BadBlocks {
+ /// Returns a list of blocks that were recently not imported because they were invalid.
+ fn bad_blocks(&self) -> Vec<(Unverified, String)>;
+}
+
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock
-+ IoClient {
++ IoClient + BadBlocks {
/// Look up the block number for the given block ID.
fn block_number(&self, id: BlockId) -> Option;
diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs
index 5ca5feb6797..f00c797942c 100644
--- a/parity/cli/mod.rs
+++ b/parity/cli/mod.rs
@@ -477,7 +477,7 @@ usage! {
ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,private,parity_pubsub,traces,rpc,shh,shh_pubsub", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")),
"--jsonrpc-apis=[APIS]",
- "Specify the APIs available through the HTTP JSON-RPC interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub",
+ "Specify the APIs available through the HTTP JSON-RPC interface using a comma-delimited list of API names. Possible names are: all, safe, debug, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore, shh, shh_pubsub. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc, shh, shh_pubsub",
ARG arg_jsonrpc_hosts: (String) = "none", or |c: &Config| c.rpc.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")),
"--jsonrpc-hosts=[HOSTS]",
diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs
index 7ecbaee5f5f..2d7b2476afa 100644
--- a/parity/rpc_apis.rs
+++ b/parity/rpc_apis.rs
@@ -58,18 +58,10 @@ pub enum Api {
Signer,
/// Parity - Custom extensions (Safe)
Parity,
- /// Parity PubSub - Generic Publish-Subscriber (Safety depends on other APIs exposed).
- ParityPubSub,
- /// Parity Accounts extensions (UNSAFE: Passwords, Side Effects (new account))
- ParityAccounts,
- /// Parity - Set methods (UNSAFE: Side Effects affecting node operation)
- ParitySet,
/// Traces (Safe)
Traces,
/// Rpc (Safe)
Rpc,
- /// SecretStore (UNSAFE: arbitrary hash signing)
- SecretStore,
/// Private transaction manager (Safe)
Private,
/// Whisper (Safe)
@@ -78,6 +70,17 @@ pub enum Api {
Whisper,
/// Whisper Pub-Sub (Safe but same concerns as above).
WhisperPubSub,
+ /// Parity PubSub - Generic Publish-Subscriber (Safety depends on other APIs exposed).
+ ParityPubSub,
+ /// Parity Accounts extensions (UNSAFE: Passwords, Side Effects (new account))
+ ParityAccounts,
+ /// Parity - Set methods (UNSAFE: Side Effects affecting node operation)
+ ParitySet,
+ /// SecretStore (UNSAFE: arbitrary hash signing)
+ SecretStore,
+ /// Geth-compatible (best-effort) debug API (Potentially UNSAFE)
+ /// NOTE We don't aim to support all methods, only the ones that are useful.
+ Debug,
}
impl FromStr for Api {
@@ -87,22 +90,23 @@ impl FromStr for Api {
use self::Api::*;
match s {
- "web3" => Ok(Web3),
- "net" => Ok(Net),
+ "debug" => Ok(Debug),
"eth" => Ok(Eth),
- "pubsub" => Ok(EthPubSub),
- "personal" => Ok(Personal),
- "signer" => Ok(Signer),
+ "net" => Ok(Net),
"parity" => Ok(Parity),
- "parity_pubsub" => Ok(ParityPubSub),
"parity_accounts" => Ok(ParityAccounts),
+ "parity_pubsub" => Ok(ParityPubSub),
"parity_set" => Ok(ParitySet),
- "traces" => Ok(Traces),
+ "personal" => Ok(Personal),
+ "private" => Ok(Private),
+ "pubsub" => Ok(EthPubSub),
"rpc" => Ok(Rpc),
"secretstore" => Ok(SecretStore),
- "private" => Ok(Private),
"shh" => Ok(Whisper),
"shh_pubsub" => Ok(WhisperPubSub),
+ "signer" => Ok(Signer),
+ "traces" => Ok(Traces),
+ "web3" => Ok(Web3),
api => Err(format!("Unknown api: {}", api))
}
}
@@ -171,20 +175,21 @@ fn to_modules(apis: &HashSet) -> BTreeMap {
let mut modules = BTreeMap::new();
for api in apis {
let (name, version) = match *api {
- Api::Web3 => ("web3", "1.0"),
- Api::Net => ("net", "1.0"),
+ Api::Debug => ("debug", "1.0"),
Api::Eth => ("eth", "1.0"),
Api::EthPubSub => ("pubsub", "1.0"),
- Api::Personal => ("personal", "1.0"),
- Api::Signer => ("signer", "1.0"),
+ Api::Net => ("net", "1.0"),
Api::Parity => ("parity", "1.0"),
Api::ParityAccounts => ("parity_accounts", "1.0"),
Api::ParityPubSub => ("parity_pubsub", "1.0"),
Api::ParitySet => ("parity_set", "1.0"),
- Api::Traces => ("traces", "1.0"),
+ Api::Personal => ("personal", "1.0"),
+ Api::Private => ("private", "1.0"),
Api::Rpc => ("rpc", "1.0"),
Api::SecretStore => ("secretstore", "1.0"),
- Api::Private => ("private", "1.0"),
+ Api::Signer => ("signer", "1.0"),
+ Api::Traces => ("traces", "1.0"),
+ Api::Web3 => ("web3", "1.0"),
Api::Whisper => ("shh", "1.0"),
Api::WhisperPubSub => ("shh_pubsub", "1.0"),
};
@@ -265,6 +270,9 @@ impl FullDependencies {
);
for api in apis {
match *api {
+ Api::Debug => {
+ handler.extend_with(DebugClient::new(self.client.clone()).to_delegate());
+ },
Api::Web3 => {
handler.extend_with(Web3Client::new().to_delegate());
},
@@ -481,6 +489,9 @@ impl LightDependencies {
for api in apis {
match *api {
+ Api::Debug => {
+ warn!(target: "rpc", "Debug API is not available in light client mode.")
+ },
Api::Web3 => {
handler.extend_with(Web3Client::new().to_delegate());
},
@@ -647,6 +658,7 @@ impl ApiSet {
public_list
},
ApiSet::SafeContext => {
+ public_list.insert(Api::Debug);
public_list.insert(Api::Traces);
public_list.insert(Api::ParityPubSub);
public_list.insert(Api::ParityAccounts);
@@ -656,6 +668,7 @@ impl ApiSet {
public_list
},
ApiSet::All => {
+ public_list.insert(Api::Debug);
public_list.insert(Api::Traces);
public_list.insert(Api::ParityPubSub);
public_list.insert(Api::ParityAccounts);
@@ -682,6 +695,7 @@ mod test {
#[test]
fn test_api_parsing() {
+ assert_eq!(Api::Debug, "debug".parse().unwrap());
assert_eq!(Api::Web3, "web3".parse().unwrap());
assert_eq!(Api::Net, "net".parse().unwrap());
assert_eq!(Api::Eth, "eth".parse().unwrap());
@@ -738,7 +752,7 @@ mod test {
// semi-safe
Api::ParityAccounts,
// Unsafe
- Api::ParitySet, Api::Signer,
+ Api::ParitySet, Api::Signer, Api::Debug
].into_iter().collect();
assert_eq!(ApiSet::SafeContext.list_apis(), expected);
}
@@ -751,6 +765,7 @@ mod test {
Api::ParitySet, Api::Signer,
Api::Personal,
Api::Private,
+ Api::Debug,
].into_iter().collect()));
}
@@ -760,7 +775,7 @@ mod test {
Api::Web3, 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::Private, Api::Debug,
].into_iter().collect()));
}
diff --git a/rpc/src/v1/impls/debug.rs b/rpc/src/v1/impls/debug.rs
new file mode 100644
index 00000000000..60d9dcdc834
--- /dev/null
+++ b/rpc/src/v1/impls/debug.rs
@@ -0,0 +1,96 @@
+// Copyright 2015-2018 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 .
+
+//! Debug APIs RPC implementation
+
+use std::sync::Arc;
+
+use ethcore::client::BlockChainClient;
+use transaction::LocalizedTransaction;
+
+use jsonrpc_core::Result;
+use v1::traits::Debug;
+use v1::types::{Block, Bytes, RichBlock, BlockTransactions, Transaction};
+
+/// Debug rpc implementation.
+pub struct DebugClient {
+ client: Arc,
+}
+
+impl DebugClient {
+ /// Creates new debug client.
+ pub fn new(client: Arc) -> Self {
+ Self {
+ client,
+ }
+ }
+}
+
+impl Debug for DebugClient {
+ fn bad_blocks(&self) -> Result> {
+ fn cast>(t: &T) -> O {
+ (*t).into()
+ }
+
+ Ok(self.client.bad_blocks().into_iter().map(|(block, reason)| {
+ let number = block.header.number();
+ let hash = block.header.hash();
+ RichBlock {
+ inner: Block {
+ hash: Some(hash.into()),
+ size: Some(block.bytes.len().into()),
+ parent_hash: cast(block.header.parent_hash()),
+ uncles_hash: cast(block.header.uncles_hash()),
+ author: cast(block.header.author()),
+ miner: cast(block.header.author()),
+ state_root: cast(block.header.state_root()),
+ receipts_root: cast(block.header.receipts_root()),
+ number: Some(number.into()),
+ gas_used: cast(block.header.gas_used()),
+ gas_limit: cast(block.header.gas_limit()),
+ logs_bloom: Some(cast(block.header.log_bloom())),
+ timestamp: block.header.timestamp().into(),
+ difficulty: cast(block.header.difficulty()),
+ total_difficulty: None,
+ seal_fields: block.header.seal().into_iter().cloned().map(Into::into).collect(),
+ uncles: block.uncles.into_iter().map(|u| u.hash().into()).collect(),
+ transactions: BlockTransactions::Full(block.transactions
+ .into_iter()
+ .enumerate()
+ .map(|(transaction_index, signed)| Transaction::from_localized(LocalizedTransaction {
+ block_number: number.into(),
+ block_hash: hash.into(),
+ transaction_index,
+ signed,
+ cached_sender: None,
+ })).collect()
+ ),
+ transactions_root: cast(block.header.transactions_root()),
+ extra_data: block.header.extra_data().clone().into(),
+ },
+ extra_info: vec![
+ ("reason".to_owned(), reason),
+ ("rlp".to_owned(), serialize(&Bytes(block.bytes))),
+ ("hash".to_owned(), format!("{:#x}", hash)),
+ ].into_iter().collect(),
+ }
+ }).collect())
+ }
+}
+
+fn serialize(t: &T) -> String {
+ ::serde_json::to_string(t).expect("RPC types serialization is non-fallible.")
+}
diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs
index 1349147207d..44bc62883a3 100644
--- a/rpc/src/v1/impls/mod.rs
+++ b/rpc/src/v1/impls/mod.rs
@@ -16,6 +16,7 @@
//! Ethereum rpc interface implementation.
+mod debug;
mod eth;
mod eth_filter;
mod eth_pubsub;
@@ -24,18 +25,19 @@ mod parity;
mod parity_accounts;
mod parity_set;
mod personal;
+mod private;
mod pubsub;
+mod rpc;
+mod secretstore;
mod signer;
mod signing;
mod signing_unsafe;
-mod rpc;
-mod secretstore;
mod traces;
mod web3;
-mod private;
pub mod light;
+pub use self::debug::DebugClient;
pub use self::eth::{EthClient, EthClientOptions};
pub use self::eth_filter::EthFilterClient;
pub use self::eth_pubsub::EthPubSubClient;
@@ -44,12 +46,12 @@ pub use self::parity::ParityClient;
pub use self::parity_accounts::ParityAccountsClient;
pub use self::parity_set::ParitySetClient;
pub use self::personal::PersonalClient;
+pub use self::private::PrivateClient;
pub use self::pubsub::PubSubClient;
+pub use self::rpc::RpcClient;
+pub use self::secretstore::SecretStoreClient;
pub use self::signer::SignerClient;
pub use self::signing::SigningQueueClient;
pub use self::signing_unsafe::SigningUnsafeClient;
pub use self::traces::TracesClient;
pub use self::web3::Web3Client;
-pub use self::rpc::RpcClient;
-pub use self::secretstore::SecretStoreClient;
-pub use self::private::PrivateClient;
diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs
index a0b74aa5aa4..c9700ec4c0f 100644
--- a/rpc/src/v1/mod.rs
+++ b/rpc/src/v1/mod.rs
@@ -41,7 +41,7 @@ pub mod informant;
pub mod metadata;
pub mod traits;
-pub use self::traits::{Web3, Eth, EthFilter, EthPubSub, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, PubSub, Signer, Personal, Traces, Rpc, SecretStore, Private};
+pub use self::traits::{Debug, Eth, EthFilter, EthPubSub, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, Personal, PubSub, Private, Rpc, SecretStore, Signer, Traces, Web3};
pub use self::impls::*;
pub use self::helpers::{NetworkSettings, block_import, dispatch};
pub use self::metadata::Metadata;
diff --git a/rpc/src/v1/tests/mocked/debug.rs b/rpc/src/v1/tests/mocked/debug.rs
new file mode 100644
index 00000000000..987cb5e1562
--- /dev/null
+++ b/rpc/src/v1/tests/mocked/debug.rs
@@ -0,0 +1,37 @@
+// Copyright 2015-2018 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 .
+
+use std::sync::Arc;
+
+use ethcore::client::TestBlockChainClient;
+
+use jsonrpc_core::IoHandler;
+use v1::{Debug, DebugClient};
+
+fn io() -> IoHandler {
+ let client = Arc::new(TestBlockChainClient::new());
+
+ let mut io = IoHandler::new();
+ io.extend_with(DebugClient::new(client).to_delegate());
+ io
+}
+
+#[test]
+fn rpc_debug_get_bad_blocks() {
+ let request = r#"{"jsonrpc": "2.0", "method": "debug_getBadBlocks", "params": [], "id": 1}"#;
+ let response = "{\"jsonrpc\":\"2.0\",\"result\":[{\"author\":\"0x0000000000000000000000000000000000000000\",\"difficulty\":\"0x0\",\"extraData\":\"0x\",\"gasLimit\":\"0x0\",\"gasUsed\":\"0x0\",\"hash\":\"27bfb37e507ce90da141307204b1c6ba24194380613590ac50ca4b1d7198ff65\",\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"miner\":\"0x0000000000000000000000000000000000000000\",\"number\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"reason\":\"Invalid block\",\"receiptsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"rlp\":\"\\\"0x010203\\\"\",\"sealFields\":[],\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x3\",\"stateRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"timestamp\":\"0x0\",\"totalDifficulty\":null,\"transactions\":[],\"transactionsRoot\":\"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",\"uncles\":[]}],\"id\":1}";
+ assert_eq!(io().handle_request_sync(request), Some(response.to_owned()));
+}
diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs
index a3de3b3b71b..9eabe2aa217 100644
--- a/rpc/src/v1/tests/mocked/mod.rs
+++ b/rpc/src/v1/tests/mocked/mod.rs
@@ -17,6 +17,7 @@
//! RPC mocked tests. Most of these test that the RPC server is serializing and forwarding
//! method calls properly.
+mod debug;
mod eth;
mod eth_pubsub;
mod manage_network;
diff --git a/rpc/src/v1/traits/debug.rs b/rpc/src/v1/traits/debug.rs
new file mode 100644
index 00000000000..0fedf0a5a8e
--- /dev/null
+++ b/rpc/src/v1/traits/debug.rs
@@ -0,0 +1,30 @@
+// Copyright 2015-2018 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 .
+
+//! Debug RPC interface.
+
+use jsonrpc_core::Result;
+
+use v1::types::RichBlock;
+
+build_rpc_trait! {
+ /// Debug RPC interface.
+ pub trait Debug {
+ /// Returns recently seen bad blocks.
+ #[rpc(name = "debug_getBadBlocks")]
+ fn bad_blocks(&self) -> Result>;
+ }
+}
diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs
index 62edac8ed66..7c4f617e15c 100644
--- a/rpc/src/v1/traits/mod.rs
+++ b/rpc/src/v1/traits/mod.rs
@@ -16,7 +16,7 @@
//! Ethereum rpc interfaces.
-pub mod web3;
+pub mod debug;
pub mod eth;
pub mod eth_pubsub;
pub mod eth_signing;
@@ -26,14 +26,15 @@ pub mod parity_accounts;
pub mod parity_set;
pub mod parity_signing;
pub mod personal;
+pub mod private;
pub mod pubsub;
-pub mod signer;
-pub mod traces;
pub mod rpc;
pub mod secretstore;
-pub mod private;
+pub mod signer;
+pub mod traces;
+pub mod web3;
-pub use self::web3::Web3;
+pub use self::debug::Debug;
pub use self::eth::{Eth, EthFilter};
pub use self::eth_pubsub::EthPubSub;
pub use self::eth_signing::EthSigning;
@@ -43,9 +44,10 @@ pub use self::parity_accounts::ParityAccounts;
pub use self::parity_set::ParitySet;
pub use self::parity_signing::ParitySigning;
pub use self::personal::Personal;
+pub use self::private::Private;
pub use self::pubsub::PubSub;
-pub use self::signer::Signer;
-pub use self::traces::Traces;
pub use self::rpc::Rpc;
pub use self::secretstore::SecretStore;
-pub use self::private::Private;
+pub use self::signer::Signer;
+pub use self::traces::Traces;
+pub use self::web3::Web3;
diff --git a/util/memory_cache/src/lib.rs b/util/memory_cache/src/lib.rs
index ff996142b92..ab3feafbf5f 100644
--- a/util/memory_cache/src/lib.rs
+++ b/util/memory_cache/src/lib.rs
@@ -86,6 +86,11 @@ impl MemoryLruCache {
pub fn current_size(&self) -> usize {
self.cur_size
}
+
+ /// Get backing LRU cache instance (read only)
+ pub fn backstore(&self) -> &LruCache {
+ &self.inner
+ }
}
#[cfg(test)]