Skip to content

Commit 3ff8eb8

Browse files
committed
lnwire: add alias to FundingLocked in TLV
This adds an optional short channel id field to the FundingLocked message that is sent/received as a TLV segment inside the ExtraOpaqueData field.
1 parent a493caf commit 3ff8eb8

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

lnwire/funding_locked.go

+36-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io"
66

77
"github.com/btcsuite/btcd/btcec/v2"
8+
"github.com/lightningnetwork/lnd/tlv"
89
)
910

1011
// FundingLocked is the message that both parties to a new channel creation
@@ -21,6 +22,11 @@ type FundingLocked struct {
2122
// next commitment transaction for the channel.
2223
NextPerCommitmentPoint *btcec.PublicKey
2324

25+
// AliasScid is an alias ShortChannelID used to refer to the underlying
26+
// channel. It can be used instead of the confirmed on-chain
27+
// ShortChannelID for forwarding.
28+
AliasScid *ShortChannelID
29+
2430
// ExtraData is the set of data that was appended to this message to
2531
// fill out the full maximum transport message size. These fields can
2632
// be used to specify optional data such as custom TLV fields.
@@ -47,11 +53,31 @@ var _ Message = (*FundingLocked)(nil)
4753
//
4854
// This is part of the lnwire.Message interface.
4955
func (c *FundingLocked) Decode(r io.Reader, pver uint32) error {
50-
return ReadElements(r,
56+
// Read all the mandatory fields in the message.
57+
err := ReadElements(r,
5158
&c.ChanID,
5259
&c.NextPerCommitmentPoint,
5360
&c.ExtraData,
5461
)
62+
if err != nil {
63+
return err
64+
}
65+
66+
// Next we'll parse out the set of known records. For now, this is just
67+
// the AliasScidRecordType.
68+
var aliasScid ShortChannelID
69+
typeMap, err := c.ExtraData.ExtractRecords(&aliasScid)
70+
if err != nil {
71+
return err
72+
}
73+
74+
// We'll only set AliasScid if the corresponding TLV type was included
75+
// in the stream.
76+
if val, ok := typeMap[AliasScidRecordType]; ok && val == nil {
77+
c.AliasScid = &aliasScid
78+
}
79+
80+
return nil
5581
}
5682

5783
// Encode serializes the target FundingLocked message into the passed io.Writer
@@ -68,6 +94,15 @@ func (c *FundingLocked) Encode(w *bytes.Buffer, pver uint32) error {
6894
return err
6995
}
7096

97+
// We'll only encode the AliasScid in a TLV segment if it exists.
98+
if c.AliasScid != nil {
99+
recordProducers := []tlv.RecordProducer{c.AliasScid}
100+
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
101+
if err != nil {
102+
return err
103+
}
104+
}
105+
71106
return WriteBytes(w, c.ExtraData)
72107
}
73108

lnwire/short_channel_id.go

+44
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ package lnwire
22

33
import (
44
"fmt"
5+
"io"
6+
7+
"github.com/lightningnetwork/lnd/tlv"
8+
)
9+
10+
const (
11+
// AliasScidRecordType is the type of the experimental record to denote
12+
// the alias being used in an option_scid_alias channel.
13+
AliasScidRecordType tlv.Type = 1
514
)
615

716
// ShortChannelID represents the set of data which is needed to retrieve all
@@ -46,3 +55,38 @@ func (c ShortChannelID) ToUint64() uint64 {
4655
func (c ShortChannelID) String() string {
4756
return fmt.Sprintf("%d:%d:%d", c.BlockHeight, c.TxIndex, c.TxPosition)
4857
}
58+
59+
// Record returns a TLV record that can be used to encode/decode a
60+
// ShortChannelID to/from a TLV stream.
61+
func (c *ShortChannelID) Record() tlv.Record {
62+
return tlv.MakeStaticRecord(
63+
AliasScidRecordType, c, 8, EShortChannelID, DShortChannelID,
64+
)
65+
}
66+
67+
// EShortChannelID is an encoder for ShortChannelID. It is exported so other
68+
// packages can use the encoding scheme.
69+
func EShortChannelID(w io.Writer, val interface{}, buf *[8]byte) error {
70+
if v, ok := val.(*ShortChannelID); ok {
71+
return tlv.EUint64T(w, v.ToUint64(), buf)
72+
}
73+
return tlv.NewTypeForEncodingErr(val, "lnwire.ShortChannelID")
74+
}
75+
76+
// DShortChannelID is a decoder for ShortChannelID. It is exported so other
77+
// packages can use the decoding scheme.
78+
func DShortChannelID(r io.Reader, val interface{}, buf *[8]byte,
79+
l uint64) error {
80+
81+
if v, ok := val.(*ShortChannelID); ok {
82+
var scid uint64
83+
err := tlv.DUint64(r, &scid, buf, 8)
84+
if err != nil {
85+
return err
86+
}
87+
88+
*v = NewShortChanIDFromInt(scid)
89+
return nil
90+
}
91+
return tlv.NewTypeForDecodingErr(val, "lnwire.ShortChannelID", l, 8)
92+
}

lnwire/short_channel_id_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"testing"
66

77
"github.com/davecgh/go-spew/spew"
8+
"github.com/stretchr/testify/require"
89
)
910

1011
func TestShortChannelIDEncoding(t *testing.T) {
@@ -39,3 +40,25 @@ func TestShortChannelIDEncoding(t *testing.T) {
3940
}
4041
}
4142
}
43+
44+
// TestScidTypeEncodeDecode tests that we're able to properly encode and decode
45+
// ShortChannelID within TLV streams.
46+
func TestScidTypeEncodeDecode(t *testing.T) {
47+
t.Parallel()
48+
49+
aliasScid := ShortChannelID{
50+
BlockHeight: (1 << 24) - 1,
51+
TxIndex: (1 << 24) - 1,
52+
TxPosition: (1 << 16) - 1,
53+
}
54+
55+
var extraData ExtraOpaqueData
56+
require.NoError(t, extraData.PackRecords(&aliasScid))
57+
58+
var aliasScid2 ShortChannelID
59+
tlvs, err := extraData.ExtractRecords(&aliasScid2)
60+
require.NoError(t, err)
61+
62+
require.Contains(t, tlvs, AliasScidRecordType)
63+
require.Equal(t, aliasScid, aliasScid2)
64+
}

0 commit comments

Comments
 (0)