Error handling improvements (particularly in chain) (#1208)

* update error handling in chain and other modules to use error/errorkind

* sizeshift errorkind
This commit is contained in:
Yeastplume
2018-06-30 23:36:38 +01:00
committed by GitHub
parent f0d5406d0b
commit d2a84b7600
28 changed files with 657 additions and 435 deletions
+10 -3
View File
@@ -103,7 +103,8 @@ pub const MAX_TX_KERNELS: u64 = 2048;
/// Whether a block exceeds the maximum acceptable weight
pub fn exceeds_weight(input_len: usize, output_len: usize, kernel_len: usize) -> bool {
input_len * BLOCK_INPUT_WEIGHT + output_len * BLOCK_OUTPUT_WEIGHT
input_len * BLOCK_INPUT_WEIGHT
+ output_len * BLOCK_OUTPUT_WEIGHT
+ kernel_len * BLOCK_KERNEL_WEIGHT > MAX_BLOCK_WEIGHT || input_len > MAX_BLOCK_INPUTS
}
@@ -159,14 +160,20 @@ pub const DAMP_FACTOR: u64 = 3;
pub const INITIAL_DIFFICULTY: u64 = 1_000_000;
/// Consensus errors
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Debug, Eq, PartialEq, Fail)]
pub enum Error {
/// Inputs/outputs/kernels must be sorted lexicographically.
SortError,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Sort Error")
}
}
/// Error when computing the next difficulty adjustment.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Fail)]
pub struct TargetError(pub String);
impl fmt::Display for TargetError {
+12 -3
View File
@@ -16,6 +16,7 @@
use rand::{thread_rng, Rng};
use std::collections::HashSet;
use std::fmt;
use std::iter::FromIterator;
use time;
@@ -24,15 +25,17 @@ use core::committed::{self, Committed};
use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH};
use core::id::ShortIdentifiable;
use core::target::Difficulty;
use core::{transaction, Commitment, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId,
Transaction, TxKernel};
use core::{
transaction, Commitment, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId,
Transaction, TxKernel,
};
use global;
use keychain::{self, BlindingFactor};
use ser::{self, read_and_verify_sorted, Readable, Reader, Writeable, WriteableSorted, Writer};
use util::{secp, secp_static, static_secp_instance, LOGGER};
/// Errors thrown by Block validation
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, Fail)]
pub enum Error {
/// The sum of output minus input commitments does not
/// match the sum of kernel commitments
@@ -95,6 +98,12 @@ impl From<consensus::Error> for Error {
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Block Error (display needs implementation")
}
}
/// Block header, fairly standard compared to other blockchains.
#[derive(Clone, Debug, PartialEq)]
pub struct BlockHeader {
+1 -1
View File
@@ -14,8 +14,8 @@
//! short ids for compact blocks
use std::cmp::Ordering;
use std::cmp::min;
use std::cmp::Ordering;
use byteorder::{ByteOrder, LittleEndian};
use siphasher::sip::SipHasher24;
+1 -1
View File
@@ -39,9 +39,9 @@ use std::marker;
use croaring::Bitmap;
use core::BlockHeader;
use core::hash::Hash;
use core::merkle_proof::MerkleProof;
use core::BlockHeader;
use ser::{PMMRIndexHashable, PMMRable};
use util::LOGGER;
+13 -19
View File
@@ -14,8 +14,8 @@
//! Transactions
use std::cmp::Ordering;
use std::cmp::max;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::{error, fmt};
@@ -27,8 +27,9 @@ use consensus::{self, VerifySortOrder};
use core::hash::Hashed;
use core::{committed, Committed};
use keychain::{self, BlindingFactor};
use ser::{self, read_and_verify_sorted, PMMRable, Readable, Reader, Writeable,
WriteableSorted, Writer};
use ser::{
self, read_and_verify_sorted, PMMRable, Readable, Reader, Writeable, WriteableSorted, Writer,
};
use util;
bitflags! {
@@ -250,7 +251,9 @@ pub struct Transaction {
/// PartialEq
impl PartialEq for Transaction {
fn eq(&self, tx: &Transaction) -> bool {
self.inputs == tx.inputs && self.outputs == tx.outputs && self.kernels == tx.kernels
self.inputs == tx.inputs
&& self.outputs == tx.outputs
&& self.kernels == tx.kernels
&& self.offset == tx.offset
}
}
@@ -290,7 +293,8 @@ impl Readable for Transaction {
let (input_len, output_len, kernel_len) =
ser_multiread!(reader, read_u64, read_u64, read_u64);
if input_len > consensus::MAX_TX_INPUTS || output_len > consensus::MAX_TX_OUTPUTS
if input_len > consensus::MAX_TX_INPUTS
|| output_len > consensus::MAX_TX_OUTPUTS
|| kernel_len > consensus::MAX_TX_KERNELS
{
return Err(ser::Error::CorruptedData);
@@ -436,16 +440,12 @@ impl Transaction {
/// Calculate transaction weight
pub fn tx_weight(&self) -> u32 {
Transaction::weight(
self.inputs.len(),
self.outputs.len(),
)
Transaction::weight(self.inputs.len(), self.outputs.len())
}
/// Calculate transaction weight from transaction details
pub fn weight(input_len: usize, output_len: usize) -> u32 {
let mut tx_weight =
-1 * (input_len as i32) + (4 * output_len as i32) + 1;
let mut tx_weight = -1 * (input_len as i32) + (4 * output_len as i32) + 1;
if tx_weight < 1 {
tx_weight = 1;
}
@@ -669,14 +669,8 @@ impl Readable for Input {
impl Input {
/// Build a new input from the data required to identify and verify an
/// output being spent.
pub fn new(
features: OutputFeatures,
commit: Commitment,
) -> Input {
Input {
features,
commit,
}
pub fn new(features: OutputFeatures, commit: Commitment) -> Input {
Input { features, commit }
}
/// The input commitment which _partially_ identifies the output being
+7 -4
View File
@@ -17,9 +17,11 @@
//! should be used sparingly.
use consensus::TargetError;
use consensus::{BLOCK_TIME_SEC, COINBASE_MATURITY, CUT_THROUGH_HORIZON, DEFAULT_MIN_SIZESHIFT,
DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, MEDIAN_TIME_WINDOW, PROOFSIZE,
REFERENCE_SIZESHIFT};
use consensus::{
BLOCK_TIME_SEC, COINBASE_MATURITY, CUT_THROUGH_HORIZON, DEFAULT_MIN_SIZESHIFT,
DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, MEDIAN_TIME_WINDOW, PROOFSIZE,
REFERENCE_SIZESHIFT,
};
use core::target::Difficulty;
/// An enum collecting sets of parameters used throughout the
/// code wherever mining is needed. This should allow for
@@ -184,7 +186,8 @@ pub fn is_user_testing_mode() -> bool {
/// Are we in production mode (a live public network)?
pub fn is_production_mode() -> bool {
let param_ref = CHAIN_TYPE.read().unwrap();
ChainTypes::Testnet1 == *param_ref || ChainTypes::Testnet2 == *param_ref
ChainTypes::Testnet1 == *param_ref
|| ChainTypes::Testnet2 == *param_ref
|| ChainTypes::Mainnet == *param_ref
}
+3
View File
@@ -38,7 +38,10 @@ extern crate serde_derive;
extern crate siphasher;
#[macro_use]
extern crate slog;
extern crate failure;
extern crate time;
#[macro_use]
extern crate failure_derive;
#[macro_use]
pub mod macros;
+17 -4
View File
@@ -171,7 +171,13 @@ impl Miner {
let size = 1 << sizeshift;
let graph = vec![0; size + 1];
let easiness = (ease as u64) * (size as u64) / 100;
Miner{easiness, cuckoo, graph, proof_size, sizeshift}
Miner {
easiness,
cuckoo,
graph,
proof_size,
sizeshift,
}
}
/// Searches for a solution
@@ -298,8 +304,13 @@ impl Miner {
/// Utility to transform a 8 bytes of a byte array into a u64.
fn u8_to_u64(p: &[u8], i: usize) -> u64 {
(p[i] as u64) | (p[i + 1] as u64) << 8 | (p[i + 2] as u64) << 16 | (p[i + 3] as u64) << 24
| (p[i + 4] as u64) << 32 | (p[i + 5] as u64) << 40 | (p[i + 6] as u64) << 48
(p[i] as u64)
| (p[i + 1] as u64) << 8
| (p[i + 2] as u64) << 16
| (p[i + 3] as u64) << 24
| (p[i + 4] as u64) << 32
| (p[i + 5] as u64) << 40
| (p[i + 6] as u64) << 48
| (p[i + 7] as u64) << 56
}
@@ -400,7 +411,9 @@ mod test {
#[test]
fn validate_fail() {
// edge checks
assert!(!Cuckoo::from_hash(blake2(&[49]).as_bytes(), 20).verify(&Proof::new(vec![0; 42]), 75));
assert!(
!Cuckoo::from_hash(blake2(&[49]).as_bytes(), 20).verify(&Proof::new(vec![0; 42]), 75)
);
assert!(!Cuckoo::from_hash(blake2(&[49]).as_bytes(), 20)
.verify(&Proof::new(vec![0xffff; 42]), 75));
// wrong data for proof
+22 -17
View File
@@ -25,16 +25,17 @@ use core::hash::{Hash, Hashed};
use keychain::{BlindingFactor, Identifier, IDENTIFIER_SIZE};
use std::io::{self, Read, Write};
use std::{cmp, error, fmt, mem};
use util::secp::Signature;
use util::secp::constants::{AGG_SIGNATURE_SIZE, MAX_PROOF_SIZE, PEDERSEN_COMMITMENT_SIZE,
SECRET_KEY_SIZE};
use util::secp::constants::{
AGG_SIGNATURE_SIZE, MAX_PROOF_SIZE, PEDERSEN_COMMITMENT_SIZE, SECRET_KEY_SIZE,
};
use util::secp::pedersen::{Commitment, RangeProof};
use util::secp::Signature;
/// Possible errors deriving from serializing or deserializing.
#[derive(Debug)]
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Error {
/// Wraps an io error produced when reading or writing
IOErr(io::Error),
IOErr(String, io::ErrorKind),
/// Expected a given value that wasn't found
UnexpectedData {
/// What we wanted
@@ -54,7 +55,7 @@ pub enum Error {
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error::IOErr(e)
Error::IOErr(format!("{}", e), e.kind())
}
}
@@ -67,7 +68,7 @@ impl From<consensus::Error> for Error {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::IOErr(ref e) => write!(f, "{}", e),
Error::IOErr(ref e, ref _k) => write!(f, "{}", e),
Error::UnexpectedData {
expected: ref e,
received: ref r,
@@ -83,14 +84,14 @@ impl fmt::Display for Error {
impl error::Error for Error {
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::IOErr(ref e) => Some(e),
Error::IOErr(ref _e, ref _k) => Some(self),
_ => None,
}
}
fn description(&self) -> &str {
match *self {
Error::IOErr(ref e) => error::Error::description(e),
Error::IOErr(ref e, _) => e,
Error::UnexpectedData {
expected: _,
received: _,
@@ -265,26 +266,30 @@ struct BinReader<'a> {
source: &'a mut Read,
}
fn map_io_err(err: io::Error) -> Error {
Error::IOErr(format!("{}", err), err.kind())
}
/// Utility wrapper for an underlying byte Reader. Defines higher level methods
/// to read numbers, byte vectors, hashes, etc.
impl<'a> Reader for BinReader<'a> {
fn read_u8(&mut self) -> Result<u8, Error> {
self.source.read_u8().map_err(Error::IOErr)
self.source.read_u8().map_err(map_io_err)
}
fn read_u16(&mut self) -> Result<u16, Error> {
self.source.read_u16::<BigEndian>().map_err(Error::IOErr)
self.source.read_u16::<BigEndian>().map_err(map_io_err)
}
fn read_u32(&mut self) -> Result<u32, Error> {
self.source.read_u32::<BigEndian>().map_err(Error::IOErr)
self.source.read_u32::<BigEndian>().map_err(map_io_err)
}
fn read_i32(&mut self) -> Result<i32, Error> {
self.source.read_i32::<BigEndian>().map_err(Error::IOErr)
self.source.read_i32::<BigEndian>().map_err(map_io_err)
}
fn read_u64(&mut self) -> Result<u64, Error> {
self.source.read_u64::<BigEndian>().map_err(Error::IOErr)
self.source.read_u64::<BigEndian>().map_err(map_io_err)
}
fn read_i64(&mut self) -> Result<i64, Error> {
self.source.read_i64::<BigEndian>().map_err(Error::IOErr)
self.source.read_i64::<BigEndian>().map_err(map_io_err)
}
/// Read a variable size vector from the underlying Read. Expects a usize
fn read_vec(&mut self) -> Result<Vec<u8>, Error> {
@@ -306,7 +311,7 @@ impl<'a> Reader for BinReader<'a> {
self.source
.read_exact(&mut buf)
.map(move |_| buf)
.map_err(Error::IOErr)
.map_err(map_io_err)
}
fn expect_u8(&mut self, val: u8) -> Result<u8, Error> {
@@ -459,7 +464,7 @@ where
let elem = T::read(reader);
match elem {
Ok(e) => buf.push(e),
Err(Error::IOErr(ref ioerr)) if ioerr.kind() == io::ErrorKind::UnexpectedEof => {
Err(Error::IOErr(ref _d, ref kind)) if *kind == io::ErrorKind::UnexpectedEof => {
break
}
Err(e) => return Err(e),