Skip to content

Commit cdcba13

Browse files
jharveybguggero
authored andcommitted
tappsbt+asset: move AltLeafAsset type alias
1 parent a9a2744 commit cdcba13

File tree

8 files changed

+115
-73
lines changed

8 files changed

+115
-73
lines changed

asset/asset.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,18 +2336,27 @@ func NewAltLeaf(key ScriptKey, keyVersion ScriptVersion,
23362336
}, nil
23372337
}
23382338

2339+
// InnerAltLeaf returns the inner value of an AltLeaf, as its concrete type.
2340+
func InnerAltLeaf[T AltLeaf[T]](a AltLeaf[T]) T {
2341+
return a.(T)
2342+
}
2343+
23392344
// CopyAltLeaf performs a deep copy of an AltLeaf.
23402345
func CopyAltLeaf[T AltLeaf[T]](a AltLeaf[T]) AltLeaf[T] {
23412346
return a.Copy()
23422347
}
23432348

23442349
// CopyAltLeaves performs a deep copy of an AltLeaf slice.
23452350
func CopyAltLeaves[T AltLeaf[T]](a []AltLeaf[T]) []AltLeaf[T] {
2351+
if len(a) == 0 {
2352+
return nil
2353+
}
2354+
23462355
return fn.Map(a, CopyAltLeaf[T])
23472356
}
23482357

2349-
// Validate checks that an Asset is a valid AltLeaf. An Asset used as an AltLeaf
2350-
// must meet these constraints:
2358+
// ValidateAltLeaf checks that an Asset is a valid AltLeaf. An Asset used as an
2359+
// AltLeaf must meet these constraints:
23512360
// - Version must be V0.
23522361
// - Genesis must be the empty Genesis.
23532362
// - Amount, LockTime, and RelativeLockTime must be 0.
@@ -2375,9 +2384,8 @@ func (a *Asset) ValidateAltLeaf() error {
23752384
}
23762385

23772386
if a.SplitCommitmentRoot != nil {
2378-
return fmt.Errorf(
2379-
"alt leaf split commitment root must be empty",
2380-
)
2387+
return fmt.Errorf("alt leaf split commitment root must be " +
2388+
"empty")
23812389
}
23822390

23832391
if a.GroupKey != nil {
@@ -2427,5 +2435,8 @@ func (a *Asset) DecodeAltLeaf(r io.Reader) error {
24272435
return a.Decode(r)
24282436
}
24292437

2438+
// AltLeafAsset is an AltLeaf backed by an Asset object.
2439+
type AltLeafAsset = AltLeaf[*Asset]
2440+
24302441
// Ensure Asset implements the AltLeaf interface.
24312442
var _ AltLeaf[*Asset] = (*Asset)(nil)

asset/encoding.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,9 @@ func DecodeTapLeaf(leafData []byte) (*txscript.TapLeaf, error) {
810810

811811
func AltLeavesEncoder(w io.Writer, val any, buf *[8]byte) error {
812812
if t, ok := val.(*[]AltLeaf[*Asset]); ok {
813+
// If the AltLeaves slice is empty, we will still encode its
814+
// length here (as 0). Callers should avoid encoding empty
815+
// AltLeaves slices.
813816
if err := tlv.WriteVarInt(w, uint64(len(*t)), buf); err != nil {
814817
return err
815818
}

asset/mock.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ import (
66
"crypto/sha256"
77
"encoding/hex"
88
"fmt"
9+
"slices"
910
"testing"
1011

1112
"github.com/btcsuite/btcd/btcec/v2"
1213
"github.com/btcsuite/btcd/btcec/v2/schnorr"
1314
"github.com/btcsuite/btcd/txscript"
1415
"github.com/btcsuite/btcd/wire"
1516
"github.com/lightninglabs/lndclient"
17+
"github.com/lightninglabs/taproot-assets/fn"
1618
"github.com/lightninglabs/taproot-assets/internal/test"
1719
"github.com/lightninglabs/taproot-assets/mssmt"
1820
"github.com/lightningnetwork/lnd/input"
@@ -151,6 +153,14 @@ func CheckAssetAsserts(a *Asset, checks ...AssetAssert) error {
151153
return nil
152154
}
153155

156+
// SortFunc is used to sort assets lexicographically by their script keys.
157+
func SortFunc(a, b *Asset) int {
158+
return bytes.Compare(
159+
a.ScriptKey.PubKey.SerializeCompressed(),
160+
b.ScriptKey.PubKey.SerializeCompressed(),
161+
)
162+
}
163+
154164
// RandGenesis creates a random genesis for testing.
155165
func RandGenesis(t testing.TB, assetType Type) Genesis {
156166
t.Helper()
@@ -660,6 +670,68 @@ func RandAssetWithValues(t testing.TB, genesis Genesis, groupKey *GroupKey,
660670
)
661671
}
662672

673+
// RandAltLeaf generates a random Asset that is a valid AltLeaf.
674+
func RandAltLeaf(t testing.TB) *Asset {
675+
randWitness := []Witness{
676+
{TxWitness: test.RandTxWitnesses(t)},
677+
}
678+
randKey := RandScriptKey(t)
679+
randVersion := ScriptVersion(test.RandInt[uint16]())
680+
randLeaf, err := NewAltLeaf(randKey, randVersion, randWitness)
681+
require.NoError(t, err)
682+
require.NoError(t, randLeaf.ValidateAltLeaf())
683+
684+
return randLeaf
685+
}
686+
687+
// RandAltLeaves generates a random number of random alt leaves.
688+
func RandAltLeaves(t testing.TB, nonZero bool) []*Asset {
689+
// Limit the number of leaves to keep test vectors small.
690+
maxLeaves := 4
691+
numLeaves := test.RandIntn(maxLeaves)
692+
if nonZero {
693+
numLeaves += 1
694+
}
695+
696+
if numLeaves == 0 {
697+
return nil
698+
}
699+
700+
altLeaves := make([]*Asset, numLeaves)
701+
for idx := range numLeaves {
702+
altLeaves[idx] = RandAltLeaf(t)
703+
}
704+
705+
return altLeaves
706+
}
707+
708+
// ToAltLeaves casts []Asset to []AltLeafAsset, without checking that the assets
709+
// are valid AltLeaves.
710+
func ToAltLeaves(leaves []*Asset) []AltLeafAsset {
711+
return fn.Map(leaves, func(l *Asset) AltLeafAsset {
712+
return AltLeafAsset(l)
713+
})
714+
}
715+
716+
// FromAltLeaves casts []AltLeafAsset to []Asset, which is always safe.
717+
func FromAltLeaves(leaves []AltLeafAsset) []*Asset {
718+
return fn.Map(leaves, InnerAltLeaf[*Asset])
719+
}
720+
721+
// CompareAltLeaves compares two slices of AltLeafAssets for equality.
722+
func CompareAltLeaves(t *testing.T, a, b []AltLeafAsset) {
723+
require.Equal(t, len(a), len(b))
724+
725+
aInner := fn.Map(a, InnerAltLeaf[*Asset])
726+
bInner := fn.Map(b, InnerAltLeaf[*Asset])
727+
728+
slices.SortStableFunc(aInner, SortFunc)
729+
slices.SortStableFunc(bInner, SortFunc)
730+
for idx := range aInner {
731+
require.True(t, aInner[idx].DeepEqual(bInner[idx]))
732+
}
733+
}
734+
663735
type ValidTestCase struct {
664736
Asset *TestAsset `json:"asset"`
665737
Expected string `json:"expected"`

tappsbt/decode.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ func proofDecoder(p **proof.Proof) decoderFunc {
366366
}
367367

368368
// altLeavesDecoder returns a decoder function that can handle nil alt leaves.
369-
func altLeavesDecoder(a *[]AltLeafAsset) decoderFunc {
369+
func altLeavesDecoder(a *[]asset.AltLeafAsset) decoderFunc {
370370
return func(key, byteVal []byte) error {
371371
if len(byteVal) == 0 {
372372
return nil

tappsbt/decode_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,8 @@ func TestEncodingDecoding(t *testing.T) {
241241
name: "random packet with colliding alt leaves",
242242
pkg: func(t *testing.T) *VPacket {
243243
pkt := RandPacket(t, true, true)
244-
firstLeaf := RandAltLeaf(t)
245-
secondLeaf := RandAltLeaf(t)
244+
firstLeaf := asset.RandAltLeaf(t)
245+
secondLeaf := asset.RandAltLeaf(t)
246246

247247
firstLeafKey := asset.ToSerialized(
248248
firstLeaf.ScriptKey.PubKey,
@@ -251,7 +251,7 @@ func TestEncodingDecoding(t *testing.T) {
251251
require.NoError(t, err)
252252

253253
secondLeaf.ScriptKey = asset.NewScriptKey(leafKeyCopy)
254-
altLeaves := []AltLeafAsset{firstLeaf, secondLeaf}
254+
altLeaves := []asset.AltLeafAsset{firstLeaf, secondLeaf}
255255

256256
pkt.Inputs[0].AltLeaves = asset.CopyAltLeaves(altLeaves)
257257
pkt.Outputs[0].AltLeaves = asset.CopyAltLeaves(
@@ -270,9 +270,9 @@ func TestEncodingDecoding(t *testing.T) {
270270
pkt := RandPacket(t, true, true)
271271

272272
numLeaves := 2000
273-
altLeaves := make([]AltLeafAsset, 0, numLeaves)
274-
for range numLeaves {
275-
altLeaves = append(altLeaves, RandAltLeaf(t))
273+
altLeaves := make([]asset.AltLeafAsset, numLeaves)
274+
for idx := range numLeaves {
275+
altLeaves[idx] = asset.RandAltLeaf(t)
276276
}
277277

278278
pkt.Inputs[0].AltLeaves = altLeaves

tappsbt/encode.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,9 +384,9 @@ func proofEncoder(p *proof.Proof) encoderFunc {
384384
}
385385

386386
// altLeavesEncoder is an encoder that does nothing if the given alt leaf slice
387-
// is nil.
388-
func altLeavesEncoder(a []AltLeafAsset) encoderFunc {
389-
if a == nil {
387+
// is nil or empty.
388+
func altLeavesEncoder(a []asset.AltLeafAsset) encoderFunc {
389+
if len(a) == 0 {
390390
return func([]byte) ([]*customPsbtField, error) {
391391
return nil, nil
392392
}

tappsbt/interface.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,6 @@ type bip32DerivationPredicate func(*psbt.Bip32Derivation) bool
106106
// BIP-0032 derivation paths.
107107
type taprootBip32DerivationPredicate func(*psbt.TaprootBip32Derivation) bool
108108

109-
// AltLeafAsset is an AltLeaf backed by an Asset object.
110-
type AltLeafAsset = asset.AltLeaf[*asset.Asset]
111-
112109
var (
113110
// VOutIsSplitRoot is a predicate that returns true if the virtual
114111
// output is a split root output.
@@ -399,7 +396,7 @@ type VInput struct {
399396
// will be inserted in the input anchor Tap commitment. These
400397
// data-carrying leaves are used for a purpose distinct from
401398
// representing individual Taproot Assets.
402-
AltLeaves []AltLeafAsset
399+
AltLeaves []asset.AltLeafAsset
403400
}
404401

405402
// Copy creates a deep copy of the VInput.
@@ -599,7 +596,7 @@ type VOutput struct {
599596
// will be inserted in the output anchor Tap commitment. These
600597
// data-carrying leaves are used for a purpose distinct from
601598
// representing individual Taproot Assets.
602-
AltLeaves []AltLeafAsset
599+
AltLeaves []asset.AltLeafAsset
603600
}
604601

605602
// Copy creates a deep copy of the VOutput.

tappsbt/mock.go

Lines changed: 12 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -37,38 +37,6 @@ var (
3737
)
3838
)
3939

40-
// RandAltLeaf generates a random Asset that is a valid AltLeaf.
41-
func RandAltLeaf(t testing.TB) *asset.Asset {
42-
randWitness := []asset.Witness{
43-
{TxWitness: test.RandTxWitnesses(t)},
44-
}
45-
randKey := asset.RandScriptKey(t)
46-
randVersion := asset.ScriptVersion(test.RandInt[uint16]())
47-
randLeaf, err := asset.NewAltLeaf(randKey, randVersion, randWitness)
48-
require.NoError(t, err)
49-
50-
require.NoError(t, randLeaf.ValidateAltLeaf())
51-
52-
return randLeaf
53-
}
54-
55-
// RandAltLeaves generates a set of random number of random alt leaves.
56-
func RandAltLeaves(t testing.TB) []AltLeafAsset {
57-
// Limit the number of leaves to keep the test vectors small.
58-
maxLeaves := int32(4)
59-
numLeaves := test.RandInt31n(maxLeaves)
60-
if numLeaves == 0 {
61-
return nil
62-
}
63-
64-
altLeaves := make([]AltLeafAsset, 0, numLeaves)
65-
for range numLeaves {
66-
altLeaves = append(altLeaves, AltLeafAsset(RandAltLeaf(t)))
67-
}
68-
69-
return altLeaves
70-
}
71-
7240
func RandAssetForPacket(t testing.TB, assetType asset.Type,
7341
desc keychain.KeyDescriptor) *asset.Asset {
7442

@@ -205,9 +173,12 @@ func RandPacket(t testing.TB, setVersion, altLeaves bool) *VPacket {
205173
}
206174

207175
if altLeaves {
208-
randVInput.AltLeaves = RandAltLeaves(t)
209-
randVOutput1.AltLeaves = RandAltLeaves(t)
210-
randVOutput2.AltLeaves = RandAltLeaves(t)
176+
inputLeaves := asset.RandAltLeaves(t, true)
177+
output1Leaves := asset.RandAltLeaves(t, true)
178+
output2Leaves := asset.RandAltLeaves(t, true)
179+
randVInput.AltLeaves = asset.ToAltLeaves(inputLeaves)
180+
randVOutput1.AltLeaves = asset.ToAltLeaves(output1Leaves)
181+
randVOutput2.AltLeaves = asset.ToAltLeaves(output2Leaves)
211182
}
212183

213184
vPacket := &VPacket{
@@ -346,15 +317,9 @@ func NewTestFromVInput(t testing.TB, i *VInput) *TestVInput {
346317

347318
ti.AltLeaves = make([]*asset.TestAsset, 0, len(i.AltLeaves))
348319
for idx := range i.AltLeaves {
349-
// We also need a type assertion on each leaf.
350-
leaf, ok := i.AltLeaves[idx].(*asset.Asset)
351-
if !ok {
352-
t.Errorf("AltLeaf must be of type *asset.Asset")
353-
}
354-
320+
leaf := asset.InnerAltLeaf(i.AltLeaves[idx])
355321
ti.AltLeaves = append(
356-
ti.AltLeaves,
357-
asset.NewTestFromAsset(t, leaf),
322+
ti.AltLeaves, asset.NewTestFromAsset(t, leaf),
358323
)
359324
}
360325
}
@@ -415,7 +380,7 @@ func (ti *TestVInput) ToVInput(t testing.TB) *VInput {
415380
}
416381

417382
if len(ti.AltLeaves) > 0 {
418-
vi.AltLeaves = make([]AltLeafAsset, len(ti.AltLeaves))
383+
vi.AltLeaves = make([]asset.AltLeafAsset, len(ti.AltLeaves))
419384
for idx, leaf := range ti.AltLeaves {
420385
vi.AltLeaves[idx] = leaf.ToAsset(t)
421386
}
@@ -669,15 +634,9 @@ func NewTestFromVOutput(t testing.TB, v *VOutput,
669634

670635
vo.AltLeaves = make([]*asset.TestAsset, 0, len(vo.AltLeaves))
671636
for idx := range v.AltLeaves {
672-
// We also need a type assertion on each leaf.
673-
leaf, ok := v.AltLeaves[idx].(*asset.Asset)
674-
if !ok {
675-
t.Errorf("AltLeaf must be of type *asset.Asset")
676-
}
677-
637+
leaf := asset.InnerAltLeaf(v.AltLeaves[idx])
678638
vo.AltLeaves = append(
679-
vo.AltLeaves,
680-
asset.NewTestFromAsset(t, leaf),
639+
vo.AltLeaves, asset.NewTestFromAsset(t, leaf),
681640
)
682641
}
683642
}
@@ -800,7 +759,7 @@ func (to *TestVOutput) ToVOutput(t testing.TB) *VOutput {
800759
}
801760

802761
if len(to.AltLeaves) > 0 {
803-
v.AltLeaves = make([]AltLeafAsset, len(to.AltLeaves))
762+
v.AltLeaves = make([]asset.AltLeafAsset, len(to.AltLeaves))
804763
for idx, leaf := range to.AltLeaves {
805764
v.AltLeaves[idx] = leaf.ToAsset(t)
806765
}

0 commit comments

Comments
 (0)