-
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
Implement the P2P discovery mechanism #51 #72
Implement the P2P discovery mechanism #51 #72
Conversation
6646b92
to
9dc9fa5
Compare
9dc9fa5
to
1b9591b
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.
Excellent work!
I really like the direction you've laid out in the discovery
package. The abstractions are quite general and should be easy to extend and add more concrete implementations in the future. I'll also be purposing much of this code as I start to implement the framing and routing portions of BOLT0007
.
However, most of my comments are centered around my sentiment that atm they're a bit too general. I think they can be reduced in scope a bit to be made more specific so we can regain access to the stronger compile time guarantees provided.
discover/messages.go
Outdated
Validate() error | ||
} | ||
|
||
var _ Validatable = (*NodeAnnouncement)(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.
Minor nit: can you place a comment here describing the rationale for these lines (compile time interface adherence assertion).
discover/messages.go
Outdated
"github.com/roasbeef/btcutil" | ||
) | ||
|
||
type Validatable interface { |
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.
Missing a godoc comment here.
discover/messages.go
Outdated
SecondNodeSig []byte | ||
} | ||
|
||
func (a *ChannelAnnouncement) Validate() error { |
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.
Missing a godoc comment here.
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 function should also be amended to calculate the two digests as dictated in BOLT0007
, with the signature verification (4 signatures total) modified accordingly to verify against the two digests.
discover/service.go
Outdated
// discovery service was stopped with error. | ||
func (s *DiscoveryService) Wait() chan error { | ||
wait := make(chan error) | ||
go func() { |
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 think this goroutine is unnecessary, and the Wait
method on the WaitGroup
can instead be called directly. As a result, the return value wouldn't be necessary.
discover/service.go
Outdated
} | ||
|
||
s.err = err | ||
s.quit <- true |
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 order to be consistent with the rest of the codebase, then channel should be closed rather than sent upon.
discover/transport.go
Outdated
} | ||
|
||
func (t *IRCTransport) onDisconnected(conn *client.Conn, line *client.Line) { | ||
t.quit <- true |
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.
Channel should be closed instead to be conformant with the rest of the codebase.
discover/utils.go
Outdated
// createHandlerFunc takes the interface as input and checks that interface is | ||
// corresponding to the handler function with specific schema, if schema is | ||
// wrong or input isn't a function it panics. | ||
func createHandlerFunc(f interface{}) (string, Handler) { |
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 my opinion, this package currently over-uses reflection. Instead, (as I mentioned above) I think a more concrete interface should be used, with further type assertions to obtain concrete types usable depending on the transport.
glide.yaml
Outdated
@@ -56,3 +56,7 @@ import: | |||
version: ^1.1.0 | |||
- package: github.com/aead/chacha20 | |||
- package: github.com/go-errors/errors | |||
- package: github.com/fluffle/goirc | |||
- package: github.com/golang/mock |
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 is the mock package necessary? I don't see it used anywhere in this PR.
routing/manager.go
Outdated
@@ -182,6 +200,8 @@ type RoutingManager struct { | |||
ChDone chan struct{} | |||
} | |||
|
|||
var _ ChannelRouter = (*RoutingManager)(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.
Can you please add a rationale comment here (the one I mentioned above a few times)? Thanks!
server.go
Outdated
@@ -490,6 +521,21 @@ func (s *server) Peers() []*peer { | |||
return <-resp | |||
} | |||
|
|||
// Channels returns a slice of all channels. | |||
func (s *server) Channels() ([]*channeldb.OpenChannel, error) { | |||
respChan := make(chan []*channeldb.OpenChannel) |
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 access to the database is already serialized, channeldb.FetchAllChannels()
can be accessed directly.
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 above comment should be included in the change request ;)
1b9591b
to
3c94ea4
Compare
72764b7
to
29276a6
Compare
As we discussed earlier we moved from Open issues:
|
discover/service.go
Outdated
// | ||
// NOTE: This MUST be run as a goroutine. | ||
func (s *DiscoveryService) announce() { | ||
s.wg.Add(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.
The WaitGroup
should be incremented before the goroutine is launched. So, within the Start
method right before the announce
goroutine is launched.
discover/utils.go
Outdated
) | ||
|
||
func getRandomDelay(maxDelay int) time.Duration { | ||
return time.Second * time.Duration(rand.Intn(maxDelay)) |
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 prng is currently being used without seeding the source first. Somewhere in this package we need to add an init
function that seeds the prng
. So it would look something like:
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
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.
Nice catch! 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.
LGTM!
Once the final two comments are addressed, and the PR is rebased to master, I'll merge this PR.
glide.lock
Outdated
@@ -53,6 +53,8 @@ imports: | |||
- spew | |||
- name: github.com/go-errors/errors | |||
version: a41850380601eeb43f4350f7d17c6bbd8944aaf8 | |||
- name: github.com/go-errors/errors |
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 line is a duplication of the one above above ^
2828e1a
to
8e01d93
Compare
d86107c
to
a34df2f
Compare
33916f4
to
4c015a7
Compare
Coverage increased (+0.2%) to 67.908% when pulling 4c015a79db200b3938b41d5e65dfeb2bcba973eb on AndrewSamokhvalov:add_irc_discovery into 5d43483 on lightningnetwork:master. |
Coverage increased (+0.2%) to 67.908% when pulling 4c015a79db200b3938b41d5e65dfeb2bcba973eb on AndrewSamokhvalov:add_irc_discovery into 5d43483 on lightningnetwork:master. |
Coverage increased (+0.2%) to 67.908% when pulling 4c015a79db200b3938b41d5e65dfeb2bcba973eb on AndrewSamokhvalov:add_irc_discovery into 5d43483 on lightningnetwork:master. |
@@ -1387,16 +1387,24 @@ func putChanEdgeInfo(edgeIndex *bolt.Bucket, edgeInfo *ChannelEdgeInfo, chanID [ | |||
} | |||
|
|||
authProof := edgeInfo.AuthProof | |||
if err := wire.WriteVarBytes(&b, 0, authProof.NodeSig1.Serialize()); err != nil { | |||
var nodeSig1, nodeSig2, bitcoinSig1, bitcoinSig2 []byte | |||
if authProof != 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.
Hmm, I don't think this change is needed or really adds much. The signatures must be present within a ChannelEdgeInfo
struct. Otherwise, we won't be able to properly serve them to 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.
As we discussed offline the signatures/proof might be equal to nil in the case if we don't want to announce the channel.
@@ -1470,7 +1478,10 @@ func deserializeChanEdgeInfo(r io.Reader) (*ChannelEdgeInfo, error) { | |||
return nil, err | |||
} | |||
|
|||
return btcec.ParseSignature(sigBytes, btcec.S256()) | |||
if len(sigBytes) != 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.
If the signature isn't present, then an error should occur rather than silently ignore the lack of signature data.
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 far as I understand after discussion the nil
signature does not designate something broken.
discover/log.go
Outdated
@@ -0,0 +1,72 @@ | |||
package discover |
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: the package name should be discovery
rather than discover
.
discover/service.go
Outdated
} | ||
|
||
// Discovery is a subsystem which is responsible for: | ||
// * receiving announcements validate them and apply the changes to router. |
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.
These bullet points below should be formatted into a series of compete sentences.
discover/service.go
Outdated
|
||
// ProcessRemoteAnnouncement sends a new remote announcement message along with | ||
// the peer that sent the routing message. The announcement will be processed then | ||
// added to a queue for batched tickled announcement to all connected peers. |
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.
tickled -> trickled
routing/router.go
Outdated
return false | ||
if edge2Timestamp.After(msg.LastUpdate) || | ||
edge2Timestamp.Equal(msg.LastUpdate) { | ||
return errors.Errorf("ignoring announcement "+ |
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: a new-line should be inserted here.
chanID, err) | ||
return false | ||
return errors.Errorf("unable to fetch utxo for "+ | ||
"chan_id=%v: %v", msg.ChannelID, 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.
With the discovery
package handling full validation, this fragment can be removed all together as the ChannelRouter
should only receive fully valid data.
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 this comment should be addressed by the comment above.
routing/router.go
Outdated
log.Errorf("unable to sync edges w/ peer: %v", err) | ||
return err | ||
default: | ||
return errors.Errorf("wrong routing msg message type") |
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.
There's an extra space before routing
here.
routing/router.go
Outdated
FeeProportionalMillionths: uint32(e2.FeeProportionalMillionths), | ||
}) | ||
} | ||
log.Infof("New channel msg applied: %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.
The log message was altered, it should be New channel update applied
.
routing/router.go
Outdated
|
||
// ForEachSelfEdgePolicy is used to iterate over all self channels info. | ||
// NOTE: Part of the Router interface. | ||
func (r *ChannelRouter) ForEachSelfEdgePolicy(cb func(c *channeldb.ChannelEdgePolicy) error) error { |
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.
Naming suggestion: ForAllOutgoingChannels
.
140f0f8
to
8b753c4
Compare
Coverage increased (+0.4%) to 69.428% when pulling 8b753c4e966401448aa12f461c395080932dda19 on AndrewSamokhvalov:add_irc_discovery into 505421d on lightningnetwork:master. |
Coverage increased (+0.4%) to 69.408% when pulling 8b753c4e966401448aa12f461c395080932dda19 on AndrewSamokhvalov:add_irc_discovery into 505421d on lightningnetwork:master. |
Coverage decreased (-0.2%) to 68.81% when pulling 4bf3ee6e290653ce4b54b422cf38c3a594493a90 on AndrewSamokhvalov:add_irc_discovery into c9c2848 on lightningnetwork:master. |
4bf3ee6
to
70f325e
Compare
Coverage decreased (-0.1%) to 68.875% when pulling 70f325eb22d747fadfcf7f907b98312fb70cf084 on AndrewSamokhvalov:add_irc_discovery into c9c2848 on lightningnetwork:master. |
Coverage decreased (-0.1%) to 68.875% when pulling 70f325eb22d747fadfcf7f907b98312fb70cf084 on AndrewSamokhvalov:add_irc_discovery into c9c2848 on lightningnetwork:master. |
1 similar comment
Coverage decreased (-0.1%) to 68.875% when pulling 70f325eb22d747fadfcf7f907b98312fb70cf084 on AndrewSamokhvalov:add_irc_discovery into c9c2848 on lightningnetwork:master. |
Coverage decreased (-0.1%) to 68.875% when pulling 70f325eb22d747fadfcf7f907b98312fb70cf084 on AndrewSamokhvalov:add_irc_discovery into c9c2848 on lightningnetwork:master. |
ed97ce4
to
57abb2a
Compare
In this commit the routing package was divided on two separete one, this was done because 'routing' package start take too much responsibily on themself, so with following commit: Routing pacakge: Enitites: * channeldb.ChannelEdge * channeldb.ChannelPolicy * channeldb.NodeLightning Responsibilities: * send topology notification * find payment paths * send payment * apply topology changes to the graph * prune graph * validate that funding point exist and corresponds to given one * to be the source of topology data Discovery package: Entities: * lnwire.AnnounceSignature * lnwire.ChannelAnnouncement * lnwire.NodeAnnouncement * lnwire.ChannelUpdateAnnouncement Responsibilities: * validate announcement signatures * sync topology with newly connected peers * handle the premature annoucement * redirect topology changes to the router susbsystem * broadcast announcement to the rest of the network * exchange channel announcement proofs Before that moment all that was in the 'routing' which is quite big for one subsystem. split
Add usage of the 'discovery' package in the lnd, now discovery service will be handle all lnwire announcement messages and send them to the remote party.
Validation of the announcements message has been removed and it will be added in the discovery package latter.
In this commit announcement signature message has been added which is needed when peers want to announce their channel to the rest of the network. This message acts as half proof carrier, nodes exchanges their half proofs with each other and after that they are able to construct the full proof.
Change the name of fields of messages which are belong to the discovery subsystem in a such way so they were the same with the names that are defined in the specification.
In case if the channel shouldn't be announced to the rest of the network the proof, which is needed to announce the channel, will not be populated, fot that reason the ability to store the empty proof has been added.
In order to properly announce the channel the announcements proofs should be persistent in boltdb.
Add check that the edge that was received really exist in the blockchain and that the announced funding keys and capcity corresponds to reality.
Originally we adding the edge without proof in order to able to use it for payments path constrcution. This method will allow us to populate the announcement proof after the exchange of the half proofs and constrcutrion of full proof finished.
Add the interaction between nodes of announce signature messages, which will allow us to exhcnage the half channel announcemen proofs later.
Added the signer which will be needed in the funding manager to sign the lnwaire announcement message before sending them to discovery package. Also in the future the message signer will be used to sign the users data.
Add validation functions and include validation checks in the annoncement process function.
57abb2a
to
11ef161
Compare
1 similar 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.
I've done some extensive testing locally and found that everything works as advertised. This PR really plugs up a major whole in our current implementation of the gossip protocol: actual validation!
With this we can also safely perform a "hard" reset on our current lnd
testnet channel graph as all channels created prior to this commit will be rejected whole sale by upgraded nodes.
Thanks for bearing with my over this long review process! By merging this we knock out the oldest outstanding PR currently which is a nice bonus.
LGTM ⚡️
In this
PR
as a stop-gap I have implemented theIRC
discovery mechanism. The implementation include addition of standalonediscover
package. I tried to keep theIRC
specific implementation as much decoupled from discovery service as possible, for that reason follow structures and interfaces was created:Transport
: interface is used to create an abstraction layer over system-dependable representation of discovery service messages (IRC). It gives the ability to discovery service operate only with final representation of messages likeChanAnnouncement
,NodeAnnouncement
thereby decouple this systems and give them ability to be easily testable.IRCTransport
: is an implementation of discovery message transport which usesIRC
bot andIRC
channels as carrier of announcement data. This structure keeps allIRC
specific stuff in it.DiscoveryService
: is a service which serves as control layer over data transport. It operates with announce messages rather than transport dependable, raw data.Questions:
BlockchainIO
interface 😄)