-
Notifications
You must be signed in to change notification settings - Fork 385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Correctly detect missing HTLCs when a local commitment tx was broadcast #1025
Correctly detect missing HTLCs when a local commitment tx was broadcast #1025
Conversation
931b054
to
b688365
Compare
Codecov Report
@@ Coverage Diff @@
## main #1025 +/- ##
==========================================
+ Coverage 90.80% 91.60% +0.80%
==========================================
Files 61 62 +1
Lines 31582 39598 +8016
==========================================
+ Hits 28678 36274 +7596
- Misses 2904 3324 +420
Continue to review full report at Codecov.
|
if is_holder_tx { | ||
fail_dust_htlcs_after_threshold_conf!(self.current_holder_commitment_tx); | ||
if let &Some(ref holder_tx) = &self.prev_holder_signed_commitment_tx { | ||
fail_dust_htlcs_after_threshold_conf!(holder_tx); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty if
block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, it'll be re-filled in the PR this one grew out of so I left it. I can remove it temporarily if you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What PR is that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll let you know when I open it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let chanmon_cfgs = create_chanmon_cfgs(3); | ||
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs); | ||
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]); | ||
let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary mut
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Old rustc incorrectly rejected this as missing-mut, see comment in lightning/src/ln/mod.rs
. I added an ignore for this.
error[E0596]: cannot borrow `nodes` as mutable, as it is not declared as mutable
--> lightning/src/ln/monitor_tests.rs:51:87
|
46 | let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
| ----- help: consider changing this to be mutable: `mut nodes`
...
51 | let (route, payment_hash, _, payment_secret) = get_route_and_payment_hash!(nodes[0], nodes[2], 1_000_000);
| ^^^^^ cannot borrow as mutable
} | ||
} | ||
} | ||
fail_unbroadcast_htlcs!(self, "previous holder", height, holder_tx.htlc_outputs.iter().map(|(a, _, c)| (a, c.as_ref())), logger); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify: is the main difference in logic that before we would only consider the relevant commitment tx's outputs
but now we consider all of counterparty_claimable_outpoints
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, so the trick here is that the counterparty commitment transaction is the "latest" one, because its the one that we generated. The local commitment transaction is the one our counterparty generated, so isn't always the HTLC state that matches our ChannelMonitor state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add some docs (including the info in your comment^) to counterparty_claimable_outpoints
? I had to search around the file to get some context about it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some docs to counterparty_claimable_outpoints, and expanded the docs on fail_unbroadcast_htlcs to describe my reasoning.
0722912
to
bb1a050
Compare
c3c0dff
to
3f3aff1
Compare
Rebased and squashed. |
This extracts the HTLC-not-in-broadcasted-commitment-transaction code from check_spend_counterparty_transaction and moves it to a global macro, DRYing up the two very similar codepaths (fixing some minor logging inconsistencies) in the process. This macro will be used for local commitment transaction HTLC failure as well in the next commit. This commit has no functional change outside of logging.
If we forward an HTLC to our counterparty, but we force-closed the channel before our counterparty provides us an updated commitment transaction, we'll end up with a commitment transaction that does not contain the HTLC which we attempted to forward. In this case, we need to wait `ANTI_REORG_DELAY` blocks and then fail back the HTLC as there is no way for us to learn the preimage and the confirmed commitment transaction paid us the value of the HTLC. However, check_spend_holder_transaction did not do this - it instead only looked for dust HTLCs in the confirmed commitment transaction, paying no attention to what other HTLCs may exist that are missed. This will eventually lead to channel force-closure as the channel on which we received the inbound HTLC to forward will be closed in time for the initial sender to claim the HTLC on-chain.
3f3aff1
to
6bfab9d
Compare
@@ -510,6 +510,9 @@ pub(crate) struct ChannelMonitorImpl<Signer: Sign> { | |||
on_holder_tx_csv: u16, | |||
|
|||
commitment_secrets: CounterpartyCommitmentSecrets, | |||
/// The set of outpoints in each counterparty commitment transaction. We always need at least |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a true statement: counterparty_claimable_outpoints
is the set of (outpoints_in_prev_counterparty_commit_tx_if_not_revoked, outpoints_in_curr_counterparty_commit_tx)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
counterparty_claimable_outpoints
, somewhat confusingly named, is a map from a single counterparty commitment transaction (by txid) to the set of HTLCs which were included in that transaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
If we forward an HTLC to our counterparty, but we force-closed the
channel before our counterparty provides us an updated commitment
transaction, we'll end up with a commitment transaction that does
not contain the HTLC which we attempted to forward. In this case,
we need to wait
ANTI_REORG_DELAY
blocks and then fail back theHTLC as there is no way for us to learn the preimage and the
confirmed commitment transaction paid us the value of the HTLC.
However, check_spend_holder_transaction did not do this - it
instead only looked for dust HTLCs in the confirmed commitment
transaction, paying no attention to what other HTLCs may exist that
are missed.
This will eventually lead to channel force-closure as the channel
on which we received the inbound HTLC to forward will be closed in
time for the initial sender to claim the HTLC on-chain.
This is a semi-important DoS issue, so tagging 0.0.100.