From 67c0b8fba75e328af0849c2601023cbeb4297134 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 25 Oct 2015 12:55:48 -0500 Subject: [PATCH] More Error implementations --- Cargo.toml | 2 +- src/blockdata/script.rs | 60 ++++++++++++++++++++++++++++++++++++---- src/util/contracthash.rs | 41 +++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2c4743f..f3bb30d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bitcoin" -version = "0.3.8" +version = "0.3.9" authors = ["Andrew Poelstra "] license = "CC0-1.0" homepage = "https://github.com/apoelstra/rust-bitcoin/" diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 79ec4d3c..fff5e00f 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -27,7 +27,7 @@ use std::hash; use std::char::from_digit; use std::default::Default; -use std::{fmt, ops}; +use std::{error, fmt, ops}; use serialize::hex::ToHex; use crypto::digest::Digest; @@ -101,8 +101,6 @@ impl hash::Hash for Script { /// would help you. #[derive(PartialEq, Eq, Debug, Clone)] pub enum Error { - /// The script returns false no matter the input - AnalyzeAlwaysReturnsFalse, /// Tried to set a boolean to both values, but neither worked AnalyzeNeitherBoolWorks, /// Tried to set a boolean to the given value, but it already @@ -158,7 +156,59 @@ pub enum Error { /// An OP_VERIFY happened with zero on the stack VerifyFailed, } -display_from_debug!(Error); + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::Ecdsa(ref e) => fmt::Display::fmt(e, f), + Error::EqualVerifyFailed(ref exp, ref got) => write!(f, "OP_EQUALVERIFY failed; {} != {}", exp, got), + Error::MultisigBadKeyCount(n) => write!(f, "bad number {} of keys for multisignature", n), + Error::MultisigBadSigCount(n) => write!(f, "bad number {} of signatures for multisignature", n), + Error::NumEqualVerifyFailed(exp, got) => write!(f, "OP_NUMEQUALVERIFY failed; {} != {}", exp, got), + _ => f.write_str(error::Error::description(self)) + } + } +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::Ecdsa(ref e) => Some(e), + _ => None + } + } + + fn description(&self) -> &'static str { + match *self { + Error::AnalyzeNeitherBoolWorks => "analyzer: switch on boolean but neither side is satisfiable", + Error::AnalyzeSetBoolMismatch(_) => "analyzer: conflicting requirements on boolean", + Error::AnalyzeValidateFailed => "analyzer: conflicting requirements on stack element", + Error::BadPublicKey => "analyzer: CHECKSIG called with bad public key", + Error::BadSignature => "analyzer: CHECKSIG called with bad signature", + Error::Ecdsa(_) => "libsecp error", + Error::ElseWithoutIf => "unexpected OP_ELSE", + Error::EndifWithoutIf => "unexpected OP_ENDIF", + Error::EqualVerifyFailed(_, _) => "OP_EQUALVERIFY failed", + Error::IfEmptyStack => "OP_IF called with nothing on the stack", + Error::IllegalOpcode => "an illegal opcode exists in the script", + Error::InterpreterStackOverflow => "analyzer: stack overflow", + Error::EarlyEndOfScript => "unexpected end of script", + Error::ExecutedReturn => "OP_RETURN or equivalent was executed", + Error::MultisigBadKeyCount(_) => "bad key count for multisignature", + Error::MultisigBadSigCount(_) => "bad signature count for multisignature", + Error::NegativePick => "OP_PICK called with negative index", + Error::NegativeRoll => "OP_ROLL called with negative index", + Error::NoTransaction => "OP_CHECKSIG evaluated outside of transaction environment", + Error::NumEqualVerifyFailed(_, _) => "OP_NUMEQUALVERIFY failed", + Error::NumericOverflow => "numeric overflow (number on stack larger than 4 bytes)", + Error::PopEmptyStack => "stack was empty but script expected otherwise", + Error::Unanalyzable => "analyzer: unable to determine script satisfiability", + Error::Unsatisfiable => "analyzer: script is unsatisfiable", + Error::VerifyEmptyStack => "OP_VERIFY called on an empty stack", + Error::VerifyFailed => "OP_VERIFY called with false on top of stack" + } + } +} /// A rule for validating an abstract stack element pub struct Validator { @@ -2461,7 +2511,7 @@ impl Script { match stack.peek_mut().bool_value() { None => stack.peek_mut().set_bool_value(true).map(|_| stack.build_initial_stack()), Some(true) => Ok(stack.build_initial_stack()), - Some(false) => Err(Error::AnalyzeAlwaysReturnsFalse) + Some(false) => Err(Error::Unsatisfiable) } } diff --git a/src/util/contracthash.rs b/src/util/contracthash.rs index 262d5428..31b1c822 100644 --- a/src/util/contracthash.rs +++ b/src/util/contracthash.rs @@ -23,6 +23,8 @@ use blockdata::{opcodes, script}; use crypto::{hmac, sha2}; use crypto::mac::Mac; +use std::{error, fmt}; + use network::constants::Network; use util::{address, hash}; @@ -54,6 +56,45 @@ pub enum Error { TooManyKeys(usize) } +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Error::BadTweak(ref e) => fmt::Display::fmt(&e, f), + Error::Secp(ref e) => fmt::Display::fmt(&e, f), + Error::Script(ref e) => fmt::Display::fmt(&e, f), + Error::UncompressedKey => f.write_str("encountered uncompressed secp public key"), + Error::ExpectedKey => f.write_str("expected key when deserializing script"), + Error::ExpectedChecksig => f.write_str("expected OP_*CHECKSIG* when deserializing script"), + Error::TooFewKeys(n) => write!(f, "got {} keys, which was not enough", n), + Error::TooManyKeys(n) => write!(f, "got {} keys, which was too many", n) + } + } +} + +impl error::Error for Error { + fn cause(&self) -> Option<&error::Error> { + match *self { + Error::BadTweak(ref e) => Some(e), + Error::Secp(ref e) => Some(e), + Error::Script(ref e) => Some(e), + _ => None + } + } + + fn description(&self) -> &'static str { + match *self { + Error::BadTweak(_) => "bad public key tweak", + Error::Secp(_) => "libsecp256k1 error", + Error::Script(_) => "script error", + Error::UncompressedKey => "encountered uncompressed secp public key", + Error::ExpectedKey => "expected key when deserializing script", + Error::ExpectedChecksig => "expected OP_*CHECKSIG* when deserializing script", + Error::TooFewKeys(_) => "too few keys for template", + Error::TooManyKeys(_) => "too many keys for template" + } + } +} + /// An element of a script template #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum TemplateElement {