From e66caab956ff003bba3f15b0fcb08944d5aacd3c Mon Sep 17 00:00:00 2001 From: Ivan Paljak Date: Thu, 8 Oct 2020 16:40:30 +0200 Subject: [PATCH] Improve error handling, fix forgotten early return --- src/blockdata/transaction.rs | 23 +++++++++++------ src/util/bip143.rs | 50 ++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index ca81e7c7..eb3c343a 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -324,7 +324,7 @@ impl Transaction { input_index: usize, script_pubkey: &Script, sighash_u32: u32 - ) { + ) -> Result<(), encode::Error> { assert!(input_index < self.input.len()); // Panic on OOB 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, 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 @@ -377,9 +378,10 @@ impl Transaction { _ => unreachable!() }; // hash the result - tx.consensus_encode(&mut writer).unwrap(); + tx.consensus_encode(&mut writer)?; 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. @@ -395,10 +397,15 @@ impl Transaction { /// # Panics /// 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 { let mut engine = SigHash::engine(); - self.encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_u32); - SigHash::from_engine(engine) + self.encode_signing_data_to(&mut engine, input_index, script_pubkey, sighash_u32)?; + Ok(SigHash::from_engine(engine)) } /// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty @@ -895,7 +902,7 @@ mod tests { raw_expected.reverse(); 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); } diff --git a/src/util/bip143.rs b/src/util/bip143.rs index 688d9cef..f5cb5c1c 100644 --- a/src/util/bip143.rs +++ b/src/util/bip143.rs @@ -23,7 +23,7 @@ use hashes::{Hash, sha256d}; use hash_types::SigHash; use blockdata::script::Script; use blockdata::transaction::{Transaction, TxIn, SigHashType}; -use consensus::encode::Encodable; +use consensus::{encode, Encodable}; use std::io; use std::ops::{Deref, DerefMut}; @@ -178,23 +178,23 @@ impl> SigHashCache { script_code: &Script, value: u64, sighash_type: SigHashType, - ) { + ) -> Result<(), encode::Error> { let zero_hash = sha256d::Hash::default(); 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 { - self.hash_prevouts().consensus_encode(&mut writer).unwrap(); + self.hash_prevouts().consensus_encode(&mut writer)?; } else { - zero_hash.consensus_encode(&mut writer).unwrap(); + zero_hash.consensus_encode(&mut writer)?; } 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 { - zero_hash.consensus_encode(&mut writer).unwrap(); + zero_hash.consensus_encode(&mut writer)?; } { @@ -202,33 +202,39 @@ impl> SigHashCache { txin .previous_output - .consensus_encode(&mut writer) - .unwrap(); - script_code.consensus_encode(&mut writer).unwrap(); - value.consensus_encode(&mut writer).unwrap(); - txin.sequence.consensus_encode(&mut writer).unwrap(); + .consensus_encode(&mut writer)?; + script_code.consensus_encode(&mut writer)?; + value.consensus_encode(&mut writer)?; + txin.sequence.consensus_encode(&mut writer)?; } 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() { let mut single_enc = SigHash::engine(); - self.tx.output[input_index].consensus_encode(&mut single_enc).unwrap(); - SigHash::from_engine(single_enc).consensus_encode(&mut writer).unwrap(); + self.tx.output[input_index].consensus_encode(&mut single_enc)?; + SigHash::from_engine(single_enc).consensus_encode(&mut writer)?; } else { - zero_hash.consensus_encode(&mut writer).unwrap(); + zero_hash.consensus_encode(&mut writer)?; } - self.tx.lock_time.consensus_encode(&mut writer).unwrap(); - sighash_type.as_u32().consensus_encode(&mut writer).unwrap(); + self.tx.lock_time.consensus_encode(&mut writer)?; + sighash_type.as_u32().consensus_encode(&mut writer)?; + Ok(()) } /// Compute the BIP143 sighash for any flag type. See SighashComponents::sighash_all simpler /// 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 { let mut enc = SigHash::engine(); - self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type); - SigHash::from_engine(enc) + self.encode_signing_data_to(&mut enc, input_index, script_code, value, sighash_type)?; + Ok(SigHash::from_engine(enc)) } } @@ -286,7 +292,7 @@ mod tests { let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap(); let mut cache = SigHashCache::new(&tx); 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); }