use ln::msgs::DecodeError;
use ln::chan_utils;
use ln::chan_utils::{CounterpartyCommitmentSecrets, HTLCOutputInCommitment, HTLCType, ChannelTransactionParameters, HolderCommitmentTransaction};
-use ln::channelmanager::{BestBlock, HTLCSource};
+use ln::channelmanager::HTLCSource;
use chain;
-use chain::WatchedOutput;
+use chain::{BestBlock, WatchedOutput};
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
use chain::transaction::{OutPoint, TransactionData};
use chain::keysinterface::{SpendableOutputDescriptor, StaticPaymentOutputDescriptor, DelayedPaymentOutputDescriptor, Sign, KeysInterface};
use core::{cmp, mem};
use std::io::Error;
use core::ops::Deref;
-use std::sync::Mutex;
+use sync::Mutex;
/// An update generated by the underlying Channel itself which contains some new information the
/// ChannelMonitor should be made aware of.
}
/// An error enum representing a failure to persist a channel monitor update.
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ChannelMonitorUpdateErr {
/// Used to indicate a temporary failure (eg connection to a watchtower or remote backup of
/// our state failed, but is expected to succeed at some point in the future).
conf_threshold
}
- fn has_reached_confirmation_threshold(&self, height: u32) -> bool {
- height >= self.confirmation_threshold()
+ fn has_reached_confirmation_threshold(&self, best_block: &BestBlock) -> bool {
+ best_block.height() >= self.confirmation_threshold()
}
}
txids.dedup();
txids
}
+
+ /// Gets the latest best block which was connected either via the [`chain::Listen`] or
+ /// [`chain::Confirm`] interfaces.
+ pub fn current_best_block(&self) -> BestBlock {
+ self.inner.lock().unwrap().best_block.clone()
+ }
}
impl<Signer: Sign> ChannelMonitorImpl<Signer> {
// *we* sign a holder commitment transaction, not when e.g. a watchtower broadcasts one of our
// holder commitment transactions.
if self.broadcasted_holder_revokable_script.is_some() {
- let (claim_reqs, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, 0);
+ // Assume that the broadcasted commitment transaction confirmed in the current best
+ // block. Even if not, its a reasonable metric for the bump criteria on the HTLC
+ // transactions.
+ let (claim_reqs, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), self.best_block.height(), broadcaster, fee_estimator, logger);
if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
- let (claim_reqs, _) = self.get_broadcasted_holder_claims(&tx, 0);
+ let (claim_reqs, _) = self.get_broadcasted_holder_claims(&tx, self.best_block.height());
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, self.best_block.height(), self.best_block.height(), broadcaster, fee_estimator, logger);
}
}
// Returns (1) `PackageTemplate`s that can be given to the OnChainTxHandler, so that the handler can
// broadcast transactions claiming holder HTLC commitment outputs and (2) a holder revokable
// script so we can detect whether a holder transaction has been seen on-chain.
- fn get_broadcasted_holder_claims(&self, holder_tx: &HolderSignedTx, height: u32) -> (Vec<PackageTemplate>, Option<(Script, PublicKey, PublicKey)>) {
+ fn get_broadcasted_holder_claims(&self, holder_tx: &HolderSignedTx, conf_height: u32) -> (Vec<PackageTemplate>, Option<(Script, PublicKey, PublicKey)>) {
let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len());
let redeemscript = chan_utils::get_revokeable_redeemscript(&holder_tx.revocation_key, self.on_holder_tx_csv, &holder_tx.delayed_payment_key);
};
HolderHTLCOutput::build_accepted(payment_preimage, htlc.amount_msat)
};
- let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), height, false, height);
+ let htlc_package = PackageTemplate::build_package(holder_tx.txid, transaction_output_index, PackageSolvingData::HolderHTLCOutput(htlc_output), htlc.cltv_expiry, false, conf_height);
claim_requests.push(htlc_package);
}
}
let mut claim_requests = Vec::new();
let mut watch_outputs = Vec::new();
- macro_rules! wait_threshold_conf {
- ($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 { source: ref update_source, .. } => {
- *update_source != $source
- },
- _ => true,
- }
- });
- let entry = OnchainEventEntry {
- txid: commitment_txid,
- height,
- event: OnchainEvent::HTLCUpdate { source: $source, payment_hash: $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);
- }
- }
-
macro_rules! append_onchain_update {
($updates: expr, $to_watch: expr) => {
claim_requests = $updates.0;
}
macro_rules! fail_dust_htlcs_after_threshold_conf {
- ($holder_tx: expr) => {
+ ($holder_tx: expr, $commitment_tx: expr) => {
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!(source.clone(), "lastest", htlc.payment_hash.clone());
+ self.onchain_events_awaiting_threshold_conf.retain(|ref entry| {
+ if entry.height != height { return true; }
+ match entry.event {
+ OnchainEvent::HTLCUpdate { source: ref update_source, .. } => {
+ update_source != source
+ },
+ _ => true,
+ }
+ });
+ let entry = OnchainEventEntry {
+ txid: commitment_txid,
+ height,
+ event: OnchainEvent::HTLCUpdate {
+ source: source.clone(), payment_hash: htlc.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!(htlc.payment_hash.0), $commitment_tx, entry.confirmation_threshold());
+ self.onchain_events_awaiting_threshold_conf.push(entry);
}
}
}
}
if is_holder_tx {
- fail_dust_htlcs_after_threshold_conf!(self.current_holder_commitment_tx);
+ fail_dust_htlcs_after_threshold_conf!(self.current_holder_commitment_tx, "latest");
if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx {
- fail_dust_htlcs_after_threshold_conf!(holder_tx);
+ fail_dust_htlcs_after_threshold_conf!(holder_tx, "previous");
}
}
} else if htlc.0.cltv_expiry > self.best_block.height() + 1 {
// Don't broadcast HTLC-Timeout transactions immediately as they don't meet the
// current locktime requirements on-chain. We will broadcast them in
- // `block_confirmed` when `would_broadcast_at_height` returns true.
+ // `block_confirmed` when `should_broadcast_holder_commitment_txn` returns true.
// Note that we add + 1 as transactions are broadcastable when they can be
// confirmed in the next block.
continue;
{
debug_assert!(self.best_block.height() >= conf_height);
- let should_broadcast = self.would_broadcast_at_height(self.best_block.height(), logger);
+ let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
if should_broadcast {
let funding_outp = HolderFundingOutput::build(self.funding_redeemscript.clone());
let commitment_package = PackageTemplate::build_package(self.funding_info.0.txid.clone(), self.funding_info.0.index as u32, PackageSolvingData::HolderFundingOutput(funding_outp), self.best_block.height(), false, self.best_block.height());
self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
let commitment_tx = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript);
self.holder_tx_signed = true;
+ // Because we're broadcasting a commitment transaction, we should construct the package
+ // assuming it gets confirmed in the next block. Sadly, we have code which considers
+ // "not yet confirmed" things as discardable, so we cannot do that here.
let (mut new_outpoints, _) = self.get_broadcasted_holder_claims(&self.current_holder_commitment_tx, self.best_block.height());
let new_outputs = self.get_broadcasted_holder_watch_outputs(&self.current_holder_commitment_tx, &commitment_tx);
if !new_outputs.is_empty() {
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(self.best_block.height()) {
+ if entry.has_reached_confirmation_threshold(&self.best_block) {
onchain_events_reaching_threshold_conf.push(entry);
} else {
self.onchain_events_awaiting_threshold_conf.push(entry);
false
}
- fn would_broadcast_at_height<L: Deref>(&self, height: u32, logger: &L) -> bool where L::Target: Logger {
+ fn should_broadcast_holder_commitment_txn<L: Deref>(&self, logger: &L) -> bool where L::Target: Logger {
// We need to consider all HTLCs which are:
// * in any unrevoked counterparty commitment transaction, as they could broadcast said
// transactions and we'd end up in a race, or
// to the source, and if we don't fail the channel we will have to ensure that the next
// updates that peer sends us are update_fails, failing the channel if not. It's probably
// easier to just fail the channel as this case should be rare enough anyway.
+ let height = self.best_block.height();
macro_rules! scan_commitment {
($htlcs: expr, $holder_tx: expr) => {
for ref htlc in $htlcs {
use bitcoin::hash_types::Txid;
use bitcoin::network::constants::Network;
use hex;
+ use chain::BestBlock;
use chain::channelmonitor::ChannelMonitor;
use chain::package::{WEIGHT_OFFERED_HTLC, WEIGHT_RECEIVED_HTLC, WEIGHT_REVOKED_OFFERED_HTLC, WEIGHT_REVOKED_RECEIVED_HTLC, WEIGHT_REVOKED_OUTPUT};
use chain::transaction::OutPoint;
use ln::{PaymentPreimage, PaymentHash};
- use ln::channelmanager::BestBlock;
use ln::chan_utils;
use ln::chan_utils::{HTLCOutputInCommitment, ChannelPublicKeys, ChannelTransactionParameters, HolderCommitmentTransaction, CounterpartyChannelTransactionParameters};
use util::test_utils::{TestLogger, TestBroadcaster, TestFeeEstimator};
use bitcoin::secp256k1::key::{SecretKey,PublicKey};
use bitcoin::secp256k1::Secp256k1;
- use std::sync::{Arc, Mutex};
+ use sync::{Arc, Mutex};
use chain::keysinterface::InMemorySigner;
use prelude::*;
let secp_ctx = Secp256k1::new();
let logger = Arc::new(TestLogger::new());
let broadcaster = Arc::new(TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), blocks: Arc::new(Mutex::new(Vec::new()))});
- let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: 253 });
+ let fee_estimator = Arc::new(TestFeeEstimator { sat_per_kw: Mutex::new(253) });
let dummy_key = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
let dummy_tx = Transaction { version: 0, lock_time: 0, input: Vec::new(), output: Vec::new() };