X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=src%2Fln%2Fchannelmonitor.rs;h=00b348002dd3faf9a63f4e6c458b088c161eda01;hb=b02176c86bfa991a7c4856e427355d6e034e1eaa;hp=891dac807f8f59109e2c5f7209eb23c8ed903766;hpb=0553945e21539f304bef16e8c5c8939e11ee1363;p=rust-lightning diff --git a/src/ln/channelmonitor.rs b/src/ln/channelmonitor.rs index 891dac80..00b34800 100644 --- a/src/ln/channelmonitor.rs +++ b/src/ln/channelmonitor.rs @@ -117,7 +117,7 @@ const CLTV_SHARED_CLAIM_BUFFER: u32 = 12; /// HTLC-Success transaction. const CLTV_CLAIM_BUFFER: u32 = 6; -#[derive(Clone)] +#[derive(Clone, PartialEq)] enum KeyStorage { PrivMode { revocation_base_key: SecretKey, @@ -130,7 +130,7 @@ enum KeyStorage { } } -#[derive(Clone)] +#[derive(Clone, PartialEq)] struct LocalSignedTx { /// txid of the transaction in tx, just used to make comparison faster txid: Sha256dHash, @@ -215,6 +215,40 @@ impl Clone for ChannelMonitor { } } +#[cfg(any(test, feature = "fuzztarget"))] +/// Used only in testing and fuzztarget to check serialization roundtrips don't change the +/// underlying object +impl PartialEq for ChannelMonitor { + fn eq(&self, other: &Self) -> bool { + if self.funding_txo != other.funding_txo || + self.commitment_transaction_number_obscure_factor != other.commitment_transaction_number_obscure_factor || + self.key_storage != other.key_storage || + self.delayed_payment_base_key != other.delayed_payment_base_key || + self.their_htlc_base_key != other.their_htlc_base_key || + self.their_cur_revocation_points != other.their_cur_revocation_points || + self.our_to_self_delay != other.our_to_self_delay || + self.their_to_self_delay != other.their_to_self_delay || + self.remote_claimable_outpoints != other.remote_claimable_outpoints || + self.remote_hash_commitment_number != other.remote_hash_commitment_number || + self.prev_local_signed_commitment_tx != other.prev_local_signed_commitment_tx || + self.current_local_signed_commitment_tx != other.current_local_signed_commitment_tx || + self.payment_preimages != other.payment_preimages || + self.destination_script != other.destination_script + { + false + } else { + for (&(ref secret, ref idx), &(ref o_secret, ref o_idx)) in self.old_secrets.iter().zip(other.old_secrets.iter()) { + if secret != o_secret || idx != o_idx { + return false + } + } + let us = self.remote_commitment_txn_on_chain.lock().unwrap(); + let them = other.remote_commitment_txn_on_chain.lock().unwrap(); + *us == *them + } + } +} + impl ChannelMonitor { pub fn new(revocation_base_key: &SecretKey, delayed_payment_base_key: &PublicKey, htlc_base_key: &SecretKey, our_to_self_delay: u16, destination_script: Script) -> ChannelMonitor { ChannelMonitor { @@ -603,7 +637,7 @@ impl ChannelMonitor { macro_rules! read_bytes { ($byte_count: expr) => { { - if ($byte_count as usize) + read_pos > data.len() { + if ($byte_count as usize) > data.len() - read_pos { return None; } read_pos += $byte_count as usize; @@ -736,7 +770,14 @@ impl ChannelMonitor { () => { { let tx_len = byte_utils::slice_to_be64(read_bytes!(8)); - let tx: Transaction = unwrap_obj!(serialize::deserialize(read_bytes!(tx_len))); + let tx_ser = read_bytes!(tx_len); + let tx: Transaction = unwrap_obj!(serialize::deserialize(tx_ser)); + if serialize::serialize(&tx).unwrap() != tx_ser { + // We check that the tx re-serializes to the same form to ensure there is + // no extra data, and as rust-bitcoin doesn't handle the 0-input ambiguity + // all that well. + return None; + } let revocation_key = unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))); let a_htlc_key = unwrap_obj!(PublicKey::from_slice(&secp_ctx, read_bytes!(33))); @@ -869,7 +910,7 @@ impl ChannelMonitor { let commitment_txid = tx.txid(); //TODO: This is gonna be a performance bottleneck for watchtowers! let per_commitment_option = self.remote_claimable_outpoints.get(&commitment_txid); - let commitment_number = (((tx.input[0].sequence as u64 & 0xffffff) << 3*8) | (tx.lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor; + let commitment_number = 0xffffffffffff - ((((tx.input[0].sequence as u64 & 0xffffff) << 3*8) | (tx.lock_time as u64 & 0xffffff)) ^ self.commitment_transaction_number_obscure_factor); if commitment_number >= self.get_min_seen_secret() { let secret = self.get_secret(commitment_number).unwrap(); let per_commitment_key = ignore_error!(SecretKey::from_slice(&self.secp_ctx, &secret));