Skip to content

Commit 81970ea

Browse files
authored
Merge pull request #8684 from lightningnetwork/aux-leaf-fetcher
[2/?]: lnwallet+channeldb: add new AuxLeafStore for dynamic aux leaves
2 parents bb44793 + 72f7b80 commit 81970ea

31 files changed

+1796
-596
lines changed

chainreg/chainregistry.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/lightningnetwork/lnd/chainntnfs/neutrinonotify"
2525
"github.com/lightningnetwork/lnd/channeldb"
2626
"github.com/lightningnetwork/lnd/channeldb/models"
27+
"github.com/lightningnetwork/lnd/fn"
2728
"github.com/lightningnetwork/lnd/input"
2829
"github.com/lightningnetwork/lnd/keychain"
2930
"github.com/lightningnetwork/lnd/kvdb"
@@ -63,6 +64,10 @@ type Config struct {
6364
// state.
6465
ChanStateDB *channeldb.ChannelStateDB
6566

67+
// AuxLeafStore is an optional store that can be used to store auxiliary
68+
// leaves for certain custom channel types.
69+
AuxLeafStore fn.Option[lnwallet.AuxLeafStore]
70+
6671
// BlockCache is the main cache for storing block information.
6772
BlockCache *blockcache.BlockCache
6873

channeldb/channel.go

Lines changed: 153 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
283290
func (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

43874535
func fetchChanCommitments(chanBucket kvdb.RBucket, channel *OpenChannel) error {

0 commit comments

Comments
 (0)