Skip to content

Conversation

ellemouton
Copy link
Collaborator

This PR does the following main things:

  • adds the missing outpoint field to the ChannelAnnouncement2 message.
  • Defines the NodeAnnouncement2 message which will be used to represent the new node_announcement_1 message.

This is part of the gossip 1.75 project. None of these types are used in the projection code yet.

@ellemouton ellemouton self-assigned this Sep 22, 2025
Copy link

Summary of Changes

Hello @ellemouton, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request lays foundational work for the Gossip 1.75 protocol by updating existing message definitions and introducing new ones. It primarily focuses on enhancing the ChannelAnnouncement2 with an outpoint field and creating a new NodeAnnouncement2 message, which leverages TLV for its fields. These changes ensure compatibility with future gossip protocol versions, although the new types are not yet actively used in the projection code.

Highlights

  • Gossip 1.75 Message Updates: The pull request introduces new message structures and fields to support the upcoming Gossip 1.75 specification. This includes adding a missing 'outpoint' field to the ChannelAnnouncement2 message and defining a new NodeAnnouncement2 message.
  • NodeAnnouncement Versioning: The existing NodeAnnouncement message has been renamed to NodeAnnouncement1 to differentiate it from the newly introduced NodeAnnouncement2. This change is reflected across various components that handle node announcements.
  • TLV Encoding for DNS Addresses and Outpoints: New TLV encoding/decoding logic has been added for DNSAddress and OutPoint types, allowing them to be seamlessly integrated into TLV-based messages like NodeAnnouncement2 and ChannelAnnouncement2.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot 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

This PR updates the gossip protocol to version 1.75. The changes include renaming NodeAnnouncement to NodeAnnouncement1, adding an outpoint field to ChannelAnnouncement2, and defining the new NodeAnnouncement2 message. The implementation looks solid and includes relevant test updates.

I've found a few minor issues:

  • An incorrect static size for the OutPoint TLV record.
  • A typo in an error message in the Tor address encoder for NodeAnnouncement2.
  • Several new unexported functions are missing comments, which is required by the style guide. I've pointed out a few examples.

Overall, great work on moving the gossip implementation forward.

@ellemouton ellemouton force-pushed the g175MessageFollowup branch 2 times, most recently from 3d6fdbd to fc770dd Compare September 23, 2025 14:18
@saubyk saubyk added this to v0.21 Sep 24, 2025
@saubyk saubyk moved this to In review in v0.21 Sep 24, 2025
Copy link
Member

@yyforyongyu yyforyongyu left a comment

Choose a reason for hiding this comment

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

Pretty close - left a few comments about some improvements we can make.

}

// allNonSignatureRecordProducers returns all the TLV record producers for the
// nonSignatureRecordProducers returns all the TLV record producers for the
Copy link
Member

Choose a reason for hiding this comment

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

🌷

}

// outpointEncoder is a TLV encoder for OutPoint.
func outpointEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
Copy link
Member

Choose a reason for hiding this comment

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

nit: can use val any, same below

// InboundFee is an optional TLV record that contains the fee
// information for incoming HTLCs.
// TODO(elle): assign normal tlv type?
InboundFee tlv.OptionalRecordT[tlv.TlvType55555, Fee]
Copy link
Member

Choose a reason for hiding this comment

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

I think we can just use FeeRecordType.

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 just defines an int. we still need the tlv type here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

(same was done in ChannelUpdate1)


// Write the port as 2 bytes.
var portBytes [2]byte
err := WriteUint16(bytes.NewBuffer(portBytes[:0]), v.Port)
Copy link
Member

Choose a reason for hiding this comment

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

hmm why portBytes[:0] but not portBytes[:]

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Totally agree that it's hard to read - so have updated with simplified version 👍

But out of interest:

portBytes[:0] creates a slice with zero length but the same underlying capacity as portBytes. This is used to reset the buffer position for bytes.NewBuffer() to start writing at the beginning of
the array.

If you used portBytes[:], it would create a slice with the full length (2 bytes) containing whatever data was previously in the array, which would interfere with the WriteUint16 function.

The [:0] slice gives bytes.NewBuffer an empty slice to start with, ensuring clean writes to the array.

}

// dnsAddressEncoder is a TLV encoder for DNSAddress.
func dnsAddressEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
Copy link
Member

Choose a reason for hiding this comment

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

nit: can use any

torV3 = tlv.ZeroRecordT[tlv.TlvType9, TorV3Addrs]()
dns = tlv.ZeroRecordT[tlv.TlvType11, DNSAddress]()
)
stream, err := tlv.NewStream(ProduceRecordsSorted(
Copy link
Member

Choose a reason for hiding this comment

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

nit: newline above

func rgbEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
if v, ok := val.(*Color); ok {
buf := bytes.NewBuffer(nil)
err := WriteColorRGBA(buf, color.RGBA(*v))
Copy link
Member

Choose a reason for hiding this comment

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

I think we can just pass w here? why creating the buf?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

WriteColorRGBA takes a buffer pointer

return err
}
onionService := tor.Base32Encoding.EncodeToString(ip[:])
onionService += tor.OnionSuffix
Copy link
Member

Choose a reason for hiding this comment

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

similar to how if len(host) != tor.V3DecodedLen above we should also validate len(onionService)

@yyforyongyu yyforyongyu added this to the v0.21.0 milestone Sep 25, 2025
Copy link
Collaborator Author

@ellemouton ellemouton left a comment

Choose a reason for hiding this comment

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

thanks @yyforyongyu 🙏

// InboundFee is an optional TLV record that contains the fee
// information for incoming HTLCs.
// TODO(elle): assign normal tlv type?
InboundFee tlv.OptionalRecordT[tlv.TlvType55555, Fee]
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 just defines an int. we still need the tlv type here

// InboundFee is an optional TLV record that contains the fee
// information for incoming HTLCs.
// TODO(elle): assign normal tlv type?
InboundFee tlv.OptionalRecordT[tlv.TlvType55555, Fee]
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

(same was done in ChannelUpdate1)


// Write the port as 2 bytes.
var portBytes [2]byte
err := WriteUint16(bytes.NewBuffer(portBytes[:0]), v.Port)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Totally agree that it's hard to read - so have updated with simplified version 👍

But out of interest:

portBytes[:0] creates a slice with zero length but the same underlying capacity as portBytes. This is used to reset the buffer position for bytes.NewBuffer() to start writing at the beginning of
the array.

If you used portBytes[:], it would create a slice with the full length (2 bytes) containing whatever data was previously in the array, which would interfere with the WriteUint16 function.

The [:0] slice gives bytes.NewBuffer an empty slice to start with, ensuring clean writes to the array.

func rgbEncoder(w io.Writer, val interface{}, _ *[8]byte) error {
if v, ok := val.(*Color); ok {
buf := bytes.NewBuffer(nil)
err := WriteColorRGBA(buf, color.RGBA(*v))
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

WriteColorRGBA takes a buffer pointer

Add a new OutPoint type that wraps wire.OutPoint and provides TLV
encoding/decoding capabilities through the tlv.RecordProducer interface.
This enables OutPoint to be used in TLV streams of messages.
The latest version of the spec has the outpoint included in the
`channel_announcement2` message.
In preparation for adding a NodeAnnouncement2 struct along with a
NodeAnnouncement interface, this commit renames the existing
NodeAnnouncment struct to NodeAnnouncement1.
We leave a TODO that should be addressed after a discussion at the spec
meeting. For now, having the incorrect TLV type is not a problem since
this ChannelUpdate2 type is not used in production.
In preparation for using this type as a TLV record, we let it implement
the RecordProducer interface.
In this commit, the lnwire.NodeAnnouncement2 type is defined. This will
be used to represent the `node_announcement_2` message used in the
Gossip 2 (1.75) protocol.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: In review
Development

Successfully merging this pull request may close these issues.

2 participants