@@ -225,27 +225,138 @@ const (
225225 // A tlv type definition used to serialize an outpoint's indexStatus
226226 // for use in the outpoint index.
227227 indexStatusType tlv.Type = 0
228+ )
228229
229- // A tlv type definition used to serialize and deserialize a KeyLocator
230- // from the database.
231- keyLocType tlv.Type = 1
230+ // chanAuxData houses the auxiliary data that is stored for each channel in a
231+ // TLV stream within the root bucket. This is stored as a TLV stream appended
232+ // to the existing hard-coded fields in the channel's root bucket.
233+ type chanAuxData struct {
234+ // revokeKeyLoc is the key locator for the revocation key.
235+ revokeKeyLoc tlv.RecordT [tlv.TlvType1 , keyLocRecord ]
232236
233- // A tlv type used to serialize and deserialize the
234- // `InitialLocalBalance` field.
235- initialLocalBalanceType tlv.Type = 2
237+ // initialLocalBalance is the initial local balance of the channel.
238+ initialLocalBalance tlv.RecordT [tlv.TlvType2 , uint64 ]
236239
237- // A tlv type used to serialize and deserialize the
238- // `InitialRemoteBalance` field.
239- initialRemoteBalanceType tlv.Type = 3
240+ // initialRemoteBalance is the initial remote balance of the channel.
241+ initialRemoteBalance tlv.RecordT [tlv.TlvType3 , uint64 ]
240242
241- // A tlv type definition used to serialize and deserialize the
242- // confirmed ShortChannelID for a zero-conf channel .
243- realScidType tlv.Type = 4
243+ // realScid is the real short channel ID of the channel corresponding to
244+ // the on-chain outpoint .
245+ realScid tlv.RecordT [tlv. TlvType4 , lnwire. ShortChannelID ]
244246
245- // A tlv type definition used to serialize and deserialize the
246- // Memo for the channel channel.
247- channelMemoType tlv.Type = 5
248- )
247+ // memo is an optional text field that gives context to the user about
248+ // the channel.
249+ memo tlv.OptionalRecordT [tlv.TlvType5 , []byte ]
250+
251+ // tapscriptRoot is the optional Tapscript root the channel funding
252+ // output commits to.
253+ tapscriptRoot tlv.OptionalRecordT [tlv.TlvType6 , [32 ]byte ]
254+ }
255+
256+ // encode serializes the chanAuxData to the given io.Writer.
257+ func (c * chanAuxData ) encode (w io.Writer ) error {
258+ tlvRecords := []tlv.Record {
259+ c .revokeKeyLoc .Record (),
260+ c .initialLocalBalance .Record (),
261+ c .initialRemoteBalance .Record (),
262+ c .realScid .Record (),
263+ }
264+ c .memo .WhenSome (func (memo tlv.RecordT [tlv.TlvType5 , []byte ]) {
265+ tlvRecords = append (tlvRecords , memo .Record ())
266+ })
267+ c .tapscriptRoot .WhenSome (
268+ func (root tlv.RecordT [tlv.TlvType6 , [32 ]byte ]) {
269+ tlvRecords = append (tlvRecords , root .Record ())
270+ },
271+ )
272+
273+ // Create the tlv stream.
274+ tlvStream , err := tlv .NewStream (tlvRecords ... )
275+ if err != nil {
276+ return err
277+ }
278+
279+ return tlvStream .Encode (w )
280+ }
281+
282+ // decode deserializes the chanAuxData from the given io.Reader.
283+ func (c * chanAuxData ) decode (r io.Reader ) error {
284+ memo := c .memo .Zero ()
285+ tapscriptRoot := c .tapscriptRoot .Zero ()
286+
287+ // Create the tlv stream.
288+ tlvStream , err := tlv .NewStream (
289+ c .revokeKeyLoc .Record (),
290+ c .initialLocalBalance .Record (),
291+ c .initialRemoteBalance .Record (),
292+ c .realScid .Record (),
293+ memo .Record (),
294+ tapscriptRoot .Record (),
295+ )
296+ if err != nil {
297+ return err
298+ }
299+
300+ tlvs , err := tlvStream .DecodeWithParsedTypes (r )
301+ if err != nil {
302+ return err
303+ }
304+
305+ if _ , ok := tlvs [memo .TlvType ()]; ok {
306+ c .memo = tlv .SomeRecordT (memo )
307+ }
308+ if _ , ok := tlvs [tapscriptRoot .TlvType ()]; ok {
309+ c .tapscriptRoot = tlv .SomeRecordT (tapscriptRoot )
310+ }
311+
312+ return nil
313+ }
314+
315+ // toOpeChan converts the chanAuxData to an OpenChannel by setting the relevant
316+ // fields in the OpenChannel struct.
317+ func (c * chanAuxData ) toOpenChan (o * OpenChannel ) {
318+ o .RevocationKeyLocator = c .revokeKeyLoc .Val .KeyLocator
319+ o .InitialLocalBalance = lnwire .MilliSatoshi (c .initialLocalBalance .Val )
320+ o .InitialRemoteBalance = lnwire .MilliSatoshi (c .initialRemoteBalance .Val )
321+ o .confirmedScid = c .realScid .Val
322+ c .memo .WhenSomeV (func (memo []byte ) {
323+ o .Memo = memo
324+ })
325+ c .tapscriptRoot .WhenSomeV (func (h [32 ]byte ) {
326+ o .TapscriptRoot = fn.Some [chainhash.Hash ](h )
327+ })
328+ }
329+
330+ // newChanAuxDataFromChan creates a new chanAuxData from the given channel.
331+ func newChanAuxDataFromChan (openChan * OpenChannel ) * chanAuxData {
332+ c := & chanAuxData {
333+ revokeKeyLoc : tlv.NewRecordT [tlv.TlvType1 ](
334+ keyLocRecord {openChan .RevocationKeyLocator },
335+ ),
336+ initialLocalBalance : tlv.NewPrimitiveRecord [tlv.TlvType2 ](
337+ uint64 (openChan .InitialLocalBalance ),
338+ ),
339+ initialRemoteBalance : tlv.NewPrimitiveRecord [tlv.TlvType3 ](
340+ uint64 (openChan .InitialRemoteBalance ),
341+ ),
342+ realScid : tlv.NewRecordT [tlv.TlvType4 ](
343+ openChan .confirmedScid ,
344+ ),
345+ }
346+
347+ if len (openChan .Memo ) != 0 {
348+ c .memo = tlv .SomeRecordT (
349+ tlv.NewPrimitiveRecord [tlv.TlvType5 ](openChan .Memo ),
350+ )
351+ }
352+ openChan .TapscriptRoot .WhenSome (func (h chainhash.Hash ) {
353+ c .tapscriptRoot = tlv .SomeRecordT (
354+ tlv.NewPrimitiveRecord [tlv.TlvType6 , [32 ]byte ](h ),
355+ )
356+ })
357+
358+ return c
359+ }
249360
250361// indexStatus is an enum-like type that describes what state the
251362// outpoint is in. Currently only two possible values.
@@ -324,6 +435,11 @@ const (
324435 // SimpleTaprootFeatureBit indicates that the simple-taproot-chans
325436 // feature bit was negotiated during the lifetime of the channel.
326437 SimpleTaprootFeatureBit ChannelType = 1 << 10
438+
439+ // TapscriptRootBit indicates that this is a MuSig2 channel with a top
440+ // level tapscript commitment. This MUST be set along with the
441+ // SimpleTaprootFeatureBit.
442+ TapscriptRootBit ChannelType = 1 << 11
327443)
328444
329445// IsSingleFunder returns true if the channel type if one of the known single
@@ -394,6 +510,12 @@ func (c ChannelType) IsTaproot() bool {
394510 return c & SimpleTaprootFeatureBit == SimpleTaprootFeatureBit
395511}
396512
513+ // HasTapscriptRoot returns true if the channel is using a top level tapscript
514+ // root commitment.
515+ func (c ChannelType ) HasTapscriptRoot () bool {
516+ return c & TapscriptRootBit == TapscriptRootBit
517+ }
518+
397519// ChannelConstraints represents a set of constraints meant to allow a node to
398520// limit their exposure, enact flow control and ensure that all HTLCs are
399521// economically relevant. This struct will be mirrored for both sides of the
@@ -856,6 +978,10 @@ type OpenChannel struct {
856978 // channel that will be useful to our future selves.
857979 Memo []byte
858980
981+ // TapscriptRoot is an optional tapscript root used to derive the MuSig2
982+ // funding output.
983+ TapscriptRoot fn.Option [chainhash.Hash ]
984+
859985 // TODO(roasbeef): eww
860986 Db * ChannelStateDB
861987
@@ -4007,32 +4133,9 @@ func putChanInfo(chanBucket kvdb.RwBucket, channel *OpenChannel) error {
40074133 return err
40084134 }
40094135
4010- // Convert balance fields into uint64.
4011- localBalance := uint64 (channel .InitialLocalBalance )
4012- remoteBalance := uint64 (channel .InitialRemoteBalance )
4013-
4014- // Create the tlv stream.
4015- tlvStream , err := tlv .NewStream (
4016- // Write the RevocationKeyLocator as the first entry in a tlv
4017- // stream.
4018- MakeKeyLocRecord (
4019- keyLocType , & channel .RevocationKeyLocator ,
4020- ),
4021- tlv .MakePrimitiveRecord (
4022- initialLocalBalanceType , & localBalance ,
4023- ),
4024- tlv .MakePrimitiveRecord (
4025- initialRemoteBalanceType , & remoteBalance ,
4026- ),
4027- MakeScidRecord (realScidType , & channel .confirmedScid ),
4028- tlv .MakePrimitiveRecord (channelMemoType , & channel .Memo ),
4029- )
4030- if err != nil {
4031- return err
4032- }
4033-
4034- if err := tlvStream .Encode (& w ); err != nil {
4035- return err
4136+ auxData := newChanAuxDataFromChan (channel )
4137+ if err := auxData .encode (& w ); err != nil {
4138+ return fmt .Errorf ("unable to encode aux data: %w" , err )
40364139 }
40374140
40384141 if err := chanBucket .Put (chanInfoKey , w .Bytes ()); err != nil {
@@ -4221,45 +4324,14 @@ func fetchChanInfo(chanBucket kvdb.RBucket, channel *OpenChannel) error {
42214324 }
42224325 }
42234326
4224- // Create balance fields in uint64, and Memo field as byte slice.
4225- var (
4226- localBalance uint64
4227- remoteBalance uint64
4228- memo []byte
4229- )
4230-
4231- // Create the tlv stream.
4232- tlvStream , err := tlv .NewStream (
4233- // Write the RevocationKeyLocator as the first entry in a tlv
4234- // stream.
4235- MakeKeyLocRecord (
4236- keyLocType , & channel .RevocationKeyLocator ,
4237- ),
4238- tlv .MakePrimitiveRecord (
4239- initialLocalBalanceType , & localBalance ,
4240- ),
4241- tlv .MakePrimitiveRecord (
4242- initialRemoteBalanceType , & remoteBalance ,
4243- ),
4244- MakeScidRecord (realScidType , & channel .confirmedScid ),
4245- tlv .MakePrimitiveRecord (channelMemoType , & memo ),
4246- )
4247- if err != nil {
4248- return err
4327+ var auxData chanAuxData
4328+ if err := auxData .decode (r ); err != nil {
4329+ return fmt .Errorf ("unable to decode aux data: %w" , err )
42494330 }
42504331
4251- if err := tlvStream .Decode (r ); err != nil {
4252- return err
4253- }
4254-
4255- // Attach the balance fields.
4256- channel .InitialLocalBalance = lnwire .MilliSatoshi (localBalance )
4257- channel .InitialRemoteBalance = lnwire .MilliSatoshi (remoteBalance )
4258-
4259- // Attach the memo field if non-empty.
4260- if len (memo ) > 0 {
4261- channel .Memo = memo
4262- }
4332+ // Assign all the relevant fields from the aux data into the actual
4333+ // open channel.
4334+ auxData .toOpenChan (channel )
42634335
42644336 channel .Packager = NewChannelPackager (channel .ShortChannelID )
42654337
@@ -4417,6 +4489,25 @@ func deleteThawHeight(chanBucket kvdb.RwBucket) error {
44174489 return chanBucket .Delete (frozenChanKey )
44184490}
44194491
4492+ // keyLocRecord is a wrapper struct around keychain.KeyLocator to implement the
4493+ // tlv.RecordProducer interface.
4494+ type keyLocRecord struct {
4495+ keychain.KeyLocator
4496+ }
4497+
4498+ // Record creates a Record out of a KeyLocator using the passed Type and the
4499+ // EKeyLocator and DKeyLocator functions. The size will always be 8 as
4500+ // KeyFamily is uint32 and the Index is uint32.
4501+ //
4502+ // NOTE: This is part of the tlv.RecordProducer interface.
4503+ func (k * keyLocRecord ) Record () tlv.Record {
4504+ // Note that we set the type here as zero, as when used with a
4505+ // tlv.RecordT, the type param will be used as the type.
4506+ return tlv .MakeStaticRecord (
4507+ 0 , & k .KeyLocator , 8 , EKeyLocator , DKeyLocator ,
4508+ )
4509+ }
4510+
44204511// EKeyLocator is an encoder for keychain.KeyLocator.
44214512func EKeyLocator (w io.Writer , val interface {}, buf * [8 ]byte ) error {
44224513 if v , ok := val .(* keychain.KeyLocator ); ok {
@@ -4445,22 +4536,6 @@ func DKeyLocator(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
44454536 return tlv .NewTypeForDecodingErr (val , "keychain.KeyLocator" , l , 8 )
44464537}
44474538
4448- // MakeKeyLocRecord creates a Record out of a KeyLocator using the passed
4449- // Type and the EKeyLocator and DKeyLocator functions. The size will always be
4450- // 8 as KeyFamily is uint32 and the Index is uint32.
4451- func MakeKeyLocRecord (typ tlv.Type , keyLoc * keychain.KeyLocator ) tlv.Record {
4452- return tlv .MakeStaticRecord (typ , keyLoc , 8 , EKeyLocator , DKeyLocator )
4453- }
4454-
4455- // MakeScidRecord creates a Record out of a ShortChannelID using the passed
4456- // Type and the EShortChannelID and DShortChannelID functions. The size will
4457- // always be 8 for the ShortChannelID.
4458- func MakeScidRecord (typ tlv.Type , scid * lnwire.ShortChannelID ) tlv.Record {
4459- return tlv .MakeStaticRecord (
4460- typ , scid , 8 , lnwire .EShortChannelID , lnwire .DShortChannelID ,
4461- )
4462- }
4463-
44644539// ShutdownInfo contains various info about the shutdown initiation of a
44654540// channel.
44664541type ShutdownInfo struct {
0 commit comments