Skip to content

Rebroadcast channel_announcements when we broadcast a node_announce #913

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

Merged
merged 11 commits into from
May 25, 2021

Conversation

TheBlueMatt
Copy link
Collaborator

Also take this chance to add a forward-compatible serialization step.

@codecov
Copy link

codecov bot commented May 6, 2021

Codecov Report

Merging #913 (5bac875) into main (ec3739b) will decrease coverage by 0.00%.
The diff coverage is 85.87%.

❗ Current head 5bac875 differs from pull request most recent head eace819. Consider uploading reports for the commit eace819 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##             main     #913      +/-   ##
==========================================
- Coverage   90.46%   90.46%   -0.01%     
==========================================
  Files          59       59              
  Lines       29896    30022     +126     
==========================================
+ Hits        27046    27159     +113     
- Misses       2850     2863      +13     
Impacted Files Coverage Δ
lightning/src/util/enforcing_trait_impls.rs 90.38% <ø> (ø)
lightning/src/routing/router.rs 96.05% <50.00%> (-0.12%) ⬇️
lightning/src/util/ser_macros.rs 91.11% <62.06%> (-5.63%) ⬇️
lightning/src/ln/channel.rs 87.21% <81.81%> (-0.04%) ⬇️
lightning/src/ln/functional_test_utils.rs 94.90% <88.88%> (-0.17%) ⬇️
lightning/src/ln/channelmanager.rs 83.64% <95.83%> (+0.09%) ⬆️
lightning/src/ln/functional_tests.rs 96.87% <97.43%> (+0.06%) ⬆️
lightning/src/chain/channelmonitor.rs 95.52% <100.00%> (+0.06%) ⬆️
lightning/src/chain/keysinterface.rs 94.96% <100.00%> (+0.04%) ⬆️
lightning/src/ln/msgs.rs 88.20% <100.00%> (-0.02%) ⬇️
... and 7 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 c7e198e...eace819. Read the comment docs.

@TheBlueMatt TheBlueMatt force-pushed the 2021-05-tlv-ser branch 2 times, most recently from 0ab8ac2 to f2fb0f8 Compare May 7, 2021 22:38
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

Looks pretty reasonable to me. Still somewhat reasoning through how upgrading and serialization are going to work.

I see you just pushed more commits so will review those later!

Comment on lines 707 to 708
writer.write_all(&[SERIALIZATION_VERSION; 1])?;
writer.write_all(&[MIN_SERIALIZATION_VERSION; 1])?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Given this will be repeated across each implementation, would it make sense to make these part of the trait with a provided method for writing these? Similarly for Readable. Or is this only needed for "top-level" structs?

Thinking mainly about consolidating documentation around forward and backwards compatibility.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's a conversation probably worth having in a meeting/on slack - I'm certainly open to moving it into the serialization traits, presumably then writing versions into ~every non-p2p struct. Alternatively we could have some helper that handles it for us, ie SerializationVersionTag{}.write(writer)??

Ok(())
}
}

impl Readable for InMemorySigner {
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
let _ver: u8 = Readable::read(reader)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

In what scenario would implementor need to examine the read version? Reading optional fields?

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'd need it to read old versions - eg "oh, we added a new field or gave a new field some different meaning, we need to check which version object was written so we can interpret it properly".

@@ -8,21 +8,54 @@
// licenses.

macro_rules! encode_tlv {
($stream: expr, {$(($type: expr, $field: expr)),*}) => { {
($stream: expr, {$(($type: expr, $field: expr)),*}, {$(($optional_type: expr, $optional_field: expr)),*}) => { {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure I fully understand the need for this. Aren't optional types defined by having an odd type number?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In this case optional_type means "thing which may or may not exist at compile time, and is actually stored in an Option at runtime, only optionally writing it.

@TheBlueMatt
Copy link
Collaborator Author

I macro-ized the new code, which allows for a good place to place documentation about the various versioning schemes in play, and also unifies the code to handle it somewhat.

@TheBlueMatt TheBlueMatt added this to the 0.0.15 milestone May 20, 2021
@TheBlueMatt
Copy link
Collaborator Author

Rebased on latest usptream, only changes were the comments Val left above.

@@ -4431,8 +4424,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
let _consistency_lock = self.total_consistency_lock.write().unwrap();

writer.write_all(&[SERIALIZATION_VERSION; 1])?;
writer.write_all(&[MIN_SERIALIZATION_VERSION; 1])?;
write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
Copy link
Contributor

@valentinewallace valentinewallace May 20, 2021

Choose a reason for hiding this comment

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

Some other structs I'm not sure if it'd be worth adding versioning to, while we're at it:
Route
NetworkGraph
EnforcingSigner
Features
?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Route and NetworkGraph: yea, good catch, added.
EnforcingSigner is currently test-only (and may very well never be exposed as lightning-signer basically does what we'd want it to be), but I added a comment about it,
Features is a on-the-wire BOLT struct so we can't differ from the prescribed serialization format there.

Copy link
Contributor

Choose a reason for hiding this comment

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

Question: so for keysend, I think I'm going to be adding/modifying fields in PendingHTLCInfo . Would this mean that versioning needs to be added to this struct (I believe this field is persisted in Channel so it could have potential compatibility issues)? Or does it mean I'll need to bump the serialization version in Channel? I guess I'm not sure of the exact procedure for changing struct fields going forward.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, so for enums its easy - we usually have 0-N already defined and we can just add N+1... For something like PendingHTLCInfo we could maybe pass a version in to the read method, which would imply defining a new VersionedReadable trait. Of course that isn't exactly ideal because it means that even people who don't use keysend can't read new ChannelManagers with an old LDK version. If we want to be really broad about supporting old versions reading LDK structs from newer versions that don't use optional features, we should probably move the entire serialization of everything into TLVs (but in a separate PR).

@TheBlueMatt TheBlueMatt force-pushed the 2021-05-tlv-ser branch 2 times, most recently from e0e0246 to 9735461 Compare May 21, 2021 16:58
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

Can't see any issues really, but I'd like to take a fresher look on Monday if that works

msg,
update_msg: match self.get_channel_update(chan) {
Ok(msg) => msg,
Err(_) => continue,
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm will this effectively continue if the channel isn't fully open yet? Could maybe use a comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This should only hit if the funding transaction hasn't been confirmed at all (ie doesn't have a short channel ID yet), in which case we shouldn't have gotten a result from get_signed_channel_announcement, either.

Copy link
Contributor

Choose a reason for hiding this comment

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

in which case we shouldn't have gotten a result from get_signed_channel_announcement, either.

If that's the case, could this be an assertion / panic?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I figured this is the correct behavior if the logic in get_channel_update ever changes (or I'm wrong about the logic now) - its not a case where we're at risk of losing funds or any serious issues, so best not to panic.

@TheBlueMatt TheBlueMatt force-pushed the 2021-05-tlv-ser branch 3 times, most recently from 5bac875 to eace819 Compare May 24, 2021 17:52
@TheBlueMatt
Copy link
Collaborator Author

Squashed without changes + rebased, which should fix the check_commits CI test.

Copy link
Contributor

@jkczyz jkczyz left a comment

Choose a reason for hiding this comment

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

Took a pass through each commit. Largely looks good.

msg,
update_msg: match self.get_channel_update(chan) {
Ok(msg) => msg,
Err(_) => continue,
Copy link
Contributor

Choose a reason for hiding this comment

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

in which case we shouldn't have gotten a result from get_signed_channel_announcement, either.

If that's the case, could this be an assertion / panic?

Currently our serialization is very compact, and contains version
numbers to indicate which versions the code can read a given
serialized struct. However, if you want to add a new field without
needlessly breaking the ability of previous versions of the code to
read the struct, there is not a good way to do so.

This adds dummy, currently empty, TLVs to the major structs we
serialize out for users, providing an easy place to put new
optional fields without breaking previous versions.
Previously we handled most of the logic of announcement_signatures
in ChannelManager, rather than Channel. This is somewhat unique as
far as our message processing goes, but it also avoided having to
pass the node_secret in to the Channel.

Eventually, we'll move the node_secret behind the signer anyway, so
there isn't much reason for this, and storing the
announcement_signatures-provided signatures in the Channel allows
us to recreate the channel_announcement later for rebroadcast,
which may be useful.
Copy link
Contributor

@valentinewallace valentinewallace left a comment

Choose a reason for hiding this comment

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

One question about changing struct fields going forward, but this LGTM 👍

@@ -4431,8 +4424,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
let _consistency_lock = self.total_consistency_lock.write().unwrap();

writer.write_all(&[SERIALIZATION_VERSION; 1])?;
writer.write_all(&[MIN_SERIALIZATION_VERSION; 1])?;
write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION);
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: so for keysend, I think I'm going to be adding/modifying fields in PendingHTLCInfo . Would this mean that versioning needs to be added to this struct (I believe this field is persisted in Channel so it could have potential compatibility issues)? Or does it mean I'll need to bump the serialization version in Channel? I guess I'm not sure of the exact procedure for changing struct fields going forward.

@TheBlueMatt
Copy link
Collaborator Author

Agreement on Slack indicated (a) merge this, (b) do a followup which TLV's most internal structs.

@TheBlueMatt TheBlueMatt merged commit 55538db into lightningdevkit:main May 25, 2021
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