mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
contractcourt: add HtlcBlobs to taprootBriefcase
In this commit, we add the set of HtlcBlobs to the taprootBriefcase struct. This new field will store all the resolution blobs for a given HTLC. We also add some new property based tests along the way for adequate test coverage.
This commit is contained in:
parent
1e7c5415ae
commit
9b8adf5f5c
@ -39,7 +39,9 @@ type taprootBriefcase struct {
|
|||||||
// used to sweep a remote party's breached output.
|
// used to sweep a remote party's breached output.
|
||||||
BreachedCommitBlob tlv.OptionalRecordT[tlv.TlvType3, tlv.Blob]
|
BreachedCommitBlob tlv.OptionalRecordT[tlv.TlvType3, tlv.Blob]
|
||||||
|
|
||||||
// TODO(roasbeef): htlc blobs
|
// HtlcBlobs is an optikonal record that contains the opaque blobs for
|
||||||
|
// the set of active HTLCs on the commitment transaction.
|
||||||
|
HtlcBlobs tlv.OptionalRecordT[tlv.TlvType4, htlcAuxBlobs]
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): morph into new tlv record
|
// TODO(roasbeef): morph into new tlv record
|
||||||
@ -70,6 +72,9 @@ func (t *taprootBriefcase) EncodeRecords() []tlv.Record {
|
|||||||
records = append(records, r.Record())
|
records = append(records, r.Record())
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
t.HtlcBlobs.WhenSome(func(r tlv.RecordT[tlv.TlvType4, htlcAuxBlobs]) {
|
||||||
|
records = append(records, r.Record())
|
||||||
|
})
|
||||||
|
|
||||||
return records
|
return records
|
||||||
}
|
}
|
||||||
@ -96,10 +101,11 @@ func (t *taprootBriefcase) Encode(w io.Writer) error {
|
|||||||
func (t *taprootBriefcase) Decode(r io.Reader) error {
|
func (t *taprootBriefcase) Decode(r io.Reader) error {
|
||||||
settledCommitBlob := t.SettledCommitBlob.Zero()
|
settledCommitBlob := t.SettledCommitBlob.Zero()
|
||||||
breachedCommitBlob := t.BreachedCommitBlob.Zero()
|
breachedCommitBlob := t.BreachedCommitBlob.Zero()
|
||||||
|
htlcBlobs := t.HtlcBlobs.Zero()
|
||||||
|
|
||||||
records := append(
|
records := append(
|
||||||
t.DecodeRecords(),
|
t.DecodeRecords(), settledCommitBlob.Record(),
|
||||||
settledCommitBlob.Record(),
|
breachedCommitBlob.Record(), htlcBlobs.Record(),
|
||||||
breachedCommitBlob.Record(),
|
|
||||||
)
|
)
|
||||||
stream, err := tlv.NewStream(records...)
|
stream, err := tlv.NewStream(records...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,6 +123,9 @@ func (t *taprootBriefcase) Decode(r io.Reader) error {
|
|||||||
if v, ok := typeMap[t.BreachedCommitBlob.TlvType()]; ok && v == nil {
|
if v, ok := typeMap[t.BreachedCommitBlob.TlvType()]; ok && v == nil {
|
||||||
t.BreachedCommitBlob = tlv.SomeRecordT(breachedCommitBlob)
|
t.BreachedCommitBlob = tlv.SomeRecordT(breachedCommitBlob)
|
||||||
}
|
}
|
||||||
|
if v, ok := typeMap[t.HtlcBlobs.TlvType()]; ok && v == nil {
|
||||||
|
t.HtlcBlobs = tlv.SomeRecordT(htlcBlobs)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -686,3 +695,110 @@ func (t *tapTweaks) Decode(r io.Reader) error {
|
|||||||
|
|
||||||
return stream.Decode(r)
|
return stream.Decode(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// htlcAuxBlobs is a map of resolver IDs to their corresponding HTLC blobs.
|
||||||
|
// This is used to store the resolution blobs for HTLCs that are not yet
|
||||||
|
// resolved.
|
||||||
|
type htlcAuxBlobs map[resolverID]tlv.Blob
|
||||||
|
|
||||||
|
// newAuxHtlcBlobs returns a new instance of the htlcAuxBlobs struct.
|
||||||
|
func newAuxHtlcBlobs() htlcAuxBlobs {
|
||||||
|
return make(htlcAuxBlobs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encodes the set of HTLC blobs into the target writer.
|
||||||
|
func (h *htlcAuxBlobs) Encode(w io.Writer) error {
|
||||||
|
var buf [8]byte
|
||||||
|
|
||||||
|
numBlobs := uint64(len(*h))
|
||||||
|
if err := tlv.WriteVarInt(w, numBlobs, &buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for id, blob := range *h {
|
||||||
|
if _, err := w.Write(id[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := varBytesEncoder(w, &blob, &buf); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode decodes the set of HTLC blobs from the target reader.
|
||||||
|
func (h *htlcAuxBlobs) Decode(r io.Reader) error {
|
||||||
|
var buf [8]byte
|
||||||
|
|
||||||
|
numBlobs, err := tlv.ReadVarInt(r, &buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint64(0); i < numBlobs; i++ {
|
||||||
|
var id resolverID
|
||||||
|
if _, err := io.ReadFull(r, id[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var blob tlv.Blob
|
||||||
|
if err := varBytesDecoder(r, &blob, &buf, 0); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
(*h)[id] = blob
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// eHtlcAuxBlobsEncoder is a custom TLV encoder for the htlcAuxBlobs struct.
|
||||||
|
func htlcAuxBlobsEncoder(w io.Writer, val any, _ *[8]byte) error {
|
||||||
|
if t, ok := val.(*htlcAuxBlobs); ok {
|
||||||
|
return (*t).Encode(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForEncodingErr(val, "htlcAuxBlobs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// dHtlcAuxBlobsDecoder is a custom TLV decoder for the htlcAuxBlobs struct.
|
||||||
|
func htlcAuxBlobsDecoder(r io.Reader, val any, _ *[8]byte,
|
||||||
|
l uint64) error {
|
||||||
|
|
||||||
|
if typ, ok := val.(*htlcAuxBlobs); ok {
|
||||||
|
blobReader := io.LimitReader(r, int64(l))
|
||||||
|
|
||||||
|
htlcBlobs := newAuxHtlcBlobs()
|
||||||
|
err := htlcBlobs.Decode(blobReader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*typ = htlcBlobs
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.NewTypeForDecodingErr(val, "htlcAuxBlobs", l, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record returns a tlv.Record for the htlcAuxBlobs struct.
|
||||||
|
func (h *htlcAuxBlobs) Record() tlv.Record {
|
||||||
|
recordSize := func() uint64 {
|
||||||
|
var (
|
||||||
|
b bytes.Buffer
|
||||||
|
buf [8]byte
|
||||||
|
)
|
||||||
|
if err := htlcAuxBlobsEncoder(&b, h, &buf); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint64(len(b.Bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return tlv.MakeDynamicRecord(
|
||||||
|
0, h, recordSize, htlcAuxBlobsEncoder, htlcAuxBlobsDecoder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"pgregory.net/rapid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func randResolverCtrlBlocks(t *testing.T) resolverCtrlBlocks {
|
func randResolverCtrlBlocks(t *testing.T) resolverCtrlBlocks {
|
||||||
@ -53,6 +54,25 @@ func randHtlcTweaks(t *testing.T) htlcTapTweaks {
|
|||||||
return tweaks
|
return tweaks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func randHtlcAuxBlobs(t *testing.T) htlcAuxBlobs {
|
||||||
|
numBlobs := rand.Int() % 256
|
||||||
|
blobs := make(htlcAuxBlobs, numBlobs)
|
||||||
|
|
||||||
|
for i := 0; i < numBlobs; i++ {
|
||||||
|
var id resolverID
|
||||||
|
_, err := rand.Read(id[:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var blob [100]byte
|
||||||
|
_, err = rand.Read(blob[:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
blobs[id] = blob[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
return blobs
|
||||||
|
}
|
||||||
|
|
||||||
// TestTaprootBriefcase tests the encode/decode methods of the taproot
|
// TestTaprootBriefcase tests the encode/decode methods of the taproot
|
||||||
// briefcase extension.
|
// briefcase extension.
|
||||||
func TestTaprootBriefcase(t *testing.T) {
|
func TestTaprootBriefcase(t *testing.T) {
|
||||||
@ -93,6 +113,9 @@ func TestTaprootBriefcase(t *testing.T) {
|
|||||||
BreachedCommitBlob: tlv.SomeRecordT(
|
BreachedCommitBlob: tlv.SomeRecordT(
|
||||||
tlv.NewPrimitiveRecord[tlv.TlvType3](commitBlob[:]),
|
tlv.NewPrimitiveRecord[tlv.TlvType3](commitBlob[:]),
|
||||||
),
|
),
|
||||||
|
HtlcBlobs: tlv.SomeRecordT(
|
||||||
|
tlv.NewRecordT[tlv.TlvType4](randHtlcAuxBlobs(t)),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
@ -103,3 +126,21 @@ func TestTaprootBriefcase(t *testing.T) {
|
|||||||
|
|
||||||
require.Equal(t, testCase, &decodedCase)
|
require.Equal(t, testCase, &decodedCase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestHtlcAuxBlobEncodeDecode tests the encode/decode methods of the HTLC aux
|
||||||
|
// blobs.
|
||||||
|
func TestHtlcAuxBlobEncodeDecode(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
rapid.Check(t, func(t *rapid.T) {
|
||||||
|
htlcBlobs := rapid.Make[htlcAuxBlobs]().Draw(t, "htlcAuxBlobs")
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
require.NoError(t, htlcBlobs.Encode(&b))
|
||||||
|
|
||||||
|
decodedBlobs := newAuxHtlcBlobs()
|
||||||
|
require.NoError(t, decodedBlobs.Decode(&b))
|
||||||
|
|
||||||
|
require.Equal(t, htlcBlobs, decodedBlobs)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
# 2024/09/02 14:02:53.354676 [TestHtlcAuxBlobEncodeDecode] [rapid] draw htlcAuxBlobs: contractcourt.htlcAuxBlobs{contractcourt.resolverID{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}:[]uint8{}}
|
||||||
|
#
|
||||||
|
v0.4.8#15807814492030881602
|
||||||
|
0x5555555555555
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
||||||
|
0x0
|
1
go.mod
1
go.mod
@ -64,6 +64,7 @@ require (
|
|||||||
google.golang.org/protobuf v1.33.0
|
google.golang.org/protobuf v1.33.0
|
||||||
gopkg.in/macaroon-bakery.v2 v2.0.1
|
gopkg.in/macaroon-bakery.v2 v2.0.1
|
||||||
gopkg.in/macaroon.v2 v2.0.0
|
gopkg.in/macaroon.v2 v2.0.0
|
||||||
|
pgregory.net/rapid v1.1.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
2
go.sum
2
go.sum
@ -1076,6 +1076,8 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
|||||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
|
||||||
|
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
Loading…
Reference in New Issue
Block a user