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,
script_pubkey: &Script,
sighash_type: U,
) -> EncodeSigningDataResult<Error> {
if input_index >= self.tx.borrow().input.len() {
return EncodeSigningDataResult::WriteResult(Err(Error::IndexOutOfInputsBounds {
index: input_index,
inputs_size: self.tx.borrow().input.len(),
}));
) -> EncodeSigningDataResult<LegacyError> {
// Validate input_index.
if let Err(e) = self.tx.borrow().tx_in(input_index) {
return EncodeSigningDataResult::WriteResult(Err(e.into()));
}
let sighash_type: u32 = sighash_type.into();
@ -1079,7 +1077,7 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
script_pubkey,
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,
script_pubkey: &Script,
sighash_type: u32,
) -> Result<LegacySighash, Error> {
let mut enc = LegacySighash::engine();
if self
.legacy_encode_signing_data_to(&mut enc, input_index, script_pubkey, sighash_type)
.is_sighash_single_bug()?
) -> Result<LegacySighash, transaction::InputsIndexError> {
let mut engine = LegacySighash::engine();
match self
.legacy_encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_type)
.is_sighash_single_bug()
{
Ok(LegacySighash::from_byte_array(UINT256_ONE))
} else {
Ok(LegacySighash::from_engine(enc))
Ok(true) => Ok(LegacySighash::from_byte_array(UINT256_ONE)),
Ok(false) => Ok(LegacySighash::from_engine(engine)),
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 {
let ty = EcdsaSighashType::from_consensus(sighash);
ty == EcdsaSighashType::Single && input_index >= outputs_len
@ -1701,10 +1743,10 @@ mod tests {
);
assert_eq!(
c.legacy_signature_hash(10, Script::new(), 0u32),
Err(Error::IndexOutOfInputsBounds {
Err(InputsIndexError(IndexOutOfBoundsError {
index: 10,
inputs_size: 1
})
length: 1
}))
);
}

View File

@ -409,14 +409,17 @@ impl Psbt {
match self.output_type(input_index)? {
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))
}
Sh => {
let script_code =
input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
let sighash =
cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?;
let sighash = cache
.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))
}
Wpkh => {