Merge pull request #2669 from cfromknecht/use-netann-in-discovery

netann+discovery+server: consolidate network announcements to netann pkg
This commit is contained in:
Conner Fromknecht 2020-03-23 13:38:06 -07:00 committed by GitHub
commit 4e793497c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 264 additions and 290 deletions

@ -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,
)
@ -323,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
}
@ -344,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
}

@ -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"
@ -350,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.
@ -1364,6 +1356,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
@ -1400,7 +1408,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 {
@ -2157,7 +2165,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(
msg.ChannelID,
peerID)
chanAnn, _, _, err := CreateChanAnnouncement(
chanAnn, _, _, err := netann.CreateChanAnnouncement(
chanInfo.AuthProof, chanInfo,
e1, e2,
)
@ -2240,7 +2248,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 {
@ -2445,42 +2453,23 @@ 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 := SignAnnouncement(d.cfg.AnnSigner, d.selfKey, chanUpdate)
// 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
}
// 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.

@ -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
}

@ -1,154 +0,0 @@
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"
)
// 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 = &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)
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)
if err != nil {
return nil, nil, nil, err
}
}
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,
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
}

@ -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)

@ -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

@ -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
}

@ -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,23 +59,8 @@ 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
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
}
@ -112,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()),
@ -130,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)

@ -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

@ -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
}

36
netann/sign.go Normal file

@ -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)
}

@ -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 {
@ -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 := discovery.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
}