Skip to content

Commit

Permalink
Merge pull request #550 from lightninglabs/loadtest-multiple-times
Browse files Browse the repository at this point in the history
loadtest: prepare for multiple consecutive runs
  • Loading branch information
Roasbeef authored Oct 6, 2023
2 parents aa8d776 + e5d4a15 commit b8af77d
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 51 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ cmd/tapd/tapd
/itest/.minerlogs/*
/itest/tapd-itest

# Load test binaries and config
/loadtest
/loadtest.conf

# Test binary, built with `go test -c`
*.test

Expand Down
54 changes: 27 additions & 27 deletions itest/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -932,12 +932,17 @@ func AssertSplitTombstoneTransfer(t *testing.T,
func AssertNumGroups(t *testing.T, client taprpc.TaprootAssetsClient,
num int) {

require.Equal(t, num, NumGroups(t, client))
}

// NumGroups returns the current number of asset groups present.
func NumGroups(t *testing.T, client taprpc.TaprootAssetsClient) int {
ctxb := context.Background()
groupResp, err := client.ListGroups(
ctxb, &taprpc.ListGroupsRequest{},
)
require.NoError(t, err)
require.Equal(t, num, len(groupResp.Groups))
return len(groupResp.Groups)
}

// AssertGroupSizes asserts that a set of groups the daemon is aware of contain
Expand Down Expand Up @@ -1039,40 +1044,37 @@ func AssertUniverseRootEquality(t *testing.T,
))
}

// AssertUniverseRoot makes sure the given universe root exists with the given
// sum, either identified by the asset ID or group key.
func AssertUniverseRoot(t *testing.T, client unirpc.UniverseClient,
sum int, assetID []byte, groupKey []byte) error {
sum int, assetID []byte, groupKey []byte) {

bothSet := assetID != nil && groupKey != nil
neitherSet := assetID == nil && groupKey == nil
if bothSet || neitherSet {
return fmt.Errorf("only set one of assetID or groupKey")
}

// Re-parse and serialize the keys to account for the different
// formats returned in RPC responses.
matchingGroupKey := func(root *unirpc.UniverseRoot) bool {
rootGroupKeyBytes := root.Id.GetGroupKey()
require.NotNil(t, rootGroupKeyBytes)

expectedGroupKey, err := btcec.ParsePubKey(groupKey)
require.NoError(t, err)
require.Equal(
t, rootGroupKeyBytes,
schnorr.SerializePubKey(expectedGroupKey),
)

return true
}
require.False(
t, bothSet || neitherSet, "only set one of assetID or groupKey",
)

// Comparing the asset ID is always safe, even if nil.
matchingRoot := func(root *unirpc.UniverseRoot) bool {
require.Equal(t, root.MssmtRoot.RootSum, int64(sum))
require.Equal(t, root.Id.GetAssetId(), assetID)
sumEqual := root.MssmtRoot.RootSum == int64(sum)
idEqual := bytes.Equal(root.Id.GetAssetId(), assetID)
groupKeyEqual := true
if groupKey != nil {
return matchingGroupKey(root)
parsedGroupKey, err := btcec.ParsePubKey(groupKey)
require.NoError(t, err)

rootGroupKey := root.Id.GetGroupKey()
if rootGroupKey != nil {
groupKeyEqual = bytes.Equal(
rootGroupKey, schnorr.SerializePubKey(
parsedGroupKey,
),
)
}
}

return true
return sumEqual && idEqual && groupKeyEqual
}

ctx := context.Background()
Expand All @@ -1082,8 +1084,6 @@ func AssertUniverseRoot(t *testing.T, client unirpc.UniverseClient,

correctRoot := fn.Any(maps.Values(uniRoots.UniverseRoots), matchingRoot)
require.True(t, correctRoot)

return nil
}

func AssertUniverseRootEqual(a, b *unirpc.UniverseRoot) bool {
Expand Down
56 changes: 40 additions & 16 deletions itest/loadtest/mint_batch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ package loadtest

import (
"context"
_ "embed"
"encoding/binary"
"encoding/hex"
"fmt"
"strconv"
"math/rand"
"strings"
"testing"
"time"

_ "embed"

"github.com/btcsuite/btcd/rpcclient"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/itest"
"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightninglabs/taproot-assets/universe"
"github.com/stretchr/testify/require"
)

Expand All @@ -44,6 +44,15 @@ func execMintBatchStressTest(t *testing.T, ctx context.Context, cfg *Config) {
// Create bitcoin client.
bitcoinClient := getBitcoinConn(t, cfg.Bitcoin)

itest.MineBlocks(t, bitcoinClient, 1, 0)

// If we fail from this point onward, we might have created a
// transaction that isn't mined yet. To make sure we can run the test
// again, we'll make sure to clean up the mempool by mining a block.
t.Cleanup(func() {
itest.MineBlocks(t, bitcoinClient, 1, 0)
})

imageMetadataBytes, err := hex.DecodeString(
strings.Trim(string(imageMetadataHex), "\n"),
)
Expand All @@ -66,11 +75,15 @@ func mintBatchStressTest(t *testing.T, ctx context.Context,

var (
batchReqs = make([]*mintrpc.MintAssetRequest, batchSize)
baseName = "jpeg"
baseName = fmt.Sprintf("jpeg-%d", rand.Int31())
metaPrefixSize = binary.MaxVarintLen16
metadataPrefix = make([]byte, metaPrefixSize)
)

// Before we mint a new group, let's first find out how many there
// already are.
initialGroups := itest.NumGroups(t, alice)

// Each asset in the batch will share a name and metdata preimage, that
// will be updated based on the asset's index in the batch.
collectibleRequestTemplate := mintrpc.MintAssetRequest{
Expand All @@ -87,9 +100,9 @@ func mintBatchStressTest(t *testing.T, ctx context.Context,
}

// Update the asset name and metadata to match an index.
incrementMintAsset := func(asset *mintrpc.MintAsset, ind int) {
asset.Name = asset.Name + strconv.Itoa(ind)
binary.PutUvarint(metadataPrefix, uint64(ind))
incrementMintAsset := func(asset *mintrpc.MintAsset, idx int) {
asset.Name = fmt.Sprintf("%s-%d", asset.Name, idx)
binary.PutUvarint(metadataPrefix, uint64(idx))
copy(asset.AssetMeta.Data[0:metaPrefixSize], metadataPrefix)
}

Expand Down Expand Up @@ -131,7 +144,7 @@ func mintBatchStressTest(t *testing.T, ctx context.Context,

// We should have one group, with the specified number of assets and an
// equivalent balance, since the group is made of collectibles.
groupCount := 1
groupCount := initialGroups + 1
groupBalance := batchSize

itest.AssertNumGroups(t, alice, groupCount)
Expand All @@ -146,16 +159,11 @@ func mintBatchStressTest(t *testing.T, ctx context.Context,
// The universe tree should reflect the same properties about the batch;
// there should be one root with a group key and balance matching what
// we asserted previously.
uniRoots, err := alice.AssetRoots(
ctx, &unirpc.AssetRootRequest{},
)
uniRoots, err := alice.AssetRoots(ctx, &unirpc.AssetRootRequest{})
require.NoError(t, err)
require.Len(t, uniRoots.UniverseRoots, groupCount)

err = itest.AssertUniverseRoot(
t, alice, groupBalance, nil, collectGroupKey,
)
require.NoError(t, err)
itest.AssertUniverseRoot(t, alice, groupBalance, nil, collectGroupKey)

// The universe tree should also have a leaf for each asset minted.
// TODO(jhb): Resolve issue of 33-byte group key handling.
Expand Down Expand Up @@ -189,7 +197,23 @@ func mintBatchStressTest(t *testing.T, ctx context.Context,
},
},
)
require.NoError(t, err)
if err != nil {
// Only fail the test for other errors than duplicate universe
// errors, as we might have already added the server in a
// previous run.
require.ErrorContains(
t, err, universe.ErrDuplicateUniverse.Error(),
)

// If we've already added the server in a previous run, we'll
// just need to kick off a sync (as that would otherwise be done
// by adding the server request already).
_, err := bob.SyncUniverse(ctx, &unirpc.SyncRequest{
UniverseHost: aliceHost,
SyncMode: unirpc.UniverseSyncMode_SYNC_ISSUANCE_ONLY,
})
require.NoError(t, err)
}

require.Eventually(t, func() bool {
return itest.AssertUniverseStateEqual(
Expand Down
5 changes: 1 addition & 4 deletions itest/mint_batch_stress_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,7 @@ func mintBatchStressTest(
require.NoError(t, err)
require.Len(t, uniRoots.UniverseRoots, groupCount)

err = AssertUniverseRoot(
t, alice, groupBalance, nil, collectGroupKey,
)
require.NoError(t, err)
AssertUniverseRoot(t, alice, groupBalance, nil, collectGroupKey)

// The universe tree should also have a leaf for each asset minted.
// TODO(jhb): Resolve issue of 33-byte group key handling.
Expand Down
32 changes: 28 additions & 4 deletions itest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"testing"
"time"

"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
Expand All @@ -20,7 +22,9 @@ import (
)

var (
zeroHash chainhash.Hash
zeroHash chainhash.Hash
regtestMiningAddr = "n1VgRjYDzJT2TV72PnungWgWu18SWorXZS"
regtestParams = &chaincfg.RegressionNetParams
)

// CopyRequest is a helper function to copy a request so that we can modify it.
Expand Down Expand Up @@ -101,9 +105,29 @@ func MineBlocks(t *testing.T, client *rpcclient.Client,

blocks := make([]*wire.MsgBlock, num)

blockHashes, err := client.Generate(num)
if err != nil {
t.Fatalf("unable to generate blocks: %v", err)
backend, err := client.BackendVersion()
require.NoError(t, err)

var blockHashes []*chainhash.Hash

switch backend {
case rpcclient.BitcoindPost19:
addr, err := btcutil.DecodeAddress(
regtestMiningAddr, regtestParams,
)
require.NoError(t, err)

blockHashes, err = client.GenerateToAddress(
int64(num), addr, nil,
)
require.NoError(t, err)

case rpcclient.Btcd:
blockHashes, err = client.Generate(num)
require.NoError(t, err)

default:
require.Fail(t, "unknown chain backend: %v", backend)
}

for i, blockHash := range blockHashes {
Expand Down

0 comments on commit b8af77d

Please sign in to comment.