Merge rust-bitcoin/rust-bitcoin#1609: Associate io, encode errors with psbt::Error
0ffd928a7d
Carry ConsensusEncoding(encode::Error) (DanGould)126cbb00ef
Associate io::Error with psbt::Error (DanGould) Pull request description: - patch 1 fix #1590 - patch 2 addresses [this related comment](https://github.com/rust-bitcoin/rust-bitcoin/pull/1532/files#r1067812911) about associated `encode::Error` EDIT (by Tobin): fix #1548 I believe this closes out PSBT refactoring and makes way for PSBTv2 in the epic 😎 patch 1 uses match to check the error type in tests. If msrv were 1.42 we could use assert!(matches!(...)); one liners instead. ACKs for top commit: apoelstra: ACK0ffd928a7d
tcharding: ACK0ffd928a7d
Kixunil: ACK0ffd928a7d
Tree-SHA512: 264d6025f8979dcd1e31545fbeb2ff8d7c02f161d9aa2cc500dc07f7f4d9554fcb5ce0ff7ce473db0729560a278c71d3d41004f2613584d9b19d25103973b2ab
This commit is contained in:
commit
397d71ad7c
|
@ -11,6 +11,7 @@ use crate::consensus::encode;
|
||||||
use crate::psbt::raw;
|
use crate::psbt::raw;
|
||||||
|
|
||||||
use crate::hashes;
|
use crate::hashes;
|
||||||
|
use crate::io;
|
||||||
use crate::bip32::ExtendedPubKey;
|
use crate::bip32::ExtendedPubKey;
|
||||||
|
|
||||||
/// Enum for marking psbt hash error.
|
/// Enum for marking psbt hash error.
|
||||||
|
@ -22,7 +23,7 @@ pub enum PsbtHash {
|
||||||
Hash256,
|
Hash256,
|
||||||
}
|
}
|
||||||
/// Ways that a Partially Signed Transaction might fail.
|
/// Ways that a Partially Signed Transaction might fail.
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Debug)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Magic bytes for a PSBT must be the ASCII for "psbt" serialized in most
|
/// Magic bytes for a PSBT must be the ASCII for "psbt" serialized in most
|
||||||
|
@ -73,7 +74,7 @@ pub enum Error {
|
||||||
/// global extended public key has inconsistent key sources
|
/// global extended public key has inconsistent key sources
|
||||||
CombineInconsistentKeySources(Box<ExtendedPubKey>),
|
CombineInconsistentKeySources(Box<ExtendedPubKey>),
|
||||||
/// Serialization error in bitcoin consensus-encoded structures
|
/// Serialization error in bitcoin consensus-encoded structures
|
||||||
ConsensusEncoding,
|
ConsensusEncoding(encode::Error),
|
||||||
/// Negative fee
|
/// Negative fee
|
||||||
NegativeFee,
|
NegativeFee,
|
||||||
/// Integer overflow in fee calculation
|
/// Integer overflow in fee calculation
|
||||||
|
@ -100,6 +101,8 @@ pub enum Error {
|
||||||
Version(&'static str),
|
Version(&'static str),
|
||||||
/// PSBT data is not consumed entirely
|
/// PSBT data is not consumed entirely
|
||||||
PartialDataConsumption,
|
PartialDataConsumption,
|
||||||
|
/// I/O error.
|
||||||
|
Io(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
@ -126,7 +129,7 @@ impl fmt::Display for Error {
|
||||||
write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash )
|
write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash )
|
||||||
},
|
},
|
||||||
Error::CombineInconsistentKeySources(ref s) => { write!(f, "combine conflict: {}", s) },
|
Error::CombineInconsistentKeySources(ref s) => { write!(f, "combine conflict: {}", s) },
|
||||||
Error::ConsensusEncoding => f.write_str("bitcoin consensus or BIP-174 encoding error"),
|
Error::ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e),
|
||||||
Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
|
Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
|
||||||
Error::FeeOverflow => f.write_str("integer overflow in fee calculation"),
|
Error::FeeOverflow => f.write_str("integer overflow in fee calculation"),
|
||||||
Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
|
Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
|
||||||
|
@ -140,6 +143,7 @@ impl fmt::Display for Error {
|
||||||
Error::XPubKey(s) => write!(f, "xpub key error - {}", s),
|
Error::XPubKey(s) => write!(f, "xpub key error - {}", s),
|
||||||
Error::Version(s) => write!(f, "version error {}", s),
|
Error::Version(s) => write!(f, "version error {}", s),
|
||||||
Error::PartialDataConsumption => f.write_str("data not consumed entirely when explicitly deserializing"),
|
Error::PartialDataConsumption => f.write_str("data not consumed entirely when explicitly deserializing"),
|
||||||
|
Error::Io(ref e) => write_err!(f, "I/O error"; e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,6 +156,8 @@ impl std::error::Error for Error {
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
HashParse(e) => Some(e),
|
HashParse(e) => Some(e),
|
||||||
|
ConsensusEncoding(e) => Some(e),
|
||||||
|
Io(e) => Some(e),
|
||||||
| InvalidMagic
|
| InvalidMagic
|
||||||
| MissingUtxo
|
| MissingUtxo
|
||||||
| InvalidSeparator
|
| InvalidSeparator
|
||||||
|
@ -167,7 +173,6 @@ impl std::error::Error for Error {
|
||||||
| NonStandardSighashType(_)
|
| NonStandardSighashType(_)
|
||||||
| InvalidPreimageHashPair{ .. }
|
| InvalidPreimageHashPair{ .. }
|
||||||
| CombineInconsistentKeySources(_)
|
| CombineInconsistentKeySources(_)
|
||||||
| ConsensusEncoding
|
|
||||||
| NegativeFee
|
| NegativeFee
|
||||||
| FeeOverflow
|
| FeeOverflow
|
||||||
| InvalidPublicKey(_)
|
| InvalidPublicKey(_)
|
||||||
|
@ -180,7 +185,7 @@ impl std::error::Error for Error {
|
||||||
| Taproot(_)
|
| Taproot(_)
|
||||||
| XPubKey(_)
|
| XPubKey(_)
|
||||||
| Version(_)
|
| Version(_)
|
||||||
| PartialDataConsumption=> None
|
| PartialDataConsumption=> None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +198,13 @@ impl From<hashes::Error> for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<encode::Error> for Error {
|
impl From<encode::Error> for Error {
|
||||||
fn from(_: encode::Error) -> Self {
|
fn from(e: encode::Error) -> Self {
|
||||||
Error::ConsensusEncoding
|
Error::ConsensusEncoding(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(e: io::Error) -> Self {
|
||||||
|
Error::Io(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1732,15 +1732,24 @@ mod tests {
|
||||||
// no previous output
|
// no previous output
|
||||||
let mut t2 = t.clone();
|
let mut t2 = t.clone();
|
||||||
t2.inputs[0].non_witness_utxo = None;
|
t2.inputs[0].non_witness_utxo = None;
|
||||||
assert_eq!(t2.fee(), Err(Error::MissingUtxo));
|
match t2.fee().unwrap_err() {
|
||||||
|
Error::MissingUtxo => {},
|
||||||
|
e => panic!("unexpected error: {:?}", e)
|
||||||
|
}
|
||||||
// negative fee
|
// negative fee
|
||||||
let mut t3 = t.clone();
|
let mut t3 = t.clone();
|
||||||
t3.unsigned_tx.output[0].value = prev_output_val;
|
t3.unsigned_tx.output[0].value = prev_output_val;
|
||||||
assert_eq!(t3.fee(), Err(Error::NegativeFee));
|
match t3.fee().unwrap_err() {
|
||||||
|
Error::NegativeFee => {},
|
||||||
|
e => panic!("unexpected error: {:?}", e)
|
||||||
|
}
|
||||||
// overflow
|
// overflow
|
||||||
t.unsigned_tx.output[0].value = u64::max_value();
|
t.unsigned_tx.output[0].value = u64::max_value();
|
||||||
t.unsigned_tx.output[1].value = u64::max_value();
|
t.unsigned_tx.output[1].value = u64::max_value();
|
||||||
assert_eq!(t.fee(), Err(Error::FeeOverflow));
|
match t.fee().unwrap_err() {
|
||||||
|
Error::FeeOverflow => {},
|
||||||
|
e => panic!("unexpected error: {:?}", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -225,7 +225,7 @@ impl Serialize for KeySource {
|
||||||
impl Deserialize for KeySource {
|
impl Deserialize for KeySource {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
if bytes.len() < 4 {
|
if bytes.len() < 4 {
|
||||||
return Err(encode::Error::from(io::Error::from(io::ErrorKind::UnexpectedEof)).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length");
|
let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length");
|
||||||
|
@ -319,7 +319,7 @@ impl Serialize for (XOnlyPublicKey, TapLeafHash) {
|
||||||
impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
|
impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
if bytes.len() < 32 {
|
if bytes.len() < 32 {
|
||||||
return Err(encode::Error::from(io::Error::from(io::ErrorKind::UnexpectedEof)).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
||||||
}
|
}
|
||||||
let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?;
|
let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?;
|
||||||
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
|
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
|
||||||
|
@ -353,7 +353,7 @@ impl Serialize for (ScriptBuf, LeafVersion) {
|
||||||
impl Deserialize for (ScriptBuf, LeafVersion) {
|
impl Deserialize for (ScriptBuf, LeafVersion) {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
if bytes.is_empty() {
|
if bytes.is_empty() {
|
||||||
return Err(encode::Error::from(io::Error::from(io::ErrorKind::UnexpectedEof)).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
||||||
}
|
}
|
||||||
// The last byte is LeafVersion.
|
// The last byte is LeafVersion.
|
||||||
let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?;
|
let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?;
|
||||||
|
|
Loading…
Reference in New Issue