+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
//! The logic to monitor for on-chain transactions and create the relevant claim responses lives
//! here.
//!
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::blockdata::opcodes;
use bitcoin::consensus::encode;
-use bitcoin::util::hash::BitcoinHash;
use bitcoin::hashes::Hash;
use bitcoin::hashes::sha256::Hash as Sha256;
use util::logger::Logger;
use util::ser::{Readable, MaybeReadable, Writer, Writeable, U48};
use util::{byte_utils, events};
+use util::events::Event;
use std::collections::{HashMap, hash_map};
use std::sync::Mutex;
use std::{hash,cmp, mem};
use std::ops::Deref;
+use std::io::Error;
/// An update generated by the underlying Channel itself which contains some new information the
/// ChannelMonitor should be made aware of.
#[derive(Debug)]
pub struct MonitorUpdateError(pub &'static str);
+/// An event to be processed by the ChannelManager.
+#[derive(PartialEq)]
+pub enum MonitorEvent {
+ /// A monitor event containing an HTLCUpdate.
+ HTLCEvent(HTLCUpdate),
+
+ /// A monitor event that the Channel's commitment transaction was broadcasted.
+ CommitmentTxBroadcasted(OutPoint),
+}
+
/// Simple structure send back by ManyChannelMonitor in case of HTLC detected onchain from a
/// forward channel and from which info are needed to update HTLC in a backward channel.
#[derive(Clone, PartialEq)]
L::Target: Logger,
C::Target: ChainWatchInterface,
{
- #[cfg(test)] // Used in ChannelManager tests to manipulate channels directly
+ /// The monitors
pub monitors: Mutex<HashMap<Key, ChannelMonitor<ChanSigner>>>,
- #[cfg(not(test))]
- monitors: Mutex<HashMap<Key, ChannelMonitor<ChanSigner>>>,
chain_monitor: C,
broadcaster: T,
logger: L,
C::Target: ChainWatchInterface,
{
fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], _indexes_of_txn_matched: &[usize]) {
- let block_hash = header.bitcoin_hash();
+ let block_hash = header.block_hash();
{
let mut monitors = self.monitors.lock().unwrap();
for monitor in monitors.values_mut() {
}
fn block_disconnected(&self, header: &BlockHeader, disconnected_height: u32) {
- let block_hash = header.bitcoin_hash();
+ let block_hash = header.block_hash();
let mut monitors = self.monitors.lock().unwrap();
for monitor in monitors.values_mut() {
monitor.block_disconnected(disconnected_height, &block_hash, &*self.broadcaster, &*self.fee_estimator, &*self.logger);
}
}
- fn get_and_clear_pending_htlcs_updated(&self) -> Vec<HTLCUpdate> {
- let mut pending_htlcs_updated = Vec::new();
+ fn get_and_clear_pending_monitor_events(&self) -> Vec<MonitorEvent> {
+ let mut pending_monitor_events = Vec::new();
for chan in self.monitors.lock().unwrap().values_mut() {
- pending_htlcs_updated.append(&mut chan.get_and_clear_pending_htlcs_updated());
+ pending_monitor_events.append(&mut chan.get_and_clear_pending_monitor_events());
}
- pending_htlcs_updated
+ pending_monitor_events
}
}
L::Target: Logger,
C::Target: ChainWatchInterface,
{
- fn get_and_clear_pending_events(&self) -> Vec<events::Event> {
+ fn get_and_clear_pending_events(&self) -> Vec<Event> {
let mut pending_events = Vec::new();
for chan in self.monitors.lock().unwrap().values_mut() {
pending_events.append(&mut chan.get_and_clear_pending_events());
/// information and are actively monitoring the chain.
///
/// Pending Events or updated HTLCs which have not yet been read out by
-/// get_and_clear_pending_htlcs_updated or get_and_clear_pending_events are serialized to disk and
+/// get_and_clear_pending_monitor_events or get_and_clear_pending_events are serialized to disk and
/// reloaded at deserialize-time. Thus, you must ensure that, when handling events, all events
/// gotten are fully handled before re-serializing the new state.
pub struct ChannelMonitor<ChanSigner: ChannelKeys> {
payment_preimages: HashMap<PaymentHash, PaymentPreimage>,
- pending_htlcs_updated: Vec<HTLCUpdate>,
- pending_events: Vec<events::Event>,
+ pending_monitor_events: Vec<MonitorEvent>,
+ pending_events: Vec<Event>,
// Used to track onchain events, i.e transactions parts of channels confirmed on chain, on which
// we have to take actions once they reach enough confs. Key is a block height timer, i.e we enforce
// (we do *not*, however, update them in update_monitor to ensure any local user copies keep
// their last_block_hash from its state and not based on updated copies that didn't run through
// the full block_connected).
- pub(crate) last_block_hash: BlockHash,
+ last_block_hash: BlockHash,
secp_ctx: Secp256k1<secp256k1::All>, //TODO: dedup this a bit...
}
/// with success or failure.
///
/// You should probably just call through to
- /// ChannelMonitor::get_and_clear_pending_htlcs_updated() for each ChannelMonitor and return
+ /// ChannelMonitor::get_and_clear_pending_monitor_events() for each ChannelMonitor and return
/// the full list.
- fn get_and_clear_pending_htlcs_updated(&self) -> Vec<HTLCUpdate>;
+ fn get_and_clear_pending_monitor_events(&self) -> Vec<MonitorEvent>;
}
#[cfg(any(test, feature = "fuzztarget"))]
self.current_local_commitment_number != other.current_local_commitment_number ||
self.current_local_commitment_tx != other.current_local_commitment_tx ||
self.payment_preimages != other.payment_preimages ||
- self.pending_htlcs_updated != other.pending_htlcs_updated ||
+ self.pending_monitor_events != other.pending_monitor_events ||
self.pending_events.len() != other.pending_events.len() || // We trust events to round-trip properly
self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf ||
self.outputs_to_watch != other.outputs_to_watch ||
/// the "reorg path" (ie disconnecting blocks until you find a common ancestor from both the
/// returned block hash and the the current chain and then reconnecting blocks to get to the
/// best chain) upon deserializing the object!
- pub fn write_for_disk<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+ pub fn write_for_disk<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
//TODO: We still write out all the serialization here manually instead of using the fancy
//serialization framework we have, we should migrate things over to it.
writer.write_all(&[SERIALIZATION_VERSION; 1])?;
writer.write_all(&payment_preimage.0[..])?;
}
- writer.write_all(&byte_utils::be64_to_array(self.pending_htlcs_updated.len() as u64))?;
- for data in self.pending_htlcs_updated.iter() {
- data.write(writer)?;
+ writer.write_all(&byte_utils::be64_to_array(self.pending_monitor_events.len() as u64))?;
+ for event in self.pending_monitor_events.iter() {
+ match event {
+ MonitorEvent::HTLCEvent(upd) => {
+ 0u8.write(writer)?;
+ upd.write(writer)?;
+ },
+ MonitorEvent::CommitmentTxBroadcasted(_) => 1u8.write(writer)?
+ }
}
writer.write_all(&byte_utils::be64_to_array(self.pending_events.len() as u64))?;
current_local_commitment_number: 0xffff_ffff_ffff - ((((local_tx_sequence & 0xffffff) << 3*8) | (local_tx_locktime as u64 & 0xffffff)) ^ commitment_transaction_number_obscure_factor),
payment_preimages: HashMap::new(),
- pending_htlcs_updated: Vec::new(),
+ pending_monitor_events: Vec::new(),
pending_events: Vec::new(),
onchain_events_waiting_threshold_conf: HashMap::new(),
for tx in self.get_latest_local_commitment_txn(logger).iter() {
broadcaster.broadcast_transaction(tx);
}
- }
-
- /// Used in Channel to cheat wrt the update_ids since it plays games, will be removed soon!
- pub(super) fn update_monitor_ooo<L: Deref>(&mut self, mut updates: ChannelMonitorUpdate, logger: &L) -> Result<(), MonitorUpdateError> where L::Target: Logger {
- for update in updates.updates.drain(..) {
- match update {
- ChannelMonitorUpdateStep::LatestLocalCommitmentTXInfo { commitment_tx, htlc_outputs } => {
- if self.lockdown_from_offchain { panic!(); }
- self.provide_latest_local_commitment_tx_info(commitment_tx, htlc_outputs)?
- },
- ChannelMonitorUpdateStep::LatestRemoteCommitmentTXInfo { unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point } =>
- self.provide_latest_remote_commitment_tx_info(&unsigned_commitment_tx, htlc_outputs, commitment_number, their_revocation_point, logger),
- ChannelMonitorUpdateStep::PaymentPreimage { payment_preimage } =>
- self.provide_payment_preimage(&PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner()), &payment_preimage),
- ChannelMonitorUpdateStep::CommitmentSecret { idx, secret } =>
- self.provide_secret(idx, secret)?,
- ChannelMonitorUpdateStep::ChannelForceClosed { .. } => {},
- }
- }
- self.latest_update_id = updates.update_id;
- Ok(())
+ self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
}
/// Updates a ChannelMonitor on the basis of some new information provided by the Channel
}
/// Get the list of HTLCs who's status has been updated on chain. This should be called by
- /// ChannelManager via ManyChannelMonitor::get_and_clear_pending_htlcs_updated().
- pub fn get_and_clear_pending_htlcs_updated(&mut self) -> Vec<HTLCUpdate> {
+ /// ChannelManager via ManyChannelMonitor::get_and_clear_pending_monitor_events().
+ pub fn get_and_clear_pending_monitor_events(&mut self) -> Vec<MonitorEvent> {
let mut ret = Vec::new();
- mem::swap(&mut ret, &mut self.pending_htlcs_updated);
+ mem::swap(&mut ret, &mut self.pending_monitor_events);
ret
}
/// This is called by ManyChannelMonitor::get_and_clear_pending_events() and is equivalent to
/// EventsProvider::get_and_clear_pending_events() except that it requires &mut self as we do
/// no internal locking in ChannelMonitors.
- pub fn get_and_clear_pending_events(&mut self) -> Vec<events::Event> {
+ pub fn get_and_clear_pending_events(&mut self) -> Vec<Event> {
let mut ret = Vec::new();
mem::swap(&mut ret, &mut self.pending_events);
ret
/// Unsafe test-only version of get_latest_local_commitment_txn used by our test framework
/// to bypass LocalCommitmentTransaction state update lockdown after signature and generate
/// revoked commitment transaction.
- #[cfg(test)]
+ #[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
pub fn unsafe_get_latest_local_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
log_trace!(logger, "Getting signed copy of latest local commitment transaction!");
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_local_tx(&self.funding_redeemscript) {
claimable_outpoints.push(ClaimRequest { absolute_timelock: height, aggregable: false, outpoint: BitcoinOutPoint { txid: self.funding_info.0.txid.clone(), vout: self.funding_info.0.index as u32 }, witness_data: InputMaterial::Funding { funding_redeemscript: self.funding_redeemscript.clone() }});
}
if should_broadcast {
+ self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_local_tx(&self.funding_redeemscript) {
+ self.local_tx_signed = true;
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_local_state(&commitment_tx, &self.current_local_commitment_tx);
if !new_outputs.is_empty() {
watch_outputs.push((self.current_local_commitment_tx.txid.clone(), new_outputs));
match ev {
OnchainEvent::HTLCUpdate { htlc_update } => {
log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!((htlc_update.1).0));
- self.pending_htlcs_updated.push(HTLCUpdate {
+ self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
payment_hash: htlc_update.1,
payment_preimage: None,
source: htlc_update.0,
- });
+ }));
},
OnchainEvent::MaturingOutput { descriptor } => {
log_trace!(logger, "Descriptor {} has got enough confirmations to be passed upstream", log_spendable!(descriptor));
- self.pending_events.push(events::Event::SpendableOutputs {
+ self.pending_events.push(Event::SpendableOutputs {
outputs: vec![descriptor]
});
}
}
}
}
+
self.onchain_tx_handler.block_connected(txn_matched, claimable_outpoints, height, &*broadcaster, &*fee_estimator, &*logger);
self.last_block_hash = block_hash.clone();
self.last_block_hash = block_hash.clone();
}
- pub(super) fn would_broadcast_at_height<L: Deref>(&self, height: u32, logger: &L) -> bool where L::Target: Logger {
+ fn would_broadcast_at_height<L: Deref>(&self, height: u32, logger: &L) -> bool where L::Target: Logger {
// We need to consider all HTLCs which are:
// * in any unrevoked remote commitment transaction, as they could broadcast said
// transactions and we'd end up in a race, or
if let Some((source, payment_hash)) = payment_data {
let mut payment_preimage = PaymentPreimage([0; 32]);
if accepted_preimage_claim {
- if !self.pending_htlcs_updated.iter().any(|update| update.source == source) {
+ if !self.pending_monitor_events.iter().any(
+ |update| if let &MonitorEvent::HTLCEvent(ref upd) = update { upd.source == source } else { false }) {
payment_preimage.0.copy_from_slice(&input.witness[3]);
- self.pending_htlcs_updated.push(HTLCUpdate {
+ self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
source,
payment_preimage: Some(payment_preimage),
payment_hash
- });
+ }));
}
} else if offered_preimage_claim {
- if !self.pending_htlcs_updated.iter().any(|update| update.source == source) {
+ if !self.pending_monitor_events.iter().any(
+ |update| if let &MonitorEvent::HTLCEvent(ref upd) = update {
+ upd.source == source
+ } else { false }) {
payment_preimage.0.copy_from_slice(&input.witness[1]);
- self.pending_htlcs_updated.push(HTLCUpdate {
+ self.pending_monitor_events.push(MonitorEvent::HTLCEvent(HTLCUpdate {
source,
payment_preimage: Some(payment_preimage),
payment_hash
- });
+ }));
}
} else {
log_info!(logger, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height{})", log_bytes!(payment_hash.0), height + ANTI_REORG_DELAY - 1);
fn is_paying_spendable_output<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) where L::Target: Logger {
let mut spendable_output = None;
for (i, outp) in tx.output.iter().enumerate() { // There is max one spendable output for any channel tx, including ones generated by us
+ if i > ::std::u16::MAX as usize {
+ // While it is possible that an output exists on chain which is greater than the
+ // 2^16th output in a given transaction, this is only possible if the output is not
+ // in a lightning transaction and was instead placed there by some third party who
+ // wishes to give us money for no reason.
+ // Namely, any lightning transactions which we pre-sign will never have anywhere
+ // near 2^16 outputs both because such transactions must have ~2^16 outputs who's
+ // scripts are not longer than one byte in length and because they are inherently
+ // non-standard due to their size.
+ // Thus, it is completely safe to ignore such outputs, and while it may result in
+ // us ignoring non-lightning fund to us, that is only possible if someone fills
+ // nearly a full block with garbage just to hit this case.
+ continue;
+ }
if outp.script_pubkey == self.destination_script {
spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
- outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
+ outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
output: outp.clone(),
});
break;
} else if let Some(ref broadcasted_local_revokable_script) = self.broadcasted_local_revokable_script {
if broadcasted_local_revokable_script.0 == outp.script_pubkey {
spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
- outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
+ outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
per_commitment_point: broadcasted_local_revokable_script.1,
to_self_delay: self.on_local_tx_csv,
output: outp.clone(),
}
} else if self.remote_payment_script == outp.script_pubkey {
spendable_output = Some(SpendableOutputDescriptor::StaticOutputRemotePayment {
- outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
+ outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
output: outp.clone(),
key_derivation_params: self.keys.key_derivation_params(),
});
break;
} else if outp.script_pubkey == self.shutdown_script {
spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
- outpoint: BitcoinOutPoint { txid: tx.txid(), vout: i as u32 },
+ outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
output: outp.clone(),
});
}
}
}
- let pending_htlcs_updated_len: u64 = Readable::read(reader)?;
- let mut pending_htlcs_updated = Vec::with_capacity(cmp::min(pending_htlcs_updated_len as usize, MAX_ALLOC_SIZE / (32 + 8*3)));
- for _ in 0..pending_htlcs_updated_len {
- pending_htlcs_updated.push(Readable::read(reader)?);
+ let pending_monitor_events_len: u64 = Readable::read(reader)?;
+ let mut pending_monitor_events = Vec::with_capacity(cmp::min(pending_monitor_events_len as usize, MAX_ALLOC_SIZE / (32 + 8*3)));
+ for _ in 0..pending_monitor_events_len {
+ let ev = match <u8 as Readable>::read(reader)? {
+ 0 => MonitorEvent::HTLCEvent(Readable::read(reader)?),
+ 1 => MonitorEvent::CommitmentTxBroadcasted(funding_info.0),
+ _ => return Err(DecodeError::InvalidValue)
+ };
+ pending_monitor_events.push(ev);
}
let pending_events_len: u64 = Readable::read(reader)?;
- let mut pending_events = Vec::with_capacity(cmp::min(pending_events_len as usize, MAX_ALLOC_SIZE / mem::size_of::<events::Event>()));
+ let mut pending_events = Vec::with_capacity(cmp::min(pending_events_len as usize, MAX_ALLOC_SIZE / mem::size_of::<Event>()));
for _ in 0..pending_events_len {
if let Some(event) = MaybeReadable::read(reader)? {
pending_events.push(event);
current_local_commitment_number,
payment_preimages,
- pending_htlcs_updated,
+ pending_monitor_events,
pending_events,
onchain_events_waiting_threshold_conf,