Decoding headers can fail (#8570)
* rlp::decode returns Result * Fix journaldb to handle rlp::decode Result * Fix ethcore to work with rlp::decode returning Result * Light client handles rlp::decode returning Result * Fix tests in rlp_derive * Fix tests * Cleanup * cleanup * Allow panic rather than breaking out of iterator * Let decoding failures when reading from disk blow up * syntax * Fix the trivial grumbles * Fix failing tests * Make Account::from_rlp return Result * Syntx, sigh * Temp-fix for decoding failures * Header::decode returns Result Handle new return type throughout the code base. * Do not continue reading from the DB when a value could not be read * Fix tests * Handle header decoding in light_sync * Handling header decoding errors * Let the DecodeError bubble up unchanged * Remove redundant error conversion
This commit is contained in:
@@ -1219,8 +1219,7 @@ impl Client {
|
||||
=> Some(self.chain.read().best_block_header()),
|
||||
BlockId::Number(number) if number == self.chain.read().best_block_number()
|
||||
=> Some(self.chain.read().best_block_header()),
|
||||
_
|
||||
=> self.block_header(id).map(|h| h.decode()),
|
||||
_ => self.block_header(id).and_then(|h| h.decode().ok())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1915,7 +1914,11 @@ impl BlockChainClient for Client {
|
||||
|
||||
fn uncle_extra_info(&self, id: UncleId) -> Option<BTreeMap<String, String>> {
|
||||
self.uncle(id)
|
||||
.map(|header| self.engine.extra_info(&header.decode()))
|
||||
.and_then(|h| {
|
||||
h.decode().map(|dh| {
|
||||
self.engine.extra_info(&dh)
|
||||
}).ok()
|
||||
})
|
||||
}
|
||||
|
||||
fn pruning_info(&self) -> PruningInfo {
|
||||
@@ -2033,7 +2036,8 @@ impl ReopenBlock for Client {
|
||||
for h in uncles {
|
||||
if !block.uncles().iter().any(|header| header.hash() == h) {
|
||||
let uncle = chain.block_header_data(&h).expect("find_uncle_hashes only returns hashes for existing headers; qed");
|
||||
block.push_uncle(uncle.decode()).expect("pushing up to maximum_uncle_count;
|
||||
let uncle = uncle.decode().expect("decoding failure");
|
||||
block.push_uncle(uncle).expect("pushing up to maximum_uncle_count;
|
||||
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||
so all push_uncle are Ok;
|
||||
qed");
|
||||
@@ -2074,7 +2078,7 @@ impl PrepareOpenBlock for Client {
|
||||
.into_iter()
|
||||
.take(engine.maximum_uncle_count(open_block.header().number()))
|
||||
.foreach(|h| {
|
||||
open_block.push_uncle(h.decode()).expect("pushing maximum_uncle_count;
|
||||
open_block.push_uncle(h.decode().expect("decoding failure")).expect("pushing maximum_uncle_count;
|
||||
open_block was just created;
|
||||
push_uncle is not ok only if more than maximum_uncle_count is pushed;
|
||||
so all push_uncle are Ok;
|
||||
|
||||
@@ -289,7 +289,7 @@ impl TestBlockChainClient {
|
||||
/// Make a bad block by setting invalid extra data.
|
||||
pub fn corrupt_block(&self, n: BlockNumber) {
|
||||
let hash = self.block_hash(BlockId::Number(n)).unwrap();
|
||||
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode();
|
||||
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode().expect("decoding failed");
|
||||
header.set_extra_data(b"This extra data is way too long to be considered valid".to_vec());
|
||||
let mut rlp = RlpStream::new_list(3);
|
||||
rlp.append(&header);
|
||||
@@ -301,7 +301,7 @@ impl TestBlockChainClient {
|
||||
/// Make a bad block by setting invalid parent hash.
|
||||
pub fn corrupt_block_parent(&self, n: BlockNumber) {
|
||||
let hash = self.block_hash(BlockId::Number(n)).unwrap();
|
||||
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode();
|
||||
let mut header: BlockHeader = self.block_header(BlockId::Number(n)).unwrap().decode().expect("decoding failed");
|
||||
header.set_parent_hash(H256::from(42));
|
||||
let mut rlp = RlpStream::new_list(3);
|
||||
rlp.append(&header);
|
||||
@@ -479,6 +479,7 @@ impl BlockInfo for TestBlockChainClient {
|
||||
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
|
||||
.expect("Best block always has header.")
|
||||
.decode()
|
||||
.expect("decoding failed")
|
||||
}
|
||||
|
||||
fn block(&self, id: BlockId) -> Option<encoded::Block> {
|
||||
|
||||
@@ -28,7 +28,7 @@ use ethereum_types::{H256, Bloom, U256, Address};
|
||||
use hash::keccak;
|
||||
use header::{BlockNumber, Header as FullHeader};
|
||||
use heapsize::HeapSizeOf;
|
||||
use rlp::{Rlp, RlpStream};
|
||||
use rlp::{self, Rlp, RlpStream};
|
||||
use transaction::UnverifiedTransaction;
|
||||
use views::{self, BlockView, HeaderView, BodyView};
|
||||
|
||||
@@ -47,7 +47,9 @@ impl Header {
|
||||
pub fn new(encoded: Vec<u8>) -> Self { Header(encoded) }
|
||||
|
||||
/// Upgrade this encoded view to a fully owned `Header` object.
|
||||
pub fn decode(&self) -> FullHeader { ::rlp::decode(&self.0).expect("decoding failure") }
|
||||
pub fn decode(&self) -> Result<FullHeader, rlp::DecoderError> {
|
||||
rlp::decode(&self.0)
|
||||
}
|
||||
|
||||
/// Get a borrowed header view onto the data.
|
||||
#[inline]
|
||||
|
||||
@@ -996,7 +996,7 @@ impl Engine<EthereumMachine> for AuthorityRound {
|
||||
|
||||
let parent = client.block_header(::client::BlockId::Hash(*block.header().parent_hash()))
|
||||
.expect("hash is from parent; parent header must exist; qed")
|
||||
.decode();
|
||||
.decode()?;
|
||||
|
||||
let parent_step = header_step(&parent, self.empty_steps_transition)?;
|
||||
let current_step = self.step.load();
|
||||
|
||||
@@ -290,6 +290,12 @@ error_chain! {
|
||||
description("Unknown engine name")
|
||||
display("Unknown engine name ({})", name)
|
||||
}
|
||||
|
||||
#[doc = "RLP decoding errors"]
|
||||
Decoder(err: ::rlp::DecoderError) {
|
||||
description("decoding value failed")
|
||||
display("decoding value failed with error: {}", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,11 +316,11 @@ impl From<AccountsError> for Error {
|
||||
fn from(err: AccountsError) -> Error {
|
||||
ErrorKind::AccountProvider(err).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<::rlp::DecoderError> for Error {
|
||||
fn from(err: ::rlp::DecoderError) -> Error {
|
||||
UtilError::from(err).into()
|
||||
ErrorKind::Decoder(err).into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -528,8 +528,8 @@ impl Miner {
|
||||
}
|
||||
|
||||
/// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal.
|
||||
fn seal_and_import_block_internally<C>(&self, chain: &C, block: ClosedBlock) -> bool where
|
||||
C: BlockChain + SealedBlockImporter,
|
||||
fn seal_and_import_block_internally<C>(&self, chain: &C, block: ClosedBlock) -> bool
|
||||
where C: BlockChain + SealedBlockImporter,
|
||||
{
|
||||
{
|
||||
let sealing = self.sealing.lock();
|
||||
@@ -544,7 +544,12 @@ impl Miner {
|
||||
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
|
||||
|
||||
let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) {
|
||||
Some(hdr) => hdr.decode(),
|
||||
Some(h) => {
|
||||
match h.decode() {
|
||||
Ok(decoded_hdr) => decoded_hdr,
|
||||
Err(_) => return false
|
||||
}
|
||||
}
|
||||
None => return false,
|
||||
};
|
||||
|
||||
|
||||
@@ -487,7 +487,7 @@ pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &EthEngine, ch
|
||||
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
||||
engine.verify_block_unordered(header)?;
|
||||
match chain.block_header_data(header.parent_hash()) {
|
||||
Some(parent) => engine.verify_block_family(header, &parent.decode()),
|
||||
Some(parent) => engine.verify_block_family(header, &parent.decode()?),
|
||||
None => Ok(()),
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -224,7 +224,7 @@ fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &Eth
|
||||
return Err(From::from(BlockError::UncleParentNotInChain(uncle_parent.hash())));
|
||||
}
|
||||
|
||||
let uncle_parent = uncle_parent.decode();
|
||||
let uncle_parent = uncle_parent.decode()?;
|
||||
verify_parent(&uncle, &uncle_parent, engine)?;
|
||||
engine.verify_block_family(&uncle, &uncle_parent)?;
|
||||
verified.insert(uncle.hash());
|
||||
@@ -500,10 +500,9 @@ mod tests {
|
||||
// no existing tests need access to test, so having this not function
|
||||
// is fine.
|
||||
let client = ::client::TestBlockChainClient::default();
|
||||
|
||||
let parent = bc.block_header_data(header.parent_hash())
|
||||
.ok_or(BlockError::UnknownParent(header.parent_hash().clone()))?
|
||||
.decode();
|
||||
.decode()?;
|
||||
|
||||
let full_params = FullFamilyParams {
|
||||
block_bytes: bytes,
|
||||
|
||||
Reference in New Issue
Block a user