use crate::{
Interpreter, ScriptError, ScriptFlags, SpendContext, TidecoinValidationError,
TransactionContext, VERIFY_CLEANSTACK, VERIFY_P2SH, VERIFY_WITNESS,
};
use primitives::Transaction;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VerificationFailure {
pub error: TidecoinValidationError,
pub script_error: ScriptError,
}
pub fn verify_script_input(
tx: &Transaction,
input_index: usize,
spend: SpendContext<'_>,
flags: u32,
) -> Result<(), TidecoinValidationError> {
verify_script_input_detailed(tx, input_index, spend, flags).map_err(|failure| failure.error)
}
pub fn validate_verification_flags(flags: u32) -> Result<(), TidecoinValidationError> {
let _ = ScriptFlags::from_bits(normalize_flags(flags))?;
Ok(())
}
pub fn verify_script_input_detailed(
tx: &Transaction,
input_index: usize,
spend: SpendContext<'_>,
flags: u32,
) -> Result<(), VerificationFailure> {
let flags = ScriptFlags::from_bits(normalize_flags(flags)).map_err(simple_failure)?;
let tx_ctx = TransactionContext::new(tx);
let mut interpreter =
Interpreter::new(&tx_ctx, input_index, spend, flags).map_err(simple_failure)?;
interpreter.verify().map_err(|err| {
let script_error = interpreter.last_script_error();
VerificationFailure { error: normalize_script_error(err, script_error), script_error }
})
}
fn normalize_flags(mut flags: u32) -> u32 {
if flags & VERIFY_CLEANSTACK != 0 {
flags |= VERIFY_P2SH | VERIFY_WITNESS;
}
flags
}
fn simple_failure(error: TidecoinValidationError) -> VerificationFailure {
VerificationFailure { error, script_error: ScriptError::Ok }
}
fn normalize_script_error(
error: TidecoinValidationError,
script_error: ScriptError,
) -> TidecoinValidationError {
match error {
TidecoinValidationError::Script(_) => TidecoinValidationError::Script(script_error),
other => other,
}
}