From 1c81a8fad6fa91b3ca2e47d94fc4e4cd4396cdee Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Fri, 30 Nov 2018 15:33:27 -0800 Subject: [PATCH 1/4] discovery/chan_series: copy chan_series to discovery --- discovery/chan_series.go | 369 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 discovery/chan_series.go diff --git a/discovery/chan_series.go b/discovery/chan_series.go new file mode 100644 index 00000000..25ecbed4 --- /dev/null +++ b/discovery/chan_series.go @@ -0,0 +1,369 @@ +package discovery + +import ( + "time" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/routing" +) + +// ChannelGraphTimeSeries is an interface that provides time and block based +// querying into our view of the channel graph. New channels will have +// monotonically increasing block heights, and new channel updates will have +// increasing timestamps. Once we connect to a peer, we'll use the methods in +// this interface to determine if we're already in sync, or need to request +// some new information from them. +type ChannelGraphTimeSeries interface { + // HighestChanID should return the channel ID of the channel we know of + // that's furthest in the target chain. This channel will have a block + // height that's close to the current tip of the main chain as we + // know it. We'll use this to start our QueryChannelRange dance with + // the remote node. + HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID, error) + + // UpdatesInHorizon returns all known channel and node updates with an + // update timestamp between the start time and end time. We'll use this + // to catch up a remote node to the set of channel updates that they + // may have missed out on within the target chain. + UpdatesInHorizon(chain chainhash.Hash, + startTime time.Time, endTime time.Time) ([]lnwire.Message, error) + + // FilterKnownChanIDs takes a target chain, and a set of channel ID's, + // and returns a filtered set of chan ID's. This filtered set of chan + // ID's represents the ID's that we don't know of which were in the + // passed superSet. + FilterKnownChanIDs(chain chainhash.Hash, + superSet []lnwire.ShortChannelID) ([]lnwire.ShortChannelID, error) + + // FilterChannelRange returns the set of channels that we created + // between the start height and the end height. We'll use this to to a + // remote peer's QueryChannelRange message. + FilterChannelRange(chain chainhash.Hash, + startHeight, endHeight uint32) ([]lnwire.ShortChannelID, error) + + // FetchChanAnns returns a full set of channel announcements as well as + // their updates that match the set of specified short channel ID's. + // We'll use this to reply to a QueryShortChanIDs message sent by a + // remote peer. The response will contain a unique set of + // ChannelAnnouncements, the latest ChannelUpdate for each of the + // announcements, and a unique set of NodeAnnouncements. + FetchChanAnns(chain chainhash.Hash, + shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error) + + // FetchChanUpdates returns the latest channel update messages for the + // specified short channel ID. If no channel updates are known for the + // channel, then an empty slice will be returned. + FetchChanUpdates(chain chainhash.Hash, + shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error) +} + +// ChanSeries is an implementation of the ChannelGraphTimeSeries +// interface backed by the channeldb ChannelGraph database. We'll provide this +// implementation to the AuthenticatedGossiper so it can properly use the +// in-protocol channel range queries to quickly and efficiently synchronize our +// channel state with all peers. +type ChanSeries struct { + graph *channeldb.ChannelGraph +} + +// NewChanSeries constructs a new ChanSeries backed by a channeldb.ChannelGraph. +// The returned ChanSeries implements the ChannelGraphTimeSeries interface. +func NewChanSeries(graph *channeldb.ChannelGraph) *ChanSeries { + return &ChanSeries{ + graph: graph, + } +} + +// HighestChanID should return is the channel ID of the channel we know of +// that's furthest in the target chain. This channel will have a block height +// that's close to the current tip of the main chain as we know it. We'll use +// this to start our QueryChannelRange dance with the remote node. +// +// NOTE: This is part of the ChannelGraphTimeSeries interface. +func (c *ChanSeries) HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID, error) { + chanID, err := c.graph.HighestChanID() + if err != nil { + return nil, err + } + + shortChanID := lnwire.NewShortChanIDFromInt(chanID) + return &shortChanID, nil +} + +// UpdatesInHorizon returns all known channel and node updates with an update +// timestamp between the start time and end time. We'll use this to catch up a +// remote node to the set of channel updates that they may have missed out on +// within the target chain. +// +// NOTE: This is part of the ChannelGraphTimeSeries interface. +func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash, + startTime time.Time, endTime time.Time) ([]lnwire.Message, error) { + + var updates []lnwire.Message + + // First, we'll query for all the set of channels that have an update + // that falls within the specified horizon. + chansInHorizon, err := c.graph.ChanUpdatesInHorizon( + startTime, endTime, + ) + if err != nil { + return nil, err + } + for _, channel := range chansInHorizon { + // If the channel hasn't been fully advertised yet, or is a + // private channel, then we'll skip it as we can't construct a + // full authentication proof if one is requested. + if channel.Info.AuthProof == nil { + continue + } + + chanAnn, edge1, edge2, err := CreateChanAnnouncement( + channel.Info.AuthProof, channel.Info, channel.Policy1, + channel.Policy2, + ) + if err != nil { + return nil, err + } + + updates = append(updates, chanAnn) + if edge1 != nil { + updates = append(updates, edge1) + } + if edge2 != nil { + updates = append(updates, edge2) + } + } + + // Next, we'll send out all the node announcements that have an update + // within the horizon as well. We send these second to ensure that they + // follow any active channels they have. + nodeAnnsInHorizon, err := c.graph.NodeUpdatesInHorizon( + startTime, endTime, + ) + if err != nil { + return nil, err + } + for _, nodeAnn := range nodeAnnsInHorizon { + // Ensure we only forward nodes that are publicly advertised to + // prevent leaking information about nodes. + isNodePublic, err := c.graph.IsPublicNode(nodeAnn.PubKeyBytes) + if err != nil { + log.Errorf("Unable to determine if node %x is "+ + "advertised: %v", nodeAnn.PubKeyBytes, err) + continue + } + + if !isNodePublic { + log.Tracef("Skipping forwarding announcement for "+ + "node %x due to being unadvertised", + nodeAnn.PubKeyBytes) + continue + } + + nodeUpdate, err := nodeAnn.NodeAnnouncement(true) + if err != nil { + return nil, err + } + + updates = append(updates, nodeUpdate) + } + + return updates, nil +} + +// FilterKnownChanIDs takes a target chain, and a set of channel ID's, and +// returns a filtered set of chan ID's. This filtered set of chan ID's +// represents the ID's that we don't know of which were in the passed superSet. +// +// NOTE: This is part of the ChannelGraphTimeSeries interface. +func (c *ChanSeries) FilterKnownChanIDs(chain chainhash.Hash, + superSet []lnwire.ShortChannelID) ([]lnwire.ShortChannelID, error) { + + chanIDs := make([]uint64, 0, len(superSet)) + for _, chanID := range superSet { + chanIDs = append(chanIDs, chanID.ToUint64()) + } + + newChanIDs, err := c.graph.FilterKnownChanIDs(chanIDs) + if err != nil { + return nil, err + } + + filteredIDs := make([]lnwire.ShortChannelID, 0, len(newChanIDs)) + for _, chanID := range newChanIDs { + filteredIDs = append( + filteredIDs, lnwire.NewShortChanIDFromInt(chanID), + ) + } + + return filteredIDs, nil +} + +// FilterChannelRange returns the set of channels that we created between the +// start height and the end height. We'll use this respond to a remote peer's +// QueryChannelRange message. +// +// NOTE: This is part of the ChannelGraphTimeSeries interface. +func (c *ChanSeries) FilterChannelRange(chain chainhash.Hash, + startHeight, endHeight uint32) ([]lnwire.ShortChannelID, error) { + + chansInRange, err := c.graph.FilterChannelRange(startHeight, endHeight) + if err != nil { + return nil, err + } + + chanResp := make([]lnwire.ShortChannelID, 0, len(chansInRange)) + for _, chanID := range chansInRange { + chanResp = append( + chanResp, lnwire.NewShortChanIDFromInt(chanID), + ) + } + + return chanResp, nil +} + +// FetchChanAnns returns a full set of channel announcements as well as their +// updates that match the set of specified short channel ID's. We'll use this +// to reply to a QueryShortChanIDs message sent by a remote peer. The response +// will contain a unique set of ChannelAnnouncements, the latest ChannelUpdate +// for each of the announcements, and a unique set of NodeAnnouncements. +// +// NOTE: This is part of the ChannelGraphTimeSeries interface. +func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash, + shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error) { + + chanIDs := make([]uint64, 0, len(shortChanIDs)) + for _, chanID := range shortChanIDs { + chanIDs = append(chanIDs, chanID.ToUint64()) + } + + channels, err := c.graph.FetchChanInfos(chanIDs) + if err != nil { + return nil, err + } + + // We'll use this map to ensure we don't send the same node + // announcement more than one time as one node may have many channel + // anns we'll need to send. + nodePubsSent := make(map[routing.Vertex]struct{}) + + chanAnns := make([]lnwire.Message, 0, len(channels)*3) + for _, channel := range channels { + // If the channel doesn't have an authentication proof, then we + // won't send it over as it may not yet be finalized, or be a + // non-advertised channel. + if channel.Info.AuthProof == nil { + continue + } + + chanAnn, edge1, edge2, err := CreateChanAnnouncement( + channel.Info.AuthProof, channel.Info, channel.Policy1, + channel.Policy2, + ) + if err != nil { + return nil, err + } + + chanAnns = append(chanAnns, chanAnn) + if edge1 != nil { + chanAnns = append(chanAnns, edge1) + + // If this edge has a validated node announcement, that + // we haven't yet sent, then we'll send that as well. + nodePub := channel.Policy1.Node.PubKeyBytes + hasNodeAnn := channel.Policy1.Node.HaveNodeAnnouncement + if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { + nodeAnn, err := channel.Policy1.Node.NodeAnnouncement(true) + if err != nil { + return nil, err + } + + chanAnns = append(chanAnns, nodeAnn) + nodePubsSent[nodePub] = struct{}{} + } + } + if edge2 != nil { + chanAnns = append(chanAnns, edge2) + + // If this edge has a validated node announcement, that + // we haven't yet sent, then we'll send that as well. + nodePub := channel.Policy2.Node.PubKeyBytes + hasNodeAnn := channel.Policy2.Node.HaveNodeAnnouncement + if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { + nodeAnn, err := channel.Policy2.Node.NodeAnnouncement(true) + if err != nil { + return nil, err + } + + chanAnns = append(chanAnns, nodeAnn) + nodePubsSent[nodePub] = struct{}{} + } + } + } + + return chanAnns, nil +} + +// FetchChanUpdates returns the latest channel update messages for the +// specified short channel ID. If no channel updates are known for the channel, +// then an empty slice will be returned. +// +// NOTE: This is part of the ChannelGraphTimeSeries interface. +func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash, + shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error) { + + chanInfo, e1, e2, err := c.graph.FetchChannelEdgesByID( + shortChanID.ToUint64(), + ) + if err != nil { + return nil, err + } + + chanUpdates := make([]*lnwire.ChannelUpdate, 0, 2) + if e1 != nil { + chanUpdate := &lnwire.ChannelUpdate{ + ChainHash: chanInfo.ChainHash, + ShortChannelID: shortChanID, + Timestamp: uint32(e1.LastUpdate.Unix()), + Flags: e1.Flags, + TimeLockDelta: e1.TimeLockDelta, + HtlcMinimumMsat: e1.MinHTLC, + BaseFee: uint32(e1.FeeBaseMSat), + FeeRate: uint32(e1.FeeProportionalMillionths), + ExtraOpaqueData: e1.ExtraOpaqueData, + } + chanUpdate.Signature, err = lnwire.NewSigFromRawSignature(e1.SigBytes) + if err != nil { + return nil, err + } + + chanUpdates = append(chanUpdates, chanUpdate) + } + if e2 != nil { + chanUpdate := &lnwire.ChannelUpdate{ + ChainHash: chanInfo.ChainHash, + ShortChannelID: shortChanID, + Timestamp: uint32(e2.LastUpdate.Unix()), + Flags: e2.Flags, + TimeLockDelta: e2.TimeLockDelta, + HtlcMinimumMsat: e2.MinHTLC, + BaseFee: uint32(e2.FeeBaseMSat), + FeeRate: uint32(e2.FeeProportionalMillionths), + ExtraOpaqueData: e2.ExtraOpaqueData, + } + chanUpdate.Signature, err = lnwire.NewSigFromRawSignature(e2.SigBytes) + if err != nil { + return nil, err + } + + chanUpdates = append(chanUpdates, chanUpdate) + } + + return chanUpdates, nil +} + +// A compile-time assertion to ensure that ChanSeries meets the +// ChannelGraphTimeSeries interface. +var _ ChannelGraphTimeSeries = (*ChanSeries)(nil) From 5fc0a192adb41d8cbd81096b13328c93e0505ae5 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Fri, 30 Nov 2018 15:33:28 -0800 Subject: [PATCH 2/4] discovery/syncer: move CGTimeSerires to chan_series --- discovery/syncer.go | 50 --------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/discovery/syncer.go b/discovery/syncer.go index 91793b72..f82c372e 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -107,56 +107,6 @@ const ( chanRangeQueryBuffer = 144 ) -// ChannelGraphTimeSeries is an interface that provides time and block based -// querying into our view of the channel graph. New channels will have -// monotonically increasing block heights, and new channel updates will have -// increasing timestamps. Once we connect to a peer, we'll use the methods in -// this interface to determine if we're already in sync, or need to request -// some new information from them. -type ChannelGraphTimeSeries interface { - // HighestChanID should return the channel ID of the channel we know of - // that's furthest in the target chain. This channel will have a block - // height that's close to the current tip of the main chain as we - // know it. We'll use this to start our QueryChannelRange dance with - // the remote node. - HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID, error) - - // UpdatesInHorizon returns all known channel and node updates with an - // update timestamp between the start time and end time. We'll use this - // to catch up a remote node to the set of channel updates that they - // may have missed out on within the target chain. - UpdatesInHorizon(chain chainhash.Hash, - startTime time.Time, endTime time.Time) ([]lnwire.Message, error) - - // FilterKnownChanIDs takes a target chain, and a set of channel ID's, - // and returns a filtered set of chan ID's. This filtered set of chan - // ID's represents the ID's that we don't know of which were in the - // passed superSet. - FilterKnownChanIDs(chain chainhash.Hash, - superSet []lnwire.ShortChannelID) ([]lnwire.ShortChannelID, error) - - // FilterChannelRange returns the set of channels that we created - // between the start height and the end height. We'll use this to to a - // remote peer's QueryChannelRange message. - FilterChannelRange(chain chainhash.Hash, - startHeight, endHeight uint32) ([]lnwire.ShortChannelID, error) - - // FetchChanAnns returns a full set of channel announcements as well as - // their updates that match the set of specified short channel ID's. - // We'll use this to reply to a QueryShortChanIDs message sent by a - // remote peer. The response will contain a unique set of - // ChannelAnnouncements, the latest ChannelUpdate for each of the - // announcements, and a unique set of NodeAnnouncements. - FetchChanAnns(chain chainhash.Hash, - shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error) - - // FetchChanUpdates returns the latest channel update messages for the - // specified short channel ID. If no channel updates are known for the - // channel, then an empty slice will be returned. - FetchChanUpdates(chain chainhash.Hash, - shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error) -} - // gossipSyncerCfg is a struct that packages all the information a gossipSyncer // needs to carry out its duties. type gossipSyncerCfg struct { From 4e48a56d5e1369113648d2bdc6fef68f84ad7cfe Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Fri, 30 Nov 2018 15:33:29 -0800 Subject: [PATCH 3/4] server: init gossiper w/ discovery.ChanSeries --- server.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server.go b/server.go index 7969bc70..05984385 100644 --- a/server.go +++ b/server.go @@ -564,12 +564,16 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl, return nil, fmt.Errorf("can't create router: %v", err) } + chanSeries := discovery.NewChanSeries( + s.chanDB.ChannelGraph(), + ) + s.authGossiper, err = discovery.New(discovery.Config{ Router: s.chanRouter, Notifier: s.cc.chainNotifier, ChainHash: *activeNetParams.GenesisHash, Broadcast: s.BroadcastMessage, - ChanSeries: &chanSeries{s.chanDB.ChannelGraph()}, + ChanSeries: chanSeries, SendToPeer: s.SendToPeer, FindPeer: func(pub *btcec.PublicKey) (lnpeer.Peer, error) { return s.FindPeer(pub) From da21f33a2a4a2bd20e8f5d3f6675d627737cd540 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Fri, 30 Nov 2018 15:33:31 -0800 Subject: [PATCH 4/4] chan_series: remove chan_series from main --- chan_series.go | 312 ------------------------------------------------- 1 file changed, 312 deletions(-) delete mode 100644 chan_series.go diff --git a/chan_series.go b/chan_series.go deleted file mode 100644 index 7f592503..00000000 --- a/chan_series.go +++ /dev/null @@ -1,312 +0,0 @@ -package main - -import ( - "time" - - "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/discovery" - "github.com/lightningnetwork/lnd/lnwire" - "github.com/lightningnetwork/lnd/routing" -) - -// chanSeries is an implementation of the discovery.ChannelGraphTimeSeries -// interface backed by the channeldb ChannelGraph database. We'll provide this -// implementation to the AuthenticatedGossiper so it can properly use the -// in-protocol channel range queries to quickly and efficiently synchronize our -// channel state with all peers. -type chanSeries struct { - graph *channeldb.ChannelGraph -} - -// HighestChanID should return is the channel ID of the channel we know of -// that's furthest in the target chain. This channel will have a block height -// that's close to the current tip of the main chain as we know it. We'll use -// this to start our QueryChannelRange dance with the remote node. -// -// NOTE: This is part of the discovery.ChannelGraphTimeSeries interface. -func (c *chanSeries) HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID, error) { - chanID, err := c.graph.HighestChanID() - if err != nil { - return nil, err - } - - shortChanID := lnwire.NewShortChanIDFromInt(chanID) - return &shortChanID, nil -} - -// UpdatesInHorizon returns all known channel and node updates with an update -// timestamp between the start time and end time. We'll use this to catch up a -// remote node to the set of channel updates that they may have missed out on -// within the target chain. -// -// NOTE: This is part of the discovery.ChannelGraphTimeSeries interface. -func (c *chanSeries) UpdatesInHorizon(chain chainhash.Hash, - startTime time.Time, endTime time.Time) ([]lnwire.Message, error) { - - var updates []lnwire.Message - - // First, we'll query for all the set of channels that have an update - // that falls within the specified horizon. - chansInHorizon, err := c.graph.ChanUpdatesInHorizon( - startTime, endTime, - ) - if err != nil { - return nil, err - } - for _, channel := range chansInHorizon { - // If the channel hasn't been fully advertised yet, or is a - // private channel, then we'll skip it as we can't construct a - // full authentication proof if one is requested. - if channel.Info.AuthProof == nil { - continue - } - - chanAnn, edge1, edge2, err := discovery.CreateChanAnnouncement( - channel.Info.AuthProof, channel.Info, channel.Policy1, - channel.Policy2, - ) - if err != nil { - return nil, err - } - - updates = append(updates, chanAnn) - if edge1 != nil { - updates = append(updates, edge1) - } - if edge2 != nil { - updates = append(updates, edge2) - } - } - - // Next, we'll send out all the node announcements that have an update - // within the horizon as well. We send these second to ensure that they - // follow any active channels they have. - nodeAnnsInHorizon, err := c.graph.NodeUpdatesInHorizon( - startTime, endTime, - ) - if err != nil { - return nil, err - } - for _, nodeAnn := range nodeAnnsInHorizon { - // Ensure we only forward nodes that are publicly advertised to - // prevent leaking information about nodes. - isNodePublic, err := c.graph.IsPublicNode(nodeAnn.PubKeyBytes) - if err != nil { - srvrLog.Errorf("Unable to determine if node %x is "+ - "advertised: %v", nodeAnn.PubKeyBytes, err) - continue - } - - if !isNodePublic { - srvrLog.Tracef("Skipping forwarding announcement for "+ - "node %x due to being unadvertised", - nodeAnn.PubKeyBytes) - continue - } - - nodeUpdate, err := nodeAnn.NodeAnnouncement(true) - if err != nil { - return nil, err - } - - updates = append(updates, nodeUpdate) - } - - return updates, nil -} - -// FilterKnownChanIDs takes a target chain, and a set of channel ID's, and -// returns a filtered set of chan ID's. This filtered set of chan ID's -// represents the ID's that we don't know of which were in the passed superSet. -// -// NOTE: This is part of the discovery.ChannelGraphTimeSeries interface. -func (c *chanSeries) FilterKnownChanIDs(chain chainhash.Hash, - superSet []lnwire.ShortChannelID) ([]lnwire.ShortChannelID, error) { - - chanIDs := make([]uint64, 0, len(superSet)) - for _, chanID := range superSet { - chanIDs = append(chanIDs, chanID.ToUint64()) - } - - newChanIDs, err := c.graph.FilterKnownChanIDs(chanIDs) - if err != nil { - return nil, err - } - - filteredIDs := make([]lnwire.ShortChannelID, 0, len(newChanIDs)) - for _, chanID := range newChanIDs { - filteredIDs = append( - filteredIDs, lnwire.NewShortChanIDFromInt(chanID), - ) - } - - return filteredIDs, nil -} - -// FilterChannelRange returns the set of channels that we created between the -// start height and the end height. We'll use this respond to a remote peer's -// QueryChannelRange message. -// -// NOTE: This is part of the discovery.ChannelGraphTimeSeries interface. -func (c *chanSeries) FilterChannelRange(chain chainhash.Hash, - startHeight, endHeight uint32) ([]lnwire.ShortChannelID, error) { - - chansInRange, err := c.graph.FilterChannelRange(startHeight, endHeight) - if err != nil { - return nil, err - } - - chanResp := make([]lnwire.ShortChannelID, 0, len(chansInRange)) - for _, chanID := range chansInRange { - chanResp = append( - chanResp, lnwire.NewShortChanIDFromInt(chanID), - ) - } - - return chanResp, nil -} - -// FetchChanAnns returns a full set of channel announcements as well as their -// updates that match the set of specified short channel ID's. We'll use this -// to reply to a QueryShortChanIDs message sent by a remote peer. The response -// will contain a unique set of ChannelAnnouncements, the latest ChannelUpdate -// for each of the announcements, and a unique set of NodeAnnouncements. -// -// NOTE: This is part of the discovery.ChannelGraphTimeSeries interface. -func (c *chanSeries) FetchChanAnns(chain chainhash.Hash, - shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error) { - - chanIDs := make([]uint64, 0, len(shortChanIDs)) - for _, chanID := range shortChanIDs { - chanIDs = append(chanIDs, chanID.ToUint64()) - } - - channels, err := c.graph.FetchChanInfos(chanIDs) - if err != nil { - return nil, err - } - - // We'll use this map to ensure we don't send the same node - // announcement more than one time as one node may have many channel - // anns we'll need to send. - nodePubsSent := make(map[routing.Vertex]struct{}) - - chanAnns := make([]lnwire.Message, 0, len(channels)*3) - for _, channel := range channels { - // If the channel doesn't have an authentication proof, then we - // won't send it over as it may not yet be finalized, or be a - // non-advertised channel. - if channel.Info.AuthProof == nil { - continue - } - - chanAnn, edge1, edge2, err := discovery.CreateChanAnnouncement( - channel.Info.AuthProof, channel.Info, channel.Policy1, - channel.Policy2, - ) - if err != nil { - return nil, err - } - - chanAnns = append(chanAnns, chanAnn) - if edge1 != nil { - chanAnns = append(chanAnns, edge1) - - // If this edge has a validated node announcement, that - // we haven't yet sent, then we'll send that as well. - nodePub := channel.Policy1.Node.PubKeyBytes - hasNodeAnn := channel.Policy1.Node.HaveNodeAnnouncement - if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { - nodeAnn, err := channel.Policy1.Node.NodeAnnouncement(true) - if err != nil { - return nil, err - } - - chanAnns = append(chanAnns, nodeAnn) - nodePubsSent[nodePub] = struct{}{} - } - } - if edge2 != nil { - chanAnns = append(chanAnns, edge2) - - // If this edge has a validated node announcement, that - // we haven't yet sent, then we'll send that as well. - nodePub := channel.Policy2.Node.PubKeyBytes - hasNodeAnn := channel.Policy2.Node.HaveNodeAnnouncement - if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn { - nodeAnn, err := channel.Policy2.Node.NodeAnnouncement(true) - if err != nil { - return nil, err - } - - chanAnns = append(chanAnns, nodeAnn) - nodePubsSent[nodePub] = struct{}{} - } - } - } - - return chanAnns, nil -} - -// FetchChanUpdates returns the latest channel update messages for the -// specified short channel ID. If no channel updates are known for the channel, -// then an empty slice will be returned. -// -// NOTE: This is part of the discovery.ChannelGraphTimeSeries interface. -func (c *chanSeries) FetchChanUpdates(chain chainhash.Hash, - shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error) { - - chanInfo, e1, e2, err := c.graph.FetchChannelEdgesByID( - shortChanID.ToUint64(), - ) - if err != nil { - return nil, err - } - - chanUpdates := make([]*lnwire.ChannelUpdate, 0, 2) - if e1 != nil { - chanUpdate := &lnwire.ChannelUpdate{ - ChainHash: chanInfo.ChainHash, - ShortChannelID: shortChanID, - Timestamp: uint32(e1.LastUpdate.Unix()), - Flags: e1.Flags, - TimeLockDelta: e1.TimeLockDelta, - HtlcMinimumMsat: e1.MinHTLC, - BaseFee: uint32(e1.FeeBaseMSat), - FeeRate: uint32(e1.FeeProportionalMillionths), - ExtraOpaqueData: e1.ExtraOpaqueData, - } - chanUpdate.Signature, err = lnwire.NewSigFromRawSignature(e1.SigBytes) - if err != nil { - return nil, err - } - - chanUpdates = append(chanUpdates, chanUpdate) - } - if e2 != nil { - chanUpdate := &lnwire.ChannelUpdate{ - ChainHash: chanInfo.ChainHash, - ShortChannelID: shortChanID, - Timestamp: uint32(e2.LastUpdate.Unix()), - Flags: e2.Flags, - TimeLockDelta: e2.TimeLockDelta, - HtlcMinimumMsat: e2.MinHTLC, - BaseFee: uint32(e2.FeeBaseMSat), - FeeRate: uint32(e2.FeeProportionalMillionths), - ExtraOpaqueData: e2.ExtraOpaqueData, - } - chanUpdate.Signature, err = lnwire.NewSigFromRawSignature(e2.SigBytes) - if err != nil { - return nil, err - } - - chanUpdates = append(chanUpdates, chanUpdate) - } - - return chanUpdates, nil -} - -// A compile-time assertion to ensure that chanSeries meets the -// discovery.ChannelGraphTimeSeries interface. -var _ discovery.ChannelGraphTimeSeries = (*chanSeries)(nil)