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:
+10
-3
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user