From 4b62aeb6f1f08def77266153fd60422bdf5454ab Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 22 Dec 2023 00:54:25 -0800 Subject: [PATCH 01/16] e2e: Switch warp test to use tmpnet fixture --- .github/workflows/ci.yml | 21 +- scripts/run_ginkgo_warp.sh | 16 +- tests/init.go | 22 ++ tests/utils/runner/network_manager.go | 3 + tests/utils/tmpnet.go | 52 +++++ tests/warp/warp_test.go | 304 +++++++++++++------------- 6 files changed, 245 insertions(+), 173 deletions(-) create mode 100644 tests/utils/tmpnet.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5fa749548..0754148c92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,9 @@ on: - 'v[0-9]+.[0-9]+.[0-9]+' pull_request: +env: + tmpnet_data_path: ~/.tmpnet/networks/1000 + jobs: lint_test: name: Lint @@ -124,14 +127,14 @@ jobs: run: ./scripts/build.sh /tmp/e2e-test/avalanchego/plugins/srEXiWaHuhNyGwPUi444Tu47ZEDwxTWrbQiuD7FmgSAQ6X7Dy - name: Run Warp E2E Tests shell: bash - run: AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego DATA_DIR=/tmp/e2e-test/warp-data ./scripts/run_ginkgo_warp.sh - - name: Upload Artifact + run: AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego ./scripts/run_ginkgo_warp.sh + - name: Upload tmpnet network dir for warp testing if: always() uses: actions/upload-artifact@v4 with: - name: subnet-evm-e2e-logs-warp - path: /tmp/network-runner-root-data*/ - retention-days: 5 + name: warp-tmpnet-data + path: ${{ env.tmpnet_data_path }} + if-no-files-found: error e2e_load: name: e2e load tests runs-on: ubuntu-latest @@ -154,13 +157,13 @@ jobs: - name: Run E2E Load Tests shell: bash run: AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego DATA_DIR=/tmp/e2e-test/load-data ./scripts/run_ginkgo_load.sh - - name: Upload Artifact + - name: Upload tmpnet network dir for load testing if: always() uses: actions/upload-artifact@v4 with: - name: subnet-evm-e2e-logs-load - path: /tmp/network-runner-root-data*/ - retention-days: 5 + name: load-tmpnet-data + path: ${{ env.tmpnet_data_path }} + if-no-files-found: error build_image: name: Build Docker Image diff --git a/scripts/run_ginkgo_warp.sh b/scripts/run_ginkgo_warp.sh index 3f12a4800c..feaebdbe50 100755 --- a/scripts/run_ginkgo_warp.sh +++ b/scripts/run_ginkgo_warp.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash -set -e + +set -euo pipefail # This script assumes that an AvalancheGo and Subnet-EVM binaries are available in the standard location # within the $GOPATH @@ -17,10 +18,13 @@ source "$SUBNET_EVM_PATH"/scripts/versions.sh # Build ginkgo # to install the ginkgo binary (required for test build and run) -go install -v "github.com/onsi/ginkgo/v2/ginkgo@${GINKGO_VERSION}" +go install -v github.com/onsi/ginkgo/v2/ginkgo@"${GINKGO_VERSION}" -ACK_GINKGO_RC=true ginkgo build ./tests/warp +EXTRA_ARGS= +AVALANCHEGO_BUILD_PATH="${AVALANCHEGO_BUILD_PATH:-}" +if [[ -n "${AVALANCHEGO_BUILD_PATH}" ]]; then + EXTRA_ARGS="-- --avalanchego-path=${AVALANCHEGO_BUILD_PATH}/avalanchego --plugin-dir=${AVALANCHEGO_BUILD_PATH}/plugins" + echo "Running with extra args: ${EXTRA_ARGS}" +fi -./tests/warp/warp.test \ - --ginkgo.vv \ - --ginkgo.label-filter="${GINKGO_LABEL_FILTER:-""}" +ginkgo -vv --label-filter="${GINKGO_LABEL_FILTER:-}" ./tests/warp ${EXTRA_ARGS} diff --git a/tests/init.go b/tests/init.go index 69ed834d6e..6d2d5bae9e 100644 --- a/tests/init.go +++ b/tests/init.go @@ -29,7 +29,9 @@ package tests import ( "fmt" "math/big" + "os" "sort" + "strings" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/utils" @@ -215,3 +217,23 @@ type UnsupportedForkError struct { func (e UnsupportedForkError) Error() string { return fmt.Sprintf("unsupported fork %q", e.Name) } + +func GetRepoRootPath(suffix string) string { + // - When executed via a test binary, the working directory will be wherever + // the binary is executed from, but scripts should require execution from + // the repo root. + // + // - When executed via ginkgo (nicer for development + supports + // parallel execution) the working directory will always be the + // target path (e.g. [repo root]./tests/warp) and getting the repo + // root will require stripping the target path suffix. + // + // TODO(marun) Avoid relying on the current working directory to find test + // dependencies by embedding data where possible (e.g. for genesis) and + // explicitly configuring paths for execution. + cwd, err := os.Getwd() + if err != nil { + panic(err) + } + return strings.TrimSuffix(cwd, suffix) +} diff --git a/tests/utils/runner/network_manager.go b/tests/utils/runner/network_manager.go index 138ce73034..352c23bb71 100644 --- a/tests/utils/runner/network_manager.go +++ b/tests/utils/runner/network_manager.go @@ -5,6 +5,7 @@ package runner import ( "context" + "crypto/ecdsa" "fmt" "os" "time" @@ -28,6 +29,8 @@ type Subnet struct { SubnetID ids.ID `json:"subnetID"` // Current ANR assumes one blockchain per subnet, so we have a single blockchainID here BlockchainID ids.ID `json:"blockchainID"` + // Key funded in the genesis of the blockchain + PreFundedKey *ecdsa.PrivateKey // ValidatorURIs is the base URIs for each participant of the Subnet ValidatorURIs []string `json:"validatorURIs"` } diff --git a/tests/utils/tmpnet.go b/tests/utils/tmpnet.go new file mode 100644 index 0000000000..3878d334c2 --- /dev/null +++ b/tests/utils/tmpnet.go @@ -0,0 +1,52 @@ +// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package utils + +import ( + "encoding/json" + "os" + + "github.com/ava-labs/avalanchego/config" + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" + + "github.com/ava-labs/subnet-evm/plugin/evm" +) + +func NewTmpnetNetwork(subnets ...*tmpnet.Subnet) *tmpnet.Network { + return &tmpnet.Network{ + DefaultFlags: tmpnet.FlagsMap{ + config.ProposerVMUseCurrentHeightKey: true, + }, + Subnets: subnets, + } +} + +// Create the configuration that will enable creation and access to a +// subnet created on a temporary network. +func NewTmpnetSubnet(name string, genesisPath string) *tmpnet.Subnet { + genesisBytes, err := os.ReadFile(genesisPath) + if err != nil { + panic(err) + } + + configBytes, err := json.Marshal(tmpnet.FlagsMap{ + "log-level": "debug", + "warp-api-enabled": true, + }) + if err != nil { + panic(err) + } + + return &tmpnet.Subnet{ + Name: name, + Chains: []*tmpnet.Chain{ + { + VMName: evm.IDStr, + Genesis: genesisBytes, + Config: string(configBytes), + PreFundedKey: tmpnet.HardhatKey, + }, + }, + } +} diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index a783dab59d..bbf2c92a2a 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -11,18 +11,31 @@ import ( "fmt" "math/big" "os" + "path/filepath" "strings" "testing" "time" - "github.com/ava-labs/avalanche-network-runner/rpcpb" + ginkgo "github.com/onsi/ginkgo/v2" + + "github.com/onsi/gomega" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/tests/fixture/e2e" + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/platformvm" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" + "github.com/ava-labs/subnet-evm/cmd/simulator/key" "github.com/ava-labs/subnet-evm/cmd/simulator/load" "github.com/ava-labs/subnet-evm/cmd/simulator/metrics" @@ -31,168 +44,129 @@ import ( "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/interfaces" "github.com/ava-labs/subnet-evm/params" - "github.com/ava-labs/subnet-evm/plugin/evm" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" "github.com/ava-labs/subnet-evm/predicate" + "github.com/ava-labs/subnet-evm/tests" "github.com/ava-labs/subnet-evm/tests/utils" "github.com/ava-labs/subnet-evm/tests/utils/runner" warpBackend "github.com/ava-labs/subnet-evm/warp" "github.com/ava-labs/subnet-evm/warp/aggregator" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/log" - ginkgo "github.com/onsi/ginkgo/v2" - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" ) -const fundedKeyStr = "56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027" // addr: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC - -var ( - config = runner.NewDefaultANRConfig() - manager = runner.NewNetworkManager(config) - warpChainConfigPath string - testPayload = []byte{1, 2, 3} - nodesPerSubnet = 5 - fundedKey *ecdsa.PrivateKey - subnetA, subnetB, cChainSubnetDetails *runner.Subnet - warpTableEntries = []ginkgo.TableEntry{ - ginkgo.Entry("SubnetA -> SubnetB", func() *warpTest { - return newWarpTest(context.Background(), subnetA, fundedKey, subnetB, fundedKey) - }), - ginkgo.Entry("SubnetA -> SubnetA", func() *warpTest { - return newWarpTest(context.Background(), subnetA, fundedKey, subnetA, fundedKey) - }), - ginkgo.Entry("SubnetA -> C-Chain", func() *warpTest { - return newWarpTest(context.Background(), subnetA, fundedKey, cChainSubnetDetails, fundedKey) - }), - ginkgo.Entry("C-Chain -> SubnetA", func() *warpTest { - return newWarpTest(context.Background(), cChainSubnetDetails, fundedKey, subnetA, fundedKey) - }), - ginkgo.Entry("C-Chain -> C-Chain", func() *warpTest { - return newWarpTest(context.Background(), cChainSubnetDetails, fundedKey, cChainSubnetDetails, fundedKey) - }), - } +const ( + subnetAName = "warp-subnet-a" + subnetBName = "warp-subnet-b" ) -var _ = ginkgo.DescribeTable("[Warp]", func(gen func() *warpTest) { - w := gen() - - log.Info("Sending message from A to B") - w.sendMessageFromSendingSubnet() - - log.Info("Aggregating signatures via API") - w.aggregateSignaturesViaAPI() +var ( + flagVars *e2e.FlagVars - log.Info("Aggregating signatures via p2p aggregator") - w.aggregateSignatures() + repoRootPath = tests.GetRepoRootPath("tests/warp") - log.Info("Delivering addressed call payload to receiving subnet") - w.deliverAddressedCallToReceivingSubnet() + genesisPath = filepath.Join(repoRootPath, "tests/precompile/genesis/warp.json") - log.Info("Delivering block hash payload to receiving subnet") - w.deliverBlockHashPayload() + subnetA, subnetB, cChainSubnetDetails *runner.Subnet - log.Info("Executing HardHat test") - w.executeHardHatTest() + testPayload = []byte{1, 2, 3} +) - log.Info("Executing warp load test") - w.warpLoad() -}, warpTableEntries) +func init() { + // Configures flags used to configure tmpnet (via SynchronizedBeforeSuite) + flagVars = e2e.RegisterFlags() +} func TestE2E(t *testing.T) { gomega.RegisterFailHandler(ginkgo.Fail) ginkgo.RunSpecs(t, "subnet-evm warp e2e test") } -func toWebsocketURI(uri string, blockchainID string) string { - return fmt.Sprintf("ws://%s/ext/bc/%s/ws", strings.TrimPrefix(uri, "http://"), blockchainID) -} +var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { + // Run only once in the first ginkgo process + return e2e.NewTestEnvironment( + flagVars, + utils.NewTmpnetNetwork( + utils.NewTmpnetSubnet(subnetAName, genesisPath), + utils.NewTmpnetSubnet(subnetBName, genesisPath), + ), + ).Marshal() +}, func(envBytes []byte) { + // Run in every ginkgo process -// BeforeSuite starts the default network and adds 10 new nodes as validators with BLS keys -// registered on the P-Chain. -// Adds two disjoint sets of 5 of the new validator nodes to validate two new subnets with a -// a single Subnet-EVM blockchain. -var _ = ginkgo.BeforeSuite(func() { - ctx := context.Background() require := require.New(ginkgo.GinkgoT()) - // Name 10 new validators (which should have BLS key registered) - subnetANodeNames := make([]string, 0) - subnetBNodeNames := make([]string, 0) - for i := 0; i < nodesPerSubnet; i++ { - subnetANodeNames = append(subnetANodeNames, fmt.Sprintf("node%d-subnetA-bls", i)) - subnetBNodeNames = append(subnetBNodeNames, fmt.Sprintf("node%d-subnetB-bls", i)) + // Initialize the local test environment from the global state + if len(envBytes) > 0 { + e2e.InitSharedTestEnvironment(envBytes) } - f, err := os.CreateTemp(os.TempDir(), "config.json") - require.NoError(err) - _, err = f.Write([]byte(`{ - "warp-api-enabled": true, - "log-level": "debug" - }`)) - require.NoError(err) - warpChainConfigPath = f.Name() - - // Construct the network using the avalanche-network-runner - _, err = manager.StartDefaultNetwork(ctx) - require.NoError(err) - err = manager.SetupNetwork( - ctx, - config.AvalancheGoExecPath, - []*rpcpb.BlockchainSpec{ - { - VmName: evm.IDStr, - Genesis: "./tests/precompile/genesis/warp.json", - ChainConfig: warpChainConfigPath, - SubnetSpec: &rpcpb.SubnetSpec{ - SubnetConfig: "", - Participants: subnetANodeNames, - }, - }, - { - VmName: evm.IDStr, - Genesis: "./tests/precompile/genesis/warp.json", - ChainConfig: warpChainConfigPath, - SubnetSpec: &rpcpb.SubnetSpec{ - SubnetConfig: "", - Participants: subnetBNodeNames, - }, - }, - }, - ) - require.NoError(err) + network := e2e.Env.GetNetwork() - fundedKey, err = crypto.HexToECDSA(fundedKeyStr) - require.NoError(err) - subnetIDs := manager.GetSubnets() + // By default all nodes are validating all subnets + validatorURIs := make([]string, len(network.Nodes)) + for i, node := range network.Nodes { + validatorURIs[i] = node.URI + } - var ok bool - subnetA, ok = manager.GetSubnet(subnetIDs[0]) - require.True(ok) - subnetB, ok = manager.GetSubnet(subnetIDs[1]) - require.True(ok) + tmpnetSubnetA := network.GetSubnet(subnetAName) + require.NotNil(tmpnetSubnetA) + subnetA = &runner.Subnet{ + SubnetID: tmpnetSubnetA.SubnetID, + BlockchainID: tmpnetSubnetA.Chains[0].ChainID, + PreFundedKey: tmpnetSubnetA.Chains[0].PreFundedKey.ToECDSA(), + ValidatorURIs: validatorURIs, + } - infoClient := info.NewClient(subnetA.ValidatorURIs[0]) - cChainBlockchainID, err := infoClient.GetBlockchainID(ctx, "C") - require.NoError(err) + tmpnetSubnetB := network.GetSubnet(subnetBName) + require.NotNil(tmpnetSubnetB) + subnetB = &runner.Subnet{ + SubnetID: tmpnetSubnetB.SubnetID, + BlockchainID: tmpnetSubnetB.Chains[0].ChainID, + PreFundedKey: tmpnetSubnetB.Chains[0].PreFundedKey.ToECDSA(), + ValidatorURIs: validatorURIs, + } - allURIs, err := manager.GetAllURIs(ctx) + infoClient := info.NewClient(network.Nodes[0].URI) + cChainBlockchainID, err := infoClient.GetBlockchainID(e2e.DefaultContext(), "C") require.NoError(err) cChainSubnetDetails = &runner.Subnet{ SubnetID: constants.PrimaryNetworkID, BlockchainID: cChainBlockchainID, - ValidatorURIs: allURIs, + PreFundedKey: tmpnet.HardhatKey.ToECDSA(), + ValidatorURIs: validatorURIs, } }) -var _ = ginkgo.AfterSuite(func() { - require := require.New(ginkgo.GinkgoT()) - require.NotNil(manager) - require.NoError(manager.TeardownNetwork()) - require.NoError(os.Remove(warpChainConfigPath)) - // TODO: bootstrap an additional node (covering all of the subnets) after the test) +var _ = ginkgo.Describe("[Warp]", func() { + testFunc := func(sendingSubnet *runner.Subnet, receivingSubnet *runner.Subnet) { + w := newWarpTest(e2e.DefaultContext(), sendingSubnet, receivingSubnet) + + log.Info("Sending message from A to B") + w.sendMessageFromSendingSubnet() + + log.Info("Aggregating signatures via API") + w.aggregateSignaturesViaAPI() + + log.Info("Aggregating signatures via p2p aggregator") + w.aggregateSignatures() + + log.Info("Delivering addressed call payload to receiving subnet") + w.deliverAddressedCallToReceivingSubnet() + + log.Info("Delivering block hash payload to receiving subnet") + w.deliverBlockHashPayload() + + log.Info("Executing HardHat test") + w.executeHardHatTest() + + log.Info("Executing warp load test") + w.warpLoad() + } + ginkgo.It("SubnetA -> SubnetB", func() { testFunc(subnetA, subnetB) }) + ginkgo.It("SubnetA -> SubnetA", func() { testFunc(subnetA, subnetA) }) + ginkgo.It("SubnetA -> C-Chain", func() { testFunc(subnetA, cChainSubnetDetails) }) + ginkgo.It("C-Chain -> SubnetA", func() { testFunc(cChainSubnetDetails, subnetA) }) + ginkgo.It("C-Chain -> C-Chain", func() { testFunc(cChainSubnetDetails, cChainSubnetDetails) }) }) type warpTest struct { @@ -227,9 +201,12 @@ type warpTest struct { addressedCallSignedMessage *avalancheWarp.Message } -func newWarpTest(ctx context.Context, sendingSubnet *runner.Subnet, sendingSubnetFundedKey *ecdsa.PrivateKey, receivingSubnet *runner.Subnet, receivingSubnetFundedKey *ecdsa.PrivateKey) *warpTest { +func newWarpTest(ctx context.Context, sendingSubnet *runner.Subnet, receivingSubnet *runner.Subnet) *warpTest { require := require.New(ginkgo.GinkgoT()) + sendingSubnetFundedKey := sendingSubnet.PreFundedKey + receivingSubnetFundedKey := receivingSubnet.PreFundedKey + warpTest := &warpTest{ sendingSubnet: sendingSubnet, sendingSubnetURIs: sendingSubnet.ValidatorURIs, @@ -301,7 +278,7 @@ func (w *warpTest) getBlockHashAndNumberFromTxReceipt(ctx context.Context, clien } func (w *warpTest) sendMessageFromSendingSubnet() { - ctx := context.Background() + ctx := e2e.DefaultContext() require := require.New(ginkgo.GinkgoT()) client := w.sendingSubnetClients[0] @@ -382,7 +359,7 @@ func (w *warpTest) sendMessageFromSendingSubnet() { func (w *warpTest) aggregateSignaturesViaAPI() { require := require.New(ginkgo.GinkgoT()) - ctx := context.Background() + ctx := e2e.DefaultContext() warpAPIs := make(map[ids.NodeID]warpBackend.Client, len(w.sendingSubnetURIs)) for _, uri := range w.sendingSubnetURIs { @@ -441,7 +418,7 @@ func (w *warpTest) aggregateSignaturesViaAPI() { func (w *warpTest) aggregateSignatures() { require := require.New(ginkgo.GinkgoT()) - ctx := context.Background() + ctx := e2e.DefaultContext() // Verify that the signature aggregation matches the results of manually constructing the warp message client, err := warpBackend.NewClient(w.sendingSubnetURIs[0], w.sendingSubnet.BlockchainID.String()) @@ -464,7 +441,7 @@ func (w *warpTest) aggregateSignatures() { func (w *warpTest) deliverAddressedCallToReceivingSubnet() { require := require.New(ginkgo.GinkgoT()) - ctx := context.Background() + ctx := e2e.DefaultContext() client := w.receivingSubnetClients[0] log.Info("Subscribing to new heads") @@ -518,7 +495,7 @@ func (w *warpTest) deliverAddressedCallToReceivingSubnet() { func (w *warpTest) deliverBlockHashPayload() { require := require.New(ginkgo.GinkgoT()) - ctx := context.Background() + ctx := e2e.DefaultContext() client := w.receivingSubnetClients[0] log.Info("Subscribing to new heads") @@ -572,8 +549,7 @@ func (w *warpTest) deliverBlockHashPayload() { func (w *warpTest) executeHardHatTest() { require := require.New(ginkgo.GinkgoT()) - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() + ctx := e2e.DefaultContext() client := w.sendingSubnetClients[0] log.Info("Subscribing to new heads") @@ -587,13 +563,13 @@ func (w *warpTest) executeHardHatTest() { rpcURI := toRPCURI(w.sendingSubnetURIs[0], w.sendingSubnet.BlockchainID.String()) - os.Setenv("SENDER_ADDRESS", crypto.PubkeyToAddress(fundedKey.PublicKey).Hex()) + os.Setenv("SENDER_ADDRESS", crypto.PubkeyToAddress(w.sendingSubnetFundedKey.PublicKey).Hex()) os.Setenv("SOURCE_CHAIN_ID", "0x"+w.sendingSubnet.BlockchainID.Hex()) os.Setenv("PAYLOAD", "0x"+common.Bytes2Hex(testPayload)) os.Setenv("EXPECTED_UNSIGNED_MESSAGE", "0x"+hex.EncodeToString(w.addressedCallUnsignedMessage.Bytes())) os.Setenv("CHAIN_ID", fmt.Sprintf("%d", chainID.Uint64())) - cmdPath := "./contracts" + cmdPath := filepath.Join(repoRootPath, "contracts") // test path is relative to the cmd path testPath := "./test/warp.ts" utils.RunHardhatTestsCustomURI(ctx, rpcURI, cmdPath, testPath) @@ -601,44 +577,35 @@ func (w *warpTest) executeHardHatTest() { func (w *warpTest) warpLoad() { require := require.New(ginkgo.GinkgoT()) - ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) - defer cancel() + ctx := e2e.DefaultContext() var ( - numWorkers = 5 + numWorkers = len(w.sendingSubnetClients) txsPerWorker uint64 = 10 batchSize uint64 = 10 sendingClient = w.sendingSubnetClients[0] ) - keys := make([]*key.Key, 0, numWorkers) - privateKeys := make([]*ecdsa.PrivateKey, 0, numWorkers) - prefundedKey := key.CreateKey(fundedKey) - keys = append(keys, prefundedKey) - for i := 1; i < numWorkers; i++ { - newKey, err := key.Generate() - require.NoError(err) - keys = append(keys, newKey) - privateKeys = append(privateKeys, newKey.PrivKey) - } + chainAKeys, chainAPrivateKeys := generateKeys(w.sendingSubnetFundedKey, numWorkers) + chainBKeys, chainBPrivateKeys := generateKeys(w.receivingSubnetFundedKey, numWorkers) loadMetrics := metrics.NewDefaultMetrics() - log.Info("Distributing funds on sending subnet", "numKeys", len(keys)) - keys, err := load.DistributeFunds(ctx, sendingClient, keys, len(keys), new(big.Int).Mul(big.NewInt(100), big.NewInt(params.Ether)), loadMetrics) + log.Info("Distributing funds on sending subnet", "numKeys", len(chainAKeys)) + chainAKeys, err := load.DistributeFunds(ctx, sendingClient, chainAKeys, len(chainAKeys), new(big.Int).Mul(big.NewInt(100), big.NewInt(params.Ether)), loadMetrics) require.NoError(err) - log.Info("Distributing funds on receiving subnet", "numKeys", len(keys)) - _, err = load.DistributeFunds(ctx, w.receivingSubnetClients[0], keys, len(keys), new(big.Int).Mul(big.NewInt(100), big.NewInt(params.Ether)), loadMetrics) + log.Info("Distributing funds on receiving subnet", "numKeys", len(chainBKeys)) + _, err = load.DistributeFunds(ctx, w.receivingSubnetClients[0], chainBKeys, len(chainBKeys), new(big.Int).Mul(big.NewInt(100), big.NewInt(params.Ether)), loadMetrics) require.NoError(err) log.Info("Creating workers for each subnet...") - chainAWorkers := make([]txs.Worker[*types.Transaction], 0, len(keys)) - for i := range keys { + chainAWorkers := make([]txs.Worker[*types.Transaction], 0, len(chainAKeys)) + for i := range chainAKeys { chainAWorkers = append(chainAWorkers, load.NewTxReceiptWorker(ctx, w.sendingSubnetClients[i])) } - chainBWorkers := make([]txs.Worker[*types.Transaction], 0, len(keys)) - for i := range keys { + chainBWorkers := make([]txs.Worker[*types.Transaction], 0, len(chainBKeys)) + for i := range chainBKeys { chainBWorkers = append(chainBWorkers, load.NewTxReceiptWorker(ctx, w.receivingSubnetClients[i])) } @@ -671,7 +638,7 @@ func (w *warpTest) warpLoad() { Data: data, }) return types.SignTx(tx, w.sendingSubnetSigner, key) - }, w.sendingSubnetClients[0], privateKeys, txsPerWorker, false) + }, w.sendingSubnetClients[0], chainAPrivateKeys, txsPerWorker, false) require.NoError(err) log.Info("Executing warp send loader...") warpSendLoader := load.New(chainAWorkers, warpSendSequences, batchSize, loadMetrics) @@ -720,8 +687,9 @@ func (w *warpTest) warpLoad() { signedWarpMessageBytes, ) return types.SignTx(tx, w.receivingSubnetSigner, key) - }, w.receivingSubnetClients[0], privateKeys, txsPerWorker, true) + }, w.receivingSubnetClients[0], chainBPrivateKeys, txsPerWorker, true) require.NoError(err) + log.Info("Executing warp delivery...") warpDeliverLoader := load.New(chainBWorkers, warpDeliverSequences, batchSize, loadMetrics) require.NoError(warpDeliverLoader.Execute(ctx)) @@ -729,6 +697,26 @@ func (w *warpTest) warpLoad() { log.Info("Completed warp delivery successfully.") } +func generateKeys(preFundedKey *ecdsa.PrivateKey, numWorkers int) ([]*key.Key, []*ecdsa.PrivateKey) { + keys := []*key.Key{ + key.CreateKey(preFundedKey), + } + privateKeys := []*ecdsa.PrivateKey{ + preFundedKey, + } + for i := 1; i < numWorkers; i++ { + newKey, err := key.Generate() + require.NoError(ginkgo.GinkgoT(), err) + keys = append(keys, newKey) + privateKeys = append(privateKeys, newKey.PrivKey) + } + return keys, privateKeys +} + +func toWebsocketURI(uri string, blockchainID string) string { + return fmt.Sprintf("ws://%s/ext/bc/%s/ws", strings.TrimPrefix(uri, "http://"), blockchainID) +} + func toRPCURI(uri string, blockchainID string) string { return fmt.Sprintf("%s/ext/bc/%s/rpc", uri, blockchainID) } From 761306974a315c7db8e20a8186faa77c073892e4 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 22 Dec 2023 16:18:00 -0800 Subject: [PATCH 02/16] e2e: Switch load test to use the tmpnet fixture --- scripts/run_ginkgo_load.sh | 11 +++++--- tests/load/load_test.go | 54 +++++++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/scripts/run_ginkgo_load.sh b/scripts/run_ginkgo_load.sh index e4f31c31ac..9bacb3035b 100755 --- a/scripts/run_ginkgo_load.sh +++ b/scripts/run_ginkgo_load.sh @@ -19,8 +19,11 @@ source "$SUBNET_EVM_PATH"/scripts/versions.sh # to install the ginkgo binary (required for test build and run) go install -v github.com/onsi/ginkgo/v2/ginkgo@"${GINKGO_VERSION}" -ACK_GINKGO_RC=true ginkgo build ./tests/load +EXTRA_ARGS= +AVALANCHEGO_BUILD_PATH="${AVALANCHEGO_BUILD_PATH:-}" +if [[ -n "${AVALANCHEGO_BUILD_PATH}" ]]; then + EXTRA_ARGS="-- --avalanchego-path=${AVALANCHEGO_BUILD_PATH}/avalanchego --plugin-dir=${AVALANCHEGO_BUILD_PATH}/plugins" + echo "Running with extra args: ${EXTRA_ARGS}" +fi -./tests/load/load.test \ - --ginkgo.vv \ - --ginkgo.label-filter="${GINKGO_LABEL_FILTER:-""}" +ginkgo -vv --label-filter="${GINKGO_LABEL_FILTER:-}" ./tests/load ${EXTRA_ARGS} diff --git a/tests/load/load_test.go b/tests/load/load_test.go index eafe8b69a3..9a3bc0f45e 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -7,19 +7,35 @@ import ( "fmt" "os" "os/exec" + "path/filepath" "strings" "testing" - "github.com/ava-labs/subnet-evm/tests/utils/runner" - "github.com/ethereum/go-ethereum/log" ginkgo "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + + "github.com/stretchr/testify/require" + + "github.com/ethereum/go-ethereum/log" + + "github.com/ava-labs/avalanchego/tests/fixture/e2e" + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" + + "github.com/ava-labs/subnet-evm/tests" + "github.com/ava-labs/subnet-evm/tests/utils" ) -var getSubnet func() *runner.Subnet +const subnetAName = "load-subnet-a" + +var ( + flagVars *e2e.FlagVars + repoRootPath = tests.GetRepoRootPath("tests/load") +) func init() { - getSubnet = runner.RegisterFiveNodeSubnetRun() + // Configures flags used to configure tmpnet + flagVars = e2e.RegisterFlags() } func TestE2E(t *testing.T) { @@ -28,25 +44,43 @@ func TestE2E(t *testing.T) { } var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { + require := require.New(ginkgo.GinkgoT()) + + var env *e2e.TestEnvironment + + ginkgo.BeforeAll(func() { + genesisPath := filepath.Join(repoRootPath, "tests/load/genesis/genesis.json") + env = e2e.NewTestEnvironment( + flagVars, + utils.NewTmpnetNetwork( + utils.NewTmpnetSubnet(subnetAName, genesisPath), + ), + ) + }) + ginkgo.It("basic subnet load test", ginkgo.Label("load"), func() { - subnetDetails := getSubnet() - blockchainID := subnetDetails.BlockchainID + network := env.GetNetwork() + + subnet := network.GetSubnet(subnetAName) + require.NotNil(subnet) + blockchainID := subnet.Chains[0].ChainID - nodeURIs := subnetDetails.ValidatorURIs + nodeURIs := tmpnet.GetNodeURIs(network.Nodes) rpcEndpoints := make([]string, 0, len(nodeURIs)) for _, uri := range nodeURIs { - rpcEndpoints = append(rpcEndpoints, fmt.Sprintf("%s/ext/bc/%s/rpc", uri, blockchainID)) + rpcEndpoints = append(rpcEndpoints, fmt.Sprintf("%s/ext/bc/%s/rpc", uri.URI, blockchainID)) } commaSeparatedRPCEndpoints := strings.Join(rpcEndpoints, ",") err := os.Setenv("RPC_ENDPOINTS", commaSeparatedRPCEndpoints) - gomega.Expect(err).Should(gomega.BeNil()) + require.NoError(err) log.Info("Running load simulator...", "rpcEndpoints", commaSeparatedRPCEndpoints) cmd := exec.Command("./scripts/run_simulator.sh") + cmd.Dir = repoRootPath log.Info("Running load simulator script", "cmd", cmd.String()) out, err := cmd.CombinedOutput() fmt.Printf("\nCombined output:\n\n%s\n", string(out)) - gomega.Expect(err).Should(gomega.BeNil()) + require.NoError(err) }) }) From 5cdde29a6703035876a551e19354f5d547dbe6bf Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 22 Dec 2023 17:12:48 -0800 Subject: [PATCH 03/16] Add readme describing use of existing network --- tests/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/README.md diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000000..43234ede56 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,28 @@ +# Developing with tmpnet + +The `load/` and `warp/` paths contain end-to-end (e2e) tests that use +the [tmpnet +fixture](https://github.com/ava-labs/avalanchego/blob/dev/tests/fixture/tmpnet/README.md). By +default both test suites use the tmpnet fixture to create a temporary +network that exists for only the duration of their execution. + +It is possible to create a temporary network that can be reused across +test runs to minimize the setup cost involved: + +```bash +# From the root of a clone of avalanchego, build the tmpnetctl cli +$ ./scripts/build_tmpnetctl.sh + +# Start a new temporary network configured with subnet-evm's default plugin path +$ ./build/tmpnetctl start-network \ + --avalanche-path=./build/avalanchego + --plugin-dir=$GOPATH/src/github.com/ava-labs/avalanchego/build/plugins + +# From the root of a clone of subnet-evm, execute the warp test suite against the existing network +$ ginkgo -vv ./tests/warp -- --use-existing-network --network-dir=$HOME/.tmpnet/networks/latest +``` + +The network started by `tmpnetctl` won't come with subnets configured, +so the test suite will add them to the network the first time it +runs. Subsequent test runs will be able to reuse those subnets without +having to set them up. From ec4c656133925f83ecd72bff50682c7bcb77e11f Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 8 Jan 2024 18:11:29 +0100 Subject: [PATCH 04/16] e2e: Remove network manager and dependency on ANR --- tests/utils/constants.go | 4 - tests/utils/runner/network_manager.go | 402 -------------------------- tests/warp/warp_test.go | 29 +- 3 files changed, 20 insertions(+), 415 deletions(-) delete mode 100644 tests/utils/runner/network_manager.go diff --git a/tests/utils/constants.go b/tests/utils/constants.go index 4b07626d08..cd507eca1b 100644 --- a/tests/utils/constants.go +++ b/tests/utils/constants.go @@ -14,7 +14,3 @@ const ( DefaultLocalNodeURI = "http://127.0.0.1:9650" ) - -var ( - NodeURIs = []string{DefaultLocalNodeURI, "http://127.0.0.1:9652", "http://127.0.0.1:9654", "http://127.0.0.1:9656", "http://127.0.0.1:9658"} -) diff --git a/tests/utils/runner/network_manager.go b/tests/utils/runner/network_manager.go deleted file mode 100644 index 352c23bb71..0000000000 --- a/tests/utils/runner/network_manager.go +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (C) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package runner - -import ( - "context" - "crypto/ecdsa" - "fmt" - "os" - "time" - - runner_sdk "github.com/ava-labs/avalanche-network-runner/client" - "github.com/ava-labs/avalanche-network-runner/rpcpb" - runner_server "github.com/ava-labs/avalanche-network-runner/server" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/utils/wrappers" - "github.com/ava-labs/subnet-evm/plugin/evm" - "github.com/ethereum/go-ethereum/log" - "github.com/onsi/ginkgo/v2" - "github.com/onsi/gomega" -) - -// Subnet provides the basic details of a created subnet -// Note: currently assumes one blockchain per subnet -type Subnet struct { - // SubnetID is the txID of the transaction that created the subnet - SubnetID ids.ID `json:"subnetID"` - // Current ANR assumes one blockchain per subnet, so we have a single blockchainID here - BlockchainID ids.ID `json:"blockchainID"` - // Key funded in the genesis of the blockchain - PreFundedKey *ecdsa.PrivateKey - // ValidatorURIs is the base URIs for each participant of the Subnet - ValidatorURIs []string `json:"validatorURIs"` -} - -type ANRConfig struct { - LogLevel string - AvalancheGoExecPath string - PluginDir string - GlobalNodeConfig string - GlobalCChainConfig string -} - -// NetworkManager is a wrapper around the ANR to simplify the setup and teardown code -// of tests that rely on the ANR. -type NetworkManager struct { - ANRConfig ANRConfig - - subnets []*Subnet - - logFactory logging.Factory - anrClient runner_sdk.Client - anrServer runner_server.Server - done chan struct{} - serverCtxCancel context.CancelFunc -} - -// NewDefaultANRConfig returns a default config for launching the avalanche-network-runner manager -// with both a server and client. -// By default, it expands $GOPATH/src/github.com/ava-labs/avalanchego/build/ directory to extract -// the AvalancheGoExecPath and PluginDir arguments. -// If the AVALANCHEGO_BUILD_PATH environment variable is set, it overrides the default location for -// the AvalancheGoExecPath and PluginDir arguments. -func NewDefaultANRConfig() ANRConfig { - defaultConfig := ANRConfig{ - LogLevel: "info", - AvalancheGoExecPath: os.ExpandEnv("$GOPATH/src/github.com/ava-labs/avalanchego/build/avalanchego"), - PluginDir: os.ExpandEnv("$GOPATH/src/github.com/ava-labs/avalanchego/build/plugins"), - GlobalNodeConfig: `{ - "log-level":"info", - "proposervm-use-current-height":true - }`, - GlobalCChainConfig: `{ - "warp-api-enabled": true, - "log-level": "debug" - }`, - } - // If AVALANCHEGO_BUILD_PATH is populated, override location set by GOPATH - if envBuildPath, exists := os.LookupEnv("AVALANCHEGO_BUILD_PATH"); exists { - defaultConfig.AvalancheGoExecPath = fmt.Sprintf("%s/avalanchego", envBuildPath) - defaultConfig.PluginDir = fmt.Sprintf("%s/plugins", envBuildPath) - } - return defaultConfig -} - -// NewNetworkManager constructs a new instance of a network manager -func NewNetworkManager(config ANRConfig) *NetworkManager { - manager := &NetworkManager{ - ANRConfig: config, - } - - logLevel, err := logging.ToLevel(config.LogLevel) - if err != nil { - panic(fmt.Errorf("invalid ANR log level: %w", err)) - } - manager.logFactory = logging.NewFactory(logging.Config{ - DisplayLevel: logLevel, - LogLevel: logLevel, - }) - - return manager -} - -// startServer starts a new ANR server and sets/overwrites the anrServer, done channel, and serverCtxCancel function. -func (n *NetworkManager) startServer(ctx context.Context) (<-chan struct{}, error) { - done := make(chan struct{}) - zapServerLog, err := n.logFactory.Make("server") - if err != nil { - return nil, fmt.Errorf("failed to make server log: %w", err) - } - - logLevel, err := logging.ToLevel(n.ANRConfig.LogLevel) - if err != nil { - return nil, fmt.Errorf("failed to parse ANR log level: %w", err) - } - - n.anrServer, err = runner_server.New( - runner_server.Config{ - Port: ":12352", - GwPort: ":12353", - GwDisabled: false, - DialTimeout: 10 * time.Second, - RedirectNodesOutput: true, - SnapshotsDir: "", - LogLevel: logLevel, - }, - zapServerLog, - ) - if err != nil { - return nil, fmt.Errorf("failed to start ANR server: %w", err) - } - n.done = done - - // Use a separate background context here, since the server should only be canceled by explicit shutdown - serverCtx, serverCtxCancel := context.WithCancel(context.Background()) - n.serverCtxCancel = serverCtxCancel - go func() { - if err := n.anrServer.Run(serverCtx); err != nil { - log.Error("Error shutting down ANR server", "err", err) - } else { - log.Info("Terminating ANR Server") - } - close(done) - }() - - return done, nil -} - -// startClient starts an ANR Client dialing the ANR server at the expected endpoint. -// Note: will overwrite client if it already exists. -func (n *NetworkManager) startClient() error { - logLevel, err := logging.ToLevel(n.ANRConfig.LogLevel) - if err != nil { - return fmt.Errorf("failed to parse ANR log level: %w", err) - } - logFactory := logging.NewFactory(logging.Config{ - DisplayLevel: logLevel, - LogLevel: logLevel, - }) - zapLog, err := logFactory.Make("main") - if err != nil { - return fmt.Errorf("failed to make client log: %w", err) - } - - n.anrClient, err = runner_sdk.New(runner_sdk.Config{ - Endpoint: "0.0.0.0:12352", - DialTimeout: 10 * time.Second, - }, zapLog) - if err != nil { - return fmt.Errorf("failed to start ANR client: %w", err) - } - - return nil -} - -// initServer starts the ANR server if it is not populated -func (n *NetworkManager) initServer() error { - if n.anrServer != nil { - return nil - } - - _, err := n.startServer(context.Background()) - return err -} - -// initClient starts an ANR client if it not populated -func (n *NetworkManager) initClient() error { - if n.anrClient != nil { - return nil - } - - return n.startClient() -} - -// init starts the ANR server and client if they are not yet populated -func (n *NetworkManager) init() error { - if err := n.initServer(); err != nil { - return err - } - return n.initClient() -} - -// StartDefaultNetwork constructs a default 5 node network. -func (n *NetworkManager) StartDefaultNetwork(ctx context.Context) (<-chan struct{}, error) { - if err := n.init(); err != nil { - return nil, err - } - - log.Info("Sending 'start'", "AvalancheGoExecPath", n.ANRConfig.AvalancheGoExecPath) - - // Start cluster - opts := []runner_sdk.OpOption{ - runner_sdk.WithPluginDir(n.ANRConfig.PluginDir), - runner_sdk.WithGlobalNodeConfig(n.ANRConfig.GlobalNodeConfig), - } - if len(n.ANRConfig.GlobalCChainConfig) != 0 { - opts = append(opts, runner_sdk.WithChainConfigs(map[string]string{ - "C": n.ANRConfig.GlobalCChainConfig, - })) - } - resp, err := n.anrClient.Start( - ctx, - n.ANRConfig.AvalancheGoExecPath, - opts..., - ) - if err != nil { - return nil, fmt.Errorf("failed to start ANR network: %w", err) - } - log.Info("successfully started cluster", "RootDataDir", resp.ClusterInfo.RootDataDir, "Subnets", resp.GetClusterInfo().GetSubnets()) - return n.done, nil -} - -// SetupNetwork constructs blockchains with the given [blockchainSpecs] and adds them to the network manager. -// Uses [execPath] as the AvalancheGo binary execution path for any started nodes. -// Note: this assumes that the default network has already been constructed. -func (n *NetworkManager) SetupNetwork(ctx context.Context, execPath string, blockchainSpecs []*rpcpb.BlockchainSpec) error { - // timeout according to how many blockchains we're creating - timeout := 2 * time.Minute * time.Duration(len(blockchainSpecs)) - cctx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - if err := n.init(); err != nil { - return err - } - sresp, err := n.anrClient.CreateBlockchains( - ctx, - blockchainSpecs, - ) - if err != nil { - return fmt.Errorf("failed to create blockchains: %w", err) - } - - // TODO: network runner health should imply custom VM healthiness - // or provide a separate API for custom VM healthiness - // "start" is async, so wait some time for cluster health - log.Info("waiting for all VMs to report healthy", "VMID", evm.ID) - for { - v, err := n.anrClient.Health(ctx) - log.Info("Pinged CLI Health", "result", v, "err", err) - if err != nil { - time.Sleep(1 * time.Second) - continue - } else if ctx.Err() != nil { - return fmt.Errorf("failed to await healthy network: %w", ctx.Err()) - } - break - } - - status, err := n.anrClient.Status(cctx) - if err != nil { - return fmt.Errorf("failed to get ANR status: %w", err) - } - nodeInfos := status.GetClusterInfo().GetNodeInfos() - - for i, chainSpec := range blockchainSpecs { - blockchainIDStr := sresp.ChainIds[i] - blockchainID, err := ids.FromString(blockchainIDStr) - if err != nil { - panic(err) - } - subnetIDStr := sresp.ClusterInfo.CustomChains[blockchainIDStr].SubnetId - subnetID, err := ids.FromString(subnetIDStr) - if err != nil { - panic(err) - } - subnet := &Subnet{ - SubnetID: subnetID, - BlockchainID: blockchainID, - } - for _, nodeName := range chainSpec.SubnetSpec.Participants { - subnet.ValidatorURIs = append(subnet.ValidatorURIs, nodeInfos[nodeName].Uri) - } - n.subnets = append(n.subnets, subnet) - } - - return nil -} - -// TeardownNetwork tears down the network constructed by the network manager and cleans up -// everything associated with it. -func (n *NetworkManager) TeardownNetwork() error { - if err := n.initClient(); err != nil { - return err - } - errs := wrappers.Errs{} - log.Info("Shutting down cluster") - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - _, err := n.anrClient.Stop(ctx) - cancel() - errs.Add(err) - errs.Add(n.anrClient.Close()) - if n.serverCtxCancel != nil { - n.serverCtxCancel() - } - return errs.Err -} - -// CloseClient closes the connection between the ANR client and server without terminating the -// running network. -func (n *NetworkManager) CloseClient() error { - if n.anrClient == nil { - return nil - } - err := n.anrClient.Close() - n.anrClient = nil - return err -} - -// GetSubnets returns the IDs of the currently running subnets -func (n *NetworkManager) GetSubnets() []ids.ID { - subnetIDs := make([]ids.ID, 0, len(n.subnets)) - for _, subnet := range n.subnets { - subnetIDs = append(subnetIDs, subnet.SubnetID) - } - return subnetIDs -} - -// GetSubnet retrieves the subnet details for the requested subnetID -func (n *NetworkManager) GetSubnet(subnetID ids.ID) (*Subnet, bool) { - for _, subnet := range n.subnets { - if subnet.SubnetID == subnetID { - return subnet, true - } - } - return nil, false -} - -func (n *NetworkManager) GetAllURIs(ctx context.Context) ([]string, error) { - return n.anrClient.URIs(ctx) -} - -func RegisterFiveNodeSubnetRun() func() *Subnet { - var ( - config = NewDefaultANRConfig() - manager = NewNetworkManager(config) - numNodes = 5 - ) - - _ = ginkgo.BeforeSuite(func() { - // Name 10 new validators (which should have BLS key registered) - subnetA := make([]string, 0) - for i := 1; i <= numNodes; i++ { - subnetA = append(subnetA, fmt.Sprintf("node%d-bls", i)) - } - - ctx := context.Background() - var err error - _, err = manager.StartDefaultNetwork(ctx) - gomega.Expect(err).Should(gomega.BeNil()) - err = manager.SetupNetwork( - ctx, - config.AvalancheGoExecPath, - []*rpcpb.BlockchainSpec{ - { - VmName: evm.IDStr, - Genesis: "./tests/load/genesis/genesis.json", - ChainConfig: "", - SubnetSpec: &rpcpb.SubnetSpec{ - Participants: subnetA, - }, - }, - }, - ) - gomega.Expect(err).Should(gomega.BeNil()) - }) - - _ = ginkgo.AfterSuite(func() { - gomega.Expect(manager).ShouldNot(gomega.BeNil()) - gomega.Expect(manager.TeardownNetwork()).Should(gomega.BeNil()) - // TODO: bootstrap an additional node to ensure that we can bootstrap the test data correctly - }) - - return func() *Subnet { - subnetIDs := manager.GetSubnets() - gomega.Expect(len(subnetIDs)).Should(gomega.Equal(1)) - subnetID := subnetIDs[0] - subnetDetails, ok := manager.GetSubnet(subnetID) - gomega.Expect(ok).Should(gomega.BeTrue()) - return subnetDetails - } -} diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index bbf2c92a2a..7d3b343d08 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -48,7 +48,6 @@ import ( "github.com/ava-labs/subnet-evm/predicate" "github.com/ava-labs/subnet-evm/tests" "github.com/ava-labs/subnet-evm/tests/utils" - "github.com/ava-labs/subnet-evm/tests/utils/runner" warpBackend "github.com/ava-labs/subnet-evm/warp" "github.com/ava-labs/subnet-evm/warp/aggregator" ) @@ -65,7 +64,7 @@ var ( genesisPath = filepath.Join(repoRootPath, "tests/precompile/genesis/warp.json") - subnetA, subnetB, cChainSubnetDetails *runner.Subnet + subnetA, subnetB, cChainSubnetDetails *Subnet testPayload = []byte{1, 2, 3} ) @@ -75,6 +74,18 @@ func init() { flagVars = e2e.RegisterFlags() } +// subnet provides the basic details of a created subnet +type Subnet struct { + // SubnetID is the txID of the transaction that created the subnet + SubnetID ids.ID + // For simplicity assume a single blockchain per subnet + BlockchainID ids.ID + // Key funded in the genesis of the blockchain + PreFundedKey *ecdsa.PrivateKey + // ValidatorURIs are the base URIs for each participant of the Subnet + ValidatorURIs []string +} + func TestE2E(t *testing.T) { gomega.RegisterFailHandler(ginkgo.Fail) ginkgo.RunSpecs(t, "subnet-evm warp e2e test") @@ -109,7 +120,7 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { tmpnetSubnetA := network.GetSubnet(subnetAName) require.NotNil(tmpnetSubnetA) - subnetA = &runner.Subnet{ + subnetA = &Subnet{ SubnetID: tmpnetSubnetA.SubnetID, BlockchainID: tmpnetSubnetA.Chains[0].ChainID, PreFundedKey: tmpnetSubnetA.Chains[0].PreFundedKey.ToECDSA(), @@ -118,7 +129,7 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { tmpnetSubnetB := network.GetSubnet(subnetBName) require.NotNil(tmpnetSubnetB) - subnetB = &runner.Subnet{ + subnetB = &Subnet{ SubnetID: tmpnetSubnetB.SubnetID, BlockchainID: tmpnetSubnetB.Chains[0].ChainID, PreFundedKey: tmpnetSubnetB.Chains[0].PreFundedKey.ToECDSA(), @@ -129,7 +140,7 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { cChainBlockchainID, err := infoClient.GetBlockchainID(e2e.DefaultContext(), "C") require.NoError(err) - cChainSubnetDetails = &runner.Subnet{ + cChainSubnetDetails = &Subnet{ SubnetID: constants.PrimaryNetworkID, BlockchainID: cChainBlockchainID, PreFundedKey: tmpnet.HardhatKey.ToECDSA(), @@ -138,7 +149,7 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { }) var _ = ginkgo.Describe("[Warp]", func() { - testFunc := func(sendingSubnet *runner.Subnet, receivingSubnet *runner.Subnet) { + testFunc := func(sendingSubnet *Subnet, receivingSubnet *Subnet) { w := newWarpTest(e2e.DefaultContext(), sendingSubnet, receivingSubnet) log.Info("Sending message from A to B") @@ -174,7 +185,7 @@ type warpTest struct { networkID uint32 // sendingSubnet fields set in the constructor - sendingSubnet *runner.Subnet + sendingSubnet *Subnet sendingSubnetURIs []string sendingSubnetClients []ethclient.Client sendingSubnetFundedKey *ecdsa.PrivateKey @@ -183,7 +194,7 @@ type warpTest struct { sendingSubnetSigner types.Signer // receivingSubnet fields set in the constructor - receivingSubnet *runner.Subnet + receivingSubnet *Subnet receivingSubnetURIs []string receivingSubnetClients []ethclient.Client receivingSubnetFundedKey *ecdsa.PrivateKey @@ -201,7 +212,7 @@ type warpTest struct { addressedCallSignedMessage *avalancheWarp.Message } -func newWarpTest(ctx context.Context, sendingSubnet *runner.Subnet, receivingSubnet *runner.Subnet) *warpTest { +func newWarpTest(ctx context.Context, sendingSubnet *Subnet, receivingSubnet *Subnet) *warpTest { require := require.New(ginkgo.GinkgoT()) sendingSubnetFundedKey := sendingSubnet.PreFundedKey From a13355051bd31cd9b27a632d051911ad7b671631 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 17 Jan 2024 12:59:17 +0100 Subject: [PATCH 05/16] fixup: Switch from VMName to VMID with tmpnet.Chain --- tests/utils/tmpnet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/tmpnet.go b/tests/utils/tmpnet.go index 3878d334c2..c0ba71fe3c 100644 --- a/tests/utils/tmpnet.go +++ b/tests/utils/tmpnet.go @@ -42,7 +42,7 @@ func NewTmpnetSubnet(name string, genesisPath string) *tmpnet.Subnet { Name: name, Chains: []*tmpnet.Chain{ { - VMName: evm.IDStr, + VMID: evm.ID, Genesis: genesisBytes, Config: string(configBytes), PreFundedKey: tmpnet.HardhatKey, From 2de78e5f4f5c5f6324bf362fc242a02496eff88f Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 25 Jan 2024 20:33:03 +0100 Subject: [PATCH 06/16] fixup: Respond to review comments --- tests/README.md | 5 ++++- tests/warp/warp_test.go | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/README.md b/tests/README.md index 43234ede56..a99cac0b6f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -2,7 +2,7 @@ The `load/` and `warp/` paths contain end-to-end (e2e) tests that use the [tmpnet -fixture](https://github.com/ava-labs/avalanchego/blob/dev/tests/fixture/tmpnet/README.md). By +fixture](https://github.com/ava-labs/avalanchego/blob/master/tests/fixture/tmpnet/README.md). By default both test suites use the tmpnet fixture to create a temporary network that exists for only the duration of their execution. @@ -20,6 +20,9 @@ $ ./build/tmpnetctl start-network \ # From the root of a clone of subnet-evm, execute the warp test suite against the existing network $ ginkgo -vv ./tests/warp -- --use-existing-network --network-dir=$HOME/.tmpnet/networks/latest + +# To stop the temporary network when no longer needed, execute the following from the root of the clone of avalanchego +$ ./build/tmpnetctl stop-network --network-dir=$HOME/.tmpnet/networks/latest ``` The network started by `tmpnetctl` won't come with subnets configured, diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index 7d3b343d08..d900a7ec9b 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -74,7 +74,7 @@ func init() { flagVars = e2e.RegisterFlags() } -// subnet provides the basic details of a created subnet +// Subnet provides the basic details of a created subnet type Subnet struct { // SubnetID is the txID of the transaction that created the subnet SubnetID ids.ID From cc453a0798fd7aba04c35c8bb958e988b2e5dd67 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 29 Jan 2024 18:42:41 +0100 Subject: [PATCH 07/16] fixup: Use 5 nodes for load testing --- tests/load/load_test.go | 8 +++++++- tests/utils/tmpnet.go | 7 ++++++- tests/warp/warp_test.go | 7 +++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index 9a3bc0f45e..e867fc677d 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -26,7 +26,12 @@ import ( "github.com/ava-labs/subnet-evm/tests/utils" ) -const subnetAName = "load-subnet-a" +const ( + // The load test requires 5 nodes + nodeCount = 5 + + subnetAName = "load-subnet-a" +) var ( flagVars *e2e.FlagVars @@ -53,6 +58,7 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { env = e2e.NewTestEnvironment( flagVars, utils.NewTmpnetNetwork( + nodeCount, utils.NewTmpnetSubnet(subnetAName, genesisPath), ), ) diff --git a/tests/utils/tmpnet.go b/tests/utils/tmpnet.go index c0ba71fe3c..56796ec975 100644 --- a/tests/utils/tmpnet.go +++ b/tests/utils/tmpnet.go @@ -13,11 +13,16 @@ import ( "github.com/ava-labs/subnet-evm/plugin/evm" ) -func NewTmpnetNetwork(subnets ...*tmpnet.Subnet) *tmpnet.Network { +func NewTmpnetNetwork(count int, subnets ...*tmpnet.Subnet) *tmpnet.Network { + nodes := make([]*tmpnet.Node, count) + for i := range nodes { + nodes[i] = tmpnet.NewNode("") + } return &tmpnet.Network{ DefaultFlags: tmpnet.FlagsMap{ config.ProposerVMUseCurrentHeightKey: true, }, + Nodes: nodes, Subnets: subnets, } } diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index d900a7ec9b..a8925ce376 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -93,13 +93,16 @@ func TestE2E(t *testing.T) { var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { // Run only once in the first ginkgo process - return e2e.NewTestEnvironment( + env := e2e.NewTestEnvironment( flagVars, utils.NewTmpnetNetwork( + tmpnet.DefaultNodeCount, utils.NewTmpnetSubnet(subnetAName, genesisPath), utils.NewTmpnetSubnet(subnetBName, genesisPath), ), - ).Marshal() + ) + + return env.Marshal() }, func(envBytes []byte) { // Run in every ginkgo process From f2b04a142fecf61d23ce3635c8d1775052b2d863 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 1 Feb 2024 19:35:23 +0100 Subject: [PATCH 08/16] fixup: Fix shellcheck errors --- scripts/run_ginkgo_load.sh | 8 ++++---- scripts/run_ginkgo_warp.sh | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/run_ginkgo_load.sh b/scripts/run_ginkgo_load.sh index 9bacb3035b..56f3a09c6b 100755 --- a/scripts/run_ginkgo_load.sh +++ b/scripts/run_ginkgo_load.sh @@ -19,11 +19,11 @@ source "$SUBNET_EVM_PATH"/scripts/versions.sh # to install the ginkgo binary (required for test build and run) go install -v github.com/onsi/ginkgo/v2/ginkgo@"${GINKGO_VERSION}" -EXTRA_ARGS= +EXTRA_ARGS=() AVALANCHEGO_BUILD_PATH="${AVALANCHEGO_BUILD_PATH:-}" if [[ -n "${AVALANCHEGO_BUILD_PATH}" ]]; then - EXTRA_ARGS="-- --avalanchego-path=${AVALANCHEGO_BUILD_PATH}/avalanchego --plugin-dir=${AVALANCHEGO_BUILD_PATH}/plugins" - echo "Running with extra args: ${EXTRA_ARGS}" + EXTRA_ARGS=("--avalanchego-path=${AVALANCHEGO_BUILD_PATH}/avalanchego" "--plugin-dir=${AVALANCHEGO_BUILD_PATH}/plugins") + echo "Running with extra args:" "${EXTRA_ARGS[@]}" fi -ginkgo -vv --label-filter="${GINKGO_LABEL_FILTER:-}" ./tests/load ${EXTRA_ARGS} +ginkgo -vv --label-filter="${GINKGO_LABEL_FILTER:-}" ./tests/load -- "${EXTRA_ARGS[@]}" diff --git a/scripts/run_ginkgo_warp.sh b/scripts/run_ginkgo_warp.sh index feaebdbe50..a30295efb8 100755 --- a/scripts/run_ginkgo_warp.sh +++ b/scripts/run_ginkgo_warp.sh @@ -20,11 +20,11 @@ source "$SUBNET_EVM_PATH"/scripts/versions.sh # to install the ginkgo binary (required for test build and run) go install -v github.com/onsi/ginkgo/v2/ginkgo@"${GINKGO_VERSION}" -EXTRA_ARGS= +EXTRA_ARGS=() AVALANCHEGO_BUILD_PATH="${AVALANCHEGO_BUILD_PATH:-}" if [[ -n "${AVALANCHEGO_BUILD_PATH}" ]]; then - EXTRA_ARGS="-- --avalanchego-path=${AVALANCHEGO_BUILD_PATH}/avalanchego --plugin-dir=${AVALANCHEGO_BUILD_PATH}/plugins" - echo "Running with extra args: ${EXTRA_ARGS}" + EXTRA_ARGS=("--avalanchego-path=${AVALANCHEGO_BUILD_PATH}/avalanchego" "--plugin-dir=${AVALANCHEGO_BUILD_PATH}/plugins") + echo "Running with extra args:" "${EXTRA_ARGS[@]}" fi -ginkgo -vv --label-filter="${GINKGO_LABEL_FILTER:-}" ./tests/warp ${EXTRA_ARGS} +ginkgo -vv --label-filter="${GINKGO_LABEL_FILTER:-}" ./tests/warp -- "${EXTRA_ARGS[@]}" From b4c66896b010fcb1fad71e92cd21a1d8cc2a8734 Mon Sep 17 00:00:00 2001 From: Ceyhun Onur Date: Tue, 30 Jan 2024 15:10:55 +0300 Subject: [PATCH 09/16] cleanup artifact dirs --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0754148c92..480f3f1b24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: subnet-evm-e2e-logs-precompile - path: /tmp/network-runner-root-data*/ + path: /tmp/e2e-test/precompile-data retention-days: 5 e2e_warp: name: e2e warp tests @@ -156,7 +156,7 @@ jobs: run: ./scripts/build.sh /tmp/e2e-test/avalanchego/plugins/srEXiWaHuhNyGwPUi444Tu47ZEDwxTWrbQiuD7FmgSAQ6X7Dy - name: Run E2E Load Tests shell: bash - run: AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego DATA_DIR=/tmp/e2e-test/load-data ./scripts/run_ginkgo_load.sh + run: AVALANCHEGO_BUILD_PATH=/tmp/e2e-test/avalanchego ./scripts/run_ginkgo_load.sh - name: Upload tmpnet network dir for load testing if: always() uses: actions/upload-artifact@v4 From 986b635e0e68ea0df5c61525b6cdd7b8a59e1df1 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 9 Feb 2024 12:30:28 -0800 Subject: [PATCH 10/16] fixup: Update to reflect tmpnet configuration changes --- tests/load/load_test.go | 16 ++++++++++++---- tests/utils/tmpnet.go | 23 ++++++++++++++++++++--- tests/warp/warp_test.go | 7 ++++--- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index e867fc677d..0b5a25eaf2 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -19,8 +19,10 @@ import ( "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" + "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/subnet-evm/tests" "github.com/ava-labs/subnet-evm/tests/utils" @@ -54,12 +56,13 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { var env *e2e.TestEnvironment ginkgo.BeforeAll(func() { + nodes := utils.NewTmpnetNodes(nodeCount) genesisPath := filepath.Join(repoRootPath, "tests/load/genesis/genesis.json") env = e2e.NewTestEnvironment( flagVars, utils.NewTmpnetNetwork( - nodeCount, - utils.NewTmpnetSubnet(subnetAName, genesisPath), + nodes, + utils.NewTmpnetSubnet(subnetAName, genesisPath, nodes...), ), ) }) @@ -72,9 +75,14 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { blockchainID := subnet.Chains[0].ChainID nodeURIs := tmpnet.GetNodeURIs(network.Nodes) + validatorIDs := set.Set[ids.NodeID]{} + validatorIDs.Add(subnet.ValidatorIDs...) rpcEndpoints := make([]string, 0, len(nodeURIs)) - for _, uri := range nodeURIs { - rpcEndpoints = append(rpcEndpoints, fmt.Sprintf("%s/ext/bc/%s/rpc", uri.URI, blockchainID)) + for _, nodeURI := range nodeURIs { + if !validatorIDs.Contains(nodeURI.NodeID) { + continue + } + rpcEndpoints = append(rpcEndpoints, fmt.Sprintf("%s/ext/bc/%s/rpc", nodeURI.URI, blockchainID)) } commaSeparatedRPCEndpoints := strings.Join(rpcEndpoints, ",") err := os.Setenv("RPC_ENDPOINTS", commaSeparatedRPCEndpoints) diff --git a/tests/utils/tmpnet.go b/tests/utils/tmpnet.go index 56796ec975..7673859ba7 100644 --- a/tests/utils/tmpnet.go +++ b/tests/utils/tmpnet.go @@ -8,16 +8,23 @@ import ( "os" "github.com/ava-labs/avalanchego/config" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" "github.com/ava-labs/subnet-evm/plugin/evm" ) -func NewTmpnetNetwork(count int, subnets ...*tmpnet.Subnet) *tmpnet.Network { +func NewTmpnetNodes(count int) []*tmpnet.Node { nodes := make([]*tmpnet.Node, count) for i := range nodes { - nodes[i] = tmpnet.NewNode("") + node := tmpnet.NewNode("") + node.EnsureKeys() + nodes[i] = node } + return nodes +} + +func NewTmpnetNetwork(nodes []*tmpnet.Node, subnets ...*tmpnet.Subnet) *tmpnet.Network { return &tmpnet.Network{ DefaultFlags: tmpnet.FlagsMap{ config.ProposerVMUseCurrentHeightKey: true, @@ -29,7 +36,16 @@ func NewTmpnetNetwork(count int, subnets ...*tmpnet.Subnet) *tmpnet.Network { // Create the configuration that will enable creation and access to a // subnet created on a temporary network. -func NewTmpnetSubnet(name string, genesisPath string) *tmpnet.Subnet { +func NewTmpnetSubnet(name string, genesisPath string, nodes ...*tmpnet.Node) *tmpnet.Subnet { + if len(nodes) == 0 { + panic("a subnet must be validated by at least one node") + } + + validatorIDs := make([]ids.NodeID, len(nodes)) + for i, node := range nodes { + validatorIDs[i] = node.NodeID + } + genesisBytes, err := os.ReadFile(genesisPath) if err != nil { panic(err) @@ -53,5 +69,6 @@ func NewTmpnetSubnet(name string, genesisPath string) *tmpnet.Subnet { PreFundedKey: tmpnet.HardhatKey, }, }, + ValidatorIDs: validatorIDs, } } diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index a8925ce376..2411ccab02 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -93,12 +93,13 @@ func TestE2E(t *testing.T) { var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { // Run only once in the first ginkgo process + nodes := utils.NewTmpnetNodes(tmpnet.DefaultNodeCount) env := e2e.NewTestEnvironment( flagVars, utils.NewTmpnetNetwork( - tmpnet.DefaultNodeCount, - utils.NewTmpnetSubnet(subnetAName, genesisPath), - utils.NewTmpnetSubnet(subnetBName, genesisPath), + nodes, + utils.NewTmpnetSubnet(subnetAName, genesisPath, nodes...), + utils.NewTmpnetSubnet(subnetBName, genesisPath, nodes...), ), ) From 2865e0e6ade0eab7ea1336cf0c6a6c29bc4fbdbd Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Sat, 24 Feb 2024 16:20:19 -0800 Subject: [PATCH 11/16] fixup: go mod tidy --- go.mod | 3 --- go.sum | 8 -------- 2 files changed, 11 deletions(-) diff --git a/go.mod b/go.mod index 1d75838900..5d8afb93fd 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,6 @@ go 1.21 require ( github.com/VictoriaMetrics/fastcache v1.10.0 - github.com/ava-labs/avalanche-network-runner v1.7.6 github.com/ava-labs/avalanchego v1.11.1 github.com/cespare/cp v0.1.0 github.com/davecgh/go-spew v1.1.1 @@ -100,7 +99,6 @@ require ( github.com/mitchellh/pointerstructure v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d // indirect - github.com/otiai10/copy v1.11.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pires/go-proxyproto v0.6.2 // indirect @@ -131,7 +129,6 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect - golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/tools v0.16.0 // indirect diff --git a/go.sum b/go.sum index 8b6b2e7078..1767342461 100644 --- a/go.sum +++ b/go.sum @@ -60,8 +60,6 @@ github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/ava-labs/avalanche-network-runner v1.7.6 h1:2yXa2Zq099t900ffpn0RG9D5dca98fs3l+/hF7AumIY= -github.com/ava-labs/avalanche-network-runner v1.7.6/go.mod h1:+Br4mCjreTMtnDiUDNXJba500fnchMk0Ygu5qWVj6A4= github.com/ava-labs/avalanchego v1.11.1 h1:NSelfZ/Di8uGCsRoFK32HOR262eHlpUFmAu8pbfg0Jo= github.com/ava-labs/avalanchego v1.11.1/go.mod h1:+UpgT8X2fNN93+iE100efkZL7ePfBRfRdmpJ/i3YnyY= github.com/ava-labs/coreth v0.13.0-rc.0 h1:V2l3qj2ek3geKDJAnF2M94mYJK8kg2kePixujfJ0bmk= @@ -465,10 +463,6 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/otiai10/copy v1.11.0 h1:OKBD80J/mLBrwnzXqGtFCzprFSGioo30JcmR4APsNwc= -github.com/otiai10/copy v1.11.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= -github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= -github.com/otiai10/mint v1.5.1/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -538,8 +532,6 @@ github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobt github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= From a29d5607e35488387775e1aa63c830dce052769f Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 26 Feb 2024 00:06:55 -0800 Subject: [PATCH 12/16] fixup: Use the default evm logging level for load testing --- tests/load/load_test.go | 10 ++++++++-- tests/utils/tmpnet.go | 9 +++------ tests/warp/warp_test.go | 11 +++++++++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index 0b5a25eaf2..67dadf1fe6 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -56,13 +56,19 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { var env *e2e.TestEnvironment ginkgo.BeforeAll(func() { - nodes := utils.NewTmpnetNodes(nodeCount) genesisPath := filepath.Join(repoRootPath, "tests/load/genesis/genesis.json") + + // The load tests are allergic to high levels of evm logging, so leave it at + // the default level instead of raising it to debug (as the warp testing does). + chainConfig := tmpnet.FlagsMap{} + + nodes := utils.NewTmpnetNodes(nodeCount) + env = e2e.NewTestEnvironment( flagVars, utils.NewTmpnetNetwork( nodes, - utils.NewTmpnetSubnet(subnetAName, genesisPath, nodes...), + utils.NewTmpnetSubnet(subnetAName, genesisPath, chainConfig, nodes...), ), ) }) diff --git a/tests/utils/tmpnet.go b/tests/utils/tmpnet.go index 7673859ba7..cb7f9a0745 100644 --- a/tests/utils/tmpnet.go +++ b/tests/utils/tmpnet.go @@ -36,7 +36,7 @@ func NewTmpnetNetwork(nodes []*tmpnet.Node, subnets ...*tmpnet.Subnet) *tmpnet.N // Create the configuration that will enable creation and access to a // subnet created on a temporary network. -func NewTmpnetSubnet(name string, genesisPath string, nodes ...*tmpnet.Node) *tmpnet.Subnet { +func NewTmpnetSubnet(name string, genesisPath string, chainConfig tmpnet.FlagsMap, nodes ...*tmpnet.Node) *tmpnet.Subnet { if len(nodes) == 0 { panic("a subnet must be validated by at least one node") } @@ -51,10 +51,7 @@ func NewTmpnetSubnet(name string, genesisPath string, nodes ...*tmpnet.Node) *tm panic(err) } - configBytes, err := json.Marshal(tmpnet.FlagsMap{ - "log-level": "debug", - "warp-api-enabled": true, - }) + chainConfigBytes, err := json.Marshal(chainConfig) if err != nil { panic(err) } @@ -65,7 +62,7 @@ func NewTmpnetSubnet(name string, genesisPath string, nodes ...*tmpnet.Node) *tm { VMID: evm.ID, Genesis: genesisBytes, - Config: string(configBytes), + Config: string(chainConfigBytes), PreFundedKey: tmpnet.HardhatKey, }, }, diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index 2411ccab02..31cbc0a133 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -93,13 +93,20 @@ func TestE2E(t *testing.T) { var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { // Run only once in the first ginkgo process + + chainConfig := tmpnet.FlagsMap{ + "log-level": "debug", + "warp-api-enabled": true, + } + nodes := utils.NewTmpnetNodes(tmpnet.DefaultNodeCount) + env := e2e.NewTestEnvironment( flagVars, utils.NewTmpnetNetwork( nodes, - utils.NewTmpnetSubnet(subnetAName, genesisPath, nodes...), - utils.NewTmpnetSubnet(subnetBName, genesisPath, nodes...), + utils.NewTmpnetSubnet(subnetAName, genesisPath, chainConfig, nodes...), + utils.NewTmpnetSubnet(subnetBName, genesisPath, chainConfig, nodes...), ), ) From 1e5be9bed0b7af9c075c1876c2ba01bc76ca70b4 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 26 Feb 2024 00:45:05 -0800 Subject: [PATCH 13/16] fixup: Lower the avalanchego logging levels for load testing --- tests/load/load_test.go | 6 ++++++ tests/utils/tmpnet.go | 15 +++++++++------ tests/warp/warp_test.go | 1 + 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index 67dadf1fe6..7634c6978b 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -19,6 +19,7 @@ import ( "github.com/ethereum/go-ethereum/log" + "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" @@ -68,6 +69,11 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { flagVars, utils.NewTmpnetNetwork( nodes, + tmpnet.FlagsMap{ + // The default tmpnet log level (info/debug) induces too much overhead for load testing. + config.LogDisplayLevelKey: "error", + config.LogLevelKey: "info", + }, utils.NewTmpnetSubnet(subnetAName, genesisPath, chainConfig, nodes...), ), ) diff --git a/tests/utils/tmpnet.go b/tests/utils/tmpnet.go index cb7f9a0745..50a83a3c34 100644 --- a/tests/utils/tmpnet.go +++ b/tests/utils/tmpnet.go @@ -24,13 +24,16 @@ func NewTmpnetNodes(count int) []*tmpnet.Node { return nodes } -func NewTmpnetNetwork(nodes []*tmpnet.Node, subnets ...*tmpnet.Subnet) *tmpnet.Network { +func NewTmpnetNetwork(nodes []*tmpnet.Node, flags tmpnet.FlagsMap, subnets ...*tmpnet.Subnet) *tmpnet.Network { + defaultFlags := tmpnet.FlagsMap{} + defaultFlags.SetDefaults(flags) + defaultFlags.SetDefaults(tmpnet.FlagsMap{ + config.ProposerVMUseCurrentHeightKey: true, + }) return &tmpnet.Network{ - DefaultFlags: tmpnet.FlagsMap{ - config.ProposerVMUseCurrentHeightKey: true, - }, - Nodes: nodes, - Subnets: subnets, + DefaultFlags: defaultFlags, + Nodes: nodes, + Subnets: subnets, } } diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index 31cbc0a133..3475aecbc8 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -105,6 +105,7 @@ var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { flagVars, utils.NewTmpnetNetwork( nodes, + tmpnet.FlagsMap{}, utils.NewTmpnetSubnet(subnetAName, genesisPath, chainConfig, nodes...), utils.NewTmpnetSubnet(subnetBName, genesisPath, chainConfig, nodes...), ), From 7c6b6b169661e724a95c8a95f269d8150ab4d2dc Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 26 Feb 2024 10:06:00 -0800 Subject: [PATCH 14/16] fixup: respond to review comments --- tests/load/load_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index 7634c6978b..6c41c6d4d4 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -87,7 +87,7 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { blockchainID := subnet.Chains[0].ChainID nodeURIs := tmpnet.GetNodeURIs(network.Nodes) - validatorIDs := set.Set[ids.NodeID]{} + validatorIDs := set.NewSet[ids.NodeID](len(subnet.ValidatorIDs)) validatorIDs.Add(subnet.ValidatorIDs...) rpcEndpoints := make([]string, 0, len(nodeURIs)) for _, nodeURI := range nodeURIs { From c11ec835a7f445214484613ac4020b4eb953b3a6 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 26 Feb 2024 14:53:39 -0800 Subject: [PATCH 15/16] fixup: Respond to review comments #2 --- tests/load/load_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index 6c41c6d4d4..c2336b0276 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -59,7 +59,7 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { ginkgo.BeforeAll(func() { genesisPath := filepath.Join(repoRootPath, "tests/load/genesis/genesis.json") - // The load tests are allergic to high levels of evm logging, so leave it at + // The load tests are flaky at high levels of evm logging, so leave it at // the default level instead of raising it to debug (as the warp testing does). chainConfig := tmpnet.FlagsMap{} From a3d799cfb965d744a3c444e6dd0dd4ef02021928 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 28 Feb 2024 15:02:14 -0800 Subject: [PATCH 16/16] fixup: Disable unnecessary stdout logging --- tests/load/load_test.go | 5 ++--- tests/utils/tmpnet.go | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/load/load_test.go b/tests/load/load_test.go index c2336b0276..5a2b5c21e5 100644 --- a/tests/load/load_test.go +++ b/tests/load/load_test.go @@ -70,9 +70,8 @@ var _ = ginkgo.Describe("[Load Simulator]", ginkgo.Ordered, func() { utils.NewTmpnetNetwork( nodes, tmpnet.FlagsMap{ - // The default tmpnet log level (info/debug) induces too much overhead for load testing. - config.LogDisplayLevelKey: "error", - config.LogLevelKey: "info", + // The default tmpnet log level (debug) induces too much overhead for load testing. + config.LogLevelKey: "info", }, utils.NewTmpnetSubnet(subnetAName, genesisPath, chainConfig, nodes...), ), diff --git a/tests/utils/tmpnet.go b/tests/utils/tmpnet.go index 50a83a3c34..af1e24908a 100644 --- a/tests/utils/tmpnet.go +++ b/tests/utils/tmpnet.go @@ -28,6 +28,8 @@ func NewTmpnetNetwork(nodes []*tmpnet.Node, flags tmpnet.FlagsMap, subnets ...*t defaultFlags := tmpnet.FlagsMap{} defaultFlags.SetDefaults(flags) defaultFlags.SetDefaults(tmpnet.FlagsMap{ + // Remove when vendored tmpnet default is `off`. tmpnet nodes are run headless so stdout logging is unnecessary. + config.LogDisplayLevelKey: "off", config.ProposerVMUseCurrentHeightKey: true, }) return &tmpnet.Network{