-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
lnwire: Update NodeAnnouncement address advertisement to match spec #154
Conversation
46d474b
to
4ae62c9
Compare
@@ -1142,7 +1142,7 @@ func (c *ChannelGraph) NewChannelEdge() *ChannelEdge { | |||
|
|||
func putLightningNode(nodeBucket *bolt.Bucket, aliasBucket *bolt.Bucket, node *LightningNode) error { | |||
var ( | |||
scratch [8]byte | |||
scratch [16]byte |
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.
Why it was changed to 16
?
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.
@AndrewSamokhvalov thanks for the review and the comments! Good catch here. I made a change that required the additional bytes, and then backed that out and left this in. Fixed now.
channeldb/graph.go
Outdated
@@ -1199,27 +1209,45 @@ func fetchLightningNode(nodeBucket *bolt.Bucket, | |||
func deserializeLightningNode(r io.Reader) (*LightningNode, error) { | |||
node := &LightningNode{} | |||
|
|||
var scratch [8]byte | |||
if _, err := r.Read(scratch[:]); err != nil { | |||
var scratch [16]byte |
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.
the same
lnwire/node_announcement.go
Outdated
|
||
// 158 | ||
return length | ||
// Base size, 147, but can be variable due to multiple addresses |
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.
Maybe it is not so important as far as it will change in near future , but it seems for me that base size should be 140
because length of addresses might be equal to 0
according to spec.
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.
Changed.
lnwire/node_announcement_test.go
Outdated
t.Fatalf("payload length estimate is incorrect: expected %v "+ | ||
"got %v", serializedLength, na.MaxPayloadLength(0)) | ||
} | ||
} |
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.
Maybe rather than removing it, we consider check the exact length of message instead?
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.
Re-added. I saw that a few of the other variable length messages had the payload length test taken out, but I think it makes sense to have it.
server.go
Outdated
Permanent: true, | ||
} | ||
s.persistentConnReqs[pubStr] = connReq | ||
go s.connMgr.Connect(connReq) |
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 believe we should think more about this logic:
- We are rewriting the connection request on every iteration now:(
s.persistentConnReqs[pubStr] = connReq
). - I am not sure but it seems for me that such approach might lead to duplicate creation of peers. Maybe we should add additional check in
addPeer
method (server.go:559-560
)?
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.
Added a slice of connReqs to address issue #1. For #2, I believe @Roasbeef was going to add something in the connection manager to ensure that when a connection is established, the other connection attempts are cancelled. I believe this should prevent the [inbound|outbound]peerConnected from being called more than once, ensuring that duplicate peers won't be created.
83e2821
to
a874ce9
Compare
LGTM! 👍 |
channeldb/graph.go
Outdated
return err | ||
} | ||
|
||
for _, address := range node.Addresses { | ||
if err := wire.WriteVarString(&b, 0, address.Network()); err != nil { |
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.
iirc whether an address is IPv4 or IPv6 it'll always return a "tcp" if it's a net.TCPAddr
. Therefore, instead I think we can just rely on the String
method of the net.Addr
itself here. It would also be a bit more compact (as we can leave out the network).
channeldb/graph.go
Outdated
address, err := net.ResolveTCPAddr(network, addr) | ||
if err != nil { | ||
return nil, err | ||
} |
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 light of my comment above, I think we should instead add a single byte prefix before the encoded address so we know how to properly decode it.
Also the address resolution above wouldn't work with say, .onion
addresses.
lnwire/lnwire.go
Outdated
if _, err := w.Write(ip[:]); err != nil { | ||
return err | ||
} | ||
switch net := e.Network(); net { |
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 won't work as expected for IPv6 addresses as they'll still always return "tcp" from the Network()
method.
I think instead, we might be able to use the To4 method on the IP
struct to discern if an address if IPv6 or not. The method will return nil
if the address an IPv6 address.
lnwire/lnwire_test.go
Outdated
@@ -56,7 +56,10 @@ var ( | |||
someSig, _ = btcec.ParseSignature(sigStr, btcec.S256()) | |||
someSigBytes = someSig.Serialize() | |||
|
|||
someAddress = &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 8333} | |||
//TODO(bvu): one of the following addresses should be an IPv6 address. |
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 TODO should be addressed before we merge this PR.
routing/pathfind_test.go
Outdated
@@ -109,10 +109,12 @@ func parseTestGraph(path string) (*channeldb.ChannelGraph, func(), aliasMap, err | |||
// We'll use this fake address for the IP address of all the nodes in | |||
// our tests. This value isn't needed for path finding so it doesn't | |||
// need to be unique. | |||
testAddrs := make([]net.Addr, 0) |
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.
Style nit, this can instead be declared as:
var testAddrs []net.Addr
server.go
Outdated
connReq := &connmgr.ConnReq{ | ||
Addr: lnAddr, | ||
Permanent: true, | ||
// In case a node has multiple addresses, attempt to connect to |
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.
A new line should be inserted above this comment.
server.go
Outdated
} | ||
delete(s.persistentConnReqs, pubStr) |
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.
The deletion should be moved into the if ... ok
clause.
server.go
Outdated
// ongoing connection attempts to ensure that we don't end up with a | ||
// duplicate connecting to the same peer. | ||
s.pendingConnMtx.RLock() | ||
delete(s.persistentConnReqs, pubStr) |
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.
Upon further consideration, I don't think deleting items from the persistentConnReqs
map is required after all. Honestly, I think the management of the peer connection state needs a bit of a re-write...
be4f621
to
3e95cd9
Compare
Updated. Previous version can be found at: https://github.com/bryanvu/lnd/tree/nodeannounce-1. Not sure the way I did the constants for TCP/ONION is idiomatic in Go, suggestions welcome. |
channeldb/graph.go
Outdated
@@ -111,6 +111,12 @@ type ChannelGraph struct { | |||
// * LRU cache for edges? | |||
} | |||
|
|||
// TODO(bvu): add comments |
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 can add a bit more typing to this definition with something along the lines of:
type addressType uint8
const (
tcp4Addr addressType = 0
tcp6Addr addressType = 1
onionAddr addressType = 2
)
channeldb/graph.go
Outdated
for _, address := range node.Addresses { | ||
if address.Network() == "tcp" { | ||
scratch[0] = byte(TCP) | ||
if _, err := b.Write(scratch[0:0]); err != nil { |
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.
scratch[0:0]
can safely be replaced with scratch[0]
channeldb/graph.go
Outdated
var address net.Addr | ||
switch addrType { | ||
case TCP: | ||
address, err = net.ResolveTCPAddr("tcp", addr) |
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.
As is now, this'll force an outbound name resolution for each address on db read which should be able to be avoided.
We can avoid this by writing the raw byte representation of a TCPAddr
rather than using the supplied .String()
method. So this would entail writing the raw bytes of the IP
, Zone
and Port
fields.
lnd_test.go
Outdated
for _, node := range chanGraph.Nodes { | ||
if node.PubKey == dave.PubKeyStr { | ||
if len(node.Addresses) != 3 { | ||
t.Fatalf("expecting dave to have two addresses, got: %v", |
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 the the error message wasn't updated when the additional addresses were added (reads "two", should be "three").
} | ||
|
||
chanAmt := btcutil.Amount(btcutil.SatoshiPerBitcoin / 2) | ||
chanPointAlice := openChannelAndAssert(ctxt, t, net, net.Alice, dave, |
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 don't think opening a new channel is necessary for this test as it only deals with the proper propagation of a node announcement within the network.
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.
Since I was using DescribeGraph to check the contents of the NodeAnnouncement, I had to open a channel here, I believe.
copy(ip[:], e.IP.To16()) | ||
if _, err := w.Write(ip[:]); err != nil { | ||
return err | ||
} |
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.
Hmm just realized the spec currently leaves out the concept of IPv6
zones...
ad66bb2
to
cae47da
Compare
Coverage decreased (-0.4%) to 67.35% when pulling cae47da908e64e398f1399c5bd7b70b6084719b3 on bryanvu:nodeannounce into 5d43483 on lightningnetwork:master. |
1 similar comment
Coverage decreased (-0.4%) to 67.35% when pulling cae47da908e64e398f1399c5bd7b70b6084719b3 on bryanvu:nodeannounce into 5d43483 on lightningnetwork:master. |
Updated with requested changes. Previous version can be found at: https://github.com/bryanvu/lnd/tree/nodeannounce-2. |
Coverage decreased (-0.4%) to 67.35% when pulling 9c9add9a8e6c9331e28c5f01d0914e6eed6d3e0c on bryanvu:nodeannounce into 5d43483 on lightningnetwork:master. |
Coverage decreased (-0.3%) to 67.46% when pulling 8162a669e660173369a498b353b0d374dff75b33 on bryanvu:nodeannounce into 5d43483 on lightningnetwork:master. |
channeldb/graph.go
Outdated
@@ -819,6 +830,8 @@ type LightningNode struct { | |||
// | |||
// TODO(roasbeef): hook into serialization once full verification is in | |||
AuthSig *btcec.Signature | |||
// Features is the list of protocol features supported by this node. |
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.
Minor nit: missing a newline above this variable definition.
channeldb/graph.go
Outdated
for _, address := range node.Addresses { | ||
if address.Network() == "tcp" { | ||
if address.(*net.TCPAddr).IP.To4() != nil { | ||
scratch[0] = 0 |
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.
To improve the readability, I think the enum defined above should be used directly here:
scratch[0] = tcp4Addr
channeldb/graph.go
Outdated
return err | ||
} | ||
} else { | ||
scratch[0] = 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.
Similar comment here about using the enum directly.
channeldb/graph.go
Outdated
return err | ||
} | ||
|
||
copy(scratch[:4], address.(*net.TCPAddr).IP.To4()) |
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.
From my reading, this looks like it'll override the address type which is the first element in the slice. To fix this, the bounds on this write should instead be:
scratch[1:5]
channeldb/graph.go
Outdated
if _, err := b.Write(scratch[:1]); err != nil { | ||
return err | ||
} | ||
copy(scratch[:], address.(*net.TCPAddr).IP.To16()) |
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.
Similar comment here about the copy overriding the addrType
set as the first variable.
lnd_test.go
Outdated
|
||
for _, node := range chanGraph.Nodes { | ||
if node.PubKey == dave.PubKeyStr { | ||
if len(node.Addresses) != 3 { |
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.
For the sake of additional coverage, I think this test should also be expanded to assert the exact existence of the three addresses listed above.
lnwire/node_announcement.go
Outdated
Addresses []net.Addr | ||
|
||
// pad is used to reserve to additional bytes for future usage. | ||
pad uint16 |
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.
Why was this padding added? It isn't a part of the struct.
You can also remove the TODO(roasbeef)
above.
if connReq, ok := s.persistentConnReqs[pubStr]; ok { | ||
s.connMgr.Remove(connReq.ID()) | ||
if connReqs, ok := s.persistentConnReqs[pubStr]; ok { | ||
for _, connReq := range connReqs { |
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.
A similar code block (removing all the connection requests for the particular node pubkey) needs to be inserted below within the outboundPeerConnected
method. We'll need to similarly cancel all the pending outbound requests (launched within newServer
) as we've successfully established a connection.
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 totally sure how this works, but when I added this to outboundPeerConnected, the nodes didn't reconnect upon startup. Is there something else I have to do to make that happen?
lnwire/lnwire.go
Outdated
} | ||
if e.IP.To4() != nil { | ||
var descriptor [1]byte | ||
descriptor[0] = 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.
Can you lift the 1
and 2
values, into an addrType
enum similar to what was done in the channeldb
package? Thanks!
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.
Meant to request changes rather than approve...
8651277
to
57ec79a
Compare
This commit modifies address handling in the NodeAnnouncement struct, switching from net.TCPAddr to []net.Addr. This enables more flexible address handling with multiple types and multiple addresses for each node. This commit addresses the first part of issue lightningnetwork#131 .
Minor change to server.go to add ExternalIPs to channeldb.LightningNode. Also, added a test that utilizes this functionality and exercises multiple addresses in NodeAnnouncement.
Add support for Features in NodeAnnouncment according to spec.
Use addresses and ports from NodeAnnouncement messages for reconnection attempts. For those nodes that don't explicitly report IP addresses, use the IP address from previous connections connection request along with the default peer port 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.
Alright, I've run some final tests locally and everything seems to be in order. This directly and indirectly addresses a number of lingering issues and opens the door to allow us to do things like experiment with automated channel creation with a fixed pool of funds for a node.
LGTM 🏂
This PR should address issues #131, #135, and #141.