Bad blocks RPC + reporting (#9433)
* Bad blocks RPC. * Return bad blocks via RPC. * Fix test. * More verbose bad block message. * Expose via CLI. * Remove stray whitespace. * Remove stray newline. * Fix tests.
This commit is contained in:
		
							parent
							
								
									915c366056
								
							
						
					
					
						commit
						61bd47ccc1
					
				
							
								
								
									
										81
									
								
								ethcore/src/client/bad_blocks.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								ethcore/src/client/bad_blocks.rs
									
									
									
									
									
										Normal file
									
								
							@ -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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! 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<MemoryLruCache<H256, (Unverified, String)>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -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<EthEngine>,
 | 
			
		||||
 | 
			
		||||
	/// 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 {
 | 
			
		||||
			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<Executed, CallError> {
 | 
			
		||||
		let address = self.transaction_address(id).ok_or(CallError::TransactionNotFound)?;
 | 
			
		||||
 | 
			
		||||
@ -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};
 | 
			
		||||
 | 
			
		||||
@ -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<Executed, CallError> {
 | 
			
		||||
		self.execution_result.read().clone().unwrap()
 | 
			
		||||
 | 
			
		||||
@ -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<BlockNumber>;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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]",
 | 
			
		||||
 | 
			
		||||
@ -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<Api>) -> BTreeMap<String, String> {
 | 
			
		||||
	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<C: LightChainClient + 'static> LightDependencies<C> {
 | 
			
		||||
 | 
			
		||||
		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()));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										96
									
								
								rpc/src/v1/impls/debug.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								rpc/src/v1/impls/debug.rs
									
									
									
									
									
										Normal file
									
								
							@ -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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! 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<C> {
 | 
			
		||||
	client: Arc<C>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C> DebugClient<C> {
 | 
			
		||||
	/// Creates new debug client.
 | 
			
		||||
	pub fn new(client: Arc<C>) -> Self {
 | 
			
		||||
		Self {
 | 
			
		||||
			client,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<C: BlockChainClient + 'static> Debug for DebugClient<C> {
 | 
			
		||||
	fn bad_blocks(&self) -> Result<Vec<RichBlock>> {
 | 
			
		||||
		fn cast<O, T: Copy + Into<O>>(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: ::serde::Serialize>(t: &T) -> String {
 | 
			
		||||
	::serde_json::to_string(t).expect("RPC types serialization is non-fallible.")
 | 
			
		||||
}
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								rpc/src/v1/tests/mocked/debug.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								rpc/src/v1/tests/mocked/debug.rs
									
									
									
									
									
										Normal file
									
								
							@ -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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
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()));
 | 
			
		||||
}
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								rpc/src/v1/traits/debug.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								rpc/src/v1/traits/debug.rs
									
									
									
									
									
										Normal file
									
								
							@ -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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 | 
			
		||||
//! 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<Vec<RichBlock>>;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -86,6 +86,11 @@ impl<K: Eq + Hash, V: HeapSizeOf> MemoryLruCache<K, V> {
 | 
			
		||||
	pub fn current_size(&self) -> usize {
 | 
			
		||||
		self.cur_size
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Get backing LRU cache instance (read only)
 | 
			
		||||
	pub fn backstore(&self) -> &LruCache<K, V> {
 | 
			
		||||
		&self.inner
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user