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

Preparations for storing channels per peer #1542

Conversation

ViktorTigerstrom
Copy link
Contributor

With #1507, we will store channels per peer in the per_peer_state map, instead of the channel_state. This PR splits up some of the functionality of #1507. To enable the transition to storing channels per peer, we need to update the short_to_id map to also include the counterparty_node_id.

The counterparty_node_id isn't passed with MonitorEvents currently, we also need to add an additional map id_to_peer, which gives us the counterparty_node_id when we only have access to the channel_id. However, we would preferably like to avoid the need for this map, so it is only used for MonitorEvent handling, so that it can be removed once we have the counterparty_node_id as an required field in ChannelMonitors.

@@ -7579,6 +7619,121 @@ mod tests {
// Check that using the original payment hash succeeds.
assert!(inbound_payment::verify(payment_hash, &payment_data, nodes[0].node.highest_seen_timestamp.load(Ordering::Acquire) as u64, &nodes[0].node.inbound_payment_key, &nodes[0].logger).is_ok());
}

#[test]
fn test_id_to_peer_coverage() {
Copy link
Contributor Author

@ViktorTigerstrom ViktorTigerstrom Jun 14, 2022

Choose a reason for hiding this comment

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

Let me know if you'd like me to add the by_id map (channel_by_id in #1507) and the short_to_chan_info map to this test. Also let me know if you'd like me to update the test with force closing the channel etc. :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not too picky here, given the code is in the same place as other similar changes I'm not too worried about it.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If you want to improve test coverage, I'd instead recommend debug_assert!()s during channelmanager operation, eg in the removal macro, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I'll look into that.

TheBlueMatt
TheBlueMatt previously approved these changes Jun 16, 2022
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
/// We should add `counterparty_node_id`s to `MonitorEvent`s, and eventually rely on it in the
/// future. That would make this map redundant, as only the `ChannelManager::per_peer_state` is
/// required to access the channel with the `counterparty_node_id`.
id_to_peer: Mutex<HashMap<[u8; 32], PublicKey>>,
Copy link

Choose a reason for hiding this comment

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

What consistency do we expect between id_to_peer and ChannelHolder::by_id, like anything in the later should be in the former ? If yes, I think there are few call sites where we retain(), e.g in timer_tick_occurred

Copy link
Contributor Author

@ViktorTigerstrom ViktorTigerstrom Jun 16, 2022

Choose a reason for hiding this comment

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

I think all cases where false is returned to retain for a channel and we have received an OpenChannel or AcceptChannel msg for the channel, update_maps_on_chan_removal! is triggered, which removes the channel entry from the id_to_peer map :).

Copy link

Choose a reason for hiding this comment

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

Okay, I went to verify the retain callsites and I think this statement is correct. Even if id_to_peer might not be long-lived on the great scheme of things, it would be nice to document the consistency requirements among the two maps. Like say by_id removal should always be follow-up by a call to update_maps_on_chan_removal!.

Copy link
Contributor Author

@ViktorTigerstrom ViktorTigerstrom Jun 20, 2022

Choose a reason for hiding this comment

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

Thanks! Oh yeah, that's a great idea! I'll update the docs with that in #1507 :)

@codecov-commenter
Copy link

codecov-commenter commented Jun 16, 2022

Codecov Report

Merging #1542 (93497bf) into main (e254912) will decrease coverage by 0.22%.
The diff coverage is 92.50%.

❗ Current head 93497bf differs from pull request most recent head fa7f170. Consider uploading reports for the commit fa7f170 to get more accurate results

@@            Coverage Diff             @@
##             main    #1542      +/-   ##
==========================================
- Coverage   91.04%   90.81%   -0.23%     
==========================================
  Files          80       80              
  Lines       44194    44526     +332     
  Branches    44194    44526     +332     
==========================================
+ Hits        40235    40437     +202     
- Misses       3959     4089     +130     
Impacted Files Coverage Δ
lightning/src/ln/channel.rs 88.75% <ø> (+0.02%) ⬆️
lightning/src/ln/channelmanager.rs 85.08% <92.30%> (+0.35%) ⬆️
lightning/src/ln/reorg_tests.rs 100.00% <100.00%> (ø)
lightning-invoice/src/payment.rs 87.76% <0.00%> (-5.15%) ⬇️
lightning/src/util/events.rs 39.25% <0.00%> (-2.42%) ⬇️
lightning/src/routing/scoring.rs 96.08% <0.00%> (-0.73%) ⬇️
lightning/src/ln/payment_tests.rs 98.57% <0.00%> (-0.69%) ⬇️
lightning/src/ln/functional_tests.rs 96.78% <0.00%> (-0.24%) ⬇️
lightning/src/routing/router.rs 92.40% <0.00%> (-0.22%) ⬇️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e254912...fa7f170. Read the comment docs.

@ViktorTigerstrom
Copy link
Contributor Author

Thanks for the reviews @TheBlueMatt & @ariard! Addressed the nits in the new fixup commits :)

ariard
ariard previously approved these changes Jun 20, 2022
Copy link

@ariard ariard left a comment

Choose a reason for hiding this comment

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

Code Review ACK ab43fcd

I think better comment of the maps consistency can be addressed in #1507 or split-off.

@ViktorTigerstrom
Copy link
Contributor Author

Code Review ACK ab43fcd

I think better comment of the maps consistency can be addressed in #1507 or split-off.

Thanks! Squashed the fix up commits without changes :).

wpaulino
wpaulino previously approved these changes Jun 22, 2022
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
@ViktorTigerstrom
Copy link
Contributor Author

Thanks for the review @wpaulino :)! Adressed the feedback and squashed the changes in the last commit.

wpaulino
wpaulino previously approved these changes Jun 22, 2022
@TheBlueMatt TheBlueMatt added the blocked on next release Should Wait Until Next Release To Land label Jun 22, 2022
ariard
ariard previously approved these changes Jun 22, 2022
Copy link

@ariard ariard left a comment

Choose a reason for hiding this comment

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

Code Review ACK 8a8a4de

@TheBlueMatt TheBlueMatt removed the blocked on next release Should Wait Until Next Release To Land label Jul 2, 2022
@TheBlueMatt
Copy link
Collaborator

Oops sorry, this needs a rebase now :(. Should be good to go once that happens, though!

As the map values are no longer only `channel_id`s, but also a
`counterparty_node_id`s, the map is renamed to better correspond to
whats actually stored in the map.
@ViktorTigerstrom ViktorTigerstrom dismissed stale reviews from ariard and wpaulino via 549c42f July 7, 2022 11:39
@ViktorTigerstrom ViktorTigerstrom force-pushed the 2022-06-prepare-maps-for-channels-per-peer branch from 8a8a4de to 549c42f Compare July 7, 2022 11:39
@ViktorTigerstrom
Copy link
Contributor Author

Rebased on upstream! Apologies for the delay.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

Oops, sorry, one issue.

@@ -4511,12 +4538,16 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
return Err(MsgHandleErrInternal::send_err_msg_no_close("Already had channel with the new channel_id".to_owned(), funding_msg.channel_id))
},
hash_map::Entry::Vacant(e) => {
let mut id_to_peer = self.id_to_peer.lock().unwrap();
if id_to_peer.insert(funding_msg.channel_id, *counterparty_node_id).is_some() {
panic!("id_to_peer map already contained funding txid, which shouldn't be possible");
Copy link
Collaborator

Choose a reason for hiding this comment

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

THis is definitely reachable - a counterparty could send us a channel with a conflicting txid. Sure, it wont have the output script pubkey that we agreed upon with the counterparty (which used unique keys), but we dont know that until we see the txid on-chain. Instead, this should be handled as a channel-closure error.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Well, okay, its obviously not reachable today as of this PR, but post-per-peer-channels it will be, so we should handle it here, no? If you want to handle it in the per-peer-storage PR that's okay too.

Copy link

Choose a reason for hiding this comment

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

IIUC your concern, you think about a counterparty collisioning the id_to_peer map by announcing Channel 2 with temporary_id=XYZ from announced-by-us Channel 1 temporary_id ? Even if our temporary ids are generated by get_secure_random_bytes().

Copy link
Collaborator

Choose a reason for hiding this comment

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

No, this is post-temporary ids, this is generated from the funding txid - the issue is a peer can open two channels and give us the same txid to us on both channels (using different peer ids/node private keys).

Copy link
Contributor Author

@ViktorTigerstrom ViktorTigerstrom Jul 7, 2022

Choose a reason for hiding this comment

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

Oh yeah, good catch! I'll update this PR to fix it.

@ariard, no at this stage the temporary_channel_id is unrelated to the problem that @TheBlueMatt is raising, as this is when we are inserting the actual channel_id. As of today with this PR, the panic isn't reachable as the channel_state.by_id entry check right above will catch the scenario Matt raised as the channel_state.by_id isn't peer specific. But once per-peer-storage PR is merged, that check will be peer specific while the id_to_peer insert remains peer unspecific, and therefore 2 different peers could send us the same txid and not be catched by the first entry check above, hence triggering the panic.

Edit: Ah Matt got to it first :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmmm @TheBlueMatt, won't the scenario you are describing already be caught by:

return Err(APIError::APIMisuseError {

That doesn't apply for funding_transaction_generated_unchecked of course, but that's for testing only.

We can of course add an extra guard for it in funding_transaction_generated_intern if you think that it's suitable though :)!

Copy link
Collaborator

Choose a reason for hiding this comment

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

For outbound channels, yes, for inbound channels we don't see the funding transaction until it hits the chain.

Copy link
Contributor Author

@ViktorTigerstrom ViktorTigerstrom Jul 8, 2022

Choose a reason for hiding this comment

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

Oh I'm stupid...!

Fixed in c09903b.

/// TODO:
/// The `counterparty_node_id` isn't passed with `MonitorEvent`s currently. To pass it, we need
/// to add the `counterparty_node_id` to `ChannelMonitor`s. However, adding it as a required
/// field in `ChannelMonitor`s would break backwards compatability.
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: THis is a bit confusing - its not adding the field that breaks backwards compat (in fact we're gonna do it in #1596), its requiring it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

{
// Assert that the channel is removed from both parties `id_to_peer` map once they both
// have everything required to fully close the channel.
assert_eq!(nodes[0].node.id_to_peer.lock().unwrap().len(), 0);
Copy link

Choose a reason for hiding this comment

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

I think this check is redundant with the one above. Though can be kept if you wanna assert node[0]'s id_to_peer has not been modified.

Copy link
Contributor Author

Choose a reason for hiding this comment

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


// Clear the `ChannelClosed` event for the nodes.
nodes[0].node.get_and_clear_pending_events();
nodes[1].node.get_and_clear_pending_events();
Copy link

Choose a reason for hiding this comment

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

I think you could use the macro get_event() to test the expected ChannelClosed event.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@@ -4511,12 +4538,16 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
return Err(MsgHandleErrInternal::send_err_msg_no_close("Already had channel with the new channel_id".to_owned(), funding_msg.channel_id))
},
hash_map::Entry::Vacant(e) => {
let mut id_to_peer = self.id_to_peer.lock().unwrap();
if id_to_peer.insert(funding_msg.channel_id, *counterparty_node_id).is_some() {
panic!("id_to_peer map already contained funding txid, which shouldn't be possible");
Copy link

Choose a reason for hiding this comment

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

IIUC your concern, you think about a counterparty collisioning the id_to_peer map by announcing Channel 2 with temporary_id=XYZ from announced-by-us Channel 1 temporary_id ? Even if our temporary ids are generated by get_secure_random_bytes().

Copy link

@ariard ariard left a comment

Choose a reason for hiding this comment

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

SGTM

@ViktorTigerstrom ViktorTigerstrom force-pushed the 2022-06-prepare-maps-for-channels-per-peer branch from 77b7477 to c09903b Compare July 8, 2022 14:54
match id_to_peer.entry(chan.channel_id()) {
hash_map::Entry::Occupied(_) => {
return Err(MsgHandleErrInternal::send_err_msg_no_close(
"Funding txid already exists with for another peer (or likely the
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we make the error here a bit more compact? Note that we send our peer the error and log it, so it should generally be readable for both. Maybe "funding_created message had the same funding txid as an existing channel - funding is not possible" or something simple like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh thanks, that makes sense:
81fc01f


// Clear the `ChannelClosed` event for the nodes.
get_event!(&nodes[0], Event::ChannelClosed);
get_event!(&nodes[1], Event::ChannelClosed);
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: check_closed_event?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@TheBlueMatt
Copy link
Collaborator

LGTM. Needs squash, but will let other reviewers comment on that.

wpaulino
wpaulino previously approved these changes Jul 11, 2022
@TheBlueMatt
Copy link
Collaborator

Can you squash the fixup commits down to clean up the history and I think we can basically land this.

@ViktorTigerstrom
Copy link
Contributor Author

Squashed without changes

Copy link

@ariard ariard left a comment

Choose a reason for hiding this comment

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

Code Review ACK fa7f170

Changes since last review :

  • update the sentence about breaking backwards compatibility
  • makes the collusion-triggerable-by-counterparty panic actually an error
  • fix few comments in test

@TheBlueMatt TheBlueMatt merged commit fda3819 into lightningdevkit:main Jul 13, 2022
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.

None yet

5 participants