feat: add json_serialize method on psbt type

This commit is contained in:
thunderbiscuit 2024-05-10 16:31:21 -04:00
parent 093eb1fc7e
commit 9790d60324
No known key found for this signature in database
GPG Key ID: 88253696EB836462
3 changed files with 109 additions and 88 deletions

View File

@ -204,7 +204,7 @@ interface PsbtError {
Version(string error_message); Version(string error_message);
PartialDataConsumption(); PartialDataConsumption();
Io(string error_message); Io(string error_message);
OtherPsbtError(); OtherPsbtErr();
}; };
[Error] [Error]

View File

@ -222,8 +222,7 @@ impl Psbt {
} }
pub(crate) fn fee(&self) -> Result<u64, PsbtError> { pub(crate) fn fee(&self) -> Result<u64, PsbtError> {
self self.0
.0
.lock() .lock()
.unwrap() .unwrap()
.fee() .fee()
@ -231,10 +230,7 @@ impl Psbt {
.map_err(PsbtError::from) .map_err(PsbtError::from)
} }
pub(crate) fn combine( pub(crate) fn combine(&self, other: Arc<Psbt>) -> Result<Arc<Psbt>, PsbtError> {
&self,
other: Arc<Psbt>,
) -> Result<Arc<Psbt>, PsbtError> {
let mut original_psbt = self.0.lock().unwrap().clone(); let mut original_psbt = self.0.lock().unwrap().clone();
let other_psbt = other.0.lock().unwrap().clone(); let other_psbt = other.0.lock().unwrap().clone();
original_psbt.combine(other_psbt)?; original_psbt.combine(other_psbt)?;

View File

@ -1,10 +1,15 @@
use crate::bitcoin::{OutPoint}; use crate::bitcoin::OutPoint;
use bdk::bitcoin::address::Error as BdkAddressError;
use bdk::bitcoin::address::ParseError; use bdk::bitcoin::address::ParseError;
use bdk::bitcoin::amount::ParseAmountError as BdkParseAmountError;
use bdk::bitcoin::bip32::Error as BdkBip32Error; use bdk::bitcoin::bip32::Error as BdkBip32Error;
use bdk::bitcoin::consensus::encode::Error as BdkEncodeError;
use bdk::bitcoin::psbt::Error as BdkPsbtError;
use bdk::bitcoin::psbt::ExtractTxError as BdkExtractTxError;
use bdk::bitcoin::psbt::PsbtParseError as BdkPsbtParseError; use bdk::bitcoin::psbt::PsbtParseError as BdkPsbtParseError;
use bdk::bitcoin::Network; use bdk::bitcoin::Network;
use bdk::bitcoin::psbt::Error as BdkPsbtError; use bdk::chain::local_chain::CannotConnectError as BdkCannotConnectError;
use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError; use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError;
use bdk::descriptor::DescriptorError as BdkDescriptorError; use bdk::descriptor::DescriptorError as BdkDescriptorError;
use bdk::keys::bip39::Error as BdkBip39Error; use bdk::keys::bip39::Error as BdkBip39Error;
@ -14,21 +19,12 @@ use bdk::wallet::error::CreateTxError as BdkCreateTxError;
use bdk::wallet::signer::SignerError as BdkSignerError; use bdk::wallet::signer::SignerError as BdkSignerError;
use bdk::wallet::tx_builder::AddUtxoError; use bdk::wallet::tx_builder::AddUtxoError;
use bdk::wallet::NewOrLoadError; use bdk::wallet::NewOrLoadError;
use bdk::KeychainKind;
use bdk_electrum::electrum_client::Error as BdkElectrumError; use bdk_electrum::electrum_client::Error as BdkElectrumError;
use bdk_esplora::esplora_client::{Error as BdkEsploraError, Error}; use bdk_esplora::esplora_client::{Error as BdkEsploraError, Error};
use bdk_file_store::FileError as BdkFileError; use bdk_file_store::FileError as BdkFileError;
use bitcoin_internals::hex::display::DisplayHex; use bitcoin_internals::hex::display::DisplayHex;
use bdk::bitcoin::amount::ParseAmountError as BdkParseAmountError;
use std::convert::TryInto;
use bdk::bitcoin::address::Error as BdkAddressError;
use bdk::bitcoin::consensus::encode::Error as BdkEncodeError;
use bdk::bitcoin::psbt::ExtractTxError as BdkExtractTxError;
use bdk::chain::local_chain::CannotConnectError as BdkCannotConnectError;
use bdk::KeychainKind;
use std::convert::TryInto; use std::convert::TryInto;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -436,17 +432,13 @@ pub enum PsbtError {
PsbtUtxoOutOfBounds, PsbtUtxoOutOfBounds,
#[error("invalid key: {key}")] #[error("invalid key: {key}")]
InvalidKey { InvalidKey { key: String },
key: String,
},
#[error("non-proprietary key type found when proprietary key was expected")] #[error("non-proprietary key type found when proprietary key was expected")]
InvalidProprietaryKey, InvalidProprietaryKey,
#[error("duplicate key: {key}")] #[error("duplicate key: {key}")]
DuplicateKey { DuplicateKey { key: String },
key: String,
},
#[error("the unsigned transaction has script sigs")] #[error("the unsigned transaction has script sigs")]
UnsignedTxHasScriptSigs, UnsignedTxHasScriptSigs,
@ -465,28 +457,20 @@ pub enum PsbtError {
UnexpectedUnsignedTx, UnexpectedUnsignedTx,
#[error("non-standard sighash type: {sighash}")] #[error("non-standard sighash type: {sighash}")]
NonStandardSighashType { NonStandardSighashType { sighash: u32 },
sighash: u32,
},
#[error("invalid hash when parsing slice: {hash}")] #[error("invalid hash when parsing slice: {hash}")]
InvalidHash { InvalidHash { hash: String },
hash: String,
},
// Note: to provide the data returned in Rust, we need to dereference the fields // Note: to provide the data returned in Rust, we need to dereference the fields
#[error("preimage does not match")] #[error("preimage does not match")]
InvalidPreimageHashPair, InvalidPreimageHashPair,
#[error("combine conflict: {xpub}")] #[error("combine conflict: {xpub}")]
CombineInconsistentKeySources { CombineInconsistentKeySources { xpub: String },
xpub: String,
},
#[error("bitcoin consensus encoding error: {encoding_error}")] #[error("bitcoin consensus encoding error: {encoding_error}")]
ConsensusEncoding { ConsensusEncoding { encoding_error: String },
encoding_error: String,
},
#[error("PSBT has a negative fee which is not allowed")] #[error("PSBT has a negative fee which is not allowed")]
NegativeFee, NegativeFee,
@ -495,27 +479,19 @@ pub enum PsbtError {
FeeOverflow, FeeOverflow,
#[error("invalid public key {error_message}")] #[error("invalid public key {error_message}")]
InvalidPublicKey { InvalidPublicKey { error_message: String },
error_message: String
},
#[error("invalid secp256k1 public key: {secp256k1_error}")] #[error("invalid secp256k1 public key: {secp256k1_error}")]
InvalidSecp256k1PublicKey { InvalidSecp256k1PublicKey { secp256k1_error: String },
secp256k1_error: String
},
#[error("invalid xonly public key")] #[error("invalid xonly public key")]
InvalidXOnlyPublicKey, InvalidXOnlyPublicKey,
#[error("invalid ECDSA signature: {error_message}")] #[error("invalid ECDSA signature: {error_message}")]
InvalidEcdsaSignature { InvalidEcdsaSignature { error_message: String },
error_message: String
},
#[error("invalid taproot signature: {error_message}")] #[error("invalid taproot signature: {error_message}")]
InvalidTaprootSignature { InvalidTaprootSignature { error_message: String },
error_message: String
},
#[error("invalid control block")] #[error("invalid control block")]
InvalidControlBlock, InvalidControlBlock,
@ -527,28 +503,22 @@ pub enum PsbtError {
Taproot, Taproot,
#[error("taproot tree error: {error_message}")] #[error("taproot tree error: {error_message}")]
TapTree { TapTree { error_message: String },
error_message: String
},
#[error("xpub key error")] #[error("xpub key error")]
XPubKey, XPubKey,
#[error("version error: {error_message}")] #[error("version error: {error_message}")]
Version { Version { error_message: String },
error_message: String
},
#[error("data not consumed entirely when explicitly deserializing")] #[error("data not consumed entirely when explicitly deserializing")]
PartialDataConsumption, PartialDataConsumption,
#[error("I/O error: {error_message}")] #[error("I/O error: {error_message}")]
Io { Io { error_message: String },
error_message: String
},
#[error("other PSBT error")] #[error("other PSBT error")]
OtherPsbtError, OtherPsbtErr,
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -1113,9 +1083,13 @@ impl From<BdkPsbtError> for PsbtError {
BdkPsbtError::MissingUtxo => PsbtError::MissingUtxo, BdkPsbtError::MissingUtxo => PsbtError::MissingUtxo,
BdkPsbtError::InvalidSeparator => PsbtError::InvalidSeparator, BdkPsbtError::InvalidSeparator => PsbtError::InvalidSeparator,
BdkPsbtError::PsbtUtxoOutOfbounds => PsbtError::PsbtUtxoOutOfBounds, BdkPsbtError::PsbtUtxoOutOfbounds => PsbtError::PsbtUtxoOutOfBounds,
BdkPsbtError::InvalidKey(key) => PsbtError::InvalidKey { key: key.to_string() }, BdkPsbtError::InvalidKey(key) => PsbtError::InvalidKey {
key: key.to_string(),
},
BdkPsbtError::InvalidProprietaryKey => PsbtError::InvalidProprietaryKey, BdkPsbtError::InvalidProprietaryKey => PsbtError::InvalidProprietaryKey,
BdkPsbtError::DuplicateKey(key) => PsbtError::DuplicateKey { key: key.to_string() }, BdkPsbtError::DuplicateKey(key) => PsbtError::DuplicateKey {
key: key.to_string(),
},
BdkPsbtError::UnsignedTxHasScriptSigs => PsbtError::UnsignedTxHasScriptSigs, BdkPsbtError::UnsignedTxHasScriptSigs => PsbtError::UnsignedTxHasScriptSigs,
BdkPsbtError::UnsignedTxHasScriptWitnesses => PsbtError::UnsignedTxHasScriptWitnesses, BdkPsbtError::UnsignedTxHasScriptWitnesses => PsbtError::UnsignedTxHasScriptWitnesses,
BdkPsbtError::MustHaveUnsignedTx => PsbtError::MustHaveUnsignedTx, BdkPsbtError::MustHaveUnsignedTx => PsbtError::MustHaveUnsignedTx,
@ -1123,31 +1097,49 @@ impl From<BdkPsbtError> for PsbtError {
BdkPsbtError::UnexpectedUnsignedTx { .. } => PsbtError::UnexpectedUnsignedTx, BdkPsbtError::UnexpectedUnsignedTx { .. } => PsbtError::UnexpectedUnsignedTx,
BdkPsbtError::NonStandardSighashType(sighash) => { BdkPsbtError::NonStandardSighashType(sighash) => {
PsbtError::NonStandardSighashType { sighash } PsbtError::NonStandardSighashType { sighash }
}
BdkPsbtError::InvalidHash(hash) => PsbtError::InvalidHash {
hash: hash.to_string(),
}, },
BdkPsbtError::InvalidHash(hash) => PsbtError::InvalidHash { hash: hash.to_string() },
BdkPsbtError::InvalidPreimageHashPair { .. } => PsbtError::InvalidPreimageHashPair, BdkPsbtError::InvalidPreimageHashPair { .. } => PsbtError::InvalidPreimageHashPair,
BdkPsbtError::CombineInconsistentKeySources(xpub) => { BdkPsbtError::CombineInconsistentKeySources(xpub) => {
PsbtError::CombineInconsistentKeySources { xpub: xpub.to_string() } PsbtError::CombineInconsistentKeySources {
}, xpub: xpub.to_string(),
BdkPsbtError::ConsensusEncoding(encoding_error) => { }
PsbtError::ConsensusEncoding { encoding_error: encoding_error.to_string() } }
BdkPsbtError::ConsensusEncoding(encoding_error) => PsbtError::ConsensusEncoding {
encoding_error: encoding_error.to_string(),
}, },
BdkPsbtError::NegativeFee => PsbtError::NegativeFee, BdkPsbtError::NegativeFee => PsbtError::NegativeFee,
BdkPsbtError::FeeOverflow => PsbtError::FeeOverflow, BdkPsbtError::FeeOverflow => PsbtError::FeeOverflow,
BdkPsbtError::InvalidPublicKey(e) => PsbtError::InvalidPublicKey { error_message: e.to_string() }, BdkPsbtError::InvalidPublicKey(e) => PsbtError::InvalidPublicKey {
BdkPsbtError::InvalidSecp256k1PublicKey(e) => PsbtError::InvalidSecp256k1PublicKey { secp256k1_error: e.to_string() }, error_message: e.to_string(),
},
BdkPsbtError::InvalidSecp256k1PublicKey(e) => PsbtError::InvalidSecp256k1PublicKey {
secp256k1_error: e.to_string(),
},
BdkPsbtError::InvalidXOnlyPublicKey => PsbtError::InvalidXOnlyPublicKey, BdkPsbtError::InvalidXOnlyPublicKey => PsbtError::InvalidXOnlyPublicKey,
BdkPsbtError::InvalidEcdsaSignature(e) => PsbtError::InvalidEcdsaSignature { error_message: e.to_string() }, BdkPsbtError::InvalidEcdsaSignature(e) => PsbtError::InvalidEcdsaSignature {
BdkPsbtError::InvalidTaprootSignature(e) => PsbtError::InvalidTaprootSignature { error_message: e.to_string() }, error_message: e.to_string(),
},
BdkPsbtError::InvalidTaprootSignature(e) => PsbtError::InvalidTaprootSignature {
error_message: e.to_string(),
},
BdkPsbtError::InvalidControlBlock => PsbtError::InvalidControlBlock, BdkPsbtError::InvalidControlBlock => PsbtError::InvalidControlBlock,
BdkPsbtError::InvalidLeafVersion => PsbtError::InvalidLeafVersion, BdkPsbtError::InvalidLeafVersion => PsbtError::InvalidLeafVersion,
BdkPsbtError::Taproot(_) => PsbtError::Taproot, BdkPsbtError::Taproot(_) => PsbtError::Taproot,
BdkPsbtError::TapTree(e) => PsbtError::TapTree { error_message: e.to_string() }, BdkPsbtError::TapTree(e) => PsbtError::TapTree {
error_message: e.to_string(),
},
BdkPsbtError::XPubKey(_) => PsbtError::XPubKey, BdkPsbtError::XPubKey(_) => PsbtError::XPubKey,
BdkPsbtError::Version(e) => PsbtError::Version { error_message: e.to_string() }, BdkPsbtError::Version(e) => PsbtError::Version {
error_message: e.to_string(),
},
BdkPsbtError::PartialDataConsumption => PsbtError::PartialDataConsumption, BdkPsbtError::PartialDataConsumption => PsbtError::PartialDataConsumption,
BdkPsbtError::Io(e) => PsbtError::Io { error_message: e.to_string() }, BdkPsbtError::Io(e) => PsbtError::Io {
_ => PsbtError::OtherPsbtError, error_message: e.to_string(),
},
_ => PsbtError::OtherPsbtErr,
} }
} }
} }
@ -1265,8 +1257,8 @@ mod test {
use crate::error::{ use crate::error::{
AddressError, Bip32Error, Bip39Error, CannotConnectError, CreateTxError, DescriptorError, AddressError, Bip32Error, Bip39Error, CannotConnectError, CreateTxError, DescriptorError,
DescriptorKeyError, ElectrumError, EsploraError, ExtractTxError, FeeRateError, DescriptorKeyError, ElectrumError, EsploraError, ExtractTxError, FeeRateError,
InspectError, ParseAmountError, PersistenceError, PsbtParseError, TransactionError, InspectError, ParseAmountError, PersistenceError, PsbtError, PsbtParseError,
TxidParseError, WalletCreationError, TransactionError, TxidParseError, WalletCreationError,
}; };
use crate::CalculateFeeError; use crate::CalculateFeeError;
use crate::OutPoint; use crate::OutPoint;
@ -1933,30 +1925,51 @@ mod test {
fn test_error_psbt() { fn test_error_psbt() {
let cases = vec![ let cases = vec![
(PsbtError::InvalidMagic, "invalid magic"), (PsbtError::InvalidMagic, "invalid magic"),
(PsbtError::MissingUtxo, "UTXO information is not present in PSBT"), (
PsbtError::MissingUtxo,
"UTXO information is not present in PSBT",
),
(PsbtError::InvalidSeparator, "invalid separator"), (PsbtError::InvalidSeparator, "invalid separator"),
(PsbtError::PsbtUtxoOutOfBounds, "output index is out of bounds of non witness script output array"), (
PsbtError::PsbtUtxoOutOfBounds,
"output index is out of bounds of non witness script output array",
),
( (
PsbtError::InvalidKey { PsbtError::InvalidKey {
key: "key".to_string(), key: "key".to_string(),
}, },
"invalid key: key", "invalid key: key",
), ),
(PsbtError::InvalidProprietaryKey, "non-proprietary key type found when proprietary key was expected"), (
PsbtError::InvalidProprietaryKey,
"non-proprietary key type found when proprietary key was expected",
),
( (
PsbtError::DuplicateKey { PsbtError::DuplicateKey {
key: "key".to_string(), key: "key".to_string(),
}, },
"duplicate key: key", "duplicate key: key",
), ),
(PsbtError::UnsignedTxHasScriptSigs, "the unsigned transaction has script sigs"), (
PsbtError::UnsignedTxHasScriptSigs,
"the unsigned transaction has script sigs",
),
( (
PsbtError::UnsignedTxHasScriptWitnesses, PsbtError::UnsignedTxHasScriptWitnesses,
"the unsigned transaction has script witnesses", "the unsigned transaction has script witnesses",
), ),
(PsbtError::MustHaveUnsignedTx, "partially signed transactions must have an unsigned transaction"), (
(PsbtError::NoMorePairs, "no more key-value pairs for this psbt map"), PsbtError::MustHaveUnsignedTx,
(PsbtError::UnexpectedUnsignedTx, "different unsigned transaction"), "partially signed transactions must have an unsigned transaction",
),
(
PsbtError::NoMorePairs,
"no more key-value pairs for this psbt map",
),
(
PsbtError::UnexpectedUnsignedTx,
"different unsigned transaction",
),
( (
PsbtError::NonStandardSighashType { sighash: 200 }, PsbtError::NonStandardSighashType { sighash: 200 },
"non-standard sighash type: 200", "non-standard sighash type: 200",
@ -1967,7 +1980,10 @@ mod test {
}, },
"invalid hash when parsing slice: abcde", "invalid hash when parsing slice: abcde",
), ),
(PsbtError::InvalidPreimageHashPair, "preimage does not match"), (
PsbtError::InvalidPreimageHashPair,
"preimage does not match",
),
( (
PsbtError::CombineInconsistentKeySources { PsbtError::CombineInconsistentKeySources {
xpub: "xpub".to_string(), xpub: "xpub".to_string(),
@ -1980,8 +1996,14 @@ mod test {
}, },
"bitcoin consensus encoding error: encoding error", "bitcoin consensus encoding error: encoding error",
), ),
(PsbtError::NegativeFee, "PSBT has a negative fee which is not allowed"), (
(PsbtError::FeeOverflow, "integer overflow in fee calculation"), PsbtError::NegativeFee,
"PSBT has a negative fee which is not allowed",
),
(
PsbtError::FeeOverflow,
"integer overflow in fee calculation",
),
( (
PsbtError::InvalidPublicKey { PsbtError::InvalidPublicKey {
error_message: "invalid public key".to_string(), error_message: "invalid public key".to_string(),
@ -2023,14 +2045,17 @@ mod test {
}, },
"version error: version error", "version error: version error",
), ),
(PsbtError::PartialDataConsumption, "data not consumed entirely when explicitly deserializing"), (
PsbtError::PartialDataConsumption,
"data not consumed entirely when explicitly deserializing",
),
( (
PsbtError::Io { PsbtError::Io {
error_message: "io error".to_string(), error_message: "io error".to_string(),
}, },
"I/O error: io error", "I/O error: io error",
), ),
(PsbtError::OtherPsbtError, "other PSBT error"), (PsbtError::OtherPsbtErr, "other PSBT error"),
]; ];
for (error, expected_message) in cases { for (error, expected_message) in cases {