Skip to content

Commit 4f023f0

Browse files
committed
Merge rust-bitcoin/rust-bitcoin#898: Make PsbtSigHashType use the same formatting as other *SigHashTypes
992857a PsbtSighashType unit tests (Dr Maxim Orlovsky) 5be1cdb PsbtSigHashType Display and FromStr implementation (Dr Maxim Orlovsky) 7cdcdaa Support SIGHASH_RESERVED in SchnorrSigHashType::from_u8 (Dr Maxim Orlovsky) Pull request description: The newly introduced `PsbtSigHashType` uses very different serde formatting from previously used `EcdsaSigHashType`; for instance it does not output human-readable sighash. This is especially obvious when printing out PSBT as JSON/YAML object and is a breaking change from the `0.27`. Serde human-readable implementation requires `Display/FromStr`, which were also absent. ACKs for top commit: sanket1729: ACK 992857a. This is much better apoelstra: ACK 992857a Tree-SHA512: 71a46471f34b5481e4c1273a66846f59d61bfd98fcb65e7823ca216ff0dd419d81ca86d99c7aaf674fcfe2b1c010e899c8e74328f60a1e809015c663c453cc89
2 parents 4e1c696 + a730e6d commit 4f023f0

File tree

3 files changed

+107
-2
lines changed

3 files changed

+107
-2
lines changed

src/blockdata/transaction.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ impl str::FromStr for EcdsaSigHashType {
788788
"SIGHASH_ALL|SIGHASH_ANYONECANPAY" => Ok(EcdsaSigHashType::AllPlusAnyoneCanPay),
789789
"SIGHASH_NONE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSigHashType::NonePlusAnyoneCanPay),
790790
"SIGHASH_SINGLE|SIGHASH_ANYONECANPAY" => Ok(EcdsaSigHashType::SinglePlusAnyoneCanPay),
791-
_ => Err(SigHashTypeParseError{ unrecognized: s.to_owned() }),
791+
_ => Err(SigHashTypeParseError { unrecognized: s.to_owned() }),
792792
}
793793
}
794794
}

src/util/psbt/map/input.rs

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414

1515
use prelude::*;
1616
use io;
17+
use core::fmt;
18+
use core::str::FromStr;
1719

1820
use secp256k1;
1921
use blockdata::script::Script;
2022
use blockdata::witness::Witness;
21-
use blockdata::transaction::{Transaction, TxOut, NonStandardSigHashType};
23+
use blockdata::transaction::{Transaction, TxOut, NonStandardSigHashType, SigHashTypeParseError};
2224
use consensus::encode;
2325
use hashes::{self, hash160, ripemd160, sha256, sha256d};
2426
use secp256k1::XOnlyPublicKey;
@@ -155,6 +157,40 @@ pub struct PsbtSigHashType {
155157
pub (in ::util::psbt) inner: u32,
156158
}
157159

160+
impl fmt::Display for PsbtSigHashType {
161+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162+
match self.schnorr_hash_ty() {
163+
Ok(SchnorrSigHashType::Reserved) | Err(_) => write!(f, "{:#x}", self.inner),
164+
Ok(schnorr_hash_ty) => fmt::Display::fmt(&schnorr_hash_ty, f),
165+
}
166+
}
167+
}
168+
169+
impl FromStr for PsbtSigHashType {
170+
type Err = SigHashTypeParseError;
171+
172+
#[inline]
173+
fn from_str(s: &str) -> Result<Self, Self::Err> {
174+
// We accept strings of form: "SIGHASH_ALL" etc.
175+
//
176+
// NB: some of Schnorr sighash types are non-standard for pre-taproot
177+
// inputs. We also do not support SIGHASH_RESERVED in verbatim form
178+
// ("0xFF" string should be used instead).
179+
match SchnorrSigHashType::from_str(s) {
180+
Ok(SchnorrSigHashType::Reserved) => return Err(SigHashTypeParseError{ unrecognized: s.to_owned() }),
181+
Ok(ty) => return Ok(ty.into()),
182+
Err(_) => {}
183+
}
184+
185+
// We accept non-standard sighash values.
186+
// TODO: Swap `trim_left_matches` for `trim_start_matches` once MSRV >= 1.30.
187+
if let Ok(inner) = u32::from_str_radix(s.trim_left_matches("0x"), 16) {
188+
return Ok(PsbtSigHashType { inner });
189+
}
190+
191+
Err(SigHashTypeParseError{ unrecognized: s.to_owned() })
192+
}
193+
}
158194
impl From<EcdsaSigHashType> for PsbtSigHashType {
159195
fn from(ecdsa_hash_ty: EcdsaSigHashType) -> Self {
160196
PsbtSigHashType { inner: ecdsa_hash_ty as u32 }
@@ -500,3 +536,71 @@ where
500536
btree_map::Entry::Occupied(_) => Err(psbt::Error::DuplicateKey(raw_key).into()),
501537
}
502538
}
539+
540+
#[cfg(test)]
541+
mod test {
542+
use super::*;
543+
544+
#[test]
545+
fn psbt_sighash_type_ecdsa() {
546+
for ecdsa in &[
547+
EcdsaSigHashType::All,
548+
EcdsaSigHashType::None,
549+
EcdsaSigHashType::Single,
550+
EcdsaSigHashType::AllPlusAnyoneCanPay,
551+
EcdsaSigHashType::NonePlusAnyoneCanPay,
552+
EcdsaSigHashType::SinglePlusAnyoneCanPay,
553+
] {
554+
let sighash = PsbtSigHashType::from(*ecdsa);
555+
let s = format!("{}", sighash);
556+
let back = PsbtSigHashType::from_str(&s).unwrap();
557+
assert_eq!(back, sighash);
558+
assert_eq!(back.ecdsa_hash_ty().unwrap(), *ecdsa);
559+
}
560+
}
561+
562+
#[test]
563+
fn psbt_sighash_type_schnorr() {
564+
for schnorr in &[
565+
SchnorrSigHashType::Default,
566+
SchnorrSigHashType::All,
567+
SchnorrSigHashType::None,
568+
SchnorrSigHashType::Single,
569+
SchnorrSigHashType::AllPlusAnyoneCanPay,
570+
SchnorrSigHashType::NonePlusAnyoneCanPay,
571+
SchnorrSigHashType::SinglePlusAnyoneCanPay,
572+
] {
573+
let sighash = PsbtSigHashType::from(*schnorr);
574+
let s = format!("{}", sighash);
575+
let back = PsbtSigHashType::from_str(&s).unwrap();
576+
assert_eq!(back, sighash);
577+
assert_eq!(back.schnorr_hash_ty().unwrap(), *schnorr);
578+
}
579+
}
580+
581+
#[test]
582+
fn psbt_sighash_type_schnorr_notstd() {
583+
for (schnorr, schnorr_str) in &[
584+
(SchnorrSigHashType::Reserved, "0xff"),
585+
] {
586+
let sighash = PsbtSigHashType::from(*schnorr);
587+
let s = format!("{}", sighash);
588+
assert_eq!(&s, schnorr_str);
589+
let back = PsbtSigHashType::from_str(&s).unwrap();
590+
assert_eq!(back, sighash);
591+
assert_eq!(back.schnorr_hash_ty().unwrap(), *schnorr);
592+
}
593+
}
594+
595+
#[test]
596+
fn psbt_sighash_type_notstd() {
597+
let nonstd = 0xdddddddd;
598+
let sighash = PsbtSigHashType { inner: nonstd };
599+
let s = format!("{}", sighash);
600+
let back = PsbtSigHashType::from_str(&s).unwrap();
601+
602+
assert_eq!(back, sighash);
603+
assert_eq!(back.ecdsa_hash_ty(), Err(NonStandardSigHashType(nonstd)));
604+
assert_eq!(back.schnorr_hash_ty(), Err(sighash::Error::InvalidSigHashType(nonstd)));
605+
}
606+
}

src/util/sighash.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ impl SchnorrSigHashType {
326326
0x81 => Ok(SchnorrSigHashType::AllPlusAnyoneCanPay),
327327
0x82 => Ok(SchnorrSigHashType::NonePlusAnyoneCanPay),
328328
0x83 => Ok(SchnorrSigHashType::SinglePlusAnyoneCanPay),
329+
0xFF => Ok(SchnorrSigHashType::Reserved),
329330
x => Err(Error::InvalidSigHashType(x as u32)),
330331
}
331332
}

0 commit comments

Comments
 (0)