use core::fmt;
use internals::write_err;
use crate::amount::Amount;
use crate::blockdata::script::Script;
use crate::blockdata::transaction::{OutPoint, Transaction, TxOut};
#[cfg(doc)]
use crate::consensus;
use crate::consensus::encode;
pub fn verify_script(
script: &Script,
index: usize,
amount: Amount,
spending_tx: &[u8],
) -> Result<(), BitcoinconsensusError> {
verify_script_with_flags(script, index, amount, spending_tx, bitcoinconsensus::VERIFY_ALL)
}
pub fn verify_script_with_flags<F: Into<u32>>(
script: &Script,
index: usize,
amount: Amount,
spending_tx: &[u8],
flags: F,
) -> Result<(), BitcoinconsensusError> {
bitcoinconsensus::verify_with_flags(
script.as_bytes(),
amount.to_sat(),
spending_tx,
index,
flags.into(),
)
.map_err(BitcoinconsensusError)
}
pub fn verify_transaction<S>(tx: &Transaction, spent: S) -> Result<(), TxVerifyError>
where
S: FnMut(&OutPoint) -> Option<TxOut>,
{
verify_transaction_with_flags(tx, spent, bitcoinconsensus::VERIFY_ALL)
}
pub fn verify_transaction_with_flags<S, F>(
tx: &Transaction,
mut spent: S,
flags: F,
) -> Result<(), TxVerifyError>
where
S: FnMut(&OutPoint) -> Option<TxOut>,
F: Into<u32>,
{
let serialized_tx = encode::serialize(tx);
let flags: u32 = flags.into();
for (idx, input) in tx.input.iter().enumerate() {
if let Some(output) = spent(&input.previous_output) {
verify_script_with_flags(
&output.script_pubkey,
idx,
output.value,
serialized_tx.as_slice(),
flags,
)?;
} else {
return Err(TxVerifyError::UnknownSpentOutput(input.previous_output));
}
}
Ok(())
}
impl Script {
pub fn verify(
&self,
index: usize,
amount: crate::Amount,
spending_tx: &[u8],
) -> Result<(), BitcoinconsensusError> {
verify_script(self, index, amount, spending_tx)
}
pub fn verify_with_flags<F: Into<u32>>(
&self,
index: usize,
amount: crate::Amount,
spending_tx: &[u8],
flags: F,
) -> Result<(), BitcoinconsensusError> {
verify_script_with_flags(self, index, amount, spending_tx, flags)
}
}
impl Transaction {
pub fn verify<S>(&self, spent: S) -> Result<(), TxVerifyError>
where
S: FnMut(&OutPoint) -> Option<TxOut>,
{
verify_transaction(self, spent)
}
pub fn verify_with_flags<S, F>(&self, spent: S, flags: F) -> Result<(), TxVerifyError>
where
S: FnMut(&OutPoint) -> Option<TxOut>,
F: Into<u32>,
{
verify_transaction_with_flags(self, spent, flags)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct BitcoinconsensusError(bitcoinconsensus::Error);
impl fmt::Display for BitcoinconsensusError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write_err!(f, "bitcoinconsensus error"; &self.0)
}
}
#[cfg(all(feature = "std", feature = "bitcoinconsensus-std"))]
impl std::error::Error for BitcoinconsensusError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
}
#[cfg(all(feature = "std", not(feature = "bitcoinconsensus-std")))]
impl std::error::Error for BitcoinconsensusError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum TxVerifyError {
ScriptVerification(BitcoinconsensusError),
UnknownSpentOutput(OutPoint),
}
internals::impl_from_infallible!(TxVerifyError);
impl fmt::Display for TxVerifyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use TxVerifyError::*;
match *self {
ScriptVerification(ref e) => write_err!(f, "bitcoinconsensus verification failed"; e),
UnknownSpentOutput(ref p) => write!(f, "unknown spent output: {}", p),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for TxVerifyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use TxVerifyError::*;
match *self {
ScriptVerification(ref e) => Some(e),
UnknownSpentOutput(_) => None,
}
}
}
impl From<BitcoinconsensusError> for TxVerifyError {
fn from(e: BitcoinconsensusError) -> Self { TxVerifyError::ScriptVerification(e) }
}