-
Notifications
You must be signed in to change notification settings - Fork 418
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
Rebroadcast channel_announcements when we broadcast a node_announce #913
Conversation
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
0ab8ac2
to
f2fb0f8
Compare
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.
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!
lightning/src/chain/keysinterface.rs
Outdated
writer.write_all(&[SERIALIZATION_VERSION; 1])?; | ||
writer.write_all(&[MIN_SERIALIZATION_VERSION; 1])?; |
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.
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.
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.
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)?
?
lightning/src/chain/keysinterface.rs
Outdated
Ok(()) | ||
} | ||
} | ||
|
||
impl Readable for InMemorySigner { | ||
fn read<R: ::std::io::Read>(reader: &mut R) -> Result<Self, DecodeError> { | ||
let _ver: u8 = Readable::read(reader)?; |
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.
In what scenario would implementor need to examine the read version? Reading optional fields?
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.
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)),*}) => { { |
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.
Not sure I fully understand the need for this. Aren't optional types defined by having an odd type number?
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.
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.
ce3b66b
to
2bdeae3
Compare
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. |
2bdeae3
to
78f5be7
Compare
78f5be7
to
c3a4e54
Compare
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); |
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.
Some other structs I'm not sure if it'd be worth adding versioning to, while we're at it:
Route
NetworkGraph
EnforcingSigner
Features
?
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.
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.
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.
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.
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 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 ChannelManager
s 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).
e0e0246
to
9735461
Compare
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.
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, |
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.
Hm will this effectively continue if the channel isn't fully open yet? Could maybe use a comment
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.
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.
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.
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?
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 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.
5bac875
to
eace819
Compare
Squashed without changes + rebased, which should fix the |
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.
Took a pass through each commit. Largely looks good.
msg, | ||
update_msg: match self.get_channel_update(chan) { | ||
Ok(msg) => msg, | ||
Err(_) => continue, |
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.
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.
eace819
to
3c7bee3
Compare
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.
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); |
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.
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.
Agreement on Slack indicated (a) merge this, (b) do a followup which TLV's most internal structs. |
Also take this chance to add a forward-compatible serialization step.