Improve error handling, fix forgotten early return

This commit is contained in:
Ivan Paljak 2020-10-08 16:40:30 +02:00
parent c21dabb824
commit e66caab956
2 changed files with 43 additions and 30 deletions

View File

@ -324,7 +324,7 @@ impl Transaction {
input_index: usize, input_index: usize,
script_pubkey: &Script, script_pubkey: &Script,
sighash_u32: u32 sighash_u32: u32
) { ) -> Result<(), encode::Error> {
assert!(input_index < self.input.len()); // Panic on OOB assert!(input_index < self.input.len()); // Panic on OOB
let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag(); let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag();
@ -334,7 +334,8 @@ impl Transaction {
writer.write_all(&[1, 0, 0, 0, 0, 0, 0, 0, writer.write_all(&[1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]).unwrap(); 0, 0, 0, 0, 0, 0, 0, 0])?;
return Ok(());
} }
// Build tx to sign // Build tx to sign
@ -377,9 +378,10 @@ impl Transaction {
_ => unreachable!() _ => unreachable!()
}; };
// hash the result // hash the result
tx.consensus_encode(&mut writer).unwrap(); tx.consensus_encode(&mut writer)?;
let sighash_arr = endian::u32_to_array_le(sighash_u32); let sighash_arr = endian::u32_to_array_le(sighash_u32);
sighash_arr.consensus_encode(&mut writer).unwrap(); sighash_arr.consensus_encode(&mut writer)?;
Ok(())
} }
/// Computes a signature hash for a given input index with a given sighash flag. /// Computes a signature hash for a given input index with a given sighash flag.
@ -395,10 +397,15 @@ impl Transaction {
/// # Panics /// # Panics
/// Panics if `input_index` is greater than or equal to `self.input.len()` /// Panics if `input_index` is greater than or equal to `self.input.len()`
/// ///
pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighash_u32: u32) -> SigHash { pub fn signature_hash(
&self,
input_index: usize,
script_pubkey: &Script,
sighash_u32: u32
) -> Result<SigHash, encode::Error> {
let mut engine = SigHash::engine(); let mut engine = SigHash::engine();
self.encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_u32); self.encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_u32)?;
SigHash::from_engine(engine) Ok(SigHash::from_engine(engine))
} }
/// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty /// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty
@ -895,7 +902,7 @@ mod tests {
raw_expected.reverse(); raw_expected.reverse();
let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap(); let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap();
let actual_result = tx.signature_hash(input_index, &script, hash_type as u32); let actual_result = tx.signature_hash(input_index, &script, hash_type as u32).unwrap();
assert_eq!(actual_result, expected_result); assert_eq!(actual_result, expected_result);
} }

View File

@ -23,7 +23,7 @@ use hashes::{Hash, sha256d};
use hash_types::SigHash; use hash_types::SigHash;
use blockdata::script::Script; use blockdata::script::Script;
use blockdata::transaction::{Transaction, TxIn, SigHashType}; use blockdata::transaction::{Transaction, TxIn, SigHashType};
use consensus::encode::Encodable; use consensus::{encode, Encodable};
use std::io; use std::io;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@ -178,23 +178,23 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
script_code: &Script, script_code: &Script,
value: u64, value: u64,
sighash_type: SigHashType, sighash_type: SigHashType,
) { ) -> Result<(), encode::Error> {
let zero_hash = sha256d::Hash::default(); let zero_hash = sha256d::Hash::default();
let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag(); let (sighash, anyone_can_pay) = sighash_type.split_anyonecanpay_flag();
self.tx.version.consensus_encode(&mut writer).unwrap(); self.tx.version.consensus_encode(&mut writer)?;
if !anyone_can_pay { if !anyone_can_pay {
self.hash_prevouts().consensus_encode(&mut writer).unwrap(); self.hash_prevouts().consensus_encode(&mut writer)?;
} else { } else {
zero_hash.consensus_encode(&mut writer).unwrap(); zero_hash.consensus_encode(&mut writer)?;
} }
if !anyone_can_pay && sighash != SigHashType::Single && sighash != SigHashType::None { if !anyone_can_pay && sighash != SigHashType::Single && sighash != SigHashType::None {
self.hash_sequence().consensus_encode(&mut writer).unwrap(); self.hash_sequence().consensus_encode(&mut writer)?;
} else { } else {
zero_hash.consensus_encode(&mut writer).unwrap(); zero_hash.consensus_encode(&mut writer)?;
} }
{ {
@ -202,33 +202,39 @@ impl<R: Deref<Target=Transaction>> SigHashCache<R> {
txin txin
.previous_output .previous_output
.consensus_encode(&mut writer) .consensus_encode(&mut writer)?;
.unwrap(); script_code.consensus_encode(&mut writer)?;
script_code.consensus_encode(&mut writer).unwrap(); value.consensus_encode(&mut writer)?;
value.consensus_encode(&mut writer).unwrap(); txin.sequence.consensus_encode(&mut writer)?;
txin.sequence.consensus_encode(&mut writer).unwrap();
} }
if sighash != SigHashType::Single && sighash != SigHashType::None { if sighash != SigHashType::Single && sighash != SigHashType::None {
self.hash_outputs().consensus_encode(&mut writer).unwrap(); self.hash_outputs().consensus_encode(&mut writer)?;
} else if sighash == SigHashType::Single && input_index < self.tx.output.len() { } else if sighash == SigHashType::Single && input_index < self.tx.output.len() {
let mut single_enc = SigHash::engine(); let mut single_enc = SigHash::engine();
self.tx.output[input_index].consensus_encode(&mut single_enc).unwrap(); self.tx.output[input_index].consensus_encode(&mut single_enc)?;
SigHash::from_engine(single_enc).consensus_encode(&mut writer).unwrap(); SigHash::from_engine(single_enc).consensus_encode(&mut writer)?;
} else { } else {
zero_hash.consensus_encode(&mut writer).unwrap(); zero_hash.consensus_encode(&mut writer)?;
} }
self.tx.lock_time.consensus_encode(&mut writer).unwrap(); self.tx.lock_time.consensus_encode(&mut writer)?;
sighash_type.as_u32().consensus_encode(&mut writer).unwrap(); sighash_type.as_u32().consensus_encode(&mut writer)?;
Ok(())
} }
/// Compute the BIP143 sighash for any flag type. See SighashComponents::sighash_all simpler /// Compute the BIP143 sighash for any flag type. See SighashComponents::sighash_all simpler
/// API for the most common case /// API for the most common case
pub fn signature_hash(&mut self, input_index: usize, script_code: &Script, value: u64, sighash_type: SigHashType) -> SigHash { pub fn signature_hash(
&mut self,
input_index: usize,
script_code: &Script,
value: u64,
sighash_type: SigHashType
) -> Result<SigHash, encode::Error> {
let mut enc = SigHash::engine(); let mut enc = SigHash::engine();
self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type); self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type)?;
SigHash::from_engine(enc) Ok(SigHash::from_engine(enc))
} }
} }
@ -286,7 +292,7 @@ mod tests {
let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap(); let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap();
let mut cache = SigHashCache::new(&tx); let mut cache = SigHashCache::new(&tx);
let sighash_type = SigHashType::from_u32(hash_type); let sighash_type = SigHashType::from_u32(hash_type);
let actual_result = cache.signature_hash(input_index, &script, value, sighash_type); let actual_result = cache.signature_hash(input_index, &script, value, sighash_type).unwrap();
assert_eq!(actual_result, expected_result); assert_eq!(actual_result, expected_result);
} }