#[cfg(feature = "silent-payments")]
pub mod dleq;
mod error;
mod extract;
mod map;
#[cfg(feature = "miniscript")]
mod miniscript;
use core::fmt;
use core::marker::PhantomData;
#[cfg(feature = "std")]
use std::collections::{HashMap, HashSet};
use bitcoin::bip32::{self, KeySource, Xpriv};
use bitcoin::key::{PrivateKey, PublicKey};
use bitcoin::locktime::absolute;
use bitcoin::secp256k1::{Message, Secp256k1, Signing};
use bitcoin::sighash::{EcdsaSighashType, SighashCache};
use bitcoin::{ecdsa, transaction, Amount, Sequence, Transaction, TxOut, Txid};
use crate::error::{write_err, FeeError, FundingUtxoError};
use crate::prelude::*;
use crate::v2::map::Map;
#[rustfmt::skip] #[doc(inline)]
pub use self::{
error::{
DeserializeError, DetermineLockTimeError, IndexOutOfBoundsError, InputsNotModifiableError,
NotUnsignedError, OutputsNotModifiableError, PartialSigsSighashTypeError,
PsbtNotModifiableError, SignError,
},
extract::{Extractor, ExtractError, ExtractTxError, ExtractTxFeeRateError},
map::{
global::{self, Global},
input::{self, Input, InputBuilder},
output::{self, Output, OutputBuilder},
},
};
#[cfg(feature = "base64")]
pub use self::display_from_str::ParsePsbtError;
#[cfg(feature = "silent-payments")]
pub use self::dleq::{DleqProof, InvalidLengthError};
#[cfg(feature = "miniscript")]
pub use self::miniscript::{
FinalizeError, FinalizeInputError, Finalizer, InputError, InterpreterCheckError,
InterpreterCheckInputError,
};
pub fn combine(this: Psbt, that: Psbt) -> Result<Psbt, CombineError> { this.combine_with(that) }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Creator(Psbt);
impl Creator {
pub fn new() -> Self {
let psbt = Psbt {
global: Global::default(),
inputs: Default::default(),
outputs: Default::default(),
};
Creator(psbt)
}
pub fn fallback_lock_time(mut self, fallback: absolute::LockTime) -> Self {
self.0.global.fallback_lock_time = Some(fallback);
self
}
pub fn sighash_single(mut self) -> Self {
self.0.global.set_sighash_single_flag();
self
}
pub fn inputs_modifiable(mut self) -> Self {
self.0.global.set_inputs_modifiable_flag();
self
}
pub fn outputs_modifiable(mut self) -> Self {
self.0.global.set_outputs_modifiable_flag();
self
}
pub fn transaction_version(mut self, version: transaction::Version) -> Self {
self.0.global.tx_version = version;
self
}
pub fn constructor_modifiable(self) -> Constructor<Modifiable> {
let mut psbt = self.0;
psbt.global.set_inputs_modifiable_flag();
psbt.global.set_outputs_modifiable_flag();
Constructor(psbt, PhantomData)
}
pub fn constructor_inputs_only_modifiable(self) -> Constructor<InputsOnlyModifiable> {
let mut psbt = self.0;
psbt.global.set_inputs_modifiable_flag();
psbt.global.clear_outputs_modifiable_flag();
Constructor(psbt, PhantomData)
}
pub fn constructor_outputs_only_modifiable(self) -> Constructor<OutputsOnlyModifiable> {
let mut psbt = self.0;
psbt.global.clear_inputs_modifiable_flag();
psbt.global.set_outputs_modifiable_flag();
Constructor(psbt, PhantomData)
}
pub fn psbt(self) -> Psbt { self.0 }
}
impl Default for Creator {
fn default() -> Self { Self::new() }
}
pub enum Modifiable {}
pub enum InputsOnlyModifiable {}
pub enum OutputsOnlyModifiable {}
mod sealed {
pub trait Mod {}
impl Mod for super::Modifiable {}
impl Mod for super::InputsOnlyModifiable {}
impl Mod for super::OutputsOnlyModifiable {}
}
pub trait Mod: sealed::Mod + Sync + Send + Sized + Unpin {}
impl Mod for Modifiable {}
impl Mod for InputsOnlyModifiable {}
impl Mod for OutputsOnlyModifiable {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Constructor<T>(Psbt, PhantomData<T>);
impl<T: Mod> Constructor<T> {
pub fn no_more_inputs(mut self) -> Self {
self.0.global.clear_inputs_modifiable_flag();
self
}
pub fn no_more_outputs(mut self) -> Self {
self.0.global.clear_outputs_modifiable_flag();
self
}
pub fn updater(self) -> Result<Updater, DetermineLockTimeError> {
self.no_more_inputs().no_more_outputs().psbt().map(Updater)
}
pub fn psbt(self) -> Result<Psbt, DetermineLockTimeError> {
let _ = self.0.determine_lock_time()?;
Ok(self.0)
}
}
impl Constructor<Modifiable> {
pub fn new(psbt: Psbt) -> Result<Self, PsbtNotModifiableError> {
if !psbt.global.is_inputs_modifiable() {
Err(InputsNotModifiableError.into())
} else if !psbt.global.is_outputs_modifiable() {
Err(OutputsNotModifiableError.into())
} else {
Ok(Self(psbt, PhantomData))
}
}
pub fn input(mut self, input: Input) -> Self {
self.0.inputs.push(input);
self.0.global.input_count += 1;
self
}
pub fn output(mut self, output: Output) -> Self {
self.0.outputs.push(output);
self.0.global.output_count += 1;
self
}
}
impl Default for Constructor<Modifiable> {
fn default() -> Self { Creator::new().constructor_modifiable() }
}
impl Constructor<InputsOnlyModifiable> {
pub fn new(psbt: Psbt) -> Result<Self, InputsNotModifiableError> {
if psbt.global.is_inputs_modifiable() {
Ok(Self(psbt, PhantomData))
} else {
Err(InputsNotModifiableError)
}
}
pub fn input(mut self, input: Input) -> Self {
self.0.inputs.push(input);
self.0.global.input_count += 1;
self
}
}
impl Default for Constructor<InputsOnlyModifiable> {
fn default() -> Self { Creator::new().constructor_inputs_only_modifiable() }
}
impl Constructor<OutputsOnlyModifiable> {
pub fn new(psbt: Psbt) -> Result<Self, OutputsNotModifiableError> {
if psbt.global.is_outputs_modifiable() {
Ok(Self(psbt, PhantomData))
} else {
Err(OutputsNotModifiableError)
}
}
pub fn output(mut self, output: Output) -> Self {
self.0.outputs.push(output);
self.0.global.output_count += 1;
self
}
}
impl Default for Constructor<OutputsOnlyModifiable> {
fn default() -> Self { Creator::new().constructor_outputs_only_modifiable() }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Updater(Psbt);
impl Updater {
pub fn new(psbt: Psbt) -> Result<Self, DetermineLockTimeError> {
let _ = psbt.determine_lock_time()?;
Ok(Self(psbt))
}
pub fn id(&self) -> Txid {
self.0.id().expect("Updater guarantees lock time can be determined")
}
pub fn set_sequence(
mut self,
n: Sequence,
input_index: usize,
) -> Result<Updater, IndexOutOfBoundsError> {
let input = self.0.checked_input_mut(input_index)?;
input.sequence = Some(n);
Ok(self)
}
pub fn psbt(self) -> Psbt { self.0 }
}
impl TryFrom<Psbt> for Updater {
type Error = DetermineLockTimeError;
fn try_from(psbt: Psbt) -> Result<Self, Self::Error> { Self::new(psbt) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Signer(Psbt);
impl Signer {
pub fn new(psbt: Psbt) -> Result<Self, DetermineLockTimeError> {
let _ = psbt.determine_lock_time()?;
Ok(Self(psbt))
}
pub fn id(&self) -> Result<Txid, DetermineLockTimeError> { self.0.id() }
pub fn unsigned_tx(&self) -> Transaction {
self.0.unsigned_tx().expect("Signer guarantees lock time can be determined")
}
pub fn sign<C, K>(
self,
k: &K,
secp: &Secp256k1<C>,
) -> Result<(Psbt, SigningKeys), (SigningKeys, SigningErrors)>
where
C: Signing,
K: GetKey,
{
let tx = self.unsigned_tx();
let mut psbt = self.psbt();
psbt.sign(tx, k, secp).map(|signing_keys| (psbt, signing_keys))
}
pub fn ecdsa_clear_tx_modifiable(&mut self, ty: EcdsaSighashType) {
self.0.clear_tx_modifiable(ty as u8)
}
pub fn psbt(self) -> Psbt { self.0 }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Psbt {
pub global: Global,
pub inputs: Vec<Input>,
pub outputs: Vec<Output>,
}
impl Psbt {
fn id(&self) -> Result<Txid, DetermineLockTimeError> {
let mut tx = self.unsigned_tx()?;
tx.input.iter_mut().for_each(|input| input.sequence = Sequence::ZERO);
Ok(tx.compute_txid())
}
fn unsigned_tx(&self) -> Result<Transaction, DetermineLockTimeError> {
let lock_time = self.determine_lock_time()?;
Ok(Transaction {
version: self.global.tx_version,
lock_time,
input: self.inputs.iter().map(|input| input.unsigned_tx_in()).collect(),
output: self.outputs.iter().map(|ouput| ouput.tx_out()).collect(),
})
}
pub fn determine_lock_time(&self) -> Result<absolute::LockTime, DetermineLockTimeError> {
let require_time_based_lock_time =
self.inputs.iter().any(|input| input.requires_time_based_lock_time());
let require_height_based_lock_time =
self.inputs.iter().any(|input| input.requires_height_based_lock_time());
if require_time_based_lock_time && require_height_based_lock_time {
return Err(DetermineLockTimeError);
}
let have_lock_time = self.inputs.iter().any(|input| input.has_lock_time());
let lock = if have_lock_time {
let all_inputs_satisfied_with_height_based_lock_time =
self.inputs.iter().all(|input| input.is_satisfied_with_height_based_lock_time());
if all_inputs_satisfied_with_height_based_lock_time {
let height = self
.inputs
.iter()
.map(|input| input.min_height)
.max()
.expect("we know we have at least one non-none min_height field")
.expect("so we know that max is non-none");
absolute::LockTime::from(height)
} else {
let time = self
.inputs
.iter()
.map(|input| input.min_time)
.max()
.expect("we know we have at least one non-none min_height field")
.expect("so we know that max is non-none");
absolute::LockTime::from(time)
}
} else {
self.global.fallback_lock_time.unwrap_or(absolute::LockTime::ZERO)
};
Ok(lock)
}
pub fn is_finalized(&self) -> bool { self.inputs.iter().all(|input| input.is_finalized()) }
pub fn serialize_hex(&self) -> String { self.serialize().to_lower_hex_string() }
pub fn serialize(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(b"psbt");
buf.push(0xff_u8);
buf.extend(self.global.serialize_map());
for i in &self.inputs {
buf.extend(i.serialize_map());
}
for i in &self.outputs {
buf.extend(i.serialize_map());
}
buf
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, DeserializeError> {
use DeserializeError::*;
const MAGIC_BYTES: &[u8] = b"psbt";
if bytes.get(0..MAGIC_BYTES.len()) != Some(MAGIC_BYTES) {
return Err(InvalidMagic);
}
const PSBT_SERPARATOR: u8 = 0xff_u8;
if bytes.get(MAGIC_BYTES.len()) != Some(&PSBT_SERPARATOR) {
return Err(InvalidSeparator);
}
let mut d = bytes.get(5..).ok_or(NoMorePairs)?;
let global = Global::decode(&mut d)?;
let inputs: Vec<Input> = {
let inputs_len: usize = global.input_count;
let mut inputs: Vec<Input> = Vec::with_capacity(inputs_len);
for _ in 0..inputs_len {
inputs.push(Input::decode(&mut d)?);
}
inputs
};
let outputs: Vec<Output> = {
let outputs_len: usize = global.output_count;
let mut outputs: Vec<Output> = Vec::with_capacity(outputs_len);
for _ in 0..outputs_len {
outputs.push(Output::decode(&mut d)?)
}
outputs
};
Ok(Psbt { global, inputs, outputs })
}
pub fn iter_funding_utxos(&self) -> impl Iterator<Item = Result<&TxOut, FundingUtxoError>> {
self.inputs.iter().map(|input| input.funding_utxo())
}
pub fn combine_with(mut self, other: Self) -> Result<Psbt, CombineError> {
self.global.combine(other.global)?;
for (self_input, other_input) in self.inputs.iter_mut().zip(other.inputs.into_iter()) {
self_input.combine(other_input)?;
}
for (self_output, other_output) in self.outputs.iter_mut().zip(other.outputs.into_iter()) {
self_output.combine(other_output)?;
}
Ok(self)
}
fn clear_tx_modifiable(&mut self, sighash_type: u8) {
let ty = sighash_type;
if !(ty == 0x81 || ty == 0x82 || ty == 0x83) {
self.global.clear_inputs_modifiable_flag();
}
if !(ty == 0x02 || ty == 0x82) {
self.global.clear_outputs_modifiable_flag();
}
if ty == 0x03 || ty == 0x83 {
self.global.set_sighash_single_flag();
}
}
fn sign<C, K>(
&mut self,
tx: Transaction,
k: &K,
secp: &Secp256k1<C>,
) -> Result<SigningKeys, (SigningKeys, SigningErrors)>
where
C: Signing,
K: GetKey,
{
let mut cache = SighashCache::new(&tx);
let mut used = BTreeMap::new();
let mut errors = BTreeMap::new();
for i in 0..self.global.input_count {
if let Ok(SigningAlgorithm::Ecdsa) = self.signing_algorithm(i) {
match self.bip32_sign_ecdsa(k, i, &mut cache, secp) {
Ok(v) => {
used.insert(i, v);
}
Err(e) => {
errors.insert(i, e);
}
}
};
}
if errors.is_empty() {
Ok(used)
} else {
Err((used, errors))
}
}
fn bip32_sign_ecdsa<C, K, T>(
&mut self,
k: &K,
input_index: usize,
cache: &mut SighashCache<T>,
secp: &Secp256k1<C>,
) -> Result<Vec<PublicKey>, SignError>
where
C: Signing,
T: Borrow<Transaction>,
K: GetKey,
{
let msg_sighash_ty_res = self.sighash_ecdsa(input_index, cache);
let sighash_ty = msg_sighash_ty_res.clone().ok().map(|(_msg, sighash_ty)| sighash_ty);
let input = &mut self.inputs[input_index]; let mut used = vec![];
for (pk, key_source) in input.bip32_derivations.iter() {
let sk = if let Ok(Some(sk)) = k.get_key(KeyRequest::Bip32(key_source.clone()), secp) {
sk
} else if let Ok(Some(sk)) = k.get_key(KeyRequest::Pubkey(*pk), secp) {
sk
} else {
continue;
};
let (msg, sighash_ty) = match msg_sighash_ty_res {
Err(e) => return Err(e),
Ok((msg, sighash_ty)) => (msg, sighash_ty),
};
let sig = ecdsa::Signature {
signature: secp.sign_ecdsa(&msg, &sk.inner),
sighash_type: sighash_ty,
};
let pk = sk.public_key(secp);
input.partial_sigs.insert(pk, sig);
used.push(pk);
}
let ty = sighash_ty.expect("at this stage we know its ok");
self.clear_tx_modifiable(ty as u8);
Ok(used)
}
pub fn sighash_ecdsa<T: Borrow<Transaction>>(
&self,
input_index: usize,
cache: &mut SighashCache<T>,
) -> Result<(Message, EcdsaSighashType), SignError> {
use OutputType::*;
if self.signing_algorithm(input_index)? != SigningAlgorithm::Ecdsa {
return Err(SignError::WrongSigningAlgorithm);
}
let input = self.checked_input(input_index)?;
let utxo = input.funding_utxo()?;
let spk = &utxo.script_pubkey;
let hash_ty = input.ecdsa_hash_ty().map_err(|_| SignError::InvalidSighashType)?;
match self.output_type(input_index)? {
Bare => {
let sighash = cache
.legacy_signature_hash(input_index, spk, hash_ty.to_u32())
.expect("input checked above");
Ok((Message::from(sighash), hash_ty))
}
Sh => {
let script_code =
input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
let sighash = cache
.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())
.expect("input checked above");
Ok((Message::from(sighash), hash_ty))
}
Wpkh => {
let sighash = cache.p2wpkh_signature_hash(input_index, spk, utxo.value, hash_ty)?;
Ok((Message::from(sighash), hash_ty))
}
ShWpkh => {
let redeem_script = input.redeem_script.as_ref().expect("checked above");
let sighash =
cache.p2wpkh_signature_hash(input_index, redeem_script, utxo.value, hash_ty)?;
Ok((Message::from(sighash), hash_ty))
}
Wsh | ShWsh => {
let witness_script =
input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?;
let sighash = cache
.p2wsh_signature_hash(input_index, witness_script, utxo.value, hash_ty)
.map_err(SignError::SegwitV0Sighash)?;
Ok((Message::from(sighash), hash_ty))
}
Tr => {
Err(SignError::Unsupported)
}
}
}
fn checked_input(&self, index: usize) -> Result<&Input, IndexOutOfBoundsError> {
self.check_input_index(index)?;
Ok(&self.inputs[index])
}
fn checked_input_mut(&mut self, index: usize) -> Result<&mut Input, IndexOutOfBoundsError> {
self.check_input_index(index)?;
Ok(&mut self.inputs[index])
}
fn check_input_index(&self, index: usize) -> Result<(), IndexOutOfBoundsError> {
if index >= self.inputs.len() {
return Err(IndexOutOfBoundsError::Inputs { index, length: self.inputs.len() });
}
if index >= self.global.input_count {
return Err(IndexOutOfBoundsError::Count { index, count: self.global.input_count });
}
Ok(())
}
fn signing_algorithm(&self, input_index: usize) -> Result<SigningAlgorithm, SignError> {
let output_type = self.output_type(input_index)?;
Ok(output_type.signing_algorithm())
}
fn output_type(&self, input_index: usize) -> Result<OutputType, SignError> {
let input = self.checked_input(input_index)?;
let utxo = input.funding_utxo()?;
let spk = utxo.script_pubkey.clone();
if !(spk.is_witness_program() || spk.is_p2sh()) {
return Ok(OutputType::Bare);
}
if spk.is_p2wpkh() {
return Ok(OutputType::Wpkh);
}
if spk.is_p2wsh() {
return Ok(OutputType::Wsh);
}
if spk.is_p2sh() {
if input.redeem_script.as_ref().map(|s| s.is_p2wpkh()).unwrap_or(false) {
return Ok(OutputType::ShWpkh);
}
if input.redeem_script.as_ref().map(|x| x.is_p2wsh()).unwrap_or(false) {
return Ok(OutputType::ShWsh);
}
return Ok(OutputType::Sh);
}
if spk.is_p2tr() {
return Ok(OutputType::Tr);
}
Err(SignError::UnknownOutputType)
}
pub fn fee(&self) -> Result<Amount, FeeError> {
use FeeError::*;
let mut input_value: u64 = 0;
for input in self.iter_funding_utxos() {
input_value = input_value.checked_add(input?.value.to_sat()).ok_or(InputOverflow)?;
}
let mut output_value: u64 = 0;
for output in &self.outputs {
output_value =
output_value.checked_add(output.amount.to_sat()).ok_or(OutputOverflow)?;
}
input_value.checked_sub(output_value).map(Amount::from_sat).ok_or(Negative)
}
#[cfg(feature = "miniscript")]
pub(crate) fn check_partial_sigs_sighash_type(
&self,
) -> Result<(), PartialSigsSighashTypeError> {
use PartialSigsSighashTypeError::*;
for (input_index, input) in self.inputs.iter().enumerate() {
let target_ecdsa_sighash_ty = match input.sighash_type {
Some(psbt_hash_ty) => psbt_hash_ty
.ecdsa_hash_ty()
.map_err(|error| NonStandardInputSighashType { input_index, error })?,
None => EcdsaSighashType::All,
};
for (key, ecdsa_sig) in &input.partial_sigs {
let flag = EcdsaSighashType::from_standard(ecdsa_sig.sighash_type as u32)
.map_err(|error| NonStandardPartialSigsSighashType { input_index, error })?;
if target_ecdsa_sighash_ty != flag {
return Err(WrongSighashFlag {
input_index,
required: target_ecdsa_sighash_ty,
got: flag,
pubkey: *key,
});
}
}
}
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum KeyRequest {
Pubkey(PublicKey),
Bip32(KeySource),
}
pub trait GetKey {
type Error: core::fmt::Debug;
fn get_key<C: Signing>(
&self,
key_request: KeyRequest,
secp: &Secp256k1<C>,
) -> Result<Option<PrivateKey>, Self::Error>;
}
impl GetKey for Xpriv {
type Error = GetKeyError;
fn get_key<C: Signing>(
&self,
key_request: KeyRequest,
secp: &Secp256k1<C>,
) -> Result<Option<PrivateKey>, Self::Error> {
match key_request {
KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
KeyRequest::Bip32((fingerprint, path)) => {
let key = if self.fingerprint(secp) == fingerprint {
let k = self.derive_priv(secp, &path)?;
Some(k.to_priv())
} else {
None
};
Ok(key)
}
}
}
}
pub type SigningKeys = BTreeMap<usize, Vec<PublicKey>>;
pub type SigningErrors = BTreeMap<usize, SignError>;
#[rustfmt::skip]
macro_rules! impl_get_key_for_set {
($set:ident) => {
impl GetKey for $set<Xpriv> {
type Error = GetKeyError;
fn get_key<C: Signing>(
&self,
key_request: KeyRequest,
secp: &Secp256k1<C>
) -> Result<Option<PrivateKey>, Self::Error> {
match key_request {
KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
KeyRequest::Bip32((fingerprint, path)) => {
for xpriv in self.iter() {
if xpriv.parent_fingerprint == fingerprint {
let k = xpriv.derive_priv(secp, &path)?;
return Ok(Some(k.to_priv()));
}
}
Ok(None)
}
}
}
}}}
impl_get_key_for_set!(BTreeSet);
#[cfg(feature = "std")]
impl_get_key_for_set!(HashSet);
#[rustfmt::skip]
macro_rules! impl_get_key_for_map {
($map:ident) => {
impl GetKey for $map<PublicKey, PrivateKey> {
type Error = GetKeyError;
fn get_key<C: Signing>(
&self,
key_request: KeyRequest,
_: &Secp256k1<C>,
) -> Result<Option<PrivateKey>, Self::Error> {
match key_request {
KeyRequest::Pubkey(pk) => Ok(self.get(&pk).cloned()),
KeyRequest::Bip32(_) => Err(GetKeyError::NotSupported),
}
}
}}}
impl_get_key_for_map!(BTreeMap);
#[cfg(feature = "std")]
impl_get_key_for_map!(HashMap);
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum GetKeyError {
Bip32(bip32::Error),
NotSupported,
}
impl fmt::Display for GetKeyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use GetKeyError::*;
match *self {
Bip32(ref e) => write_err!(f, "a bip23 error"; e),
NotSupported =>
f.write_str("the GetKey operation is not supported for this key request"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for GetKeyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use GetKeyError::*;
match *self {
NotSupported => None,
Bip32(ref e) => Some(e),
}
}
}
impl From<bip32::Error> for GetKeyError {
fn from(e: bip32::Error) -> Self { GetKeyError::Bip32(e) }
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum OutputType {
Bare,
Wpkh,
Wsh,
ShWpkh,
ShWsh,
Sh,
Tr,
}
impl OutputType {
pub fn signing_algorithm(&self) -> SigningAlgorithm {
use OutputType::*;
match self {
Bare | Wpkh | Wsh | ShWpkh | ShWsh | Sh => SigningAlgorithm::Ecdsa,
Tr => SigningAlgorithm::Schnorr,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SigningAlgorithm {
Ecdsa,
Schnorr,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum DecodeError {
InvalidMagic,
InvalidSeparator,
NoMorePairs,
Global(global::DecodeError),
Input(input::DecodeError),
Output(output::DecodeError),
}
impl fmt::Display for DecodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use DecodeError::*;
match *self {
InvalidMagic => f.write_str("invalid magic"),
InvalidSeparator => f.write_str("invalid separator"),
NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
Global(ref e) => write_err!(f, "global map decode error"; e),
Input(ref e) => write_err!(f, "input map decode error"; e),
Output(ref e) => write_err!(f, "output map decode error"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for DecodeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use DecodeError::*;
match *self {
InvalidMagic | InvalidSeparator | NoMorePairs => None,
Global(ref e) => Some(e),
Input(ref e) => Some(e),
Output(ref e) => Some(e),
}
}
}
impl From<global::DecodeError> for DecodeError {
fn from(e: global::DecodeError) -> Self { Self::Global(e) }
}
impl From<input::DecodeError> for DecodeError {
fn from(e: input::DecodeError) -> Self { Self::Input(e) }
}
impl From<output::DecodeError> for DecodeError {
fn from(e: output::DecodeError) -> Self { Self::Output(e) }
}
#[cfg(feature = "base64")]
mod display_from_str {
use core::fmt::{self, Display, Formatter};
use core::str::FromStr;
use bitcoin::base64::display::Base64Display;
use bitcoin::base64::prelude::{Engine as _, BASE64_STANDARD};
use super::*;
impl Display for Psbt {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", Base64Display::new(&self.serialize(), &BASE64_STANDARD))
}
}
impl FromStr for Psbt {
type Err = ParsePsbtError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let data = BASE64_STANDARD.decode(s).map_err(ParsePsbtError::Base64Encoding)?;
Psbt::deserialize(&data).map_err(ParsePsbtError::PsbtEncoding)
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ParsePsbtError {
PsbtEncoding(DeserializeError),
Base64Encoding(bitcoin::base64::DecodeError),
}
impl Display for ParsePsbtError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
use self::ParsePsbtError::*;
match *self {
PsbtEncoding(ref e) => write_err!(f, "error in internal PSBT data structure"; e),
Base64Encoding(ref e) => write_err!(f, "error in PSBT base64 encoding"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParsePsbtError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::ParsePsbtError::*;
match self {
PsbtEncoding(e) => Some(e),
Base64Encoding(e) => Some(e),
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum CombineError {
Global(global::CombineError),
Input(input::CombineError),
Output(output::CombineError),
}
impl fmt::Display for CombineError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use CombineError::*;
match *self {
Global(ref e) => write_err!(f, "error while combining the global maps"; e),
Input(ref e) => write_err!(f, "error while combining the input maps"; e),
Output(ref e) => write_err!(f, "error while combining the output maps"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for CombineError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use CombineError::*;
match *self {
Global(ref e) => Some(e),
Input(ref e) => Some(e),
Output(ref e) => Some(e),
}
}
}
impl From<global::CombineError> for CombineError {
fn from(e: global::CombineError) -> Self { Self::Global(e) }
}
impl From<input::CombineError> for CombineError {
fn from(e: input::CombineError) -> Self { Self::Input(e) }
}
impl From<output::CombineError> for CombineError {
fn from(e: output::CombineError) -> Self { Self::Output(e) }
}