diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index ec4071a8a2..9184f7a345 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -20,7 +20,7 @@ use blockdata::script::Script; use blockdata::transaction::Transaction; -use consensus::{encode, Encodable, Decodable}; +use consensus::{encode, Encodable, Decodable, self}; use std::io; @@ -91,14 +91,35 @@ impl PartiallySignedTransaction { } } +/// Error happening during PSBT decoding from Base64 string +#[cfg(feature = "base64")] +#[derive(Debug)] +pub enum PsbtParseError { + /// Error in internal PSBT data structure + PsbtEncoding(consensus::encode::Error), + /// Error in PSBT Base64 encoding + Base64Encoding(::base64::DecodeError) +} + #[cfg(feature = "base64")] mod _base64encoding { - use super::{PartiallySignedTransaction, Error}; + use super::{PartiallySignedTransaction, PsbtParseError}; use std::fmt::{Display, Formatter, self}; use std::str::FromStr; use consensus::encode; use ::base64::display::Base64Display; + impl Display for PsbtParseError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + PsbtParseError::PsbtEncoding(err) => Display::fmt(err, f), + PsbtParseError::Base64Encoding(err) => Display::fmt(err, f), + } + } + } + + impl std::error::Error for PsbtParseError { } + impl Display for PartiallySignedTransaction { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{}", Base64Display::with_config(&encode::serialize(self), ::base64::STANDARD)) @@ -106,10 +127,11 @@ mod _base64encoding { } impl FromStr for PartiallySignedTransaction { - type Err = Error; + type Err = PsbtParseError; fn from_str(s: &str) -> Result { - Ok(encode::deserialize(&::base64::decode(s).map_err(|_| Error::ConsensusEncoding)?)?) + let data = ::base64::decode(s).map_err(PsbtParseError::Base64Encoding)?; + Ok(encode::deserialize(&data).map_err(PsbtParseError::PsbtEncoding)?) } } } @@ -449,7 +471,7 @@ mod tests { use blockdata::transaction::{SigHashType, Transaction, TxIn, TxOut, OutPoint}; use consensus::encode::serialize_hex; use util::psbt::map::{Map, Global, Input, Output}; - use util::psbt::raw; + use util::psbt::{raw, PsbtParseError}; use util::psbt::{PartiallySignedTransaction, Error}; #[test] @@ -469,6 +491,7 @@ mod tests { #[should_panic(expected = "ConsensusEncoding")] fn invalid_vector_2() { hex_psbt!("70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000") + // This weird thing is necessary since rustc 0.29 prints out I/O error in a different format than later versions .map_err(Error::from) .unwrap(); } @@ -477,7 +500,14 @@ mod tests { #[test] #[should_panic(expected = "ConsensusEncoding")] fn invalid_vector_2_base64() { - PartiallySignedTransaction::from_str("cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==").unwrap(); + PartiallySignedTransaction::from_str("cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA==") + // This weird thing is necessary since rustc 0.29 prints out I/O error in a different format than later versions + .map_err(|err| match err { + PsbtParseError::PsbtEncoding(err) => err, + PsbtParseError::Base64Encoding(_) => panic!("PSBT Base64 decoding failed") + }) + .map_err(Error::from) + .unwrap(); } #[test]