diff --git a/discovery/gossiper.go b/discovery/gossiper.go index bebc19760..50dd3a57a 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -244,11 +244,11 @@ type Config struct { // FetchSelfAnnouncement retrieves our current node announcement, for // use when determining whether we should update our peers about our // presence in the network. - FetchSelfAnnouncement func() lnwire.NodeAnnouncement + FetchSelfAnnouncement func() lnwire.NodeAnnouncement1 // UpdateSelfAnnouncement produces a new announcement for our node with // an updated timestamp which can be broadcast to our peers. - UpdateSelfAnnouncement func() (lnwire.NodeAnnouncement, error) + UpdateSelfAnnouncement func() (lnwire.NodeAnnouncement1, error) // ProofMatureDelta the number of confirmations which is needed before // exchange the channel announcement proofs. @@ -1186,7 +1186,7 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) { // Node announcements are identified by the Vertex field. Use the // NodeID to create the corresponding Vertex. - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: sender := route.NewVertex(message.source) deDupKey := route.Vertex(msg.NodeID) @@ -1195,7 +1195,8 @@ func (d *deDupedAnnouncements) addMsg(message networkMsg) { oldTimestamp := uint32(0) mws, ok := d.nodeAnnouncements[deDupKey] if ok { - oldTimestamp = mws.msg.(*lnwire.NodeAnnouncement).Timestamp + ann, _ := mws.msg.(*lnwire.NodeAnnouncement1) + oldTimestamp = ann.Timestamp } // Discard the message if it's old. @@ -1806,7 +1807,7 @@ func (d *AuthenticatedGossiper) retransmitStaleAnns(ctx context.Context, return nil } - // We'll also check that our NodeAnnouncement is not too old. + // We'll also check that our NodeAnnouncement1 is not too old. currentNodeAnn := d.cfg.FetchSelfAnnouncement() timestamp := time.Unix(int64(currentNodeAnn.Timestamp), 0) timeElapsed := now.Sub(timestamp) @@ -2062,7 +2063,7 @@ func (d *AuthenticatedGossiper) fetchPKScript(chanID lnwire.ShortChannelID) ( // addNode processes the given node announcement, and adds it to our channel // graph. func (d *AuthenticatedGossiper) addNode(ctx context.Context, - msg *lnwire.NodeAnnouncement, op ...batch.SchedulerOption) error { + msg *lnwire.NodeAnnouncement1, op ...batch.SchedulerOption) error { if err := netann.ValidateNodeAnn(msg); err != nil { return fmt.Errorf("unable to validate node announcement: %w", @@ -2153,7 +2154,7 @@ func (d *AuthenticatedGossiper) processNetworkAnnouncement(ctx context.Context, // A new node announcement has arrived which either presents new // information about a node in one of the channels we know about, or a // updating previously advertised information. - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: return d.handleNodeAnnouncement(ctx, nMsg, msg, schedulerOp) // A new channel announcement has arrived, this indicates the @@ -2248,7 +2249,7 @@ func (d *AuthenticatedGossiper) processZombieUpdate(_ context.Context, // announcement fields and returns an error if they are invalid to prevent // forwarding invalid node announcements to our peers. func (d *AuthenticatedGossiper) fetchNodeAnn(ctx context.Context, - pubKey [33]byte) (*lnwire.NodeAnnouncement, error) { + pubKey [33]byte) (*lnwire.NodeAnnouncement1, error) { node, err := d.cfg.Graph.FetchNode(ctx, pubKey) if err != nil { @@ -2478,12 +2479,12 @@ func (d *AuthenticatedGossiper) latestHeight() uint32 { // handleNodeAnnouncement processes a new node announcement. func (d *AuthenticatedGossiper) handleNodeAnnouncement(ctx context.Context, - nMsg *networkMsg, nodeAnn *lnwire.NodeAnnouncement, + nMsg *networkMsg, nodeAnn *lnwire.NodeAnnouncement1, ops []batch.SchedulerOption) ([]networkMsg, bool) { timestamp := time.Unix(int64(nodeAnn.Timestamp), 0) - log.Debugf("Processing NodeAnnouncement: peer=%v, timestamp=%v, "+ + log.Debugf("Processing NodeAnnouncement1: peer=%v, timestamp=%v, "+ "node=%x, source=%x", nMsg.peer, timestamp, nodeAnn.NodeID, nMsg.source.SerializeCompressed()) @@ -2542,7 +2543,7 @@ func (d *AuthenticatedGossiper) handleNodeAnnouncement(ctx context.Context, nMsg.err <- nil // TODO(roasbeef): get rid of the above - log.Debugf("Processed NodeAnnouncement: peer=%v, timestamp=%v, "+ + log.Debugf("Processed NodeAnnouncement1: peer=%v, timestamp=%v, "+ "node=%x, source=%x", nMsg.peer, timestamp, nodeAnn.NodeID, nMsg.source.SerializeCompressed()) diff --git a/discovery/gossiper_test.go b/discovery/gossiper_test.go index 63369f4d6..521e08963 100644 --- a/discovery/gossiper_test.go +++ b/discovery/gossiper_test.go @@ -493,8 +493,8 @@ func (m *mockNotifier) Stop() error { } type annBatch struct { - nodeAnn1 *lnwire.NodeAnnouncement - nodeAnn2 *lnwire.NodeAnnouncement + nodeAnn1 *lnwire.NodeAnnouncement1 + nodeAnn2 *lnwire.NodeAnnouncement1 chanAnn *lnwire.ChannelAnnouncement1 @@ -577,8 +577,8 @@ func (ctx *testCtx) createAnnouncements(blockHeight uint32, key1, } -func createNodeAnnouncement(priv *btcec.PrivateKey, - timestamp uint32, extraBytes ...[]byte) (*lnwire.NodeAnnouncement, error) { +func createNodeAnnouncement(priv *btcec.PrivateKey, timestamp uint32, + extraBytes ...[]byte) (*lnwire.NodeAnnouncement1, error) { var err error k := hex.EncodeToString(priv.Serialize()) @@ -587,7 +587,7 @@ func createNodeAnnouncement(priv *btcec.PrivateKey, return nil, err } - a := &lnwire.NodeAnnouncement{ + a := &lnwire.NodeAnnouncement1{ Timestamp: timestamp, Addresses: testAddrs, Alias: alias, @@ -966,15 +966,15 @@ func createTestCtx(t *testing.T, startHeight uint32, isChanPeer bool) ( c := make(chan struct{}) return c }, - FetchSelfAnnouncement: func() lnwire.NodeAnnouncement { - return lnwire.NodeAnnouncement{ + FetchSelfAnnouncement: func() lnwire.NodeAnnouncement1 { + return lnwire.NodeAnnouncement1{ Timestamp: testTimestamp, } }, - UpdateSelfAnnouncement: func() (lnwire.NodeAnnouncement, + UpdateSelfAnnouncement: func() (lnwire.NodeAnnouncement1, error) { - return lnwire.NodeAnnouncement{ + return lnwire.NodeAnnouncement1{ Timestamp: testTimestamp, }, nil }, @@ -2285,7 +2285,7 @@ func TestForwardPrivateNodeAnnouncement(t *testing.T) { case <-time.After(2 * trickleDelay): } - // Now, we'll attempt to forward the NodeAnnouncement for the same node + // Now, we'll attempt to forward the NodeAnnouncement1 for the same node // by opening a public channel on the network. We'll create a // ChannelAnnouncement and hand it off to the gossiper in order to // process it. @@ -2312,8 +2312,9 @@ func TestForwardPrivateNodeAnnouncement(t *testing.T) { t.Fatal("gossiper should have broadcast the channel announcement") } - // We'll recreate the NodeAnnouncement with an updated timestamp to - // prevent a stale update. The NodeAnnouncement should now be forwarded. + // We'll recreate the NodeAnnouncement1 with an updated timestamp to + // prevent a stale update. The NodeAnnouncement1 should now be + // forwarded. nodeAnn, err = createNodeAnnouncement(remoteKeyPriv1, timestamp+1) require.NoError(t, err, "unable to create node announcement") @@ -2897,7 +2898,7 @@ func TestExtraDataChannelUpdateValidation(t *testing.T) { } // TestExtraDataNodeAnnouncementValidation tests that we're able to properly -// validate a NodeAnnouncement that includes opaque bytes that we don't +// validate a NodeAnnouncement1 that includes opaque bytes that we don't // currently know of. func TestExtraDataNodeAnnouncementValidation(t *testing.T) { t.Parallel() @@ -3044,7 +3045,7 @@ func TestRetransmit(t *testing.T) { chanAnn++ case *lnwire.ChannelUpdate1: chanUpd++ - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: nodeAnn++ } } diff --git a/discovery/syncer.go b/discovery/syncer.go index b8c51a9a5..1f120b3f8 100644 --- a/discovery/syncer.go +++ b/discovery/syncer.go @@ -1653,7 +1653,7 @@ func (g *GossipSyncer) FilterGossipMsgs(ctx context.Context, // Similarly, we only send node announcements if the update // timestamp ifs between our set gossip filter time range. - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: if passesFilter(msg.Timestamp) { msgsToSend = append(msgsToSend, msg) } diff --git a/discovery/syncer_test.go b/discovery/syncer_test.go index faef40bbe..4420f4aa4 100644 --- a/discovery/syncer_test.go +++ b/discovery/syncer_test.go @@ -249,10 +249,14 @@ func TestGossipSyncerFilterGossipMsgsNoHorizon(t *testing.T) { // through the gossiper to the target peer. msgs := []msgWithSenders{ { - msg: &lnwire.NodeAnnouncement{Timestamp: uint32(time.Now().Unix())}, + msg: &lnwire.NodeAnnouncement1{ + Timestamp: uint32(time.Now().Unix()), + }, }, { - msg: &lnwire.NodeAnnouncement{Timestamp: uint32(time.Now().Unix())}, + msg: &lnwire.NodeAnnouncement1{ + Timestamp: uint32(time.Now().Unix()), + }, }, } @@ -308,15 +312,21 @@ func TestGossipSyncerFilterGossipMsgsAllInMemory(t *testing.T) { msgs := []msgWithSenders{ { // Node ann above horizon. - msg: &lnwire.NodeAnnouncement{Timestamp: unixStamp(25001)}, + msg: &lnwire.NodeAnnouncement1{ + Timestamp: unixStamp(25001), + }, }, { // Node ann below horizon. - msg: &lnwire.NodeAnnouncement{Timestamp: unixStamp(5)}, + msg: &lnwire.NodeAnnouncement1{ + Timestamp: unixStamp(5), + }, }, { // Node ann above horizon. - msg: &lnwire.NodeAnnouncement{Timestamp: unixStamp(999999)}, + msg: &lnwire.NodeAnnouncement1{ + Timestamp: unixStamp(999999), + }, }, { // Ann tuple below horizon. @@ -737,7 +747,7 @@ func TestGossipSyncerReplyShortChanIDs(t *testing.T) { ShortChannelID: lnwire.NewShortChanIDFromInt(20), Timestamp: unixStamp(999999), }, - &lnwire.NodeAnnouncement{Timestamp: unixStamp(25001)}, + &lnwire.NodeAnnouncement1{Timestamp: unixStamp(25001)}, } // We'll then craft a reply to the upcoming query for all the matching diff --git a/discovery/validation_barrier.go b/discovery/validation_barrier.go index 7153dd49e..ebd3fccef 100644 --- a/discovery/validation_barrier.go +++ b/discovery/validation_barrier.go @@ -188,7 +188,7 @@ func (v *ValidationBarrier) InitJobDependencies(job interface{}) (JobID, populateDependencies(msg.ShortChannelID.String(), childJobID) return childJobID, nil - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: childJobID := JobID(v.idCtr.Add(1)) populateDependencies( route.Vertex(msg.NodeID).String(), childJobID, @@ -242,7 +242,7 @@ func (v *ValidationBarrier) WaitForParents(childJobID JobID, v.Lock() switch msg := job.(type) { - // Any ChannelUpdate or NodeAnnouncement jobs will need to wait on the + // Any ChannelUpdate or NodeAnnouncement1 jobs will need to wait on the // completion of any active ChannelAnnouncement jobs related to them. case *lnwire.ChannelUpdate1: annID = msg.ShortChannelID.String() @@ -258,7 +258,7 @@ func (v *ValidationBarrier) WaitForParents(childJobID JobID, jobDesc = fmt.Sprintf("job=lnwire.ChannelUpdate, scid=%v", msg.ShortChannelID.ToUint64()) - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: annID = route.Vertex(msg.NodeID).String() parentJobIDs, ok = v.jobDependencies[childJobID] @@ -269,7 +269,7 @@ func (v *ValidationBarrier) WaitForParents(childJobID JobID, return nil } - jobDesc = fmt.Sprintf("job=lnwire.NodeAnnouncement, pub=%s", + jobDesc = fmt.Sprintf("job=lnwire.NodeAnnouncement1, pub=%s", route.Vertex(msg.NodeID)) // Other types of jobs can be executed immediately, so we'll just @@ -446,7 +446,7 @@ func (v *ValidationBarrier) SignalDependents(job interface{}, id JobID) error { return nil - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: // Remove child job info. return removeJob(route.Vertex(msg.NodeID).String(), id, true) diff --git a/discovery/validation_barrier_test.go b/discovery/validation_barrier_test.go index bc58fe9ec..ee4d2e926 100644 --- a/discovery/validation_barrier_test.go +++ b/discovery/validation_barrier_test.go @@ -186,7 +186,7 @@ func TestValidationBarrierQuit(t *testing.T) { } // TestValidationBarrierParentJobsClear tests that creating two parent jobs for -// ChannelUpdate / NodeAnnouncement will pause child jobs until the set of +// ChannelUpdate / NodeAnnouncement1 will pause child jobs until the set of // parent jobs has cleared. func TestValidationBarrierParentJobsClear(t *testing.T) { t.Parallel() @@ -230,14 +230,14 @@ func TestValidationBarrierParentJobsClear(t *testing.T) { parentID3, err := barrier.InitJobDependencies(ann3) require.NoError(t, err) - // Create the ChannelUpdate & NodeAnnouncement messages. + // Create the ChannelUpdate & NodeAnnouncement1 messages. upd1 := &lnwire.ChannelUpdate1{ ShortChannelID: sharedScid, } childID1, err := barrier.InitJobDependencies(upd1) require.NoError(t, err) - node1 := &lnwire.NodeAnnouncement{ + node1 := &lnwire.NodeAnnouncement1{ NodeID: sharedNodeID, } childID2, err := barrier.InitJobDependencies(node1) diff --git a/funding/manager.go b/funding/manager.go index 4bfb7f9d0..8176e6aa2 100644 --- a/funding/manager.go +++ b/funding/manager.go @@ -398,7 +398,7 @@ type Config struct { // CurrentNodeAnnouncement should return the latest, fully signed node // announcement from the backing Lightning Network node with a fresh // timestamp. - CurrentNodeAnnouncement func() (lnwire.NodeAnnouncement, error) + CurrentNodeAnnouncement func() (lnwire.NodeAnnouncement1, error) // SendAnnouncement is used by the FundingManager to send announcement // messages to the Gossiper to possibly broadcast to the greater @@ -3757,8 +3757,8 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel, shortChanID *lnwire.ShortChannelID) error { // If this channel is not meant to be announced to the greater network, - // we'll only send our NodeAnnouncement to our counterparty to ensure we - // don't leak any of our information. + // we'll only send our NodeAnnouncement1 to our counterparty to ensure + // we don't leak any of our information. announceChan := completeChan.ChannelFlags&lnwire.FFAnnounceChannel != 0 if !announceChan { log.Debugf("Will not announce private channel %v.", @@ -3779,7 +3779,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel, completeChan.FundingOutpoint, ) pubKey := peer.PubKey() - log.Debugf("Sending our NodeAnnouncement for "+ + log.Debugf("Sending our NodeAnnouncement1 for "+ "ChannelID(%v) to %x", chanID, pubKey) // TODO(halseth): make reliable. If the peer is not online this @@ -4724,7 +4724,7 @@ func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey, graph.ErrIgnored) { log.Debugf("Graph rejected "+ - "NodeAnnouncement: %v", err) + "NodeAnnouncement1: %v", err) } else { log.Errorf("Unable to send node "+ "announcement: %v", err) diff --git a/funding/manager_test.go b/funding/manager_test.go index 57d9299d2..45b847ffd 100644 --- a/funding/manager_test.go +++ b/funding/manager_test.go @@ -485,10 +485,10 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey, } return errChan }, - CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, + CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement1, error) { - return lnwire.NodeAnnouncement{}, nil + return lnwire.NodeAnnouncement1{}, nil }, TempChanIDSeed: chanIDSeed, FindChannel: func(node *btcec.PublicKey, @@ -660,10 +660,10 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) { } return errChan }, - CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, + CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement1, error) { - return lnwire.NodeAnnouncement{}, nil + return lnwire.NodeAnnouncement1{}, nil }, NotifyWhenOnline: func(peer [33]byte, connectedChan chan<- lnpeer.Peer) { @@ -1328,9 +1328,9 @@ func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) { // by having the nodes exchange announcement signatures. // Two distinct messages will be sent: // 1) AnnouncementSignatures - // 2) NodeAnnouncement + // 2) NodeAnnouncement1 // These may arrive in no particular order. - // Note that sending the NodeAnnouncement at this point is an + // Note that sending the NodeAnnouncement1 at this point is an // implementation detail, and not something required by the LN spec. for j, node := range []*testNode{alice, bob} { announcements := make([]lnwire.Message, 2) @@ -1348,7 +1348,7 @@ func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) { switch msg.(type) { case *lnwire.AnnounceSignatures1: gotAnnounceSignatures = true - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: gotNodeAnnouncement = true } } @@ -1358,7 +1358,8 @@ func assertAnnouncementSignatures(t *testing.T, alice, bob *testNode) { j) } if !gotNodeAnnouncement { - t.Fatalf("did not get NodeAnnouncement from node %d", j) + t.Fatalf("did not get NodeAnnouncement1 from node %d", + j) } } } @@ -1378,7 +1379,7 @@ func assertNodeAnnSent(t *testing.T, alice, bob *testNode) { node.msgChan, time.Second*5, ) require.NoError(t, err) - assertType[*lnwire.NodeAnnouncement](t, *nodeAnn) + assertType[*lnwire.NodeAnnouncement1](t, *nodeAnn) } } @@ -2959,7 +2960,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) { // We should however receive each side's node announcement. select { case msg := <-alice.msgChan: - if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + if _, ok := msg.(*lnwire.NodeAnnouncement1); !ok { t.Fatalf("expected to receive node announcement") } case <-time.After(time.Second): @@ -2968,7 +2969,7 @@ func TestFundingManagerPrivateChannel(t *testing.T) { select { case msg := <-bob.msgChan: - if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + if _, ok := msg.(*lnwire.NodeAnnouncement1); !ok { t.Fatalf("expected to receive node announcement") } case <-time.After(time.Second): @@ -3085,7 +3086,7 @@ func TestFundingManagerPrivateRestart(t *testing.T) { // We should however receive each side's node announcement. select { case msg := <-alice.msgChan: - if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + if _, ok := msg.(*lnwire.NodeAnnouncement1); !ok { t.Fatalf("expected to receive node announcement") } case <-time.After(time.Second): @@ -3094,7 +3095,7 @@ func TestFundingManagerPrivateRestart(t *testing.T) { select { case msg := <-bob.msgChan: - if _, ok := msg.(*lnwire.NodeAnnouncement); !ok { + if _, ok := msg.(*lnwire.NodeAnnouncement1); !ok { t.Fatalf("expected to receive node announcement") } case <-time.After(time.Second): diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index 774492786..482c1aa18 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -4754,10 +4754,10 @@ func TestLightningNodePersistence(t *testing.T) { require.NoError(t, err) // Use the raw serialized node announcement message create an - // lnwire.NodeAnnouncement instance. + // lnwire.NodeAnnouncement1 instance. msg, err := lnwire.ReadMessage(bytes.NewBuffer(nodeAnnBytes), 0) require.NoError(t, err) - na, ok := msg.(*lnwire.NodeAnnouncement) + na, ok := msg.(*lnwire.NodeAnnouncement1) require.True(t, ok) // Convert the wire message to our internal node representation. diff --git a/graph/db/models/node.go b/graph/db/models/node.go index ba4437c0a..23d6a4268 100644 --- a/graph/db/models/node.go +++ b/graph/db/models/node.go @@ -96,7 +96,7 @@ func (l *Node) AddPubKey(key *btcec.PublicKey) { } // NodeAnnouncement retrieves the latest node announcement of the node. -func (l *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement, +func (l *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement1, error) { if !l.HaveNodeAnnouncement { @@ -108,7 +108,7 @@ func (l *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement, return nil, err } - nodeAnn := &lnwire.NodeAnnouncement{ + nodeAnn := &lnwire.NodeAnnouncement1{ Features: l.Features.RawFeatureVector, NodeID: l.PubKeyBytes, RGBColor: l.Color, @@ -133,8 +133,8 @@ func (l *Node) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement, } // NodeFromWireAnnouncement creates a Node instance from an -// lnwire.NodeAnnouncement message. -func NodeFromWireAnnouncement(msg *lnwire.NodeAnnouncement) *Node { +// lnwire.NodeAnnouncement1 message. +func NodeFromWireAnnouncement(msg *lnwire.NodeAnnouncement1) *Node { timestamp := time.Unix(int64(msg.Timestamp), 0) features := lnwire.NewFeatureVector(msg.Features, lnwire.Features) diff --git a/lnrpc/peersrpc/config_active.go b/lnrpc/peersrpc/config_active.go index 6b9ef6d26..fec8affda 100644 --- a/lnrpc/peersrpc/config_active.go +++ b/lnrpc/peersrpc/config_active.go @@ -19,7 +19,7 @@ import ( type Config struct { // GetNodeAnnouncement is used to send our retrieve the current // node announcement information. - GetNodeAnnouncement func() lnwire.NodeAnnouncement + GetNodeAnnouncement func() lnwire.NodeAnnouncement1 // ParseAddr parses an address from its string format to a net.Addr. ParseAddr func(addr string) (net.Addr, error) diff --git a/lnwire/channel_announcement_2.go b/lnwire/channel_announcement_2.go index 94474d957..a82624a51 100644 --- a/lnwire/channel_announcement_2.go +++ b/lnwire/channel_announcement_2.go @@ -56,6 +56,9 @@ type ChannelAnnouncement2 struct { // the funding output is a pure 2-of-2 MuSig aggregate public key. MerkleRootHash tlv.OptionalRecordT[tlv.TlvType16, [32]byte] + // Outpoint is the outpoint of the funding transaction. + Outpoint tlv.RecordT[tlv.TlvType18, OutPoint] + // Signature is a Schnorr signature over serialised signed-range TLV // stream of the message. Signature tlv.RecordT[tlv.TlvType160, Sig] @@ -81,17 +84,17 @@ func (c *ChannelAnnouncement2) Encode(w *bytes.Buffer, _ uint32) error { // NOTE: this is part of the PureTLVMessage interface. func (c *ChannelAnnouncement2) AllRecords() []tlv.Record { recordProducers := append( - c.allNonSignatureRecordProducers(), &c.Signature, + c.nonSignatureRecordProducers(), &c.Signature, ) return ProduceRecordsSorted(recordProducers...) } -// allNonSignatureRecordProducers returns all the TLV record producers for the +// nonSignatureRecordProducers returns all the TLV record producers for the // message except the signature record producer. // //nolint:ll -func (c *ChannelAnnouncement2) allNonSignatureRecordProducers() []tlv.RecordProducer { +func (c *ChannelAnnouncement2) nonSignatureRecordProducers() []tlv.RecordProducer { // The chain-hash record is only included if it is _not_ equal to the // bitcoin mainnet genisis block hash. var recordProducers []tlv.RecordProducer @@ -121,6 +124,7 @@ func (c *ChannelAnnouncement2) allNonSignatureRecordProducers() []tlv.RecordProd }, ) + recordProducers = append(recordProducers, &c.Outpoint) recordProducers = append(recordProducers, RecordsAsProducers( tlv.MapToRecords(c.ExtraSignedFields), )...) @@ -149,6 +153,7 @@ func (c *ChannelAnnouncement2) Decode(r io.Reader, _ uint32) error { &btcKey1, &btcKey2, &merkleRootHash, + &c.Outpoint, &c.Signature, )...) if err != nil { @@ -202,6 +207,7 @@ func (c *ChannelAnnouncement2) DecodeNonSigTLVRecords(r io.Reader) error { &btcKey1, &btcKey2, &merkleRootHash, + &c.Outpoint, )...) if err != nil { return err @@ -239,7 +245,7 @@ func (c *ChannelAnnouncement2) DecodeNonSigTLVRecords(r io.Reader) error { // excludes the signature field. func (c *ChannelAnnouncement2) EncodeAllNonSigFields(w io.Writer) error { return EncodeRecordsTo( - w, ProduceRecordsSorted(c.allNonSignatureRecordProducers()...), + w, ProduceRecordsSorted(c.nonSignatureRecordProducers()...), ) } diff --git a/lnwire/channel_announcement_2_test.go b/lnwire/channel_announcement_2_test.go index 40d255b55..3a2ce28a9 100644 --- a/lnwire/channel_announcement_2_test.go +++ b/lnwire/channel_announcement_2_test.go @@ -58,6 +58,17 @@ func TestChanAnn2EncodeDecode(t *testing.T) { 0xb3, 0xee, 0x17, 0x2f, 0x7f, 0x16, 0x1, 0xe6, 0x7d, 0x1d, 0xa6, 0xca, 0xd4, 0xb, 0x54, 0xc4, 0x46, 0x8d, 0x48, 0x23, 0x6c, 0x39, + // Outpoint record. + 0x12, // type (18). + 0x22, // length (34 bytes). + // Hash (32 bytes). + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + // Index (2 bytes). + 0x30, 0x39, // value: 12345. + // Unknown TLV record. 0x6f, // type. 0x2, // length. diff --git a/lnwire/channel_update_2.go b/lnwire/channel_update_2.go index b832bc58d..7fe7670ed 100644 --- a/lnwire/channel_update_2.go +++ b/lnwire/channel_update_2.go @@ -70,6 +70,11 @@ type ChannelUpdate2 struct { // millionth of a satoshi. FeeProportionalMillionths tlv.RecordT[tlv.TlvType18, uint32] + // InboundFee is an optional TLV record that contains the fee + // information for incoming HTLCs. + // TODO(elle): assign normal tlv type? + InboundFee tlv.OptionalRecordT[tlv.TlvType55555, Fee] + // Signature is used to validate the announced data and prove the // ownership of node id. Signature tlv.RecordT[tlv.TlvType160, Sig] @@ -102,12 +107,13 @@ func (c *ChannelUpdate2) Decode(r io.Reader, _ uint32) error { var ( chainHash = tlv.ZeroRecordT[tlv.TlvType0, [32]byte]() secondPeer = tlv.ZeroRecordT[tlv.TlvType8, TrueBoolean]() + inboundFee = tlv.ZeroRecordT[tlv.TlvType55555, Fee]() ) typeMap, err := tlvRecords.ExtractRecords( &chainHash, &c.ShortChannelID, &c.BlockHeight, &c.DisabledFlags, &secondPeer, &c.CLTVExpiryDelta, &c.HTLCMinimumMsat, &c.HTLCMaximumMsat, &c.FeeBaseMsat, - &c.FeeProportionalMillionths, + &c.FeeProportionalMillionths, &inboundFee, &c.Signature, ) if err != nil { @@ -149,6 +155,11 @@ func (c *ChannelUpdate2) Decode(r io.Reader, _ uint32) error { c.FeeProportionalMillionths.Val = defaultFeeProportionalMillionths //nolint:ll } + // If the inbound fee was encoded, set it. + if _, ok := typeMap[c.InboundFee.TlvType()]; ok { + c.InboundFee = tlv.SomeRecordT(inboundFee) + } + c.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap) return nil @@ -207,6 +218,10 @@ func (c *ChannelUpdate2) AllRecords() []tlv.Record { ) } + c.InboundFee.WhenSome(func(r tlv.RecordT[tlv.TlvType55555, Fee]) { + recordProducers = append(recordProducers, &r) + }) + recordProducers = append(recordProducers, RecordsAsProducers( tlv.MapToRecords(c.ExtraSignedFields), )...) diff --git a/lnwire/dns_addr.go b/lnwire/dns_addr.go index 87ddcd8cd..ed0c6fade 100644 --- a/lnwire/dns_addr.go +++ b/lnwire/dns_addr.go @@ -1,10 +1,14 @@ package lnwire import ( + "bytes" "errors" "fmt" + "io" "net" "strconv" + + "github.com/lightningnetwork/lnd/tlv" ) var ( @@ -86,3 +90,70 @@ func ValidateDNSAddr(hostname string, port uint16) error { return nil } + +// Record returns a TLV record that can be used to encode/decode the DNSAddress. +// +// NOTE: this is part of the tlv.RecordProducer interface. +func (d *DNSAddress) Record() tlv.Record { + sizeFunc := func() uint64 { + // Hostname length + 2 bytes for port. + return uint64(len(d.Hostname) + 2) + } + + return tlv.MakeDynamicRecord( + 0, d, sizeFunc, dnsAddressEncoder, dnsAddressDecoder, + ) +} + +// dnsAddressEncoder is a TLV encoder for DNSAddress. +func dnsAddressEncoder(w io.Writer, val any, _ *[8]byte) error { + if v, ok := val.(*DNSAddress); ok { + var buf bytes.Buffer + + // Write the hostname as raw bytes (no length prefix for TLV). + if _, err := buf.WriteString(v.Hostname); err != nil { + return err + } + + // Write the port as 2 bytes. + err := WriteUint16(&buf, v.Port) + if err != nil { + return err + } + + _, err = w.Write(buf.Bytes()) + + return err + } + + return tlv.NewTypeForEncodingErr(val, "DNSAddress") +} + +// dnsAddressDecoder is a TLV decoder for DNSAddress. +func dnsAddressDecoder(r io.Reader, val any, _ *[8]byte, + l uint64) error { + + if v, ok := val.(*DNSAddress); ok { + if l < 2 { + return fmt.Errorf("DNS address must be at least 2 " + + "bytes") + } + + // Read hostname (all bytes except last 2). + hostnameLen := l - 2 + hostnameBytes := make([]byte, hostnameLen) + if _, err := io.ReadFull(r, hostnameBytes); err != nil { + return err + } + v.Hostname = string(hostnameBytes) + + // Read port (last 2 bytes). + if err := ReadElement(r, &v.Port); err != nil { + return err + } + + return ValidateDNSAddr(v.Hostname, v.Port) + } + + return tlv.NewTypeForDecodingErr(val, "DNSAddress", l, 0) +} diff --git a/lnwire/dns_addr_test.go b/lnwire/dns_addr_test.go index 8cdf2a858..1808fa8dd 100644 --- a/lnwire/dns_addr_test.go +++ b/lnwire/dns_addr_test.go @@ -1,11 +1,14 @@ package lnwire import ( + "bytes" "fmt" "strings" "testing" + "github.com/lightningnetwork/lnd/tlv" "github.com/stretchr/testify/require" + "pgregory.net/rapid" ) // TestValidateDNSAddr tests hostname and port validation per BOLT #7. @@ -85,3 +88,112 @@ func TestValidateDNSAddr(t *testing.T) { }) } } + +// TestDNSAddressTLVEncoding tests the TLV encoding and decoding of DNSAddress +// structs using the ExtraOpaqueData interface. +func TestDNSAddressTLVEncoding(t *testing.T) { + t.Parallel() + + testDNSAddr := DNSAddress{ + Hostname: "lightning.example.com", + Port: 9000, + } + + var extraData ExtraOpaqueData + require.NoError(t, extraData.PackRecords(&testDNSAddr)) + + var decodedDNSAddr DNSAddress + tlvs, err := extraData.ExtractRecords(&decodedDNSAddr) + require.NoError(t, err) + + require.Contains(t, tlvs, tlv.Type(0)) + require.Equal(t, testDNSAddr, decodedDNSAddr) +} + +// TestDNSAddressRecord tests the TLV Record interface of DNSAddress +// by directly encoding and decoding using the Record method. +func TestDNSAddressRecord(t *testing.T) { + t.Parallel() + + testDNSAddr := DNSAddress{ + Hostname: "lightning.example.com", + Port: 9000, + } + + var buf bytes.Buffer + record := testDNSAddr.Record() + require.NoError(t, record.Encode(&buf)) + + var decodedDNSAddr DNSAddress + decodedRecord := decodedDNSAddr.Record() + require.NoError(t, decodedRecord.Decode(&buf, uint64(buf.Len()))) + + require.Equal(t, testDNSAddr, decodedDNSAddr) +} + +// TestDNSAddressInvalidDecoding tests error cases during TLV decoding. +func TestDNSAddressInvalidDecoding(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + data []byte + errMsg string + }{ + { + name: "too short (only 1 byte)", + data: []byte{0x61}, + errMsg: "DNS address must be at least 2 bytes", + }, + { + name: "empty data", + data: []byte{}, + errMsg: "DNS address must be at least 2 bytes", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var dnsAddr DNSAddress + record := dnsAddr.Record() + + buf := bytes.NewReader(tc.data) + err := record.Decode(buf, uint64(len(tc.data))) + require.Error(t, err) + require.ErrorContains(t, err, tc.errMsg) + }) + } +} + +// TestDNSAddressProperty uses property-based testing to verify that DNSAddress +// TLV encoding and decoding is correct for random DNSAddress values. +func TestDNSAddressProperty(t *testing.T) { + t.Parallel() + + scenario := func(t *rapid.T) { + // Generate a random valid hostname. + hostname := genValidHostname(t) + + // Generate a random port (excluding 0 which is invalid). + port := rapid.Uint16Range(1, 65535).Draw(t, "port") + + dnsAddr := DNSAddress{ + Hostname: hostname, + Port: port, + } + + var buf bytes.Buffer + record := dnsAddr.Record() + err := record.Encode(&buf) + require.NoError(t, err) + + var decodedDNSAddr DNSAddress + decodedRecord := decodedDNSAddr.Record() + err = decodedRecord.Decode(&buf, uint64(buf.Len())) + require.NoError(t, err) + + require.Equal(t, dnsAddr, decodedDNSAddr) + } + + rapid.Check(t, scenario) +} diff --git a/lnwire/fuzz_test.go b/lnwire/fuzz_test.go index 054af585c..a143ce6d9 100644 --- a/lnwire/fuzz_test.go +++ b/lnwire/fuzz_test.go @@ -220,10 +220,10 @@ func FuzzNodeAnnouncement(f *testing.F) { // can be represented by different underlying bytes. Instead, we // compare the normalized string representation of each address. assertEq := func(t *testing.T, x, y any) { - require.IsType(t, &NodeAnnouncement{}, x) - first, _ := x.(*NodeAnnouncement) - require.IsType(t, &NodeAnnouncement{}, y) - second, _ := y.(*NodeAnnouncement) + require.IsType(t, &NodeAnnouncement1{}, x) + first, _ := x.(*NodeAnnouncement1) + require.IsType(t, &NodeAnnouncement1{}, y) + second, _ := y.(*NodeAnnouncement1) require.Equal( t, len(first.Addresses), len(second.Addresses), @@ -244,6 +244,30 @@ func FuzzNodeAnnouncement(f *testing.F) { }) } +func FuzzNodeAnnouncement2(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + // We can't use require.Equal for Features, since we consider + // the empty map and nil to be equivalent. + assertEq := func(t *testing.T, x, y any) { + require.IsType(t, &NodeAnnouncement2{}, x) + first, _ := x.(*NodeAnnouncement2) + require.IsType(t, &NodeAnnouncement2{}, y) + second, _ := y.(*NodeAnnouncement2) + + require.True( + t, + first.Features.Val.Equals(&second.Features.Val), + ) + first.Features.Val = *NewRawFeatureVector() + second.Features.Val = *NewRawFeatureVector() + + require.Equal(t, first, second) + } + + wireMsgHarnessCustom(t, data, MsgNodeAnnouncement2, assertEq) + }) +} + func FuzzOpenChannel(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { // We can't use require.Equal for UpfrontShutdownScript, since diff --git a/lnwire/message.go b/lnwire/message.go index a36359f0b..c64b09b12 100644 --- a/lnwire/message.go +++ b/lnwire/message.go @@ -64,6 +64,7 @@ const ( MsgReplyChannelRange = 264 MsgGossipTimestampRange = 265 MsgChannelAnnouncement2 = 267 + MsgNodeAnnouncement2 = 269 MsgChannelUpdate2 = 271 MsgKickoffSig = 777 @@ -166,7 +167,7 @@ func (t MessageType) String() string { case MsgChannelUpdate: return "ChannelUpdate" case MsgNodeAnnouncement: - return "NodeAnnouncement" + return "NodeAnnouncement1" case MsgPing: return "Ping" case MsgAnnounceSignatures: @@ -193,6 +194,8 @@ func (t MessageType) String() string { return "MsgAnnounceSignatures2" case MsgChannelAnnouncement2: return "ChannelAnnouncement2" + case MsgNodeAnnouncement2: + return "NodeAnnouncement2" case MsgChannelUpdate2: return "ChannelUpdate2" default: @@ -330,7 +333,7 @@ func makeEmptyMessage(msgType MessageType) (Message, error) { case MsgChannelUpdate: msg = &ChannelUpdate1{} case MsgNodeAnnouncement: - msg = &NodeAnnouncement{} + msg = &NodeAnnouncement1{} case MsgPing: msg = &Ping{} case MsgAnnounceSignatures: @@ -355,6 +358,8 @@ func makeEmptyMessage(msgType MessageType) (Message, error) { msg = &AnnounceSignatures2{} case MsgChannelAnnouncement2: msg = &ChannelAnnouncement2{} + case MsgNodeAnnouncement2: + msg = &NodeAnnouncement2{} case MsgChannelUpdate2: msg = &ChannelUpdate2{} default: diff --git a/lnwire/message_test.go b/lnwire/message_test.go index 4f95cb0ef..f1232e85f 100644 --- a/lnwire/message_test.go +++ b/lnwire/message_test.go @@ -670,11 +670,11 @@ func newMsgChannelAnnouncement(t testing.TB, } func newMsgNodeAnnouncement(t testing.TB, - r *rand.Rand) *lnwire.NodeAnnouncement { + r *rand.Rand) *lnwire.NodeAnnouncement1 { t.Helper() - msg := &lnwire.NodeAnnouncement{ + msg := &lnwire.NodeAnnouncement1{ Features: rawFeatureVector(), Timestamp: uint32(r.Int31()), Alias: randAlias(r), diff --git a/lnwire/node_announcement.go b/lnwire/node_announcement.go index d3502a7d9..0a7c60542 100644 --- a/lnwire/node_announcement.go +++ b/lnwire/node_announcement.go @@ -62,11 +62,11 @@ func (n NodeAlias) String() string { return string(bytes.Trim(n[:], "\x00")) } -// NodeAnnouncement message is used to announce the presence of a Lightning +// NodeAnnouncement1 message is used to announce the presence of a Lightning // node and also to signal that the node is accepting incoming connections. -// Each NodeAnnouncement authenticating the advertised information within the +// Each NodeAnnouncement1 authenticating the advertised information within the // announcement via a signature using the advertised node pubkey. -type NodeAnnouncement struct { +type NodeAnnouncement1 struct { // Signature is used to prove the ownership of node id. Signature Sig @@ -100,19 +100,19 @@ type NodeAnnouncement struct { ExtraOpaqueData ExtraOpaqueData } -// A compile time check to ensure NodeAnnouncement implements the +// A compile time check to ensure NodeAnnouncement1 implements the // lnwire.Message interface. -var _ Message = (*NodeAnnouncement)(nil) +var _ Message = (*NodeAnnouncement1)(nil) -// A compile time check to ensure NodeAnnouncement implements the +// A compile time check to ensure NodeAnnouncement1 implements the // lnwire.SizeableMessage interface. -var _ SizeableMessage = (*NodeAnnouncement)(nil) +var _ SizeableMessage = (*NodeAnnouncement1)(nil) -// Decode deserializes a serialized NodeAnnouncement stored in the passed +// Decode deserializes a serialized NodeAnnouncement1 stored in the passed // io.Reader observing the specified protocol version. // // This is part of the lnwire.Message interface. -func (a *NodeAnnouncement) Decode(r io.Reader, _ uint32) error { +func (a *NodeAnnouncement1) Decode(r io.Reader, _ uint32) error { err := ReadElements(r, &a.Signature, &a.Features, @@ -130,11 +130,11 @@ func (a *NodeAnnouncement) Decode(r io.Reader, _ uint32) error { return a.ExtraOpaqueData.ValidateTLV() } -// Encode serializes the target NodeAnnouncement into the passed io.Writer +// Encode serializes the target NodeAnnouncement1 into the passed io.Writer // observing the protocol version specified. // // This is part of the lnwire.Message interface. -func (a *NodeAnnouncement) Encode(w *bytes.Buffer, pver uint32) error { +func (a *NodeAnnouncement1) Encode(w *bytes.Buffer, pver uint32) error { if err := WriteSig(w, a.Signature); err != nil { return err } @@ -170,13 +170,12 @@ func (a *NodeAnnouncement) Encode(w *bytes.Buffer, pver uint32) error { // wire. // // This is part of the lnwire.Message interface. -func (a *NodeAnnouncement) MsgType() MessageType { +func (a *NodeAnnouncement1) MsgType() MessageType { return MsgNodeAnnouncement } // DataToSign returns the part of the message that should be signed. -func (a *NodeAnnouncement) DataToSign() ([]byte, error) { - +func (a *NodeAnnouncement1) DataToSign() ([]byte, error) { // We should not include the signatures itself. buffer := make([]byte, 0, MaxMsgBody) buf := bytes.NewBuffer(buffer) @@ -215,6 +214,6 @@ func (a *NodeAnnouncement) DataToSign() ([]byte, error) { // SerializedSize returns the serialized size of the message in bytes. // // This is part of the lnwire.SizeableMessage interface. -func (a *NodeAnnouncement) SerializedSize() (uint32, error) { +func (a *NodeAnnouncement1) SerializedSize() (uint32, error) { return MessageSerializedSize(a) } diff --git a/lnwire/node_announcement_2.go b/lnwire/node_announcement_2.go new file mode 100644 index 000000000..23fcc509f --- /dev/null +++ b/lnwire/node_announcement_2.go @@ -0,0 +1,581 @@ +package lnwire + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "image/color" + "io" + "net" + "unicode/utf8" + + "github.com/lightningnetwork/lnd/tlv" + "github.com/lightningnetwork/lnd/tor" +) + +// NodeAnnouncement2 message is used to announce the presence of a Lightning +// node and also to signal that the node is accepting incoming connections. +// Each NodeAnnouncement2 authenticating the advertised information within the +// announcement via a signature using the advertised node pubkey. +type NodeAnnouncement2 struct { + // Features is the feature vector that encodes the features supported + // by the target node. + Features tlv.RecordT[tlv.TlvType0, RawFeatureVector] + + // Color is an optional field used to customize a node's appearance in + // maps and graphs. + Color tlv.OptionalRecordT[tlv.TlvType1, Color] + + // BlockHeight allows ordering in the case of multiple announcements. We + // should ignore the message if block height is not greater than the + // last-received. The block height must always be greater or equal to + // the block height that the channel funding transaction was confirmed + // in. + BlockHeight tlv.RecordT[tlv.TlvType2, uint32] + + // Alias is used to customize their node's appearance in maps and + // graphs. + Alias tlv.OptionalRecordT[tlv.TlvType3, NodeAlias2] + + // NodeID is the public key of the node creating the announcement. + NodeID tlv.RecordT[tlv.TlvType4, [33]byte] + + // IPV4Addrs is an optional list of ipv4 addresses that the node is + // reachable at. + IPV4Addrs tlv.OptionalRecordT[tlv.TlvType5, IPV4Addrs] + + // IPV6Addrs is an optional list of ipv6 addresses that the node is + // reachable at. + IPV6Addrs tlv.OptionalRecordT[tlv.TlvType7, IPV6Addrs] + + // TorV3Addrs is an optional list of tor v3 addresses that the node is + // reachable at. + TorV3Addrs tlv.OptionalRecordT[tlv.TlvType9, TorV3Addrs] + + // DNSHostName is an optional DNS hostname that the node is reachable + // at. + DNSHostName tlv.OptionalRecordT[tlv.TlvType11, DNSAddress] + + // Signature is used to validate the announced data and prove the + // ownership of node id. + Signature tlv.RecordT[tlv.TlvType160, Sig] + + // Any extra fields in the signed range that we do not yet know about, + // but we need to keep them for signature validation and to produce a + // valid message. + ExtraSignedFields +} + +// SerializedSize returns the serialized size of the message in bytes. +// +// This is part of the lnwire.SizeableMessage interface. +func (n *NodeAnnouncement2) SerializedSize() (uint32, error) { + return MessageSerializedSize(n) +} + +// AllRecords returns all the TLV records for the message. This will include all +// the records we know about along with any that we don't know about but that +// fall in the signed TLV range. +// +// NOTE: this is part of the PureTLVMessage interface. +func (n *NodeAnnouncement2) AllRecords() []tlv.Record { + recordProducers := []tlv.RecordProducer{ + &n.Features, + &n.BlockHeight, + &n.NodeID, + &n.Signature, + } + + n.Color.WhenSome(func(r tlv.RecordT[tlv.TlvType1, Color]) { + recordProducers = append(recordProducers, &r) + }) + + n.Alias.WhenSome(func(a tlv.RecordT[tlv.TlvType3, NodeAlias2]) { + recordProducers = append(recordProducers, &a) + }) + + n.IPV4Addrs.WhenSome(func(r tlv.RecordT[tlv.TlvType5, IPV4Addrs]) { + recordProducers = append(recordProducers, &r) + }) + + n.IPV6Addrs.WhenSome(func(r tlv.RecordT[tlv.TlvType7, IPV6Addrs]) { + recordProducers = append(recordProducers, &r) + }) + + n.TorV3Addrs.WhenSome(func(r tlv.RecordT[tlv.TlvType9, TorV3Addrs]) { + recordProducers = append(recordProducers, &r) + }) + + n.DNSHostName.WhenSome(func(r tlv.RecordT[tlv.TlvType11, DNSAddress]) { + recordProducers = append(recordProducers, &r) + }) + + recordProducers = append(recordProducers, RecordsAsProducers( + tlv.MapToRecords(n.ExtraSignedFields), + )...) + + return ProduceRecordsSorted(recordProducers...) +} + +// Decode deserializes a serialized NodeAnnouncement2 stored in the passed +// io.Reader observing the specified protocol version. +// +// This is part of the lnwire.Message interface. +func (n *NodeAnnouncement2) Decode(r io.Reader, _ uint32) error { + var ( + color = tlv.ZeroRecordT[tlv.TlvType1, Color]() + alias = tlv.ZeroRecordT[tlv.TlvType3, NodeAlias2]() + ipv4 = tlv.ZeroRecordT[tlv.TlvType5, IPV4Addrs]() + ipv6 = tlv.ZeroRecordT[tlv.TlvType7, IPV6Addrs]() + torV3 = tlv.ZeroRecordT[tlv.TlvType9, TorV3Addrs]() + dns = tlv.ZeroRecordT[tlv.TlvType11, DNSAddress]() + ) + + stream, err := tlv.NewStream(ProduceRecordsSorted( + &n.Features, + &n.BlockHeight, + &n.NodeID, + &n.Signature, + &alias, + &color, + &ipv4, + &ipv6, + &torV3, + &dns, + )...) + if err != nil { + return err + } + n.Signature.Val.ForceSchnorr() + + typeMap, err := stream.DecodeWithParsedTypesP2P(r) + if err != nil { + return err + } + + if _, ok := typeMap[n.Alias.TlvType()]; ok { + n.Alias = tlv.SomeRecordT(alias) + } + + if _, ok := typeMap[n.Color.TlvType()]; ok { + n.Color = tlv.SomeRecordT(color) + } + + if _, ok := typeMap[n.IPV4Addrs.TlvType()]; ok { + n.IPV4Addrs = tlv.SomeRecordT(ipv4) + } + + if _, ok := typeMap[n.IPV6Addrs.TlvType()]; ok { + n.IPV6Addrs = tlv.SomeRecordT(ipv6) + } + + if _, ok := typeMap[n.TorV3Addrs.TlvType()]; ok { + n.TorV3Addrs = tlv.SomeRecordT(torV3) + } + + if _, ok := typeMap[n.DNSHostName.TlvType()]; ok { + n.DNSHostName = tlv.SomeRecordT(dns) + } + + n.ExtraSignedFields = ExtraSignedFieldsFromTypeMap(typeMap) + + return nil +} + +// Encode serializes the target NodeAnnouncement2 into the passed io.Writer +// observing the protocol version specified. +// +// This is part of the lnwire.Message interface. +func (n *NodeAnnouncement2) Encode(w *bytes.Buffer, _ uint32) error { + return EncodePureTLVMessage(n, w) +} + +// MsgType returns the integer uniquely identifying this message type on the +// wire. +// +// This is part of the lnwire.Message interface. +func (n *NodeAnnouncement2) MsgType() MessageType { + return MsgNodeAnnouncement2 +} + +// A compile-time check to ensure NodeAnnouncement2 implements the Message +// interface. +var _ Message = (*NodeAnnouncement2)(nil) + +// A compile-time check to ensure NodeAnnouncement2 implements the +// PureTLVMessage interface. +var _ PureTLVMessage = (*NodeAnnouncement2)(nil) + +// A compile time check to ensure ChannelAnnouncement2 implements the +// lnwire.SizeableMessage interface. +var _ SizeableMessage = (*NodeAnnouncement2)(nil) + +// NodeAlias2 represents a UTF-8 encoded node alias with a maximum length of 32 +// bytes. +type NodeAlias2 []byte + +// Record returns a TLV record for encoding/decoding NodeAlias2. +func (n *NodeAlias2) Record() tlv.Record { + sizeFunc := func() uint64 { + return uint64(len(*n)) + } + + return tlv.MakeDynamicRecord( + 0, n, sizeFunc, nodeAlias2Encoder, nodeAlias2Decoder, + ) +} + +// ValidateNodeAlias2 validates that the node alias is valid UTF-8 and within +// the 32-byte limit. +func ValidateNodeAlias2(alias []byte) error { + if len(alias) == 0 { + return errors.New("node alias cannot be empty") + } + + if len(alias) > 32 { + return fmt.Errorf("node alias exceeds 32 bytes: length %d", + len(alias)) + } + + if !utf8.Valid(alias) { + return errors.New("node alias contains invalid UTF-8") + } + + return nil +} + +// nodeAlias2Encoder encodes a NodeAlias2 as raw UTF-8 bytes. +func nodeAlias2Encoder(w io.Writer, val any, _ *[8]byte) error { + if v, ok := val.(*NodeAlias2); ok { + if err := ValidateNodeAlias2(*v); err != nil { + return err + } + + _, err := w.Write(*v) + + return err + } + + return tlv.NewTypeForEncodingErr(val, "NodeAlias2") +} + +// nodeAlias2Decoder decodes raw bytes into a NodeAlias2. +func nodeAlias2Decoder(r io.Reader, val any, _ *[8]byte, l uint64) error { + if v, ok := val.(*NodeAlias2); ok { + if l > 32 { + return fmt.Errorf("node alias exceeds 32 bytes: %d", l) + } + + aliasBytes := make([]byte, l) + if _, err := io.ReadFull(r, aliasBytes); err != nil { + return err + } + + if err := ValidateNodeAlias2(aliasBytes); err != nil { + return err + } + + *v = aliasBytes + + return nil + } + + return tlv.NewTypeForDecodingErr(val, "NodeAlias2", l, 0) +} + +// Color is a custom type to represent a color.RGBA that can be encoded/decoded +// as a TLV record. +type Color color.RGBA + +// Record returns a TLV record for encoding/decoding Color. +func (c *Color) Record() tlv.Record { + return tlv.MakeStaticRecord(0, c, 3, rgbEncoder, rgbDecoder) +} + +// rgbEncoder encodes a Color as RGB bytes. +func rgbEncoder(w io.Writer, val any, _ *[8]byte) error { + if v, ok := val.(*Color); ok { + buf := bytes.NewBuffer(nil) + err := WriteColorRGBA(buf, color.RGBA(*v)) + if err != nil { + return err + } + _, err = w.Write(buf.Bytes()) + + return err + } + + return tlv.NewTypeForEncodingErr(val, "Color") +} + +// rgbDecoder decodes RGB bytes into a Color. +func rgbDecoder(r io.Reader, val any, _ *[8]byte, l uint64) error { + if v, ok := val.(*Color); ok { + return ReadElements(r, &v.R, &v.G, &v.B) + } + + return tlv.NewTypeForDecodingErr(val, "Color", l, 3) +} + +// ipv4AddrEncodedSize is the number of bytes required to encode a single ipv4 +// address. Four bytes are used to encode the IP address and two bytes for the +// port number. +const ipv4AddrEncodedSize = 4 + 2 + +// IPV4Addrs is a list of ipv4 addresses that can be encoded as a TLV record. +type IPV4Addrs []*net.TCPAddr + +// Record returns a Record that can be used to encode/decode a IPV4Addrs +// to/from a TLV stream. +func (a *IPV4Addrs) Record() tlv.Record { + return tlv.MakeDynamicRecord( + 0, a, a.encodedSize, ipv4AddrsEncoder, ipv4AddrsDecoder, + ) +} + +// encodedSize returns the number of bytes required to encode an IPV4Addrs +// variable. +func (a *IPV4Addrs) encodedSize() uint64 { + return uint64(len(*a) * ipv4AddrEncodedSize) +} + +// ipv4AddrsEncoder encodes IPv4 addresses as TLV bytes. +func ipv4AddrsEncoder(w io.Writer, val interface{}, _ *[8]byte) error { + if v, ok := val.(*IPV4Addrs); ok { + for _, ip := range *v { + _, err := w.Write(ip.IP.To4()) + if err != nil { + return err + } + var port [2]byte + binary.BigEndian.PutUint16(port[:], uint16(ip.Port)) + _, err = w.Write(port[:]) + if err != nil { + return err + } + } + + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.IPV4Addrs") +} + +// ipv4AddrsDecoder decodes TLV bytes into IPv4 addresses. +func ipv4AddrsDecoder(r io.Reader, val interface{}, _ *[8]byte, + l uint64) error { + + if v, ok := val.(*IPV4Addrs); ok { + if l%(ipv4AddrEncodedSize) != 0 { + return fmt.Errorf("invalid ipv4 list encoding") + } + var ( + numAddrs = int(l / ipv4AddrEncodedSize) + addrs = make([]*net.TCPAddr, 0, numAddrs) + ip [4]byte + port [2]byte + ) + for len(addrs) < numAddrs { + _, err := r.Read(ip[:]) + if err != nil { + return err + } + _, err = r.Read(port[:]) + if err != nil { + return err + } + addrs = append(addrs, &net.TCPAddr{ + IP: ip[:], + Port: int(binary.BigEndian.Uint16(port[:])), + }) + } + *v = addrs + + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.IPV4Addrs") +} + +// IPV6Addrs is a list of ipv6 addresses that can be encoded as a TLV record. +type IPV6Addrs []*net.TCPAddr + +// Record returns a Record that can be used to encode/decode a IPV4Addrs +// to/from a TLV stream. +func (a *IPV6Addrs) Record() tlv.Record { + return tlv.MakeDynamicRecord( + 0, a, a.encodedSize, ipv6AddrsEncoder, ipv6AddrsDecoder, + ) +} + +// ipv6AddrEncodedSize is the number of bytes required to encode a single ipv6 +// address. Sixteen bytes are used to encode the IP address and two bytes for +// the port number. +const ipv6AddrEncodedSize = 16 + 2 + +// encodedSize returns the number of bytes required to encode an IPV6Addrs +// variable. +func (a *IPV6Addrs) encodedSize() uint64 { + return uint64(len(*a) * ipv6AddrEncodedSize) +} + +// ipv6AddrsEncoder encodes IPv6 addresses as TLV bytes. +func ipv6AddrsEncoder(w io.Writer, val interface{}, _ *[8]byte) error { + if v, ok := val.(*IPV6Addrs); ok { + for _, ip := range *v { + _, err := w.Write(ip.IP.To16()) + if err != nil { + return err + } + var port [2]byte + binary.BigEndian.PutUint16(port[:], uint16(ip.Port)) + _, err = w.Write(port[:]) + if err != nil { + return err + } + } + + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.IPV6Addrs") +} + +// ipv6AddrsDecoder decodes TLV bytes into IPv6 addresses. +func ipv6AddrsDecoder(r io.Reader, val interface{}, _ *[8]byte, + l uint64) error { + + if v, ok := val.(*IPV6Addrs); ok { + if l%(ipv6AddrEncodedSize) != 0 { + return fmt.Errorf("invalid ipv6 list encoding") + } + var ( + numAddrs = int(l / ipv6AddrEncodedSize) + addrs = make([]*net.TCPAddr, 0, numAddrs) + ip [16]byte + port [2]byte + ) + for len(addrs) < numAddrs { + _, err := r.Read(ip[:]) + if err != nil { + return err + } + _, err = r.Read(port[:]) + if err != nil { + return err + } + addrs = append(addrs, &net.TCPAddr{ + IP: ip[:], + Port: int(binary.BigEndian.Uint16(port[:])), + }) + } + *v = addrs + + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.IPV6Addrs") +} + +// TorV3Addrs is a list of tor v3 addresses that can be encoded as a TLV record. +type TorV3Addrs []*tor.OnionAddr + +// torV3AddrEncodedSize is the number of bytes required to encode a single tor +// v3 address. +const torV3AddrEncodedSize = tor.V3DecodedLen + 2 + +// encodedSize returns the number of bytes required to encode an TorV3Addrs +// variable. +func (a *TorV3Addrs) encodedSize() uint64 { + return uint64(len(*a) * torV3AddrEncodedSize) +} + +// Record returns a Record that can be used to encode/decode a IPV4Addrs +// to/from a TLV stream. +func (a *TorV3Addrs) Record() tlv.Record { + return tlv.MakeDynamicRecord( + 0, a, a.encodedSize, torV3AddrsEncoder, torV3AddrsDecoder, + ) +} + +// torV3AddrsEncoder encodes Tor v3 addresses as TLV bytes. +func torV3AddrsEncoder(w io.Writer, val interface{}, _ *[8]byte) error { + if v, ok := val.(*TorV3Addrs); ok { + for _, addr := range *v { + encodedHostLen := tor.V3Len - tor.OnionSuffixLen + host, err := tor.Base32Encoding.DecodeString( + addr.OnionService[:encodedHostLen], + ) + if err != nil { + return err + } + + if len(host) != tor.V3DecodedLen { + return fmt.Errorf("expected a tor v3 host "+ + "length of %d, got: %d", + tor.V3DecodedLen, len(host)) + } + + if _, err = w.Write(host); err != nil { + return err + } + + var port [2]byte + binary.BigEndian.PutUint16(port[:], uint16(addr.Port)) + if _, err = w.Write(port[:]); err != nil { + return err + } + } + + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.TorV3Addrs") +} + +// torV3AddrsDecoder decodes TLV bytes into Tor v3 addresses. +func torV3AddrsDecoder(r io.Reader, val interface{}, _ *[8]byte, + l uint64) error { + + if v, ok := val.(*TorV3Addrs); ok { + if l%torV3AddrEncodedSize != 0 { + return fmt.Errorf("invalid tor v3 list encoding") + } + var ( + numAddrs = int(l / torV3AddrEncodedSize) + addrs = make([]*tor.OnionAddr, 0, numAddrs) + ip [tor.V3DecodedLen]byte + p [2]byte + ) + for len(addrs) < numAddrs { + _, err := r.Read(ip[:]) + if err != nil { + return err + } + _, err = r.Read(p[:]) + if err != nil { + return err + } + onionService := tor.Base32Encoding.EncodeToString(ip[:]) + onionService += tor.OnionSuffix + + if len(onionService) != tor.V3Len { + return fmt.Errorf("expected a tor v3 onion "+ + "service length of %d, got: %d", + tor.V3Len, len(onionService)) + } + + port := int(binary.BigEndian.Uint16(p[:])) + addrs = append(addrs, &tor.OnionAddr{ + OnionService: onionService, + Port: port, + }) + } + *v = addrs + + return nil + } + + return tlv.NewTypeForEncodingErr(val, "lnwire.TorV3Addrs") +} diff --git a/lnwire/node_announcement_2_test.go b/lnwire/node_announcement_2_test.go new file mode 100644 index 000000000..0aea66147 --- /dev/null +++ b/lnwire/node_announcement_2_test.go @@ -0,0 +1,119 @@ +package lnwire + +import ( + "bytes" + "testing" + + "github.com/lightningnetwork/lnd/tlv" + "github.com/stretchr/testify/require" +) + +// TestNodeAnn2EncodeDecode tests the encoding and decoding of the +// NodeAnnouncement2 message using hardcoded byte slices. +func TestNodeAnn2EncodeDecode(t *testing.T) { + t.Parallel() + + // We'll create a raw byte stream that represents a valid + // NodeAnnouncement2 message with various known and unknown fields in + // the signed TLV ranges along with the signature in the unsigned range. + rawBytes := []byte{ + // Features record. + 0x00, // type. + 0x02, // length. + 0x1, 0x2, // value. + + // Color record (optional). + 0x01, // type. + 0x03, // length. + 0xff, 0x00, 0x80, // value: RGB(255, 0, 128). + + // BlockHeight record. + 0x02, // type. + 0x04, // length. + 0x00, 0x01, 0x86, 0xa0, // value: 100000. + + // Alias record (optional). + 0x03, // type. + 0x20, // length (32). + 0x4c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, + 0x67, 0x20, 0x4e, 0x6f, 0x64, 0x65, 0x20, 0x54, + 0x65, 0x73, 0x74, 0x20, 0x41, 0x6c, 0x69, 0x61, + 0x73, 0x20, 0x4e, 0x61, 0x6d, 0x65, 0x21, 0x00, // value. + + // NodeID record. + 0x04, // type. + 0x21, // length. + 0x02, 0x28, 0xf2, 0xaf, 0xa, 0xbe, 0x32, 0x24, 0x3, 0x48, 0xf, + 0xb3, 0xee, 0x17, 0x2f, 0x7f, 0x16, 0x1, 0xe6, 0x7d, 0x1d, 0xa6, + 0xca, 0xd4, 0xb, 0x54, 0xc4, 0x46, 0x8d, 0x48, 0x23, 0x6c, 0x39, + + // IPV4Addrs record (optional). + 0x05, // type. + 0x0c, // length (12 bytes). + 0x0a, 0x00, 0x00, 0x01, 0x23, 0x28, // 10.0.0.1:9000 + 0x0a, 0x00, 0x00, 0x01, 0x1f, 0x90, // 10.0.0.1:8080 + + // IPV6Addrs record (optional). + 0x07, // type. + 0x12, // length. + 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, // IPv6 address + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // 2001:db8::1 + 0x1f, 0x40, // port 8000 + + // TorV3Addrs record (optional). + 0x09, // type. + 0x25, // length (37 bytes = 1 address). + // value: 35-byte tor v3 address + 2-byte port. + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, + 0x23, 0x28, // port 9000. + + // DNSHostName record (optional). + 0x0b, // type (11). + 0x17, // length (23). + 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x6e, + 0x67, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, // value. + 0x65, 0x2e, 0x63, 0x6f, 0x6d, + 0x23, 0x28, // port 9000. + + // Signature. + 0xa0, // type. + 0x40, // length. + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, + 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, + 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, // value. + } + secondSignedRangeType := new(bytes.Buffer) + var buf [8]byte + err := tlv.WriteVarInt( + secondSignedRangeType, pureTLVSignedSecondRangeStart+1, &buf, + ) + require.NoError(t, err) + rawBytes = append(rawBytes, secondSignedRangeType.Bytes()...) // type. + rawBytes = append(rawBytes, []byte{ + 0x02, // length. + 0x79, 0x79, // value. + }...) + + // Now, create a new empty message and decode the raw bytes into it. + msg := &NodeAnnouncement2{} + r := bytes.NewReader(rawBytes) + err = msg.Decode(r, 0) + require.NoError(t, err) + + // Next, encode the message back into a new byte buffer. + var b bytes.Buffer + err = msg.Encode(&b, 0) + require.NoError(t, err) + + // The re-encoded bytes should be exactly the same as the original raw + // bytes. + require.Equal(t, rawBytes, b.Bytes()) +} diff --git a/lnwire/outpoint.go b/lnwire/outpoint.go new file mode 100644 index 000000000..ec893ee65 --- /dev/null +++ b/lnwire/outpoint.go @@ -0,0 +1,53 @@ +package lnwire + +import ( + "bytes" + "io" + + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/tlv" +) + +// OutPoint describes an outpoint of a transaction via its transaction hash +// and the outpoint index. This is a thin wrapper around the wire.OutPoint to +// provide TLV encoding/decoding. +type OutPoint wire.OutPoint + +// Record returns a TLV record that can be used to encode/decode the OutPoint. +// +// NOTE: this is part of the tlv.RecordProducer interface. +func (o *OutPoint) Record() tlv.Record { + return tlv.MakeStaticRecord(0, o, 34, outpointEncoder, outpointDecoder) +} + +// outpointEncoder is a TLV encoder for OutPoint. +func outpointEncoder(w io.Writer, val any, _ *[8]byte) error { + if v, ok := val.(*OutPoint); ok { + buf := bytes.NewBuffer(nil) + err := WriteOutPoint(buf, wire.OutPoint(*v)) + if err != nil { + return err + } + _, err = w.Write(buf.Bytes()) + + return err + } + + return tlv.NewTypeForEncodingErr(val, "OutPoint") +} + +// outpointDecoder is a TLV decoder for OutPoint. +func outpointDecoder(r io.Reader, val any, _ *[8]byte, l uint64) error { + if v, ok := val.(*OutPoint); ok { + var o wire.OutPoint + if err := ReadElement(r, &o); err != nil { + return err + } + + *v = OutPoint(o) + + return nil + } + + return tlv.NewTypeForDecodingErr(val, "OutPoint", l, 34) +} diff --git a/lnwire/outpoint_test.go b/lnwire/outpoint_test.go new file mode 100644 index 000000000..b8ac1a70d --- /dev/null +++ b/lnwire/outpoint_test.go @@ -0,0 +1,107 @@ +package lnwire + +import ( + "bytes" + "testing" + + "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/wire" + "github.com/lightningnetwork/lnd/tlv" + "github.com/stretchr/testify/require" + "pgregory.net/rapid" +) + +// TestOutPointTLVEncoding tests the TLV encoding and decoding of OutPoint +// structs using the Record interface. +func TestOutPointTLVEncoding(t *testing.T) { + t.Parallel() + + testOutPoint := OutPoint(wire.OutPoint{ + Hash: chainhash.Hash{ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + }, + Index: 12345, + }) + + var extraData ExtraOpaqueData + require.NoError(t, extraData.PackRecords(&testOutPoint)) + + var decodedOutPoint OutPoint + tlvs, err := extraData.ExtractRecords(&decodedOutPoint) + require.NoError(t, err) + + require.Contains(t, tlvs, tlv.Type(0)) + require.Equal(t, testOutPoint, decodedOutPoint) +} + +// TestOutPointRecord tests the TLV Record interface of OutPoint +// by directly encoding and decoding using the Record method. +func TestOutPointRecord(t *testing.T) { + t.Parallel() + + testOutPoint := OutPoint(wire.OutPoint{ + Hash: chainhash.Hash{ + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8, + 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, + }, + Index: 65535, + }) + + var buf bytes.Buffer + record := testOutPoint.Record() + require.NoError(t, record.Encode(&buf)) + + var decodedOutPoint OutPoint + decodedRecord := decodedOutPoint.Record() + require.NoError(t, decodedRecord.Decode(&buf, uint64(buf.Len()))) + + require.Equal(t, testOutPoint, decodedOutPoint) +} + +// TestOutPointProperty uses property-based testing to verify that OutPoint +// TLV encoding and decoding is correct for random OutPoint values. +func TestOutPointProperty(t *testing.T) { + t.Parallel() + + scenario := func(t *rapid.T) { + wireOutPoint := RandOutPoint(t) + lnOutPoint := OutPoint(wireOutPoint) + + var buf bytes.Buffer + record := lnOutPoint.Record() + err := record.Encode(&buf) + require.NoError(t, err) + + var decodedOutPoint OutPoint + decodedRecord := decodedOutPoint.Record() + err = decodedRecord.Decode(&buf, uint64(buf.Len())) + require.NoError(t, err) + + require.Equal(t, lnOutPoint, decodedOutPoint) + require.Equal(t, wireOutPoint, wire.OutPoint(decodedOutPoint)) + } + + rapid.Check(t, scenario) +} + +// TestOutPointZeroValues tests that OutPoint handles zero values correctly. +func TestOutPointZeroValues(t *testing.T) { + t.Parallel() + + zeroOutPoint := OutPoint(wire.OutPoint{}) + + var buf bytes.Buffer + record := zeroOutPoint.Record() + require.NoError(t, record.Encode(&buf)) + + var decodedOutPoint OutPoint + decodedRecord := decodedOutPoint.Record() + require.NoError(t, decodedRecord.Decode(&buf, uint64(buf.Len()))) + + require.Equal(t, zeroOutPoint, decodedOutPoint) +} diff --git a/lnwire/test_message.go b/lnwire/test_message.go index 0c2fe5e55..4e62bee98 100644 --- a/lnwire/test_message.go +++ b/lnwire/test_message.go @@ -5,12 +5,14 @@ import ( "fmt" "image/color" "math" + "net" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/lightningnetwork/lnd/fn/v2" "github.com/lightningnetwork/lnd/tlv" + "github.com/lightningnetwork/lnd/tor" "github.com/stretchr/testify/require" "pgregory.net/rapid" ) @@ -291,6 +293,10 @@ func (c *ChannelAnnouncement2) RandTestMessage(t *rapid.T) Message { ) } + msg.Outpoint = tlv.NewRecordT[tlv.TlvType18, OutPoint]( + OutPoint(RandOutPoint(t)), + ) + return msg } @@ -565,6 +571,18 @@ func (c *ChannelUpdate2) RandTestMessage(t *rapid.T) Message { ExtraSignedFields: make(map[uint64][]byte), } + if rapid.Bool().Draw(t, "includeInboundFee") { + base := rapid.IntRange(-1000, 1000).Draw(t, "inFeeBase") + rate := rapid.IntRange(-1000, 1000).Draw(t, "inFeeProp") + fee := Fee{ + BaseFee: int32(base), + FeeRate: int32(rate), + } + msg.InboundFee = tlv.SomeRecordT( + tlv.NewRecordT[tlv.TlvType55555](fee), + ) + } + msg.Signature.Val = RandSignature(t) msg.Signature.Val.ForceSchnorr() @@ -1211,15 +1229,19 @@ func (ks *KickoffSig) RandTestMessage(t *rapid.T) Message { } } -// A compile time check to ensure NodeAnnouncement implements the +// A compile time check to ensure NodeAnnouncement1 implements the // lnwire.TestMessage interface. -var _ TestMessage = (*NodeAnnouncement)(nil) +var _ TestMessage = (*NodeAnnouncement1)(nil) + +// A compile time check to ensure NodeAnnouncement2 implements the +// lnwire.TestMessage interface. +var _ TestMessage = (*NodeAnnouncement2)(nil) // RandTestMessage populates the message with random data suitable for testing. // It uses the rapid testing framework to generate random values. // // This is part of the TestMessage interface. -func (a *NodeAnnouncement) RandTestMessage(t *rapid.T) Message { +func (a *NodeAnnouncement1) RandTestMessage(t *rapid.T) Message { // Generate random compressed public key for node ID pubKey := RandPubKey(t) var nodeID [33]byte @@ -1232,7 +1254,7 @@ func (a *NodeAnnouncement) RandTestMessage(t *rapid.T) Message { B: uint8(rapid.IntRange(0, 255).Draw(t, "rgbB")), } - return &NodeAnnouncement{ + return &NodeAnnouncement1{ Signature: RandSignature(t), Features: RandFeatureVector(t), Timestamp: uint32(rapid.IntRange(0, 0x7FFFFFFF).Draw( @@ -1246,6 +1268,131 @@ func (a *NodeAnnouncement) RandTestMessage(t *rapid.T) Message { } } +// RandTestMessage populates the message with random data suitable for testing. +// It uses the rapid testing framework to generate random values. +// +// This is part of the TestMessage interface. +func (n *NodeAnnouncement2) RandTestMessage(t *rapid.T) Message { + features := RandFeatureVector(t) + blockHeight := uint32(rapid.IntRange(0, 1000000).Draw(t, "blockHeight")) + + // Generate random compressed public key for node ID + pubKey := RandPubKey(t) + var nodeID [33]byte + copy(nodeID[:], pubKey.SerializeCompressed()) + + msg := &NodeAnnouncement2{ + Features: tlv.NewRecordT[tlv.TlvType0](*features), + BlockHeight: tlv.NewPrimitiveRecord[tlv.TlvType2]( + blockHeight, + ), + NodeID: tlv.NewPrimitiveRecord[tlv.TlvType4](nodeID), + ExtraSignedFields: make(map[uint64][]byte), + } + + msg.Signature.Val = RandSignature(t) + msg.Signature.Val.ForceSchnorr() + + // Test optional fields one by one + if rapid.Bool().Draw(t, "includeColor") { + rgbColor := Color{ + R: uint8(rapid.IntRange(0, 255).Draw(t, "rgbR")), + G: uint8(rapid.IntRange(0, 255).Draw(t, "rgbG")), + B: uint8(rapid.IntRange(0, 255).Draw(t, "rgbB")), + } + colorRecord := tlv.ZeroRecordT[tlv.TlvType1, Color]() + colorRecord.Val = rgbColor + msg.Color = tlv.SomeRecordT(colorRecord) + } + + if rapid.Bool().Draw(t, "includeAlias") { + aliasBytes := RandNodeAlias2(t) + aliasRecord := tlv.ZeroRecordT[tlv.TlvType3, NodeAlias2]() + aliasRecord.Val = aliasBytes + msg.Alias = tlv.SomeRecordT(aliasRecord) + } + + if rapid.Bool().Draw(t, "includeIPV4Addrs") { + ipv4Addrs := make(IPV4Addrs, 1) + ip := make(net.IP, 4) + ip[0] = uint8(rapid.IntRange(1, 223).Draw(t, "ip4_0")) + ip[1] = uint8(rapid.IntRange(0, 255).Draw(t, "ip4_1")) + ip[2] = uint8(rapid.IntRange(0, 255).Draw(t, "ip4_2")) + ip[3] = uint8(rapid.IntRange(1, 254).Draw(t, "ip4_3")) + + ipv4Addrs[0] = &net.TCPAddr{ + IP: ip, + Port: rapid.IntRange(1, 65535).Draw(t, "port4"), + } + + ipv4Record := tlv.ZeroRecordT[tlv.TlvType5, IPV4Addrs]() + ipv4Record.Val = ipv4Addrs + msg.IPV4Addrs = tlv.SomeRecordT(ipv4Record) + } + + if rapid.Bool().Draw(t, "includeIPV6Addrs") { + ipv6Addrs := make(IPV6Addrs, 1) + ip := make(net.IP, 16) + // Generate random IPv6 address. + for j := 0; j < 16; j++ { + ip[j] = uint8(rapid.IntRange(0, 255).Draw( + t, fmt.Sprintf("ip6_%d", j)), + ) + } + + ipv6Addrs[0] = &net.TCPAddr{ + IP: ip, + Port: rapid.IntRange(1, 65535).Draw(t, "port6"), + } + + ipv6Record := tlv.ZeroRecordT[tlv.TlvType7, IPV6Addrs]() + ipv6Record.Val = ipv6Addrs + msg.IPV6Addrs = tlv.SomeRecordT(ipv6Record) + } + + if rapid.Bool().Draw(t, "includeTorV3Addrs") { + torV3Addrs := make(TorV3Addrs, 1) + onionBytes := rapid.SliceOfN(rapid.Byte(), 35, 35).Draw( + t, "onion", + ) + onionService := tor.Base32Encoding.EncodeToString(onionBytes) + + tor.OnionSuffix + + torV3Addrs[0] = &tor.OnionAddr{ + OnionService: onionService, + Port: rapid.IntRange(1, 65535).Draw( + t, "torPort", + ), + } + + torV3Record := tlv.ZeroRecordT[tlv.TlvType9, TorV3Addrs]() + torV3Record.Val = torV3Addrs + msg.TorV3Addrs = tlv.SomeRecordT(torV3Record) + } + + if rapid.Bool().Draw(t, "includeDNSHostName") { + // Generate a valid DNS hostname. + hostname := genValidHostname(t) + port := rapid.Uint16Range(1, 65535).Draw(t, "dnsPort") + + dnsAddr := DNSAddress{ + Hostname: hostname, + Port: port, + } + + dnsRecord := tlv.ZeroRecordT[tlv.TlvType11, DNSAddress]() + dnsRecord.Val = dnsAddr + msg.DNSHostName = tlv.SomeRecordT(dnsRecord) + } + + randRecs, _ := RandSignedRangeRecords(t) + if len(randRecs) > 0 { + msg.ExtraSignedFields = ExtraSignedFields(randRecs) + } + + return msg +} + // A compile time check to ensure OpenChannel implements the TestMessage // interface. var _ TestMessage = (*OpenChannel)(nil) @@ -1851,3 +1998,24 @@ func (c *Error) RandTestMessage(t *rapid.T) Message { return msg } + +// genValidHostname generates a random valid hostname according to BOLT #7 +// rules. +func genValidHostname(t *rapid.T) string { + // Valid characters: a-z, A-Z, 0-9, -, . + validChars := "abcdefghijklmnopqrstuvwxyzABCDE" + + "FGHIJKLMNOPQRSTUVWXYZ0123456789-." + + // Generate hostname length between 1 and 255 characters. + length := rapid.IntRange(1, 255).Draw(t, "hostname_length") + + hostname := make([]byte, length) + for i := 0; i < length; i++ { + charIndex := rapid.IntRange(0, len(validChars)-1).Draw( + t, fmt.Sprintf("char_%d", i), + ) + hostname[i] = validChars[charIndex] + } + + return string(hostname) +} diff --git a/lnwire/test_utils.go b/lnwire/test_utils.go index 4c88687d1..ed8623034 100644 --- a/lnwire/test_utils.go +++ b/lnwire/test_utils.go @@ -152,6 +152,19 @@ func RandNodeAlias(t *rapid.T) NodeAlias { return alias } +// RandNodeAlias2 generates a random node alias that is compatible with +// NodeAlias2 validation (non-empty, max 32 bytes, valid UTF-8). +func RandNodeAlias2(t *rapid.T) NodeAlias2 { + // Ensure length is at least 1 to satisfy NodeAlias2 validation + aliasLength := rapid.IntRange(1, 32).Draw(t, "aliasLength") + + aliasBytes := rapid.SliceOfN( + rapid.SampledFrom([]rune(charset)), aliasLength, aliasLength, + ).Draw(t, "alias") + + return []byte(string(aliasBytes)) +} + // RandNetAddrs generates random network addresses. func RandNetAddrs(t *rapid.T) []net.Addr { numAddresses := rapid.IntRange(0, 5).Draw(t, "numAddresses") diff --git a/netann/host_ann.go b/netann/host_ann.go index 95ba277b5..9612f1ccb 100644 --- a/netann/host_ann.go +++ b/netann/host_ann.go @@ -22,8 +22,8 @@ type HostAnnouncerConfig struct { LookupHost func(string) (net.Addr, error) // AdvertisedIPs is the set of IPs that we've already announced with - // our current NodeAnnouncement. This set will be constructed to avoid - // unnecessary node NodeAnnouncement updates. + // our current NodeAnnouncement1. This set will be constructed to avoid + // unnecessary node NodeAnnouncement1 updates. AdvertisedIPs map[string]struct{} // AnnounceNewIPs announces a new set of IP addresses for the backing @@ -36,7 +36,7 @@ type HostAnnouncerConfig struct { // HostAnnouncer is a sub-system that allows a user to specify a set of hosts // for lnd that will be continually resolved to notice any IP address changes. // If the target IP address for a host changes, then we'll generate a new -// NodeAnnouncement that includes these new IPs. +// NodeAnnouncement1 that includes these new IPs. type HostAnnouncer struct { cfg HostAnnouncerConfig @@ -171,7 +171,7 @@ func (h *HostAnnouncer) hostWatcher() { // announcement on disk. It returns the updated node announcement given a set // of updates to be applied to the current node announcement. type NodeAnnUpdater func(modifier ...NodeAnnModifier, -) (lnwire.NodeAnnouncement, error) +) (lnwire.NodeAnnouncement1, error) // IPAnnouncer is a factory function that generates a new function that uses // the passed annUpdater function to to announce new IP changes for a given @@ -181,7 +181,7 @@ func IPAnnouncer(annUpdater NodeAnnUpdater) func([]net.Addr, return func(newAddrs []net.Addr, oldAddrs map[string]struct{}) error { _, err := annUpdater(func( - currentNodeAnn *lnwire.NodeAnnouncement) { + currentNodeAnn *lnwire.NodeAnnouncement1) { // To ensure we don't duplicate any addresses, we'll // filter out the same of addresses we should no longer // advertise. diff --git a/netann/node_announcement.go b/netann/node_announcement.go index 893e9fc4a..b2d288bf7 100644 --- a/netann/node_announcement.go +++ b/netann/node_announcement.go @@ -16,37 +16,39 @@ import ( ) // NodeAnnModifier is a closure that makes in-place modifications to an -// lnwire.NodeAnnouncement. -type NodeAnnModifier func(*lnwire.NodeAnnouncement) +// lnwire.NodeAnnouncement1. +type NodeAnnModifier func(*lnwire.NodeAnnouncement1) // NodeAnnSetAlias is a functional option that sets the alias of the // given node announcement. -func NodeAnnSetAlias(alias lnwire.NodeAlias) func(*lnwire.NodeAnnouncement) { - return func(nodeAnn *lnwire.NodeAnnouncement) { +func NodeAnnSetAlias(alias lnwire.NodeAlias) func(*lnwire.NodeAnnouncement1) { + return func(nodeAnn *lnwire.NodeAnnouncement1) { nodeAnn.Alias = alias } } // 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) { +func NodeAnnSetAddrs(addrs []net.Addr) func(*lnwire.NodeAnnouncement1) { + return func(nodeAnn *lnwire.NodeAnnouncement1) { nodeAnn.Addresses = addrs } } // NodeAnnSetColor is a functional option that sets the color of the // given node announcement. -func NodeAnnSetColor(newColor color.RGBA) func(*lnwire.NodeAnnouncement) { - return func(nodeAnn *lnwire.NodeAnnouncement) { +func NodeAnnSetColor(newColor color.RGBA) func(*lnwire.NodeAnnouncement1) { + return func(nodeAnn *lnwire.NodeAnnouncement1) { nodeAnn.RGBColor = newColor } } // NodeAnnSetFeatures is a functional option that allows updating the features of // the given node announcement. -func NodeAnnSetFeatures(features *lnwire.RawFeatureVector) func(*lnwire.NodeAnnouncement) { - return func(nodeAnn *lnwire.NodeAnnouncement) { +func NodeAnnSetFeatures( + features *lnwire.RawFeatureVector) func(*lnwire.NodeAnnouncement1) { + + return func(nodeAnn *lnwire.NodeAnnouncement1) { nodeAnn.Features = features } } @@ -54,7 +56,7 @@ func NodeAnnSetFeatures(features *lnwire.RawFeatureVector) func(*lnwire.NodeAnno // 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) { +func NodeAnnSetTimestamp(nodeAnn *lnwire.NodeAnnouncement1) { newTimestamp := uint32(time.Now().Unix()) if newTimestamp <= nodeAnn.Timestamp { // Increment the prior value to ensure the timestamp @@ -65,11 +67,11 @@ func NodeAnnSetTimestamp(nodeAnn *lnwire.NodeAnnouncement) { nodeAnn.Timestamp = newTimestamp } -// SignNodeAnnouncement signs the lnwire.NodeAnnouncement provided, which +// SignNodeAnnouncement signs the lnwire.NodeAnnouncement1 provided, which // should be the most recent, valid update, otherwise the timestamp may not // monotonically increase from the prior. func SignNodeAnnouncement(signer lnwallet.MessageSigner, - keyLoc keychain.KeyLocator, nodeAnn *lnwire.NodeAnnouncement) error { + keyLoc keychain.KeyLocator, nodeAnn *lnwire.NodeAnnouncement1) error { // Create the DER-encoded ECDSA signature over the message digest. sig, err := SignAnnouncement(signer, keyLoc, nodeAnn) @@ -83,7 +85,7 @@ func SignNodeAnnouncement(signer lnwallet.MessageSigner, } // ValidateNodeAnn validates the fields and signature of a node announcement. -func ValidateNodeAnn(a *lnwire.NodeAnnouncement) error { +func ValidateNodeAnn(a *lnwire.NodeAnnouncement1) error { err := ValidateNodeAnnFields(a) if err != nil { return fmt.Errorf("invalid node announcement fields: %w", err) @@ -93,7 +95,7 @@ func ValidateNodeAnn(a *lnwire.NodeAnnouncement) error { } // ValidateNodeAnnFields validates the fields of a node announcement. -func ValidateNodeAnnFields(a *lnwire.NodeAnnouncement) error { +func ValidateNodeAnnFields(a *lnwire.NodeAnnouncement1) error { // Check that it only has at most one DNS address. hasDNSAddr := false for _, addr := range a.Addresses { @@ -120,7 +122,7 @@ func ValidateNodeAnnFields(a *lnwire.NodeAnnouncement) error { // ValidateNodeAnnSignature validates the node announcement by ensuring that the // attached signature is needed a signature of the node announcement under the // specified node public key. -func ValidateNodeAnnSignature(a *lnwire.NodeAnnouncement) error { +func ValidateNodeAnnSignature(a *lnwire.NodeAnnouncement1) error { // Reconstruct the data of announcement which should be covered by the // signature so we can verify the signature shortly below data, err := a.DataToSign() @@ -146,7 +148,7 @@ func ValidateNodeAnnSignature(a *lnwire.NodeAnnouncement) error { return err } - return fmt.Errorf("signature on NodeAnnouncement(%x) is "+ + return fmt.Errorf("signature on NodeAnnouncement1(%x) is "+ "invalid: %x", nodeKey.SerializeCompressed(), msgBuf.Bytes()) } diff --git a/netann/sign.go b/netann/sign.go index 0c7612eac..6d92c123a 100644 --- a/netann/sign.go +++ b/netann/sign.go @@ -24,7 +24,7 @@ func SignAnnouncement(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator, data, err = m.DataToSign() case *lnwire.ChannelUpdate1: data, err = m.DataToSign() - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: data, err = m.DataToSign() default: return nil, fmt.Errorf("can't sign %T message", m) diff --git a/peer/brontide.go b/peer/brontide.go index d1f9ef111..9191cbb2e 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -329,7 +329,7 @@ type Config struct { // GenNodeAnnouncement is used to send our node announcement to the remote // on startup. GenNodeAnnouncement func(...netann.NodeAnnModifier) ( - lnwire.NodeAnnouncement, error) + lnwire.NodeAnnouncement1, error) // PrunePersistentPeerConnection is used to remove all internal state // related to this peer in the server. @@ -2092,7 +2092,7 @@ out: idleTimer.Reset(idleTimeout) continue - // If the NodeAnnouncement has an invalid alias, then + // If the NodeAnnouncement1 has an invalid alias, then // we'll log that error above and continue so we can // continue to read messages from the peer. We do not // store this error because it is of little debugging @@ -2213,7 +2213,7 @@ out: case *lnwire.ChannelUpdate1, *lnwire.ChannelAnnouncement1, - *lnwire.NodeAnnouncement, + *lnwire.NodeAnnouncement1, *lnwire.AnnounceSignatures1, *lnwire.GossipTimestampRange, *lnwire.QueryShortChanIDs, @@ -2494,7 +2494,7 @@ func messageSummary(msg lnwire.Message) string { msg.ShortChannelID.ToUint64(), msg.MessageFlags, msg.ChannelFlags, time.Unix(int64(msg.Timestamp), 0)) - case *lnwire.NodeAnnouncement: + case *lnwire.NodeAnnouncement1: return fmt.Sprintf("node=%x, update_time=%v", msg.NodeID, time.Unix(int64(msg.Timestamp), 0)) diff --git a/server.go b/server.go index a48405e5c..a2d36eb86 100644 --- a/server.go +++ b/server.go @@ -400,7 +400,7 @@ type server struct { // currentNodeAnn is the node announcement that has been broadcast to // the network upon startup, if the attributes of the node (us) has // changed since last start. - currentNodeAnn *lnwire.NodeAnnouncement + currentNodeAnn *lnwire.NodeAnnouncement1 // chansToRestore is the set of channels that upon starting, the server // should attempt to restore/recover. @@ -1069,7 +1069,7 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr, NotifyWhenOnline: s.NotifyWhenOnline, NotifyWhenOffline: s.NotifyWhenOffline, FetchSelfAnnouncement: s.getNodeAnnouncement, - UpdateSelfAnnouncement: func() (lnwire.NodeAnnouncement, + UpdateSelfAnnouncement: func() (lnwire.NodeAnnouncement1, error) { return s.genNodeAnnouncement(nil) @@ -1466,7 +1466,7 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr, ChannelDB: s.chanStateDB, FeeEstimator: cc.FeeEstimator, SignMessage: cc.MsgSigner.SignMessage, - CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, + CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement1, error) { return s.genNodeAnnouncement(nil) @@ -1796,7 +1796,7 @@ func newServer(ctx context.Context, cfg *Config, listenAddrs []net.Addr, AdvertisedIPs: advertisedIPs, AnnounceNewIPs: netann.IPAnnouncer( func(modifier ...netann.NodeAnnModifier) ( - lnwire.NodeAnnouncement, error) { + lnwire.NodeAnnouncement1, error) { return s.genNodeAnnouncement( nil, modifier..., @@ -3306,7 +3306,7 @@ func (s *server) createNewHiddenService(ctx context.Context) error { // Now that the onion service has been created, we'll add the onion // address it can be reached at to our list of advertised addresses. newNodeAnn, err := s.genNodeAnnouncement( - nil, func(currentAnn *lnwire.NodeAnnouncement) { + nil, func(currentAnn *lnwire.NodeAnnouncement1) { currentAnn.Addresses = append(currentAnn.Addresses, addr) }, ) @@ -3357,7 +3357,7 @@ func (s *server) findChannel(node *btcec.PublicKey, chanID lnwire.ChannelID) ( } // getNodeAnnouncement fetches the current, fully signed node announcement. -func (s *server) getNodeAnnouncement() lnwire.NodeAnnouncement { +func (s *server) getNodeAnnouncement() lnwire.NodeAnnouncement1 { s.mu.Lock() defer s.mu.Unlock() @@ -3368,7 +3368,7 @@ func (s *server) getNodeAnnouncement() lnwire.NodeAnnouncement { // announcement. The time stamp of the announcement will be updated in order // to ensure it propagates through the network. func (s *server) genNodeAnnouncement(features *lnwire.RawFeatureVector, - modifiers ...netann.NodeAnnModifier) (lnwire.NodeAnnouncement, error) { + modifiers ...netann.NodeAnnModifier) (lnwire.NodeAnnouncement1, error) { s.mu.Lock() defer s.mu.Unlock() @@ -3386,7 +3386,7 @@ func (s *server) genNodeAnnouncement(features *lnwire.RawFeatureVector, } err := s.featureMgr.UpdateFeatureSets(proposedFeatures) if err != nil { - return lnwire.NodeAnnouncement{}, err + return lnwire.NodeAnnouncement1{}, err } // If we could successfully update our feature manager, add @@ -3411,7 +3411,7 @@ func (s *server) genNodeAnnouncement(features *lnwire.RawFeatureVector, s.nodeSigner, s.identityKeyLoc, &newNodeAnn, ) if err != nil { - return lnwire.NodeAnnouncement{}, err + return lnwire.NodeAnnouncement1{}, err } // If signing succeeds, update the current announcement. @@ -3501,7 +3501,7 @@ func (s *server) establishPersistentConnections(ctx context.Context) error { // After checking our previous connections for addresses to connect to, // iterate through the nodes in our channel graph to find addresses - // that have been added via NodeAnnouncement messages. + // that have been added via NodeAnnouncement1 messages. // TODO(roasbeef): instead iterate over link nodes and query graph for // each of the nodes. graphAddrs := make(map[string]*nodeAddresses) @@ -4394,7 +4394,7 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq, TowerClient: towerClient, DisconnectPeer: s.DisconnectPeer, GenNodeAnnouncement: func(...netann.NodeAnnModifier) ( - lnwire.NodeAnnouncement, error) { + lnwire.NodeAnnouncement1, error) { return s.genNodeAnnouncement(nil) }, diff --git a/subrpcserver_config.go b/subrpcserver_config.go index 5034fcc40..d55d5a492 100644 --- a/subrpcserver_config.go +++ b/subrpcserver_config.go @@ -122,7 +122,7 @@ func (s *subRPCServerConfigs) PopulateDependencies(cfg *Config, tcpResolver lncfg.TCPResolver, genInvoiceFeatures func() *lnwire.FeatureVector, genAmpInvoiceFeatures func() *lnwire.FeatureVector, - getNodeAnnouncement func() lnwire.NodeAnnouncement, + getNodeAnnouncement func() lnwire.NodeAnnouncement1, updateNodeAnnouncement func(ctx context.Context, features *lnwire.RawFeatureVector, modifiers ...netann.NodeAnnModifier) error,