Skip to content

Commit 1e44a55

Browse files
valentinewallaceAntoine Riard
and
Antoine Riard
committed
Claim HTLC output on-chain if preimage is recv'd after force-close
If we receive a preimage for an outgoing HTLC on a force-closed channel, we need to claim the HTLC output on-chain. Note that if no counterparty commitment transaction has been broadcasted, we currently default to broadcasting two preimage-output-claiming txs whenever we receive a preimage. This will be fixed in the next commit. Co-authored-by: Antoine Riard <[email protected]> Co-authored-by: Valentine Wallace <[email protected]>
1 parent ae851db commit 1e44a55

File tree

4 files changed

+260
-30
lines changed

4 files changed

+260
-30
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 117 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,32 @@ pub struct ChannelMonitorUpdate {
6464
pub(crate) updates: Vec<ChannelMonitorUpdateStep>,
6565
/// The sequence number of this update. Updates *must* be replayed in-order according to this
6666
/// sequence number (and updates may panic if they are not). The update_id values are strictly
67-
/// increasing and increase by one for each new update.
67+
/// increasing and increase by one for each new update, with one exception specified below.
6868
///
6969
/// This sequence number is also used to track up to which points updates which returned
7070
/// ChannelMonitorUpdateErr::TemporaryFailure have been applied to all copies of a given
7171
/// ChannelMonitor when ChannelManager::channel_monitor_updated is called.
72+
///
73+
/// The only instance where update_id values are not strictly increasing is the case where: (1)
74+
/// the channel has been force closed and (2) we receive a preimage from a forward link that
75+
/// allows us to spend an HTLC output on this channel's (the backward link's) broadcasted
76+
/// commitment transaction. In this case, we allow the `ChannelManager` to send a
77+
/// `ChannelMonitorUpdate` with an update_id of [`CLOSED_CHANNEL_UPDATE_ID`], with the update
78+
/// providing said payment preimage. No other update types are allowed after force-close.
79+
///
80+
/// [`CLOSED_CHANNEL_UPDATE_ID`]: constant.CLOSED_CHANNEL_UPDATE_ID.html
7281
pub update_id: u64,
7382
}
7483

84+
/// If:
85+
/// (1) a channel has been force closed and
86+
/// (2) we receive a preimage from a forward link that allows us to spend an HTLC output on
87+
/// this channel's (the backward link's) broadcasted commitment transaction
88+
/// then we allow the `ChannelManager` to send a `ChannelMonitorUpdate` with this update ID,
89+
/// with the update providing said payment preimage. No other update types are allowed after
90+
/// force-close.
91+
pub const CLOSED_CHANNEL_UPDATE_ID: u64 = std::u64::MAX;
92+
7593
impl Writeable for ChannelMonitorUpdate {
7694
fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
7795
self.update_id.write(w)?;
@@ -1150,6 +1168,46 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
11501168
L::Target: Logger,
11511169
{
11521170
self.payment_preimages.insert(payment_hash.clone(), payment_preimage.clone());
1171+
1172+
// If the channel is force closed, try to claim the output from this preimage.
1173+
// First check if a counterparty commitment transaction has been broadcasted:
1174+
macro_rules! claim_htlcs {
1175+
($commitment_number: expr, $txid: expr) => {
1176+
let (htlc_claim_reqs, set_script) = self.get_counterparty_htlc_output_claim_reqs($commitment_number, $txid, None);
1177+
if set_script {
1178+
self.counterparty_payment_script = {
1179+
// Note that the Network here is ignored as we immediately drop the address for the
1180+
// script_pubkey version
1181+
let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize());
1182+
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()
1183+
};
1184+
}
1185+
self.onchain_tx_handler.update_claims_view(&Vec::new(), htlc_claim_reqs, None, broadcaster, fee_estimator, logger);
1186+
}
1187+
}
1188+
if let Some(txid) = self.current_counterparty_commitment_txid {
1189+
if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
1190+
claim_htlcs!(*commitment_number, txid);
1191+
return;
1192+
}
1193+
}
1194+
if let Some(txid) = self.prev_counterparty_commitment_txid {
1195+
if let Some(commitment_number) = self.counterparty_commitment_txn_on_chain.get(&txid) {
1196+
claim_htlcs!(*commitment_number, txid);
1197+
return;
1198+
}
1199+
}
1200+
1201+
// Then if a holder commitment transaction has been signed, broadcast transactions claiming
1202+
// the HTLC output from each of the holder commitment transactions.
1203+
if self.broadcasted_holder_revokable_script.is_some() {
1204+
let (claim_reqs, _, _) = self.broadcast_by_holder_state(None, &self.current_holder_commitment_tx);
1205+
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
1206+
if let Some(ref tx) = self.prev_holder_signed_commitment_tx {
1207+
let (claim_reqs, _, _) = self.broadcast_by_holder_state(None, &tx);
1208+
self.onchain_tx_handler.update_claims_view(&Vec::new(), claim_reqs, None, broadcaster, fee_estimator, logger);
1209+
}
1210+
}
11531211
}
11541212

11551213
pub(crate) fn broadcast_latest_holder_commitment_txn<B: Deref, L: Deref>(&mut self, broadcaster: &B, logger: &L)
@@ -1171,7 +1229,18 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
11711229
F::Target: FeeEstimator,
11721230
L::Target: Logger,
11731231
{
1174-
if self.latest_update_id + 1 != updates.update_id {
1232+
// ChannelMonitor updates may be applied after force close if we receive a
1233+
// preimage for a broadcasted commitment transaction HTLC output that we'd
1234+
// like to claim on-chain. If this is the case, we no longer have guaranteed
1235+
// access to the monitor's update ID, so we use a sentinel value instead.
1236+
if updates.update_id == CLOSED_CHANNEL_UPDATE_ID {
1237+
match updates.updates[0] {
1238+
ChannelMonitorUpdateStep::PaymentPreimage { .. } => {},
1239+
_ => panic!("Attempted to apply post-force-close ChannelMonitorUpdate that wasn't providing a payment preimage"),
1240+
}
1241+
assert_eq!(updates.updates.len(), 1);
1242+
}
1243+
if updates.update_id != CLOSED_CHANNEL_UPDATE_ID && self.latest_update_id + 1 != updates.update_id {
11751244
panic!("Attempted to apply ChannelMonitorUpdates out of order, check the update_id before passing an update to update_monitor!");
11761245
}
11771246
for update in updates.updates.iter() {
@@ -1438,39 +1507,61 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
14381507
check_htlc_fails!(txid, "previous", 'prev_loop);
14391508
}
14401509

1510+
let (htlc_claim_reqs, set_script) = self.get_counterparty_htlc_output_claim_reqs(commitment_number, commitment_txid, Some(tx));
1511+
if set_script {
1512+
self.counterparty_payment_script = {
1513+
// Note that the Network here is ignored as we immediately drop the address for the
1514+
// script_pubkey version
1515+
let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize());
1516+
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()
1517+
};
1518+
}
1519+
for req in htlc_claim_reqs {
1520+
claimable_outpoints.push(req);
1521+
}
1522+
1523+
}
1524+
(claimable_outpoints, (commitment_txid, watch_outputs))
1525+
}
1526+
1527+
fn get_counterparty_htlc_output_claim_reqs(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>) -> (Vec<ClaimRequest>, bool) {
1528+
let mut claims = Vec::new();
1529+
let mut set_counterparty_payment_script = false;
1530+
if let Some(htlc_outputs) = self.counterparty_claimable_outpoints.get(&commitment_txid) {
14411531
if let Some(revocation_points) = self.their_cur_revocation_points {
14421532
let revocation_point_option =
14431533
if revocation_points.0 == commitment_number { Some(&revocation_points.1) }
1444-
else if let Some(point) = revocation_points.2.as_ref() {
1445-
if revocation_points.0 == commitment_number + 1 { Some(point) } else { None }
1446-
} else { None };
1534+
else if let Some(point) = revocation_points.2.as_ref() {
1535+
if revocation_points.0 == commitment_number + 1 { Some(point) } else { None }
1536+
} else { None };
14471537
if let Some(revocation_point) = revocation_point_option {
1448-
self.counterparty_payment_script = {
1449-
// Note that the Network here is ignored as we immediately drop the address for the
1450-
// script_pubkey version
1451-
let payment_hash160 = WPubkeyHash::hash(&self.keys.pubkeys().payment_point.serialize());
1452-
Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&payment_hash160[..]).into_script()
1453-
};
1538+
set_counterparty_payment_script = true;
14541539

14551540
// Then, try to find htlc outputs
1456-
for (_, &(ref htlc, _)) in per_commitment_data.iter().enumerate() {
1541+
for (_, &(ref htlc, _)) in htlc_outputs.iter().enumerate() {
14571542
if let Some(transaction_output_index) = htlc.transaction_output_index {
1458-
if transaction_output_index as usize >= tx.output.len() ||
1459-
tx.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
1460-
return (claimable_outpoints, (commitment_txid, watch_outputs)); // Corrupted per_commitment_data, fuck this user
1543+
if let Some(transaction) = tx {
1544+
if transaction_output_index as usize >= transaction.output.len() ||
1545+
transaction.output[transaction_output_index as usize].value != htlc.amount_msat / 1000 {
1546+
return (claims, set_counterparty_payment_script) // Corrupted per_commitment_data, fuck this user
1547+
}
14611548
}
1462-
let preimage = if htlc.offered { if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) { Some(*p) } else { None } } else { None };
1549+
let preimage = if htlc.offered {
1550+
if let Some(p) = self.payment_preimages.get(&htlc.payment_hash) {
1551+
Some(*p)
1552+
} else { None }
1553+
} else { None };
14631554
let aggregable = if !htlc.offered { false } else { true };
14641555
if preimage.is_some() || !htlc.offered {
14651556
let witness_data = InputMaterial::CounterpartyHTLC { per_commitment_point: *revocation_point, counterparty_delayed_payment_base_key: self.counterparty_tx_cache.counterparty_delayed_payment_base_key, counterparty_htlc_base_key: self.counterparty_tx_cache.counterparty_htlc_base_key, preimage, htlc: htlc.clone() };
1466-
claimable_outpoints.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
1557+
claims.push(ClaimRequest { absolute_timelock: htlc.cltv_expiry, aggregable, outpoint: BitcoinOutPoint { txid: commitment_txid, vout: transaction_output_index }, witness_data });
14671558
}
14681559
}
14691560
}
14701561
}
14711562
}
14721563
}
1473-
(claimable_outpoints, (commitment_txid, watch_outputs))
1564+
(claims, set_counterparty_payment_script)
14741565
}
14751566

14761567
/// Attempts to claim a counterparty HTLC-Success/HTLC-Timeout's outputs using the revocation key
@@ -1500,7 +1591,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15001591
(claimable_outpoints, Some((htlc_txid, outputs)))
15011592
}
15021593

1503-
fn broadcast_by_holder_state(&self, commitment_tx: &Transaction, holder_tx: &HolderSignedTx) -> (Vec<ClaimRequest>, Vec<(u32, TxOut)>, Option<(Script, PublicKey, PublicKey)>) {
1594+
fn broadcast_by_holder_state(&self, commitment_tx: Option<&Transaction>, holder_tx: &HolderSignedTx) -> (Vec<ClaimRequest>, Vec<(u32, TxOut)>, Option<(Script, PublicKey, PublicKey)>) {
15041595
let mut claim_requests = Vec::with_capacity(holder_tx.htlc_outputs.len());
15051596
let mut watch_outputs = Vec::with_capacity(holder_tx.htlc_outputs.len());
15061597

@@ -1521,7 +1612,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15211612
} else { None },
15221613
amount: htlc.amount_msat,
15231614
}});
1524-
watch_outputs.push((transaction_output_index, commitment_tx.output[transaction_output_index as usize].clone()));
1615+
if let Some(commitment_tx) = commitment_tx {
1616+
watch_outputs.push((transaction_output_index, commitment_tx.output[transaction_output_index as usize].clone()));
1617+
}
15251618
}
15261619
}
15271620

@@ -1573,13 +1666,13 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
15731666
if self.current_holder_commitment_tx.txid == commitment_txid {
15741667
is_holder_tx = true;
15751668
log_trace!(logger, "Got latest holder commitment tx broadcast, searching for available HTLCs to claim");
1576-
let mut res = self.broadcast_by_holder_state(tx, &self.current_holder_commitment_tx);
1669+
let mut res = self.broadcast_by_holder_state(Some(tx), &self.current_holder_commitment_tx);
15771670
append_onchain_update!(res);
15781671
} else if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx {
15791672
if holder_tx.txid == commitment_txid {
15801673
is_holder_tx = true;
15811674
log_trace!(logger, "Got previous holder commitment tx broadcast, searching for available HTLCs to claim");
1582-
let mut res = self.broadcast_by_holder_state(tx, holder_tx);
1675+
let mut res = self.broadcast_by_holder_state(Some(tx), holder_tx);
15831676
append_onchain_update!(res);
15841677
}
15851678
}
@@ -1748,7 +1841,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17481841
self.pending_monitor_events.push(MonitorEvent::CommitmentTxBroadcasted(self.funding_info.0));
17491842
if let Some(commitment_tx) = self.onchain_tx_handler.get_fully_signed_holder_tx(&self.funding_redeemscript) {
17501843
self.holder_tx_signed = true;
1751-
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_holder_state(&commitment_tx, &self.current_holder_commitment_tx);
1844+
let (mut new_outpoints, new_outputs, _) = self.broadcast_by_holder_state(Some(&commitment_tx), &self.current_holder_commitment_tx);
17521845
if !new_outputs.is_empty() {
17531846
watch_outputs.push((self.current_holder_commitment_tx.txid.clone(), new_outputs));
17541847
}
@@ -1776,7 +1869,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
17761869
}
17771870
}
17781871

1779-
self.onchain_tx_handler.block_connected(&txn_matched, claimable_outpoints, height, &*broadcaster, &*fee_estimator, &*logger);
1872+
self.onchain_tx_handler.update_claims_view(&txn_matched, claimable_outpoints, Some(height), &&*broadcaster, &&*fee_estimator, &&*logger);
17801873
self.last_block_hash = block_hash;
17811874

17821875
// Determine new outputs to watch by comparing against previously known outputs to watch,

lightning/src/ln/channelmanager.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use bitcoin::secp256k1;
3737
use chain;
3838
use chain::Watch;
3939
use chain::chaininterface::{BroadcasterInterface, FeeEstimator};
40-
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, ChannelMonitorUpdateErr, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent};
40+
use chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdate, ChannelMonitorUpdateStep, ChannelMonitorUpdateErr, HTLC_FAIL_BACK_BUFFER, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY, MonitorEvent, CLOSED_CHANNEL_UPDATE_ID};
4141
use chain::transaction::{OutPoint, TransactionData};
4242
use ln::channel::{Channel, ChannelError};
4343
use ln::features::{InitFeatures, NodeFeatures};
@@ -2165,7 +2165,7 @@ impl<ChanSigner: ChannelKeys, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
21652165
Ok(()) => Ok(()),
21662166
Err(None) => {
21672167
let preimage_update = ChannelMonitorUpdate {
2168-
update_id: std::u64::MAX,
2168+
update_id: CLOSED_CHANNEL_UPDATE_ID,
21692169
updates: vec![ChannelMonitorUpdateStep::PaymentPreimage {
21702170
payment_preimage: payment_preimage.clone(),
21712171
}],

0 commit comments

Comments
 (0)