Skip to content

Commit f916e13

Browse files
committed
Track outpoint creation height in PackageSolvingData
When we have an outpoint to claim which is lock-timed and the locktime is reached, we add it to `OnchainTxHandler::claimable_outpoints` to indicate the outpoint is now being claimed. However, `claimable_outpoints` is supposed to track when the outpoint first appeared on chain so that we can remove the claim if the outpoint is reorged out. Sadly, in the handling for lock-timed packages, we incorrectly stored the current height in `claimable_outpoints`, causing such claims to be removed in case of a reorg right after they were generated, even if the output we intend to claim isn't removed at all. Here we start tracking when the outpoint we're spending was created in `PackageSolvingData`'s constituent types. While we could have tracked this information in `PackageTemplate`, it would preclude later merging packages that are spending outpoints included in different blocks, which we don't necessarily want to do.
1 parent 92fe3aa commit f916e13

File tree

3 files changed

+96
-46
lines changed

3 files changed

+96
-46
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3514,23 +3514,26 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
35143514
(payment_preimage.clone(), payment_info.clone().into_iter().collect())
35153515
});
35163516

3517-
let confirmed_spend_txid = self.funding_spend_confirmed.or_else(|| {
3518-
self.onchain_events_awaiting_threshold_conf.iter().find_map(|event| match event.event {
3519-
OnchainEvent::FundingSpendConfirmation { .. } => Some(event.txid),
3520-
_ => None,
3521-
})
3522-
});
3523-
let confirmed_spend_txid = if let Some(txid) = confirmed_spend_txid {
3524-
txid
3525-
} else {
3526-
return;
3527-
};
3517+
let confirmed_spend_info = self.funding_spend_confirmed
3518+
.map(|txid| (txid, None))
3519+
.or_else(|| {
3520+
self.onchain_events_awaiting_threshold_conf.iter().find_map(|event| match event.event {
3521+
OnchainEvent::FundingSpendConfirmation { .. } => Some((event.txid, Some(event.height))),
3522+
_ => None,
3523+
})
3524+
});
3525+
let (confirmed_spend_txid, confirmed_spend_height) =
3526+
if let Some((txid, height)) = confirmed_spend_info {
3527+
(txid, height)
3528+
} else {
3529+
return;
3530+
};
35283531

35293532
// If the channel is force closed, try to claim the output from this preimage.
35303533
// First check if a counterparty commitment transaction has been broadcasted:
35313534
macro_rules! claim_htlcs {
35323535
($commitment_number: expr, $txid: expr, $htlcs: expr) => {
3533-
let (htlc_claim_reqs, _) = self.get_counterparty_output_claim_info($commitment_number, $txid, None, $htlcs);
3536+
let (htlc_claim_reqs, _) = self.get_counterparty_output_claim_info($commitment_number, $txid, None, $htlcs, confirmed_spend_height);
35343537
let conf_target = self.closure_conf_target();
35353538
self.onchain_tx_handler.update_claims_view_from_requests(
35363539
htlc_claim_reqs, self.best_block.height, self.best_block.height, broadcaster,
@@ -4226,6 +4229,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
42264229
per_commitment_point, per_commitment_key, outp.value,
42274230
self.funding.channel_parameters.channel_type_features.supports_anchors_zero_fee_htlc_tx(),
42284231
self.funding.channel_parameters.clone(),
4232+
height,
42294233
);
42304234
let justice_package = PackageTemplate::build_package(
42314235
commitment_txid, idx as u32,
@@ -4250,6 +4254,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
42504254
let revk_htlc_outp = RevokedHTLCOutput::build(
42514255
per_commitment_point, per_commitment_key, htlc.clone(),
42524256
self.funding.channel_parameters.clone(),
4257+
height,
42534258
);
42544259
let counterparty_spendable_height = if htlc.offered {
42554260
htlc.cltv_expiry
@@ -4304,7 +4309,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
43044309
(htlc, htlc_source.as_ref().map(|htlc_source| htlc_source.as_ref()))
43054310
), logger);
43064311
let (htlc_claim_reqs, counterparty_output_info) =
4307-
self.get_counterparty_output_claim_info(commitment_number, commitment_txid, Some(tx), per_commitment_option);
4312+
self.get_counterparty_output_claim_info(commitment_number, commitment_txid, Some(tx), per_commitment_option, Some(height));
43084313
to_counterparty_output_info = counterparty_output_info;
43094314
for req in htlc_claim_reqs {
43104315
claimable_outpoints.push(req);
@@ -4316,8 +4321,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
43164321

43174322
/// Returns the HTLC claim package templates and the counterparty output info
43184323
#[rustfmt::skip]
4319-
fn get_counterparty_output_claim_info(&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>, per_commitment_option: Option<&Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>)
4320-
-> (Vec<PackageTemplate>, CommitmentTxCounterpartyOutputInfo) {
4324+
fn get_counterparty_output_claim_info(
4325+
&self, commitment_number: u64, commitment_txid: Txid, tx: Option<&Transaction>,
4326+
per_commitment_option: Option<&Vec<(HTLCOutputInCommitment, Option<Box<HTLCSource>>)>>,
4327+
confirmation_height: Option<u32>,
4328+
) -> (Vec<PackageTemplate>, CommitmentTxCounterpartyOutputInfo) {
43214329
let mut claimable_outpoints = Vec::new();
43224330
let mut to_counterparty_output_info: CommitmentTxCounterpartyOutputInfo = None;
43234331

@@ -4374,15 +4382,19 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
43744382
let counterparty_htlc_outp = if htlc.offered {
43754383
PackageSolvingData::CounterpartyOfferedHTLCOutput(
43764384
CounterpartyOfferedHTLCOutput::build(
4377-
*per_commitment_point, preimage.unwrap(), htlc.clone(),
4385+
*per_commitment_point, preimage.unwrap(),
4386+
htlc.clone(),
43784387
self.funding.channel_parameters.clone(),
4388+
confirmation_height,
43794389
)
43804390
)
43814391
} else {
43824392
PackageSolvingData::CounterpartyReceivedHTLCOutput(
43834393
CounterpartyReceivedHTLCOutput::build(
4384-
*per_commitment_point, htlc.clone(),
4394+
*per_commitment_point,
4395+
htlc.clone(),
43854396
self.funding.channel_parameters.clone(),
4397+
confirmation_height,
43864398
)
43874399
)
43884400
};
@@ -4426,6 +4438,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
44264438
let revk_outp = RevokedOutput::build(
44274439
per_commitment_point, per_commitment_key, tx.output[idx].value, false,
44284440
self.funding.channel_parameters.clone(),
4441+
height,
44294442
);
44304443
let justice_package = PackageTemplate::build_package(
44314444
htlc_txid, idx as u32, PackageSolvingData::RevokedOutput(revk_outp),
@@ -4507,7 +4520,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
45074520
.expect("Expected transaction output index for non-dust HTLC");
45084521
PackageTemplate::build_package(
45094522
tx.txid(), transaction_output_index,
4510-
PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build(htlc_descriptor)),
4523+
PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build(htlc_descriptor, conf_height)),
45114524
counterparty_spendable_height,
45124525
)
45134526
})
@@ -4687,7 +4700,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
46874700
let txid = self.funding.current_holder_commitment_tx.trust().txid();
46884701
let vout = htlc_descriptor.htlc.transaction_output_index
46894702
.expect("Expected transaction output index for non-dust HTLC");
4690-
let htlc_output = HolderHTLCOutput::build(htlc_descriptor);
4703+
let htlc_output = HolderHTLCOutput::build(htlc_descriptor, 0);
46914704
if let Some(htlc_tx) = htlc_output.get_maybe_signed_htlc_tx(
46924705
&mut self.onchain_tx_handler, &::bitcoin::OutPoint { txid, vout },
46934706
) {

lightning/src/chain/onchaintx.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,19 +1379,21 @@ mod tests {
13791379
holder_commit_txid,
13801380
htlc.transaction_output_index.unwrap(),
13811381
PackageSolvingData::HolderHTLCOutput(HolderHTLCOutput::build(HTLCDescriptor {
1382-
channel_derivation_parameters: ChannelDerivationParameters {
1383-
value_satoshis: tx_handler.channel_value_satoshis,
1384-
keys_id: tx_handler.channel_keys_id,
1385-
transaction_parameters: tx_handler.channel_transaction_parameters.clone(),
1382+
channel_derivation_parameters: ChannelDerivationParameters {
1383+
value_satoshis: tx_handler.channel_value_satoshis,
1384+
keys_id: tx_handler.channel_keys_id,
1385+
transaction_parameters: tx_handler.channel_transaction_parameters.clone(),
1386+
},
1387+
commitment_txid: holder_commit_txid,
1388+
per_commitment_number: holder_commit.commitment_number(),
1389+
per_commitment_point: holder_commit.per_commitment_point(),
1390+
feerate_per_kw: holder_commit.feerate_per_kw(),
1391+
htlc: htlc.clone(),
1392+
preimage: None,
1393+
counterparty_sig: *counterparty_sig,
13861394
},
1387-
commitment_txid: holder_commit_txid,
1388-
per_commitment_number: holder_commit.commitment_number(),
1389-
per_commitment_point: holder_commit.per_commitment_point(),
1390-
feerate_per_kw: holder_commit.feerate_per_kw(),
1391-
htlc: htlc.clone(),
1392-
preimage: None,
1393-
counterparty_sig: *counterparty_sig,
1394-
})),
1395+
0
1396+
)),
13951397
0,
13961398
));
13971399
}

0 commit comments

Comments
 (0)