Skip to content

Commit 5b736bd

Browse files
committed
miniscript: move lexer errors into their own type
Also clean up the names and format messages for them.
1 parent ceadd0d commit 5b736bd

File tree

2 files changed

+63
-26
lines changed

2 files changed

+63
-26
lines changed

src/lib.rs

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,6 @@ mod util;
131131
use core::{fmt, hash, str};
132132

133133
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
134-
use bitcoin::hex::DisplayHex;
135-
use bitcoin::{script, Opcode};
136134

137135
pub use crate::blanket_traits::FromStrKey;
138136
pub use crate::descriptor::{DefiniteDescriptorKey, Descriptor, DescriptorPublicKey};
@@ -436,15 +434,8 @@ pub trait ForEachKey<Pk: MiniscriptKey> {
436434
437435
#[derive(Debug)]
438436
pub enum Error {
439-
/// Opcode appeared which is not part of the script subset
440-
InvalidOpcode(Opcode),
441-
/// Some opcode occurred followed by `OP_VERIFY` when it had
442-
/// a `VERIFY` version that should have been used instead
443-
NonMinimalVerify(String),
444-
/// Push was illegal in some context
445-
InvalidPush(Vec<u8>),
446-
/// rust-bitcoin script error
447-
Script(script::Error),
437+
/// Error when lexing a bitcoin Script.
438+
ScriptLexer(crate::miniscript::lex::Error),
448439
/// rust-bitcoin address error
449440
AddrError(bitcoin::address::ParseError),
450441
/// rust-bitcoin p2sh address error
@@ -519,12 +510,7 @@ const MAX_RECURSION_DEPTH: u32 = 402;
519510
impl fmt::Display for Error {
520511
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
521512
match *self {
522-
Error::InvalidOpcode(op) => write!(f, "invalid opcode {}", op),
523-
Error::NonMinimalVerify(ref tok) => write!(f, "{} VERIFY", tok),
524-
Error::InvalidPush(ref push) => {
525-
write!(f, "invalid push {:x}", push.as_hex())
526-
},
527-
Error::Script(ref e) => fmt::Display::fmt(e, f),
513+
Error::ScriptLexer(ref e) => e.fmt(f),
528514
Error::AddrError(ref e) => fmt::Display::fmt(e, f),
529515
Error::AddrP2shError(ref e) => fmt::Display::fmt(e, f),
530516
Error::UnexpectedStart => f.write_str("unexpected start of script"),
@@ -576,10 +562,7 @@ impl std::error::Error for Error {
576562
use self::Error::*;
577563

578564
match self {
579-
InvalidOpcode(_)
580-
| NonMinimalVerify(_)
581-
| InvalidPush(_)
582-
| UnexpectedStart
565+
UnexpectedStart
583566
| Unexpected(_)
584567
| UnknownWrapper(_)
585568
| NonTopLevel(_)
@@ -593,7 +576,7 @@ impl std::error::Error for Error {
593576
| BareDescriptorAddr
594577
| TrNoScriptCode
595578
| MultipathDescLenMismatch => None,
596-
Script(e) => Some(e),
579+
ScriptLexer(e) => Some(e),
597580
AddrError(e) => Some(e),
598581
AddrP2shError(e) => Some(e),
599582
Secp(e) => Some(e),
@@ -614,6 +597,11 @@ impl std::error::Error for Error {
614597
}
615598
}
616599

600+
#[doc(hidden)]
601+
impl From<miniscript::lex::Error> for Error {
602+
fn from(e: miniscript::lex::Error) -> Error { Error::ScriptLexer(e) }
603+
}
604+
617605
#[doc(hidden)]
618606
impl From<miniscript::types::Error> for Error {
619607
fn from(e: miniscript::types::Error) -> Error { Error::TypeCheck(e.to_string()) }

src/miniscript/lex.rs

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use core::fmt;
1010
use bitcoin::blockdata::{opcodes, script};
1111
use bitcoin::hex::DisplayHex as _;
1212

13-
use super::Error;
1413
use crate::prelude::*;
1514

1615
/// Atom of a tokenized version of a script
@@ -187,7 +186,7 @@ pub fn lex(script: &'_ script::Script) -> Result<Vec<Token>, Error> {
187186
Some(op @ &Token::Equal)
188187
| Some(op @ &Token::CheckSig)
189188
| Some(op @ &Token::CheckMultiSig) => {
190-
return Err(Error::NonMinimalVerify(format!("{:?}", op)))
189+
return Err(Error::NonMinimalVerify(*op));
191190
}
192191
_ => {}
193192
}
@@ -220,8 +219,8 @@ pub fn lex(script: &'_ script::Script) -> Result<Vec<Token>, Error> {
220219
Ok(v) if v >= 0 => {
221220
ret.push(Token::Num(v as u32));
222221
}
223-
Ok(_) => return Err(Error::InvalidPush(bytes.to_owned().into())),
224-
Err(e) => return Err(Error::Script(e)),
222+
Ok(n) => return Err(Error::NegativeInt { bytes: bytes.to_owned(), n }),
223+
Err(err) => return Err(Error::InvalidInt { bytes: bytes.to_owned(), err }),
225224
}
226225
}
227226
}
@@ -281,3 +280,53 @@ pub fn lex(script: &'_ script::Script) -> Result<Vec<Token>, Error> {
281280
}
282281
Ok(ret)
283282
}
283+
284+
/// Lexer error.
285+
#[derive(Debug, Clone, PartialEq, Eq)]
286+
pub enum Error {
287+
/// Parsed a negative number.
288+
InvalidInt {
289+
/// The bytes of the push that were attempted to be parsed.
290+
bytes: bitcoin::script::PushBytesBuf,
291+
/// The error that occured.
292+
err: bitcoin::script::Error,
293+
},
294+
/// Parsed an opcode outside of the Miniscript language.
295+
InvalidOpcode(bitcoin::Opcode),
296+
/// Parsed a negative number.
297+
NegativeInt {
298+
/// The bytes of the push that were parsed to a negative number.
299+
bytes: bitcoin::script::PushBytesBuf,
300+
/// The resulting number.
301+
n: i64,
302+
},
303+
/// Non-minimal verify (e.g. `CHECKSIG VERIFY` in place of `CHECKSIGVERIFY`).
304+
NonMinimalVerify(Token),
305+
/// Error iterating through script.
306+
Script(bitcoin::script::Error),
307+
}
308+
309+
impl fmt::Display for Error {
310+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311+
match *self {
312+
Self::Script(ref e) => e.fmt(f),
313+
Self::InvalidInt { ref bytes, ref err } => write!(f, "push {} of length {} is not a key, hash or minimal integer: {}", bytes.as_bytes().as_hex(), bytes.len(), err),
314+
Self::InvalidOpcode(ref op) => write!(f, "found opcode {} which does not occur in Miniscript", op),
315+
Self::NegativeInt { ref bytes, n } => write!(f, "push {} of length {} parses as a negative number {} which does not occur in Miniscript", bytes.as_bytes().as_hex(), bytes.len(), n),
316+
Self::NonMinimalVerify(ref op) => write!(f, "found {} VERIFY (should be one opcode, {}VERIFY)", op, op),
317+
}
318+
}
319+
}
320+
321+
#[cfg(feature = "std")]
322+
impl std::error::Error for Error {
323+
fn cause(&self) -> Option<&(dyn std::error::Error + 'static)> {
324+
match *self {
325+
Self::InvalidInt { ref err, .. } => Some(err),
326+
Self::InvalidOpcode(..) => None,
327+
Self::NegativeInt { .. } => None,
328+
Self::NonMinimalVerify(..) => None,
329+
Self::Script(ref e) => Some(e),
330+
}
331+
}
332+
}

0 commit comments

Comments
 (0)