use std::{error, fmt};
use crate::encode;
use crate::Txid;
use super::raw;
use crate::blind::ConfidentialTxOutError;
use crate::hashes;
use secp256k1_zkp;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PsetHash {
Ripemd,
Sha256,
Hash160,
Hash256,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Error {
InvalidMagic,
InvalidSeparator,
InvalidKey(raw::Key),
InvalidProprietaryKey,
DuplicateKey(raw::Key),
LocktimeConflict,
UnsignedTxHasScriptSigs,
UnsignedTxHasScriptWitnesses,
MustHaveUnsignedTx,
NoMorePairs,
UniqueIdMismatch {
expected: Txid,
actual: Txid,
},
NonStandardSighashType(u32),
HashParseError(hashes::FromSliceError),
InvalidPreimageHashPair {
hash_type: PsetHash,
preimage: Vec<u8>,
hash: Vec<u8>,
},
MergeConflict(String),
ConsensusEncoding,
TooLargePset,
ExpiredPsbtv0Field,
IncorrectPsetVersion,
MissingTxVersion,
MissingInputCount,
MissingOutputCount,
MissingInputPrevTxId,
MissingInputPrevVout,
SecpScalarSizeError(usize),
MissingOutputValue,
MissingOutputAsset,
MissingOutputSpk,
MissingBlinderIndex,
MissingBlindingInfo,
InputCountMismatch,
OutputCountMismatch,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey),
Error::InvalidProprietaryKey => write!(
f,
"non-proprietary key type found when proprietary key was expected"
),
Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey),
Error::LocktimeConflict => write!(f, "conflicting locktime requirements"),
Error::UniqueIdMismatch {
expected: ref e,
actual: ref a,
} => write!(f, "different id: expected {}, actual {}", e, a),
Error::NonStandardSighashType(ref sht) => {
write!(f, "non-standard sighash type: {}", sht)
}
Error::InvalidMagic => f.write_str("invalid magic"),
Error::InvalidSeparator => f.write_str("invalid separator"),
Error::UnsignedTxHasScriptSigs => {
f.write_str("the unsigned transaction has script sigs")
}
Error::UnsignedTxHasScriptWitnesses => {
f.write_str("the unsigned transaction has script witnesses")
}
Error::MustHaveUnsignedTx => {
f.write_str("partially signed transactions must have an unsigned transaction")
}
Error::NoMorePairs => f.write_str("no more key-value pairs for this pset map"),
Error::HashParseError(e) => write!(f, "Hash Parse Error: {}", e),
Error::InvalidPreimageHashPair {
ref preimage,
ref hash,
ref hash_type,
} => {
write!(
f,
"Preimage {:?} does not match {:?} hash {:?}",
preimage, hash_type, hash
)
}
Error::MergeConflict(ref s) => {
write!(f, "Merge conflict: {}", s)
}
Error::ConsensusEncoding => f.write_str("bitcoin consensus encoding error"),
Error::TooLargePset => {
write!(f, "Psets with 10_000 or more inputs/outputs unsupported")
}
Error::ExpiredPsbtv0Field => {
f.write_str("psbt v0 field specified in pset(based on pset)")
}
Error::IncorrectPsetVersion => f.write_str("Pset version must be 2"),
Error::MissingTxVersion => f.write_str("PSET missing global transaction version"),
Error::MissingInputCount => f.write_str("PSET missing input count"),
Error::MissingOutputCount => f.write_str("PSET missing output count"),
Error::MissingInputPrevTxId => f.write_str("PSET input missing previous txid"),
Error::MissingInputPrevVout => f.write_str("PSET input missing previous output index"),
Error::SecpScalarSizeError(actual) => {
write!(
f,
"PSET blinding scalars must be 32 bytes. Found {} bytes",
actual
)
}
Error::MissingOutputValue => f.write_str(
"PSET output missing value. Must have \
at least one of explicit/confidential value set",
),
Error::MissingOutputAsset => f.write_str(
"PSET output missing asset. Must have \
at least one of explicit/confidential asset set",
),
Error::MissingBlinderIndex => {
f.write_str("Output is blinded but does not have a blinder index")
}
Error::MissingBlindingInfo => f.write_str(
"Output marked for blinding, but missing \
some blinding information",
),
Error::MissingOutputSpk => f.write_str(
"PSET output missing script pubkey. Must have \
exactly one of explicit/confidential script pubkey set",
),
Error::InputCountMismatch => f.write_str(
"PSET input count global field must \
match the number of inputs",
),
Error::OutputCountMismatch => f.write_str(
"PSET output count global field must \
match the number of outputs",
),
}
}
}
impl error::Error for Error {}
#[doc(hidden)]
impl From<hashes::FromSliceError> for Error {
fn from(e: hashes::FromSliceError) -> Error {
Error::HashParseError(e)
}
}
impl From<encode::Error> for Error {
fn from(err: encode::Error) -> Self {
match err {
encode::Error::PsetError(err) => err,
_ => Error::ConsensusEncoding,
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum PsetBlindError {
InputTxOutSecretLen,
OutputTxOutSecretLen,
BlinderIndexOutOfBounds(usize, usize),
MissingInputBlinds(usize, usize),
AtleastOneOutputBlind,
MustHaveExplicitTxOut(usize),
MissingWitnessUtxo(usize),
ConfidentialTxOutError(usize, ConfidentialTxOutError),
BlindingProofsCreationError(usize, secp256k1_zkp::Error),
BlindingIssuanceUnsupported(usize),
}
impl fmt::Display for PsetBlindError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
PsetBlindError::InputTxOutSecretLen => {
write!(f, "Input Secret Count must match pset input count")
}
PsetBlindError::OutputTxOutSecretLen => {
write!(f, "Output Secret Count must match pset output count")
}
PsetBlindError::AtleastOneOutputBlind => {
write!(f, "Atleast one output secrets should be provided")
}
PsetBlindError::BlinderIndexOutOfBounds(i, bl) => {
write!(
f,
"Blinder index {} for output index {} must be less \
than total input count",
bl, i
)
}
PsetBlindError::MissingInputBlinds(i, bl) => {
write!(f, "Output index {} expects blinding input index {}", i, bl)
}
PsetBlindError::MustHaveExplicitTxOut(i) => {
write!(f, "Output index {} must be a explicit txout", i)
}
PsetBlindError::MissingWitnessUtxo(i) => {
write!(f, "Input index {} must have witness utxo", i)
}
PsetBlindError::ConfidentialTxOutError(i, e) => {
write!(f, "Blinding error {} at output index {}", e, i)
}
PsetBlindError::BlindingProofsCreationError(i, e) => {
write!(
f,
"Blinding proof creation error {} at output index {}",
e, i
)
}
PsetBlindError::BlindingIssuanceUnsupported(i) => {
write!(f, "Blinding issuance is not supported, set blinded_issuance to 0 at input index {}", i)
}
}
}
}
impl error::Error for PsetBlindError {}