Skip to content

lnwire: create new ExtraOpaqueData type for parsing TLV extensions#3966

Closed
Roasbeef wants to merge 43 commits into
lightningnetwork:masterfrom
Roasbeef:wire-uniform-tlv
Closed

lnwire: create new ExtraOpaqueData type for parsing TLV extensions#3966
Roasbeef wants to merge 43 commits into
lightningnetwork:masterfrom
Roasbeef:wire-uniform-tlv

Conversation

@Roasbeef
Copy link
Copy Markdown
Member

In this Pr, we create a new ExtraOpaqueData based on the field with the same name that's present in all the announcement related messages. In later commits, we'll embed this new type in each message, so we'll have a generic way to add/parse TLV extensions from messages.

We then convert all the current known messages to include this new field, and parse it accordignly. The new ExtraOpaqueData also comes with some propsective helper methods for TLV encoding/decoding. I envision these will be used either within the top-level Encode/Decode methods, or by callers to populate new (optional) pointer fields that get added in the wire messages similar to the structs in htlcswitch/hop.

@Roasbeef Roasbeef added the v0.10 label Jan 28, 2020
@Roasbeef Roasbeef added this to the 0.10.0 milestone Jan 28, 2020
Copy link
Copy Markdown
Contributor

@cfromknecht cfromknecht left a comment

Choose a reason for hiding this comment

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

nice pr, looks pretty good on first pass! main comment is related to leveraging the codec to make the diff smaller. also would be a good opportunity to remove the max message size method from the message interface, since we now allow all messages to be up to 65KB.

Comment thread lnwire/update_fulfill_htlc.go Outdated
Comment thread lnwire/update_add_htlc.go Outdated
Comment thread lnwire/reply_channel_range.go Outdated
Comment thread lnwire/reply_channel_range.go Outdated
@wpaulino wpaulino removed their request for review January 29, 2020 18:12
Copy link
Copy Markdown
Contributor

@halseth halseth left a comment

Choose a reason for hiding this comment

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

Where is OpenChannel?

Comment thread lnwire/extra_bytes.go Outdated
Comment thread lnwire/extra_bytes.go Outdated
Comment thread lnwire/extra_bytes_test.go Outdated
Comment thread lnwire/extra_bytes_test.go Outdated
Comment thread lnwire/accept_channel.go Outdated
Comment thread lnwire/update_fulfill_htlc.go Outdated
@Roasbeef Roasbeef force-pushed the wire-uniform-tlv branch 2 times, most recently from 6851ed3 to ab3b5b5 Compare March 12, 2020 01:50
@Roasbeef Roasbeef requested review from cfromknecht and halseth March 13, 2020 22:24
@Roasbeef
Copy link
Copy Markdown
Member Author

Roasbeef commented Mar 15, 2020

I ran into a snag with this PR: in certain places we store a message, but then pack in additional data after the wire message, like the commitment diffs we store for the state machine. The current logic here will attempt to read all data after the base message as extra TLV data, so it ends up consuming all the extra bytes, leading to an EOF error when we attempt to read information serialized after the wire message.

A few solutions come to mind:

  1. Do a db migration to prepend a length in front of all wire messages we store in the database. This resolves things as we'd read the entire blob, then pass it into the relevant Decode method.
  2. Add another serialization that includes a length prefix in front of the extra data. This also requires a migration to re-serialize all the messages on disk.
  3. Update the spec to dictate that all TLV extensions include a length prefix. This resolves the issue as we'd stop reading (zero bytes length) at the end of the messages.

Thoughts?

I favor the 1st option myself. Note that certain unit tests in this PR won't pass until we resolve this issue, as they fail with EOF errors. To make things easier, we'd create a [write|read]WireMessage helper function that will be used in channeldb to write/read all wire messages.

If we opt to go with #1, I'll make a new PR for this logic, as to not increase the size of this PR any further.

@halseth
Copy link
Copy Markdown
Contributor

halseth commented Mar 16, 2020

  1. sounds like the easiest one

@Roasbeef
Copy link
Copy Markdown
Member Author

#1 has been done in: #4099.

@halseth
Copy link
Copy Markdown
Contributor

halseth commented Mar 25, 2020

#1

Trip down memory lane

@Roasbeef Roasbeef modified the milestones: 0.10.0, 0.11.0 Apr 7, 2020
@wpaulino wpaulino removed the v0.10 label Apr 13, 2020
@Roasbeef Roasbeef added enhancement Improvements to existing features / behaviour P2 should be fixed if one has time spec wire protocol Encoding of messages for the communication between nodes v0.11 labels Apr 14, 2020
@Roasbeef Roasbeef force-pushed the wire-uniform-tlv branch from f1ee009 to 47d5811 Compare May 22, 2020 23:38
@Roasbeef
Copy link
Copy Markdown
Member Author

Here's a combined branch with the migration PR to show everything passes with both applied: https://github.com/Roasbeef/lnd/pull/new/combined-wire-tlv

The tests won't pass for this PR in isolation, as since the new wire parsing tries to read until EOF, it can read any of the HTLC in the commitment diff as an example.

@Roasbeef
Copy link
Copy Markdown
Member Author

Pushed up a new rebased version of https://github.com/Roasbeef/lnd/pull/new/combined-wire-tlv

@cfromknecht cfromknecht modified the milestones: 0.11.0, 0.12.0 Jun 27, 2020
In order to prep for allowing TLV extensions for the `ReplyChannelRange`
and `QueryChannelRange` messages, we'll need to remove the struct
embedding as is. If we don't remove this, then we'll attempt to decode
TLV extensions from both the embedded and outer struct.

All relevant call sites have been updated to reflect this minor change.
In this commit, we convert the delivery address in the open and accept
channel methods to be a TLV type. This works as an "empty" delivery
address is encoded using a two zero bytes (uint16 length zero), and a
tlv type of 0 is encoded in the same manner (byte for type, byte for
zero length). This change allows us to easily extend these messages in
the future, in a uniform manner.
In this commit, we update a series of unit tests in the code base to now
pass due to the new wire message encode/decode logic. In many instances,
we'll now manually set the extra bytes to an empty byte slice to avoid
comparisons that fail due to one message having an empty byte slice and
the other having a nil pointer.
…rsion for TLV

In this commit, we update all the existing methods for encoding and
decoding in the package to also observe the currently unused `pver`
(protocol version) argument. With this change, we can enforce the new
"TLV everywhere" rules for all the new code, while leaving the existing
migrations untouched (using the legacy version). Otherwise, a legacy
migration would possibly read too many bytes (as the ExtraOpaqueBytes
reads until EOF), causing it to corrupt existing data on disk.

The Encode/Decode methods of the ExtraOpaqueData struct will now observe
the new `pver` value, and return early (not reading/writing) the extra
bytes based on this value.
In this commit, update the encode/decode code concerning wire messages
in the existing migrations to force them to specify that they want the
legacy protocol version which doesn't attempt to read the extra bytes
for all messages other than gossip messages.
@Roasbeef
Copy link
Copy Markdown
Member Author

Roasbeef commented Nov 5, 2020

This PR is going away now (in favor of the combined version), but I pushed up a rebased version for posterity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvements to existing features / behaviour P2 should be fixed if one has time spec v0.12 wire protocol Encoding of messages for the communication between nodes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants