//! ChannelMonitors should do so). Thus, if you're building rust-lightning into an HSM or other
//! security-domain-separated system design, you should consider having multiple paths for
//! ChannelMonitors to get out of the HSM and onto monitoring devices.
-//!
-//! [`chain::Watch`]: ../trait.Watch.html
-use bitcoin::blockdata::block::BlockHeader;
+use bitcoin::blockdata::block::{Block, BlockHeader};
use bitcoin::blockdata::transaction::{TxOut,Transaction};
use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
use bitcoin::blockdata::script::{Script, Builder};
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
use bitcoin::secp256k1;
+use ln::{PaymentHash, PaymentPreimage};
use ln::msgs::DecodeError;
use ln::chan_utils;
use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCType, ChannelTransactionParameters, HolderCommitmentTransaction};
-use ln::channelmanager::{HTLCSource, PaymentPreimage, PaymentHash};
+use ln::channelmanager::{BestBlock, HTLCSource};
use ln::onchaintx::{OnchainTxHandler, InputDescriptors};
+use chain;
+use chain::WatchedOutput;
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
use chain::transaction::{OutPoint, TransactionData};
-use chain::keysinterface::{SpendableOutputDescriptor, ChannelKeys, KeysInterface};
+use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface};
+use chain::Filter;
use util::logger::Logger;
use util::ser::{Readable, ReadableArgs, MaybeReadable, Writer, Writeable, U48};
use util::byte_utils;
use util::events::Event;
-use std::collections::{HashMap, HashSet, hash_map};
+use std::collections::{HashMap, HashSet};
use std::{cmp, mem};
-use std::ops::Deref;
use std::io::Error;
+use std::ops::Deref;
+use std::sync::Mutex;
/// An update generated by the underlying Channel itself which contains some new information the
/// ChannelMonitor should be made aware of.
/// The only instance where update_id values are not strictly increasing is the case where we
/// allow post-force-close updates with a special update ID of [`CLOSED_CHANNEL_UPDATE_ID`]. See
/// its docs for more details.
- ///
- /// [`CLOSED_CHANNEL_UPDATE_ID`]: constant.CLOSED_CHANNEL_UPDATE_ID.html
pub update_id: u64,
}
/// means you tried to update a monitor for a different channel or the ChannelMonitorUpdate was
/// corrupted.
/// Contains a developer-readable error message.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub struct MonitorUpdateError(pub &'static str);
/// An event to be processed by the ChannelManager.
/// Simple structure sent back by `chain::Watch` when an HTLC from a forward channel is detected on
/// chain. Used to update the corresponding HTLC in the backward channel. Failing to pass the
/// preimage claim backward will lead to loss of funds.
-///
-/// [`chain::Watch`]: ../trait.Watch.html
#[derive(Clone, PartialEq)]
pub struct HTLCUpdate {
pub(crate) payment_hash: PaymentHash,
/// HTLC-Success transaction.
/// In other words, this is an upper bound on how many blocks we think it can take us to get a
/// transaction confirmed (and we use it in a few more, equivalent, places).
-pub(crate) const CLTV_CLAIM_BUFFER: u32 = 6;
+pub(crate) const CLTV_CLAIM_BUFFER: u32 = 18;
/// Number of blocks by which point we expect our counterparty to have seen new blocks on the
/// network and done a full update_fail_htlc/commitment_signed dance (+ we've updated all our
/// copies of ChannelMonitors, including watchtowers). We could enforce the contract by failing
pub(crate) witness_data: InputMaterial
}
+/// An entry for an [`OnchainEvent`], stating the block height when the event was observed and the
+/// transaction causing it.
+///
+/// Used to determine when the on-chain event can be considered safe from a chain reorganization.
+#[derive(PartialEq)]
+struct OnchainEventEntry {
+ txid: Txid,
+ height: u32,
+ event: OnchainEvent,
+}
+
+impl OnchainEventEntry {
+ fn confirmation_threshold(&self) -> u32 {
+ self.height + ANTI_REORG_DELAY - 1
+ }
+
+ fn has_reached_confirmation_threshold(&self, height: u32) -> bool {
+ height >= self.confirmation_threshold()
+ }
+}
+
/// Upon discovering of some classes of onchain tx by ChannelMonitor, we may have to take actions on it
/// once they mature to enough confirmations (ANTI_REORG_DELAY)
-#[derive(Clone, PartialEq)]
+#[derive(PartialEq)]
enum OnchainEvent {
/// HTLC output getting solved by a timeout, at maturation we pass upstream payment source information to solve
/// inbound HTLC in backward channel. Note, in case of preimage, we pass info to upstream without delay as we can
/// reloaded at deserialize-time. Thus, you must ensure that, when handling events, all events
/// gotten are fully handled before re-serializing the new state.
///
-/// Note that the deserializer is only implemented for (Sha256dHash, ChannelMonitor), which
+/// Note that the deserializer is only implemented for (BlockHash, ChannelMonitor), which
/// tells you the last block hash which was block_connect()ed. You MUST rescan any blocks along
/// 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 struct ChannelMonitor<ChanSigner: ChannelKeys> {
+pub struct ChannelMonitor<Signer: Sign> {
+ #[cfg(test)]
+ pub(crate) inner: Mutex<ChannelMonitorImpl<Signer>>,
+ #[cfg(not(test))]
+ inner: Mutex<ChannelMonitorImpl<Signer>>,
+}
+
+pub(crate) struct ChannelMonitorImpl<Signer: Sign> {
latest_update_id: u64,
commitment_transaction_number_obscure_factor: u64,
counterparty_payment_script: Script,
shutdown_script: Script,
- key_derivation_params: (u64, u64),
+ channel_keys_id: [u8; 32],
holder_revocation_basepoint: PublicKey,
funding_info: (OutPoint, Script),
current_counterparty_commitment_txid: Option<Txid>,
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
- // actions when we receive a block with given height. Actions depend on OnchainEvent type.
- onchain_events_waiting_threshold_conf: HashMap<u32, Vec<OnchainEvent>>,
+ // Used to track on-chain events (i.e., transactions part of channels confirmed on chain) on
+ // which to take actions once they reach enough confirmations. Each entry includes the
+ // transaction's id and the height when the transaction was confirmed on chain.
+ onchain_events_awaiting_threshold_conf: Vec<OnchainEventEntry>,
// If we get serialized out and re-read, we need to make sure that the chain monitoring
// interface knows about the TXOs that we want to be notified of spends of. We could probably
outputs_to_watch: HashMap<Txid, Vec<(u32, Script)>>,
#[cfg(test)]
- pub onchain_tx_handler: OnchainTxHandler<ChanSigner>,
+ pub onchain_tx_handler: OnchainTxHandler<Signer>,
#[cfg(not(test))]
- onchain_tx_handler: OnchainTxHandler<ChanSigner>,
+ onchain_tx_handler: OnchainTxHandler<Signer>,
// This is set when the Channel[Manager] generated a ChannelMonitorUpdate which indicated the
// channel has been force-closed. After this is set, no further holder commitment transaction
// remote monitor out-of-order with regards to the block view.
holder_tx_signed: bool,
- // We simply modify last_block_hash in Channel's block_connected so that serialization is
+ // We simply modify best_block in Channel's block_connected so that serialization is
// consistent but hopefully the users' copy handles block_connected in a consistent way.
// (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
+ // their best_block from its state and not based on updated copies that didn't run through
// the full block_connected).
- last_block_hash: BlockHash,
+ best_block: BestBlock,
+
secp_ctx: Secp256k1<secp256k1::All>, //TODO: dedup this a bit...
}
+/// Transaction outputs to watch for on-chain spends.
+pub type TransactionOutputs = (Txid, Vec<(u32, TxOut)>);
+
#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
/// Used only in testing and fuzztarget to check serialization roundtrips don't change the
/// underlying object
-impl<ChanSigner: ChannelKeys> PartialEq for ChannelMonitor<ChanSigner> {
+impl<Signer: Sign> PartialEq for ChannelMonitor<Signer> {
+ fn eq(&self, other: &Self) -> bool {
+ let inner = self.inner.lock().unwrap();
+ let other = other.inner.lock().unwrap();
+ inner.eq(&other)
+ }
+}
+
+#[cfg(any(test, feature = "fuzztarget", feature = "_test_utils"))]
+/// Used only in testing and fuzztarget to check serialization roundtrips don't change the
+/// underlying object
+impl<Signer: Sign> PartialEq for ChannelMonitorImpl<Signer> {
fn eq(&self, other: &Self) -> bool {
if self.latest_update_id != other.latest_update_id ||
self.commitment_transaction_number_obscure_factor != other.commitment_transaction_number_obscure_factor ||
self.destination_script != other.destination_script ||
self.broadcasted_holder_revokable_script != other.broadcasted_holder_revokable_script ||
self.counterparty_payment_script != other.counterparty_payment_script ||
- self.key_derivation_params != other.key_derivation_params ||
+ self.channel_keys_id != other.channel_keys_id ||
self.holder_revocation_basepoint != other.holder_revocation_basepoint ||
self.funding_info != other.funding_info ||
self.current_counterparty_commitment_txid != other.current_counterparty_commitment_txid ||
self.payment_preimages != other.payment_preimages ||
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.onchain_events_awaiting_threshold_conf != other.onchain_events_awaiting_threshold_conf ||
self.outputs_to_watch != other.outputs_to_watch ||
self.lockdown_from_offchain != other.lockdown_from_offchain ||
self.holder_tx_signed != other.holder_tx_signed
}
}
-impl<ChanSigner: ChannelKeys> Writeable for ChannelMonitor<ChanSigner> {
+impl<Signer: Sign> Writeable for ChannelMonitor<Signer> {
fn write<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(&[MIN_SERIALIZATION_VERSION; 1])?;
+ self.inner.lock().unwrap().write(writer)
+ }
+}
+
+impl<Signer: Sign> Writeable for ChannelMonitorImpl<Signer> {
+ fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
self.latest_update_id.write(writer)?;
// Set in initial Channel-object creation, so should always be set by now:
self.counterparty_payment_script.write(writer)?;
self.shutdown_script.write(writer)?;
- self.key_derivation_params.write(writer)?;
+ self.channel_keys_id.write(writer)?;
self.holder_revocation_basepoint.write(writer)?;
writer.write_all(&self.funding_info.0.txid[..])?;
writer.write_all(&byte_utils::be16_to_array(self.funding_info.0.index))?;
event.write(writer)?;
}
- self.last_block_hash.write(writer)?;
+ self.best_block.block_hash().write(writer)?;
+ writer.write_all(&byte_utils::be32_to_array(self.best_block.height()))?;
- writer.write_all(&byte_utils::be64_to_array(self.onchain_events_waiting_threshold_conf.len() as u64))?;
- for (ref target, ref events) in self.onchain_events_waiting_threshold_conf.iter() {
- writer.write_all(&byte_utils::be32_to_array(**target))?;
- writer.write_all(&byte_utils::be64_to_array(events.len() as u64))?;
- for ev in events.iter() {
- match *ev {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- 0u8.write(writer)?;
- htlc_update.0.write(writer)?;
- htlc_update.1.write(writer)?;
- },
- OnchainEvent::MaturingOutput { ref descriptor } => {
- 1u8.write(writer)?;
- descriptor.write(writer)?;
- },
- }
+ writer.write_all(&byte_utils::be64_to_array(self.onchain_events_awaiting_threshold_conf.len() as u64))?;
+ for ref entry in self.onchain_events_awaiting_threshold_conf.iter() {
+ entry.txid.write(writer)?;
+ writer.write_all(&byte_utils::be32_to_array(entry.height))?;
+ match entry.event {
+ OnchainEvent::HTLCUpdate { ref htlc_update } => {
+ 0u8.write(writer)?;
+ htlc_update.0.write(writer)?;
+ htlc_update.1.write(writer)?;
+ },
+ OnchainEvent::MaturingOutput { ref descriptor } => {
+ 1u8.write(writer)?;
+ descriptor.write(writer)?;
+ },
}
}
}
}
-impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
- pub(crate) fn new(keys: ChanSigner, shutdown_pubkey: &PublicKey,
+impl<Signer: Sign> ChannelMonitor<Signer> {
+ pub(crate) fn new(secp_ctx: Secp256k1<secp256k1::All>, keys: Signer, shutdown_pubkey: &PublicKey,
on_counterparty_tx_csv: u16, destination_script: &Script, funding_info: (OutPoint, Script),
channel_parameters: &ChannelTransactionParameters,
funding_redeemscript: Script, channel_value_satoshis: u64,
commitment_transaction_number_obscure_factor: u64,
- initial_holder_commitment_tx: HolderCommitmentTransaction) -> ChannelMonitor<ChanSigner> {
+ initial_holder_commitment_tx: HolderCommitmentTransaction,
+ best_block: BestBlock) -> ChannelMonitor<Signer> {
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
let our_channel_close_key_hash = WPubkeyHash::hash(&shutdown_pubkey.serialize());
let counterparty_htlc_base_key = counterparty_channel_parameters.pubkeys.htlc_basepoint;
let counterparty_tx_cache = CounterpartyCommitmentTransaction { counterparty_delayed_payment_base_key, counterparty_htlc_base_key, on_counterparty_tx_csv, per_htlc: HashMap::new() };
- let key_derivation_params = keys.key_derivation_params();
+ let channel_keys_id = keys.channel_keys_id();
let holder_revocation_basepoint = keys.pubkeys().revocation_basepoint;
- let mut onchain_tx_handler = OnchainTxHandler::new(destination_script.clone(), keys, channel_parameters.clone());
-
- let secp_ctx = Secp256k1::new();
// block for Rust 1.34 compat
let (holder_commitment_tx, current_holder_commitment_number) = {
};
(holder_commitment_tx, trusted_tx.commitment_number())
};
- onchain_tx_handler.provide_latest_holder_tx(initial_holder_commitment_tx);
+
+ let onchain_tx_handler =
+ OnchainTxHandler::new(destination_script.clone(), keys,
+ channel_parameters.clone(), initial_holder_commitment_tx, secp_ctx.clone());
let mut outputs_to_watch = HashMap::new();
outputs_to_watch.insert(funding_info.0.txid, vec![(funding_info.0.index as u32, funding_info.1.clone())]);
ChannelMonitor {
- latest_update_id: 0,
- commitment_transaction_number_obscure_factor,
+ inner: Mutex::new(ChannelMonitorImpl {
+ latest_update_id: 0,
+ commitment_transaction_number_obscure_factor,
+
+ destination_script: destination_script.clone(),
+ broadcasted_holder_revokable_script: None,
+ counterparty_payment_script,
+ shutdown_script,
- destination_script: destination_script.clone(),
- broadcasted_holder_revokable_script: None,
- counterparty_payment_script,
- shutdown_script,
+ channel_keys_id,
+ holder_revocation_basepoint,
+ funding_info,
+ current_counterparty_commitment_txid: None,
+ prev_counterparty_commitment_txid: None,
- key_derivation_params,
- holder_revocation_basepoint,
- funding_info,
- current_counterparty_commitment_txid: None,
- prev_counterparty_commitment_txid: None,
+ counterparty_tx_cache,
+ funding_redeemscript,
+ channel_value_satoshis,
+ their_cur_revocation_points: None,
- counterparty_tx_cache,
- funding_redeemscript,
- channel_value_satoshis,
- their_cur_revocation_points: None,
+ on_holder_tx_csv: counterparty_channel_parameters.selected_contest_delay,
- on_holder_tx_csv: counterparty_channel_parameters.selected_contest_delay,
+ commitment_secrets: CounterpartyCommitmentSecrets::new(),
+ counterparty_claimable_outpoints: HashMap::new(),
+ counterparty_commitment_txn_on_chain: HashMap::new(),
+ counterparty_hash_commitment_number: HashMap::new(),
- commitment_secrets: CounterpartyCommitmentSecrets::new(),
- counterparty_claimable_outpoints: HashMap::new(),
- counterparty_commitment_txn_on_chain: HashMap::new(),
- counterparty_hash_commitment_number: HashMap::new(),
+ prev_holder_signed_commitment_tx: None,
+ current_holder_commitment_tx: holder_commitment_tx,
+ current_counterparty_commitment_number: 1 << 48,
+ current_holder_commitment_number,
- prev_holder_signed_commitment_tx: None,
- current_holder_commitment_tx: holder_commitment_tx,
- current_counterparty_commitment_number: 1 << 48,
- current_holder_commitment_number,
+ payment_preimages: HashMap::new(),
+ pending_monitor_events: Vec::new(),
+ pending_events: Vec::new(),
- payment_preimages: HashMap::new(),
- pending_monitor_events: Vec::new(),
- pending_events: Vec::new(),
+ onchain_events_awaiting_threshold_conf: Vec::new(),
+ outputs_to_watch,
- onchain_events_waiting_threshold_conf: HashMap::new(),
- outputs_to_watch,
+ onchain_tx_handler,
- onchain_tx_handler,
+ lockdown_from_offchain: false,
+ holder_tx_signed: false,
- lockdown_from_offchain: false,
- holder_tx_signed: false,
+ best_block,
- last_block_hash: Default::default(),
- secp_ctx,
+ secp_ctx,
+ }),
}
}
+ #[cfg(test)]
+ fn provide_secret(&self, idx: u64, secret: [u8; 32]) -> Result<(), MonitorUpdateError> {
+ self.inner.lock().unwrap().provide_secret(idx, secret)
+ }
+
+ /// Informs this monitor of the latest counterparty (ie non-broadcastable) commitment transaction.
+ /// The monitor watches for it to be broadcasted and then uses the HTLC information (and
+ /// possibly future revocation/preimage information) to claim outputs where possible.
+ /// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers.
+ pub(crate) fn provide_latest_counterparty_commitment_tx<L: Deref>(
+ &self,
+ txid: Txid,
+ htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>,
+ commitment_number: u64,
+ their_revocation_point: PublicKey,
+ logger: &L,
+ ) where L::Target: Logger {
+ self.inner.lock().unwrap().provide_latest_counterparty_commitment_tx(
+ txid, htlc_outputs, commitment_number, their_revocation_point, logger)
+ }
+
+ #[cfg(test)]
+ fn provide_latest_holder_commitment_tx(
+ &self,
+ holder_commitment_tx: HolderCommitmentTransaction,
+ htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Signature>, Option<HTLCSource>)>,
+ ) -> Result<(), MonitorUpdateError> {
+ self.inner.lock().unwrap().provide_latest_holder_commitment_tx(
+ holder_commitment_tx, htlc_outputs)
+ }
+
+ #[cfg(test)]
+ pub(crate) fn provide_payment_preimage<B: Deref, F: Deref, L: Deref>(
+ &self,
+ payment_hash: &PaymentHash,
+ payment_preimage: &PaymentPreimage,
+ broadcaster: &B,
+ fee_estimator: &F,
+ logger: &L,
+ ) where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().provide_payment_preimage(
+ payment_hash, payment_preimage, broadcaster, fee_estimator, logger)
+ }
+
+ pub(crate) fn broadcast_latest_holder_commitment_txn<B: Deref, L: Deref>(
+ &self,
+ broadcaster: &B,
+ logger: &L,
+ ) where
+ B::Target: BroadcasterInterface,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().broadcast_latest_holder_commitment_txn(broadcaster, logger)
+ }
+
+ /// Updates a ChannelMonitor on the basis of some new information provided by the Channel
+ /// itself.
+ ///
+ /// panics if the given update is not the next update by update_id.
+ pub fn update_monitor<B: Deref, F: Deref, L: Deref>(
+ &self,
+ updates: &ChannelMonitorUpdate,
+ broadcaster: &B,
+ fee_estimator: &F,
+ logger: &L,
+ ) -> Result<(), MonitorUpdateError>
+ where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().update_monitor(updates, broadcaster, fee_estimator, logger)
+ }
+
+ /// Gets the update_id from the latest ChannelMonitorUpdate which was applied to this
+ /// ChannelMonitor.
+ pub fn get_latest_update_id(&self) -> u64 {
+ self.inner.lock().unwrap().get_latest_update_id()
+ }
+
+ /// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for.
+ pub fn get_funding_txo(&self) -> (OutPoint, Script) {
+ self.inner.lock().unwrap().get_funding_txo().clone()
+ }
+
+ /// Gets a list of txids, with their output scripts (in the order they appear in the
+ /// transaction), which we must learn about spends of via block_connected().
+ pub fn get_outputs_to_watch(&self) -> Vec<(Txid, Vec<(u32, Script)>)> {
+ self.inner.lock().unwrap().get_outputs_to_watch()
+ .iter().map(|(txid, outputs)| (*txid, outputs.clone())).collect()
+ }
+
+ /// Loads the funding txo and outputs to watch into the given `chain::Filter` by repeatedly
+ /// calling `chain::Filter::register_output` and `chain::Filter::register_tx` until all outputs
+ /// have been registered.
+ pub fn load_outputs_to_watch<F: Deref>(&self, filter: &F) where F::Target: chain::Filter {
+ let lock = self.inner.lock().unwrap();
+ filter.register_tx(&lock.get_funding_txo().0.txid, &lock.get_funding_txo().1);
+ for (txid, outputs) in lock.get_outputs_to_watch().iter() {
+ for (index, script_pubkey) in outputs.iter() {
+ assert!(*index <= u16::max_value() as u32);
+ filter.register_output(WatchedOutput {
+ block_hash: None,
+ outpoint: OutPoint { txid: *txid, index: *index as u16 },
+ script_pubkey: script_pubkey.clone(),
+ });
+ }
+ }
+ }
+
+ /// Get the list of HTLCs who's status has been updated on chain. This should be called by
+ /// ChannelManager via [`chain::Watch::release_pending_monitor_events`].
+ pub fn get_and_clear_pending_monitor_events(&self) -> Vec<MonitorEvent> {
+ self.inner.lock().unwrap().get_and_clear_pending_monitor_events()
+ }
+
+ /// Gets the list of pending events which were generated by previous actions, clearing the list
+ /// in the process.
+ ///
+ /// This is called by ChainMonitor::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(&self) -> Vec<Event> {
+ self.inner.lock().unwrap().get_and_clear_pending_events()
+ }
+
+ pub(crate) fn get_min_seen_secret(&self) -> u64 {
+ self.inner.lock().unwrap().get_min_seen_secret()
+ }
+
+ pub(crate) fn get_cur_counterparty_commitment_number(&self) -> u64 {
+ self.inner.lock().unwrap().get_cur_counterparty_commitment_number()
+ }
+
+ pub(crate) fn get_cur_holder_commitment_number(&self) -> u64 {
+ self.inner.lock().unwrap().get_cur_holder_commitment_number()
+ }
+
+ /// Used by ChannelManager deserialization to broadcast the latest holder state if its copy of
+ /// the Channel was out-of-date. You may use it to get a broadcastable holder toxic tx in case of
+ /// fallen-behind, i.e when receiving a channel_reestablish with a proof that our counterparty side knows
+ /// a higher revocation secret than the holder commitment number we are aware of. Broadcasting these
+ /// transactions are UNSAFE, as they allow counterparty side to punish you. Nevertheless you may want to
+ /// broadcast them if counterparty don't close channel with his higher commitment transaction after a
+ /// substantial amount of time (a month or even a year) to get back funds. Best may be to contact
+ /// out-of-band the other node operator to coordinate with him if option is available to you.
+ /// In any-case, choice is up to the user.
+ pub fn get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
+ where L::Target: Logger {
+ self.inner.lock().unwrap().get_latest_holder_commitment_txn(logger)
+ }
+
+ /// Unsafe test-only version of get_latest_holder_commitment_txn used by our test framework
+ /// to bypass HolderCommitmentTransaction state update lockdown after signature and generate
+ /// revoked commitment transaction.
+ #[cfg(any(test, feature = "unsafe_revoked_tx_signing"))]
+ pub fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&self, logger: &L) -> Vec<Transaction>
+ where L::Target: Logger {
+ self.inner.lock().unwrap().unsafe_get_latest_holder_commitment_txn(logger)
+ }
+
+ /// Processes transactions in a newly connected block, which may result in any of the following:
+ /// - update the monitor's state against resolved HTLCs
+ /// - punish the counterparty in the case of seeing a revoked commitment transaction
+ /// - force close the channel and claim/timeout incoming/outgoing HTLCs if near expiration
+ /// - detect settled outputs for later spending
+ /// - schedule and bump any in-flight claims
+ ///
+ /// Returns any new outputs to watch from `txdata`; after called, these are also included in
+ /// [`get_outputs_to_watch`].
+ ///
+ /// [`get_outputs_to_watch`]: #method.get_outputs_to_watch
+ pub fn block_connected<B: Deref, F: Deref, L: Deref>(
+ &self,
+ header: &BlockHeader,
+ txdata: &TransactionData,
+ height: u32,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) -> Vec<TransactionOutputs>
+ where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().block_connected(
+ header, txdata, height, broadcaster, fee_estimator, logger)
+ }
+
+ /// Determines if the disconnected block contained any transactions of interest and updates
+ /// appropriately.
+ pub fn block_disconnected<B: Deref, F: Deref, L: Deref>(
+ &self,
+ header: &BlockHeader,
+ height: u32,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().block_disconnected(
+ header, height, broadcaster, fee_estimator, logger)
+ }
+
+ /// Processes transactions confirmed in a block with the given header and height, returning new
+ /// outputs to watch. See [`block_connected`] for details.
+ ///
+ /// Used instead of [`block_connected`] by clients that are notified of transactions rather than
+ /// blocks. See [`chain::Confirm`] for calling expectations.
+ ///
+ /// [`block_connected`]: Self::block_connected
+ pub fn transactions_confirmed<B: Deref, F: Deref, L: Deref>(
+ &self,
+ header: &BlockHeader,
+ txdata: &TransactionData,
+ height: u32,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) -> Vec<TransactionOutputs>
+ where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().transactions_confirmed(
+ header, txdata, height, broadcaster, fee_estimator, logger)
+ }
+
+ /// Processes a transaction that was reorganized out of the chain.
+ ///
+ /// Used instead of [`block_disconnected`] by clients that are notified of transactions rather
+ /// than blocks. See [`chain::Confirm`] for calling expectations.
+ ///
+ /// [`block_disconnected`]: Self::block_disconnected
+ pub fn transaction_unconfirmed<B: Deref, F: Deref, L: Deref>(
+ &self,
+ txid: &Txid,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().transaction_unconfirmed(
+ txid, broadcaster, fee_estimator, logger);
+ }
+
+ /// Updates the monitor with the current best chain tip, returning new outputs to watch. See
+ /// [`block_connected`] for details.
+ ///
+ /// Used instead of [`block_connected`] by clients that are notified of transactions rather than
+ /// blocks. See [`chain::Confirm`] for calling expectations.
+ ///
+ /// [`block_connected`]: Self::block_connected
+ pub fn best_block_updated<B: Deref, F: Deref, L: Deref>(
+ &self,
+ header: &BlockHeader,
+ height: u32,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) -> Vec<TransactionOutputs>
+ where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.inner.lock().unwrap().best_block_updated(
+ header, height, broadcaster, fee_estimator, logger)
+ }
+
+ /// Returns the set of txids that should be monitored for re-organization out of the chain.
+ pub fn get_relevant_txids(&self) -> Vec<Txid> {
+ let inner = self.inner.lock().unwrap();
+ let mut txids: Vec<Txid> = inner.onchain_events_awaiting_threshold_conf
+ .iter()
+ .map(|entry| entry.txid)
+ .chain(inner.onchain_tx_handler.get_relevant_txids().into_iter())
+ .collect();
+ txids.sort_unstable();
+ txids.dedup();
+ txids
+ }
+}
+
+impl<Signer: Sign> ChannelMonitorImpl<Signer> {
/// Inserts a revocation secret into this channel monitor. Prunes old preimages if neither
/// needed by holder commitment transactions HTCLs nor by counterparty ones. Unless we haven't already seen
/// counterparty commitment transaction's secret, they are de facto pruned (we can use revocation key).
Ok(())
}
- /// Informs this monitor of the latest counterparty (ie non-broadcastable) commitment transaction.
- /// The monitor watches for it to be broadcasted and then uses the HTLC information (and
- /// possibly future revocation/preimage information) to claim outputs where possible.
- /// We cache also the mapping hash:commitment number to lighten pruning of old preimages by watchtowers.
pub(crate) fn provide_latest_counterparty_commitment_tx<L: Deref>(&mut self, txid: Txid, htlc_outputs: Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>, commitment_number: u64, their_revocation_point: PublicKey, logger: &L) where L::Target: Logger {
// TODO: Encrypt the htlc_outputs data with the single-hash of the commitment transaction
// so that a remote monitor doesn't learn anything unless there is a malicious close.
/// Provides a payment_hash->payment_preimage mapping. Will be automatically pruned when all
/// commitment_tx_infos which contain the payment hash have been revoked.
- pub(crate) fn provide_payment_preimage<B: Deref, F: Deref, L: Deref>(&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage, broadcaster: &B, fee_estimator: &F, logger: &L)
+ fn provide_payment_preimage<B: Deref, F: Deref, L: Deref>(&mut self, payment_hash: &PaymentHash, payment_preimage: &PaymentPreimage, broadcaster: &B, fee_estimator: &F, logger: &L)
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator,
L::Target: Logger,
L::Target: Logger,
{
for tx in self.get_latest_holder_commitment_txn(logger).iter() {
+ log_info!(logger, "Broadcasting local {}", log_tx!(tx));
broadcaster.broadcast_transaction(tx);
}
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
- /// itself.
- ///
- /// panics if the given update is not the next update by update_id.
pub fn update_monitor<B: Deref, F: Deref, L: Deref>(&mut self, updates: &ChannelMonitorUpdate, broadcaster: &B, fee_estimator: &F, logger: &L) -> Result<(), MonitorUpdateError>
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator,
self.lockdown_from_offchain = true;
if *should_broadcast {
self.broadcast_latest_holder_commitment_txn(broadcaster, logger);
- } else {
+ } else if !self.holder_tx_signed {
log_error!(logger, "You have a toxic holder commitment transaction avaible in channel monitor, read comment in ChannelMonitor::get_latest_holder_commitment_txn to be informed of manual action to take");
+ } else {
+ // If we generated a MonitorEvent::CommitmentTxBroadcasted, the ChannelManager
+ // will still give us a ChannelForceClosed event with !should_broadcast, but we
+ // shouldn't print the scary warning above.
+ log_info!(logger, "Channel off-chain state closed after we broadcasted our latest commitment transaction.");
}
}
}
Ok(())
}
- /// Gets the update_id from the latest ChannelMonitorUpdate which was applied to this
- /// ChannelMonitor.
pub fn get_latest_update_id(&self) -> u64 {
self.latest_update_id
}
- /// Gets the funding transaction outpoint of the channel this ChannelMonitor is monitoring for.
pub fn get_funding_txo(&self) -> &(OutPoint, Script) {
&self.funding_info
}
- /// Gets a list of txids, with their output scripts (in the order they appear in the
- /// transaction), which we must learn about spends of via block_connected().
- ///
- /// (C-not exported) because we have no HashMap bindings
pub fn get_outputs_to_watch(&self) -> &HashMap<Txid, Vec<(u32, Script)>> {
// If we've detected a counterparty commitment tx on chain, we must include it in the set
// of outputs to watch for spends of, otherwise we're likely to lose user funds. Because
&self.outputs_to_watch
}
- /// Get the list of HTLCs who's status has been updated on chain. This should be called by
- /// ChannelManager via [`chain::Watch::release_pending_monitor_events`].
- ///
- /// [`chain::Watch::release_pending_monitor_events`]: ../trait.Watch.html#tymethod.release_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_monitor_events);
ret
}
- /// Gets the list of pending events which were generated by previous actions, clearing the list
- /// in the process.
- ///
- /// This is called by ChainMonitor::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<Event> {
let mut ret = Vec::new();
mem::swap(&mut ret, &mut self.pending_events);
/// HTLC-Success/HTLC-Timeout transactions.
/// Return updates for HTLC pending in the channel and failed automatically by the broadcast of
/// revoked counterparty commitment tx
- fn check_spend_counterparty_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<ClaimRequest>, (Txid, Vec<(u32, TxOut)>)) where L::Target: Logger {
+ fn check_spend_counterparty_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<ClaimRequest>, TransactionOutputs) where L::Target: Logger {
// Most secp and related errors trying to create keys means we have no hope of constructing
// a spend transaction...so we return no transactions to broadcast
let mut claimable_outpoints = Vec::new();
if let Some(ref outpoints) = self.counterparty_claimable_outpoints.get($txid) {
for &(ref htlc, ref source_option) in outpoints.iter() {
if let &Some(ref source) = source_option {
- log_info!(logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of revoked counterparty commitment transaction, waiting for confirmation (at height {})", log_bytes!(htlc.payment_hash.0), $commitment_tx, height + ANTI_REORG_DELAY - 1);
- match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) {
- hash_map::Entry::Occupied(mut entry) => {
- let e = entry.get_mut();
- e.retain(|ref event| {
- match **event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- return htlc_update.0 != **source
- },
- _ => true
- }
- });
- e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
- }
- hash_map::Entry::Vacant(entry) => {
- entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())}]);
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
+ if entry.height != height { return true; }
+ match entry.event {
+ OnchainEvent::HTLCUpdate { ref htlc_update } => {
+ htlc_update.0 != **source
+ },
+ _ => true,
}
- }
+ });
+ let entry = OnchainEventEntry {
+ txid: *$txid,
+ height,
+ event: OnchainEvent::HTLCUpdate {
+ htlc_update: ((**source).clone(), htlc.payment_hash.clone())
+ },
+ };
+ log_info!(logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of revoked counterparty commitment transaction, waiting for confirmation (at height {})", log_bytes!(htlc.payment_hash.0), $commitment_tx, entry.confirmation_threshold());
+ self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
}
}
}
log_trace!(logger, "Failing HTLC with payment_hash {} from {} counterparty commitment tx due to broadcast of counterparty commitment transaction", log_bytes!(htlc.payment_hash.0), $commitment_tx);
- match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) {
- hash_map::Entry::Occupied(mut entry) => {
- let e = entry.get_mut();
- e.retain(|ref event| {
- match **event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- return htlc_update.0 != **source
- },
- _ => true
- }
- });
- e.push(OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())});
- }
- hash_map::Entry::Vacant(entry) => {
- entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: ((**source).clone(), htlc.payment_hash.clone())}]);
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
+ if entry.height != height { return true; }
+ match entry.event {
+ OnchainEvent::HTLCUpdate { ref htlc_update } => {
+ htlc_update.0 != **source
+ },
+ _ => true,
}
- }
+ });
+ self.onchain_events_awaiting_threshold_conf.push(OnchainEventEntry {
+ txid: *$txid,
+ height,
+ event: OnchainEvent::HTLCUpdate {
+ htlc_update: ((**source).clone(), htlc.payment_hash.clone())
+ },
+ });
}
}
}
}
/// Attempts to claim a counterparty HTLC-Success/HTLC-Timeout's outputs using the revocation key
- fn check_spend_counterparty_htlc<L: Deref>(&mut self, tx: &Transaction, commitment_number: u64, height: u32, logger: &L) -> (Vec<ClaimRequest>, Option<(Txid, Vec<(u32, TxOut)>)>) where L::Target: Logger {
+ fn check_spend_counterparty_htlc<L: Deref>(&mut self, tx: &Transaction, commitment_number: u64, height: u32, logger: &L) -> (Vec<ClaimRequest>, Option<TransactionOutputs>) where L::Target: Logger {
let htlc_txid = tx.txid();
if tx.input.len() != 1 || tx.output.len() != 1 || tx.input[0].witness.len() != 5 {
return (Vec::new(), None)
/// Attempts to claim any claimable HTLCs in a commitment transaction which was not (yet)
/// revoked using data in holder_claimable_outpoints.
/// Should not be used if check_spend_revoked_transaction succeeds.
- fn check_spend_holder_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<ClaimRequest>, (Txid, Vec<(u32, TxOut)>)) where L::Target: Logger {
+ fn check_spend_holder_transaction<L: Deref>(&mut self, tx: &Transaction, height: u32, logger: &L) -> (Vec<ClaimRequest>, TransactionOutputs) where L::Target: Logger {
let commitment_txid = tx.txid();
let mut claim_requests = Vec::new();
let mut watch_outputs = Vec::new();
macro_rules! wait_threshold_conf {
- ($height: expr, $source: expr, $commitment_tx: expr, $payment_hash: expr) => {
- log_trace!(logger, "Failing HTLC with payment_hash {} from {} holder commitment tx due to broadcast of transaction, waiting confirmation (at height{})", log_bytes!($payment_hash.0), $commitment_tx, height + ANTI_REORG_DELAY - 1);
- match self.onchain_events_waiting_threshold_conf.entry($height + ANTI_REORG_DELAY - 1) {
- hash_map::Entry::Occupied(mut entry) => {
- let e = entry.get_mut();
- e.retain(|ref event| {
- match **event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- return htlc_update.0 != $source
- },
- _ => true
- }
- });
- e.push(OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash)});
+ ($source: expr, $commitment_tx: expr, $payment_hash: expr) => {
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
+ if entry.height != height { return true; }
+ match entry.event {
+ OnchainEvent::HTLCUpdate { ref htlc_update } => {
+ htlc_update.0 != $source
+ },
+ _ => true,
}
- hash_map::Entry::Vacant(entry) => {
- entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash)}]);
- }
- }
+ });
+ let entry = OnchainEventEntry {
+ txid: commitment_txid,
+ height,
+ event: OnchainEvent::HTLCUpdate { htlc_update: ($source, $payment_hash) },
+ };
+ log_trace!(logger, "Failing HTLC with payment_hash {} from {} holder commitment tx due to broadcast of transaction, waiting confirmation (at height{})", log_bytes!($payment_hash.0), $commitment_tx, entry.confirmation_threshold());
+ self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
for &(ref htlc, _, ref source) in &$holder_tx.htlc_outputs {
if htlc.transaction_output_index.is_none() {
if let &Some(ref source) = source {
- wait_threshold_conf!(height, source.clone(), "lastest", htlc.payment_hash.clone());
+ wait_threshold_conf!(source.clone(), "lastest", htlc.payment_hash.clone());
}
}
}
(claim_requests, (commitment_txid, watch_outputs))
}
- /// Used by ChannelManager deserialization to broadcast the latest holder state if its copy of
- /// the Channel was out-of-date. You may use it to get a broadcastable holder toxic tx in case of
- /// fallen-behind, i.e when receiving a channel_reestablish with a proof that our counterparty side knows
- /// a higher revocation secret than the holder commitment number we are aware of. Broadcasting these
- /// transactions are UNSAFE, as they allow counterparty side to punish you. Nevertheless you may want to
- /// broadcast them if counterparty don't close channel with his higher commitment transaction after a
- /// substantial amount of time (a month or even a year) to get back funds. Best may be to contact
- /// out-of-band the other node operator to coordinate with him if option is available to you.
- /// In any-case, choice is up to the user.
pub fn get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
log_trace!(logger, "Getting signed latest holder commitment transaction!");
self.holder_tx_signed = true;
- if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) {
- let txid = commitment_tx.txid();
- let mut res = vec![commitment_tx];
- for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
- if let Some(vout) = htlc.0.transaction_output_index {
- let preimage = if !htlc.0.offered {
- if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
- // We can't build an HTLC-Success transaction without the preimage
- continue;
- }
- } else { None };
- if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
- &::bitcoin::OutPoint { txid, vout }, &preimage) {
- res.push(htlc_tx);
+ let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
+ let txid = commitment_tx.txid();
+ let mut res = vec![commitment_tx];
+ for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
+ if let Some(vout) = htlc.0.transaction_output_index {
+ let preimage = if !htlc.0.offered {
+ if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
+ // We can't build an HTLC-Success transaction without the preimage
+ continue;
}
+ } else { None };
+ if let Some(htlc_tx) = self.onchain_tx_handler.get_fully_signed_htlc_tx(
+ &::bitcoin::OutPoint { txid, vout }, &preimage) {
+ res.push(htlc_tx);
}
}
- // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
- // The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
- return res
}
- Vec::new()
+ // We throw away the generated waiting_first_conf data as we aren't (yet) confirmed and we don't actually know what the caller wants to do.
+ // The data will be re-generated and tracked in check_spend_holder_transaction if we get a confirmation.
+ return res;
}
- /// Unsafe test-only version of get_latest_holder_commitment_txn used by our test framework
- /// to bypass HolderCommitmentTransaction state update lockdown after signature and generate
- /// revoked commitment transaction.
#[cfg(any(test,feature = "unsafe_revoked_tx_signing"))]
- pub fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
+ fn unsafe_get_latest_holder_commitment_txn<L: Deref>(&mut self, logger: &L) -> Vec<Transaction> where L::Target: Logger {
log_trace!(logger, "Getting signed copy of latest holder commitment transaction!");
- if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript) {
- let txid = commitment_tx.txid();
- let mut res = vec![commitment_tx];
- for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
- if let Some(vout) = htlc.0.transaction_output_index {
- let preimage = if !htlc.0.offered {
- if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
- // We can't build an HTLC-Success transaction without the preimage
- continue;
- }
- } else { None };
- if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx(
- &::bitcoin::OutPoint { txid, vout }, &preimage) {
- res.push(htlc_tx);
+ let commitment_tx = self.onchain_tx_handler.get_fully_signed_copy_holder_tx(&self.funding_redeemscript);
+ let txid = commitment_tx.txid();
+ let mut res = vec![commitment_tx];
+ for htlc in self.current_holder_commitment_tx.htlc_outputs.iter() {
+ if let Some(vout) = htlc.0.transaction_output_index {
+ let preimage = if !htlc.0.offered {
+ if let Some(preimage) = self.payment_preimages.get(&htlc.0.payment_hash) { Some(preimage.clone()) } else {
+ // We can't build an HTLC-Success transaction without the preimage
+ continue;
}
+ } else { None };
+ if let Some(htlc_tx) = self.onchain_tx_handler.unsafe_get_fully_signed_htlc_tx(
+ &::bitcoin::OutPoint { txid, vout }, &preimage) {
+ res.push(htlc_tx);
}
}
- return res
}
- Vec::new()
+ return res
}
- /// Processes transactions in a newly connected block, which may result in any of the following:
- /// - update the monitor's state against resolved HTLCs
- /// - punish the counterparty in the case of seeing a revoked commitment transaction
- /// - force close the channel and claim/timeout incoming/outgoing HTLCs if near expiration
- /// - detect settled outputs for later spending
- /// - schedule and bump any in-flight claims
- ///
- /// Returns any new outputs to watch from `txdata`; after called, these are also included in
- /// [`get_outputs_to_watch`].
- ///
- /// [`get_outputs_to_watch`]: #method.get_outputs_to_watch
- pub fn block_connected<B: Deref, F: Deref, L: Deref>(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L)-> Vec<(Txid, Vec<(u32, TxOut)>)>
+ pub fn block_connected<B: Deref, F: Deref, L: Deref>(&mut self, header: &BlockHeader, txdata: &TransactionData, height: u32, broadcaster: B, fee_estimator: F, logger: L) -> Vec<TransactionOutputs>
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator,
L::Target: Logger,
+ {
+ let block_hash = header.block_hash();
+ log_trace!(logger, "New best block {} at height {}", block_hash, height);
+ self.best_block = BestBlock::new(block_hash, height);
+
+ self.transactions_confirmed(header, txdata, height, broadcaster, fee_estimator, logger)
+ }
+
+ fn best_block_updated<B: Deref, F: Deref, L: Deref>(
+ &mut self,
+ header: &BlockHeader,
+ height: u32,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) -> Vec<TransactionOutputs>
+ where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ let block_hash = header.block_hash();
+ log_trace!(logger, "New best block {} at height {}", block_hash, height);
+
+ if height > self.best_block.height() {
+ self.best_block = BestBlock::new(block_hash, height);
+ self.block_confirmed(height, vec![], vec![], vec![], broadcaster, fee_estimator, logger)
+ } else {
+ self.best_block = BestBlock::new(block_hash, height);
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height <= height);
+ self.onchain_tx_handler.block_disconnected(height + 1, broadcaster, fee_estimator, logger);
+ Vec::new()
+ }
+ }
+
+ fn transactions_confirmed<B: Deref, F: Deref, L: Deref>(
+ &mut self,
+ header: &BlockHeader,
+ txdata: &TransactionData,
+ height: u32,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) -> Vec<TransactionOutputs>
+ where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
{
let txn_matched = self.filter_block(txdata);
for tx in &txn_matched {
self.is_paying_spendable_output(&tx, height, &logger);
}
+
+ self.block_confirmed(height, txn_matched, watch_outputs, claimable_outpoints, broadcaster, fee_estimator, logger)
+ }
+
+ fn block_confirmed<B: Deref, F: Deref, L: Deref>(
+ &mut self,
+ height: u32,
+ txn_matched: Vec<&Transaction>,
+ mut watch_outputs: Vec<TransactionOutputs>,
+ mut claimable_outpoints: Vec<ClaimRequest>,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) -> Vec<TransactionOutputs>
+ where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
let should_broadcast = self.would_broadcast_at_height(height, &logger);
if should_broadcast {
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_holder_tx(&self.funding_redeemscript) {
- self.holder_tx_signed = true;
- let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx);
- let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
- if !new_outputs.is_empty() {
- watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
- }
- claimable_outpoints.append(&mut new_outpoints);
- }
- }
- if let Some(events) = self.onchain_events_waiting_threshold_conf.remove(&height) {
- for ev in events {
- 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_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(Event::SpendableOutputs {
- outputs: vec![descriptor]
- });
+ let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
+ self.holder_tx_signed = true;
+ let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx);
+ let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
+ if !new_outputs.is_empty() {
+ watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
+ }
+ claimable_outpoints.append(&mut new_outpoints);
+ }
+
+ // Find which on-chain events have reached their confirmation threshold.
+ let onchain_events_awaiting_threshold_conf =
+ self.onchain_events_awaiting_threshold_conf.drain(..).collect::<Vec<_>>();
+ let mut onchain_events_reaching_threshold_conf = Vec::new();
+ for entry in onchain_events_awaiting_threshold_conf {
+ if entry.has_reached_confirmation_threshold(height) {
+ onchain_events_reaching_threshold_conf.push(entry);
+ } else {
+ self.onchain_events_awaiting_threshold_conf.push(entry);
+ }
+ }
+
+ // Used to check for duplicate HTLC resolutions.
+ #[cfg(debug_assertions)]
+ let unmatured_htlcs: Vec<_> = self.onchain_events_awaiting_threshold_conf
+ .iter()
+ .filter_map(|entry| match &entry.event {
+ OnchainEvent::HTLCUpdate { htlc_update } => Some(htlc_update.0.clone()),
+ OnchainEvent::MaturingOutput { .. } => None,
+ })
+ .collect();
+ #[cfg(debug_assertions)]
+ let mut matured_htlcs = Vec::new();
+
+ // Produce actionable events from on-chain events having reached their threshold.
+ for entry in onchain_events_reaching_threshold_conf.drain(..) {
+ match entry.event {
+ OnchainEvent::HTLCUpdate { htlc_update } => {
+ // Check for duplicate HTLC resolutions.
+ #[cfg(debug_assertions)]
+ {
+ debug_assert!(
+ unmatured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
+ "An unmature HTLC transaction conflicts with a maturing one; failed to \
+ call either transaction_unconfirmed for the conflicting transaction \
+ or block_disconnected for a block containing it.");
+ debug_assert!(
+ matured_htlcs.iter().find(|&htlc| htlc == &htlc_update.0).is_none(),
+ "A matured HTLC transaction conflicts with a maturing one; failed to \
+ call either transaction_unconfirmed for the conflicting transaction \
+ or block_disconnected for a block containing it.");
+ matured_htlcs.push(htlc_update.0.clone());
}
+
+ log_trace!(logger, "HTLC {} failure update has got enough confirmations to be passed upstream", log_bytes!((htlc_update.1).0));
+ 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(Event::SpendableOutputs {
+ outputs: vec![descriptor]
+ });
}
}
}
self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, Some(height), &&*broadcaster, &&*fee_estimator, &&*logger);
- self.last_block_hash = block_hash;
// Determine new outputs to watch by comparing against previously known outputs to watch,
// updating the latter in the process.
watch_outputs
}
- /// Determines if the disconnected block contained any transactions of interest and updates
- /// appropriately.
pub fn block_disconnected<B: Deref, F: Deref, L: Deref>(&mut self, header: &BlockHeader, height: u32, broadcaster: B, fee_estimator: F, logger: L)
where B::Target: BroadcasterInterface,
F::Target: FeeEstimator,
L::Target: Logger,
{
- let block_hash = header.block_hash();
- log_trace!(logger, "Block {} at height {} disconnected", block_hash, height);
+ log_trace!(logger, "Block {} at height {} disconnected", header.block_hash(), height);
- if let Some(_) = self.onchain_events_waiting_threshold_conf.remove(&(height + ANTI_REORG_DELAY - 1)) {
- //We may discard:
- //- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
- //- maturing spendable output has transaction paying us has been disconnected
- }
+ //We may discard:
+ //- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
+ //- maturing spendable output has transaction paying us has been disconnected
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height < height);
self.onchain_tx_handler.block_disconnected(height, broadcaster, fee_estimator, logger);
- self.last_block_hash = block_hash;
+ self.best_block = BestBlock::new(header.prev_blockhash, height - 1);
+ }
+
+ fn transaction_unconfirmed<B: Deref, F: Deref, L: Deref>(
+ &mut self,
+ txid: &Txid,
+ broadcaster: B,
+ fee_estimator: F,
+ logger: L,
+ ) where
+ B::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+ {
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.txid != *txid);
+ self.onchain_tx_handler.transaction_unconfirmed(txid, broadcaster, fee_estimator, logger);
}
/// Filters a block's `txdata` for transactions spending watched outputs or for any child
}));
}
} 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);
- match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) {
- hash_map::Entry::Occupied(mut entry) => {
- let e = entry.get_mut();
- e.retain(|ref event| {
- match **event {
- OnchainEvent::HTLCUpdate { ref htlc_update } => {
- return htlc_update.0 != source
- },
- _ => true
- }
- });
- e.push(OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)});
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
+ if entry.height != height { return true; }
+ match entry.event {
+ OnchainEvent::HTLCUpdate { ref htlc_update } => {
+ htlc_update.0 != source
+ },
+ _ => true,
}
- hash_map::Entry::Vacant(entry) => {
- entry.insert(vec![OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash)}]);
- }
- }
+ });
+ let entry = OnchainEventEntry {
+ txid: tx.txid(),
+ height,
+ event: OnchainEvent::HTLCUpdate { htlc_update: (source, payment_hash) },
+ };
+ log_info!(logger, "Failing HTLC with payment_hash {} timeout by a spend tx, waiting for confirmation (at height{})", log_bytes!(payment_hash.0), entry.confirmation_threshold());
+ self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
}
break;
} else if let Some(ref broadcasted_holder_revokable_script) = self.broadcasted_holder_revokable_script {
if broadcasted_holder_revokable_script.0 == outp.script_pubkey {
- spendable_output = Some(SpendableOutputDescriptor::DynamicOutputP2WSH {
+ spendable_output = Some(SpendableOutputDescriptor::DelayedPaymentOutput(DelayedPaymentOutputDescriptor {
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
per_commitment_point: broadcasted_holder_revokable_script.1,
to_self_delay: self.on_holder_tx_csv,
output: outp.clone(),
- key_derivation_params: self.key_derivation_params,
revocation_pubkey: broadcasted_holder_revokable_script.2.clone(),
- });
+ channel_keys_id: self.channel_keys_id,
+ channel_value_satoshis: self.channel_value_satoshis,
+ }));
break;
}
} else if self.counterparty_payment_script == outp.script_pubkey {
- spendable_output = Some(SpendableOutputDescriptor::StaticOutputCounterpartyPayment {
+ spendable_output = Some(SpendableOutputDescriptor::StaticPaymentOutput(StaticPaymentOutputDescriptor {
outpoint: OutPoint { txid: tx.txid(), index: i as u16 },
output: outp.clone(),
- key_derivation_params: self.key_derivation_params,
- });
+ channel_keys_id: self.channel_keys_id,
+ channel_value_satoshis: self.channel_value_satoshis,
+ }));
break;
} else if outp.script_pubkey == self.shutdown_script {
spendable_output = Some(SpendableOutputDescriptor::StaticOutput {
}
}
if let Some(spendable_output) = spendable_output {
- log_trace!(logger, "Maturing {} until {}", log_spendable!(spendable_output), height + ANTI_REORG_DELAY - 1);
- match self.onchain_events_waiting_threshold_conf.entry(height + ANTI_REORG_DELAY - 1) {
- hash_map::Entry::Occupied(mut entry) => {
- let e = entry.get_mut();
- e.push(OnchainEvent::MaturingOutput { descriptor: spendable_output });
- }
- hash_map::Entry::Vacant(entry) => {
- entry.insert(vec![OnchainEvent::MaturingOutput { descriptor: spendable_output }]);
- }
- }
+ let entry = OnchainEventEntry {
+ txid: tx.txid(),
+ height: height,
+ event: OnchainEvent::MaturingOutput { descriptor: spendable_output.clone() },
+ };
+ log_trace!(logger, "Maturing {} until {}", log_spendable!(spendable_output), entry.confirmation_threshold());
+ self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
}
/// transaction and losing money. This is a risk because previous channel states
/// are toxic, so it's important that whatever channel state is persisted is
/// kept up-to-date.
-pub trait Persist<Keys: ChannelKeys>: Send + Sync {
+pub trait Persist<ChannelSigner: Sign> {
/// Persist a new channel's data. The data can be stored any way you want, but
/// the identifier provided by Rust-Lightning is the channel's outpoint (and
/// it is up to you to maintain a correct mapping between the outpoint and the
/// stored channel data). Note that you **must** persist every new monitor to
/// disk. See the `Persist` trait documentation for more details.
///
- /// See [`ChannelMonitor::serialize_for_disk`] for writing out a `ChannelMonitor`,
+ /// See [`ChannelMonitor::write`] for writing out a `ChannelMonitor`,
/// and [`ChannelMonitorUpdateErr`] for requirements when returning errors.
- ///
- /// [`ChannelMonitor::serialize_for_disk`]: struct.ChannelMonitor.html#method.serialize_for_disk
- /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html
- fn persist_new_channel(&self, id: OutPoint, data: &ChannelMonitor<Keys>) -> Result<(), ChannelMonitorUpdateErr>;
+ fn persist_new_channel(&self, id: OutPoint, data: &ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr>;
/// Update one channel's data. The provided `ChannelMonitor` has already
/// applied the given update.
/// them in batches. The size of each monitor grows `O(number of state updates)`
/// whereas updates are small and `O(1)`.
///
- /// See [`ChannelMonitor::serialize_for_disk`] for writing out a `ChannelMonitor`,
+ /// See [`ChannelMonitor::write`] for writing out a `ChannelMonitor`,
/// [`ChannelMonitorUpdate::write`] for writing out an update, and
/// [`ChannelMonitorUpdateErr`] for requirements when returning errors.
- ///
- /// [`ChannelMonitor::update_monitor`]: struct.ChannelMonitor.html#impl-1
- /// [`ChannelMonitor::serialize_for_disk`]: struct.ChannelMonitor.html#method.serialize_for_disk
- /// [`ChannelMonitorUpdate::write`]: struct.ChannelMonitorUpdate.html#method.write
- /// [`ChannelMonitorUpdateErr`]: enum.ChannelMonitorUpdateErr.html
- fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor<Keys>) -> Result<(), ChannelMonitorUpdateErr>;
+ fn update_persisted_channel(&self, id: OutPoint, update: &ChannelMonitorUpdate, data: &ChannelMonitor<ChannelSigner>) -> Result<(), ChannelMonitorUpdateErr>;
+}
+
+impl<Signer: Sign, T: Deref, F: Deref, L: Deref> chain::Listen for (ChannelMonitor<Signer>, T, F, L)
+where
+ T::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+{
+ fn block_connected(&self, block: &Block, height: u32) {
+ let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
+ self.0.block_connected(&block.header, &txdata, height, &*self.1, &*self.2, &*self.3);
+ }
+
+ fn block_disconnected(&self, header: &BlockHeader, height: u32) {
+ self.0.block_disconnected(header, height, &*self.1, &*self.2, &*self.3);
+ }
+}
+
+impl<Signer: Sign, T: Deref, F: Deref, L: Deref> chain::Confirm for (ChannelMonitor<Signer>, T, F, L)
+where
+ T::Target: BroadcasterInterface,
+ F::Target: FeeEstimator,
+ L::Target: Logger,
+{
+ fn transactions_confirmed(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
+ self.0.transactions_confirmed(header, txdata, height, &*self.1, &*self.2, &*self.3);
+ }
+
+ fn transaction_unconfirmed(&self, txid: &Txid) {
+ self.0.transaction_unconfirmed(txid, &*self.1, &*self.2, &*self.3);
+ }
+
+ fn best_block_updated(&self, header: &BlockHeader, height: u32) {
+ self.0.best_block_updated(header, height, &*self.1, &*self.2, &*self.3);
+ }
+
+ fn get_relevant_txids(&self) -> Vec<Txid> {
+ self.0.get_relevant_txids()
+ }
}
const MAX_ALLOC_SIZE: usize = 64*1024;
-impl<'a, ChanSigner: ChannelKeys, K: KeysInterface<ChanKeySigner = ChanSigner>> ReadableArgs<&'a K>
- for (BlockHash, ChannelMonitor<ChanSigner>) {
+impl<'a, Signer: Sign, K: KeysInterface<Signer = Signer>> ReadableArgs<&'a K>
+ for (BlockHash, ChannelMonitor<Signer>) {
fn read<R: ::std::io::Read>(reader: &mut R, keys_manager: &'a K) -> Result<Self, DecodeError> {
macro_rules! unwrap_obj {
($key: expr) => {
let counterparty_payment_script = Readable::read(reader)?;
let shutdown_script = Readable::read(reader)?;
- let key_derivation_params = Readable::read(reader)?;
+ let channel_keys_id = Readable::read(reader)?;
let holder_revocation_basepoint = Readable::read(reader)?;
// Technically this can fail and serialize fail a round-trip, but only for serialization of
// barely-init'd ChannelMonitors that we can't do anything with.
}
}
- let last_block_hash: BlockHash = Readable::read(reader)?;
+ let best_block = BestBlock::new(Readable::read(reader)?, Readable::read(reader)?);
let waiting_threshold_conf_len: u64 = Readable::read(reader)?;
- let mut onchain_events_waiting_threshold_conf = HashMap::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
+ let mut onchain_events_awaiting_threshold_conf = Vec::with_capacity(cmp::min(waiting_threshold_conf_len as usize, MAX_ALLOC_SIZE / 128));
for _ in 0..waiting_threshold_conf_len {
- let height_target = Readable::read(reader)?;
- let events_len: u64 = Readable::read(reader)?;
- let mut events = Vec::with_capacity(cmp::min(events_len as usize, MAX_ALLOC_SIZE / 128));
- for _ in 0..events_len {
- let ev = match <u8 as Readable>::read(reader)? {
- 0 => {
- let htlc_source = Readable::read(reader)?;
- let hash = Readable::read(reader)?;
- OnchainEvent::HTLCUpdate {
- htlc_update: (htlc_source, hash)
- }
- },
- 1 => {
- let descriptor = Readable::read(reader)?;
- OnchainEvent::MaturingOutput {
- descriptor
- }
- },
- _ => return Err(DecodeError::InvalidValue),
- };
- events.push(ev);
- }
- onchain_events_waiting_threshold_conf.insert(height_target, events);
+ let txid = Readable::read(reader)?;
+ let height = Readable::read(reader)?;
+ let event = match <u8 as Readable>::read(reader)? {
+ 0 => {
+ let htlc_source = Readable::read(reader)?;
+ let hash = Readable::read(reader)?;
+ OnchainEvent::HTLCUpdate {
+ htlc_update: (htlc_source, hash)
+ }
+ },
+ 1 => {
+ let descriptor = Readable::read(reader)?;
+ OnchainEvent::MaturingOutput {
+ descriptor
+ }
+ },
+ _ => return Err(DecodeError::InvalidValue),
+ };
+ onchain_events_awaiting_threshold_conf.push(OnchainEventEntry { txid, height, event });
}
let outputs_to_watch_len: u64 = Readable::read(reader)?;
let lockdown_from_offchain = Readable::read(reader)?;
let holder_tx_signed = Readable::read(reader)?;
- Ok((last_block_hash.clone(), ChannelMonitor {
- latest_update_id,
- commitment_transaction_number_obscure_factor,
+ let mut secp_ctx = Secp256k1::new();
+ secp_ctx.seeded_randomize(&keys_manager.get_secure_random_bytes());
+
+ Ok((best_block.block_hash(), ChannelMonitor {
+ inner: Mutex::new(ChannelMonitorImpl {
+ latest_update_id,
+ commitment_transaction_number_obscure_factor,
- destination_script,
- broadcasted_holder_revokable_script,
- counterparty_payment_script,
- shutdown_script,
+ destination_script,
+ broadcasted_holder_revokable_script,
+ counterparty_payment_script,
+ shutdown_script,
- key_derivation_params,
- holder_revocation_basepoint,
- funding_info,
- current_counterparty_commitment_txid,
- prev_counterparty_commitment_txid,
+ channel_keys_id,
+ holder_revocation_basepoint,
+ funding_info,
+ current_counterparty_commitment_txid,
+ prev_counterparty_commitment_txid,
- counterparty_tx_cache,
- funding_redeemscript,
- channel_value_satoshis,
- their_cur_revocation_points,
+ counterparty_tx_cache,
+ funding_redeemscript,
+ channel_value_satoshis,
+ their_cur_revocation_points,
- on_holder_tx_csv,
+ on_holder_tx_csv,
- commitment_secrets,
- counterparty_claimable_outpoints,
- counterparty_commitment_txn_on_chain,
- counterparty_hash_commitment_number,
+ commitment_secrets,
+ counterparty_claimable_outpoints,
+ counterparty_commitment_txn_on_chain,
+ counterparty_hash_commitment_number,
- prev_holder_signed_commitment_tx,
- current_holder_commitment_tx,
- current_counterparty_commitment_number,
- current_holder_commitment_number,
+ prev_holder_signed_commitment_tx,
+ current_holder_commitment_tx,
+ current_counterparty_commitment_number,
+ current_holder_commitment_number,
- payment_preimages,
- pending_monitor_events,
- pending_events,
+ payment_preimages,
+ pending_monitor_events,
+ pending_events,
- onchain_events_waiting_threshold_conf,
- outputs_to_watch,
+ onchain_events_awaiting_threshold_conf,
+ outputs_to_watch,
- onchain_tx_handler,
+ onchain_tx_handler,
- lockdown_from_offchain,
- holder_tx_signed,
+ lockdown_from_offchain,
+ holder_tx_signed,
- last_block_hash,
- secp_ctx: Secp256k1::new(),
+ best_block,
+
+ secp_ctx,
+ }),
}))
}
}
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::hex::FromHex;
use bitcoin::hash_types::Txid;
+ use bitcoin::network::constants::Network;
use hex;
use chain::channelmonitor::ChannelMonitor;
use chain::transaction::OutPoint;
- use ln::channelmanager::{PaymentPreimage, PaymentHash};
+ use ln::{PaymentPreimage, PaymentHash};
+ use ln::channelmanager::BestBlock;
use ln::onchaintx::{OnchainTxHandler, InputDescriptors};
use ln::chan_utils;
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
use bitcoin::secp256k1::Secp256k1;
use std::sync::{Arc, Mutex};
- use chain::keysinterface::InMemoryChannelKeys;
+ use chain::keysinterface::InMemorySigner;
#[test]
fn test_prune_preimages() {
macro_rules! test_preimages_exist {
($preimages_slice: expr, $monitor: expr) => {
for preimage in $preimages_slice {
- assert!($monitor.payment_preimages.contains_key(&preimage.1));
+ assert!($monitor.inner.lock().unwrap().payment_preimages.contains_key(&preimage.1));
}
}
}
- let keys = InMemoryChannelKeys::new(
+ let keys = InMemorySigner::new(
&secp_ctx,
SecretKey::from_slice(&[41; 32]).unwrap(),
SecretKey::from_slice(&[41; 32]).unwrap(),
SecretKey::from_slice(&[41; 32]).unwrap(),
[41; 32],
0,
- (0, 0)
+ [0; 32]
);
let counterparty_pubkeys = ChannelPublicKeys {
};
// Prune with one old state and a holder commitment tx holding a few overlaps with the
// old state.
- let mut monitor = ChannelMonitor::new(keys,
- &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(),
- (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
- &channel_parameters,
- Script::new(), 46, 0,
- HolderCommitmentTransaction::dummy());
+ let best_block = BestBlock::from_genesis(Network::Testnet);
+ let monitor = ChannelMonitor::new(Secp256k1::new(), keys,
+ &PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap()), 0, &Script::new(),
+ (OutPoint { txid: Txid::from_slice(&[43; 32]).unwrap(), index: 0 }, Script::new()),
+ &channel_parameters,
+ Script::new(), 46, 0,
+ HolderCommitmentTransaction::dummy(), best_block);
monitor.provide_latest_holder_commitment_tx(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..10])).unwrap();
let dummy_txid = dummy_tx.txid();
let mut secret = [0; 32];
secret[0..32].clone_from_slice(&hex::decode("7cc854b54e3e0dcdb010d7a3fee464a9687be6e8db3be6854c475621e007a5dc").unwrap());
monitor.provide_secret(281474976710655, secret.clone()).unwrap();
- assert_eq!(monitor.payment_preimages.len(), 15);
+ assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 15);
test_preimages_exist!(&preimages[0..10], monitor);
test_preimages_exist!(&preimages[15..20], monitor);
// Now provide a further secret, pruning preimages 15-17
secret[0..32].clone_from_slice(&hex::decode("c7518c8ae4660ed02894df8976fa1a3659c1a8b4b5bec0c4b872abeba4cb8964").unwrap());
monitor.provide_secret(281474976710654, secret.clone()).unwrap();
- assert_eq!(monitor.payment_preimages.len(), 13);
+ assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 13);
test_preimages_exist!(&preimages[0..10], monitor);
test_preimages_exist!(&preimages[17..20], monitor);
monitor.provide_latest_holder_commitment_tx(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..5])).unwrap();
secret[0..32].clone_from_slice(&hex::decode("2273e227a5b7449b6e70f1fb4652864038b1cbf9cd7c043a7d6456b7fc275ad8").unwrap());
monitor.provide_secret(281474976710653, secret.clone()).unwrap();
- assert_eq!(monitor.payment_preimages.len(), 12);
+ assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 12);
test_preimages_exist!(&preimages[0..10], monitor);
test_preimages_exist!(&preimages[18..20], monitor);
monitor.provide_latest_holder_commitment_tx(HolderCommitmentTransaction::dummy(), preimages_to_holder_htlcs!(preimages[0..3])).unwrap();
secret[0..32].clone_from_slice(&hex::decode("27cddaa5624534cb6cb9d7da077cf2b22ab21e9b506fd4998a51d54502e99116").unwrap());
monitor.provide_secret(281474976710652, secret.clone()).unwrap();
- assert_eq!(monitor.payment_preimages.len(), 5);
+ assert_eq!(monitor.inner.lock().unwrap().payment_preimages.len(), 5);
test_preimages_exist!(&preimages[0..5], monitor);
}
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
}
}
- assert_eq!(base_weight + OnchainTxHandler::<InMemoryChannelKeys>::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs));
+ assert_eq!(base_weight + OnchainTxHandler::<InMemorySigner>::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs));
// Claim tx with 1 offered HTLCs, 3 received HTLCs
claim_tx.input.clear();
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
}
}
- assert_eq!(base_weight + OnchainTxHandler::<InMemoryChannelKeys>::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs));
+ assert_eq!(base_weight + OnchainTxHandler::<InMemorySigner>::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_sig */ (73 * inputs_des.len() - sum_actual_sigs));
// Justice tx with 1 revoked HTLC-Success tx output
claim_tx.input.clear();
sign_input!(sighash_parts, idx, 0, inp, sum_actual_sigs);
}
}
- assert_eq!(base_weight + OnchainTxHandler::<InMemoryChannelKeys>::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_isg */ (73 * inputs_des.len() - sum_actual_sigs));
+ assert_eq!(base_weight + OnchainTxHandler::<InMemorySigner>::get_witnesses_weight(&inputs_des[..]), claim_tx.get_weight() + /* max_length_isg */ (73 * inputs_des.len() - sum_actual_sigs));
}
// Further testing is done in the ChannelManager integration tests.