Introduce sighash::LegacyError

Introduce a `sighash::LegacyError` type and return it for all the
legacy sighash calculation functions.
This commit is contained in:
Tobin C. Harding 2024-01-18 11:53:11 +11:00
parent a1b21e2f1d
commit f0b567313b
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
2 changed files with 66 additions and 21 deletions

View File

@ -982,12 +982,10 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
input_index: usize, input_index: usize,
script_pubkey: &Script, script_pubkey: &Script,
sighash_type: U, sighash_type: U,
) -> EncodeSigningDataResult<Error> { ) -> EncodeSigningDataResult<LegacyError> {
if input_index >= self.tx.borrow().input.len() { // Validate input_index.
return EncodeSigningDataResult::WriteResult(Err(Error::IndexOutOfInputsBounds { if let Err(e) = self.tx.borrow().tx_in(input_index) {
index: input_index, return EncodeSigningDataResult::WriteResult(Err(e.into()));
inputs_size: self.tx.borrow().input.len(),
}));
} }
let sighash_type: u32 = sighash_type.into(); let sighash_type: u32 = sighash_type.into();
@ -1079,7 +1077,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
script_pubkey, script_pubkey,
sighash_type, sighash_type,
) )
.map_err(|e| Error::Io(e.kind())), .map_err(|e| LegacyError::Io(e.kind())),
) )
} }
@ -1107,15 +1105,18 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
input_index: usize, input_index: usize,
script_pubkey: &Script, script_pubkey: &Script,
sighash_type: u32, sighash_type: u32,
) -> Result<LegacySighash, Error> { ) -> Result<LegacySighash, transaction::InputsIndexError> {
let mut enc = LegacySighash::engine(); let mut engine = LegacySighash::engine();
if self match self
.legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type) .legacy_encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_type)
.is_sighash_single_bug()? .is_sighash_single_bug()
{ {
Ok(LegacySighash::from_byte_array(UINT256_ONE)) Ok(true) => Ok(LegacySighash::from_byte_array(UINT256_ONE)),
} else { Ok(false) => Ok(LegacySighash::from_engine(engine)),
Ok(LegacySighash::from_engine(enc)) Err(e) => match e {
LegacyError::InputsIndex(e) => Err(e),
LegacyError::Io(_) => unreachable!("engines don't error"),
},
} }
} }
@ -1370,6 +1371,47 @@ impl std::error::Error for AnnexError {
} }
} }
/// Error computing the legacy sighash.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum LegacyError {
/// Index out of bounds when accessing transaction input vector.
InputsIndex(transaction::InputsIndexError),
/// Writer errored during consensus encoding.
Io(io::ErrorKind),
}
impl fmt::Display for LegacyError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use LegacyError::*;
match *self {
InputsIndex(ref e) => write_err!(f, "inputs index"; e),
Io(error_kind) => write!(f, "write failed: {:?}", error_kind),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for LegacyError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use LegacyError::*;
match *self {
InputsIndex(ref e) => Some(e),
Io(_) => None,
}
}
}
impl From<transaction::InputsIndexError> for LegacyError {
fn from(e: transaction::InputsIndexError) -> Self { Self::InputsIndex(e) }
}
impl From<io::Error> for LegacyError {
fn from(e: io::Error) -> Self { Self::Io(e.kind()) }
}
fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, outputs_len: usize) -> bool { fn is_invalid_use_of_sighash_single(sighash: u32, input_index: usize, outputs_len: usize) -> bool {
let ty = EcdsaSighashType::from_consensus(sighash); let ty = EcdsaSighashType::from_consensus(sighash);
ty == EcdsaSighashType::Single && input_index >= outputs_len ty == EcdsaSighashType::Single && input_index >= outputs_len
@ -1701,10 +1743,10 @@ mod tests {
); );
assert_eq!( assert_eq!(
c.legacy_signature_hash(10, Script::new(), 0u32), c.legacy_signature_hash(10, Script::new(), 0u32),
Err(Error::IndexOutOfInputsBounds { Err(InputsIndexError(IndexOutOfBoundsError {
index: 10, index: 10,
inputs_size: 1 length: 1
}) }))
); );
} }

View File

@ -409,14 +409,17 @@ impl Psbt {
match self.output_type(input_index)? { match self.output_type(input_index)? {
Bare => { Bare => {
let sighash = cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())?; let sighash = cache
.legacy_signature_hash(input_index, spk, hash_ty.to_u32())
.expect("input checked above");
Ok((Message::from_digest(sighash.to_byte_array()), hash_ty)) Ok((Message::from_digest(sighash.to_byte_array()), hash_ty))
} }
Sh => { Sh => {
let script_code = let script_code =
input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?; input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
let sighash = let sighash = cache
cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?; .legacy_signature_hash(input_index, script_code, hash_ty.to_u32())
.expect("input checked above");
Ok((Message::from_digest(sighash.to_byte_array()), hash_ty)) Ok((Message::from_digest(sighash.to_byte_array()), hash_ty))
} }
Wpkh => { Wpkh => {