From 739e5e8e2031d0c4ca0645a78fc45917aa7f094c Mon Sep 17 00:00:00 2001 From: Aaron Buchwald Date: Tue, 31 Oct 2023 12:42:16 -0400 Subject: [PATCH 01/39] WIP: add fixture for vm integration tests --- plugin/evm/atomic_trie_iterator_test.go | 5 - plugin/evm/import_tx.go | 10 + plugin/evm/integration/vm_integration_test.go | 206 +++++++++++++ plugin/evm/shared_test_vm.go | 290 ++++++++++++++++++ plugin/evm/shared_test_vm_fixture.go | 82 +++++ plugin/evm/vm.go | 7 + plugin/evm/vm_test.go | 9 - 7 files changed, 595 insertions(+), 14 deletions(-) create mode 100644 plugin/evm/integration/vm_integration_test.go create mode 100644 plugin/evm/shared_test_vm.go create mode 100644 plugin/evm/shared_test_vm_fixture.go diff --git a/plugin/evm/atomic_trie_iterator_test.go b/plugin/evm/atomic_trie_iterator_test.go index 6d8c98cf35..720e603553 100644 --- a/plugin/evm/atomic_trie_iterator_test.go +++ b/plugin/evm/atomic_trie_iterator_test.go @@ -16,11 +16,6 @@ import ( "github.com/stretchr/testify/require" ) -func testSharedMemory() atomic.SharedMemory { - m := atomic.NewMemory(memdb.New()) - return m.NewSharedMemory(testCChainID) -} - func TestIteratorCanIterate(t *testing.T) { lastAcceptedHeight := uint64(1000) db := versiondb.New(memdb.New()) diff --git a/plugin/evm/import_tx.go b/plugin/evm/import_tx.go index 7fd9e688f8..23f4b7b98e 100644 --- a/plugin/evm/import_tx.go +++ b/plugin/evm/import_tx.go @@ -274,6 +274,16 @@ func (utx *UnsignedImportTx) AtomicOps() (ids.ID, *atomic.Requests, error) { return utx.SourceChain, &atomic.Requests{RemoveRequests: utxoIDs}, nil } +// NewImportTx returns a new ImportTx +func (vm *VM) NewImportTx( + chainID ids.ID, // chain to import from + to common.Address, // Address of recipient + baseFee *big.Int, // fee to use post-AP3 + keys []*secp256k1.PrivateKey, // Keys to import the funds +) (*Tx, error) { + return vm.newImportTx(chainID, to, baseFee, keys) +} + // newImportTx returns a new ImportTx func (vm *VM) newImportTx( chainID ids.ID, // chain to import from diff --git a/plugin/evm/integration/vm_integration_test.go b/plugin/evm/integration/vm_integration_test.go new file mode 100644 index 0000000000..ee2d4ec8d4 --- /dev/null +++ b/plugin/evm/integration/vm_integration_test.go @@ -0,0 +1,206 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package integration + +import ( + "context" + "encoding/json" + "math/big" + "testing" + "time" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow/choices" + "github.com/ava-labs/avalanchego/utils/cb58" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/coreth/core" + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/eth/filters" + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/plugin/evm" + "github.com/ethereum/go-ethereum/common" + ginkgo "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + genesisJSONApricotPhase2 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + testKeys []*secp256k1.PrivateKey + testEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] + testShortIDAddrs []ids.ShortID + initialBaseFee = big.NewInt(params.ApricotPhase3InitialBaseFee) +) + +func init() { + +} + +func TestE2E(t *testing.T) { + gomega.RegisterFailHandler(ginkgo.Fail) + ginkgo.RunSpecs(t, "Coreth EVM Integration Tests") +} + +var _ = ginkgo.BeforeSuite(func() { + var b []byte + + for _, key := range []string{ + "24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5", + "2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY", + "cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35", + } { + b, _ = cb58.Decode(key) + pk, _ := secp256k1.ToPrivateKey(b) + testKeys = append(testKeys, pk) + testEthAddrs = append(testEthAddrs, evm.GetEthAddress(pk)) + testShortIDAddrs = append(testShortIDAddrs, pk.PublicKey().Address()) + } +}) + +var _ = ginkgo.AfterSuite(func() { + // TODO +}) + + +type IntegrationFixture interface { + IssueTxs(txs []*types.Transaction) + IssueAtomicTxs(atomicTxs []*evm.Tx) + + BuildAndAccept() + + Teardown() + // ConfirmTxs(txs []*types.Transaction) + // ConfirmAtomicTxs(atomicTxs []*evm.Tx) + + // Define index getter functions + // GetTxReceipt(txHash common.Hash) *types.Receipt +} + +func TestIssueAtomicTxs(t *testing.T) { + importAmount := uint64(50000000) + fixture := createVMFixture("", "", nil, map[ids.ShortID]uint64{ + testShortIDAddrs[0]: importAmount, + }) + + ginkgo.DeferCleanup(func() { + fixture.Teardown() + }) + + // TODO: Construct the atomic transaction + fixture.BuildAndAccept() + // Construct atomic transaction + // build and accept + // check some indices + + importTx, err := fixture.vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]}) + if err != nil { + t.Fatal(err) + } + + if err := vm.mempool.AddLocalTx(importTx); err != nil { + t.Fatal(err) + } + + <-issuer + + blk, err := vm.BuildBlock(context.Background()) + if err != nil { + t.Fatal(err) + } + + if err := blk.Verify(context.Background()); err != nil { + t.Fatal(err) + } + + if status := blk.Status(); status != choices.Processing { + t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status) + } + + if err := vm.SetPreference(context.Background(), blk.ID()); err != nil { + t.Fatal(err) + } + + if err := blk.Accept(context.Background()); err != nil { + t.Fatal(err) + } + + if status := blk.Status(); status != choices.Accepted { + t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status) + } + + if lastAcceptedID, err := vm.LastAccepted(context.Background()); err != nil { + t.Fatal(err) + } else if lastAcceptedID != blk.ID() { + t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID) + } + vm.blockChain.DrainAcceptorQueue() + filterAPI := filters.NewFilterAPI(filters.NewFilterSystem(vm.eth.APIBackend, filters.Config{ + Timeout: 5 * time.Minute, + })) + blockHash := common.Hash(blk.ID()) + logs, err := filterAPI.GetLogs(context.Background(), filters.FilterCriteria{ + BlockHash: &blockHash, + }) + if err != nil { + t.Fatal(err) + } + if len(logs) != 0 { + t.Fatalf("Expected log length to be 0, but found %d", len(logs)) + } + if logs == nil { + t.Fatal("Expected logs to be non-nil") + } + + exportTx, err := vm.newExportTx(vm.ctx.AVAXAssetID, importAmount-(2*params.AvalancheAtomicTxFee), vm.ctx.XChainID, testShortIDAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]}) + if err != nil { + t.Fatal(err) + } + + if err := vm.mempool.AddLocalTx(exportTx); err != nil { + t.Fatal(err) + } + + <-issuer + + blk2, err := vm.BuildBlock(context.Background()) + if err != nil { + t.Fatal(err) + } + + if err := blk2.Verify(context.Background()); err != nil { + t.Fatal(err) + } + + if status := blk2.Status(); status != choices.Processing { + t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status) + } + + if err := blk2.Accept(context.Background()); err != nil { + t.Fatal(err) + } + + if status := blk2.Status(); status != choices.Accepted { + t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status) + } + + if lastAcceptedID, err := vm.LastAccepted(context.Background()); err != nil { + t.Fatal(err) + } else if lastAcceptedID != blk2.ID() { + t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk2.ID(), lastAcceptedID) + } + + // Check that both atomic transactions were indexed as expected. + indexedImportTx, status, height, err := vm.getAtomicTx(importTx.ID()) + assert.NoError(t, err) + assert.Equal(t, evm.Accepted, status) + assert.Equal(t, uint64(1), height, "expected height of indexed import tx to be 1") + assert.Equal(t, indexedImportTx.ID(), importTx.ID(), "expected ID of indexed import tx to match original txID") + + indexedExportTx, status, height, err := vm.getAtomicTx(exportTx.ID()) + assert.NoError(t, err) + assert.Equal(t, evm.Accepted, status) + assert.Equal(t, uint64(2), height, "expected height of indexed export tx to be 2") + assert.Equal(t, indexedExportTx.ID(), exportTx.ID(), "expected ID of indexed import tx to match original txID") +} diff --git a/plugin/evm/shared_test_vm.go b/plugin/evm/shared_test_vm.go new file mode 100644 index 0000000000..3c1113533a --- /dev/null +++ b/plugin/evm/shared_test_vm.go @@ -0,0 +1,290 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "encoding/json" + "errors" + "testing" + + "github.com/ava-labs/avalanchego/api/keystore" + "github.com/ava-labs/avalanchego/chains/atomic" + "github.com/ava-labs/avalanchego/database/manager" + "github.com/ava-labs/avalanchego/database/memdb" + "github.com/ava-labs/avalanchego/database/prefixdb" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow" + engCommon "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/snow/validators" + "github.com/ava-labs/avalanchego/utils/cb58" + "github.com/ava-labs/avalanchego/utils/constants" + "github.com/ava-labs/avalanchego/utils/crypto/bls" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/formatting" + "github.com/ava-labs/avalanchego/utils/hashing" + "github.com/ava-labs/avalanchego/utils/logging" + "github.com/ava-labs/avalanchego/version" + "github.com/ava-labs/avalanchego/vms/components/avax" + avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/coreth/core" + "github.com/ava-labs/coreth/params" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" +) + +var ( + testNetworkID uint32 = 10 + testCChainID = ids.ID{'c', 'c', 'h', 'a', 'i', 'n', 't', 'e', 's', 't'} + testXChainID = ids.ID{'t', 'e', 's', 't', 'x'} + nonExistentID = ids.ID{'F'} + testKeys []*secp256k1.PrivateKey + testEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] + testShortIDAddrs []ids.ShortID + testAvaxAssetID = ids.ID{1, 2, 3} + username = "Johns" + password = "CjasdjhiPeirbSenfeI13" // #nosec G101 + // Use chainId: 43111, so that it does not overlap with any Avalanche ChainIDs, which may have their + // config overridden in vm.Initialize. + genesisJSONApricotPhase0 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONApricotPhase1 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONApricotPhase2 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONApricotPhase3 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONApricotPhase4 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONApricotPhase5 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + + genesisJSONApricotPhasePre6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONApricotPhase6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONApricotPhasePost6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + + genesisJSONBanff = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONCortina = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONDUpgrade = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0,\"dUpgradeBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0x99b9DEA54C48Dfea6aA9A4Ca4623633EE04ddbB5\":{\"balance\":\"0x56bc75e2d63100000\"},\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONLatest = genesisJSONDUpgrade + + apricotRulesPhase0 = params.Rules{} + apricotRulesPhase1 = params.Rules{IsApricotPhase1: true} + apricotRulesPhase2 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true} + apricotRulesPhase3 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true} + apricotRulesPhase4 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true} + apricotRulesPhase5 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true} + apricotRulesPhase6 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true} + banffRules = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true, IsBanff: true} + // cortinaRules = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true, IsBanff: true, IsCortina: true} +) + +func init() { + var b []byte + + for _, key := range []string{ + "24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5", + "2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY", + "cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35", + } { + b, _ = cb58.Decode(key) + pk, _ := secp256k1.ToPrivateKey(b) + testKeys = append(testKeys, pk) + testEthAddrs = append(testEthAddrs, GetEthAddress(pk)) + testShortIDAddrs = append(testShortIDAddrs, pk.PublicKey().Address()) + } +} + +// BuildGenesisTest returns the genesis bytes for Coreth VM to be used in testing +func BuildGenesisTest(t *testing.T, genesisJSON string) []byte { + ss := StaticService{} + + genesis := &core.Genesis{} + if err := json.Unmarshal([]byte(genesisJSON), genesis); err != nil { + t.Fatalf("Problem unmarshaling genesis JSON: %s", err) + } + genesisReply, err := ss.BuildGenesis(nil, genesis) + if err != nil { + t.Fatalf("Failed to create test genesis") + } + genesisBytes, err := formatting.Decode(genesisReply.Encoding, genesisReply.Bytes) + if err != nil { + t.Fatalf("Failed to decode genesis bytes: %s", err) + } + return genesisBytes +} + +func testSharedMemory() atomic.SharedMemory { + m := atomic.NewMemory(memdb.New()) + return m.NewSharedMemory(testCChainID) +} + +func NewContext() *snow.Context { + ctx := snow.DefaultContextTest() + ctx.NodeID = ids.GenerateTestNodeID() + ctx.NetworkID = testNetworkID + ctx.ChainID = testCChainID + ctx.AVAXAssetID = testAvaxAssetID + ctx.XChainID = testXChainID + ctx.SharedMemory = testSharedMemory() + aliaser := ctx.BCLookup.(ids.Aliaser) + _ = aliaser.Alias(testCChainID, "C") + _ = aliaser.Alias(testCChainID, testCChainID.String()) + _ = aliaser.Alias(testXChainID, "X") + _ = aliaser.Alias(testXChainID, testXChainID.String()) + ctx.ValidatorState = &validators.TestState{ + GetSubnetIDF: func(_ context.Context, chainID ids.ID) (ids.ID, error) { + subnetID, ok := map[ids.ID]ids.ID{ + constants.PlatformChainID: constants.PrimaryNetworkID, + testXChainID: constants.PrimaryNetworkID, + testCChainID: constants.PrimaryNetworkID, + }[chainID] + if !ok { + return ids.Empty, errors.New("unknown chain") + } + return subnetID, nil + }, + } + blsSecretKey, err := bls.NewSecretKey() + if err != nil { + panic(err) + } + ctx.WarpSigner = avalancheWarp.NewSigner(blsSecretKey, ctx.NetworkID, ctx.ChainID) + ctx.PublicKey = bls.PublicFromSecretKey(blsSecretKey) + + return ctx +} + +// setupGenesis sets up the genesis +// If [genesisJSON] is empty, defaults to using [genesisJSONLatest] +func setupGenesis(t *testing.T, + genesisJSON string, +) (*snow.Context, + manager.Manager, + []byte, + chan engCommon.Message, + *atomic.Memory) { + if len(genesisJSON) == 0 { + genesisJSON = genesisJSONLatest + } + genesisBytes := BuildGenesisTest(t, genesisJSON) + ctx := NewContext() + + baseDBManager := manager.NewMemDB(&version.Semantic{ + Major: 1, + Minor: 4, + Patch: 5, + }) + + m := atomic.NewMemory(prefixdb.New([]byte{0}, baseDBManager.Current().Database)) + ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID) + + // NB: this lock is intentionally left locked when this function returns. + // The caller of this function is responsible for unlocking. + ctx.Lock.Lock() + + userKeystore := keystore.New( + logging.NoLog{}, + manager.NewMemDB(&version.Semantic{ + Major: 1, + Minor: 4, + Patch: 5, + }), + ) + if err := userKeystore.CreateUser(username, password); err != nil { + t.Fatal(err) + } + ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID) + + issuer := make(chan engCommon.Message, 1) + prefixedDBManager := baseDBManager.NewPrefixDBManager([]byte{1}) + return ctx, prefixedDBManager, genesisBytes, issuer, m +} + +// GenesisVM creates a VM instance with the genesis test bytes and returns +// the channel use to send messages to the engine, the vm, and atomic memory +// If [genesisJSON] is empty, defaults to using [genesisJSONLatest] +func GenesisVM(t *testing.T, + finishBootstrapping bool, + genesisJSON string, + configJSON string, + upgradeJSON string, +) (chan engCommon.Message, + *VM, manager.Manager, + *atomic.Memory, + *engCommon.SenderTest) { + vm := &VM{} + ctx, dbManager, genesisBytes, issuer, m := setupGenesis(t, genesisJSON) + appSender := &engCommon.SenderTest{T: t} + appSender.CantSendAppGossip = true + appSender.SendAppGossipF = func(context.Context, []byte) error { return nil } + if err := vm.Initialize( + context.Background(), + ctx, + dbManager, + genesisBytes, + []byte(upgradeJSON), + []byte(configJSON), + issuer, + []*engCommon.Fx{}, + appSender, + ); err != nil { + t.Fatal(err) + } + + if finishBootstrapping { + assert.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping)) + assert.NoError(t, vm.SetState(context.Background(), snow.NormalOp)) + } + + return issuer, vm, dbManager, m, appSender +} + +func addUTXO(sharedMemory *atomic.Memory, ctx *snow.Context, txID ids.ID, index uint32, assetID ids.ID, amount uint64, addr ids.ShortID) (*avax.UTXO, error) { + utxo := &avax.UTXO{ + UTXOID: avax.UTXOID{ + TxID: txID, + OutputIndex: index, + }, + Asset: avax.Asset{ID: assetID}, + Out: &secp256k1fx.TransferOutput{ + Amt: amount, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{addr}, + }, + }, + } + utxoBytes, err := Codec.Marshal(codecVersion, utxo) + if err != nil { + return nil, err + } + + xChainSharedMemory := sharedMemory.NewSharedMemory(ctx.XChainID) + inputID := utxo.InputID() + if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{ctx.ChainID: {PutRequests: []*atomic.Element{{ + Key: inputID[:], + Value: utxoBytes, + Traits: [][]byte{ + addr.Bytes(), + }, + }}}}); err != nil { + return nil, err + } + + return utxo, nil +} + +// GenesisVMWithUTXOs creates a GenesisVM and generates UTXOs in the X-Chain Shared Memory containing AVAX based on the [utxos] map +// Generates UTXOIDs by using a hash of the address in the [utxos] map such that the UTXOs will be generated deterministically. +// If [genesisJSON] is empty, defaults to using [genesisJSONLatest] +func GenesisVMWithUTXOs(t testing.TB, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, utxos map[ids.ShortID]uint64) (chan engCommon.Message, *VM, manager.Manager, *atomic.Memory, *engCommon.SenderTest) { + issuer, vm, dbManager, sharedMemory, sender := GenesisVM(t, finishBootstrapping, genesisJSON, configJSON, upgradeJSON) + for addr, avaxAmount := range utxos { + txID, err := ids.ToID(hashing.ComputeHash256(addr.Bytes())) + if err != nil { + t.Fatalf("Failed to generate txID from addr: %s", err) + } + if _, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, avaxAmount, addr); err != nil { + t.Fatalf("Failed to add UTXO to shared memory: %s", err) + } + } + + return issuer, vm, dbManager, sharedMemory, sender +} diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go new file mode 100644 index 0000000000..ec9383253f --- /dev/null +++ b/plugin/evm/shared_test_vm_fixture.go @@ -0,0 +1,82 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package evm + +import ( + "context" + "encoding/json" + "math/big" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/coreth/core" + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/params" + "github.com/ethereum/go-ethereum/common" + ginkgo "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" +) + +type vmFixture struct { + require *require.Assertions + vm *VM +} + +func newPrefundedGenesis( + prefundedEthAddrs map[common.Address]uint64, +) *core.Genesis { + alloc := core.GenesisAlloc{} + for address, balance := range prefundedEthAddrs { + alloc[address] = core.GenesisAccount{ + Balance: big.NewInt(int64(balance)), + } + } + + return &core.Genesis{ + Config: params.TestChainConfig, + Difficulty: big.NewInt(0), + Alloc: alloc, + } +} + +func createVMFixture(configJSON string, upgradeJSON string, prefundedEthAddrs map[common.Address]uint64, prefundedUTXOs map[ids.ShortID]uint64) *vmFixture { + require := require.New(ginkgo.GinkgoT()) + + genesis := newPrefundedGenesis(prefundedEthAddrs) + genesisBytes, err := json.Marshal(genesis) + require.NoError(err) + + _, vm, _, _, _ := GenesisVMWithUTXOs(ginkgo.GinkgoT(), true, string(genesisBytes), configJSON, upgradeJSON, prefundedUTXOs) + return &vmFixture{ + vm: vm, + require: require, + } +} + +func (v *vmFixture) IssueTxs(txs []*types.Transaction) { + errs := v.vm.GetTxpool().AddRemotesSync(txs) + for _, err := range errs { + v.require.NoError(err) + } +} + +func (v *vmFixture) IssueAtomicTxs(atomicTxs []*Tx) { + mempool := v.vm.GetAtomicMempool() + for _, tx := range atomicTxs { + v.require.NoError(mempool.AddTx(tx)) + } +} + +func (v *vmFixture) BuildAndAccept() { + ctx := context.Background() + block, err := v.vm.BuildBlock(ctx) + v.require.NoError(err) + + v.require.NoError(block.Verify(ctx)) + v.require.NoError(v.vm.SetPreference(ctx, block.ID())) + v.require.NoError(block.Accept(ctx)) +} + +func (v *vmFixture) Teardown() { + v.require.NoError(v.vm.Shutdown(context.Background())) +} diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 304073d6ef..9a58b48638 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -352,6 +352,8 @@ func (vm *VM) Clock() *mockable.Clock { return &vm.clock } // Logger implements the secp256k1fx interface func (vm *VM) Logger() logging.Logger { return vm.ctx.Log } +func (vm *VM) SnowContext() *snow.Context { return vm.ctx } + /* ****************************************************************************** ********************************* Snowman API ******************************** @@ -2045,3 +2047,8 @@ func (vm *VM) stateSyncEnabled(lastAcceptedHeight uint64) bool { // enable state sync by default if the chain is empty. return lastAcceptedHeight == 0 } + +// To be used for testing fixture +func (vm *VM) GetTxpool() *txpool.TxPool { return vm.txPool } + +func (vm *VM) GetAtomicMempool() *Mempool { return vm.mempool } diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 94a219e04a..56649ae6fa 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -32,22 +32,14 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ava-labs/avalanchego/api/keystore" "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow" "github.com/ava-labs/avalanchego/snow/choices" - "github.com/ava-labs/avalanchego/snow/validators" - "github.com/ava-labs/avalanchego/utils/cb58" - "github.com/ava-labs/avalanchego/utils/constants" - "github.com/ava-labs/avalanchego/utils/crypto/bls" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - "github.com/ava-labs/avalanchego/utils/formatting" "github.com/ava-labs/avalanchego/utils/hashing" - "github.com/ava-labs/avalanchego/utils/logging" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/utils/units" "github.com/ava-labs/avalanchego/vms/components/avax" @@ -63,7 +55,6 @@ import ( "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/rpc" - avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/coreth/accounts/abi" accountKeystore "github.com/ava-labs/coreth/accounts/keystore" ) From 3e048a0d425041397aba6f9b81222bf022bb4526 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 3 Nov 2023 19:32:23 +0100 Subject: [PATCH 02/39] Move vm integration test to tests/integration --- plugin/evm/import_tx.go | 10 - plugin/evm/integration/vm_integration_test.go | 206 -------------- plugin/evm/shared_test_vm.go | 96 +++---- plugin/evm/shared_test_vm_fixture.go | 36 +-- plugin/evm/vm.go | 29 ++ plugin/evm/vm_test.go | 260 ------------------ tests/fixture.go | 23 ++ tests/integration/integration.go | 25 ++ tests/integration/integration_test.go | 42 +++ tests/integration/vm/atomic_tx.go | 130 +++++++++ 10 files changed, 308 insertions(+), 549 deletions(-) delete mode 100644 plugin/evm/integration/vm_integration_test.go create mode 100644 tests/fixture.go create mode 100644 tests/integration/integration.go create mode 100644 tests/integration/integration_test.go create mode 100644 tests/integration/vm/atomic_tx.go diff --git a/plugin/evm/import_tx.go b/plugin/evm/import_tx.go index 23f4b7b98e..7fd9e688f8 100644 --- a/plugin/evm/import_tx.go +++ b/plugin/evm/import_tx.go @@ -274,16 +274,6 @@ func (utx *UnsignedImportTx) AtomicOps() (ids.ID, *atomic.Requests, error) { return utx.SourceChain, &atomic.Requests{RemoveRequests: utxoIDs}, nil } -// NewImportTx returns a new ImportTx -func (vm *VM) NewImportTx( - chainID ids.ID, // chain to import from - to common.Address, // Address of recipient - baseFee *big.Int, // fee to use post-AP3 - keys []*secp256k1.PrivateKey, // Keys to import the funds -) (*Tx, error) { - return vm.newImportTx(chainID, to, baseFee, keys) -} - // newImportTx returns a new ImportTx func (vm *VM) newImportTx( chainID ids.ID, // chain to import from diff --git a/plugin/evm/integration/vm_integration_test.go b/plugin/evm/integration/vm_integration_test.go deleted file mode 100644 index ee2d4ec8d4..0000000000 --- a/plugin/evm/integration/vm_integration_test.go +++ /dev/null @@ -1,206 +0,0 @@ -// (c) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package integration - -import ( - "context" - "encoding/json" - "math/big" - "testing" - "time" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow/choices" - "github.com/ava-labs/avalanchego/utils/cb58" - "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/coreth/eth/filters" - "github.com/ava-labs/coreth/params" - "github.com/ava-labs/coreth/plugin/evm" - "github.com/ethereum/go-ethereum/common" - ginkgo "github.com/onsi/ginkgo/v2" - "github.com/onsi/gomega" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -var ( - genesisJSONApricotPhase2 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - testKeys []*secp256k1.PrivateKey - testEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] - testShortIDAddrs []ids.ShortID - initialBaseFee = big.NewInt(params.ApricotPhase3InitialBaseFee) -) - -func init() { - -} - -func TestE2E(t *testing.T) { - gomega.RegisterFailHandler(ginkgo.Fail) - ginkgo.RunSpecs(t, "Coreth EVM Integration Tests") -} - -var _ = ginkgo.BeforeSuite(func() { - var b []byte - - for _, key := range []string{ - "24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5", - "2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY", - "cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35", - } { - b, _ = cb58.Decode(key) - pk, _ := secp256k1.ToPrivateKey(b) - testKeys = append(testKeys, pk) - testEthAddrs = append(testEthAddrs, evm.GetEthAddress(pk)) - testShortIDAddrs = append(testShortIDAddrs, pk.PublicKey().Address()) - } -}) - -var _ = ginkgo.AfterSuite(func() { - // TODO -}) - - -type IntegrationFixture interface { - IssueTxs(txs []*types.Transaction) - IssueAtomicTxs(atomicTxs []*evm.Tx) - - BuildAndAccept() - - Teardown() - // ConfirmTxs(txs []*types.Transaction) - // ConfirmAtomicTxs(atomicTxs []*evm.Tx) - - // Define index getter functions - // GetTxReceipt(txHash common.Hash) *types.Receipt -} - -func TestIssueAtomicTxs(t *testing.T) { - importAmount := uint64(50000000) - fixture := createVMFixture("", "", nil, map[ids.ShortID]uint64{ - testShortIDAddrs[0]: importAmount, - }) - - ginkgo.DeferCleanup(func() { - fixture.Teardown() - }) - - // TODO: Construct the atomic transaction - fixture.BuildAndAccept() - // Construct atomic transaction - // build and accept - // check some indices - - importTx, err := fixture.vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]}) - if err != nil { - t.Fatal(err) - } - - if err := vm.mempool.AddLocalTx(importTx); err != nil { - t.Fatal(err) - } - - <-issuer - - blk, err := vm.BuildBlock(context.Background()) - if err != nil { - t.Fatal(err) - } - - if err := blk.Verify(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk.Status(); status != choices.Processing { - t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status) - } - - if err := vm.SetPreference(context.Background(), blk.ID()); err != nil { - t.Fatal(err) - } - - if err := blk.Accept(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk.Status(); status != choices.Accepted { - t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status) - } - - if lastAcceptedID, err := vm.LastAccepted(context.Background()); err != nil { - t.Fatal(err) - } else if lastAcceptedID != blk.ID() { - t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID) - } - vm.blockChain.DrainAcceptorQueue() - filterAPI := filters.NewFilterAPI(filters.NewFilterSystem(vm.eth.APIBackend, filters.Config{ - Timeout: 5 * time.Minute, - })) - blockHash := common.Hash(blk.ID()) - logs, err := filterAPI.GetLogs(context.Background(), filters.FilterCriteria{ - BlockHash: &blockHash, - }) - if err != nil { - t.Fatal(err) - } - if len(logs) != 0 { - t.Fatalf("Expected log length to be 0, but found %d", len(logs)) - } - if logs == nil { - t.Fatal("Expected logs to be non-nil") - } - - exportTx, err := vm.newExportTx(vm.ctx.AVAXAssetID, importAmount-(2*params.AvalancheAtomicTxFee), vm.ctx.XChainID, testShortIDAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]}) - if err != nil { - t.Fatal(err) - } - - if err := vm.mempool.AddLocalTx(exportTx); err != nil { - t.Fatal(err) - } - - <-issuer - - blk2, err := vm.BuildBlock(context.Background()) - if err != nil { - t.Fatal(err) - } - - if err := blk2.Verify(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk2.Status(); status != choices.Processing { - t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status) - } - - if err := blk2.Accept(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk2.Status(); status != choices.Accepted { - t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status) - } - - if lastAcceptedID, err := vm.LastAccepted(context.Background()); err != nil { - t.Fatal(err) - } else if lastAcceptedID != blk2.ID() { - t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk2.ID(), lastAcceptedID) - } - - // Check that both atomic transactions were indexed as expected. - indexedImportTx, status, height, err := vm.getAtomicTx(importTx.ID()) - assert.NoError(t, err) - assert.Equal(t, evm.Accepted, status) - assert.Equal(t, uint64(1), height, "expected height of indexed import tx to be 1") - assert.Equal(t, indexedImportTx.ID(), importTx.ID(), "expected ID of indexed import tx to match original txID") - - indexedExportTx, status, height, err := vm.getAtomicTx(exportTx.ID()) - assert.NoError(t, err) - assert.Equal(t, evm.Accepted, status) - assert.Equal(t, uint64(2), height, "expected height of indexed export tx to be 2") - assert.Equal(t, indexedExportTx.ID(), exportTx.ID(), "expected ID of indexed import tx to match original txID") -} diff --git a/plugin/evm/shared_test_vm.go b/plugin/evm/shared_test_vm.go index 3c1113533a..2160468866 100644 --- a/plugin/evm/shared_test_vm.go +++ b/plugin/evm/shared_test_vm.go @@ -7,11 +7,15 @@ import ( "context" "encoding/json" "errors" - "testing" + + "github.com/ethereum/go-ethereum/common" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/api/keystore" "github.com/ava-labs/avalanchego/chains/atomic" - "github.com/ava-labs/avalanchego/database/manager" + "github.com/ava-labs/avalanchego/database" "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/ids" @@ -25,14 +29,12 @@ import ( "github.com/ava-labs/avalanchego/utils/formatting" "github.com/ava-labs/avalanchego/utils/hashing" "github.com/ava-labs/avalanchego/utils/logging" - "github.com/ava-labs/avalanchego/version" "github.com/ava-labs/avalanchego/vms/components/avax" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/params" - "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" ) var ( @@ -59,10 +61,10 @@ var ( genesisJSONApricotPhase6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" genesisJSONApricotPhasePost6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONBanff = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONCortina = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONDUpgrade = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0,\"dUpgradeBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0x99b9DEA54C48Dfea6aA9A4Ca4623633EE04ddbB5\":{\"balance\":\"0x56bc75e2d63100000\"},\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONLatest = genesisJSONDUpgrade + genesisJSONBanff = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONCortina = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONDurango = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0,\"durangoBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0x99b9DEA54C48Dfea6aA9A4Ca4623633EE04ddbB5\":{\"balance\":\"0x56bc75e2d63100000\"},\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" + genesisJSONLatest = genesisJSONDurango apricotRulesPhase0 = params.Rules{} apricotRulesPhase1 = params.Rules{IsApricotPhase1: true} @@ -92,21 +94,17 @@ func init() { } // BuildGenesisTest returns the genesis bytes for Coreth VM to be used in testing -func BuildGenesisTest(t *testing.T, genesisJSON string) []byte { +func BuildGenesisTest(t require.TestingT, genesisJSON string) []byte { + require := require.New(t) ss := StaticService{} genesis := &core.Genesis{} - if err := json.Unmarshal([]byte(genesisJSON), genesis); err != nil { - t.Fatalf("Problem unmarshaling genesis JSON: %s", err) - } + err := json.Unmarshal([]byte(genesisJSON), genesis) + require.NoError(err, "problem unmarshaling genesis JSON") genesisReply, err := ss.BuildGenesis(nil, genesis) - if err != nil { - t.Fatalf("Failed to create test genesis") - } + require.NoError(err, "failed to create test genesis") genesisBytes, err := formatting.Decode(genesisReply.Encoding, genesisReply.Bytes) - if err != nil { - t.Fatalf("Failed to decode genesis bytes: %s", err) - } + require.NoError(err, "failed to decode genesis bytes") return genesisBytes } @@ -153,10 +151,10 @@ func NewContext() *snow.Context { // setupGenesis sets up the genesis // If [genesisJSON] is empty, defaults to using [genesisJSONLatest] -func setupGenesis(t *testing.T, +func setupGenesis(t require.TestingT, genesisJSON string, ) (*snow.Context, - manager.Manager, + database.Database, []byte, chan engCommon.Message, *atomic.Memory) { @@ -166,13 +164,9 @@ func setupGenesis(t *testing.T, genesisBytes := BuildGenesisTest(t, genesisJSON) ctx := NewContext() - baseDBManager := manager.NewMemDB(&version.Semantic{ - Major: 1, - Minor: 4, - Patch: 5, - }) + baseDB := memdb.New() - m := atomic.NewMemory(prefixdb.New([]byte{0}, baseDBManager.Current().Database)) + m := atomic.NewMemory(prefixdb.New([]byte{0}, baseDB)) ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID) // NB: this lock is intentionally left locked when this function returns. @@ -181,59 +175,53 @@ func setupGenesis(t *testing.T, userKeystore := keystore.New( logging.NoLog{}, - manager.NewMemDB(&version.Semantic{ - Major: 1, - Minor: 4, - Patch: 5, - }), + memdb.New(), ) - if err := userKeystore.CreateUser(username, password); err != nil { - t.Fatal(err) - } + err := userKeystore.CreateUser(username, password) + require.NoError(t, err) ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID) issuer := make(chan engCommon.Message, 1) - prefixedDBManager := baseDBManager.NewPrefixDBManager([]byte{1}) - return ctx, prefixedDBManager, genesisBytes, issuer, m + prefixedDB := prefixdb.New([]byte{1}, baseDB) + return ctx, prefixedDB, genesisBytes, issuer, m } // GenesisVM creates a VM instance with the genesis test bytes and returns // the channel use to send messages to the engine, the vm, and atomic memory // If [genesisJSON] is empty, defaults to using [genesisJSONLatest] -func GenesisVM(t *testing.T, +func GenesisVM(t require.TestingT, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, ) (chan engCommon.Message, - *VM, manager.Manager, + *VM, database.Database, *atomic.Memory, *engCommon.SenderTest) { vm := &VM{} - ctx, dbManager, genesisBytes, issuer, m := setupGenesis(t, genesisJSON) + ctx, db, genesisBytes, issuer, m := setupGenesis(t, genesisJSON) appSender := &engCommon.SenderTest{T: t} appSender.CantSendAppGossip = true appSender.SendAppGossipF = func(context.Context, []byte) error { return nil } - if err := vm.Initialize( + err := vm.Initialize( context.Background(), ctx, - dbManager, + db, genesisBytes, []byte(upgradeJSON), []byte(configJSON), issuer, []*engCommon.Fx{}, appSender, - ); err != nil { - t.Fatal(err) - } + ) + require.NoError(t, err) if finishBootstrapping { assert.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping)) assert.NoError(t, vm.SetState(context.Background(), snow.NormalOp)) } - return issuer, vm, dbManager, m, appSender + return issuer, vm, db, m, appSender } func addUTXO(sharedMemory *atomic.Memory, ctx *snow.Context, txID ids.ID, index uint32, assetID ids.ID, amount uint64, addr ids.ShortID) (*avax.UTXO, error) { @@ -274,17 +262,15 @@ func addUTXO(sharedMemory *atomic.Memory, ctx *snow.Context, txID ids.ID, index // GenesisVMWithUTXOs creates a GenesisVM and generates UTXOs in the X-Chain Shared Memory containing AVAX based on the [utxos] map // Generates UTXOIDs by using a hash of the address in the [utxos] map such that the UTXOs will be generated deterministically. // If [genesisJSON] is empty, defaults to using [genesisJSONLatest] -func GenesisVMWithUTXOs(t testing.TB, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, utxos map[ids.ShortID]uint64) (chan engCommon.Message, *VM, manager.Manager, *atomic.Memory, *engCommon.SenderTest) { - issuer, vm, dbManager, sharedMemory, sender := GenesisVM(t, finishBootstrapping, genesisJSON, configJSON, upgradeJSON) +func GenesisVMWithUTXOs(t require.TestingT, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, utxos map[ids.ShortID]uint64) (chan engCommon.Message, *VM, database.Database, *atomic.Memory, *engCommon.SenderTest) { + require := require.New(t) + issuer, vm, db, sharedMemory, sender := GenesisVM(t, finishBootstrapping, genesisJSON, configJSON, upgradeJSON) for addr, avaxAmount := range utxos { txID, err := ids.ToID(hashing.ComputeHash256(addr.Bytes())) - if err != nil { - t.Fatalf("Failed to generate txID from addr: %s", err) - } - if _, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, avaxAmount, addr); err != nil { - t.Fatalf("Failed to add UTXO to shared memory: %s", err) - } + require.NoError(err, "failed to generate txID from addr") + _, err = addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, avaxAmount, addr) + require.NoError(err, "failed to add UTXO to shared memory") } - return issuer, vm, dbManager, sharedMemory, sender + return issuer, vm, db, sharedMemory, sender } diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index ec9383253f..61f4dbde30 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -5,21 +5,24 @@ package evm import ( "context" - "encoding/json" "math/big" + "github.com/ethereum/go-ethereum/common" + + "github.com/stretchr/testify/require" + "github.com/ava-labs/avalanchego/ids" + engCommon "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" - "github.com/ethereum/go-ethereum/common" - ginkgo "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/require" ) type vmFixture struct { require *require.Assertions - vm *VM + Issuer chan engCommon.Message + VM *VM } func newPrefundedGenesis( @@ -39,29 +42,26 @@ func newPrefundedGenesis( } } -func createVMFixture(configJSON string, upgradeJSON string, prefundedEthAddrs map[common.Address]uint64, prefundedUTXOs map[ids.ShortID]uint64) *vmFixture { - require := require.New(ginkgo.GinkgoT()) - - genesis := newPrefundedGenesis(prefundedEthAddrs) - genesisBytes, err := json.Marshal(genesis) - require.NoError(err) +func CreateVMFixture(t require.TestingT, prefundedUTXOs map[ids.ShortID]uint64) *vmFixture { + require := require.New(t) - _, vm, _, _, _ := GenesisVMWithUTXOs(ginkgo.GinkgoT(), true, string(genesisBytes), configJSON, upgradeJSON, prefundedUTXOs) + issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", prefundedUTXOs) return &vmFixture{ - vm: vm, + VM: vm, + Issuer: issuer, require: require, } } func (v *vmFixture) IssueTxs(txs []*types.Transaction) { - errs := v.vm.GetTxpool().AddRemotesSync(txs) + errs := v.VM.GetTxpool().AddRemotesSync(txs) for _, err := range errs { v.require.NoError(err) } } func (v *vmFixture) IssueAtomicTxs(atomicTxs []*Tx) { - mempool := v.vm.GetAtomicMempool() + mempool := v.VM.GetAtomicMempool() for _, tx := range atomicTxs { v.require.NoError(mempool.AddTx(tx)) } @@ -69,14 +69,14 @@ func (v *vmFixture) IssueAtomicTxs(atomicTxs []*Tx) { func (v *vmFixture) BuildAndAccept() { ctx := context.Background() - block, err := v.vm.BuildBlock(ctx) + block, err := v.VM.BuildBlock(ctx) v.require.NoError(err) v.require.NoError(block.Verify(ctx)) - v.require.NoError(v.vm.SetPreference(ctx, block.ID())) + v.require.NoError(v.VM.SetPreference(ctx, block.ID())) v.require.NoError(block.Accept(ctx)) } func (v *vmFixture) Teardown() { - v.require.NoError(v.vm.Shutdown(context.Background())) + v.require.NoError(v.VM.Shutdown(context.Background())) } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 9a58b48638..3f9341c7e7 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -2052,3 +2052,32 @@ func (vm *VM) stateSyncEnabled(lastAcceptedHeight uint64) bool { func (vm *VM) GetTxpool() *txpool.TxPool { return vm.txPool } func (vm *VM) GetAtomicMempool() *Mempool { return vm.mempool } + +func (vm *VM) NewImportTx(chainID ids.ID, to common.Address, baseFee *big.Int, keys []*secp256k1.PrivateKey) (*Tx, error) { + return vm.newImportTx(chainID, to, baseFee, keys) +} + +func (vm *VM) GetXChainID() ids.ID { return vm.ctx.XChainID } + +func (vm *VM) GetAVAXAssetID() ids.ID { return vm.ctx.AVAXAssetID } + +func (vm *VM) GetBlockChain() *core.BlockChain { return vm.blockChain } + +func (vm *VM) NewExportTx( + assetID ids.ID, + amount uint64, + chainID ids.ID, + to ids.ShortID, + baseFee *big.Int, + keys []*secp256k1.PrivateKey, +) (*Tx, error) { + return vm.newExportTx(assetID, amount, chainID, to, baseFee, keys) +} + +func (vm *VM) GetAtomicTx(txID ids.ID) (*Tx, Status, uint64, error) { + return vm.getAtomicTx(txID) +} + +func (vm *VM) GetAPIBackend() *eth.EthAPIBackend { + return vm.eth.APIBackend +} diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 56649ae6fa..6d79109f7b 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -59,266 +59,6 @@ import ( accountKeystore "github.com/ava-labs/coreth/accounts/keystore" ) -var ( - testNetworkID uint32 = 10 - testCChainID = ids.ID{'c', 'c', 'h', 'a', 'i', 'n', 't', 'e', 's', 't'} - testXChainID = ids.ID{'t', 'e', 's', 't', 'x'} - nonExistentID = ids.ID{'F'} - testKeys []*secp256k1.PrivateKey - testEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] - testShortIDAddrs []ids.ShortID - testAvaxAssetID = ids.ID{1, 2, 3} - username = "Johns" - password = "CjasdjhiPeirbSenfeI13" // #nosec G101 - // Use chainId: 43111, so that it does not overlap with any Avalanche ChainIDs, which may have their - // config overridden in vm.Initialize. - genesisJSONApricotPhase0 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONApricotPhase1 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONApricotPhase2 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONApricotPhase3 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONApricotPhase4 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONApricotPhase5 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - - genesisJSONApricotPhasePre6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONApricotPhase6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONApricotPhasePost6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - - genesisJSONBanff = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONCortina = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONDurango = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"cortinaBlockTimestamp\":0,\"durangoBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0x99b9DEA54C48Dfea6aA9A4Ca4623633EE04ddbB5\":{\"balance\":\"0x56bc75e2d63100000\"},\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}" - genesisJSONLatest = genesisJSONDurango - - apricotRulesPhase0 = params.Rules{} - apricotRulesPhase1 = params.Rules{IsApricotPhase1: true} - apricotRulesPhase2 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true} - apricotRulesPhase3 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true} - apricotRulesPhase4 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true} - apricotRulesPhase5 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true} - apricotRulesPhase6 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true} - banffRules = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true, IsBanff: true} - // cortinaRules = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true, IsBanff: true, IsCortina: true} -) - -func init() { - var b []byte - - for _, key := range []string{ - "24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5", - "2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY", - "cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35", - } { - b, _ = cb58.Decode(key) - pk, _ := secp256k1.ToPrivateKey(b) - testKeys = append(testKeys, pk) - testEthAddrs = append(testEthAddrs, GetEthAddress(pk)) - testShortIDAddrs = append(testShortIDAddrs, pk.PublicKey().Address()) - } -} - -func newPrefundedGenesis( - balance int, - addresses ...common.Address, -) *core.Genesis { - alloc := core.GenesisAlloc{} - for _, address := range addresses { - alloc[address] = core.GenesisAccount{ - Balance: big.NewInt(int64(balance)), - } - } - - return &core.Genesis{ - Config: params.TestChainConfig, - Difficulty: big.NewInt(0), - Alloc: alloc, - } -} - -// BuildGenesisTest returns the genesis bytes for Coreth VM to be used in testing -func BuildGenesisTest(t *testing.T, genesisJSON string) []byte { - ss := StaticService{} - - genesis := &core.Genesis{} - if err := json.Unmarshal([]byte(genesisJSON), genesis); err != nil { - t.Fatalf("Problem unmarshaling genesis JSON: %s", err) - } - genesisReply, err := ss.BuildGenesis(nil, genesis) - if err != nil { - t.Fatalf("Failed to create test genesis") - } - genesisBytes, err := formatting.Decode(genesisReply.Encoding, genesisReply.Bytes) - if err != nil { - t.Fatalf("Failed to decode genesis bytes: %s", err) - } - return genesisBytes -} - -func NewContext() *snow.Context { - ctx := utils.TestSnowContext() - ctx.NodeID = ids.GenerateTestNodeID() - ctx.NetworkID = testNetworkID - ctx.ChainID = testCChainID - ctx.AVAXAssetID = testAvaxAssetID - ctx.XChainID = testXChainID - ctx.SharedMemory = testSharedMemory() - aliaser := ctx.BCLookup.(ids.Aliaser) - _ = aliaser.Alias(testCChainID, "C") - _ = aliaser.Alias(testCChainID, testCChainID.String()) - _ = aliaser.Alias(testXChainID, "X") - _ = aliaser.Alias(testXChainID, testXChainID.String()) - ctx.ValidatorState = &validators.TestState{ - GetSubnetIDF: func(_ context.Context, chainID ids.ID) (ids.ID, error) { - subnetID, ok := map[ids.ID]ids.ID{ - constants.PlatformChainID: constants.PrimaryNetworkID, - testXChainID: constants.PrimaryNetworkID, - testCChainID: constants.PrimaryNetworkID, - }[chainID] - if !ok { - return ids.Empty, errors.New("unknown chain") - } - return subnetID, nil - }, - } - blsSecretKey, err := bls.NewSecretKey() - if err != nil { - panic(err) - } - ctx.WarpSigner = avalancheWarp.NewSigner(blsSecretKey, ctx.NetworkID, ctx.ChainID) - ctx.PublicKey = bls.PublicFromSecretKey(blsSecretKey) - return ctx -} - -// setupGenesis sets up the genesis -// If [genesisJSON] is empty, defaults to using [genesisJSONLatest] -func setupGenesis( - t *testing.T, - genesisJSON string, -) (*snow.Context, - database.Database, - []byte, - chan commonEng.Message, - *atomic.Memory, -) { - if len(genesisJSON) == 0 { - genesisJSON = genesisJSONLatest - } - genesisBytes := BuildGenesisTest(t, genesisJSON) - ctx := NewContext() - - baseDB := memdb.New() - - // initialize the atomic memory - atomicMemory := atomic.NewMemory(prefixdb.New([]byte{0}, baseDB)) - ctx.SharedMemory = atomicMemory.NewSharedMemory(ctx.ChainID) - - // NB: this lock is intentionally left locked when this function returns. - // The caller of this function is responsible for unlocking. - ctx.Lock.Lock() - - userKeystore := keystore.New(logging.NoLog{}, memdb.New()) - if err := userKeystore.CreateUser(username, password); err != nil { - t.Fatal(err) - } - ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID) - - issuer := make(chan commonEng.Message, 1) - prefixedDB := prefixdb.New([]byte{1}, baseDB) - return ctx, prefixedDB, genesisBytes, issuer, atomicMemory -} - -// GenesisVM creates a VM instance with the genesis test bytes and returns -// the channel use to send messages to the engine, the VM, database manager, -// sender, and atomic memory. -// If [genesisJSON] is empty, defaults to using [genesisJSONLatest] -func GenesisVM(t *testing.T, - finishBootstrapping bool, - genesisJSON string, - configJSON string, - upgradeJSON string, -) (chan commonEng.Message, - *VM, database.Database, - *atomic.Memory, - *commonEng.SenderTest, -) { - vm := &VM{} - vm.p2pSender = &commonEng.FakeSender{} - ctx, dbManager, genesisBytes, issuer, m := setupGenesis(t, genesisJSON) - appSender := &commonEng.SenderTest{T: t} - appSender.CantSendAppGossip = true - appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } - err := vm.Initialize( - context.Background(), - ctx, - dbManager, - genesisBytes, - []byte(upgradeJSON), - []byte(configJSON), - issuer, - []*commonEng.Fx{}, - appSender, - ) - require.NoError(t, err, "error initializing GenesisVM") - - if finishBootstrapping { - require.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping)) - require.NoError(t, vm.SetState(context.Background(), snow.NormalOp)) - } - - return issuer, vm, dbManager, m, appSender -} - -func addUTXO(sharedMemory *atomic.Memory, ctx *snow.Context, txID ids.ID, index uint32, assetID ids.ID, amount uint64, addr ids.ShortID) (*avax.UTXO, error) { - utxo := &avax.UTXO{ - UTXOID: avax.UTXOID{ - TxID: txID, - OutputIndex: index, - }, - Asset: avax.Asset{ID: assetID}, - Out: &secp256k1fx.TransferOutput{ - Amt: amount, - OutputOwners: secp256k1fx.OutputOwners{ - Threshold: 1, - Addrs: []ids.ShortID{addr}, - }, - }, - } - utxoBytes, err := Codec.Marshal(codecVersion, utxo) - if err != nil { - return nil, err - } - - xChainSharedMemory := sharedMemory.NewSharedMemory(ctx.XChainID) - inputID := utxo.InputID() - if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{ctx.ChainID: {PutRequests: []*atomic.Element{{ - Key: inputID[:], - Value: utxoBytes, - Traits: [][]byte{ - addr.Bytes(), - }, - }}}}); err != nil { - return nil, err - } - - return utxo, nil -} - -// GenesisVMWithUTXOs creates a GenesisVM and generates UTXOs in the X-Chain Shared Memory containing AVAX based on the [utxos] map -// Generates UTXOIDs by using a hash of the address in the [utxos] map such that the UTXOs will be generated deterministically. -// If [genesisJSON] is empty, defaults to using [genesisJSONLatest] -func GenesisVMWithUTXOs(t *testing.T, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, utxos map[ids.ShortID]uint64) (chan commonEng.Message, *VM, database.Database, *atomic.Memory, *commonEng.SenderTest) { - issuer, vm, db, sharedMemory, sender := GenesisVM(t, finishBootstrapping, genesisJSON, configJSON, upgradeJSON) - for addr, avaxAmount := range utxos { - txID, err := ids.ToID(hashing.ComputeHash256(addr.Bytes())) - if err != nil { - t.Fatalf("Failed to generate txID from addr: %s", err) - } - if _, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, avaxAmount, addr); err != nil { - t.Fatalf("Failed to add UTXO to shared memory: %s", err) - } - } - - return issuer, vm, db, sharedMemory, sender -} - func TestVMConfig(t *testing.T) { txFeeCap := float64(11) enabledEthAPIs := []string{"debug"} diff --git a/tests/fixture.go b/tests/fixture.go new file mode 100644 index 0000000000..587ee955e3 --- /dev/null +++ b/tests/fixture.go @@ -0,0 +1,23 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package tests + +import ( + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/plugin/evm" +) + +type IntegrationFixture interface { + IssueTxs(txs []*types.Transaction) + IssueAtomicTxs(atomicTxs []*evm.Tx) + + BuildAndAccept() + + Teardown() + // ConfirmTxs(txs []*types.Transaction) + // ConfirmAtomicTxs(atomicTxs []*evm.Tx) + + // Define index getter functions + // GetTxReceipt(txHash common.Hash) *types.Receipt +} diff --git a/tests/integration/integration.go b/tests/integration/integration.go new file mode 100644 index 0000000000..bbada50cac --- /dev/null +++ b/tests/integration/integration.go @@ -0,0 +1,25 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package integration + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + + "github.com/ava-labs/coreth/params" +) + +var ( + InitialBaseFee = big.NewInt(params.ApricotPhase3InitialBaseFee) + + // Will be initialized by BeforeSuite + // TODO(marun) Maybe supply with a test env as per avalanchego's example? + TestKeys []*secp256k1.PrivateKey + TestEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] + TestShortIDAddrs []ids.ShortID +) diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go new file mode 100644 index 0000000000..2f26e781ad --- /dev/null +++ b/tests/integration/integration_test.go @@ -0,0 +1,42 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package integration_test + +import ( + "testing" + + ginkgo "github.com/onsi/ginkgo/v2" + + "github.com/onsi/gomega" + + "github.com/ava-labs/avalanchego/utils/cb58" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + + "github.com/ava-labs/coreth/plugin/evm" + i9n "github.com/ava-labs/coreth/tests/integration" + + // ensure test packages are scanned by ginkgo + _ "github.com/ava-labs/coreth/tests/integration/vm" +) + +func TestE2E(t *testing.T) { + gomega.RegisterFailHandler(ginkgo.Fail) + ginkgo.RunSpecs(t, "Coreth EVM Integration Tests") +} + +var _ = ginkgo.BeforeSuite(func() { + var b []byte + + for _, key := range []string{ + "24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5", + "2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY", + "cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35", + } { + b, _ = cb58.Decode(key) + pk, _ := secp256k1.ToPrivateKey(b) + i9n.TestKeys = append(i9n.TestKeys, pk) + i9n.TestEthAddrs = append(i9n.TestEthAddrs, evm.GetEthAddress(pk)) + i9n.TestShortIDAddrs = append(i9n.TestShortIDAddrs, pk.PublicKey().Address()) + } +}) diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go new file mode 100644 index 0000000000..fc62db0fe5 --- /dev/null +++ b/tests/integration/vm/atomic_tx.go @@ -0,0 +1,130 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package vm + +import ( + "context" + "time" + + "github.com/ethereum/go-ethereum/common" + + ginkgo "github.com/onsi/ginkgo/v2" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow/choices" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + + "github.com/ava-labs/coreth/eth/filters" + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/plugin/evm" + i9n "github.com/ava-labs/coreth/tests/integration" +) + +var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { + require := require.New(ginkgo.GinkgoT()) + assert := assert.New(ginkgo.GinkgoT()) + + ginkgo.It("should support issuing atomic transactions", func() { + importAmount := uint64(50000000) + fixture := evm.CreateVMFixture(ginkgo.GinkgoT(), map[ids.ShortID]uint64{ + i9n.TestShortIDAddrs[0]: importAmount, + }) + + ginkgo.DeferCleanup(func() { + fixture.Teardown() + }) + + // TODO: Construct the atomic transaction + // fixture.BuildAndAccept() + // Construct atomic transaction + // build and accept + // check some indices + + vm := fixture.VM + + importTx, err := vm.NewImportTx( + vm.GetXChainID(), + i9n.TestEthAddrs[0], + i9n.InitialBaseFee, + []*secp256k1.PrivateKey{i9n.TestKeys[0]}, + ) + require.NoError(err) + + require.NoError(vm.GetAtomicMempool().AddLocalTx(importTx)) + + <-fixture.Issuer + + blk, err := vm.BuildBlock(context.Background()) + require.NoError(err) + + require.NoError(blk.Verify(context.Background())) + require.Equal(blk.Status(), choices.Processing) + + require.NoError(vm.SetPreference(context.Background(), blk.ID())) + + err = blk.Accept(context.Background()) + require.NoError(err) + require.Equal(blk.Status(), choices.Accepted) + + lastAcceptedID, err := vm.LastAccepted(context.Background()) + require.NoError(err) + require.Equal(lastAcceptedID, blk.ID()) + vm.GetBlockChain().DrainAcceptorQueue() + filterAPI := filters.NewFilterAPI(filters.NewFilterSystem(vm.GetAPIBackend(), filters.Config{ + Timeout: 5 * time.Minute, + })) + blockHash := common.Hash(blk.ID()) + logs, err := filterAPI.GetLogs(context.Background(), filters.FilterCriteria{ + BlockHash: &blockHash, + }) + require.NoError(err) + require.Zero(len(logs)) + + exportTx, err := vm.NewExportTx( + vm.GetAVAXAssetID(), + importAmount-(2*params.AvalancheAtomicTxFee), + vm.GetXChainID(), + i9n.TestShortIDAddrs[0], + i9n.InitialBaseFee, + []*secp256k1.PrivateKey{ + i9n.TestKeys[0], + }, + ) + require.NoError(err) + + require.NoError(vm.GetAtomicMempool().AddLocalTx(exportTx)) + + <-fixture.Issuer + + blk2, err := vm.BuildBlock(context.Background()) + require.NoError(err) + + require.NoError(blk2.Verify(context.Background())) + require.Equal(blk2.Status(), choices.Processing) + + require.NoError(blk2.Accept(context.Background())) + require.Equal(blk2.Status(), choices.Accepted) + + lastAcceptedID, err = vm.LastAccepted(context.Background()) + require.NoError(err) + require.Equal(lastAcceptedID, blk2.ID()) + + // Check that both atomic transactions were indexed as expected. + indexedImportTx, status, height, err := vm.GetAtomicTx(importTx.ID()) + require.NoError(err) + assert.Equal(evm.Accepted, status) + assert.Equal(uint64(1), height, "expected height of indexed import tx to be 1") + assert.Equal(indexedImportTx.ID(), importTx.ID(), "expected ID of indexed import tx to match original txID") + + indexedExportTx, status, height, err := vm.GetAtomicTx(exportTx.ID()) + require.NoError(err) + assert.Equal(evm.Accepted, status) + assert.Equal(uint64(2), height, "expected height of indexed export tx to be 2") + assert.Equal(indexedExportTx.ID(), exportTx.ID(), "expected ID of indexed import tx to match original txID") + }) + +}) From eec362db166963151f1b80f15398f25c5846e9e2 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 3 Nov 2023 17:12:54 +0100 Subject: [PATCH 03/39] Factor vm-specific tests into fixture --- plugin/evm/shared_test_vm_fixture.go | 138 +++++++++++++++++++-------- plugin/evm/vm.go | 36 ------- tests/integration/vm/atomic_tx.go | 101 +++----------------- 3 files changed, 108 insertions(+), 167 deletions(-) diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index 61f4dbde30..b2be982b8e 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -6,40 +6,26 @@ package evm import ( "context" "math/big" + "time" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/snow/choices" engCommon "github.com/ava-labs/avalanchego/snow/engine/common" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - "github.com/ava-labs/coreth/core" - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/eth/filters" ) type vmFixture struct { require *require.Assertions - Issuer chan engCommon.Message - VM *VM -} - -func newPrefundedGenesis( - prefundedEthAddrs map[common.Address]uint64, -) *core.Genesis { - alloc := core.GenesisAlloc{} - for address, balance := range prefundedEthAddrs { - alloc[address] = core.GenesisAccount{ - Balance: big.NewInt(int64(balance)), - } - } - - return &core.Genesis{ - Config: params.TestChainConfig, - Difficulty: big.NewInt(0), - Alloc: alloc, - } + issuer chan engCommon.Message + height uint64 + vm *VM } func CreateVMFixture(t require.TestingT, prefundedUTXOs map[ids.ShortID]uint64) *vmFixture { @@ -47,36 +33,104 @@ func CreateVMFixture(t require.TestingT, prefundedUTXOs map[ids.ShortID]uint64) issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", prefundedUTXOs) return &vmFixture{ - VM: vm, - Issuer: issuer, + vm: vm, + issuer: issuer, require: require, } } -func (v *vmFixture) IssueTxs(txs []*types.Transaction) { - errs := v.VM.GetTxpool().AddRemotesSync(txs) - for _, err := range errs { - v.require.NoError(err) - } +func (v *vmFixture) Teardown() { + v.require.NoError(v.vm.Shutdown(context.Background())) } -func (v *vmFixture) IssueAtomicTxs(atomicTxs []*Tx) { - mempool := v.VM.GetAtomicMempool() - for _, tx := range atomicTxs { - v.require.NoError(mempool.AddTx(tx)) - } +func (v *vmFixture) GetXChainID() ids.ID { return v.vm.ctx.XChainID } + +func (v *vmFixture) GetAVAXAssetID() ids.ID { return v.vm.ctx.AVAXAssetID } + +func (v *vmFixture) IssueImportTx( + t require.TestingT, + ctx context.Context, + chainID ids.ID, + to common.Address, + baseFee *big.Int, + keys []*secp256k1.PrivateKey, +) *Tx { + importTx, err := v.vm.newImportTx(chainID, to, baseFee, keys) + v.require.NoError(err) + + v.require.NoError(v.vm.mempool.AddLocalTx(importTx)) + + <-v.issuer + + height := v.buildAndAcceptBlockForTx(ctx, importTx) + + v.checkAtomicTxIndexing(t, importTx, height) + + return importTx } -func (v *vmFixture) BuildAndAccept() { - ctx := context.Background() - block, err := v.VM.BuildBlock(ctx) +func (v *vmFixture) IssueExportTx( + t require.TestingT, + ctx context.Context, + assetID ids.ID, + amount uint64, + chainID ids.ID, + to ids.ShortID, + baseFee *big.Int, + keys []*secp256k1.PrivateKey, +) *Tx { + exportTx, err := v.vm.newExportTx(assetID, amount, chainID, to, baseFee, keys) v.require.NoError(err) - v.require.NoError(block.Verify(ctx)) - v.require.NoError(v.VM.SetPreference(ctx, block.ID())) - v.require.NoError(block.Accept(ctx)) + v.require.NoError(v.vm.mempool.AddLocalTx(exportTx)) + + <-v.issuer + + height := v.buildAndAcceptBlockForTx(ctx, exportTx) + + v.checkAtomicTxIndexing(t, exportTx, height) + + return exportTx } -func (v *vmFixture) Teardown() { - v.require.NoError(v.VM.Shutdown(context.Background())) +func (v *vmFixture) buildAndAcceptBlockForTx(ctx context.Context, tx *Tx) uint64 { + require := v.require + + blk, err := v.vm.BuildBlock(ctx) + require.NoError(err) + + require.NoError(blk.Verify(ctx)) + require.Equal(blk.Status(), choices.Processing) + + require.NoError(v.vm.SetPreference(ctx, blk.ID())) + + require.NoError(blk.Accept(ctx)) + require.Equal(blk.Status(), choices.Accepted) + + lastAcceptedID, err := v.vm.LastAccepted(ctx) + require.NoError(err) + require.Equal(lastAcceptedID, blk.ID()) + + v.vm.blockChain.DrainAcceptorQueue() + filterAPI := filters.NewFilterAPI(filters.NewFilterSystem(v.vm.eth.APIBackend, filters.Config{ + Timeout: 5 * time.Minute, + })) + blockHash := common.Hash(blk.ID()) + logs, err := filterAPI.GetLogs(ctx, filters.FilterCriteria{ + BlockHash: &blockHash, + }) + require.NoError(err) + require.Zero(len(logs)) + + v.height += uint64(1) + return v.height +} + +func (v *vmFixture) checkAtomicTxIndexing(t require.TestingT, tx *Tx, expectedHeight uint64) { + // Check that the atomic transactions were indexed as expected. + indexedTx, status, height, err := v.vm.getAtomicTx(tx.ID()) + v.require.NoError(err) + assert.Equal(t, Accepted, status) + assert.Equal(t, expectedHeight, height, "unexpected height") + assert.Equal(t, indexedTx.ID(), tx.ID(), "expected ID of indexed tx to match original txID") } diff --git a/plugin/evm/vm.go b/plugin/evm/vm.go index 3f9341c7e7..304073d6ef 100644 --- a/plugin/evm/vm.go +++ b/plugin/evm/vm.go @@ -352,8 +352,6 @@ func (vm *VM) Clock() *mockable.Clock { return &vm.clock } // Logger implements the secp256k1fx interface func (vm *VM) Logger() logging.Logger { return vm.ctx.Log } -func (vm *VM) SnowContext() *snow.Context { return vm.ctx } - /* ****************************************************************************** ********************************* Snowman API ******************************** @@ -2047,37 +2045,3 @@ func (vm *VM) stateSyncEnabled(lastAcceptedHeight uint64) bool { // enable state sync by default if the chain is empty. return lastAcceptedHeight == 0 } - -// To be used for testing fixture -func (vm *VM) GetTxpool() *txpool.TxPool { return vm.txPool } - -func (vm *VM) GetAtomicMempool() *Mempool { return vm.mempool } - -func (vm *VM) NewImportTx(chainID ids.ID, to common.Address, baseFee *big.Int, keys []*secp256k1.PrivateKey) (*Tx, error) { - return vm.newImportTx(chainID, to, baseFee, keys) -} - -func (vm *VM) GetXChainID() ids.ID { return vm.ctx.XChainID } - -func (vm *VM) GetAVAXAssetID() ids.ID { return vm.ctx.AVAXAssetID } - -func (vm *VM) GetBlockChain() *core.BlockChain { return vm.blockChain } - -func (vm *VM) NewExportTx( - assetID ids.ID, - amount uint64, - chainID ids.ID, - to ids.ShortID, - baseFee *big.Int, - keys []*secp256k1.PrivateKey, -) (*Tx, error) { - return vm.newExportTx(assetID, amount, chainID, to, baseFee, keys) -} - -func (vm *VM) GetAtomicTx(txID ids.ID) (*Tx, Status, uint64, error) { - return vm.getAtomicTx(txID) -} - -func (vm *VM) GetAPIBackend() *eth.EthAPIBackend { - return vm.eth.APIBackend -} diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index fc62db0fe5..4a2fcf9eaf 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -5,126 +5,49 @@ package vm import ( "context" - "time" - - "github.com/ethereum/go-ethereum/common" ginkgo "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/avalanchego/snow/choices" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - "github.com/ava-labs/coreth/eth/filters" "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/plugin/evm" i9n "github.com/ava-labs/coreth/tests/integration" ) var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { - require := require.New(ginkgo.GinkgoT()) - assert := assert.New(ginkgo.GinkgoT()) - ginkgo.It("should support issuing atomic transactions", func() { importAmount := uint64(50000000) - fixture := evm.CreateVMFixture(ginkgo.GinkgoT(), map[ids.ShortID]uint64{ + + vmFixture := evm.CreateVMFixture(ginkgo.GinkgoT(), map[ids.ShortID]uint64{ i9n.TestShortIDAddrs[0]: importAmount, }) - ginkgo.DeferCleanup(func() { - fixture.Teardown() + vmFixture.Teardown() }) - // TODO: Construct the atomic transaction - // fixture.BuildAndAccept() - // Construct atomic transaction - // build and accept - // check some indices - - vm := fixture.VM - - importTx, err := vm.NewImportTx( - vm.GetXChainID(), + _ = vmFixture.IssueImportTx( + ginkgo.GinkgoT(), + context.Background(), + vmFixture.GetXChainID(), i9n.TestEthAddrs[0], i9n.InitialBaseFee, []*secp256k1.PrivateKey{i9n.TestKeys[0]}, ) - require.NoError(err) - - require.NoError(vm.GetAtomicMempool().AddLocalTx(importTx)) - - <-fixture.Issuer - - blk, err := vm.BuildBlock(context.Background()) - require.NoError(err) - - require.NoError(blk.Verify(context.Background())) - require.Equal(blk.Status(), choices.Processing) - - require.NoError(vm.SetPreference(context.Background(), blk.ID())) - err = blk.Accept(context.Background()) - require.NoError(err) - require.Equal(blk.Status(), choices.Accepted) - - lastAcceptedID, err := vm.LastAccepted(context.Background()) - require.NoError(err) - require.Equal(lastAcceptedID, blk.ID()) - vm.GetBlockChain().DrainAcceptorQueue() - filterAPI := filters.NewFilterAPI(filters.NewFilterSystem(vm.GetAPIBackend(), filters.Config{ - Timeout: 5 * time.Minute, - })) - blockHash := common.Hash(blk.ID()) - logs, err := filterAPI.GetLogs(context.Background(), filters.FilterCriteria{ - BlockHash: &blockHash, - }) - require.NoError(err) - require.Zero(len(logs)) - - exportTx, err := vm.NewExportTx( - vm.GetAVAXAssetID(), + _ = vmFixture.IssueExportTx( + ginkgo.GinkgoT(), + context.Background(), + vmFixture.GetAVAXAssetID(), importAmount-(2*params.AvalancheAtomicTxFee), - vm.GetXChainID(), + vmFixture.GetXChainID(), i9n.TestShortIDAddrs[0], i9n.InitialBaseFee, []*secp256k1.PrivateKey{ i9n.TestKeys[0], }, ) - require.NoError(err) - - require.NoError(vm.GetAtomicMempool().AddLocalTx(exportTx)) - - <-fixture.Issuer - - blk2, err := vm.BuildBlock(context.Background()) - require.NoError(err) - - require.NoError(blk2.Verify(context.Background())) - require.Equal(blk2.Status(), choices.Processing) - - require.NoError(blk2.Accept(context.Background())) - require.Equal(blk2.Status(), choices.Accepted) - - lastAcceptedID, err = vm.LastAccepted(context.Background()) - require.NoError(err) - require.Equal(lastAcceptedID, blk2.ID()) - - // Check that both atomic transactions were indexed as expected. - indexedImportTx, status, height, err := vm.GetAtomicTx(importTx.ID()) - require.NoError(err) - assert.Equal(evm.Accepted, status) - assert.Equal(uint64(1), height, "expected height of indexed import tx to be 1") - assert.Equal(indexedImportTx.ID(), importTx.ID(), "expected ID of indexed import tx to match original txID") - - indexedExportTx, status, height, err := vm.GetAtomicTx(exportTx.ID()) - require.NoError(err) - assert.Equal(evm.Accepted, status) - assert.Equal(uint64(2), height, "expected height of indexed export tx to be 2") - assert.Equal(indexedExportTx.ID(), exportTx.ID(), "expected ID of indexed import tx to match original txID") }) }) From f5b2c0dae95ffa2453f5f7637023fa68b3a51248 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 3 Nov 2023 20:23:39 +0100 Subject: [PATCH 04/39] Move all test data into the fixture --- plugin/evm/shared_test_vm_fixture.go | 55 ++++++++++++++++++--------- tests/fixture.go | 23 ----------- tests/integration/integration.go | 49 +++++++++++++++++++++--- tests/integration/integration_test.go | 22 ----------- tests/integration/vm/atomic_tx.go | 23 +++++------ 5 files changed, 90 insertions(+), 82 deletions(-) delete mode 100644 tests/fixture.go diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index b2be982b8e..a1fd7c463d 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -21,21 +21,36 @@ import ( "github.com/ava-labs/coreth/eth/filters" ) +// Arbitrarily large amount of AVAX (10^12) to fund keys on the C-Chain for testing +var DefaultFundedKeyCChainAmount = new(big.Int).Exp(big.NewInt(10), big.NewInt(30), nil) + type vmFixture struct { - require *require.Assertions - issuer chan engCommon.Message - height uint64 - vm *VM + require *require.Assertions + assert *assert.Assertions + prefundedKey *secp256k1.PrivateKey + vm *VM + issuer chan engCommon.Message + height uint64 } -func CreateVMFixture(t require.TestingT, prefundedUTXOs map[ids.ShortID]uint64) *vmFixture { +func CreateVMFixture( + t require.TestingT, +) *vmFixture { require := require.New(t) - issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", prefundedUTXOs) + prefundedKey, err := secp256k1.NewPrivateKey() + require.NoError(err) + + issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", map[ids.ShortID]uint64{ + prefundedKey.Address(): DefaultFundedKeyCChainAmount.Uint64(), + }) + return &vmFixture{ - vm: vm, - issuer: issuer, - require: require, + require: require, + assert: assert.New(t), + prefundedKey: prefundedKey, + vm: vm, + issuer: issuer, } } @@ -43,12 +58,19 @@ func (v *vmFixture) Teardown() { v.require.NoError(v.vm.Shutdown(context.Background())) } +func (v *vmFixture) AllocateFundedKey() *secp256k1.PrivateKey { + // This method supports allocation of funded keys for a shared + // test network, but for the VM instance the fixture is not + // intended to be shared so its assumed safe to return the same + // key from every call. + return v.prefundedKey +} + func (v *vmFixture) GetXChainID() ids.ID { return v.vm.ctx.XChainID } func (v *vmFixture) GetAVAXAssetID() ids.ID { return v.vm.ctx.AVAXAssetID } func (v *vmFixture) IssueImportTx( - t require.TestingT, ctx context.Context, chainID ids.ID, to common.Address, @@ -64,13 +86,12 @@ func (v *vmFixture) IssueImportTx( height := v.buildAndAcceptBlockForTx(ctx, importTx) - v.checkAtomicTxIndexing(t, importTx, height) + v.checkAtomicTxIndexing(importTx, height) return importTx } func (v *vmFixture) IssueExportTx( - t require.TestingT, ctx context.Context, assetID ids.ID, amount uint64, @@ -88,7 +109,7 @@ func (v *vmFixture) IssueExportTx( height := v.buildAndAcceptBlockForTx(ctx, exportTx) - v.checkAtomicTxIndexing(t, exportTx, height) + v.checkAtomicTxIndexing(exportTx, height) return exportTx } @@ -126,11 +147,11 @@ func (v *vmFixture) buildAndAcceptBlockForTx(ctx context.Context, tx *Tx) uint64 return v.height } -func (v *vmFixture) checkAtomicTxIndexing(t require.TestingT, tx *Tx, expectedHeight uint64) { +func (v *vmFixture) checkAtomicTxIndexing(tx *Tx, expectedHeight uint64) { // Check that the atomic transactions were indexed as expected. indexedTx, status, height, err := v.vm.getAtomicTx(tx.ID()) v.require.NoError(err) - assert.Equal(t, Accepted, status) - assert.Equal(t, expectedHeight, height, "unexpected height") - assert.Equal(t, indexedTx.ID(), tx.ID(), "expected ID of indexed tx to match original txID") + v.assert.Equal(Accepted, status) + v.assert.Equal(expectedHeight, height, "unexpected height") + v.assert.Equal(indexedTx.ID(), tx.ID(), "expected ID of indexed tx to match original txID") } diff --git a/tests/fixture.go b/tests/fixture.go deleted file mode 100644 index 587ee955e3..0000000000 --- a/tests/fixture.go +++ /dev/null @@ -1,23 +0,0 @@ -// (c) 2023, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -package tests - -import ( - "github.com/ava-labs/coreth/core/types" - "github.com/ava-labs/coreth/plugin/evm" -) - -type IntegrationFixture interface { - IssueTxs(txs []*types.Transaction) - IssueAtomicTxs(atomicTxs []*evm.Tx) - - BuildAndAccept() - - Teardown() - // ConfirmTxs(txs []*types.Transaction) - // ConfirmAtomicTxs(atomicTxs []*evm.Tx) - - // Define index getter functions - // GetTxReceipt(txHash common.Hash) *types.Receipt -} diff --git a/tests/integration/integration.go b/tests/integration/integration.go index bbada50cac..1313a5fd78 100644 --- a/tests/integration/integration.go +++ b/tests/integration/integration.go @@ -4,22 +4,59 @@ package integration import ( + "context" "math/big" "github.com/ethereum/go-ethereum/common" + ginkgo "github.com/onsi/ginkgo/v2" + "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/plugin/evm" ) var ( InitialBaseFee = big.NewInt(params.ApricotPhase3InitialBaseFee) - - // Will be initialized by BeforeSuite - // TODO(marun) Maybe supply with a test env as per avalanchego's example? - TestKeys []*secp256k1.PrivateKey - TestEthAddrs []common.Address // testEthAddrs[i] corresponds to testKeys[i] - TestShortIDAddrs []ids.ShortID ) + +type IntegrationFixture interface { + AllocateFundedKey() *secp256k1.PrivateKey + + GetXChainID() ids.ID + + GetAVAXAssetID() ids.ID + + IssueImportTx( + ctx context.Context, + chainID ids.ID, + to common.Address, + baseFee *big.Int, + keys []*secp256k1.PrivateKey, + ) *evm.Tx + + IssueExportTx( + ctx context.Context, + assetID ids.ID, + amount uint64, + chainID ids.ID, + to ids.ShortID, + baseFee *big.Int, + keys []*secp256k1.PrivateKey, + ) *evm.Tx + + Teardown() +} + +func NewIntegrationFixture() IntegrationFixture { + // TODO(marun) Support use of testnet fixture + + vmFixture := evm.CreateVMFixture(ginkgo.GinkgoT()) + ginkgo.DeferCleanup(func() { + vmFixture.Teardown() + }) + + return vmFixture +} diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 2f26e781ad..bebbadd176 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -10,12 +10,6 @@ import ( "github.com/onsi/gomega" - "github.com/ava-labs/avalanchego/utils/cb58" - "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - - "github.com/ava-labs/coreth/plugin/evm" - i9n "github.com/ava-labs/coreth/tests/integration" - // ensure test packages are scanned by ginkgo _ "github.com/ava-labs/coreth/tests/integration/vm" ) @@ -24,19 +18,3 @@ func TestE2E(t *testing.T) { gomega.RegisterFailHandler(ginkgo.Fail) ginkgo.RunSpecs(t, "Coreth EVM Integration Tests") } - -var _ = ginkgo.BeforeSuite(func() { - var b []byte - - for _, key := range []string{ - "24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5", - "2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY", - "cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35", - } { - b, _ = cb58.Decode(key) - pk, _ := secp256k1.ToPrivateKey(b) - i9n.TestKeys = append(i9n.TestKeys, pk) - i9n.TestEthAddrs = append(i9n.TestEthAddrs, evm.GetEthAddress(pk)) - i9n.TestShortIDAddrs = append(i9n.TestShortIDAddrs, pk.PublicKey().Address()) - } -}) diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index 4a2fcf9eaf..1e7b8b0eec 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -8,7 +8,6 @@ import ( ginkgo "github.com/onsi/ginkgo/v2" - "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/coreth/params" @@ -18,34 +17,30 @@ import ( var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { ginkgo.It("should support issuing atomic transactions", func() { - importAmount := uint64(50000000) + vmFixture := i9n.NewIntegrationFixture() - vmFixture := evm.CreateVMFixture(ginkgo.GinkgoT(), map[ids.ShortID]uint64{ - i9n.TestShortIDAddrs[0]: importAmount, - }) - ginkgo.DeferCleanup(func() { - vmFixture.Teardown() - }) + key := vmFixture.AllocateFundedKey() + importAmount := uint64(50000000) _ = vmFixture.IssueImportTx( - ginkgo.GinkgoT(), context.Background(), vmFixture.GetXChainID(), - i9n.TestEthAddrs[0], + evm.GetEthAddress(key), i9n.InitialBaseFee, - []*secp256k1.PrivateKey{i9n.TestKeys[0]}, + []*secp256k1.PrivateKey{ + key, + }, ) _ = vmFixture.IssueExportTx( - ginkgo.GinkgoT(), context.Background(), vmFixture.GetAVAXAssetID(), importAmount-(2*params.AvalancheAtomicTxFee), vmFixture.GetXChainID(), - i9n.TestShortIDAddrs[0], + key.Address(), i9n.InitialBaseFee, []*secp256k1.PrivateKey{ - i9n.TestKeys[0], + key, }, ) }) From 5bb73ccd106299006daab62c7fd02b18473fd073 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 3 Nov 2023 20:34:33 +0100 Subject: [PATCH 05/39] Enable running as part of regular test suite --- .github/workflows/ci.yml | 2 ++ scripts/tests.integration.sh | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100755 scripts/tests.integration.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d0e78d16b..ac4406d40e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,6 +81,8 @@ jobs: shell: bash - run: ./scripts/build_test.sh shell: bash + - run: ./scripts/tests.integration.sh + shell: bash - run: ./scripts/coverage.sh shell: bash test-race: diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh new file mode 100755 index 0000000000..d4bfaff06a --- /dev/null +++ b/scripts/tests.integration.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# e.g., +# ./scripts/tests.integration.sh +# ./scripts/tests.e2e.sh --ginkgo.label-filter=x # All arguments are supplied to gi +if ! [[ "$0" =~ scripts/tests.integration.sh ]]; then + echo "must be run from repository root" + exit 255 +fi + +echo "building integration.test" +# Install the ginkgo binary (required for test build and run) +go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.1.4 +ACK_GINKGO_RC=true ginkgo build ./tests/integration +./tests/integration/integration.test --help + +# Execute in random order to identify unwanted dependency +ginkgo -v --randomize-all ./tests/integration/integration.test -- "${@}" From e9b843ffc3c7384b1ff3a4dc3ece26040e6feb03 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 3 Nov 2023 20:37:40 +0100 Subject: [PATCH 06/39] Remove redundant TestIssueAtomicTxs unit test --- plugin/evm/vm_test.go | 129 ------------------------------------------ 1 file changed, 129 deletions(-) diff --git a/plugin/evm/vm_test.go b/plugin/evm/vm_test.go index 6d79109f7b..f07db8cffa 100644 --- a/plugin/evm/vm_test.go +++ b/plugin/evm/vm_test.go @@ -22,7 +22,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" - "github.com/ava-labs/coreth/eth/filters" "github.com/ava-labs/coreth/internal/ethapi" "github.com/ava-labs/coreth/metrics" "github.com/ava-labs/coreth/plugin/evm/message" @@ -33,9 +32,6 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/chains/atomic" - "github.com/ava-labs/avalanchego/database" - "github.com/ava-labs/avalanchego/database/memdb" - "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow/choices" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" @@ -439,131 +435,6 @@ func TestImportMissingUTXOs(t *testing.T) { require.Len(t, badBlocks, 0) } -// Simple test to ensure we can issue an import transaction followed by an export transaction -// and they will be indexed correctly when accepted. -func TestIssueAtomicTxs(t *testing.T) { - importAmount := uint64(50000000) - issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", map[ids.ShortID]uint64{ - testShortIDAddrs[0]: importAmount, - }) - - defer func() { - if err := vm.Shutdown(context.Background()); err != nil { - t.Fatal(err) - } - }() - - importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]}) - if err != nil { - t.Fatal(err) - } - - if err := vm.mempool.AddLocalTx(importTx); err != nil { - t.Fatal(err) - } - - <-issuer - - blk, err := vm.BuildBlock(context.Background()) - if err != nil { - t.Fatal(err) - } - - if err := blk.Verify(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk.Status(); status != choices.Processing { - t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status) - } - - if err := vm.SetPreference(context.Background(), blk.ID()); err != nil { - t.Fatal(err) - } - - if err := blk.Accept(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk.Status(); status != choices.Accepted { - t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status) - } - - if lastAcceptedID, err := vm.LastAccepted(context.Background()); err != nil { - t.Fatal(err) - } else if lastAcceptedID != blk.ID() { - t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID) - } - vm.blockChain.DrainAcceptorQueue() - filterAPI := filters.NewFilterAPI(filters.NewFilterSystem(vm.eth.APIBackend, filters.Config{ - Timeout: 5 * time.Minute, - })) - blockHash := common.Hash(blk.ID()) - logs, err := filterAPI.GetLogs(context.Background(), filters.FilterCriteria{ - BlockHash: &blockHash, - }) - if err != nil { - t.Fatal(err) - } - if len(logs) != 0 { - t.Fatalf("Expected log length to be 0, but found %d", len(logs)) - } - if logs == nil { - t.Fatal("Expected logs to be non-nil") - } - - exportTx, err := vm.newExportTx(vm.ctx.AVAXAssetID, importAmount-(2*params.AvalancheAtomicTxFee), vm.ctx.XChainID, testShortIDAddrs[0], initialBaseFee, []*secp256k1.PrivateKey{testKeys[0]}) - if err != nil { - t.Fatal(err) - } - - if err := vm.mempool.AddLocalTx(exportTx); err != nil { - t.Fatal(err) - } - - <-issuer - - blk2, err := vm.BuildBlock(context.Background()) - if err != nil { - t.Fatal(err) - } - - if err := blk2.Verify(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk2.Status(); status != choices.Processing { - t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status) - } - - if err := blk2.Accept(context.Background()); err != nil { - t.Fatal(err) - } - - if status := blk2.Status(); status != choices.Accepted { - t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status) - } - - if lastAcceptedID, err := vm.LastAccepted(context.Background()); err != nil { - t.Fatal(err) - } else if lastAcceptedID != blk2.ID() { - t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk2.ID(), lastAcceptedID) - } - - // Check that both atomic transactions were indexed as expected. - indexedImportTx, status, height, err := vm.getAtomicTx(importTx.ID()) - assert.NoError(t, err) - assert.Equal(t, Accepted, status) - assert.Equal(t, uint64(1), height, "expected height of indexed import tx to be 1") - assert.Equal(t, indexedImportTx.ID(), importTx.ID(), "expected ID of indexed import tx to match original txID") - - indexedExportTx, status, height, err := vm.getAtomicTx(exportTx.ID()) - assert.NoError(t, err) - assert.Equal(t, Accepted, status) - assert.Equal(t, uint64(2), height, "expected height of indexed export tx to be 2") - assert.Equal(t, indexedExportTx.ID(), exportTx.ID(), "expected ID of indexed import tx to match original txID") -} - func TestBuildEthTxBlock(t *testing.T) { importAmount := uint64(20000000) issuer, vm, dbManager, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "{\"pruning-enabled\":true}", "", map[ids.ShortID]uint64{ From 4f8e818db1778fd797a6d7660dadc5541e206adf Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 3 Nov 2023 20:55:17 +0100 Subject: [PATCH 07/39] Fix doc comment in integration test script --- scripts/tests.integration.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index d4bfaff06a..d404ca33f3 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -4,7 +4,7 @@ set -euo pipefail # e.g., # ./scripts/tests.integration.sh -# ./scripts/tests.e2e.sh --ginkgo.label-filter=x # All arguments are supplied to gi +# ./scripts/tests.integration.sh --ginkgo.label-filter=x # All arguments are supplied to ginkgo if ! [[ "$0" =~ scripts/tests.integration.sh ]]; then echo "must be run from repository root" exit 255 From 92ac20ac83ef23fe11ba8c7892e28d189846cbaf Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 6 Nov 2023 20:38:31 +0100 Subject: [PATCH 08/39] Add shared network fixture --- plugin/evm/shared_test_vm_fixture.go | 17 +- tests/integration/integration.go | 30 ++-- tests/integration/integration_test.go | 34 ++++ tests/integration/shared_network_fixture.go | 164 ++++++++++++++++++++ tests/integration/vm/atomic_tx.go | 19 +-- 5 files changed, 226 insertions(+), 38 deletions(-) create mode 100644 tests/integration/shared_network_fixture.go diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index a1fd7c463d..18a83c88fa 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -33,9 +33,7 @@ type vmFixture struct { height uint64 } -func CreateVMFixture( - t require.TestingT, -) *vmFixture { +func CreateVMFixture(t require.TestingT) *vmFixture { require := require.New(t) prefundedKey, err := secp256k1.NewPrivateKey() @@ -58,11 +56,7 @@ func (v *vmFixture) Teardown() { v.require.NoError(v.vm.Shutdown(context.Background())) } -func (v *vmFixture) AllocateFundedKey() *secp256k1.PrivateKey { - // This method supports allocation of funded keys for a shared - // test network, but for the VM instance the fixture is not - // intended to be shared so its assumed safe to return the same - // key from every call. +func (v *vmFixture) GetPrefundedKey() *secp256k1.PrivateKey { return v.prefundedKey } @@ -71,8 +65,8 @@ func (v *vmFixture) GetXChainID() ids.ID { return v.vm.ctx.XChainID } func (v *vmFixture) GetAVAXAssetID() ids.ID { return v.vm.ctx.AVAXAssetID } func (v *vmFixture) IssueImportTx( - ctx context.Context, chainID ids.ID, + amount uint64, // Ignored - all available funds will be imported to common.Address, baseFee *big.Int, keys []*secp256k1.PrivateKey, @@ -84,7 +78,7 @@ func (v *vmFixture) IssueImportTx( <-v.issuer - height := v.buildAndAcceptBlockForTx(ctx, importTx) + height := v.buildAndAcceptBlockForTx(context.Background(), importTx) v.checkAtomicTxIndexing(importTx, height) @@ -92,7 +86,6 @@ func (v *vmFixture) IssueImportTx( } func (v *vmFixture) IssueExportTx( - ctx context.Context, assetID ids.ID, amount uint64, chainID ids.ID, @@ -107,7 +100,7 @@ func (v *vmFixture) IssueExportTx( <-v.issuer - height := v.buildAndAcceptBlockForTx(ctx, exportTx) + height := v.buildAndAcceptBlockForTx(context.Background(), exportTx) v.checkAtomicTxIndexing(exportTx, height) diff --git a/tests/integration/integration.go b/tests/integration/integration.go index 1313a5fd78..8ea6fca726 100644 --- a/tests/integration/integration.go +++ b/tests/integration/integration.go @@ -4,7 +4,6 @@ package integration import ( - "context" "math/big" "github.com/ethereum/go-ethereum/common" @@ -12,6 +11,7 @@ import ( ginkgo "github.com/onsi/ginkgo/v2" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/coreth/params" @@ -23,22 +23,21 @@ var ( ) type IntegrationFixture interface { - AllocateFundedKey() *secp256k1.PrivateKey + GetPrefundedKey() *secp256k1.PrivateKey GetXChainID() ids.ID GetAVAXAssetID() ids.ID IssueImportTx( - ctx context.Context, chainID ids.ID, + amount uint64, to common.Address, baseFee *big.Int, keys []*secp256k1.PrivateKey, ) *evm.Tx IssueExportTx( - ctx context.Context, assetID ids.ID, amount uint64, chainID ids.ID, @@ -46,17 +45,18 @@ type IntegrationFixture interface { baseFee *big.Int, keys []*secp256k1.PrivateKey, ) *evm.Tx - - Teardown() } -func NewIntegrationFixture() IntegrationFixture { - // TODO(marun) Support use of testnet fixture - - vmFixture := evm.CreateVMFixture(ginkgo.GinkgoT()) - ginkgo.DeferCleanup(func() { - vmFixture.Teardown() - }) - - return vmFixture +func GetFixture() IntegrationFixture { + if e2e.Env == nil { + // Shared network fixture not initialized, return a fresh vm fixture + vmFixture := evm.CreateVMFixture(ginkgo.GinkgoT()) + ginkgo.DeferCleanup(func() { + vmFixture.Teardown() + }) + return vmFixture + } + + // e2e.Env being non-nil indicates the use of a shared network fixture + return newSharedNetworkFixture(ginkgo.GinkgoT()) } diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index bebbadd176..b3dad8d295 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -4,12 +4,15 @@ package integration_test import ( + "flag" "testing" ginkgo "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" + "github.com/ava-labs/avalanchego/tests/fixture/e2e" + // ensure test packages are scanned by ginkgo _ "github.com/ava-labs/coreth/tests/integration/vm" ) @@ -18,3 +21,34 @@ func TestE2E(t *testing.T) { gomega.RegisterFailHandler(ginkgo.Fail) ginkgo.RunSpecs(t, "Coreth EVM Integration Tests") } + +var ( + flagVars *e2e.FlagVars + + useNetworkFixture bool +) + +func init() { + flagVars = e2e.RegisterFlags() + flag.BoolVar( + &useNetworkFixture, + "use-network-fixture", + false, + "[optional] whether to target a network fixture. By default a lighter-weight vm fixture will be used.", + ) +} + +var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { + if useNetworkFixture { + // Run only once in the first ginkgo process + return e2e.NewTestEnvironment(flagVars).Marshal() + } + return nil +}, func(envBytes []byte) { + // Run in every ginkgo process + + // Initialize the local test environment from the global state + if len(envBytes) > 0 { + e2e.InitSharedTestEnvironment(envBytes) + } +}) diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go new file mode 100644 index 0000000000..e1a6e234c2 --- /dev/null +++ b/tests/integration/shared_network_fixture.go @@ -0,0 +1,164 @@ +// (c) 2023, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package integration + +import ( + "math/big" + + ethcommon "github.com/ethereum/go-ethereum/common" + + ginkgo "github.com/onsi/ginkgo/v2" + + "github.com/stretchr/testify/require" + + "github.com/ava-labs/avalanchego/api/info" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/tests/fixture/e2e" + "github.com/ava-labs/avalanchego/tests/fixture/testnet" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/vms/avm" + "github.com/ava-labs/avalanchego/vms/components/avax" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/subnet/primary" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" + + "github.com/ava-labs/coreth/plugin/evm" +) + +// Shared network implementation of IntegrationFixture +type sharedNetworkFixture struct { + // The URI of the only node the fixture is intended to communciate with + nodeURI testnet.NodeURI + + // Wallet to perform transactions + baseWallet primary.Wallet + + // Prefunded key used to configure the wallet + prefundedKey *secp256k1.PrivateKey + + require *require.Assertions +} + +func newSharedNetworkFixture(t require.TestingT) *sharedNetworkFixture { + nodeURI := e2e.Env.GetRandomNodeURI() + keychain := e2e.Env.NewKeychain(1) + return &sharedNetworkFixture{ + nodeURI: nodeURI, + baseWallet: e2e.NewWallet(keychain, nodeURI), + prefundedKey: keychain.Keys[0], + require: require.New(t), + } +} + +func (f *sharedNetworkFixture) GetPrefundedKey() *secp256k1.PrivateKey { + return f.prefundedKey +} + +func (f *sharedNetworkFixture) GetXChainID() ids.ID { + id, err := info.NewClient(f.nodeURI.URI).GetBlockchainID(e2e.DefaultContext(), "X") + f.require.NoError(err) + return id +} + +func (f *sharedNetworkFixture) GetAVAXAssetID() ids.ID { + asset, err := avm.NewClient(f.nodeURI.URI, "X").GetAssetDescription(e2e.DefaultContext(), "AVAX") + f.require.NoError(err) + return asset.AssetID +} + +func (f *sharedNetworkFixture) IssueImportTx( + chainID ids.ID, + amount uint64, + to ethcommon.Address, + baseFee *big.Int, + keys []*secp256k1.PrivateKey, +) *evm.Tx { + addresses := make([]ids.ShortID, len(keys)) + for i, key := range keys { + addresses[i] = key.Address() + } + + // TODO(marun) Ensure this message accurately reflects the recipient chain + ginkgo.By("exporting AVAX from the X-Chain to the C-Chain") + _, err := f.baseWallet.X().IssueExportTx( + f.baseWallet.C().BlockchainID(), + []*avax.TransferableOutput{ + { + Asset: avax.Asset{ + ID: f.GetAVAXAssetID(), + }, + Out: &secp256k1fx.TransferOutput{ + Amt: amount, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: addresses, + }, + }, + }, + }, + e2e.WithDefaultContext(), + ) + f.require.NoError(err) + + // TODO(marun) Ensure this message accurately reflects the recipient chain + ginkgo.By("importing AVAX from the X-Chain to the C-Chain") + tx, err := f.baseWallet.C().IssueImportTx( + chainID, + to, + e2e.WithDefaultContext(), + common.WithBaseFee(baseFee), + ) + f.require.NoError(err) + + // TODO(marun) verify result + + return tx +} + +func (f *sharedNetworkFixture) IssueExportTx( + _ ids.ID, // Ignored - wallet will determine correct asset id + amount uint64, + chainID ids.ID, + to ids.ShortID, + baseFee *big.Int, + keys []*secp256k1.PrivateKey, // Ignored - prefunded key will be used +) *evm.Tx { + // TODO(marun) Ensure this message accurately reflects the recipient chain + ginkgo.By("exporting AVAX from the C-Chain to the X-Chain") + tx, err := f.baseWallet.C().IssueExportTx( + chainID, + []*secp256k1fx.TransferOutput{ + { + Amt: amount, + OutputOwners: secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + f.prefundedKey.Address(), + }, + }, + }, + }, + e2e.WithDefaultContext(), + common.WithBaseFee(baseFee), + ) + f.require.NoError(err) + + // TODO(marun) Ensure this message accurately reflects the recipient chain + ginkgo.By("importing AVAX from the C-Chain to the X-Chain") + _, err = f.baseWallet.X().IssueImportTx( + f.baseWallet.C().BlockchainID(), + &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{ + to, + }, + }, + e2e.WithDefaultContext(), + ) + f.require.NoError(err) + + // TODO(marun) verify result + + return tx +} diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index 1e7b8b0eec..563f022c71 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -4,8 +4,6 @@ package vm import ( - "context" - ginkgo "github.com/onsi/ginkgo/v2" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" @@ -17,14 +15,14 @@ import ( var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { ginkgo.It("should support issuing atomic transactions", func() { - vmFixture := i9n.NewIntegrationFixture() + f := i9n.GetFixture() - key := vmFixture.AllocateFundedKey() + key := f.GetPrefundedKey() importAmount := uint64(50000000) - _ = vmFixture.IssueImportTx( - context.Background(), - vmFixture.GetXChainID(), + _ = f.IssueImportTx( + f.GetXChainID(), + importAmount, evm.GetEthAddress(key), i9n.InitialBaseFee, []*secp256k1.PrivateKey{ @@ -32,11 +30,10 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { }, ) - _ = vmFixture.IssueExportTx( - context.Background(), - vmFixture.GetAVAXAssetID(), + _ = f.IssueExportTx( + f.GetAVAXAssetID(), importAmount-(2*params.AvalancheAtomicTxFee), - vmFixture.GetXChainID(), + f.GetXChainID(), key.Address(), i9n.InitialBaseFee, []*secp256k1.PrivateKey{ From 98edbb40be7c64e0132a5751dfe0e836d76870c4 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 6 Nov 2023 20:39:46 +0100 Subject: [PATCH 09/39] Add integration test workflow with network fixture --- .github/workflows/ci.yml | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac4406d40e..c30984d7fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,6 +116,36 @@ jobs: shell: bash - run: ./scripts/build_test.sh -race shell: bash + integration: + name: Coreth EVM Integration Tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-20.04 ] + steps: + - uses: actions/checkout@v3 + - name: check out ${{ github.event.inputs.avalanchegoRepo }} ${{ github.event.inputs.avalanchegoBranch }} + if: ${{ github.event_name == 'workflow_dispatch' }} + uses: actions/checkout@v3 + with: + repository: ${{ github.event.inputs.avalanchegoRepo }} + ref: ${{ github.event.inputs.avalanchegoBranch }} + path: avalanchego + token: ${{ secrets.AVALANCHE_PAT }} + - uses: actions/setup-go@v3 + with: + go-version: '~1.20.8' + check-latest: true + - name: Run integration tests + run: ./scripts/tests.integration.sh --use-network-fixture + shell: bash + - name: Upload tmpnet network dir + uses: actions/upload-artifact@v3 + if: always() + with: + name: tmpnet-integration-data + path: ~/.tmpnet/networks/1000 + avalanchego_e2e: name: AvalancheGo E2E Tests v${{ matrix.go }} (${{ matrix.os }}) runs-on: ${{ matrix.os }} @@ -143,5 +173,5 @@ jobs: uses: actions/upload-artifact@v4 if: always() with: - name: tmpnet-data + name: tmpnet-e2e-data path: ~/.tmpnet/networks/1000 From 0c2c973432115342d63a1a92b8e5d778a1183286 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 6 Nov 2023 20:58:40 +0100 Subject: [PATCH 10/39] Fix lint error --- tests/integration/shared_network_fixture.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index e1a6e234c2..b90c89c806 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -28,7 +28,7 @@ import ( // Shared network implementation of IntegrationFixture type sharedNetworkFixture struct { - // The URI of the only node the fixture is intended to communciate with + // The URI of the only node the fixture is intended to communicate with nodeURI testnet.NodeURI // Wallet to perform transactions From a97454705d5e70c5dd9b5a96d930d5cc97bad3ca Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 6 Nov 2023 21:11:02 +0100 Subject: [PATCH 11/39] Fix integration test workflow to build avalanchego --- scripts/build_avalanchego.sh | 48 ++++++++++++++++++++++++++++++++++++ scripts/tests.e2e.sh | 35 +------------------------- scripts/tests.integration.sh | 8 ++++++ 3 files changed, 57 insertions(+), 34 deletions(-) create mode 100755 scripts/build_avalanchego.sh diff --git a/scripts/build_avalanchego.sh b/scripts/build_avalanchego.sh new file mode 100755 index 0000000000..2a91b63dc0 --- /dev/null +++ b/scripts/build_avalanchego.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Run AvalancheGo e2e tests from the target version against the current state of coreth. + +# e.g., +# ./scripts/build_avalanchego.sh +# AVALANCHE_VERSION=v1.10.x ./scripts/build_avalanchego.sh +if ! [[ "$0" =~ scripts/build_avalanchego.sh ]]; then + echo "must be run from repository root" + exit 255 +fi + +# Coreth root directory +CORETH_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd ) + +# Allow configuring the clone path to point to an existing clone +AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" + +# Load the version +source "$CORETH_PATH"/scripts/versions.sh + +# Always return to the coreth path on exit +function cleanup { + cd "${CORETH_PATH}" +} +trap cleanup EXIT + +echo "checking out target AvalancheGo version ${avalanche_version}" +if [[ -d "${AVALANCHEGO_CLONE_PATH}" ]]; then + echo "updating existing clone" + cd "${AVALANCHEGO_CLONE_PATH}" + git fetch +else + echo "creating new clone" + git clone https://github.com/ava-labs/avalanchego.git "${AVALANCHEGO_CLONE_PATH}" + cd "${AVALANCHEGO_CLONE_PATH}" +fi +# Branch will be reset to $avalanche_version if it already exists +git checkout -B "test-${avalanche_version}" "${avalanche_version}" + +echo "updating coreth dependency to point to ${CORETH_PATH}" +go mod edit -replace "github.com/ava-labs/coreth=${CORETH_PATH}" +go mod tidy + +echo "building avalanchego" +./scripts/build.sh -r diff --git a/scripts/tests.e2e.sh b/scripts/tests.e2e.sh index b7530503c7..345efbd8fc 100755 --- a/scripts/tests.e2e.sh +++ b/scripts/tests.e2e.sh @@ -12,40 +12,7 @@ if ! [[ "$0" =~ scripts/tests.e2e.sh ]]; then exit 255 fi -# Coreth root directory -CORETH_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd ) - -# Allow configuring the clone path to point to an existing clone -AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" - -# Load the version -source "$CORETH_PATH"/scripts/versions.sh - -# Always return to the coreth path on exit -function cleanup { - cd "${CORETH_PATH}" -} -trap cleanup EXIT - -echo "checking out target AvalancheGo version ${avalanche_version}" -if [[ -d "${AVALANCHEGO_CLONE_PATH}" ]]; then - echo "updating existing clone" - cd "${AVALANCHEGO_CLONE_PATH}" - git fetch -else - echo "creating new clone" - git clone https://github.com/ava-labs/avalanchego.git "${AVALANCHEGO_CLONE_PATH}" - cd "${AVALANCHEGO_CLONE_PATH}" -fi -# Branch will be reset to $avalanche_version if it already exists -git checkout -B "test-${avalanche_version}" "${avalanche_version}" - -echo "updating coreth dependency to point to ${CORETH_PATH}" -go mod edit -replace "github.com/ava-labs/coreth=${CORETH_PATH}" -go mod tidy - -echo "building avalanchego" -./scripts/build.sh -r +./scripts/build_avalanchego.sh echo "running AvalancheGo e2e tests" E2E_SERIAL=1 ./scripts/tests.e2e.sh --ginkgo.label-filter='c || uses-c' diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index d404ca33f3..475d2afced 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -2,6 +2,8 @@ set -euo pipefail +# Run Coreth EVM integration tests against the target version of AvalancheGo + # e.g., # ./scripts/tests.integration.sh # ./scripts/tests.integration.sh --ginkgo.label-filter=x # All arguments are supplied to ginkgo @@ -16,5 +18,11 @@ go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.1.4 ACK_GINKGO_RC=true ginkgo build ./tests/integration ./tests/integration/integration.test --help +# Only build avalanchego if using the network fixture +if [[ "${@}" =~ "--use-network-fixture" ]]; then + ./scripts/build_avalanchego.sh + AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-./avalanchego/build/avalanchego})" +fi + # Execute in random order to identify unwanted dependency ginkgo -v --randomize-all ./tests/integration/integration.test -- "${@}" From e6e2d319ca58bf789bf96f7317db222788ca5fe6 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 6 Nov 2023 21:35:33 +0100 Subject: [PATCH 12/39] Ensure e2e and integration jobs use the right avalanchego binary --- scripts/build_avalanchego.sh | 3 --- scripts/tests.e2e.sh | 11 +++++++++++ scripts/tests.integration.sh | 5 ++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/scripts/build_avalanchego.sh b/scripts/build_avalanchego.sh index 2a91b63dc0..1b6e443b94 100755 --- a/scripts/build_avalanchego.sh +++ b/scripts/build_avalanchego.sh @@ -15,9 +15,6 @@ fi # Coreth root directory CORETH_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd ) -# Allow configuring the clone path to point to an existing clone -AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" - # Load the version source "$CORETH_PATH"/scripts/versions.sh diff --git a/scripts/tests.e2e.sh b/scripts/tests.e2e.sh index 345efbd8fc..6e973a5919 100755 --- a/scripts/tests.e2e.sh +++ b/scripts/tests.e2e.sh @@ -12,7 +12,18 @@ if ! [[ "$0" =~ scripts/tests.e2e.sh ]]; then exit 255 fi +# Allow configuring the clone path to point to an existing clone +export AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" + ./scripts/build_avalanchego.sh +# Always return to the coreth path on exit +CORETH_PATH="$(echo "${PWD}")" +function cleanup { + cd "${CORETH_PATH}" +} +trap cleanup EXIT + echo "running AvalancheGo e2e tests" +cd "${AVALANCHEGO_CLONE_PATH}" E2E_SERIAL=1 ./scripts/tests.e2e.sh --ginkgo.label-filter='c || uses-c' diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index 475d2afced..a9c4222f90 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -12,6 +12,9 @@ if ! [[ "$0" =~ scripts/tests.integration.sh ]]; then exit 255 fi +# Allow configuring the clone path to point to an existing clone +export AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" + echo "building integration.test" # Install the ginkgo binary (required for test build and run) go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.1.4 @@ -21,7 +24,7 @@ ACK_GINKGO_RC=true ginkgo build ./tests/integration # Only build avalanchego if using the network fixture if [[ "${@}" =~ "--use-network-fixture" ]]; then ./scripts/build_avalanchego.sh - AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-./avalanchego/build/avalanchego})" + AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego})" fi # Execute in random order to identify unwanted dependency From 834c07b0c58f669a2fe67a5e02099c4d45ad1487 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 6 Nov 2023 22:10:36 +0100 Subject: [PATCH 13/39] Try to ensure integration job picks the intended avalanchego path --- scripts/tests.integration.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index a9c4222f90..3e15cc683e 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -24,7 +24,7 @@ ACK_GINKGO_RC=true ginkgo build ./tests/integration # Only build avalanchego if using the network fixture if [[ "${@}" =~ "--use-network-fixture" ]]; then ./scripts/build_avalanchego.sh - AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego})" + export AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego})" fi # Execute in random order to identify unwanted dependency From bc15cbd0dffc8d901a80c1cdb4286fa13c55e59b Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 6 Nov 2023 22:20:09 +0100 Subject: [PATCH 14/39] Rename integration job --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c30984d7fe..a0c2b558eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,7 +117,7 @@ jobs: - run: ./scripts/build_test.sh -race shell: bash integration: - name: Coreth EVM Integration Tests + name: Integration Tests runs-on: ${{ matrix.os }} strategy: matrix: From d35d292ce5b6f628409115bcdeefe12196a1a30a Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Tue, 7 Nov 2023 16:37:55 +0100 Subject: [PATCH 15/39] Minor cleanup to test scripts --- scripts/build_avalanchego.sh | 2 +- scripts/tests.integration.sh | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/build_avalanchego.sh b/scripts/build_avalanchego.sh index 1b6e443b94..2da5db1959 100755 --- a/scripts/build_avalanchego.sh +++ b/scripts/build_avalanchego.sh @@ -2,7 +2,7 @@ set -euo pipefail -# Run AvalancheGo e2e tests from the target version against the current state of coreth. +# Build avalanchego binary from the target version against the current state of coreth. # e.g., # ./scripts/build_avalanchego.sh diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index 3e15cc683e..ec17615cf9 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -15,17 +15,17 @@ fi # Allow configuring the clone path to point to an existing clone export AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" -echo "building integration.test" -# Install the ginkgo binary (required for test build and run) -go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.1.4 -ACK_GINKGO_RC=true ginkgo build ./tests/integration -./tests/integration/integration.test --help - # Only build avalanchego if using the network fixture if [[ "${@}" =~ "--use-network-fixture" ]]; then ./scripts/build_avalanchego.sh export AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego})" fi +echo "building integration.test" +# Install the ginkgo binary (required for test build and run) +go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.1.4 +ACK_GINKGO_RC=true ginkgo build ./tests/integration +./tests/integration/integration.test --help + # Execute in random order to identify unwanted dependency ginkgo -v --randomize-all ./tests/integration/integration.test -- "${@}" From 246dd8d7a22d31810907d946d6b2a5a4c7854a91 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 8 Nov 2023 14:16:34 +0100 Subject: [PATCH 16/39] Use dynamic gas price for shared network atomic tx test and verify xfers --- plugin/evm/shared_test_vm_fixture.go | 24 ++++-- tests/integration/integration.go | 9 --- tests/integration/shared_network_fixture.go | 88 ++++++++++++--------- tests/integration/vm/atomic_tx.go | 15 ++-- 4 files changed, 76 insertions(+), 60 deletions(-) diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index 18a83c88fa..5773ade0c5 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -10,6 +10,8 @@ import ( "github.com/ethereum/go-ethereum/common" + ginkgo "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,8 +23,10 @@ import ( "github.com/ava-labs/coreth/eth/filters" ) -// Arbitrarily large amount of AVAX (10^12) to fund keys on the C-Chain for testing -var DefaultFundedKeyCChainAmount = new(big.Int).Exp(big.NewInt(10), big.NewInt(30), nil) +var ( + // Arbitrarily large amount of AVAX (10^12) to fund keys on the C-Chain for testing + defaultFundedKeyCChainAmount = new(big.Int).Exp(big.NewInt(10), big.NewInt(30), nil) +) type vmFixture struct { require *require.Assertions @@ -40,7 +44,7 @@ func CreateVMFixture(t require.TestingT) *vmFixture { require.NoError(err) issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", map[ids.ShortID]uint64{ - prefundedKey.Address(): DefaultFundedKeyCChainAmount.Uint64(), + prefundedKey.Address(): defaultFundedKeyCChainAmount.Uint64(), }) return &vmFixture{ @@ -66,12 +70,14 @@ func (v *vmFixture) GetAVAXAssetID() ids.ID { return v.vm.ctx.AVAXAssetID } func (v *vmFixture) IssueImportTx( chainID ids.ID, - amount uint64, // Ignored - all available funds will be imported + _ uint64, // amount is ignored - all available funds will be imported to common.Address, - baseFee *big.Int, keys []*secp256k1.PrivateKey, ) *Tx { - importTx, err := v.vm.newImportTx(chainID, to, baseFee, keys) + // TODO(marun) Ensure this message accurately reflects the sending chain + ginkgo.By("importing AVAX from the X-Chain to the C-Chain") + + importTx, err := v.vm.newImportTx(chainID, to, initialBaseFee, keys) v.require.NoError(err) v.require.NoError(v.vm.mempool.AddLocalTx(importTx)) @@ -90,10 +96,12 @@ func (v *vmFixture) IssueExportTx( amount uint64, chainID ids.ID, to ids.ShortID, - baseFee *big.Int, keys []*secp256k1.PrivateKey, ) *Tx { - exportTx, err := v.vm.newExportTx(assetID, amount, chainID, to, baseFee, keys) + // TODO(marun) Ensure this message accurately reflects the recipient chain + ginkgo.By("exporting AVAX from the C-Chain to the X-Chain") + + exportTx, err := v.vm.newExportTx(assetID, amount, chainID, to, initialBaseFee, keys) v.require.NoError(err) v.require.NoError(v.vm.mempool.AddLocalTx(exportTx)) diff --git a/tests/integration/integration.go b/tests/integration/integration.go index 8ea6fca726..2dbfc8ff26 100644 --- a/tests/integration/integration.go +++ b/tests/integration/integration.go @@ -4,8 +4,6 @@ package integration import ( - "math/big" - "github.com/ethereum/go-ethereum/common" ginkgo "github.com/onsi/ginkgo/v2" @@ -14,14 +12,9 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" - "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/plugin/evm" ) -var ( - InitialBaseFee = big.NewInt(params.ApricotPhase3InitialBaseFee) -) - type IntegrationFixture interface { GetPrefundedKey() *secp256k1.PrivateKey @@ -33,7 +26,6 @@ type IntegrationFixture interface { chainID ids.ID, amount uint64, to common.Address, - baseFee *big.Int, keys []*secp256k1.PrivateKey, ) *evm.Tx @@ -42,7 +34,6 @@ type IntegrationFixture interface { amount uint64, chainID ids.ID, to ids.ShortID, - baseFee *big.Int, keys []*secp256k1.PrivateKey, ) *evm.Tx } diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index b90c89c806..bb8dcdb368 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -17,10 +17,10 @@ import ( "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/ava-labs/avalanchego/tests/fixture/testnet" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/avm" "github.com/ava-labs/avalanchego/vms/components/avax" "github.com/ava-labs/avalanchego/vms/secp256k1fx" - "github.com/ava-labs/avalanchego/wallet/subnet/primary" "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" "github.com/ava-labs/coreth/plugin/evm" @@ -28,26 +28,20 @@ import ( // Shared network implementation of IntegrationFixture type sharedNetworkFixture struct { + require *require.Assertions + // The URI of the only node the fixture is intended to communicate with nodeURI testnet.NodeURI - // Wallet to perform transactions - baseWallet primary.Wallet - // Prefunded key used to configure the wallet prefundedKey *secp256k1.PrivateKey - - require *require.Assertions } func newSharedNetworkFixture(t require.TestingT) *sharedNetworkFixture { - nodeURI := e2e.Env.GetRandomNodeURI() - keychain := e2e.Env.NewKeychain(1) return &sharedNetworkFixture{ - nodeURI: nodeURI, - baseWallet: e2e.NewWallet(keychain, nodeURI), - prefundedKey: keychain.Keys[0], require: require.New(t), + nodeURI: e2e.Env.GetRandomNodeURI(), + prefundedKey: e2e.Env.AllocateFundedKey(), } } @@ -56,12 +50,14 @@ func (f *sharedNetworkFixture) GetPrefundedKey() *secp256k1.PrivateKey { } func (f *sharedNetworkFixture) GetXChainID() ids.ID { + // TODO(marun) cache this value id, err := info.NewClient(f.nodeURI.URI).GetBlockchainID(e2e.DefaultContext(), "X") f.require.NoError(err) return id } func (f *sharedNetworkFixture) GetAVAXAssetID() ids.ID { + // TODO(marun) cache this value asset, err := avm.NewClient(f.nodeURI.URI, "X").GetAssetDescription(e2e.DefaultContext(), "AVAX") f.require.NoError(err) return asset.AssetID @@ -70,19 +66,17 @@ func (f *sharedNetworkFixture) GetAVAXAssetID() ids.ID { func (f *sharedNetworkFixture) IssueImportTx( chainID ids.ID, amount uint64, - to ethcommon.Address, - baseFee *big.Int, + toEthAddress ethcommon.Address, keys []*secp256k1.PrivateKey, ) *evm.Tx { - addresses := make([]ids.ShortID, len(keys)) - for i, key := range keys { - addresses[i] = key.Address() - } + keychain := secp256k1fx.NewKeychain(keys...) + wallet := e2e.NewWallet(keychain, f.nodeURI) + ethClient := e2e.NewEthClient(f.nodeURI) - // TODO(marun) Ensure this message accurately reflects the recipient chain + // TODO(marun) Ensure this message accurately reflects the sending chain ginkgo.By("exporting AVAX from the X-Chain to the C-Chain") - _, err := f.baseWallet.X().IssueExportTx( - f.baseWallet.C().BlockchainID(), + _, err := wallet.X().IssueExportTx( + wallet.C().BlockchainID(), []*avax.TransferableOutput{ { Asset: avax.Asset{ @@ -92,26 +86,29 @@ func (f *sharedNetworkFixture) IssueImportTx( Amt: amount, OutputOwners: secp256k1fx.OutputOwners{ Threshold: 1, - Addrs: addresses, + Addrs: keysToAddresses(keys), }, }, }, }, e2e.WithDefaultContext(), + e2e.WithSuggestedGasPrice(ethClient), ) f.require.NoError(err) - // TODO(marun) Ensure this message accurately reflects the recipient chain + // TODO(marun) Ensure this message accurately reflects the sending chain ginkgo.By("importing AVAX from the X-Chain to the C-Chain") - tx, err := f.baseWallet.C().IssueImportTx( + tx, err := wallet.C().IssueImportTx( chainID, - to, + toEthAddress, e2e.WithDefaultContext(), - common.WithBaseFee(baseFee), ) f.require.NoError(err) - // TODO(marun) verify result + ginkgo.By("checking that the recipient address has received imported funds on the C-Chain") + balance, err := ethClient.BalanceAt(e2e.DefaultContext(), toEthAddress, nil) + f.require.NoError(err) + f.require.Positive(balance.Cmp(big.NewInt(0))) return tx } @@ -120,45 +117,60 @@ func (f *sharedNetworkFixture) IssueExportTx( _ ids.ID, // Ignored - wallet will determine correct asset id amount uint64, chainID ids.ID, - to ids.ShortID, - baseFee *big.Int, - keys []*secp256k1.PrivateKey, // Ignored - prefunded key will be used + toAddress ids.ShortID, + keys []*secp256k1.PrivateKey, ) *evm.Tx { + keychain := secp256k1fx.NewKeychain(keys...) + wallet := e2e.NewWallet(keychain, f.nodeURI) + ethClient := e2e.NewEthClient(f.nodeURI) + // TODO(marun) Ensure this message accurately reflects the recipient chain ginkgo.By("exporting AVAX from the C-Chain to the X-Chain") - tx, err := f.baseWallet.C().IssueExportTx( + tx, err := wallet.C().IssueExportTx( chainID, []*secp256k1fx.TransferOutput{ { Amt: amount, OutputOwners: secp256k1fx.OutputOwners{ Threshold: 1, - Addrs: []ids.ShortID{ - f.prefundedKey.Address(), - }, + Addrs: keysToAddresses(keys), }, }, }, e2e.WithDefaultContext(), - common.WithBaseFee(baseFee), + e2e.WithSuggestedGasPrice(ethClient), ) f.require.NoError(err) // TODO(marun) Ensure this message accurately reflects the recipient chain ginkgo.By("importing AVAX from the C-Chain to the X-Chain") - _, err = f.baseWallet.X().IssueImportTx( - f.baseWallet.C().BlockchainID(), + _, err = wallet.X().IssueImportTx( + wallet.C().BlockchainID(), &secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{ - to, + toAddress, }, }, e2e.WithDefaultContext(), ) f.require.NoError(err) - // TODO(marun) verify result + // TODO(marun) Ensure this message accurately reflects the recipient chain + ginkgo.By("checking that the recipient address has received imported funds on the X-Chain") + balances, err := wallet.X().Builder().GetFTBalance(common.WithCustomAddresses(set.Of( + toAddress, + ))) + f.require.NoError(err) + f.require.Positive(balances[f.GetAVAXAssetID()]) return tx } + +func keysToAddresses(keys []*secp256k1.PrivateKey) []ids.ShortID { + addresses := make([]ids.ShortID, len(keys)) + for i, key := range keys { + addresses[i] = key.Address() + } + return addresses +} diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index 563f022c71..3d45e4d317 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -6,6 +6,8 @@ package vm import ( ginkgo "github.com/onsi/ginkgo/v2" + "github.com/stretchr/testify/require" + "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/coreth/params" @@ -14,17 +16,21 @@ import ( ) var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { + require := require.New(ginkgo.GinkgoT()) + ginkgo.It("should support issuing atomic transactions", func() { f := i9n.GetFixture() key := f.GetPrefundedKey() importAmount := uint64(50000000) + recipientKey, err := secp256k1.NewPrivateKey() + require.NoError(err) + _ = f.IssueImportTx( f.GetXChainID(), importAmount, - evm.GetEthAddress(key), - i9n.InitialBaseFee, + evm.GetEthAddress(recipientKey), []*secp256k1.PrivateKey{ key, }, @@ -34,10 +40,9 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { f.GetAVAXAssetID(), importAmount-(2*params.AvalancheAtomicTxFee), f.GetXChainID(), - key.Address(), - i9n.InitialBaseFee, + recipientKey.Address(), []*secp256k1.PrivateKey{ - key, + recipientKey, }, ) }) From f574f02ebed4b6cfaee3e627c90b29fe61fea205 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 8 Nov 2023 15:04:37 +0100 Subject: [PATCH 17/39] Ensure test logging reports the correct chain alias --- plugin/evm/shared_test_vm_fixture.go | 15 ++++++++--- tests/integration/shared_network_fixture.go | 29 ++++++++++++--------- tests/integration/vm/atomic_tx.go | 4 +-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index 5773ade0c5..0f72dc95d9 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -5,6 +5,7 @@ package evm import ( "context" + "fmt" "math/big" "time" @@ -74,8 +75,7 @@ func (v *vmFixture) IssueImportTx( to common.Address, keys []*secp256k1.PrivateKey, ) *Tx { - // TODO(marun) Ensure this message accurately reflects the sending chain - ginkgo.By("importing AVAX from the X-Chain to the C-Chain") + ginkgo.By(fmt.Sprintf("importing AVAX from the %s-Chain to the C-Chain", v.getChainAlias(chainID))) importTx, err := v.vm.newImportTx(chainID, to, initialBaseFee, keys) v.require.NoError(err) @@ -98,8 +98,7 @@ func (v *vmFixture) IssueExportTx( to ids.ShortID, keys []*secp256k1.PrivateKey, ) *Tx { - // TODO(marun) Ensure this message accurately reflects the recipient chain - ginkgo.By("exporting AVAX from the C-Chain to the X-Chain") + ginkgo.By(fmt.Sprintf("exporting AVAX from the C-Chain to the %s-Chain", v.getChainAlias(chainID))) exportTx, err := v.vm.newExportTx(assetID, amount, chainID, to, initialBaseFee, keys) v.require.NoError(err) @@ -156,3 +155,11 @@ func (v *vmFixture) checkAtomicTxIndexing(tx *Tx, expectedHeight uint64) { v.assert.Equal(expectedHeight, height, "unexpected height") v.assert.Equal(indexedTx.ID(), tx.ID(), "expected ID of indexed tx to match original txID") } + +// Determine the chain alias for a chainID representing either the X- or P-Chain. +func (v *vmFixture) getChainAlias(chainID ids.ID) string { + if chainID == v.GetXChainID() { + return "X" + } + return "P" +} diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index bb8dcdb368..72d15440ac 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -4,6 +4,7 @@ package integration import ( + "fmt" "math/big" ethcommon "github.com/ethereum/go-ethereum/common" @@ -16,6 +17,7 @@ import ( "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/ava-labs/avalanchego/tests/fixture/testnet" + "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/set" "github.com/ava-labs/avalanchego/vms/avm" @@ -50,14 +52,12 @@ func (f *sharedNetworkFixture) GetPrefundedKey() *secp256k1.PrivateKey { } func (f *sharedNetworkFixture) GetXChainID() ids.ID { - // TODO(marun) cache this value id, err := info.NewClient(f.nodeURI.URI).GetBlockchainID(e2e.DefaultContext(), "X") f.require.NoError(err) return id } func (f *sharedNetworkFixture) GetAVAXAssetID() ids.ID { - // TODO(marun) cache this value asset, err := avm.NewClient(f.nodeURI.URI, "X").GetAssetDescription(e2e.DefaultContext(), "AVAX") f.require.NoError(err) return asset.AssetID @@ -72,9 +72,9 @@ func (f *sharedNetworkFixture) IssueImportTx( keychain := secp256k1fx.NewKeychain(keys...) wallet := e2e.NewWallet(keychain, f.nodeURI) ethClient := e2e.NewEthClient(f.nodeURI) + chainAlias := getChainAlias(chainID) - // TODO(marun) Ensure this message accurately reflects the sending chain - ginkgo.By("exporting AVAX from the X-Chain to the C-Chain") + ginkgo.By(fmt.Sprintf("exporting AVAX from the %s-Chain to the C-Chain", chainAlias)) _, err := wallet.X().IssueExportTx( wallet.C().BlockchainID(), []*avax.TransferableOutput{ @@ -96,8 +96,7 @@ func (f *sharedNetworkFixture) IssueImportTx( ) f.require.NoError(err) - // TODO(marun) Ensure this message accurately reflects the sending chain - ginkgo.By("importing AVAX from the X-Chain to the C-Chain") + ginkgo.By(fmt.Sprintf("importing AVAX from the %s-Chain to the C-Chain", chainAlias)) tx, err := wallet.C().IssueImportTx( chainID, toEthAddress, @@ -123,9 +122,9 @@ func (f *sharedNetworkFixture) IssueExportTx( keychain := secp256k1fx.NewKeychain(keys...) wallet := e2e.NewWallet(keychain, f.nodeURI) ethClient := e2e.NewEthClient(f.nodeURI) + chainAlias := getChainAlias(chainID) - // TODO(marun) Ensure this message accurately reflects the recipient chain - ginkgo.By("exporting AVAX from the C-Chain to the X-Chain") + ginkgo.By(fmt.Sprintf("exporting AVAX from the C-Chain to the %s-Chain", chainAlias)) tx, err := wallet.C().IssueExportTx( chainID, []*secp256k1fx.TransferOutput{ @@ -142,8 +141,7 @@ func (f *sharedNetworkFixture) IssueExportTx( ) f.require.NoError(err) - // TODO(marun) Ensure this message accurately reflects the recipient chain - ginkgo.By("importing AVAX from the C-Chain to the X-Chain") + ginkgo.By(fmt.Sprintf("importing AVAX from the C-Chain to the %s-Chain", chainAlias)) _, err = wallet.X().IssueImportTx( wallet.C().BlockchainID(), &secp256k1fx.OutputOwners{ @@ -156,8 +154,7 @@ func (f *sharedNetworkFixture) IssueExportTx( ) f.require.NoError(err) - // TODO(marun) Ensure this message accurately reflects the recipient chain - ginkgo.By("checking that the recipient address has received imported funds on the X-Chain") + ginkgo.By(fmt.Sprintf("checking that the recipient address has received imported funds on the %s-Chain", chainAlias)) balances, err := wallet.X().Builder().GetFTBalance(common.WithCustomAddresses(set.Of( toAddress, ))) @@ -174,3 +171,11 @@ func keysToAddresses(keys []*secp256k1.PrivateKey) []ids.ShortID { } return addresses } + +// Determine the chain alias for a chainID representing either the X- or P-Chain. +func getChainAlias(chainID ids.ID) string { + if chainID == constants.PlatformChainID { + return "P" + } + return "X" +} diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index 3d45e4d317..6316da59f0 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -21,7 +21,7 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { ginkgo.It("should support issuing atomic transactions", func() { f := i9n.GetFixture() - key := f.GetPrefundedKey() + prefundedKey := f.GetPrefundedKey() importAmount := uint64(50000000) recipientKey, err := secp256k1.NewPrivateKey() @@ -32,7 +32,7 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { importAmount, evm.GetEthAddress(recipientKey), []*secp256k1.PrivateKey{ - key, + prefundedKey, }, ) From 84ae56a212b6eb7103acf0fd32f64dcbb323fe8a Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 8 Nov 2023 20:00:52 +0100 Subject: [PATCH 18/39] Enable bootstrap check on shared network fixture teardown --- tests/integration/integration.go | 20 ++++++++++++-------- tests/integration/shared_network_fixture.go | 7 +++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/tests/integration/integration.go b/tests/integration/integration.go index 2dbfc8ff26..03cc77091b 100644 --- a/tests/integration/integration.go +++ b/tests/integration/integration.go @@ -16,6 +16,8 @@ import ( ) type IntegrationFixture interface { + Teardown() + GetPrefundedKey() *secp256k1.PrivateKey GetXChainID() ids.ID @@ -39,15 +41,17 @@ type IntegrationFixture interface { } func GetFixture() IntegrationFixture { + var fixture IntegrationFixture if e2e.Env == nil { - // Shared network fixture not initialized, return a fresh vm fixture - vmFixture := evm.CreateVMFixture(ginkgo.GinkgoT()) - ginkgo.DeferCleanup(func() { - vmFixture.Teardown() - }) - return vmFixture + // Shared network fixture not initialized, return a vm fixture + fixture = evm.CreateVMFixture(ginkgo.GinkgoT()) + } else { + // e2e.Env being non-nil indicates availability of shared network fixture + fixture = newSharedNetworkFixture(ginkgo.GinkgoT()) } + ginkgo.DeferCleanup(func() { + fixture.Teardown() + }) - // e2e.Env being non-nil indicates the use of a shared network fixture - return newSharedNetworkFixture(ginkgo.GinkgoT()) + return fixture } diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index 72d15440ac..5be5279479 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -47,6 +47,13 @@ func newSharedNetworkFixture(t require.TestingT) *sharedNetworkFixture { } } +func (f *sharedNetworkFixture) Teardown() { + if !ginkgo.CurrentSpecReport().Failed() { + // Only check if bootstrap is possible for passing tests + e2e.CheckBootstrapIsPossible(e2e.Env.GetNetwork()) + } +} + func (f *sharedNetworkFixture) GetPrefundedKey() *secp256k1.PrivateKey { return f.prefundedKey } From 6cd75642c9b5b687fcd0003d9289cb0becb80e38 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 8 Nov 2023 20:02:05 +0100 Subject: [PATCH 19/39] Update export amount to account for dynamic fees with shared network fixture --- tests/integration/vm/atomic_tx.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index 6316da59f0..2d146a3e5d 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -8,9 +8,10 @@ import ( "github.com/stretchr/testify/require" + "github.com/ava-labs/avalanchego/tests" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" + "github.com/ava-labs/avalanchego/utils/units" - "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/plugin/evm" i9n "github.com/ava-labs/coreth/tests/integration" ) @@ -18,19 +19,24 @@ import ( var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { require := require.New(ginkgo.GinkgoT()) + // Arbitrary amount to transfer + const importAmount = 100 * units.Avax + const exportAmount = 80 * units.Avax // Less than import to account for fees + ginkgo.It("should support issuing atomic transactions", func() { f := i9n.GetFixture() prefundedKey := f.GetPrefundedKey() - importAmount := uint64(50000000) recipientKey, err := secp256k1.NewPrivateKey() require.NoError(err) + recipientEthAddress := evm.GetEthAddress(recipientKey) + tests.Outf("{{blue}} using recipient address: %+v{{/}}\n", recipientEthAddress) _ = f.IssueImportTx( f.GetXChainID(), importAmount, - evm.GetEthAddress(recipientKey), + recipientEthAddress, []*secp256k1.PrivateKey{ prefundedKey, }, @@ -38,7 +44,7 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { _ = f.IssueExportTx( f.GetAVAXAssetID(), - importAmount-(2*params.AvalancheAtomicTxFee), + exportAmount, f.GetXChainID(), recipientKey.Address(), []*secp256k1.PrivateKey{ From 365e7aeadaf75d5ea89e267660261f146147c1ea Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 8 Nov 2023 20:18:19 +0100 Subject: [PATCH 20/39] Add node restart check on teardown --- tests/integration/shared_network_fixture.go | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index 5be5279479..c7796eecc7 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -6,6 +6,7 @@ package integration import ( "fmt" "math/big" + "strings" ethcommon "github.com/ethereum/go-ethereum/common" @@ -14,9 +15,11 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/api/info" + "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/testnet" + "github.com/ava-labs/avalanchego/tests/fixture/testnet/local" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/set" @@ -51,6 +54,34 @@ func (f *sharedNetworkFixture) Teardown() { if !ginkgo.CurrentSpecReport().Failed() { // Only check if bootstrap is possible for passing tests e2e.CheckBootstrapIsPossible(e2e.Env.GetNetwork()) + + ginkgo.By(fmt.Sprintf("checking if restart of %q is possible with current network state", f.nodeURI.NodeID)) + // TODO(marun) Ensure this works for more than local nodes + // TODO(marun) Allow this to be skipped just like the bootstrap check (to allow for parallel execution and simplify dev) + // TODO(marun) Simplify restart (here and for upgrade test) + network, err := local.ReadNetwork(e2e.Env.NetworkDir) + f.require.NoError(err) + var targetNode *local.LocalNode + for _, node := range network.Nodes { + if node.GetID() == f.nodeURI.NodeID { + targetNode = node + break + } + } + f.require.NotNil(targetNode) + f.require.NoError(targetNode.Stop()) + + bootstrapIPs, bootstrapIDs, err := network.GetBootstrapIPsAndIDs() + f.require.NoError(err) + f.require.NotEmpty(bootstrapIDs) + targetNode.Flags[config.BootstrapIDsKey] = strings.Join(bootstrapIDs, ",") + targetNode.Flags[config.BootstrapIPsKey] = strings.Join(bootstrapIPs, ",") + f.require.NoError(targetNode.WriteConfig()) + + f.require.NoError(targetNode.Start(ginkgo.GinkgoWriter, network.ExecPath)) + + ginkgo.By(fmt.Sprintf("waiting for node %q to report healthy after restart", targetNode.NodeID)) + e2e.WaitForHealthy(targetNode) } } From 4d029f38d9ff0df3f3e42a9487d6dedae01f8de5 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 8 Nov 2023 20:25:34 +0100 Subject: [PATCH 21/39] Revert CORETH_PATH definition in scripts/tests.e2e.sh --- scripts/tests.e2e.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/tests.e2e.sh b/scripts/tests.e2e.sh index 6e973a5919..fa31a7e4a8 100755 --- a/scripts/tests.e2e.sh +++ b/scripts/tests.e2e.sh @@ -12,13 +12,15 @@ if ! [[ "$0" =~ scripts/tests.e2e.sh ]]; then exit 255 fi +# Coreth root directory +CORETH_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd ) + # Allow configuring the clone path to point to an existing clone export AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" ./scripts/build_avalanchego.sh # Always return to the coreth path on exit -CORETH_PATH="$(echo "${PWD}")" function cleanup { cd "${CORETH_PATH}" } From bfd1a3d4ca26f621d165799d688d98b95f97b59c Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 8 Nov 2023 20:29:25 +0100 Subject: [PATCH 22/39] Rename tests/integration/integration.go -> tests/integration/fixture.go --- tests/integration/{integration.go => fixture.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/integration/{integration.go => fixture.go} (100%) diff --git a/tests/integration/integration.go b/tests/integration/fixture.go similarity index 100% rename from tests/integration/integration.go rename to tests/integration/fixture.go From e0d24eab3c02ddeb1f400a4ff02278d410749139 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 30 Nov 2023 14:40:19 -0800 Subject: [PATCH 23/39] Ensure avalanche build script fetches tags for an existing clone --- scripts/build_avalanchego.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/build_avalanchego.sh b/scripts/build_avalanchego.sh index 2da5db1959..a62916f239 100755 --- a/scripts/build_avalanchego.sh +++ b/scripts/build_avalanchego.sh @@ -28,7 +28,8 @@ echo "checking out target AvalancheGo version ${avalanche_version}" if [[ -d "${AVALANCHEGO_CLONE_PATH}" ]]; then echo "updating existing clone" cd "${AVALANCHEGO_CLONE_PATH}" - git fetch + # Ensure the clone has all commits and tags that might be referenced by $avalanche_version + git fetch --tags else echo "creating new clone" git clone https://github.com/ava-labs/avalanchego.git "${AVALANCHEGO_CLONE_PATH}" From 895e3664ca812e2b15ec31aebcd8e595783ea06f Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 30 Nov 2023 16:42:59 -0800 Subject: [PATCH 24/39] Run the integration test binary directly for compatibility with windows --- scripts/tests.integration.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index ec17615cf9..b6b55ddd2c 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -28,4 +28,4 @@ ACK_GINKGO_RC=true ginkgo build ./tests/integration ./tests/integration/integration.test --help # Execute in random order to identify unwanted dependency -ginkgo -v --randomize-all ./tests/integration/integration.test -- "${@}" +./tests/integration/integration.test --ginkgo.randomize-all --ginkgo.trace --ginkgo.v "${@}" From 834668a4895578d2e86cb71066a2baccf38475b0 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 30 Nov 2023 17:03:13 -0800 Subject: [PATCH 25/39] Attemp to work around ancient bash version in macos unit test machine --- scripts/tests.integration.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index b6b55ddd2c..db5a2a602c 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -16,7 +16,7 @@ fi export AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" # Only build avalanchego if using the network fixture -if [[ "${@}" =~ "--use-network-fixture" ]]; then +if [[ "$@" =~ "--use-network-fixture" ]]; then ./scripts/build_avalanchego.sh export AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego})" fi @@ -28,4 +28,4 @@ ACK_GINKGO_RC=true ginkgo build ./tests/integration ./tests/integration/integration.test --help # Execute in random order to identify unwanted dependency -./tests/integration/integration.test --ginkgo.randomize-all --ginkgo.trace --ginkgo.v "${@}" +./tests/integration/integration.test --ginkgo.randomize-all --ginkgo.trace --ginkgo.v "$@" From 7707ea1f6aa9481526834fb22875bec62221a2bd Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 1 Dec 2023 04:46:53 -0800 Subject: [PATCH 26/39] Try to fix macos compilation failure --- scripts/tests.integration.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index db5a2a602c..0a3cbeb937 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -21,6 +21,11 @@ if [[ "$@" =~ "--use-network-fixture" ]]; then export AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego})" fi +# Ensure blst configuration +CORETH_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd ) +source ./scripts/versions.sh +source ./scripts/constants.sh + echo "building integration.test" # Install the ginkgo binary (required for test build and run) go install -v github.com/onsi/ginkgo/v2/ginkgo@v2.1.4 From 4b3702c8f133d9cbeccd0ec9e273571e2877cb53 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 3 Jan 2024 08:33:20 -0800 Subject: [PATCH 27/39] fixup: Rename prefunded -> pre-funded --- plugin/evm/shared_test_vm_fixture.go | 12 ++++++------ tests/integration/fixture.go | 2 +- tests/integration/shared_network_fixture.go | 10 +++++----- tests/integration/vm/atomic_tx.go | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index 0f72dc95d9..89d3985900 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -32,7 +32,7 @@ var ( type vmFixture struct { require *require.Assertions assert *assert.Assertions - prefundedKey *secp256k1.PrivateKey + preFundedKey *secp256k1.PrivateKey vm *VM issuer chan engCommon.Message height uint64 @@ -41,17 +41,17 @@ type vmFixture struct { func CreateVMFixture(t require.TestingT) *vmFixture { require := require.New(t) - prefundedKey, err := secp256k1.NewPrivateKey() + preFundedKey, err := secp256k1.NewPrivateKey() require.NoError(err) issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", map[ids.ShortID]uint64{ - prefundedKey.Address(): defaultFundedKeyCChainAmount.Uint64(), + preFundedKey.Address(): defaultFundedKeyCChainAmount.Uint64(), }) return &vmFixture{ require: require, assert: assert.New(t), - prefundedKey: prefundedKey, + preFundedKey: preFundedKey, vm: vm, issuer: issuer, } @@ -61,8 +61,8 @@ func (v *vmFixture) Teardown() { v.require.NoError(v.vm.Shutdown(context.Background())) } -func (v *vmFixture) GetPrefundedKey() *secp256k1.PrivateKey { - return v.prefundedKey +func (v *vmFixture) GetPreFundedKey() *secp256k1.PrivateKey { + return v.preFundedKey } func (v *vmFixture) GetXChainID() ids.ID { return v.vm.ctx.XChainID } diff --git a/tests/integration/fixture.go b/tests/integration/fixture.go index 03cc77091b..d1753b11d4 100644 --- a/tests/integration/fixture.go +++ b/tests/integration/fixture.go @@ -18,7 +18,7 @@ import ( type IntegrationFixture interface { Teardown() - GetPrefundedKey() *secp256k1.PrivateKey + GetPreFundedKey() *secp256k1.PrivateKey GetXChainID() ids.ID diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index c7796eecc7..24f0fd92be 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -38,15 +38,15 @@ type sharedNetworkFixture struct { // The URI of the only node the fixture is intended to communicate with nodeURI testnet.NodeURI - // Prefunded key used to configure the wallet - prefundedKey *secp256k1.PrivateKey + // Pre-funded key used to configure the wallet + preFundedKey *secp256k1.PrivateKey } func newSharedNetworkFixture(t require.TestingT) *sharedNetworkFixture { return &sharedNetworkFixture{ require: require.New(t), nodeURI: e2e.Env.GetRandomNodeURI(), - prefundedKey: e2e.Env.AllocateFundedKey(), + preFundedKey: e2e.Env.AllocatePreFundedKey(), } } @@ -85,8 +85,8 @@ func (f *sharedNetworkFixture) Teardown() { } } -func (f *sharedNetworkFixture) GetPrefundedKey() *secp256k1.PrivateKey { - return f.prefundedKey +func (f *sharedNetworkFixture) GetPreFundedKey() *secp256k1.PrivateKey { + return f.preFundedKey } func (f *sharedNetworkFixture) GetXChainID() ids.ID { diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index 2d146a3e5d..2a65369919 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -26,7 +26,7 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { ginkgo.It("should support issuing atomic transactions", func() { f := i9n.GetFixture() - prefundedKey := f.GetPrefundedKey() + preFundedKey := f.GetPreFundedKey() recipientKey, err := secp256k1.NewPrivateKey() require.NoError(err) @@ -38,7 +38,7 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { importAmount, recipientEthAddress, []*secp256k1.PrivateKey{ - prefundedKey, + preFundedKey, }, ) From 9630b6159f13b7fa4063a56c888498d8df75832d Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 3 Jan 2024 08:36:56 -0800 Subject: [PATCH 28/39] fixup: Get tests passing --- plugin/evm/shared_test_vm.go | 3 ++- plugin/evm/tx_gossip_test.go | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/plugin/evm/shared_test_vm.go b/plugin/evm/shared_test_vm.go index 2160468866..1246fee6d5 100644 --- a/plugin/evm/shared_test_vm.go +++ b/plugin/evm/shared_test_vm.go @@ -35,6 +35,7 @@ import ( "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/params" + "github.com/ava-labs/coreth/utils" ) var ( @@ -114,7 +115,7 @@ func testSharedMemory() atomic.SharedMemory { } func NewContext() *snow.Context { - ctx := snow.DefaultContextTest() + ctx := utils.TestSnowContext() ctx.NodeID = ids.GenerateTestNodeID() ctx.NetworkID = testNetworkID ctx.ChainID = testCChainID diff --git a/plugin/evm/tx_gossip_test.go b/plugin/evm/tx_gossip_test.go index 03427b2c27..52a0c7227f 100644 --- a/plugin/evm/tx_gossip_test.go +++ b/plugin/evm/tx_gossip_test.go @@ -11,6 +11,8 @@ import ( "testing" "time" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ava-labs/avalanchego/chains/atomic" "github.com/ava-labs/avalanchego/database/memdb" "github.com/ava-labs/avalanchego/ids" @@ -32,11 +34,30 @@ import ( "google.golang.org/protobuf/proto" + "github.com/ava-labs/coreth/core" "github.com/ava-labs/coreth/core/types" "github.com/ava-labs/coreth/params" "github.com/ava-labs/coreth/utils" ) +func newPrefundedGenesis( + balance int, + addresses ...ethcommon.Address, +) *core.Genesis { + alloc := core.GenesisAlloc{} + for _, address := range addresses { + alloc[address] = core.GenesisAccount{ + Balance: big.NewInt(int64(balance)), + } + } + + return &core.Genesis{ + Config: params.TestChainConfig, + Difficulty: big.NewInt(0), + Alloc: alloc, + } +} + func TestEthTxGossip(t *testing.T) { require := require.New(t) ctx := context.Background() From e8d8e6c8af0ebdd6fbd490c986a6b5bd400b26ab Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 3 Jan 2024 09:34:03 -0800 Subject: [PATCH 29/39] fixup: Update fixture use to latest tmpnet --- tests/integration/shared_network_fixture.go | 27 ++++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index 24f0fd92be..d5276b08c8 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -4,6 +4,7 @@ package integration import ( + "context" "fmt" "math/big" "strings" @@ -18,8 +19,7 @@ import ( "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/testnet" - "github.com/ava-labs/avalanchego/tests/fixture/testnet/local" + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/secp256k1" "github.com/ava-labs/avalanchego/utils/set" @@ -36,7 +36,7 @@ type sharedNetworkFixture struct { require *require.Assertions // The URI of the only node the fixture is intended to communicate with - nodeURI testnet.NodeURI + nodeURI tmpnet.NodeURI // Pre-funded key used to configure the wallet preFundedKey *secp256k1.PrivateKey @@ -53,32 +53,35 @@ func newSharedNetworkFixture(t require.TestingT) *sharedNetworkFixture { func (f *sharedNetworkFixture) Teardown() { if !ginkgo.CurrentSpecReport().Failed() { // Only check if bootstrap is possible for passing tests + // TODO(marun) Ensure this is safe to perform on teardown. Currently it uses DeferCleanup to stop the node. e2e.CheckBootstrapIsPossible(e2e.Env.GetNetwork()) + // TODO(marun) Allow node restart to be skipped just like the bootstrap check (to allow for parallel execution and faster dev iteration) ginkgo.By(fmt.Sprintf("checking if restart of %q is possible with current network state", f.nodeURI.NodeID)) - // TODO(marun) Ensure this works for more than local nodes - // TODO(marun) Allow this to be skipped just like the bootstrap check (to allow for parallel execution and simplify dev) - // TODO(marun) Simplify restart (here and for upgrade test) - network, err := local.ReadNetwork(e2e.Env.NetworkDir) + network, err := tmpnet.ReadNetwork(e2e.Env.NetworkDir) f.require.NoError(err) - var targetNode *local.LocalNode + var targetNode *tmpnet.Node for _, node := range network.Nodes { - if node.GetID() == f.nodeURI.NodeID { + if node.NodeID == f.nodeURI.NodeID { targetNode = node break } } f.require.NotNil(targetNode) - f.require.NoError(targetNode.Stop()) + ctx, cancel := context.WithTimeout(context.Background(), e2e.DefaultTimeout) + defer cancel() + f.require.NoError(targetNode.Stop(ctx)) + + // TODO(marun) Update to use Network.StartNode which handles bootstrap setup automatically once https://github.com/ava-labs/avalanchego/pull/2464 merges bootstrapIPs, bootstrapIDs, err := network.GetBootstrapIPsAndIDs() f.require.NoError(err) f.require.NotEmpty(bootstrapIDs) targetNode.Flags[config.BootstrapIDsKey] = strings.Join(bootstrapIDs, ",") targetNode.Flags[config.BootstrapIPsKey] = strings.Join(bootstrapIPs, ",") - f.require.NoError(targetNode.WriteConfig()) + f.require.NoError(targetNode.Write()) - f.require.NoError(targetNode.Start(ginkgo.GinkgoWriter, network.ExecPath)) + f.require.NoError(targetNode.Start(ginkgo.GinkgoWriter)) ginkgo.By(fmt.Sprintf("waiting for node %q to report healthy after restart", targetNode.NodeID)) e2e.WaitForHealthy(targetNode) From 218e61cb73bc9d6c258e486d70f7e14ddfaff288 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 3 Jan 2024 09:34:25 -0800 Subject: [PATCH 30/39] fixup: go mod tidy --- go.mod | 13 +++++++++++++ go.sum | 28 ++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/go.mod b/go.mod index 1bce6a6de7..ca504946f5 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,8 @@ require ( github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.16 github.com/olekukonko/tablewriter v0.0.5 + github.com/onsi/ginkgo/v2 v2.13.1 + github.com/onsi/gomega v1.29.0 github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_model v0.3.0 github.com/shirou/gopsutil v3.21.11+incompatible @@ -49,6 +51,7 @@ require ( require ( github.com/BurntSushi/toml v1.3.2 // indirect github.com/DataDog/zstd v1.5.2 // indirect + github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcutil v1.1.3 // indirect @@ -67,14 +70,21 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-stack/stack v1.8.1 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/renameio/v2 v2.0.0 // indirect + github.com/gorilla/mux v1.8.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/huin/goupnp v1.0.3 // indirect + github.com/jackpal/gateway v1.0.6 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/klauspost/compress v1.15.15 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect @@ -87,11 +97,13 @@ require ( github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d // 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 github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/common v0.39.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect + github.com/rs/cors v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -114,6 +126,7 @@ require ( go.uber.org/zap v1.26.0 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/term v0.16.0 // indirect + golang.org/x/tools v0.16.0 // indirect gonum.org/v1/gonum v0.11.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect diff --git a/go.sum b/go.sum index fa6c96b16a..da4247eb36 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,8 @@ github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMd github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8= github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/VictoriaMetrics/fastcache v1.10.0 h1:5hDJnLsKLpnUEToub7ETuRu8RCkb40woBZAUiKonXzY= github.com/VictoriaMetrics/fastcache v1.10.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= @@ -193,6 +195,8 @@ github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5Nq github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -242,6 +246,8 @@ github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -282,6 +288,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -305,6 +313,9 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -316,6 +327,10 @@ github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/ github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/jackpal/gateway v1.0.6 h1:/MJORKvJEwNVldtGVJC2p2cwCnsSoLn3hl3zxmZT7tk= +github.com/jackpal/gateway v1.0.6/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= @@ -352,6 +367,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= @@ -408,6 +425,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.13.1 h1:LNGfMbR2OVGBfXjvRZIZ2YCTQdGKtPLvuI1rMCCj3OU= +github.com/onsi/ginkgo/v2 v2.13.1/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -423,6 +442,8 @@ github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwb github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= +github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -445,6 +466,8 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -482,6 +505,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= @@ -616,6 +640,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -828,6 +854,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 4830341388b593d489eca26c27da418fdb054f7b Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 3 Jan 2024 09:42:20 -0800 Subject: [PATCH 31/39] fixup: Responded to review feedback --- .github/workflows/ci.yml | 16 +++++++++++----- plugin/evm/shared_test_vm_fixture.go | 13 +++++-------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a0c2b558eb..8ef6dba0bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,10 @@ on: required: true default: 'master' +env: + go_version: '~1.20.12' + tmpnet_data_path: ~/.tmpnet/networks/1000 + jobs: lint: name: Lint @@ -31,7 +35,7 @@ jobs: token: ${{ secrets.AVALANCHE_PAT }} - uses: actions/setup-go@v5 with: - go-version: '~1.21.7' + go-version: ${{ env.go_version }} check-latest: true - name: change avalanchego dep if: ${{ github.event_name == 'workflow_dispatch' }} @@ -134,7 +138,7 @@ jobs: token: ${{ secrets.AVALANCHE_PAT }} - uses: actions/setup-go@v3 with: - go-version: '~1.20.8' + go-version: ${{ env.go_version }} check-latest: true - name: Run integration tests run: ./scripts/tests.integration.sh --use-network-fixture @@ -144,7 +148,8 @@ jobs: if: always() with: name: tmpnet-integration-data - path: ~/.tmpnet/networks/1000 + path: ${{ env.tmpnet_data_path }} + if-no-files-found: error avalanchego_e2e: name: AvalancheGo E2E Tests v${{ matrix.go }} (${{ matrix.os }}) @@ -164,7 +169,7 @@ jobs: token: ${{ secrets.AVALANCHE_PAT }} - uses: actions/setup-go@v5 with: - go-version: '~1.21.7' + go-version: ${{ env.go_version }} check-latest: true - name: Run e2e tests run: E2E_SERIAL=1 ./scripts/tests.e2e.sh @@ -174,4 +179,5 @@ jobs: if: always() with: name: tmpnet-e2e-data - path: ~/.tmpnet/networks/1000 + path: ${{ env.tmpnet_data_path }} + if-no-files-found: error diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index 89d3985900..000696e8b6 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -84,9 +84,7 @@ func (v *vmFixture) IssueImportTx( <-v.issuer - height := v.buildAndAcceptBlockForTx(context.Background(), importTx) - - v.checkAtomicTxIndexing(importTx, height) + v.buildAndAcceptBlockForTx(context.Background(), importTx) return importTx } @@ -107,14 +105,12 @@ func (v *vmFixture) IssueExportTx( <-v.issuer - height := v.buildAndAcceptBlockForTx(context.Background(), exportTx) - - v.checkAtomicTxIndexing(exportTx, height) + v.buildAndAcceptBlockForTx(context.Background(), exportTx) return exportTx } -func (v *vmFixture) buildAndAcceptBlockForTx(ctx context.Context, tx *Tx) uint64 { +func (v *vmFixture) buildAndAcceptBlockForTx(ctx context.Context, tx *Tx) { require := v.require blk, err := v.vm.BuildBlock(ctx) @@ -144,7 +140,8 @@ func (v *vmFixture) buildAndAcceptBlockForTx(ctx context.Context, tx *Tx) uint64 require.Zero(len(logs)) v.height += uint64(1) - return v.height + + v.checkAtomicTxIndexing(tx, v.height) } func (v *vmFixture) checkAtomicTxIndexing(tx *Tx, expectedHeight uint64) { From 3d7070eb27ce75f35951bf0ebbae16318dd14432 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Wed, 3 Jan 2024 10:24:03 -0800 Subject: [PATCH 32/39] fixup: Fix broken unit test --- plugin/evm/shared_test_vm.go | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/evm/shared_test_vm.go b/plugin/evm/shared_test_vm.go index 1246fee6d5..a4380fea86 100644 --- a/plugin/evm/shared_test_vm.go +++ b/plugin/evm/shared_test_vm.go @@ -200,6 +200,7 @@ func GenesisVM(t require.TestingT, *atomic.Memory, *engCommon.SenderTest) { vm := &VM{} + vm.p2pSender = &engCommon.FakeSender{} ctx, db, genesisBytes, issuer, m := setupGenesis(t, genesisJSON) appSender := &engCommon.SenderTest{T: t} appSender.CantSendAppGossip = true From 0736144aa6895740872e862b2a73b295a70065b8 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Mon, 8 Jan 2024 13:51:20 +0100 Subject: [PATCH 33/39] fixup: Add CheckBootstrapIsPossible until available in tagged release --- tests/integration/shared_network_fixture.go | 33 ++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index d5276b08c8..c7e90b4cd8 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "math/big" + "os" "strings" ethcommon "github.com/ethereum/go-ethereum/common" @@ -18,6 +19,7 @@ import ( "github.com/ava-labs/avalanchego/api/info" "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/tests" "github.com/ava-labs/avalanchego/tests/fixture/e2e" "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" "github.com/ava-labs/avalanchego/utils/constants" @@ -54,7 +56,7 @@ func (f *sharedNetworkFixture) Teardown() { if !ginkgo.CurrentSpecReport().Failed() { // Only check if bootstrap is possible for passing tests // TODO(marun) Ensure this is safe to perform on teardown. Currently it uses DeferCleanup to stop the node. - e2e.CheckBootstrapIsPossible(e2e.Env.GetNetwork()) + CheckBootstrapIsPossible(e2e.Env.GetNetwork()) // TODO(marun) Allow node restart to be skipped just like the bootstrap check (to allow for parallel execution and faster dev iteration) ginkgo.By(fmt.Sprintf("checking if restart of %q is possible with current network state", f.nodeURI.NodeID)) @@ -220,3 +222,32 @@ func getChainAlias(chainID ids.ID) string { } return "X" } + +// TODO(marun) Remove when e2e.CheckBootstrapIsPossible is available in a tagged release of avalanchego +func CheckBootstrapIsPossible(network *tmpnet.Network) { + require := require.New(ginkgo.GinkgoT()) + + if len(os.Getenv(e2e.SkipBootstrapChecksEnvName)) > 0 { + tests.Outf("{{yellow}}Skipping bootstrap check due to the %s env var being set", e2e.SkipBootstrapChecksEnvName) + return + } + ginkgo.By("checking if bootstrap is possible with the current network state") + + ctx, cancel := context.WithTimeout(context.Background(), e2e.DefaultTimeout) + defer cancel() + + node, err := network.AddEphemeralNode(ctx, ginkgo.GinkgoWriter, tmpnet.FlagsMap{}) + // AddEphemeralNode will initiate node stop if an error is encountered during start, + // so no further cleanup effort is required if an error is seen here. + require.NoError(err) + + // Ensure the node is always stopped at the end of the check + defer func() { + ctx, cancel = context.WithTimeout(context.Background(), e2e.DefaultTimeout) + defer cancel() + require.NoError(node.Stop(ctx)) + }() + + // Check that the node becomes healthy within timeout + require.NoError(tmpnet.WaitForHealthy(ctx, node)) +} From a3c9b315eaec5209def7f4c422c2da7f8c994917 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 12 Jan 2024 18:12:51 +0100 Subject: [PATCH 34/39] fixup: Update to use network.StartNode for teardown check --- tests/integration/shared_network_fixture.go | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tests/integration/shared_network_fixture.go b/tests/integration/shared_network_fixture.go index c7e90b4cd8..9662859d92 100644 --- a/tests/integration/shared_network_fixture.go +++ b/tests/integration/shared_network_fixture.go @@ -8,7 +8,6 @@ import ( "fmt" "math/big" "os" - "strings" ethcommon "github.com/ethereum/go-ethereum/common" @@ -17,7 +16,6 @@ import ( "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/api/info" - "github.com/ava-labs/avalanchego/config" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/tests" "github.com/ava-labs/avalanchego/tests/fixture/e2e" @@ -75,15 +73,7 @@ func (f *sharedNetworkFixture) Teardown() { defer cancel() f.require.NoError(targetNode.Stop(ctx)) - // TODO(marun) Update to use Network.StartNode which handles bootstrap setup automatically once https://github.com/ava-labs/avalanchego/pull/2464 merges - bootstrapIPs, bootstrapIDs, err := network.GetBootstrapIPsAndIDs() - f.require.NoError(err) - f.require.NotEmpty(bootstrapIDs) - targetNode.Flags[config.BootstrapIDsKey] = strings.Join(bootstrapIDs, ",") - targetNode.Flags[config.BootstrapIPsKey] = strings.Join(bootstrapIPs, ",") - f.require.NoError(targetNode.Write()) - - f.require.NoError(targetNode.Start(ginkgo.GinkgoWriter)) + f.require.NoError(network.StartNode(ctx, ginkgo.GinkgoWriter, targetNode)) ginkgo.By(fmt.Sprintf("waiting for node %q to report healthy after restart", targetNode.NodeID)) e2e.WaitForHealthy(targetNode) From a988f8648b2e4931f118433c0a7e9b68b419de08 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 12 Jan 2024 19:28:31 +0100 Subject: [PATCH 35/39] fixup: Simplify fixture teardown registration --- tests/integration/fixture.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/integration/fixture.go b/tests/integration/fixture.go index d1753b11d4..293763fe34 100644 --- a/tests/integration/fixture.go +++ b/tests/integration/fixture.go @@ -49,9 +49,7 @@ func GetFixture() IntegrationFixture { // e2e.Env being non-nil indicates availability of shared network fixture fixture = newSharedNetworkFixture(ginkgo.GinkgoT()) } - ginkgo.DeferCleanup(func() { - fixture.Teardown() - }) + ginkgo.DeferCleanup(fixture.Teardown) return fixture } From e9ba3d792e8911674c8a25310f6bc0e2d876d9b3 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Fri, 12 Jan 2024 20:13:26 +0100 Subject: [PATCH 36/39] fixup: Respond to review feedback --- plugin/evm/shared_test_vm.go | 5 ++--- plugin/evm/shared_test_vm_fixture.go | 9 +++------ tests/integration/vm/atomic_tx.go | 6 ++++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/plugin/evm/shared_test_vm.go b/plugin/evm/shared_test_vm.go index a4380fea86..f048fef335 100644 --- a/plugin/evm/shared_test_vm.go +++ b/plugin/evm/shared_test_vm.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/api/keystore" @@ -219,8 +218,8 @@ func GenesisVM(t require.TestingT, require.NoError(t, err) if finishBootstrapping { - assert.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping)) - assert.NoError(t, vm.SetState(context.Background(), snow.NormalOp)) + require.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping)) + require.NoError(t, vm.SetState(context.Background(), snow.NormalOp)) } return issuer, vm, db, m, appSender diff --git a/plugin/evm/shared_test_vm_fixture.go b/plugin/evm/shared_test_vm_fixture.go index 000696e8b6..fec6644526 100644 --- a/plugin/evm/shared_test_vm_fixture.go +++ b/plugin/evm/shared_test_vm_fixture.go @@ -13,7 +13,6 @@ import ( ginkgo "github.com/onsi/ginkgo/v2" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ava-labs/avalanchego/ids" @@ -31,7 +30,6 @@ var ( type vmFixture struct { require *require.Assertions - assert *assert.Assertions preFundedKey *secp256k1.PrivateKey vm *VM issuer chan engCommon.Message @@ -50,7 +48,6 @@ func CreateVMFixture(t require.TestingT) *vmFixture { return &vmFixture{ require: require, - assert: assert.New(t), preFundedKey: preFundedKey, vm: vm, issuer: issuer, @@ -148,9 +145,9 @@ func (v *vmFixture) checkAtomicTxIndexing(tx *Tx, expectedHeight uint64) { // Check that the atomic transactions were indexed as expected. indexedTx, status, height, err := v.vm.getAtomicTx(tx.ID()) v.require.NoError(err) - v.assert.Equal(Accepted, status) - v.assert.Equal(expectedHeight, height, "unexpected height") - v.assert.Equal(indexedTx.ID(), tx.ID(), "expected ID of indexed tx to match original txID") + v.require.Equal(Accepted, status) + v.require.Equal(expectedHeight, height, "unexpected height") + v.require.Equal(indexedTx.ID(), tx.ID(), "expected ID of indexed tx to match original txID") } // Determine the chain alias for a chainID representing either the X- or P-Chain. diff --git a/tests/integration/vm/atomic_tx.go b/tests/integration/vm/atomic_tx.go index 2a65369919..404cea0b59 100644 --- a/tests/integration/vm/atomic_tx.go +++ b/tests/integration/vm/atomic_tx.go @@ -33,8 +33,10 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { recipientEthAddress := evm.GetEthAddress(recipientKey) tests.Outf("{{blue}} using recipient address: %+v{{/}}\n", recipientEthAddress) + xChainID := f.GetXChainID() + _ = f.IssueImportTx( - f.GetXChainID(), + xChainID, importAmount, recipientEthAddress, []*secp256k1.PrivateKey{ @@ -45,7 +47,7 @@ var _ = ginkgo.Describe("[VM] [Atomic TX]", func() { _ = f.IssueExportTx( f.GetAVAXAssetID(), exportAmount, - f.GetXChainID(), + xChainID, recipientKey.Address(), []*secp256k1.PrivateKey{ recipientKey, From 71176addfd36608434ce8b94119d7b46941597d0 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 14 Mar 2024 20:28:33 -0700 Subject: [PATCH 37/39] fixup: Fix compilation errors and reconcile changes to vm_test.go --- plugin/evm/shared_test_vm.go | 40 +++++++++++++-------------- tests/integration/integration_test.go | 3 +- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/plugin/evm/shared_test_vm.go b/plugin/evm/shared_test_vm.go index f048fef335..d1d712bd0f 100644 --- a/plugin/evm/shared_test_vm.go +++ b/plugin/evm/shared_test_vm.go @@ -19,7 +19,7 @@ import ( "github.com/ava-labs/avalanchego/database/prefixdb" "github.com/ava-labs/avalanchego/ids" "github.com/ava-labs/avalanchego/snow" - engCommon "github.com/ava-labs/avalanchego/snow/engine/common" + commonEng "github.com/ava-labs/avalanchego/snow/engine/common" "github.com/ava-labs/avalanchego/snow/validators" "github.com/ava-labs/avalanchego/utils/cb58" "github.com/ava-labs/avalanchego/utils/constants" @@ -156,7 +156,7 @@ func setupGenesis(t require.TestingT, ) (*snow.Context, database.Database, []byte, - chan engCommon.Message, + chan commonEng.Message, *atomic.Memory) { if len(genesisJSON) == 0 { genesisJSON = genesisJSONLatest @@ -166,24 +166,22 @@ func setupGenesis(t require.TestingT, baseDB := memdb.New() - m := atomic.NewMemory(prefixdb.New([]byte{0}, baseDB)) - ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID) + // initialize the atomic memory + atomicMemory := atomic.NewMemory(prefixdb.New([]byte{0}, baseDB)) + ctx.SharedMemory = atomicMemory.NewSharedMemory(ctx.ChainID) // NB: this lock is intentionally left locked when this function returns. // The caller of this function is responsible for unlocking. ctx.Lock.Lock() - userKeystore := keystore.New( - logging.NoLog{}, - memdb.New(), - ) + userKeystore := keystore.New(logging.NoLog{}, memdb.New()) err := userKeystore.CreateUser(username, password) require.NoError(t, err) ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID) - issuer := make(chan engCommon.Message, 1) + issuer := make(chan commonEng.Message, 1) prefixedDB := prefixdb.New([]byte{1}, baseDB) - return ctx, prefixedDB, genesisBytes, issuer, m + return ctx, prefixedDB, genesisBytes, issuer, atomicMemory } // GenesisVM creates a VM instance with the genesis test bytes and returns @@ -194,35 +192,35 @@ func GenesisVM(t require.TestingT, genesisJSON string, configJSON string, upgradeJSON string, -) (chan engCommon.Message, +) (chan commonEng.Message, *VM, database.Database, *atomic.Memory, - *engCommon.SenderTest) { + *commonEng.SenderTest) { vm := &VM{} - vm.p2pSender = &engCommon.FakeSender{} - ctx, db, genesisBytes, issuer, m := setupGenesis(t, genesisJSON) - appSender := &engCommon.SenderTest{T: t} + vm.p2pSender = &commonEng.FakeSender{} + ctx, dbManager, genesisBytes, issuer, m := setupGenesis(t, genesisJSON) + appSender := &commonEng.SenderTest{T: t} appSender.CantSendAppGossip = true - appSender.SendAppGossipF = func(context.Context, []byte) error { return nil } + appSender.SendAppGossipF = func(context.Context, commonEng.SendConfig, []byte) error { return nil } err := vm.Initialize( context.Background(), ctx, - db, + dbManager, genesisBytes, []byte(upgradeJSON), []byte(configJSON), issuer, - []*engCommon.Fx{}, + []*commonEng.Fx{}, appSender, ) - require.NoError(t, err) + require.NoError(t, err, "error initializing GenesisVM") if finishBootstrapping { require.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping)) require.NoError(t, vm.SetState(context.Background(), snow.NormalOp)) } - return issuer, vm, db, m, appSender + return issuer, vm, dbManager, m, appSender } func addUTXO(sharedMemory *atomic.Memory, ctx *snow.Context, txID ids.ID, index uint32, assetID ids.ID, amount uint64, addr ids.ShortID) (*avax.UTXO, error) { @@ -263,7 +261,7 @@ func addUTXO(sharedMemory *atomic.Memory, ctx *snow.Context, txID ids.ID, index // GenesisVMWithUTXOs creates a GenesisVM and generates UTXOs in the X-Chain Shared Memory containing AVAX based on the [utxos] map // Generates UTXOIDs by using a hash of the address in the [utxos] map such that the UTXOs will be generated deterministically. // If [genesisJSON] is empty, defaults to using [genesisJSONLatest] -func GenesisVMWithUTXOs(t require.TestingT, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, utxos map[ids.ShortID]uint64) (chan engCommon.Message, *VM, database.Database, *atomic.Memory, *engCommon.SenderTest) { +func GenesisVMWithUTXOs(t require.TestingT, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, utxos map[ids.ShortID]uint64) (chan commonEng.Message, *VM, database.Database, *atomic.Memory, *commonEng.SenderTest) { require := require.New(t) issuer, vm, db, sharedMemory, sender := GenesisVM(t, finishBootstrapping, genesisJSON, configJSON, upgradeJSON) for addr, avaxAmount := range utxos { diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index b3dad8d295..1a85cf69d3 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -12,6 +12,7 @@ import ( "github.com/onsi/gomega" "github.com/ava-labs/avalanchego/tests/fixture/e2e" + "github.com/ava-labs/avalanchego/tests/fixture/tmpnet" // ensure test packages are scanned by ginkgo _ "github.com/ava-labs/coreth/tests/integration/vm" @@ -41,7 +42,7 @@ func init() { var _ = ginkgo.SynchronizedBeforeSuite(func() []byte { if useNetworkFixture { // Run only once in the first ginkgo process - return e2e.NewTestEnvironment(flagVars).Marshal() + return e2e.NewTestEnvironment(flagVars, &tmpnet.Network{}).Marshal() } return nil }, func(envBytes []byte) { From 2036a23556e42e71def2b240933045dc7542f7f4 Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 14 Mar 2024 20:50:13 -0700 Subject: [PATCH 38/39] fixup: ensure consistent go version in ci --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ef6dba0bf..be96b4bed3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ on: default: 'master' env: - go_version: '~1.20.12' + go_version: '~1.21.7' tmpnet_data_path: ~/.tmpnet/networks/1000 jobs: @@ -72,7 +72,7 @@ jobs: token: ${{ secrets.AVALANCHE_PAT }} - uses: actions/setup-go@v5 with: - go-version: '~1.21.7' + go-version: ${{ env.go_version }} check-latest: true - name: change avalanchego dep if: ${{ github.event_name == 'workflow_dispatch' }} @@ -107,7 +107,7 @@ jobs: token: ${{ secrets.AVALANCHE_PAT }} - uses: actions/setup-go@v5 with: - go-version: '~1.21.7' + go-version: ${{ env.go_version }} check-latest: true - name: change avalanchego dep if: ${{ github.event_name == 'workflow_dispatch' }} From 7aa10c6e2773cfe1b643cc0abbf6c45f2fd3b78e Mon Sep 17 00:00:00 2001 From: Maru Newby Date: Thu, 14 Mar 2024 22:50:49 -0700 Subject: [PATCH 39/39] fixup: Address shellcheck issues --- scripts/tests.integration.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/tests.integration.sh b/scripts/tests.integration.sh index 0a3cbeb937..ac29111ad8 100755 --- a/scripts/tests.integration.sh +++ b/scripts/tests.integration.sh @@ -16,9 +16,10 @@ fi export AVALANCHEGO_CLONE_PATH="${AVALANCHEGO_CLONE_PATH:-avalanchego}" # Only build avalanchego if using the network fixture -if [[ "$@" =~ "--use-network-fixture" ]]; then +if [[ "$*" =~ "--use-network-fixture" ]]; then ./scripts/build_avalanchego.sh - export AVALANCHEGO_PATH="$(realpath ${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego})" + AVALANCHEGO_PATH="$(realpath "${AVALANCHEGO_PATH:-${AVALANCHEGO_CLONE_PATH}/build/avalanchego}")" + export AVALANCHEGO_PATH fi # Ensure blst configuration