Skip to content
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

Refactor tlc saving in channel state and fix a few bugs #72

Merged
merged 21 commits into from
Jun 18, 2024

Conversation

contrun
Copy link
Collaborator

@contrun contrun commented Jun 14, 2024

This PR refactored TLC fields in channel state. We will save all the tlcs in a unified tlcs field. This make it more convenient to see when a tlc is added/removed. When refactoring this I also found a few bugs. Below are the changes in this PR.

  1. A notification for local commitment signed LocalCommitmentSigned is added. This may be used to notify watch tower that some transactions are now broadcastable by the peer.
  2. We now have complete information for when a tlc is added/removed.
  3. Previously commitment number is updated on RevokeAndAck from the peer received. This effectively makes local/remote commitment number always the same. We should instead update commitment numbers on CommitmentSigned messages sent or received. This PR fixes that.
  4. The commitment number used to obtain remote commitment point should always be local commitment number (instead of remote commitment number). This asymmetry takes some time to understand, and previously we implemented in the wrong way. A remote commitment point is only obtained when RevokeAndAck is received from the remote party. And RevokeAndAck is sent only when the remote party receives a CommitmentSigned message. This is exactly when the local commitment transaction is updated.

@contrun contrun force-pushed the keep-tlc-on-remove branch 2 times, most recently from 7bf2b7c to c1c4557 Compare June 14, 2024 11:51
src/ckb/channel.rs Outdated Show resolved Hide resolved
} else {
self.to_remote_amount += current.tlc.amount;
}
current.removal_info = Some((commitment_numbers, reason));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it better we remove the current entry from self.tlcs?
otherwise tlcs will keep growing, and we need to serialize and store this field.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need this historical tlc information to construct valid revocation transaction. Imagine that the adversary broadcasts an older commitment transaction, and we want to revoke this. In order to do so, we will need to fill in all the tlcs that are committed commitment transaction in the witness. This is the reason why we need to keep tlcs forever. Of course, we can also save the witnesses for commitment transaction (just hook into this event https://github.com/nervosnetwork/cfn-node/blob/c1c4557a15d6457b23008328e1fc5cdf82e9611b/src/ckb/network.rs#L152C5-L152C27). I personally prefer the latter method. But I haven't think carefully about the tradeoffs. I think it is not such so important to optimize this yet.

src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
src/ckb/channel.rs Outdated Show resolved Hide resolved
Comment on lines +2059 to +2194
a.sort_by(|x, y| u64::from(x.0.tlc.id).cmp(&u64::from(y.0.tlc.id)));
b.sort_by(|x, y| u64::from(x.0.tlc.id).cmp(&u64::from(y.0.tlc.id)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTreeMap is sorted, I don't think we need sort again here. btw, we need unit test for this fn.

Comment on lines 1731 to 1733
self.tlcs.insert(tlc.id, detailed_tlc);
if tlc.is_offered() {
self.to_local_amount -= tlc.amount;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chenyukang a reminder, we need to check to_local_amount / to_remote_amount - tlc.amount > min_amount here before inserting.

Add notification on commitment transaction signed locally

Fix initial commitment number

Bundle local and remote commitment numbers in channel state

Bundle offering and received tlc ids in channel state

Use enum for TLC id

Use a unified field to represent all tlcs in channel state

Use btree map instead of hash map for tlcs

Refactor add tlc

Greatly simplify tlc handling

Remove two subtle bugs due to tlc data structure change

Fix json serde error because keys in objects must be strings

Refactor get active tlc implementation

Remove outdated code

Fix balance calculation in removing tlc
Commitment numbers of each parties are independent. Updating remote
commitment number after received RevokeAndAck effectively means we are
using the same commitment number.
A remote commitment point is only obtained when RevokeAndAck is
received from the remote party. And RevokeAndAck is sent only when the
remote party receives a CommitmentSigned message. This is exactly when
the local commitment transaction is updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants