diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index b2ba886b4dd..ad58953a826 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -213,6 +213,7 @@ pub struct BlockChain { block_hashes: RwLock>, transaction_addresses: RwLock>, block_receipts: RwLock>, + bad_blocks: RwLock>, db: Arc, @@ -527,6 +528,7 @@ impl BlockChain { block_hashes: RwLock::new(HashMap::new()), transaction_addresses: RwLock::new(HashMap::new()), block_receipts: RwLock::new(HashMap::new()), + bad_blocks: RwLock::new(HashMap::new()), db: db.clone(), cache_man: Mutex::new(cache_man), pending_best_block: RwLock::new(None), @@ -985,6 +987,11 @@ impl BlockChain { let info = self.block_info(&header, route, &extras); + if self.is_blacklisted_hash(hash) { + self.bad_blocks.write().insert(hash, info); + return ImportRoute::none(); + } + if let BlockLocation::BranchBecomingCanonChain(ref d) = info.location { info!(target: "reorg", "Reorg to {} ({} {} {})", Colour::Yellow.bold().paint(format!("#{} {}", info.number, info.hash)), @@ -1364,6 +1371,26 @@ impl BlockChain { } } + /// Determine if a hash is blacklisted (part of a hard fork) + fn is_blacklisted_hash(&self, hash: H256) -> bool { + if self.blacklisted_hashes().contains_key(&hash) { + return true + } + false + } + + /// Get all blacklisted hashes + fn blacklisted_hashes(&self) -> HashMap { + let mut blacklist = HashMap::new(); + blacklist.insert("05bef30ef572270f654746da22639a7a0c97dd97a7050b9e252391996aaeb689".into(), true); + blacklist.insert("7d05d08cbc596a2e5e4f13b80a743e53e09221b5323c3a61946b20873e58583f".into(), true); + blacklist + } + + pub fn bad_blocks(&self) -> Vec { + self.bad_blocks.read().iter().map(|(hash, _)| *hash).collect::>() + } + /// Get best block hash. pub fn best_block_hash(&self) -> H256 { self.best_block.read().header.hash() diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 56c71a86ec9..046a03fe4e1 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1650,6 +1650,16 @@ impl BlockChainClient for Client { Self::block_hash(&chain, id) } + fn bad_blocks(&self) -> Option> { + let blocks = self.chain.read().bad_blocks(); + + if blocks.len() > 0 { + Some(blocks) + } else { + None + } + } + fn code(&self, address: &Address, state: StateOrBlock) -> Option> { let result = match state { StateOrBlock::State(s) => s.code(address).ok(), diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 7a3dfcd0075..0f0c7cab553 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -324,6 +324,12 @@ impl TestBlockChainClient { } } + fn bad_blocks(&self) -> Option> { + let mut bad_block = Vec::new(); + bad_block.push("05bef30ef572270f654746da22639a7a0c97dd97a7050b9e252391996aaeb689".into()); + Some(bad_block) + } + /// Inserts a transaction with given gas price to miners transactions queue. pub fn insert_transaction_with_gas_price_to_queue(&self, gas_price: U256) -> H256 { let keypair = Random.generate().unwrap(); @@ -622,6 +628,10 @@ impl BlockChainClient for TestBlockChainClient { Self::block_hash(self, id) } + fn bad_blocks(&self) -> Option> { + Self::bad_blocks(self) + } + fn storage_root(&self, _address: &Address, _id: BlockId) -> Option { None } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 65bf0092118..4bf59acf733 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -233,6 +233,9 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra /// Get block hash. fn block_hash(&self, id: BlockId) -> Option; + /// Get all known bad blocks in chain. + fn bad_blocks(&self) -> Option>; + /// Get address code at given block's state. fn code(&self, address: &Address, state: StateOrBlock) -> Option>; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d20b2feb267..c735ca9992e 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -817,6 +817,22 @@ impl Eth for EthClient< Ok(true) } + fn bad_blocks(&self, include_txs: bool) -> BoxFuture> { + let blocks = self.client.bad_blocks() + .and_then(|vec| { + vec.iter() + .filter_map(|hash| { + self.rich_block(BlockNumberOrId::Id(BlockId::Hash(*hash)), include_txs).ok() + }) + .collect() + }); + + match blocks { + Some(b) => Box::new(future::done(Ok(b))), + None => Box::new(future::done(Ok(>::new()))) + } + } + fn send_raw_transaction(&self, raw: Bytes) -> Result { Rlp::new(&raw.into_vec()).as_val() .map_err(errors::rlp) diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index e88ac2dab35..5fe83cd7841 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -528,6 +528,10 @@ impl Eth for EthClient { fn submit_hashrate(&self, _rate: RpcU256, _id: RpcH256) -> Result { Err(errors::light_unimplemented(None)) } + + fn bad_blocks(&self, _include_txs: bool) -> BoxFuture> { + Box::new(future::done(Ok(>::new()))) + } } // This trait implementation triggers a blanked impl of `EthFilter`. diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 48e315ce7e9..b73205fd071 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -174,6 +174,10 @@ build_rpc_trait! { /// Used for submitting mining hashrate. #[rpc(name = "eth_submitHashrate")] fn submit_hashrate(&self, U256, H256) -> Result; + + /// Used for finding bad blocks in current chain. + #[rpc(name = "debug_getBadBlocks")] + fn bad_blocks(&self, bool) -> BoxFuture>; } }