use thiserror::Error;
use zcash_script::{interpreter, script};
#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum Error {
#[error("{0}")]
Script(script::Error),
#[error("caught exception during verification")]
CaughtException,
#[error("unknown error code: {0}")]
Unknown(i64),
}
impl Error {
pub fn normalize(&self) -> Self {
match self {
Error::Script(serr) => Error::Script(serr.normalize()),
_ => self.clone(),
}
}
}
impl From<script::Error> for Error {
fn from(value: script::Error) -> Self {
Error::Script(value)
}
}
pub type AnnError = (Option<script::ComponentType>, Error);
pub trait ZcashScript {
fn verify_callback(
&self,
script: &script::Raw,
flags: interpreter::Flags,
) -> Result<bool, AnnError>;
fn legacy_sigop_count_script(&self, script: &script::Code) -> Result<u32, script::Error>;
}
pub struct RustInterpreter<C> {
checker: C,
}
impl<C> RustInterpreter<C> {
pub fn new(checker: C) -> Self {
RustInterpreter { checker }
}
}
impl<C: interpreter::SignatureChecker> ZcashScript for RustInterpreter<C> {
fn legacy_sigop_count_script(&self, script: &script::Code) -> Result<u32, script::Error> {
Ok(script.sig_op_count(false))
}
fn verify_callback(
&self,
script: &script::Raw,
flags: interpreter::Flags,
) -> Result<bool, AnnError> {
script
.eval(flags, &self.checker)
.map_err(|(t, e)| (Some(t), Error::Script(e)))
}
}