use core::fmt;
use bitcoin::sighash::{self, EcdsaSighashType, NonStandardSighashTypeError};
use bitcoin::{transaction, PublicKey};
use crate::error::{write_err, FundingUtxoError};
use crate::v2::map::{global, input, output};
#[derive(Debug)]
#[non_exhaustive]
pub enum DeserializeError {
InvalidMagic,
InvalidSeparator,
NoMorePairs,
DecodeGlobal(global::DecodeError),
DecodeInput(input::DecodeError),
DecodeOutput(output::DecodeError),
}
impl fmt::Display for DeserializeError {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { todo!() }
}
#[cfg(feature = "std")]
impl std::error::Error for DeserializeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { todo!() }
}
impl From<global::DecodeError> for DeserializeError {
fn from(e: global::DecodeError) -> Self { Self::DecodeGlobal(e) }
}
impl From<input::DecodeError> for DeserializeError {
fn from(e: input::DecodeError) -> Self { Self::DecodeInput(e) }
}
impl From<output::DecodeError> for DeserializeError {
fn from(e: output::DecodeError) -> Self { Self::DecodeOutput(e) }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum IndexOutOfBoundsError {
Inputs {
index: usize,
length: usize,
},
Count {
index: usize,
count: usize,
},
}
impl fmt::Display for IndexOutOfBoundsError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use IndexOutOfBoundsError::*;
match *self {
Inputs { ref index, ref length } => write!(
f,
"index {} is out-of-bounds for PSBT inputs vector length {}",
index, length
),
Count { ref index, ref count } =>
write!(f, "index {} is greater global.input_count {}", index, count),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for IndexOutOfBoundsError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use IndexOutOfBoundsError::*;
match *self {
Inputs { .. } | Count { .. } => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum SignError {
IndexOutOfBounds(IndexOutOfBoundsError),
InvalidSighashType,
MissingInputUtxo,
MissingRedeemScript,
FundingUtxo(FundingUtxoError),
MissingWitnessScript,
MismatchedAlgoKey,
NotEcdsa,
NotWpkh,
SegwitV0Sighash(transaction::InputsIndexError),
P2wpkhSighash(sighash::P2wpkhError),
TaprootError(sighash::TaprootError),
UnknownOutputType,
KeyNotFound,
WrongSigningAlgorithm,
Unsupported,
}
impl fmt::Display for SignError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use SignError::*;
match *self {
IndexOutOfBounds(ref e) => write_err!(f, "index out of bounds"; e),
InvalidSighashType => write!(f, "invalid sighash type"),
MissingInputUtxo => write!(f, "missing input utxo in PBST"),
MissingRedeemScript => write!(f, "missing redeem script"),
FundingUtxo(ref e) => write_err!(f, "input funding utxo error"; e),
MissingWitnessScript => write!(f, "missing witness script"),
MismatchedAlgoKey => write!(f, "signing algorithm and key type does not match"),
NotEcdsa => write!(f, "attempted to ECDSA sign an non-ECDSA input"),
NotWpkh => write!(f, "the scriptPubkey is not a P2WPKH script"),
SegwitV0Sighash(ref e) => write_err!(f, "segwit v0 sighash"; e),
P2wpkhSighash(ref e) => write_err!(f, "p2wpkh sighash"; e),
TaprootError(ref e) => write_err!(f, "taproot sighash"; e),
UnknownOutputType => write!(f, "unable to determine the output type"),
KeyNotFound => write!(f, "unable to find key"),
WrongSigningAlgorithm =>
write!(f, "attempt to sign an input with the wrong signing algorithm"),
Unsupported => write!(f, "signing request currently unsupported"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for SignError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use SignError::*;
match *self {
SegwitV0Sighash(ref e) => Some(e),
P2wpkhSighash(ref e) => Some(e),
TaprootError(ref e) => Some(e),
IndexOutOfBounds(ref e) => Some(e),
FundingUtxo(ref e) => Some(e),
InvalidSighashType
| MissingInputUtxo
| MissingRedeemScript
| MissingWitnessScript
| MismatchedAlgoKey
| NotEcdsa
| NotWpkh
| UnknownOutputType
| KeyNotFound
| WrongSigningAlgorithm
| Unsupported => None,
}
}
}
impl From<sighash::P2wpkhError> for SignError {
fn from(e: sighash::P2wpkhError) -> Self { Self::P2wpkhSighash(e) }
}
impl From<IndexOutOfBoundsError> for SignError {
fn from(e: IndexOutOfBoundsError) -> Self { Self::IndexOutOfBounds(e) }
}
impl From<sighash::TaprootError> for SignError {
fn from(e: sighash::TaprootError) -> Self { SignError::TaprootError(e) }
}
impl From<FundingUtxoError> for SignError {
fn from(e: FundingUtxoError) -> Self { Self::FundingUtxo(e) }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum PsbtNotModifiableError {
Outputs(OutputsNotModifiableError),
Inputs(InputsNotModifiableError),
}
impl fmt::Display for PsbtNotModifiableError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use PsbtNotModifiableError::*;
match *self {
Outputs(ref e) => write_err!(f, "outputs not modifiable"; e),
Inputs(ref e) => write_err!(f, "inputs not modifiable"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PsbtNotModifiableError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use PsbtNotModifiableError::*;
match *self {
Outputs(ref e) => Some(e),
Inputs(ref e) => Some(e),
}
}
}
impl From<InputsNotModifiableError> for PsbtNotModifiableError {
fn from(e: InputsNotModifiableError) -> Self { Self::Inputs(e) }
}
impl From<OutputsNotModifiableError> for PsbtNotModifiableError {
fn from(e: OutputsNotModifiableError) -> Self { Self::Outputs(e) }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct InputsNotModifiableError;
impl fmt::Display for InputsNotModifiableError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("PSBT does not have the inputs modifiable flag set")
}
}
#[cfg(feature = "std")]
impl std::error::Error for InputsNotModifiableError {}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct OutputsNotModifiableError;
impl fmt::Display for OutputsNotModifiableError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("PSBT does not have the outputs modifiable flag set")
}
}
#[cfg(feature = "std")]
impl std::error::Error for OutputsNotModifiableError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum NotUnsignedError {
Finalized,
SigData,
}
impl fmt::Display for NotUnsignedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use NotUnsignedError::*;
match *self {
Finalized => f.write_str("input has already been finalized"),
SigData => f.write_str("input already has signature data"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for NotUnsignedError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct DetermineLockTimeError;
impl fmt::Display for DetermineLockTimeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(
"unable to determine lock time, multiple inputs have conflicting locking requirements",
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for DetermineLockTimeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[derive(Debug)]
pub enum PartialSigsSighashTypeError {
NonStandardInputSighashType {
input_index: usize,
error: NonStandardSighashTypeError,
},
NonStandardPartialSigsSighashType {
input_index: usize,
error: NonStandardSighashTypeError,
},
WrongSighashFlag {
input_index: usize,
got: EcdsaSighashType,
required: EcdsaSighashType,
pubkey: PublicKey,
},
}
impl fmt::Display for PartialSigsSighashTypeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use PartialSigsSighashTypeError::*;
match *self {
NonStandardInputSighashType { input_index, ref error } =>
write_err!(f, "non-standard sighash type for input {} in sighash_type field", input_index; error),
NonStandardPartialSigsSighashType { input_index, ref error } =>
write_err!(f, "non-standard sighash type for input {} in partial_sigs", input_index; error),
WrongSighashFlag { input_index, got, required, pubkey } => write!(
f,
"wrong sighash flag for input {} (got: {}, required: {}) pubkey: {}",
input_index, got, required, pubkey
),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PartialSigsSighashTypeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use PartialSigsSighashTypeError::*;
match *self {
NonStandardInputSighashType { input_index: _, ref error } => Some(error),
NonStandardPartialSigsSighashType { input_index: _, ref error } => Some(error),
WrongSighashFlag { .. } => None,
}
}
}