diff --git a/CHANGELOG.md b/CHANGELOG.md index 47734f671..e0bb671c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ - [\#659](https://github.com/cosmos/evm/pull/659) Move configs out of EVMD and deduplicate configs - [\#664](https://github.com/cosmos/evm/pull/664) Add EIP-7702 integration test - [\#684](https://github.com/cosmos/evm/pull/684) Add unit test cases for EIP-7702 +- [\#685](https://github.com/cosmos/evm/pull/685) Add EIP-7702 e2e test ### FEATURES diff --git a/tests/jsonrpc/simulator/simulator b/tests/jsonrpc/simulator/simulator new file mode 100755 index 000000000..43c7f0b0f Binary files /dev/null and b/tests/jsonrpc/simulator/simulator differ diff --git a/tests/systemtests/README.md b/tests/systemtests/README.md index d8d9c3c64..8f620b2d9 100644 --- a/tests/systemtests/README.md +++ b/tests/systemtests/README.md @@ -44,7 +44,14 @@ go test -p 1 -parallel 1 -mod=readonly -tags='system_test' -v ./... \ --run TestExceptions --verbose --binary evmd --block-time 5s --chain-id local-4221 ``` -## Run Entire test +### Run EIP-7702 test + +```shell +go test -p 1 -mod=readonly -tags='system_test' -v ./... \ +--run TestEIP7702 --verbose --binary evmd --block-time 3s --chain-id local-4221 +``` + +## Run all tests ```shell make test diff --git a/tests/systemtests/accountabstraction/interface.go b/tests/systemtests/accountabstraction/interface.go new file mode 100644 index 000000000..5314215c8 --- /dev/null +++ b/tests/systemtests/accountabstraction/interface.go @@ -0,0 +1,31 @@ +package accountabstraction + +import ( + "crypto/ecdsa" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" +) + +type AccountAbstractionTestSuite interface { + // Lifecycle + SetupTest(t *testing.T) + WaitForCommit(txHash common.Hash) + + // Query helpers + GetChainID() uint64 + GetNonce(accID string) uint64 + GetPrivKey(accID string) *ecdsa.PrivateKey + GetAddr(accID string) common.Address + GetCounterAddr() common.Address + + // Transactions + SendSetCodeTx(accID string, signedAuth ...ethtypes.SetCodeAuthorization) (common.Hash, error) + InvokeCounter(accID string, method string, args ...interface{}) (common.Hash, error) + + // Verification + CheckSetCode(authorityAccID string, delegate common.Address, expectDelegation bool) + QueryCounterNumber(accID string) (*big.Int, error) +} diff --git a/tests/systemtests/accountabstraction/test_eip7702.go b/tests/systemtests/accountabstraction/test_eip7702.go new file mode 100644 index 000000000..da81a07f4 --- /dev/null +++ b/tests/systemtests/accountabstraction/test_eip7702.go @@ -0,0 +1,242 @@ +package accountabstraction + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/ginkgo/v2" + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/gomega" +) + +func TestEIP7702(t *testing.T) { + const ( + user0 = "acc0" + user1 = "acc1" + ) + + Describe("test EIP-7702 scenorios", Ordered, func() { + var ( + s AccountAbstractionTestSuite + ) + + // We intentionally use BeforeAll instead of BeforeAll because, + // The test takes too much time if we restart network for each test case. + BeforeAll(func() { + s = NewTestSuite(t) + s.SetupTest(t) + }) + + AfterEach(func() { + // Reset code of EoAs to 0x0 address + // + // We set user0's authorization nonce to currentNonce + 1 + // because user0 will also send the SetCode transaction. + // Since the sender’s nonce is incremented before applying authorization, + // the SetCodeAuthorization must use currentNonce + 1. + user0Nonce := s.GetNonce(user0) + 1 + cleanupAuth0 := createSetCodeAuthorization(s.GetChainID(), user0Nonce, common.Address{}) + signedCleanup0, signErr := signSetCodeAuthorization(s.GetPrivKey(user0), cleanupAuth0) + Expect(signErr).To(BeNil()) + + user1Nonce := s.GetNonce(user1) + cleanupAuth1 := createSetCodeAuthorization(s.GetChainID(), user1Nonce, common.Address{}) + signedCleanup1, signErr := signSetCodeAuthorization(s.GetPrivKey(user1), cleanupAuth1) + Expect(signErr).To(BeNil()) + + txHash, err := s.SendSetCodeTx(user0, signedCleanup0, signedCleanup1) + Expect(err).To(BeNil(), "error while clearing SetCode delegation") + + s.WaitForCommit(txHash) + s.CheckSetCode(user0, common.Address{}, false) + s.CheckSetCode(user1, common.Address{}, false) + }) + + type testCase struct { + authChainID func() uint64 + authNonce func() uint64 + authAddress func() common.Address + authSigner string + txSender string + expDelegation bool + } + + DescribeTable("SetCode authorization scenarios", func(tc testCase) { + authorization := createSetCodeAuthorization(tc.authChainID(), tc.authNonce(), tc.authAddress()) + signedAuthorization, err := signSetCodeAuthorization(s.GetPrivKey(tc.authSigner), authorization) + Expect(err).To(BeNil()) + + txHash, err := s.SendSetCodeTx(tc.txSender, signedAuthorization) + Expect(err).To(BeNil(), "error while sending SetCode tx") + s.WaitForCommit(txHash) + s.CheckSetCode(tc.authSigner, tc.authAddress(), tc.expDelegation) + }, + Entry("setCode with invalid chainID should fail", testCase{ + authChainID: func() uint64 { return s.GetChainID() + 1 }, + authNonce: func() uint64 { + return s.GetNonce(user0) + 1 + }, + authAddress: func() common.Address { + return s.GetCounterAddr() + }, + authSigner: user0, + txSender: user0, + expDelegation: false, + }), + Entry("setCode with empty address should reset delegation", testCase{ + authChainID: func() uint64 { return s.GetChainID() + 1 }, + authNonce: func() uint64 { + return s.GetNonce(user0) + 1 + }, + authAddress: func() common.Address { + return common.HexToAddress("0x0") + }, + authSigner: user0, + txSender: user0, + expDelegation: false, + }), + Entry("setCode with invalid address should fail", testCase{ + authChainID: func() uint64 { return s.GetChainID() + 1 }, + authNonce: func() uint64 { + return s.GetNonce(user0) + 1 + }, + authAddress: func() common.Address { + return common.BytesToAddress([]byte("invalid")) + }, + authSigner: user0, + txSender: user0, + expDelegation: false, + }), + Entry("setCode with EoA address should fail", testCase{ + authChainID: func() uint64 { return s.GetChainID() + 1 }, + authNonce: func() uint64 { + return s.GetNonce(user0) + 1 + }, + authAddress: func() common.Address { + return s.GetAddr(user1) + }, + authSigner: user0, + txSender: user0, + expDelegation: false, + }), + Entry("same signer/sender with matching nonce should fail", testCase{ + authChainID: func() uint64 { return s.GetChainID() }, + authNonce: func() uint64 { + return s.GetNonce(user0) + }, + authAddress: func() common.Address { + return s.GetCounterAddr() + }, + authSigner: user0, + txSender: user0, + expDelegation: false, + }), + Entry("same signer/sender with future nonce sholud succeed", testCase{ + authChainID: func() uint64 { return s.GetChainID() }, + authNonce: func() uint64 { + return s.GetNonce(user0) + 1 + }, + authAddress: func() common.Address { + return s.GetCounterAddr() + }, + authSigner: user0, + txSender: user0, + expDelegation: true, + }), + Entry("different signer/sender with current nonce should succeed", testCase{ + authChainID: func() uint64 { return s.GetChainID() }, + authNonce: func() uint64 { + return s.GetNonce(user1) + }, + authAddress: func() common.Address { + return s.GetCounterAddr() + }, + authSigner: user1, + txSender: user0, + expDelegation: true, + }), + Entry("different signer/sender with future nonce should fail", testCase{ + authChainID: func() uint64 { return s.GetChainID() }, + authNonce: func() uint64 { + return s.GetNonce(user1) + 1 + }, + authAddress: func() common.Address { + return s.GetCounterAddr() + }, + authSigner: user1, + txSender: user0, + expDelegation: false, + }), + ) + + Describe("executes counter contract methods via delegated account", func() { + Context("when delegation is active", func() { + It("should succeed", func() { + counterAddr := s.GetCounterAddr() + + chainID := s.GetChainID() + authorization := createSetCodeAuthorization(chainID, s.GetNonce(user0)+1, counterAddr) + signedAuthorization, err := signSetCodeAuthorization(s.GetPrivKey(user0), authorization) + Expect(err).To(BeNil()) + + txHash, err := s.SendSetCodeTx(user0, signedAuthorization) + Expect(err).To(BeNil(), "error while sending SetCode tx") + s.WaitForCommit(txHash) + s.CheckSetCode(user0, counterAddr, true) + + txHash, err = s.InvokeCounter(user0, "setNumber", big.NewInt(0)) + Expect(err).To(BeNil(), "failed to reset counter") + s.WaitForCommit(txHash) + + txHash, err = s.InvokeCounter(user0, "increment") + Expect(err).To(BeNil(), "failed to increment counter") + s.WaitForCommit(txHash) + + value, err := s.QueryCounterNumber(user0) + Expect(err).To(BeNil(), "failed to query counter value") + Expect(value.Uint64()).To(Equal(uint64(1))) + }) + }) + + Context("after delegation has been revoked", func() { + It("should no longer execute counter methods", func() { + counterAddr := s.GetCounterAddr() + chainID := s.GetChainID() + + authorization := createSetCodeAuthorization(chainID, s.GetNonce(user0)+1, counterAddr) + signedAuthorization, err := signSetCodeAuthorization(s.GetPrivKey(user0), authorization) + Expect(err).To(BeNil()) + + txHash, err := s.SendSetCodeTx(user0, signedAuthorization) + Expect(err).To(BeNil(), "error while sending SetCode tx") + s.WaitForCommit(txHash) + s.CheckSetCode(user0, counterAddr, true) + + cleanup := createSetCodeAuthorization(chainID, s.GetNonce(user0)+1, common.Address{}) + signedCleanup, err := signSetCodeAuthorization(s.GetPrivKey(user0), cleanup) + Expect(err).To(BeNil()) + + txHash, err = s.SendSetCodeTx(user0, signedCleanup) + Expect(err).To(BeNil(), "error while clearing SetCode delegation") + s.WaitForCommit(txHash) + s.CheckSetCode(user0, common.Address{}, false) + + txHash, err = s.InvokeCounter(user0, "increment") + Expect(err).To(BeNil(), "counter invocation tx should be accepted but do nothing") + s.WaitForCommit(txHash) + + value, err := s.QueryCounterNumber(user0) + Expect(err).To(BeNil(), "failed to query counter value after revocation") + Expect(value.Uint64()).To(Equal(uint64(0)), "counter value should remain unchanged without delegation") + }) + }) + }) + }) + + // Run Ginkgo integration tests + RegisterFailHandler(Fail) + RunSpecs(t, "EIP7702 Integration Test Suite") +} diff --git a/tests/systemtests/accountabstraction/test_suite.go b/tests/systemtests/accountabstraction/test_suite.go new file mode 100644 index 000000000..185231240 --- /dev/null +++ b/tests/systemtests/accountabstraction/test_suite.go @@ -0,0 +1,267 @@ +package accountabstraction + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "path/filepath" + "testing" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/holiman/uint256" + + //nolint:revive // dot imports are fine for Ginkgo + . "github.com/onsi/gomega" + + basesuite "github.com/cosmos/evm/tests/systemtests/suite" + "github.com/stretchr/testify/require" +) + +type TestSuite struct { + *basesuite.SystemTestSuite + + counterAddress common.Address + counterABI abi.ABI +} + +func NewTestSuite(t *testing.T) *TestSuite { + return &TestSuite{ + SystemTestSuite: basesuite.NewSystemTestSuite(t), + } +} + +// SetupTest setup test suite and deploy test contracts +func (s *TestSuite) SetupTest(t *testing.T) { + s.SystemTestSuite.SetupTest(t) + + counterPath := filepath.Join("..", "Counter", "out", "Counter.sol", "Counter.json") + bytecode, err := loadContractCreationBytecode(counterPath) + Expect(err).To(BeNil(), "failed to load counter creation bytecode") + + addr, err := deployContract(s.EthClient, bytecode) + require.NoError(t, err, "failed to deploy counter contract") + s.counterAddress = addr + + counterABI, err := loadContractABI(counterPath) + Expect(err).To(BeNil(), "failed to load counter contract abi") + s.counterABI = counterABI +} + +// WaitForCommit waits for a commit of given transaction +func (s *TestSuite) WaitForCommit(txHash common.Hash) { + _, err := s.EthClient.WaitForCommit("node0", txHash.Hex(), time.Second*10) + Expect(err).To(BeNil()) +} + +// GetChainID returns chain id of test network +func (s *TestSuite) GetChainID() uint64 { + return s.EthClient.ChainID.Uint64() +} + +// GetNonce returns current nonce of account +func (s *TestSuite) GetNonce(accID string) uint64 { + nonce, err := s.NonceAt("node0", accID) + Expect(err).To(BeNil()) + return nonce +} + +// GetSequence returns the Cosmos account sequence for the given account ID. +func (s *TestSuite) GetSequence(accID string) uint64 { + cosmosAcc := s.CosmosClient.Accs[accID] + ctx := s.CosmosClient.ClientCtx.WithClient(s.CosmosClient.RpcClients["node0"]) + account, err := ctx.AccountRetriever.GetAccount(ctx, cosmosAcc.AccAddress) + Expect(err).To(BeNil(), "unable to retrieve cosmos account for %s", accID) + return account.GetSequence() +} + +// GetPrivKey returns ecdsa private key of account +func (s *TestSuite) GetPrivKey(accID string) *ecdsa.PrivateKey { + return s.EthClient.Accs[accID].PrivKey +} + +// GetAddr returns ethereum address of account +func (s *TestSuite) GetAddr(accID string) common.Address { + return s.EthClient.Accs[accID].Address +} + +// GetCounterAddr returns the deployed counter contract address. +func (s *TestSuite) GetCounterAddr() common.Address { + return s.counterAddress +} + +// SendSetCodeTx sends SetCodeTx +func (s *TestSuite) SendSetCodeTx(accID string, signedAuths ...ethtypes.SetCodeAuthorization) (common.Hash, error) { + ctx := context.Background() + ethCli := s.EthClient.Clients["node0"] + acc := s.EthClient.Accs[accID] + if acc == nil { + return common.Hash{}, fmt.Errorf("account %s not found", accID) + } + key := acc.PrivKey + + chainID, err := ethCli.ChainID(ctx) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to get evm chain id") + } + + fromAddr := acc.Address + nonce, err := ethCli.PendingNonceAt(ctx, fromAddr) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to fetch pending nonce: %w", err) + } + + txdata := ðtypes.SetCodeTx{ + ChainID: uint256.MustFromBig(chainID), + Nonce: nonce, + GasTipCap: uint256.NewInt(1_000_000), + GasFeeCap: uint256.NewInt(1_000_000_000), + Gas: 100_000, + To: common.Address{}, + Value: uint256.NewInt(0), + Data: []byte{}, + AccessList: ethtypes.AccessList{}, + AuthList: signedAuths, + } + + signer := ethtypes.LatestSignerForChainID(chainID) + signedTx := ethtypes.MustSignNewTx(key, signer, txdata) + + if err := ethCli.SendTransaction(ctx, signedTx); err != nil { + return common.Hash{}, fmt.Errorf("failed to send transaction: %w", err) + } + + return signedTx.Hash(), nil +} + +// CheckSetCode checks the account is EIP-7702 SetCode authorized. +func (s *TestSuite) CheckSetCode(authorityAccID string, delegate common.Address, expectDelegation bool) { + account := s.EthClient.Accs[authorityAccID] + Expect(account).ToNot(BeNil(), "account %s not found", authorityAccID) + + ctx := context.Background() + code, err := s.EthClient.Clients["node0"].CodeAt(ctx, account.Address, nil) + Expect(err).To(BeNil(), "unable to retrieve updated code for %s", authorityAccID) + + if expectDelegation { + // 3byte prefix + 20byte authorized contract address + Expect(len(code)).To(Equal(23), "expected delegation code for %s", authorityAccID) + resolvedAddr, ok := ethtypes.ParseDelegation(code) + Expect(ok).To(BeTrue(), "expected delegation prefix in code for %s", authorityAccID) + Expect(resolvedAddr).To(Equal(delegate), "unexpected delegate for %s", authorityAccID) + return + } else { + Expect(len(code)).To(Equal(0), "expected delegation code for %s", authorityAccID) + _, ok := ethtypes.ParseDelegation(code) + Expect(ok).To(BeFalse(), "expected delegation prefix in code for %s", authorityAccID) + } +} + +// InvokeCounter sends a transaction from the delegated account to execute a counter method. +func (s *TestSuite) InvokeCounter(accID string, method string, args ...interface{}) (common.Hash, error) { + account := s.EthClient.Accs[accID] + if account == nil { + return common.Hash{}, fmt.Errorf("account %s not found", accID) + } + + calldata, err := s.counterABI.Pack(method, args...) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to pack counter calldata: %w", err) + } + + ctx := context.Background() + ethCli := s.EthClient.Clients["node0"] + chainID, err := ethCli.ChainID(ctx) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to fetch chain id: %w", err) + } + + nonce, err := ethCli.PendingNonceAt(ctx, account.Address) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to fetch pending nonce: %w", err) + } + + gasTipCap := big.NewInt(1_000_000) + gasFeeCap := big.NewInt(1_000_000_000) + gasLimit := uint64(500_000) + + to := account.Address + txData := ðtypes.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + GasTipCap: gasTipCap, + GasFeeCap: gasFeeCap, + Gas: gasLimit, + To: &to, + Value: big.NewInt(0), + Data: calldata, + } + + signer := ethtypes.LatestSignerForChainID(chainID) + signedTx, err := ethtypes.SignNewTx(account.PrivKey, signer, txData) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to sign counter tx: %w", err) + } + + if err := ethCli.SendTransaction(ctx, signedTx); err != nil { + return common.Hash{}, fmt.Errorf("failed to send counter tx: %w", err) + } + + receipt, err := s.EthClient.WaitForCommit("node0", signedTx.Hash().Hex(), time.Second*10) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to fetch counter tx receipt: %w", err) + } + if receipt.Status != 1 { + return common.Hash{}, fmt.Errorf("counter tx reverted: %s", signedTx.Hash()) + } + + return signedTx.Hash(), nil +} + +// QueryCounterNumber queries the delegated counter contract via the account code. +func (s *TestSuite) QueryCounterNumber(accID string) (*big.Int, error) { + account := s.EthClient.Accs[accID] + if account == nil { + return nil, fmt.Errorf("account %s not found", accID) + } + + calldata, err := s.counterABI.Pack("number") + if err != nil { + return nil, fmt.Errorf("failed to pack counter number calldata: %w", err) + } + + ctx := context.Background() + ethCli := s.EthClient.Clients["node0"] + callMsg := ethereum.CallMsg{ + From: account.Address, + To: &account.Address, + Data: calldata, + } + + output, err := ethCli.CallContract(ctx, callMsg, nil) + if err != nil { + return nil, fmt.Errorf("failed to call counter contract: %w", err) + } + if len(output) == 0 { + return big.NewInt(0), nil + } + + values, err := s.counterABI.Unpack("number", output) + if err != nil { + return nil, fmt.Errorf("failed to unpack counter result: %w", err) + } + if len(values) == 0 { + return nil, fmt.Errorf("counter query returned no values") + } + + value, ok := values[0].(*big.Int) + if !ok { + return nil, fmt.Errorf("unexpected counter return type %T", values[0]) + } + + return new(big.Int).Set(value), nil +} diff --git a/tests/systemtests/accountabstraction/test_utils.go b/tests/systemtests/accountabstraction/test_utils.go new file mode 100644 index 000000000..da1f007da --- /dev/null +++ b/tests/systemtests/accountabstraction/test_utils.go @@ -0,0 +1,150 @@ +package accountabstraction + +import ( + "context" + "crypto/ecdsa" + "encoding/hex" + "errors" + "fmt" + "math/big" + "os" + "path/filepath" + "runtime" + "strings" + "time" + + "github.com/cosmos/evm/tests/systemtests/clients" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/holiman/uint256" + "github.com/tidwall/gjson" +) + +func createSetCodeAuthorization(chainID, nonce uint64, contractAddr common.Address) ethtypes.SetCodeAuthorization { + return ethtypes.SetCodeAuthorization{ + ChainID: *uint256.NewInt(chainID), + Address: contractAddr, + Nonce: nonce, + } +} + +func signSetCodeAuthorization(key *ecdsa.PrivateKey, authorization ethtypes.SetCodeAuthorization) (ethtypes.SetCodeAuthorization, error) { + authorization, err := ethtypes.SignSetCode(key, authorization) + if err != nil { + return ethtypes.SetCodeAuthorization{}, fmt.Errorf("failed to sign set code authorization: %w", err) + } + + return authorization, nil +} + +func loadContractCreationBytecode(filePath string) ([]byte, error) { + _, caller, _, ok := runtime.Caller(0) + if !ok { + return nil, errors.New("failed to resolve caller for smart wallet artifact") + } + + artifactPath := filepath.Join(filepath.Dir(caller), filePath) + contents, err := os.ReadFile(filepath.Clean(artifactPath)) + if err != nil { + return nil, fmt.Errorf("failed to read smart wallet artifact: %w", err) + } + + bytecodeHex := gjson.GetBytes(contents, "bytecode.object").String() + if bytecodeHex == "" { + bytecodeHex = gjson.GetBytes(contents, "bytecode").String() + } + if bytecodeHex == "" { + return nil, errors.New("smart wallet artifact has empty creation bytecode") + } + + bytecodeHex = strings.TrimPrefix(bytecodeHex, "0x") + if bytecodeHex == "" { + return nil, errors.New("smart wallet artifact has empty creation bytecode") + } + + bytecode, err := hex.DecodeString(bytecodeHex) + if err != nil { + return nil, fmt.Errorf("failed to decode smart wallet bytecode: %w", err) + } + + return bytecode, nil +} + +func loadContractABI(filePath string) (abi.ABI, error) { + _, caller, _, ok := runtime.Caller(0) + if !ok { + return abi.ABI{}, errors.New("failed to resolve caller for contract artifact") + } + + artifactPath := filepath.Join(filepath.Dir(caller), filePath) + contents, err := os.ReadFile(filepath.Clean(artifactPath)) + if err != nil { + return abi.ABI{}, fmt.Errorf("failed to read contract artifact: %w", err) + } + + abiField := gjson.GetBytes(contents, "abi") + if !abiField.Exists() { + return abi.ABI{}, errors.New("contract artifact missing abi field") + } + + parsedABI, err := abi.JSON(strings.NewReader(abiField.Raw)) + if err != nil { + return abi.ABI{}, fmt.Errorf("failed to parse contract ABI: %w", err) + } + + return parsedABI, nil +} + +func deployContract(ethClient *clients.EthClient, creationBytecode []byte) (common.Address, error) { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + ethCli := ethClient.Clients["node0"] + deployer := ethClient.Accs["acc0"] + + chainID, err := ethCli.ChainID(ctx) + if err != nil { + return common.Address{}, fmt.Errorf("failed to fetch chain id: %w", err) + } + + nonce, err := ethCli.PendingNonceAt(ctx, deployer.Address) + if err != nil { + return common.Address{}, fmt.Errorf("failed to fetch pending nonce: %w", err) + } + + gasFeeCap := big.NewInt(20_000_000_000) + gasTipCap := big.NewInt(1_000_000_000) + gasLimit := uint64(3_000_000) + + txData := ðtypes.DynamicFeeTx{ + ChainID: chainID, + Nonce: nonce, + GasTipCap: gasTipCap, + GasFeeCap: gasFeeCap, + Gas: gasLimit, + Value: big.NewInt(0), + Data: creationBytecode, + } + + signer := ethtypes.LatestSignerForChainID(chainID) + signedTx, err := ethtypes.SignNewTx(deployer.PrivKey, signer, txData) + if err != nil { + return common.Address{}, fmt.Errorf("failed to sign contract deployment tx: %w", err) + } + + if err := ethCli.SendTransaction(ctx, signedTx); err != nil { + return common.Address{}, fmt.Errorf("failed to send contract deployment tx: %w", err) + } + + receipt, err := ethClient.WaitForCommit("node0", signedTx.Hash().Hex(), time.Second*10) + if err != nil { + return common.Address{}, fmt.Errorf("failed to fetch set code tx receipt: %w", err) + } + + if receipt.Status != 1 { + return common.Address{}, fmt.Errorf("set code tx reverted: %s", signedTx.Hash()) + } + + return receipt.ContractAddress, nil +} diff --git a/tests/systemtests/accountabstraction/types.go b/tests/systemtests/accountabstraction/types.go new file mode 100644 index 000000000..2ec3f2d67 --- /dev/null +++ b/tests/systemtests/accountabstraction/types.go @@ -0,0 +1,105 @@ +package accountabstraction + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/cosmos/evm/crypto/ethsecp256k1" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" +) + +type UserOperation struct { + Sender common.Address + Nonce *big.Int + InitCode []byte + CallData []byte + CallGasLimit *big.Int + VerificationGasLimit *big.Int + PreVerificationGas *big.Int + MaxFeePerGas *big.Int + MaxPriorityFeePerGas *big.Int + PaymasterAndData []byte + Signature []byte +} + +func NewUserOperation(sender common.Address, nonce uint64, calldata []byte) *UserOperation { + return &UserOperation{ + Sender: sender, + Nonce: big.NewInt(int64(nonce)), //#nosec G115 + InitCode: []byte{}, + CallData: calldata, + CallGasLimit: big.NewInt(100000), + VerificationGasLimit: big.NewInt(200000), + PreVerificationGas: big.NewInt(50000), + MaxFeePerGas: big.NewInt(900000000), + MaxPriorityFeePerGas: big.NewInt(100000000), + PaymasterAndData: []byte{}, + Signature: []byte{}, + } +} + +func SignUserOperation(userOp *UserOperation, entryPointAddr common.Address, privKey cryptotypes.PrivKey) (*UserOperation, error) { + chainID := uint64(4221) + + addressType, _ := abi.NewType("address", "", nil) + uint256Type, _ := abi.NewType("uint256", "", nil) + bytes32Type, _ := abi.NewType("bytes32", "", nil) + + args := abi.Arguments{ + {Type: addressType}, // sender + {Type: uint256Type}, // nonce + {Type: bytes32Type}, // keccak(initCode) + {Type: bytes32Type}, // keccak(callData) + {Type: uint256Type}, // callGasLimit + {Type: uint256Type}, // verificationGasLimit + {Type: uint256Type}, // preVerificationGas + {Type: uint256Type}, // maxFeePerGas + {Type: uint256Type}, // maxPriorityFeePerGas + {Type: bytes32Type}, // keccak(paymasterAndData) + {Type: addressType}, // entryPoint + {Type: uint256Type}, // chainId + } + + packed, err := args.Pack( + userOp.Sender, + userOp.Nonce, + crypto.Keccak256Hash(userOp.InitCode), + crypto.Keccak256Hash(userOp.CallData), + userOp.CallGasLimit, + userOp.VerificationGasLimit, + userOp.PreVerificationGas, + userOp.MaxFeePerGas, + userOp.MaxPriorityFeePerGas, + crypto.Keccak256Hash(userOp.PaymasterAndData), + entryPointAddr, + chainID, + ) + if err != nil { + return nil, fmt.Errorf("failed to pack arguments of UserOperation") + } + + userOpHash := crypto.Keccak256Hash(packed) + + ecdsaPrivKey, err := privKey.(*ethsecp256k1.PrivKey).ToECDSA() + if err != nil { + return nil, fmt.Errorf("failed to convert private key to ecdsa private key") + } + + signature, err := crypto.Sign(userOpHash.Bytes(), ecdsaPrivKey) + if err != nil { + return nil, fmt.Errorf("failed to sign user operationHash") + } + + // Transform V from 0/1 to 27/28 according to the yellow paper + if signature[64] < 27 { + signature[64] += 27 + } + + userOp.Signature = signature + return userOp, nil +} diff --git a/tests/systemtests/clients/ethclient.go b/tests/systemtests/clients/ethclient.go index c084e8b4d..4d3bd3e28 100644 --- a/tests/systemtests/clients/ethclient.go +++ b/tests/systemtests/clients/ethclient.go @@ -182,3 +182,25 @@ func extractTxHashesSorted(txMap map[string]map[string]*EthRPCTransaction) []str return result } + +func (ec *EthClient) CodeAt(nodeID, accID string) ([]byte, error) { + acc := ec.Accs[accID] + if acc == nil { + return nil, fmt.Errorf("account %s not found", accID) + } + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + blockNumber, err := ec.Clients[nodeID].BlockNumber(ctx) + if err != nil { + return nil, fmt.Errorf("failed to query block number: %w", err) + } + + code, err := ec.Clients[nodeID].CodeAt(ctx, acc.Address, big.NewInt(int64(blockNumber))) + if err != nil { + return nil, fmt.Errorf("failed to query code for %s: %w", accID, err) + } + + return code, nil +} diff --git a/tests/systemtests/go.mod b/tests/systemtests/go.mod index 76231a8b2..4364d367d 100644 --- a/tests/systemtests/go.mod +++ b/tests/systemtests/go.mod @@ -8,7 +8,10 @@ require ( github.com/cometbft/cometbft/v2 v2.0.0-rc1 github.com/cosmos/cosmos-sdk v0.54.0-rc.1 github.com/cosmos/evm v0.5.0-rc.0 - github.com/ethereum/go-ethereum v1.15.11 + github.com/ethereum/go-ethereum v1.16.3 + github.com/holiman/uint256 v1.3.2 + github.com/onsi/ginkgo/v2 v2.23.4 + github.com/onsi/gomega v1.38.0 github.com/stretchr/testify v1.10.0 github.com/test-go/testify v1.1.4 github.com/tidwall/gjson v1.18.0 @@ -83,6 +86,7 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect @@ -93,6 +97,7 @@ require ( github.com/google/flatbuffers v25.2.10+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect + github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect @@ -108,7 +113,6 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect - github.com/holiman/uint256 v1.3.2 // indirect github.com/huandu/skiplist v1.2.1 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect @@ -167,8 +171,10 @@ require ( go.opentelemetry.io/otel v1.36.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect go.opentelemetry.io/otel/trace v1.36.0 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.17.0 // indirect golang.org/x/crypto v0.41.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect @@ -177,6 +183,7 @@ require ( golang.org/x/sys v0.35.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect + golang.org/x/tools v0.36.0 // indirect google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect diff --git a/tests/systemtests/go.sum b/tests/systemtests/go.sum index cb2a24f64..2466d65f9 100644 --- a/tests/systemtests/go.sum +++ b/tests/systemtests/go.sum @@ -219,8 +219,6 @@ github.com/crate-crypto/go-eth-kzg v1.3.0 h1:05GrhASN9kDAidaFJOda6A4BEvgvuXbazXg github.com/crate-crypto/go-eth-kzg v1.3.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= -github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= -github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/creachadair/tomledit v0.0.28 h1:aQJVwcNTzx4SZ/tSbkyGE69w4YQ6Gn+xhHHKtqMZwuw= github.com/creachadair/tomledit v0.0.28/go.mod h1:pqb2HRQi0lMu6MBiUmTk/0XQ+SmPtq2QbUrG+eiLP5w= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -231,6 +229,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= @@ -277,8 +277,8 @@ github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfU github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/ethereum/c-kzg-4844/v2 v2.1.0 h1:gQropX9YFBhl3g4HYhwE70zq3IHFRgbbNPw0Shwzf5w= github.com/ethereum/c-kzg-4844/v2 v2.1.0/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= -github.com/ethereum/go-ethereum v1.15.11 h1:JK73WKeu0WC0O1eyX+mdQAVHUV+UR1a9VB/domDngBU= -github.com/ethereum/go-ethereum v1.15.11/go.mod h1:mf8YiHIb0GR4x4TipcvBUPxJLw1mFdmxzoDi11sDRoI= +github.com/ethereum/go-ethereum v1.16.3 h1:nDoBSrmsrPbrDIVLTkDQCy1U9KdHN+F2PzvMbDoS42Q= +github.com/ethereum/go-ethereum v1.16.3/go.mod h1:Lrsc6bt9Gm9RyvhfFK53vboCia8kpF9nv+2Ukntnl+8= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -287,6 +287,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= @@ -336,6 +338,8 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -356,8 +360,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= -github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -411,6 +415,8 @@ github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= +github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= @@ -598,6 +604,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -653,6 +661,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.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= 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= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= @@ -713,6 +723,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= @@ -908,6 +920,8 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -924,8 +938,8 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1095,6 +1109,8 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= +golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= 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= diff --git a/tests/systemtests/main_test.go b/tests/systemtests/main_test.go index 9bb4b2277..74c412db6 100644 --- a/tests/systemtests/main_test.go +++ b/tests/systemtests/main_test.go @@ -6,8 +6,31 @@ import ( "testing" "cosmossdk.io/systemtests" + "github.com/cosmos/evm/tests/systemtests/accountabstraction" + "github.com/cosmos/evm/tests/systemtests/mempool" ) func TestMain(m *testing.M) { systemtests.RunTests(m) } + +// Mempool Tests +func TestTxsOrdering(t *testing.T) { + mempool.TestTxsOrdering(t) +} + +func TestTxsReplacement(t *testing.T) { + mempool.TestTxsReplacement(t) + mempool.TestMixedTxsReplacementEVMAndCosmos(t) + mempool.TestMixedTxsReplacementLegacyAndDynamicFee(t) +} + +func TestExceptions(t *testing.T) { + mempool.TestTxRebroadcasting(t) + mempool.TestMinimumGasPricesZero(t) +} + +// Account Abstraction Tests +func TestEIP7702(t *testing.T) { + accountabstraction.TestEIP7702(t) +} diff --git a/tests/systemtests/mempool_test.go b/tests/systemtests/mempool_test.go deleted file mode 100644 index e342a65fc..000000000 --- a/tests/systemtests/mempool_test.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build system_test - -package systemtests - -import ( - "testing" - - "github.com/cosmos/evm/tests/systemtests/mempool" -) - -func TestTxsOrdering(t *testing.T) { - mempool.TestTxsOrdering(t) -} - -func TestTxsReplacement(t *testing.T) { - mempool.TestTxsReplacement(t) - mempool.TestMixedTxsReplacementEVMAndCosmos(t) - mempool.TestMixedTxsReplacementLegacyAndDynamicFee(t) -} - -func TestExceptions(t *testing.T) { - mempool.TestTxRebroadcasting(t) - mempool.TestMinimumGasPricesZero(t) -}