Skip to content

Commit c04fbbb

Browse files
committed
asset: add GroupKeyRevealV1 encoding/decoding unit test
Unit test also validates spend script control block.
1 parent 471707b commit c04fbbb

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

asset/group_key_reveal_test.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package asset
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/btcsuite/btcd/btcec/v2"
8+
"github.com/btcsuite/btcd/chaincfg/chainhash"
9+
"github.com/btcsuite/btcd/txscript"
10+
"github.com/lightninglabs/taproot-assets/fn"
11+
"github.com/lightninglabs/taproot-assets/internal/test"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
type testCaseGkrEncodeDecode struct {
16+
testName string
17+
18+
internalKey btcec.PublicKey
19+
genesisAssetID ID
20+
customSubtreeRoot fn.Option[chainhash.Hash]
21+
}
22+
23+
// GroupKeyReveal generates a GroupKeyReveal instance from the test case.
24+
func (tc testCaseGkrEncodeDecode) GroupKeyReveal() (GroupKeyReveal, error) {
25+
gkr, err := NewGroupKeyRevealV1(
26+
tc.internalKey, tc.genesisAssetID, tc.customSubtreeRoot,
27+
).Unpack()
28+
29+
return &gkr, err
30+
}
31+
32+
func TestGroupKeyTapscriptEncodeDecode(t *testing.T) {
33+
t.Parallel()
34+
35+
// Create a random internal public key.
36+
internalKey := *(test.RandPubKey(t))
37+
38+
// Create a random genesis asset ID.
39+
randomAssetIdBytes := test.RandBytes(32)
40+
genesisAssetID := ID(randomAssetIdBytes)
41+
42+
// Construct a custom user script leaf. This is used to validate any
43+
// control block.
44+
customScriptLeaf := txscript.NewBaseTapLeaf(
45+
[]byte("I'm a custom user script"),
46+
)
47+
customSubtreeRoot := fn.Some(customScriptLeaf.TapHash())
48+
49+
testCases := []testCaseGkrEncodeDecode{
50+
{
51+
testName: "no custom root",
52+
53+
internalKey: internalKey,
54+
genesisAssetID: genesisAssetID,
55+
customSubtreeRoot: fn.None[chainhash.Hash](),
56+
},
57+
{
58+
testName: "with custom root",
59+
60+
internalKey: internalKey,
61+
genesisAssetID: genesisAssetID,
62+
customSubtreeRoot: customSubtreeRoot,
63+
},
64+
}
65+
66+
for _, tc := range testCases {
67+
t.Run(tc.testName, func(tt *testing.T) {
68+
gkr, err := tc.GroupKeyReveal()
69+
require.NoError(tt, err)
70+
71+
groupPubKey, err := gkr.GroupPubKey(tc.genesisAssetID)
72+
require.NoError(tt, err)
73+
74+
// Encode the GroupKeyReveal into buffer.
75+
var buffer bytes.Buffer
76+
var scratchBuffEncode [8]byte
77+
err = GroupKeyRevealEncoder(
78+
&buffer, &gkr, &scratchBuffEncode,
79+
)
80+
require.NoError(tt, err)
81+
82+
// Decode the GroupKeyReveal from buffer.
83+
var gkrDecoded GroupKeyReveal
84+
var scratchBuffDecode [8]byte
85+
err = GroupKeyRevealDecoder(
86+
&buffer, &gkrDecoded, &scratchBuffDecode,
87+
uint64(buffer.Len()),
88+
)
89+
require.NoError(tt, err)
90+
91+
// Prepare the original GroupKeyReveal for comparison.
92+
// Remove fields which are not included in
93+
// encoding/decoding.
94+
gkrV1, ok := gkr.(*GroupKeyRevealV1)
95+
require.True(tt, ok)
96+
gkrV1.tapscript.customSubtreeInclusionProof = nil
97+
98+
// Compare decoded group key reveal with the original.
99+
require.Equal(tt, gkrV1, gkrDecoded)
100+
101+
// Ensure the decoded group public key matches the
102+
// original.
103+
groupPubKeyDecoded, err := gkrDecoded.GroupPubKey(
104+
tc.genesisAssetID,
105+
)
106+
require.NoError(tt, err)
107+
108+
require.Equal(
109+
tt, groupPubKey, groupPubKeyDecoded,
110+
"decoded GroupKeyReveal group pub key does "+
111+
"not match original",
112+
)
113+
114+
// If a custom subtree root is set, ensure the control
115+
// block is correct.
116+
if tc.customSubtreeRoot.IsSome() {
117+
gkrDecodedV1, ok :=
118+
gkrDecoded.(*GroupKeyRevealV1)
119+
require.True(tt, ok)
120+
121+
ctrlBlock, err :=
122+
gkrDecodedV1.ScriptSpendControlBlock(
123+
tc.genesisAssetID,
124+
).Unpack()
125+
require.NoError(tt, err)
126+
127+
// Use the control block and the custom spend
128+
// script to compute the root hash.
129+
computedRoot := chainhash.Hash(
130+
ctrlBlock.RootHash(
131+
customScriptLeaf.Script,
132+
),
133+
)
134+
135+
// Ensure the computed root matches the custom
136+
// subtree root.
137+
require.Equal(
138+
tt, gkrDecodedV1.tapscript.root,
139+
computedRoot,
140+
)
141+
}
142+
})
143+
}
144+
}

0 commit comments

Comments
 (0)