From df44d1993614c7373fc13602998d42599e019f23 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:23:01 -0700 Subject: [PATCH 01/10] discovery/multi: move SignAnnouncement to netann --- discovery/gossiper.go | 5 ++++- discovery/gossiper_test.go | 13 +++++++------ discovery/utils.go | 31 ------------------------------- netann/sign.go | 36 ++++++++++++++++++++++++++++++++++++ server.go | 4 ++-- 5 files changed, 49 insertions(+), 40 deletions(-) create mode 100644 netann/sign.go diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 8c9ed6e5..5ee79852 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -20,6 +20,7 @@ import ( "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/multimutex" + "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/ticker" @@ -2469,7 +2470,9 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo, // With the update applied, we'll generate a new signature over a // digest of the channel announcement itself. - sig, err := SignAnnouncement(d.cfg.AnnSigner, d.selfKey, chanUpdate) + sig, err := netann.SignAnnouncement( + d.cfg.AnnSigner, d.selfKey, chanUpdate, + ) if err != nil { return nil, nil, err } diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 4252397c..f927a960 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -26,6 +26,7 @@ import ( "github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lntest/wait" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/routing" "github.com/lightningnetwork/lnd/routing/route" "github.com/lightningnetwork/lnd/ticker" @@ -550,7 +551,7 @@ func createNodeAnnouncement(priv *btcec.PrivateKey, } signer := mockSigner{priv} - sig, err := SignAnnouncement(&signer, priv.PubKey(), a) + sig, err := netann.SignAnnouncement(&signer, priv.PubKey(), a) if err != nil { return nil, err } @@ -602,7 +603,7 @@ func createUpdateAnnouncement(blockHeight uint32, func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error { pub := nodeKey.PubKey() signer := mockSigner{nodeKey} - sig, err := SignAnnouncement(&signer, pub, a) + sig, err := netann.SignAnnouncement(&signer, pub, a) if err != nil { return err } @@ -644,7 +645,7 @@ func createRemoteChannelAnnouncement(blockHeight uint32, pub := nodeKeyPriv1.PubKey() signer := mockSigner{nodeKeyPriv1} - sig, err := SignAnnouncement(&signer, pub, a) + sig, err := netann.SignAnnouncement(&signer, pub, a) if err != nil { return nil, err } @@ -655,7 +656,7 @@ func createRemoteChannelAnnouncement(blockHeight uint32, pub = nodeKeyPriv2.PubKey() signer = mockSigner{nodeKeyPriv2} - sig, err = SignAnnouncement(&signer, pub, a) + sig, err = netann.SignAnnouncement(&signer, pub, a) if err != nil { return nil, err } @@ -666,7 +667,7 @@ func createRemoteChannelAnnouncement(blockHeight uint32, pub = bitcoinKeyPriv1.PubKey() signer = mockSigner{bitcoinKeyPriv1} - sig, err = SignAnnouncement(&signer, pub, a) + sig, err = netann.SignAnnouncement(&signer, pub, a) if err != nil { return nil, err } @@ -677,7 +678,7 @@ func createRemoteChannelAnnouncement(blockHeight uint32, pub = bitcoinKeyPriv2.PubKey() signer = mockSigner{bitcoinKeyPriv2} - sig, err = SignAnnouncement(&signer, pub, a) + sig, err = netann.SignAnnouncement(&signer, pub, a) if err != nil { return nil, err } diff --git a/discovery/utils.go b/discovery/utils.go index ce211493..04793a60 100644 --- a/discovery/utils.go +++ b/discovery/utils.go @@ -1,10 +1,7 @@ package discovery import ( - "github.com/btcsuite/btcd/btcec" - "github.com/go-errors/errors" "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwire" ) @@ -109,34 +106,6 @@ func CreateChanAnnouncement(chanProof *channeldb.ChannelAuthProof, return chanAnn, edge1Ann, edge2Ann, nil } -// SignAnnouncement is a helper function which is used to sign any outgoing -// channel node node announcement messages. -func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, - msg lnwire.Message) (*btcec.Signature, error) { - - var ( - data []byte - err error - ) - - switch m := msg.(type) { - case *lnwire.ChannelAnnouncement: - data, err = m.DataToSign() - case *lnwire.ChannelUpdate: - data, err = m.DataToSign() - case *lnwire.NodeAnnouncement: - data, err = m.DataToSign() - default: - return nil, errors.New("can't sign message " + - "of this format") - } - if err != nil { - return nil, errors.Errorf("unable to get data to sign: %v", err) - } - - return signer.SignMessage(pubKey, data) -} - // remotePubFromChanInfo returns the public key of the remote peer given a // ChannelEdgeInfo that describe a channel we have with them. func remotePubFromChanInfo(chanInfo *channeldb.ChannelEdgeInfo, diff --git a/netann/sign.go b/netann/sign.go new file mode 100644 index 00000000..5a669620 --- /dev/null +++ b/netann/sign.go @@ -0,0 +1,36 @@ +package netann + +import ( + "fmt" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwire" +) + +// SignAnnouncement signs any type of gossip message that is announced on the +// network. +func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, + msg lnwire.Message) (*btcec.Signature, error) { + + var ( + data []byte + err error + ) + + switch m := msg.(type) { + case *lnwire.ChannelAnnouncement: + data, err = m.DataToSign() + case *lnwire.ChannelUpdate: + data, err = m.DataToSign() + case *lnwire.NodeAnnouncement: + data, err = m.DataToSign() + default: + return nil, fmt.Errorf("can't sign %T message", m) + } + if err != nil { + return nil, fmt.Errorf("unable to get data to sign: %v", err) + } + + return signer.SignMessage(pubKey, data) +} diff --git a/server.go b/server.go index 98f446d7..32caa33e 100644 --- a/server.go +++ b/server.go @@ -651,7 +651,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, // With the announcement generated, we'll sign it to properly // authenticate the message on the network. - authSig, err := discovery.SignAnnouncement( + authSig, err := netann.SignAnnouncement( s.nodeSigner, s.identityPriv.PubKey(), nodeAnn, ) if err != nil { @@ -2068,7 +2068,7 @@ func (s *server) genNodeAnnouncement(refresh bool, // Now that the announcement is fully updated, we'll generate a new // signature over the announcement to ensure nodes on the network // accepted the new authenticated announcement. - sig, err := discovery.SignAnnouncement( + sig, err := netann.SignAnnouncement( s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn, ) if err != nil { From 9d92cfd2b446c0d3ec42cfcaba793a86a7cf4e27 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:23:19 -0700 Subject: [PATCH 02/10] netann/channel_update: use generic SignAnnouncement --- netann/channel_update.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/netann/channel_update.go b/netann/channel_update.go index c405a0c6..b3c53136 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -55,13 +55,8 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, } update.Timestamp = newTimestamp - chanUpdateMsg, err := update.DataToSign() - if err != nil { - return err - } - // Create the DER-encoded ECDSA signature over the message digest. - sig, err := signer.SignMessage(pubKey, chanUpdateMsg) + sig, err := SignAnnouncement(signer, pubKey, update) if err != nil { return err } From d82aacbdc57ecf19fb57154e92d65d5ac765d243 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:23:37 -0700 Subject: [PATCH 03/10] discovery/utils: use netann.ChannelUpdateFromEdge --- discovery/utils.go | 31 +++---------------------------- 1 file changed, 3 insertions(+), 28 deletions(-) diff --git a/discovery/utils.go b/discovery/utils.go index 04793a60..9114e5a3 100644 --- a/discovery/utils.go +++ b/discovery/utils.go @@ -3,6 +3,7 @@ package discovery import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/netann" ) // CreateChanAnnouncement is a helper function which creates all channel @@ -65,39 +66,13 @@ func CreateChanAnnouncement(chanProof *channeldb.ChannelAuthProof, // nil. var edge1Ann, edge2Ann *lnwire.ChannelUpdate if e1 != nil { - edge1Ann = &lnwire.ChannelUpdate{ - ChainHash: chanInfo.ChainHash, - ShortChannelID: chanID, - Timestamp: uint32(e1.LastUpdate.Unix()), - MessageFlags: e1.MessageFlags, - ChannelFlags: e1.ChannelFlags, - TimeLockDelta: e1.TimeLockDelta, - HtlcMinimumMsat: e1.MinHTLC, - HtlcMaximumMsat: e1.MaxHTLC, - BaseFee: uint32(e1.FeeBaseMSat), - FeeRate: uint32(e1.FeeProportionalMillionths), - ExtraOpaqueData: e1.ExtraOpaqueData, - } - edge1Ann.Signature, err = lnwire.NewSigFromRawSignature(e1.SigBytes) + edge1Ann, err = netann.ChannelUpdateFromEdge(chanInfo, e1) if err != nil { return nil, nil, nil, err } } if e2 != nil { - edge2Ann = &lnwire.ChannelUpdate{ - ChainHash: chanInfo.ChainHash, - ShortChannelID: chanID, - Timestamp: uint32(e2.LastUpdate.Unix()), - MessageFlags: e2.MessageFlags, - ChannelFlags: e2.ChannelFlags, - TimeLockDelta: e2.TimeLockDelta, - HtlcMinimumMsat: e2.MinHTLC, - HtlcMaximumMsat: e2.MaxHTLC, - BaseFee: uint32(e2.FeeBaseMSat), - FeeRate: uint32(e2.FeeProportionalMillionths), - ExtraOpaqueData: e2.ExtraOpaqueData, - } - edge2Ann.Signature, err = lnwire.NewSigFromRawSignature(e2.SigBytes) + edge2Ann, err = netann.ChannelUpdateFromEdge(chanInfo, e2) if err != nil { return nil, nil, nil, err } From 6a813e3433d05cb08d2eec7df73ced67a1e0443f Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:23:54 -0700 Subject: [PATCH 04/10] discovery/multi: move CreateChanAnnouncement to netann --- discovery/chan_series.go | 5 ++- discovery/gossiper.go | 6 +-- discovery/utils.go | 76 ------------------------------- netann/channel_announcement.go | 81 ++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 81 deletions(-) create mode 100644 netann/channel_announcement.go diff --git a/discovery/chan_series.go b/discovery/chan_series.go index ddea5104..7ed101b3 100644 --- a/discovery/chan_series.go +++ b/discovery/chan_series.go @@ -6,6 +6,7 @@ import ( "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" + "github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/routing/route" ) @@ -119,7 +120,7 @@ func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash, continue } - chanAnn, edge1, edge2, err := CreateChanAnnouncement( + chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement( channel.Info.AuthProof, channel.Info, channel.Policy1, channel.Policy2, ) @@ -258,7 +259,7 @@ func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash, continue } - chanAnn, edge1, edge2, err := CreateChanAnnouncement( + chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement( channel.Info.AuthProof, channel.Info, channel.Policy1, channel.Policy2, ) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 5ee79852..742c260d 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1401,7 +1401,7 @@ func (d *AuthenticatedGossiper) processRejectedEdge( // We'll then create then validate the new fully assembled // announcement. - chanAnn, e1Ann, e2Ann, err := CreateChanAnnouncement( + chanAnn, e1Ann, e2Ann, err := netann.CreateChanAnnouncement( proof, chanInfo, e1, e2, ) if err != nil { @@ -2158,7 +2158,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( msg.ChannelID, peerID) - chanAnn, _, _, err := CreateChanAnnouncement( + chanAnn, _, _, err := netann.CreateChanAnnouncement( chanInfo.AuthProof, chanInfo, e1, e2, ) @@ -2241,7 +2241,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement( dbProof.BitcoinSig1Bytes = oppositeProof.BitcoinSignature.ToSignatureBytes() dbProof.BitcoinSig2Bytes = msg.BitcoinSignature.ToSignatureBytes() } - chanAnn, e1Ann, e2Ann, err := CreateChanAnnouncement( + chanAnn, e1Ann, e2Ann, err := netann.CreateChanAnnouncement( &dbProof, chanInfo, e1, e2, ) if err != nil { diff --git a/discovery/utils.go b/discovery/utils.go index 9114e5a3..6a5e2dee 100644 --- a/discovery/utils.go +++ b/discovery/utils.go @@ -3,84 +3,8 @@ package discovery import ( "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/lnwire" - "github.com/lightningnetwork/lnd/netann" ) -// CreateChanAnnouncement is a helper function which creates all channel -// announcements given the necessary channel related database items. This -// function is used to transform out database structs into the corresponding wire -// structs for announcing new channels to other peers, or simply syncing up a -// peer's initial routing table upon connect. -func CreateChanAnnouncement(chanProof *channeldb.ChannelAuthProof, - chanInfo *channeldb.ChannelEdgeInfo, - e1, e2 *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement, - *lnwire.ChannelUpdate, *lnwire.ChannelUpdate, error) { - - // First, using the parameters of the channel, along with the channel - // authentication chanProof, we'll create re-create the original - // authenticated channel announcement. - chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID) - chanAnn := &lnwire.ChannelAnnouncement{ - ShortChannelID: chanID, - NodeID1: chanInfo.NodeKey1Bytes, - NodeID2: chanInfo.NodeKey2Bytes, - ChainHash: chanInfo.ChainHash, - BitcoinKey1: chanInfo.BitcoinKey1Bytes, - BitcoinKey2: chanInfo.BitcoinKey2Bytes, - Features: lnwire.NewRawFeatureVector(), - ExtraOpaqueData: chanInfo.ExtraOpaqueData, - } - - var err error - chanAnn.BitcoinSig1, err = lnwire.NewSigFromRawSignature( - chanProof.BitcoinSig1Bytes, - ) - if err != nil { - return nil, nil, nil, err - } - chanAnn.BitcoinSig2, err = lnwire.NewSigFromRawSignature( - chanProof.BitcoinSig2Bytes, - ) - if err != nil { - return nil, nil, nil, err - } - chanAnn.NodeSig1, err = lnwire.NewSigFromRawSignature( - chanProof.NodeSig1Bytes, - ) - if err != nil { - return nil, nil, nil, err - } - chanAnn.NodeSig2, err = lnwire.NewSigFromRawSignature( - chanProof.NodeSig2Bytes, - ) - if err != nil { - return nil, nil, nil, err - } - - // We'll unconditionally queue the channel's existence chanProof as it - // will need to be processed before either of the channel update - // networkMsgs. - - // Since it's up to a node's policy as to whether they advertise the - // edge in a direction, we don't create an advertisement if the edge is - // nil. - var edge1Ann, edge2Ann *lnwire.ChannelUpdate - if e1 != nil { - edge1Ann, err = netann.ChannelUpdateFromEdge(chanInfo, e1) - if err != nil { - return nil, nil, nil, err - } - } - if e2 != nil { - edge2Ann, err = netann.ChannelUpdateFromEdge(chanInfo, e2) - if err != nil { - return nil, nil, nil, err - } - } - - return chanAnn, edge1Ann, edge2Ann, nil -} - // remotePubFromChanInfo returns the public key of the remote peer given a // ChannelEdgeInfo that describe a channel we have with them. func remotePubFromChanInfo(chanInfo *channeldb.ChannelEdgeInfo, diff --git a/netann/channel_announcement.go b/netann/channel_announcement.go new file mode 100644 index 00000000..99f909e2 --- /dev/null +++ b/netann/channel_announcement.go @@ -0,0 +1,81 @@ +package netann + +import ( + "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/lnwire" +) + +// CreateChanAnnouncement is a helper function which creates all channel +// announcements given the necessary channel related database items. This +// function is used to transform out database structs into the corresponding wire +// structs for announcing new channels to other peers, or simply syncing up a +// peer's initial routing table upon connect. +func CreateChanAnnouncement(chanProof *channeldb.ChannelAuthProof, + chanInfo *channeldb.ChannelEdgeInfo, + e1, e2 *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement, + *lnwire.ChannelUpdate, *lnwire.ChannelUpdate, error) { + + // First, using the parameters of the channel, along with the channel + // authentication chanProof, we'll create re-create the original + // authenticated channel announcement. + chanID := lnwire.NewShortChanIDFromInt(chanInfo.ChannelID) + chanAnn := &lnwire.ChannelAnnouncement{ + ShortChannelID: chanID, + NodeID1: chanInfo.NodeKey1Bytes, + NodeID2: chanInfo.NodeKey2Bytes, + ChainHash: chanInfo.ChainHash, + BitcoinKey1: chanInfo.BitcoinKey1Bytes, + BitcoinKey2: chanInfo.BitcoinKey2Bytes, + Features: lnwire.NewRawFeatureVector(), + ExtraOpaqueData: chanInfo.ExtraOpaqueData, + } + + var err error + chanAnn.BitcoinSig1, err = lnwire.NewSigFromRawSignature( + chanProof.BitcoinSig1Bytes, + ) + if err != nil { + return nil, nil, nil, err + } + chanAnn.BitcoinSig2, err = lnwire.NewSigFromRawSignature( + chanProof.BitcoinSig2Bytes, + ) + if err != nil { + return nil, nil, nil, err + } + chanAnn.NodeSig1, err = lnwire.NewSigFromRawSignature( + chanProof.NodeSig1Bytes, + ) + if err != nil { + return nil, nil, nil, err + } + chanAnn.NodeSig2, err = lnwire.NewSigFromRawSignature( + chanProof.NodeSig2Bytes, + ) + if err != nil { + return nil, nil, nil, err + } + + // We'll unconditionally queue the channel's existence chanProof as it + // will need to be processed before either of the channel update + // networkMsgs. + + // Since it's up to a node's policy as to whether they advertise the + // edge in a direction, we don't create an advertisement if the edge is + // nil. + var edge1Ann, edge2Ann *lnwire.ChannelUpdate + if e1 != nil { + edge1Ann, err = ChannelUpdateFromEdge(chanInfo, e1) + if err != nil { + return nil, nil, nil, err + } + } + if e2 != nil { + edge2Ann, err = ChannelUpdateFromEdge(chanInfo, e2) + if err != nil { + return nil, nil, nil, err + } + } + + return chanAnn, edge1Ann, edge2Ann, nil +} From 7b0d564692925bf2970257cfc489ee9d10236fa3 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:24:10 -0700 Subject: [PATCH 05/10] discovery: move remotePubFromChanInfo to gossiper, remove utils --- discovery/gossiper.go | 16 ++++++++++++++++ discovery/utils.go | 22 ---------------------- 2 files changed, 16 insertions(+), 22 deletions(-) delete mode 100644 discovery/utils.go diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 742c260d..338558e7 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -1365,6 +1365,22 @@ func (d *AuthenticatedGossiper) processChanPolicyUpdate( return chanUpdates, nil } +// remotePubFromChanInfo returns the public key of the remote peer given a +// ChannelEdgeInfo that describe a channel we have with them. +func remotePubFromChanInfo(chanInfo *channeldb.ChannelEdgeInfo, + chanFlags lnwire.ChanUpdateChanFlags) [33]byte { + + var remotePubKey [33]byte + switch { + case chanFlags&lnwire.ChanUpdateDirection == 0: + remotePubKey = chanInfo.NodeKey2Bytes + case chanFlags&lnwire.ChanUpdateDirection == 1: + remotePubKey = chanInfo.NodeKey1Bytes + } + + return remotePubKey +} + // processRejectedEdge examines a rejected edge to see if we can extract any // new announcements from it. An edge will get rejected if we already added // the same edge without AuthProof to the graph. If the received announcement diff --git a/discovery/utils.go b/discovery/utils.go deleted file mode 100644 index 6a5e2dee..00000000 --- a/discovery/utils.go +++ /dev/null @@ -1,22 +0,0 @@ -package discovery - -import ( - "github.com/lightningnetwork/lnd/channeldb" - "github.com/lightningnetwork/lnd/lnwire" -) - -// remotePubFromChanInfo returns the public key of the remote peer given a -// ChannelEdgeInfo that describe a channel we have with them. -func remotePubFromChanInfo(chanInfo *channeldb.ChannelEdgeInfo, - chanFlags lnwire.ChanUpdateChanFlags) [33]byte { - - var remotePubKey [33]byte - switch { - case chanFlags&lnwire.ChanUpdateDirection == 0: - remotePubKey = chanInfo.NodeKey2Bytes - case chanFlags&lnwire.ChanUpdateDirection == 1: - remotePubKey = chanInfo.NodeKey1Bytes - } - - return remotePubKey -} From 089ac647d84e0cd7501dbbd0f83557cd15f59922 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:24:25 -0700 Subject: [PATCH 06/10] discovery/chan_series: use netann.ChannelUpdateFromEdge helper --- discovery/chan_series.go | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/discovery/chan_series.go b/discovery/chan_series.go index 7ed101b3..ffb59b4e 100644 --- a/discovery/chan_series.go +++ b/discovery/chan_series.go @@ -324,20 +324,7 @@ func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash, chanUpdates := make([]*lnwire.ChannelUpdate, 0, 2) if e1 != nil { - chanUpdate := &lnwire.ChannelUpdate{ - ChainHash: chanInfo.ChainHash, - ShortChannelID: shortChanID, - Timestamp: uint32(e1.LastUpdate.Unix()), - MessageFlags: e1.MessageFlags, - ChannelFlags: e1.ChannelFlags, - TimeLockDelta: e1.TimeLockDelta, - HtlcMinimumMsat: e1.MinHTLC, - HtlcMaximumMsat: e1.MaxHTLC, - BaseFee: uint32(e1.FeeBaseMSat), - FeeRate: uint32(e1.FeeProportionalMillionths), - ExtraOpaqueData: e1.ExtraOpaqueData, - } - chanUpdate.Signature, err = lnwire.NewSigFromRawSignature(e1.SigBytes) + chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e1) if err != nil { return nil, err } @@ -345,20 +332,7 @@ func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash, chanUpdates = append(chanUpdates, chanUpdate) } if e2 != nil { - chanUpdate := &lnwire.ChannelUpdate{ - ChainHash: chanInfo.ChainHash, - ShortChannelID: shortChanID, - Timestamp: uint32(e2.LastUpdate.Unix()), - MessageFlags: e2.MessageFlags, - ChannelFlags: e2.ChannelFlags, - TimeLockDelta: e2.TimeLockDelta, - HtlcMinimumMsat: e2.MinHTLC, - HtlcMaximumMsat: e2.MaxHTLC, - BaseFee: uint32(e2.FeeBaseMSat), - FeeRate: uint32(e2.FeeProportionalMillionths), - ExtraOpaqueData: e2.ExtraOpaqueData, - } - chanUpdate.Signature, err = lnwire.NewSigFromRawSignature(e2.SigBytes) + chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e2) if err != nil { return nil, err } From f6c194c3cdebe4e1d9a5169f0d80cb08ccdf89ec Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:25:02 -0700 Subject: [PATCH 07/10] netann/node_announcement: consolidate signing logic --- lnwire/node_announcement.go | 8 ----- netann/node_announcement.go | 60 +++++++++++++++++++++++++++++++++++++ server.go | 33 ++++++-------------- 3 files changed, 69 insertions(+), 32 deletions(-) create mode 100644 netann/node_announcement.go diff --git a/lnwire/node_announcement.go b/lnwire/node_announcement.go index 4ea64fa6..f0d897bc 100644 --- a/lnwire/node_announcement.go +++ b/lnwire/node_announcement.go @@ -101,14 +101,6 @@ type NodeAnnouncement struct { ExtraOpaqueData []byte } -// UpdateNodeAnnAddrs is a functional option that allows updating the addresses -// of the given node announcement. -func UpdateNodeAnnAddrs(addrs []net.Addr) func(*NodeAnnouncement) { - return func(nodeAnn *NodeAnnouncement) { - nodeAnn.Addresses = addrs - } -} - // A compile time check to ensure NodeAnnouncement implements the // lnwire.Message interface. var _ Message = (*NodeAnnouncement)(nil) diff --git a/netann/node_announcement.go b/netann/node_announcement.go new file mode 100644 index 00000000..84a26105 --- /dev/null +++ b/netann/node_announcement.go @@ -0,0 +1,60 @@ +package netann + +import ( + "net" + "time" + + "github.com/btcsuite/btcd/btcec" + "github.com/lightningnetwork/lnd/lnwallet" + "github.com/lightningnetwork/lnd/lnwire" +) + +// NodeAnnModifier is a closure that makes in-place modifications to an +// lnwire.NodeAnnouncement. +type NodeAnnModifier func(*lnwire.NodeAnnouncement) + +// NodeAnnSetAddrs is a functional option that allows updating the addresses of +// the given node announcement. +func NodeAnnSetAddrs(addrs []net.Addr) func(*lnwire.NodeAnnouncement) { + return func(nodeAnn *lnwire.NodeAnnouncement) { + nodeAnn.Addresses = addrs + } +} + +// NodeAnnSetTimestamp is a functional option that sets the timestamp of the +// announcement to the current time, or increments it if the timestamp is +// already in the future. +func NodeAnnSetTimestamp(nodeAnn *lnwire.NodeAnnouncement) { + newTimestamp := uint32(time.Now().Unix()) + if newTimestamp <= nodeAnn.Timestamp { + // Increment the prior value to ensure the timestamp + // monotonically increases, otherwise the announcement won't + // propagate. + newTimestamp = nodeAnn.Timestamp + 1 + } + nodeAnn.Timestamp = newTimestamp +} + +// SignNodeAnnouncement applies the given modifies to the passed +// lnwire.NodeAnnouncement, then signs the resulting announcement. The provided +// update should be the most recent, valid update, otherwise the timestamp may +// not monotonically increase from the prior. +func SignNodeAnnouncement(signer lnwallet.MessageSigner, + pubKey *btcec.PublicKey, nodeAnn *lnwire.NodeAnnouncement, + mods ...NodeAnnModifier) error { + + // Apply the requested changes to the node announcement. + for _, modifier := range mods { + modifier(nodeAnn) + } + + // Create the DER-encoded ECDSA signature over the message digest. + sig, err := SignAnnouncement(signer, pubKey, nodeAnn) + if err != nil { + return err + } + + // Parse the DER-encoded signature into a fixed-size 64-byte array. + nodeAnn.Signature, err = lnwire.NewSigFromSignature(sig) + return err +} diff --git a/server.go b/server.go index 32caa33e..db9ba4e9 100644 --- a/server.go +++ b/server.go @@ -1657,7 +1657,7 @@ out: // announcement with the updated addresses and broadcast // it to our peers. newNodeAnn, err := s.genNodeAnnouncement( - true, lnwire.UpdateNodeAnnAddrs(newAddrs), + true, netann.NodeAnnSetAddrs(newAddrs), ) if err != nil { srvrLog.Debugf("Unable to generate new node "+ @@ -2039,7 +2039,7 @@ func (s *server) initTorController() error { // announcement. If refresh is true, then the time stamp of the announcement // will be updated in order to ensure it propagates through the network. func (s *server) genNodeAnnouncement(refresh bool, - updates ...func(*lnwire.NodeAnnouncement)) (lnwire.NodeAnnouncement, error) { + modifiers ...netann.NodeAnnModifier) (lnwire.NodeAnnouncement, error) { s.mu.Lock() defer s.mu.Unlock() @@ -2050,34 +2050,19 @@ func (s *server) genNodeAnnouncement(refresh bool, return *s.currentNodeAnn, nil } - // Now that we know we need to update our copy, we'll apply all the - // function updates that'll mutate the current version of our node - // announcement. - for _, update := range updates { - update(s.currentNodeAnn) - } + // Always update the timestamp when refreshing to ensure the update + // propagates. + modifiers = append(modifiers, netann.NodeAnnSetTimestamp) - // We'll now update the timestamp, ensuring that with each update, the - // timestamp monotonically increases. - newStamp := uint32(time.Now().Unix()) - if newStamp <= s.currentNodeAnn.Timestamp { - newStamp = s.currentNodeAnn.Timestamp + 1 - } - s.currentNodeAnn.Timestamp = newStamp - - // Now that the announcement is fully updated, we'll generate a new - // signature over the announcement to ensure nodes on the network - // accepted the new authenticated announcement. - sig, err := netann.SignAnnouncement( + // Otherwise, we'll sign a new update after applying all of the passed + // modifiers. + err := netann.SignNodeAnnouncement( s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn, + modifiers..., ) if err != nil { return lnwire.NodeAnnouncement{}, err } - s.currentNodeAnn.Signature, err = lnwire.NewSigFromSignature(sig) - if err != nil { - return lnwire.NodeAnnouncement{}, err - } return *s.currentNodeAnn, nil } From 5147a6d63d4c55a8b70584d4e7f0c222fdaa1cb5 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Tue, 17 Mar 2020 16:25:22 -0700 Subject: [PATCH 08/10] netann/channel_update: set timestamp via modifier --- netann/chan_status_manager.go | 2 +- netann/channel_update.go | 30 +++++++++++++++++------------- netann/channel_update_test.go | 4 +++- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/netann/chan_status_manager.go b/netann/chan_status_manager.go index 146fef47..51797c87 100644 --- a/netann/chan_status_manager.go +++ b/netann/chan_status_manager.go @@ -527,7 +527,7 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint, err = SignChannelUpdate( m.cfg.MessageSigner, m.cfg.OurPubKey, chanUpdate, - ChannelUpdateSetDisable(disabled), + ChanUpdSetDisable(disabled), ChanUpdSetTimestamp, ) if err != nil { return err diff --git a/netann/channel_update.go b/netann/channel_update.go index b3c53136..a40abc25 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -15,9 +15,9 @@ import ( // lnwire.ChannelUpdate. type ChannelUpdateModifier func(*lnwire.ChannelUpdate) -// ChannelUpdateSetDisable sets the disabled channel flag if disabled is true, -// and clears the bit otherwise. -func ChannelUpdateSetDisable(disabled bool) ChannelUpdateModifier { +// ChanUpdSetDisable is a functional option that sets the disabled channel flag +// if disabled is true, and clears the bit otherwise. +func ChanUpdSetDisable(disabled bool) ChannelUpdateModifier { return func(update *lnwire.ChannelUpdate) { if disabled { // Set the bit responsible for marking a channel as @@ -31,6 +31,20 @@ func ChannelUpdateSetDisable(disabled bool) ChannelUpdateModifier { } } +// ChanUpdSetTimestamp is a functional option that sets the timestamp of the +// update to the current time, or increments it if the timestamp is already in +// the future. +func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) { + newTimestamp := uint32(time.Now().Unix()) + if newTimestamp <= update.Timestamp { + // Increment the prior value to ensure the timestamp + // monotonically increases, otherwise the update won't + // propagate. + newTimestamp = update.Timestamp + 1 + } + update.Timestamp = newTimestamp +} + // SignChannelUpdate applies the given modifiers to the passed // lnwire.ChannelUpdate, then signs the resulting update. The provided update // should be the most recent, valid update, otherwise the timestamp may not @@ -45,16 +59,6 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, modifier(update) } - // Update the message's timestamp to the current time. If the update's - // current time is already in the future, we increment the prior value - // to ensure the timestamps monotonically increase, otherwise the - // update won't propagate. - newTimestamp := uint32(time.Now().Unix()) - if newTimestamp <= update.Timestamp { - newTimestamp = update.Timestamp + 1 - } - update.Timestamp = newTimestamp - // Create the DER-encoded ECDSA signature over the message digest. sig, err := SignAnnouncement(signer, pubKey, update) if err != nil { diff --git a/netann/channel_update_test.go b/netann/channel_update_test.go index 4ed019a8..0bc48e5c 100644 --- a/netann/channel_update_test.go +++ b/netann/channel_update_test.go @@ -103,6 +103,7 @@ func TestUpdateDisableFlag(t *testing.T) { t.Parallel() for _, tc := range updateDisableTests { + tc := tc t.Run(tc.name, func(t *testing.T) { // Create the initial update, the only fields we are // concerned with in this test are the timestamp and the @@ -127,7 +128,8 @@ func TestUpdateDisableFlag(t *testing.T) { // disabled or enabled as prescribed in the test case. err := netann.SignChannelUpdate( tc.signer, pubKey, newUpdate, - netann.ChannelUpdateSetDisable(tc.disable), + netann.ChanUpdSetDisable(tc.disable), + netann.ChanUpdSetTimestamp, ) var fail bool From 5c2fc4a2d6ba61ab79ac46930f3dd2c71b7962de Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Thu, 19 Mar 2020 13:43:39 -0700 Subject: [PATCH 09/10] discovery/gossiper: use netann pkg for signing channel updates --- discovery/gossiper.go | 37 ++++++++----------------------------- netann/channel_update.go | 18 +++++++++++++----- 2 files changed, 21 insertions(+), 34 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 338558e7..bbc1ebd1 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -2462,32 +2462,14 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo, edge *channeldb.ChannelEdgePolicy) (*lnwire.ChannelAnnouncement, *lnwire.ChannelUpdate, error) { - // Make sure timestamp is always increased, such that our update gets - // propagated. - timestamp := time.Now().Unix() - if timestamp <= edge.LastUpdate.Unix() { - timestamp = edge.LastUpdate.Unix() + 1 - } - edge.LastUpdate = time.Unix(timestamp, 0) + // Parse the unsigned edge into a channel update. + chanUpdate := netann.UnsignedChannelUpdateFromEdge(info, edge) - chanUpdate := &lnwire.ChannelUpdate{ - ChainHash: info.ChainHash, - ShortChannelID: lnwire.NewShortChanIDFromInt(edge.ChannelID), - Timestamp: uint32(timestamp), - MessageFlags: edge.MessageFlags, - ChannelFlags: edge.ChannelFlags, - TimeLockDelta: edge.TimeLockDelta, - HtlcMinimumMsat: edge.MinHTLC, - HtlcMaximumMsat: edge.MaxHTLC, - BaseFee: uint32(edge.FeeBaseMSat), - FeeRate: uint32(edge.FeeProportionalMillionths), - ExtraOpaqueData: edge.ExtraOpaqueData, - } - - // With the update applied, we'll generate a new signature over a - // digest of the channel announcement itself. - sig, err := netann.SignAnnouncement( + // We'll generate a new signature over a digest of the channel + // announcement itself and update the timestamp to ensure it propagate. + err := netann.SignChannelUpdate( d.cfg.AnnSigner, d.selfKey, chanUpdate, + netann.ChanUpdSetTimestamp, ) if err != nil { return nil, nil, err @@ -2495,11 +2477,8 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo, // Next, we'll set the new signature in place, and update the reference // in the backing slice. - edge.SetSigBytes(sig.Serialize()) - chanUpdate.Signature, err = lnwire.NewSigFromSignature(sig) - if err != nil { - return nil, nil, err - } + edge.LastUpdate = time.Unix(int64(chanUpdate.Timestamp), 0) + edge.SigBytes = chanUpdate.Signature.ToSignatureBytes() // To ensure that our signature is valid, we'll verify it ourself // before committing it to the slice returned. diff --git a/netann/channel_update.go b/netann/channel_update.go index a40abc25..4423f4ec 100644 --- a/netann/channel_update.go +++ b/netann/channel_update.go @@ -111,12 +111,12 @@ func ExtractChannelUpdate(ownerPubKey []byte, info.ChannelPoint) } -// ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge -// info and policy. -func ChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo, - policy *channeldb.ChannelEdgePolicy) (*lnwire.ChannelUpdate, error) { +// UnsignedChannelUpdateFromEdge reconstructs an unsigned ChannelUpdate from the +// given edge info and policy. +func UnsignedChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo, + policy *channeldb.ChannelEdgePolicy) *lnwire.ChannelUpdate { - update := &lnwire.ChannelUpdate{ + return &lnwire.ChannelUpdate{ ChainHash: info.ChainHash, ShortChannelID: lnwire.NewShortChanIDFromInt(policy.ChannelID), Timestamp: uint32(policy.LastUpdate.Unix()), @@ -129,6 +129,14 @@ func ChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo, FeeRate: uint32(policy.FeeProportionalMillionths), ExtraOpaqueData: policy.ExtraOpaqueData, } +} + +// ChannelUpdateFromEdge reconstructs a signed ChannelUpdate from the given edge +// info and policy. +func ChannelUpdateFromEdge(info *channeldb.ChannelEdgeInfo, + policy *channeldb.ChannelEdgePolicy) (*lnwire.ChannelUpdate, error) { + + update := UnsignedChannelUpdateFromEdge(info, policy) var err error update.Signature, err = lnwire.NewSigFromRawSignature(policy.SigBytes) From 92456d063d83ddef549d9cd8d35a74ebe23eed65 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Thu, 19 Mar 2020 13:43:57 -0700 Subject: [PATCH 10/10] discovery: remove unused updateChanPolicies struct --- discovery/gossiper.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index bbc1ebd1..03139412 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -351,15 +351,6 @@ func New(cfg Config, selfKey *btcec.PublicKey) *AuthenticatedGossiper { return gossiper } -// updatedChanPolicies is a set of channel policies that have been successfully -// updated and written to disk, or an error if the policy update failed. This -// struct's map field is intended to be used for updating channel policies on -// the link layer. -type updatedChanPolicies struct { - chanPolicies map[wire.OutPoint]*channeldb.ChannelEdgePolicy - err error -} - // EdgeWithInfo contains the information that is required to update an edge. type EdgeWithInfo struct { // Info describes the channel.