Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: add test vectors for asset/address/proof/PSBT TLV encoding and VM/MS-SMT validation #326

Merged
merged 13 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ jobs:
- name: Run go mod tidy
run: make mod-check

test-vector-check:
name: test vector check
runs-on: ubuntu-latest
steps:
- name: git checkout
uses: actions/checkout@v3

- name: Setup go environment
uses: ./.github/actions/setup-go

- name: Run test vector creation check
run: make test-vector-check

########################
# Compilation check.
########################
Expand Down
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,22 @@ mod-check: mod-tidy
@$(call print, "Checking modules.")
if test -n "$$(git status | grep -e "go.mod\|go.sum")"; then echo "Running go mod tidy changes go.mod/go.sum"; git status; git diff; exit 1; fi

gen-test-vectors:
@$(call print, "Generating test vectors.")
make unit gen-test-vectors=true pkg=address case=TestAddressEncoding
make unit gen-test-vectors=true pkg=asset case=TestAssetEncoding
make unit gen-test-vectors=true pkg=mssmt case=TestProofEncoding
make unit gen-test-vectors=true pkg=mssmt case=TestInsertionOverflow
make unit gen-test-vectors=true pkg=mssmt case=TestReplaceWithEmptyBranch
make unit gen-test-vectors=true pkg=mssmt case=TestReplace
make unit gen-test-vectors=true pkg=proof case=TestGenesisProofVerification
make unit gen-test-vectors=true pkg=tappsbt case=TestEncodingDecoding
make unit gen-test-vectors=true pkg=vm case=TestVM

test-vector-check: gen-test-vectors
@$(call print, "Checking test vectors.")
if test -n "$$(git status | grep -e ".json")"; then echo "Test vectors not updated"; git status; git diff; exit 1; fi

clean:
@$(call print, "Cleaning source.$(NC)")
$(RM) coverage.txt
Expand Down
155 changes: 142 additions & 13 deletions address/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package address

import (
"encoding/hex"
"math/rand"
"testing"

"github.com/btcsuite/btcd/btcec/v2"
Expand All @@ -11,6 +10,7 @@ import (
"github.com/btcsuite/btcd/txscript"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/commitment"
"github.com/lightninglabs/taproot-assets/internal/test"
"github.com/stretchr/testify/require"
)

Expand All @@ -22,6 +22,13 @@ var (
"078f",
)
pubKey, _ = schnorr.ParsePubKey(pubKeyBytes)

generatedTestVectorName = "address_tlv_encoding_generated.json"

allTestVectorFiles = []string{
generatedTestVectorName,
"address_tlv_encoding_error_cases.json",
}
)

func randAddress(t *testing.T, net *ChainParams, groupPubKey, sibling bool,
Expand All @@ -35,7 +42,7 @@ func randAddress(t *testing.T, net *ChainParams, groupPubKey, sibling bool,
}

if amt == nil && assetType == asset.Normal {
amount = rand.Uint64()
amount = test.RandInt[uint64]()
}

var tapscriptSibling *commitment.TapscriptPreimage
Expand Down Expand Up @@ -75,7 +82,9 @@ func randEncodedAddress(t *testing.T, net *ChainParams, groupPubKey,
newAddr, err := randAddress(
t, net, groupPubKey, sibling, nil, assetType,
)
require.NoError(t, err)
if err != nil {
return nil, "", err
}

encodedAddr, err := newAddr.EncodeAddress()

Expand All @@ -95,8 +104,6 @@ func assertAddressEqual(t *testing.T, a, b *Tap) {

// TestNewAddress tests edge cases around creating a new address.
func TestNewAddress(t *testing.T) {
t.Parallel()

testCases := []struct {
name string
f func() (*Tap, error)
Expand Down Expand Up @@ -167,9 +174,9 @@ func TestNewAddress(t *testing.T) {
}

for _, testCase := range testCases {
success := t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
testCase := testCase
guggero marked this conversation as resolved.
Show resolved Hide resolved

success := t.Run(testCase.name, func(t *testing.T) {
address, err := testCase.f()
require.Equal(t, testCase.err, err)

Expand All @@ -188,7 +195,8 @@ func TestNewAddress(t *testing.T) {
func TestAddressEncoding(t *testing.T) {
t.Parallel()

assetAddressEncoding := func(a *Tap) {
testVectors := &TestVectors{}
assertAddressEncoding := func(comment string, a *Tap) {
t.Helper()

assertAddressEqual(t, a, a.Copy())
Expand All @@ -199,6 +207,14 @@ func TestAddressEncoding(t *testing.T) {
b, err := DecodeAddress(addr, net)
require.NoError(t, err)
assertAddressEqual(t, a, b)

testVectors.ValidTestCases = append(
testVectors.ValidTestCases, &ValidTestCase{
Address: NewTestFromAddress(t, a),
Expected: addr,
Comment: comment,
},
)
}

testCases := []struct {
Expand All @@ -207,7 +223,7 @@ func TestAddressEncoding(t *testing.T) {
err error
}{
{
name: "valid address",
name: "valid regtest address",
f: func() (*Tap, string, error) {
return randEncodedAddress(
t, &RegressionNetTap, false, false,
Expand All @@ -217,7 +233,37 @@ func TestAddressEncoding(t *testing.T) {
err: nil,
},
{
name: "group collectible",
name: "valid simnet address",
f: func() (*Tap, string, error) {
return randEncodedAddress(
t, &SimNetTap, false, false,
asset.Normal,
)
},
err: nil,
},
{
name: "valid testnet address",
f: func() (*Tap, string, error) {
return randEncodedAddress(
t, &TestNet3Tap, false, false,
asset.Normal,
)
},
err: nil,
},
{
name: "valid mainnet address",
f: func() (*Tap, string, error) {
return randEncodedAddress(
t, &MainNetTap, false, false,
asset.Normal,
)
},
err: nil,
},
{
name: "signet group collectible",
f: func() (*Tap, string, error) {
return randEncodedAddress(
t, &SigNetTap, true, false,
Expand Down Expand Up @@ -288,17 +334,100 @@ func TestAddressEncoding(t *testing.T) {
}

for _, testCase := range testCases {
success := t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
testCase := testCase

success := t.Run(testCase.name, func(t *testing.T) {
addr, _, err := testCase.f()
require.Equal(t, testCase.err, err)
if testCase.err == nil {
assetAddressEncoding(addr)
assertAddressEncoding(testCase.name, addr)
}
})
if !success {
return
}
}

// Write test vectors to file. This is a no-op if the "gen_test_vectors"
// build tag is not set.
test.WriteTestVectors(t, generatedTestVectorName, testVectors)
}

// TestBIPTestVectors tests that the BIP test vectors are passing.
func TestBIPTestVectors(t *testing.T) {
t.Parallel()

for idx := range allTestVectorFiles {
var (
fileName = allTestVectorFiles[idx]
testVectors = &TestVectors{}
)
test.ParseTestVectors(t, fileName, &testVectors)
t.Run(fileName, func(tt *testing.T) {
tt.Parallel()

runBIPTestVector(tt, testVectors)
})
}
}

// runBIPTestVector runs the tests in a single BIP test vector file.
func runBIPTestVector(t *testing.T, testVectors *TestVectors) {
for _, validCase := range testVectors.ValidTestCases {
validCase := validCase

t.Run(validCase.Comment, func(tt *testing.T) {
tt.Parallel()

a := validCase.Address.ToAddress(tt)

addrString, err := a.EncodeAddress()
require.NoError(tt, err)

areEqual := validCase.Expected == addrString

// Create nice diff if things don't match.
if !areEqual {
chainParams, err := a.Net()
require.NoError(tt, err)

expectedAddress, err := DecodeAddress(
validCase.Expected, chainParams,
)
require.NoError(tt, err)

require.Equal(tt, a, expectedAddress)

// Make sure we still fail the test.
require.Equal(
tt, validCase.Expected,
addrString,
)
}

// We also want to make sure that the address is decoded
// correctly from the encoded TLV stream.
chainParams, err := a.Net()
require.NoError(tt, err)

decoded, err := DecodeAddress(
validCase.Expected, chainParams,
)
require.NoError(tt, err)

require.Equal(tt, a, decoded)
})
}

for _, invalidCase := range testVectors.ErrorTestCases {
invalidCase := invalidCase

t.Run(invalidCase.Comment, func(tt *testing.T) {
tt.Parallel()

require.PanicsWithValue(tt, invalidCase.Error, func() {
invalidCase.Address.ToAddress(tt)
})
})
}
}
Loading
Loading