@@ -251,6 +251,10 @@ type chanAuxData struct {
251251 // tapscriptRoot is the optional Tapscript root the channel funding
252252 // output commits to.
253253 tapscriptRoot tlv.OptionalRecordT [tlv.TlvType6 , [32 ]byte ]
254+
255+ // customBlob is an optional TLV encoded blob of data representing
256+ // custom channel funding information.
257+ customBlob tlv.OptionalRecordT [tlv.TlvType7 , tlv.Blob ]
254258}
255259
256260// encode serializes the chanAuxData to the given io.Writer.
@@ -269,6 +273,9 @@ func (c *chanAuxData) encode(w io.Writer) error {
269273 tlvRecords = append (tlvRecords , root .Record ())
270274 },
271275 )
276+ c .customBlob .WhenSome (func (blob tlv.RecordT [tlv.TlvType7 , tlv.Blob ]) {
277+ tlvRecords = append (tlvRecords , blob .Record ())
278+ })
272279
273280 // Create the tlv stream.
274281 tlvStream , err := tlv .NewStream (tlvRecords ... )
@@ -283,6 +290,7 @@ func (c *chanAuxData) encode(w io.Writer) error {
283290func (c * chanAuxData ) decode (r io.Reader ) error {
284291 memo := c .memo .Zero ()
285292 tapscriptRoot := c .tapscriptRoot .Zero ()
293+ blob := c .customBlob .Zero ()
286294
287295 // Create the tlv stream.
288296 tlvStream , err := tlv .NewStream (
@@ -292,6 +300,7 @@ func (c *chanAuxData) decode(r io.Reader) error {
292300 c .realScid .Record (),
293301 memo .Record (),
294302 tapscriptRoot .Record (),
303+ blob .Record (),
295304 )
296305 if err != nil {
297306 return err
@@ -308,6 +317,9 @@ func (c *chanAuxData) decode(r io.Reader) error {
308317 if _ , ok := tlvs [tapscriptRoot .TlvType ()]; ok {
309318 c .tapscriptRoot = tlv .SomeRecordT (tapscriptRoot )
310319 }
320+ if _ , ok := tlvs [c .customBlob .TlvType ()]; ok {
321+ c .customBlob = tlv .SomeRecordT (blob )
322+ }
311323
312324 return nil
313325}
@@ -325,6 +337,9 @@ func (c *chanAuxData) toOpenChan(o *OpenChannel) {
325337 c .tapscriptRoot .WhenSomeV (func (h [32 ]byte ) {
326338 o .TapscriptRoot = fn.Some [chainhash.Hash ](h )
327339 })
340+ c .customBlob .WhenSomeV (func (blob tlv.Blob ) {
341+ o .CustomBlob = fn .Some (blob )
342+ })
328343}
329344
330345// newChanAuxDataFromChan creates a new chanAuxData from the given channel.
@@ -354,6 +369,11 @@ func newChanAuxDataFromChan(openChan *OpenChannel) *chanAuxData {
354369 tlv.NewPrimitiveRecord [tlv.TlvType6 , [32 ]byte ](h ),
355370 )
356371 })
372+ openChan .CustomBlob .WhenSome (func (blob tlv.Blob ) {
373+ c .customBlob = tlv .SomeRecordT (
374+ tlv.NewPrimitiveRecord [tlv.TlvType7 ](blob ),
375+ )
376+ })
357377
358378 return c
359379}
@@ -607,6 +627,74 @@ type ChannelConfig struct {
607627 HtlcBasePoint keychain.KeyDescriptor
608628}
609629
630+ // commitAuxData stores all the optional data that may be stored as a TLV stream
631+ // at the _end_ of the normal serialized commit on disk.
632+ type commitAuxData struct {
633+ // customBlob is a custom blob that may store extra data for custom
634+ // channels.
635+ customBlob tlv.OptionalRecordT [tlv.TlvType1 , tlv.Blob ]
636+ }
637+
638+ // encode encodes the aux data into the passed io.Writer.
639+ func (c * commitAuxData ) encode (w io.Writer ) error {
640+ var tlvRecords []tlv.Record
641+ c .customBlob .WhenSome (func (blob tlv.RecordT [tlv.TlvType1 , tlv.Blob ]) {
642+ tlvRecords = append (tlvRecords , blob .Record ())
643+ })
644+
645+ // Create the tlv stream.
646+ tlvStream , err := tlv .NewStream (tlvRecords ... )
647+ if err != nil {
648+ return err
649+ }
650+
651+ return tlvStream .Encode (w )
652+ }
653+
654+ // decode attempts to ecode the aux data from the passed io.Reader.
655+ func (c * commitAuxData ) decode (r io.Reader ) error {
656+ blob := c .customBlob .Zero ()
657+
658+ tlvStream , err := tlv .NewStream (
659+ blob .Record (),
660+ )
661+ if err != nil {
662+ return err
663+ }
664+
665+ tlvs , err := tlvStream .DecodeWithParsedTypes (r )
666+ if err != nil {
667+ return err
668+ }
669+
670+ if _ , ok := tlvs [c .customBlob .TlvType ()]; ok {
671+ c .customBlob = tlv .SomeRecordT (blob )
672+ }
673+
674+ return nil
675+ }
676+
677+ // toChanCommit extracts the optional data stored in the commitAuxData struct
678+ // and stores it in the ChannelCommitment.
679+ func (c * commitAuxData ) toChanCommit (commit * ChannelCommitment ) {
680+ c .customBlob .WhenSomeV (func (blob tlv.Blob ) {
681+ commit .CustomBlob = fn .Some (blob )
682+ })
683+ }
684+
685+ // newCommitAuxData creates an aux data struct from the normal chan commitment.
686+ func newCommitAuxData (commit * ChannelCommitment ) commitAuxData {
687+ var c commitAuxData
688+
689+ commit .CustomBlob .WhenSome (func (blob tlv.Blob ) {
690+ c .customBlob = tlv .SomeRecordT (
691+ tlv.NewPrimitiveRecord [tlv.TlvType1 ](blob ),
692+ )
693+ })
694+
695+ return c
696+ }
697+
610698// ChannelCommitment is a snapshot of the commitment state at a particular
611699// point in the commitment chain. With each state transition, a snapshot of the
612700// current state along with all non-settled HTLCs are recorded. These snapshots
@@ -673,6 +761,11 @@ type ChannelCommitment struct {
673761 // able by us.
674762 CommitTx * wire.MsgTx
675763
764+ // CustomBlob is an optional blob that can be used to store information
765+ // specific to a custom channel type. This may track some custom
766+ // specific state for this given commitment.
767+ CustomBlob fn.Option [tlv.Blob ]
768+
676769 // CommitSig is one half of the signature required to fully complete
677770 // the script for the commitment transaction above. This is the
678771 // signature signed by the remote party for our version of the
@@ -682,9 +775,6 @@ type ChannelCommitment struct {
682775 // Htlcs is the set of HTLC's that are pending at this particular
683776 // commitment height.
684777 Htlcs []HTLC
685-
686- // TODO(roasbeef): pending commit pointer?
687- // * lets just walk through
688778}
689779
690780// ChannelStatus is a bit vector used to indicate whether an OpenChannel is in
@@ -982,6 +1072,12 @@ type OpenChannel struct {
9821072 // funding output.
9831073 TapscriptRoot fn.Option [chainhash.Hash ]
9841074
1075+ // CustomBlob is an optional blob that can be used to store information
1076+ // specific to a custom channel type. This information is only created
1077+ // at channel funding time, and after wards is to be considered
1078+ // immutable.
1079+ CustomBlob fn.Option [tlv.Blob ]
1080+
9851081 // TODO(roasbeef): eww
9861082 Db * ChannelStateDB
9871083
@@ -2793,6 +2889,16 @@ func serializeCommitDiff(w io.Writer, diff *CommitDiff) error { // nolint: dupl
27932889 }
27942890 }
27952891
2892+ // We'll also encode the commit aux data stream here. We do this here
2893+ // rather than above (at the call to serializeChanCommit), to ensure
2894+ // backwards compat for reads to existing non-custom channels.
2895+ //
2896+ // TODO(roasbeef): migrate it after all?
2897+ auxData := newCommitAuxData (& diff .Commitment )
2898+ if err := auxData .encode (w ); err != nil {
2899+ return fmt .Errorf ("unable to write aux data: %w" , err )
2900+ }
2901+
27962902 return nil
27972903}
27982904
@@ -2853,6 +2959,17 @@ func deserializeCommitDiff(r io.Reader) (*CommitDiff, error) {
28532959 }
28542960 }
28552961
2962+ // As a final step, we'll read out any aux commit data that we have at
2963+ // the end of this byte stream. We do this here to ensure backward
2964+ // compatibility, as otherwise we risk erroneously reading into the
2965+ // wrong field.
2966+ var auxData commitAuxData
2967+ if err := auxData .decode (r ); err != nil {
2968+ return nil , fmt .Errorf ("unable to decode aux data: %w" , err )
2969+ }
2970+
2971+ auxData .toChanCommit (& d .Commitment )
2972+
28562973 return & d , nil
28572974}
28582975
@@ -3831,6 +3948,13 @@ func (c *OpenChannel) Snapshot() *ChannelSnapshot {
38313948 },
38323949 }
38333950
3951+ localCommit .CustomBlob .WhenSome (func (blob tlv.Blob ) {
3952+ blobCopy := make ([]byte , len (blob ))
3953+ copy (blobCopy , blob )
3954+
3955+ snapshot .ChannelCommitment .CustomBlob = fn .Some (blobCopy )
3956+ })
3957+
38343958 // Copy over the current set of HTLCs to ensure the caller can't mutate
38353959 // our internal state.
38363960 snapshot .Htlcs = make ([]HTLC , len (localCommit .Htlcs ))
@@ -4222,6 +4346,12 @@ func putChanCommitment(chanBucket kvdb.RwBucket, c *ChannelCommitment,
42224346 return err
42234347 }
42244348
4349+ // Before we write to disk, we'll also write our aux data as well.
4350+ auxData := newCommitAuxData (c )
4351+ if err := auxData .encode (& b ); err != nil {
4352+ return fmt .Errorf ("unable to write aux data: %w" , err )
4353+ }
4354+
42254355 return chanBucket .Put (commitKey , b .Bytes ())
42264356}
42274357
@@ -4367,7 +4497,9 @@ func deserializeChanCommit(r io.Reader) (ChannelCommitment, error) {
43674497 return c , nil
43684498}
43694499
4370- func fetchChanCommitment (chanBucket kvdb.RBucket , local bool ) (ChannelCommitment , error ) {
4500+ func fetchChanCommitment (chanBucket kvdb.RBucket ,
4501+ local bool ) (ChannelCommitment , error ) {
4502+
43714503 var commitKey []byte
43724504 if local {
43734505 commitKey = append (chanCommitmentKey , byte (0x00 ))
@@ -4381,7 +4513,23 @@ func fetchChanCommitment(chanBucket kvdb.RBucket, local bool) (ChannelCommitment
43814513 }
43824514
43834515 r := bytes .NewReader (commitBytes )
4384- return deserializeChanCommit (r )
4516+ chanCommit , err := deserializeChanCommit (r )
4517+ if err != nil {
4518+ return ChannelCommitment {}, fmt .Errorf ("unable to decode " +
4519+ "chan commit: %w" , err )
4520+ }
4521+
4522+ // We'll also check to see if we have any aux data stored as the end of
4523+ // the stream.
4524+ var auxData commitAuxData
4525+ if err := auxData .decode (r ); err != nil {
4526+ return ChannelCommitment {}, fmt .Errorf ("unable to decode " +
4527+ "chan aux data: %w" , err )
4528+ }
4529+
4530+ auxData .toChanCommit (& chanCommit )
4531+
4532+ return chanCommit , nil
43854533}
43864534
43874535func fetchChanCommitments (chanBucket kvdb.RBucket , channel * OpenChannel ) error {
0 commit comments