pub mod bitcoin;
#[cfg(feature = "miniscript")]
pub mod miniscript;
use core::fmt;
use ::bitcoin::ScriptBuf;
use crate::v0::bitcoin::OutputType;
#[rustfmt::skip] #[doc(inline)]
pub use self::bitcoin::{Psbt, Input, Output};
impl Psbt {
pub fn signer_checks(&self) -> Result<(), SignerChecksError> {
let unsigned_tx = &self.unsigned_tx;
for (i, input) in self.inputs.iter().enumerate() {
if input.witness_utxo.is_some() {
match self.output_type(i) {
Ok(OutputType::Bare) => return Err(SignerChecksError::NonWitnessSig),
Ok(_) => {}
Err(_) => {} }
}
if let Some(ref tx) = input.non_witness_utxo {
if tx.compute_txid() != unsigned_tx.input[i].previous_output.txid {
return Err(SignerChecksError::NonWitnessUtxoTxidMismatch);
}
}
if let Some(ref redeem_script) = input.redeem_script {
match input.witness_utxo {
Some(ref tx_out) => {
let script_pubkey = ScriptBuf::new_p2sh(&redeem_script.script_hash());
if tx_out.script_pubkey != script_pubkey {
return Err(SignerChecksError::RedeemScriptMismatch);
}
}
None => return Err(SignerChecksError::MissingTxOut),
}
}
if let Some(ref witness_script) = input.witness_script {
match input.witness_utxo {
Some(ref utxo) => {
let script_pubkey = &utxo.script_pubkey;
if script_pubkey.is_p2wsh() {
if ScriptBuf::new_p2wsh(&witness_script.wscript_hash())
!= *script_pubkey
{
return Err(SignerChecksError::WitnessScriptMismatchWsh);
}
} else if script_pubkey.is_p2sh() {
if let Some(ref redeem_script) = input.redeem_script {
if ScriptBuf::new_p2wsh(&redeem_script.wscript_hash())
!= *script_pubkey
{
return Err(SignerChecksError::WitnessScriptMismatchShWsh);
}
}
} else {
}
}
None => return Err(SignerChecksError::MissingTxOut),
}
}
if let Some(_sighash_type) = input.sighash_type {
{}
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum SignerChecksError {
NonWitnessSig,
NonWitnessUtxoTxidMismatch,
WitnessAndNonWitnessUtxo,
RedeemScriptMismatch,
MissingTxOut,
WitnessScriptMismatchWsh,
WitnessScriptMismatchShWsh,
}
impl fmt::Display for SignerChecksError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use SignerChecksError::*;
match *self {
NonWitnessSig => write!(f, "witness input will produce a non-witness signature"),
NonWitnessUtxoTxidMismatch =>
write!(f, "non-witness input has a mismatch between the txid and prevout txid"),
WitnessAndNonWitnessUtxo => write!(f, "input has both witness and non-witness utxos"),
RedeemScriptMismatch =>
write!(f, "redeem script hash did not match the hash in the script_pubkey"),
MissingTxOut => write!(f, "missing witness_utxo"),
WitnessScriptMismatchWsh =>
write!(f, "native segwit p2wsh script_pubkey did not match witness script hash"),
WitnessScriptMismatchShWsh =>
write!(f, "nested segwit p2wsh script_pubkey did not match redeem script hash"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for SignerChecksError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}