From 04f595d3d5aeda12e4b54a0ca010aa2db4392ca3 Mon Sep 17 00:00:00 2001 From: crypto-facs <84574577+crypto-facs@users.noreply.github.com> Date: Thu, 20 Jan 2022 17:05:02 -0500 Subject: [PATCH] Integration tests (#913) --- tests/e2e/integration_test.go | 419 +++++++++++++++++++- tests/rpc/rpc_test.go | 510 +------------------------ x/evm/types/SimpleStorageContract.json | 4 + x/evm/types/compiled_contract.go | 15 + 4 files changed, 435 insertions(+), 513 deletions(-) create mode 100644 x/evm/types/SimpleStorageContract.json diff --git a/tests/e2e/integration_test.go b/tests/e2e/integration_test.go index 4ca6e4b3..773f95ac 100644 --- a/tests/e2e/integration_test.go +++ b/tests/e2e/integration_test.go @@ -1,9 +1,11 @@ package e2e_test import ( + "bytes" "context" "fmt" - "github.com/ethereum/go-ethereum/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" + evmtypes "github.com/tharsis/ethermint/x/evm/types" "math/big" "testing" @@ -42,6 +44,7 @@ type IntegrationTestSuite struct { network *network.Network gethClient *gethclient.Client + ethSigner ethtypes.Signer } func (s *IntegrationTestSuite) SetupSuite() { @@ -72,6 +75,9 @@ func (s *IntegrationTestSuite) SetupSuite() { s.Require().NoError(err) s.gethClient = gethclient.New(rpcClient) s.Require().NotNil(s.gethClient) + chainId, err := ethermint.ParseChainID(s.cfg.ChainID) + s.Require().NoError(err) + s.ethSigner = ethtypes.LatestSignerForChainID(chainId) } func (s *IntegrationTestSuite) TestChainID() { @@ -139,6 +145,20 @@ func (s *IntegrationTestSuite) TestBlock() { // TODO: parse Tm block to Ethereum and compare } +func (s *IntegrationTestSuite) TestBlockBloom() { + transactionHash, _ := s.deployTestContract() + receipt, err := s.network.Validators[0].JSONRPCClient.TransactionReceipt(s.ctx, transactionHash) + s.Require().NoError(err) + + number := receipt.BlockNumber + block, err := s.network.Validators[0].JSONRPCClient.BlockByNumber(s.ctx, number) + s.Require().NoError(err) + + lb := block.Bloom().Big() + s.Require().NotEqual(big.NewInt(0), lb) + s.Require().Equal(transactionHash.String(), block.Transactions()[0].Hash().String()) +} + func (s *IntegrationTestSuite) TestHeader() { blockNum, err := s.network.Validators[0].JSONRPCClient.BlockNumber(s.ctx) s.Require().NoError(err) @@ -263,14 +283,403 @@ func (s *IntegrationTestSuite) TestSendTransactionContractDeploymentNoGas() { var data hexutil.Bytes err := data.UnmarshalText([]byte(bytecode)) - var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - tx := ethtypes.NewContractCreation(0, nil, 0x5208, nil, data) - tx, _ = ethtypes.SignTx(tx, ethtypes.HomesteadSigner{}, testKey) + chainID, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx) + s.Require().NoError(err) - err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, tx) + owner := common.BytesToAddress(s.network.Validators[0].Address) + nonce := s.getAccountNonce(owner) + contractDeployTx := evmtypes.NewTxContract( + chainID, + nonce, + nil, // amount + 0x5208, // gasLimit + nil, // gasPrice + nil, nil, + data, // input + nil, // accesses + ) + contractDeployTx.From = owner.Hex() + err = contractDeployTx.Sign(s.ethSigner, s.network.Validators[0].ClientCtx.Keyring) + s.Require().NoError(err) + + err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, contractDeployTx.AsTransaction()) s.Require().Error(err) } +func (s *IntegrationTestSuite) TestBlockTransactionCount() { + // start with clean block + err := s.network.WaitForNextBlock() + s.Require().NoError(err) + + signedTx := s.signValidTx(common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(10)) + err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, signedTx.AsTransaction()) + s.Require().NoError(err) + + s.waitForTransaction() + receipt := s.expectSuccessReceipt(signedTx.AsTransaction().Hash()) + // TransactionCount endpoint represents eth_getTransactionCountByHash + count, err := s.network.Validators[0].JSONRPCClient.TransactionCount(s.ctx, receipt.BlockHash) + s.Require().NoError(err) + s.Require().Equal(uint(1), count) + + // expect 0 response with random block hash + anyBlockHash := common.HexToHash("0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35") + count, err = s.network.Validators[0].JSONRPCClient.TransactionCount(s.ctx, anyBlockHash) + s.Require().NoError(err) + s.Require().NotEqual(uint(0), 0) +} + +func (s *IntegrationTestSuite) TestGetTransactionByBlockHashAndIndex() { + signedTx := s.signValidTx(common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(10)) + err := s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, signedTx.AsTransaction()) + s.Require().NoError(err) + + s.waitForTransaction() + receipt := s.expectSuccessReceipt(signedTx.AsTransaction().Hash()) + + // TransactionInBlock endpoint represents eth_getTransactionByBlockHashAndIndex + transaction, err := s.network.Validators[0].JSONRPCClient.TransactionInBlock(s.ctx, receipt.BlockHash, 0) + s.Require().NoError(err) + s.Require().NotNil(transaction) + s.Require().Equal(receipt.TxHash, transaction.Hash()) +} + +func (s *IntegrationTestSuite) TestGetBalance() { + blockNumber, err := s.network.Validators[0].JSONRPCClient.BlockNumber(s.ctx) + s.Require().NoError(err) + + initialBalance, err := s.network.Validators[0].JSONRPCClient.BalanceAt(s.ctx, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ed"), big.NewInt(int64(blockNumber))) + s.Require().NoError(err) + + amountToTransfer := big.NewInt(10) + signedTx := s.signValidTx(common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ed"), amountToTransfer) + err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, signedTx.AsTransaction()) + s.Require().NoError(err) + + s.waitForTransaction() + receipt := s.expectSuccessReceipt(signedTx.AsTransaction().Hash()) + finalBalance, err := s.network.Validators[0].JSONRPCClient.BalanceAt(s.ctx, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ed"), receipt.BlockNumber) + s.Require().NoError(err) + + var result big.Int + s.Require().Equal(result.Add(initialBalance, amountToTransfer), finalBalance) + + // test old balance is still the same + prevBalance, err := s.network.Validators[0].JSONRPCClient.BalanceAt(s.ctx, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ed"), big.NewInt(int64(blockNumber))) + s.Require().NoError(err) + s.Require().Equal(initialBalance, prevBalance) +} + +func (s *IntegrationTestSuite) TestGetLogs() { + //TODO create tests to cover different filterQuery params + _, contractAddr := s.deployERC20Contract() + + blockNum, err := s.network.Validators[0].JSONRPCClient.BlockNumber(s.ctx) + s.Require().NoError(err) + + s.transferERC20Transaction(contractAddr, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(10)) + filterQuery := ethereum.FilterQuery{ + FromBlock: big.NewInt(int64(blockNum)), + } + + logs, err := s.network.Validators[0].JSONRPCClient.FilterLogs(s.ctx, filterQuery) + s.Require().NoError(err) + s.Require().NotNil(logs) + s.Require().Equal(1, len(logs)) + + expectedTopics := []common.Hash{ + common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + common.HexToHash("0x000000000000000000000000" + fmt.Sprintf("%x", common.BytesToAddress(s.network.Validators[0].Address))), + common.HexToHash("0x000000000000000000000000378c50d9264c63f3f92b806d4ee56e9d86ffb3ec"), + } + s.Require().Equal(expectedTopics, logs[0].Topics) +} + +func (s *IntegrationTestSuite) TestTransactionReceiptERC20Transfer() { + //start with clean block + err := s.network.WaitForNextBlock() + s.Require().NoError(err) + // deploy erc20 contract + _, contractAddr := s.deployERC20Contract() + + amount := big.NewInt(10) + hash := s.transferERC20Transaction(contractAddr, common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), amount) + transferReceipt := s.expectSuccessReceipt(hash) + logs := transferReceipt.Logs + s.Require().Equal(1, len(logs)) + s.Require().Equal(contractAddr, logs[0].Address) + + s.Require().Equal(amount, big.NewInt(0).SetBytes(logs[0].Data)) + + s.Require().Equal(false, logs[0].Removed) + s.Require().Equal(uint(0x0), logs[0].Index) + s.Require().Equal(uint(0x0), logs[0].TxIndex) + + expectedTopics := []common.Hash{ + common.HexToHash("0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"), + common.HexToHash("0x000000000000000000000000" + fmt.Sprintf("%x", common.BytesToAddress(s.network.Validators[0].Address))), + common.HexToHash("0x000000000000000000000000378c50d9264c63f3f92b806d4ee56e9d86ffb3ec"), + } + s.Require().Equal(expectedTopics, logs[0].Topics) +} + +func (s *IntegrationTestSuite) TestGetCode() { + expectedCode := "0x608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b578063d04ad49514610059575b600080fd5b610043610075565b6040516100509190610132565b60405180910390f35b610073600480360381019061006e91906100f6565b61009e565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000813590506100f081610172565b92915050565b60006020828403121561010c5761010b61016d565b5b600061011a848285016100e1565b91505092915050565b61012c8161014d565b82525050565b60006020820190506101476000830184610123565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600080fd5b61017b8161014d565b811461018657600080fd5b5056fea26469706673582212204c98c8f28598d29acc328cb34578de54cbed70b20bf9364897d48b2381f0c78b64736f6c63430008070033" + + _, addr := s.deploySimpleStorageContract() + block, err := s.network.Validators[0].JSONRPCClient.BlockNumber(s.ctx) + s.Require().NoError(err) + code, err := s.network.Validators[0].JSONRPCClient.CodeAt(s.ctx, addr, big.NewInt(int64(block))) + s.Require().NoError(err) + s.Require().Equal(expectedCode, hexutil.Encode(code)) +} + +func (s *IntegrationTestSuite) TestGetStorageAt() { + expectedStore := []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5} + _, addr := s.deploySimpleStorageContract() + + s.storeValueStorageContract(addr, big.NewInt(5)) + block, err := s.network.Validators[0].JSONRPCClient.BlockNumber(s.ctx) + s.Require().NoError(err) + + storage, err := s.network.Validators[0].JSONRPCClient.StorageAt(s.ctx, addr, common.BigToHash(big.NewInt(0)), big.NewInt(int64(block))) + s.Require().NoError(err) + s.Require().NotNil(storage) + s.Require().True(bytes.Equal(expectedStore, storage)) +} + +func (s *IntegrationTestSuite) getGasPrice() *big.Int { + gasPrice, err := s.network.Validators[0].JSONRPCClient.SuggestGasPrice(s.ctx) + s.Require().NoError(err) + return gasPrice +} + +func (s *IntegrationTestSuite) getAccountNonce(addr common.Address) uint64 { + nonce, err := s.network.Validators[0].JSONRPCClient.NonceAt(s.ctx, addr, nil) + s.Require().NoError(err) + return nonce +} + +func (s *IntegrationTestSuite) signValidTx(to common.Address, amount *big.Int) *evmtypes.MsgEthereumTx { + chainId, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx) + s.Require().NoError(err) + + gasPrice := s.getGasPrice() + from := common.BytesToAddress(s.network.Validators[0].Address) + nonce := s.getAccountNonce(from) + + msgTx := evmtypes.NewTx( + chainId, + nonce, + &to, + amount, + 100000, + gasPrice, + big.NewInt(200), + nil, + nil, + nil, + ) + msgTx.From = from.Hex() + err = msgTx.Sign(s.ethSigner, s.network.Validators[0].ClientCtx.Keyring) + s.Require().NoError(err) + return msgTx +} + +func (s *IntegrationTestSuite) signValidContractDeploymentTx(input []byte) *evmtypes.MsgEthereumTx { + chainId, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx) + s.Require().NoError(err) + + gasPrice := s.getGasPrice() + from := common.BytesToAddress(s.network.Validators[0].Address) + nonce := s.getAccountNonce(from) + + msgTx := evmtypes.NewTxContract( + chainId, + nonce, + big.NewInt(10), + 134216, + gasPrice, + big.NewInt(200), + nil, + input, + nil, + ) + msgTx.From = from.Hex() + err = msgTx.Sign(s.ethSigner, s.network.Validators[0].ClientCtx.Keyring) + s.Require().NoError(err) + return msgTx +} + +func (s *IntegrationTestSuite) deployTestContract() (transaction common.Hash, contractAddr common.Address) { + bytecode := "0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029" + + var data hexutil.Bytes + err := data.UnmarshalText([]byte(bytecode)) + s.Require().NoError(err) + + return s.deployContract(data) +} + +func (s *IntegrationTestSuite) deployContract(data []byte) (transaction common.Hash, contractAddr common.Address) { + chainID, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx) + s.Require().NoError(err) + + owner := common.BytesToAddress(s.network.Validators[0].Address) + nonce := s.getAccountNonce(owner) + + gas, err := s.network.Validators[0].JSONRPCClient.EstimateGas(s.ctx, ethereum.CallMsg{ + From: owner, + Data: data, + }) + s.Require().NoError(err) + + gasPrice := s.getGasPrice() + + contractDeployTx := evmtypes.NewTxContract( + chainID, + nonce, + nil, // amount + gas, // gasLimit + gasPrice, // gasPrice + nil, nil, + data, // input + nil, // accesses + ) + + contractDeployTx.From = owner.Hex() + err = contractDeployTx.Sign(s.ethSigner, s.network.Validators[0].ClientCtx.Keyring) + s.Require().NoError(err) + err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, contractDeployTx.AsTransaction()) + s.Require().NoError(err) + + s.waitForTransaction() + + receipt := s.expectSuccessReceipt(contractDeployTx.AsTransaction().Hash()) + s.Require().NotNil(receipt.ContractAddress) + return contractDeployTx.AsTransaction().Hash(), receipt.ContractAddress +} + +// Deploys erc20 contract, commits block and returns contract address +func (s *IntegrationTestSuite) deployERC20Contract() (transaction common.Hash, contractAddr common.Address) { + owner := common.BytesToAddress(s.network.Validators[0].Address) + supply := sdk.NewIntWithDecimal(1000, 18).BigInt() + + ctorArgs, err := evmtypes.ERC20Contract.ABI.Pack("", owner, supply) + s.Require().NoError(err) + + data := append(evmtypes.ERC20Contract.Bin, ctorArgs...) + return s.deployContract(data) +} + +// Deploys SimpleStorageContract and,commits block and returns contract address +func (s *IntegrationTestSuite) deploySimpleStorageContract() (transaction common.Hash, contractAddr common.Address) { + ctorArgs, err := evmtypes.SimpleStorageContract.ABI.Pack("") + s.Require().NoError(err) + + data := append(evmtypes.SimpleStorageContract.Bin, ctorArgs...) + return s.deployContract(data) +} + +func (s *IntegrationTestSuite) expectSuccessReceipt(hash common.Hash) *ethtypes.Receipt { + receipt, err := s.network.Validators[0].JSONRPCClient.TransactionReceipt(s.ctx, hash) + s.Require().NoError(err) + s.Require().NotNil(receipt) + s.Require().Equal(uint64(0x1), receipt.Status) + return receipt +} + +func (s *IntegrationTestSuite) transferERC20Transaction(contractAddr, to common.Address, amount *big.Int) common.Hash { + chainID, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx) + s.Require().NoError(err) + + transferData, err := evmtypes.ERC20Contract.ABI.Pack("transfer", to, amount) + s.Require().NoError(err) + owner := common.BytesToAddress(s.network.Validators[0].Address) + nonce := s.getAccountNonce(owner) + + gas, err := s.network.Validators[0].JSONRPCClient.EstimateGas(s.ctx, ethereum.CallMsg{ + To: &contractAddr, + From: owner, + Data: transferData, + }) + s.Require().NoError(err) + + gasPrice := s.getGasPrice() + ercTransferTx := evmtypes.NewTx( + chainID, + nonce, + &contractAddr, + nil, + gas, + gasPrice, + nil, nil, + transferData, + nil, + ) + + ercTransferTx.From = owner.Hex() + err = ercTransferTx.Sign(s.ethSigner, s.network.Validators[0].ClientCtx.Keyring) + s.Require().NoError(err) + err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, ercTransferTx.AsTransaction()) + s.Require().NoError(err) + + s.waitForTransaction() + + receipt := s.expectSuccessReceipt(ercTransferTx.AsTransaction().Hash()) + s.Require().NotEmpty(receipt.Logs) + return ercTransferTx.AsTransaction().Hash() + +} + +func (s *IntegrationTestSuite) storeValueStorageContract(contractAddr common.Address, amount *big.Int) common.Hash { + chainID, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx) + s.Require().NoError(err) + + transferData, err := evmtypes.SimpleStorageContract.ABI.Pack("store", amount) + s.Require().NoError(err) + owner := common.BytesToAddress(s.network.Validators[0].Address) + nonce := s.getAccountNonce(owner) + + gas, err := s.network.Validators[0].JSONRPCClient.EstimateGas(s.ctx, ethereum.CallMsg{ + To: &contractAddr, + From: owner, + Data: transferData, + }) + s.Require().NoError(err) + + gasPrice := s.getGasPrice() + ercTransferTx := evmtypes.NewTx( + chainID, + nonce, + &contractAddr, + nil, + gas, + gasPrice, + nil, nil, + transferData, + nil, + ) + + ercTransferTx.From = owner.Hex() + err = ercTransferTx.Sign(s.ethSigner, s.network.Validators[0].ClientCtx.Keyring) + s.Require().NoError(err) + err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, ercTransferTx.AsTransaction()) + s.Require().NoError(err) + + s.waitForTransaction() + + s.expectSuccessReceipt(ercTransferTx.AsTransaction().Hash()) + return ercTransferTx.AsTransaction().Hash() +} + +// waits 2 blocks time to keep tests stable +func (s *IntegrationTestSuite) waitForTransaction() { + err := s.network.WaitForNextBlock() + err = s.network.WaitForNextBlock() + s.Require().NoError(err) +} + func TestIntegrationTestSuite(t *testing.T) { suite.Run(t, new(IntegrationTestSuite)) } diff --git a/tests/rpc/rpc_test.go b/tests/rpc/rpc_test.go index 97889ccc..8ff18b6a 100644 --- a/tests/rpc/rpc_test.go +++ b/tests/rpc/rpc_test.go @@ -8,10 +8,8 @@ package rpc import ( "bytes" - "encoding/hex" "encoding/json" "fmt" - "math/big" "net/http" "os" "testing" @@ -26,7 +24,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" ) const ( @@ -35,9 +32,8 @@ const ( ) var ( - MODE = os.Getenv("MODE") - zeroString = "0x0" - from = []byte{} + MODE = os.Getenv("MODE") + from = []byte{} ) func TestMain(m *testing.M) { @@ -139,155 +135,6 @@ func callWithError(method string, params interface{}) (*Response, error) { return rpcRes, nil } -// turns a 0x prefixed hex string to a big.Int -func hexToBigInt(t *testing.T, in string) *big.Int { - s := in[2:] - b, err := hex.DecodeString(s) - require.NoError(t, err) - return big.NewInt(0).SetBytes(b) -} - -func TestBlockBloom(t *testing.T) { - hash := deployTestContractWithFunction(t) - receipt := waitForReceipt(t, hash) - - number := receipt["blockNumber"].(string) - param := []interface{}{number, false} - rpcRes := call(t, "eth_getBlockByNumber", param) - - block := make(map[string]interface{}) - err := json.Unmarshal(rpcRes.Result, &block) - require.NoError(t, err) - - lb := hexToBigInt(t, block["logsBloom"].(string)) - require.NotEqual(t, big.NewInt(0), lb) - require.Equal(t, hash.String(), block["transactions"].([]interface{})[0]) -} - -func TestEth_GetLogs_NoLogs(t *testing.T) { - param := make([]map[string][]string, 1) - param[0] = make(map[string][]string) - param[0]["topics"] = []string{} - call(t, "eth_getLogs", param) -} - -func TestEth_GetLogs_Topics_AB(t *testing.T) { - // TODO: this test passes on when run on its own, but fails when run with the other tests - if testing.Short() { - t.Skip("skipping TestEth_GetLogs_Topics_AB") - } - - rpcRes := call(t, "eth_blockNumber", []string{}) - - var res hexutil.Uint64 - err := res.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - - param := make([]map[string]interface{}, 1) - param[0] = make(map[string]interface{}) - param[0]["topics"] = []string{helloTopic, worldTopic} - param[0]["fromBlock"] = res.String() - - hash := deployTestContractWithFunction(t) - waitForReceipt(t, hash) - - rpcRes = call(t, "eth_getLogs", param) - - var logs []*ethtypes.Log - err = json.Unmarshal(rpcRes.Result, &logs) - require.NoError(t, err) - - require.Equal(t, 1, len(logs)) -} - -func TestEth_GetTransactionCount(t *testing.T) { - // TODO: this test passes on when run on its own, but fails when run with the other tests - if testing.Short() { - t.Skip("skipping TestEth_GetTransactionCount") - } - - prev := getNonce(t) - sendTestTransaction(t) - post := getNonce(t) - require.Equal(t, prev, post-1) -} - -func TestETH_GetBlockTransactionCountByHash(t *testing.T) { - txHash := sendTestTransaction(t) - - receipt := waitForReceipt(t, txHash) - require.NotNil(t, receipt, "transaction failed") - require.Equal(t, "0x1", receipt["status"].(string)) - - blockHash := receipt["blockHash"].(string) - param := []string{blockHash} - rpcRes := call(t, "eth_getBlockTransactionCountByHash", param) - - var res hexutil.Uint - err := res.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - require.Equal(t, "0x1", res.String()) -} - -func TestETH_GetBlockTransactionCountByHash_BlockHashNotFound(t *testing.T) { - anyBlockHash := "0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35" - param := []string{anyBlockHash} - rpcRes := call(t, "eth_getBlockTransactionCountByHash", param) - - var result interface{} - err := json.Unmarshal(rpcRes.Result, &result) - require.NoError(t, err) - require.Nil(t, result) -} - -func TestETH_GetTransactionByBlockHashAndIndex(t *testing.T) { - txHash := sendTestTransaction(t) - - receipt := waitForReceipt(t, txHash) - require.NotNil(t, receipt, "transaction failed") - require.Equal(t, "0x1", receipt["status"].(string)) - blockHash := receipt["blockHash"].(string) - - param := []string{blockHash, "0x0"} - rpcRes := call(t, "eth_getTransactionByBlockHashAndIndex", param) - - tx := make(map[string]interface{}) - err := json.Unmarshal(rpcRes.Result, &tx) - require.NoError(t, err) - require.NotNil(t, tx) - require.Equal(t, blockHash, tx["blockHash"].(string)) - require.Equal(t, "0x0", tx["transactionIndex"].(string)) -} - -func TestETH_GetTransactionByBlockHashAndIndex_BlockHashNotFound(t *testing.T) { - anyBlockHash := "0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35" - - param := []string{anyBlockHash, "0x0"} - rpcRes := call(t, "eth_getTransactionByBlockHashAndIndex", param) - - var result interface{} - err := json.Unmarshal(rpcRes.Result, &result) - require.NoError(t, err) - require.Nil(t, result) -} - -func TestEth_GetTransactionLogs(t *testing.T) { - // TODO: this test passes on when run on its own, but fails when run with the other tests - if testing.Short() { - t.Skip("skipping TestEth_GetTransactionLogs") - } - - hash, _ := deployTestContract(t) - - param := []string{hash.String()} - rpcRes := call(t, "eth_getTransactionLogs", param) - - logs := new([]*ethtypes.Log) - err := json.Unmarshal(rpcRes.Result, logs) - require.NoError(t, err) - require.Equal(t, 1, len(*logs)) -} - func TestEth_protocolVersion(t *testing.T) { expectedRes := hexutil.Uint(ethermint.ProtocolVersion) @@ -301,25 +148,6 @@ func TestEth_protocolVersion(t *testing.T) { require.Equal(t, expectedRes, res, "expected: %s got: %s\n", expectedRes.String(), rpcRes.Result) } -func TestEth_chainId(t *testing.T) { - rpcRes := call(t, "eth_chainId", []string{}) - - var res hexutil.Uint - err := res.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - require.NotEqual(t, "0x0", res.String()) -} - -func TestEth_blockNumber(t *testing.T) { - rpcRes := call(t, "eth_blockNumber", []string{}) - - var res hexutil.Uint64 - err := res.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - - t.Logf("Got block number: %s\n", res.String()) -} - func TestEth_coinbase(t *testing.T) { zeroAddress := hexutil.Bytes(common.Address{}.Bytes()) rpcRes := call(t, "eth_coinbase", []string{}) @@ -332,34 +160,6 @@ func TestEth_coinbase(t *testing.T) { require.NotEqual(t, zeroAddress.String(), res.String(), "expected: not %s got: %s\n", zeroAddress.String(), res.String()) } -func TestEth_GetBalance(t *testing.T) { - rpcRes := call(t, "eth_getBalance", []string{addrA, zeroString}) - - var res hexutil.Big - err := res.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - - t.Logf("Got balance %s for %s\n", res.String(), addrA) - - // 0 if x == y; where x is res, y is 0 - if res.ToInt().Cmp(big.NewInt(0)) != 0 { - t.Errorf("expected balance: %d, got: %s", 0, res.String()) - } -} - -func TestEth_GetStorageAt(t *testing.T) { - expectedRes := hexutil.Bytes{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - rpcRes := call(t, "eth_getStorageAt", []string{addrA, fmt.Sprint(addrAStoreKey), zeroString}) - - var storage hexutil.Bytes - err := storage.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - - t.Logf("Got value [%X] for %s with key %X\n", storage, addrA, addrAStoreKey) - - require.True(t, bytes.Equal(storage, expectedRes), "expected: %d (%d bytes) got: %d (%d bytes)", expectedRes, len(expectedRes), storage, len(storage)) -} - func TestEth_GetProof(t *testing.T) { rpcRes := call(t, "eth_sendTransaction", makeEthTxParam()) @@ -387,49 +187,6 @@ func TestEth_GetProof(t *testing.T) { t.Logf("Got AccountResult %s", rpcRes.Result) } -func TestEth_GetCode(t *testing.T) { - expectedRes := hexutil.Bytes{} - rpcRes := call(t, "eth_getCode", []string{addrA, zeroString}) - - var code hexutil.Bytes - err := code.UnmarshalJSON(rpcRes.Result) - - require.NoError(t, err) - - t.Logf("Got code [%X] for %s\n", code, addrA) - require.True(t, bytes.Equal(expectedRes, code), "expected: %X got: %X", expectedRes, code) -} - -func TestEth_SendTransaction_Transfer(t *testing.T) { - rpcRes := call(t, "eth_sendTransaction", makeEthTxParam()) - - var hash hexutil.Bytes - err := json.Unmarshal(rpcRes.Result, &hash) - require.NoError(t, err) - - receipt := waitForReceipt(t, hash) - require.NotNil(t, receipt) - require.Equal(t, "0x1", receipt["status"].(string)) -} - -func TestEth_SendTransaction_ContractDeploy(t *testing.T) { - param := makeTestContractDeployParam(t, true) - rpcRes, err := callWithError("eth_sendTransaction", param) - require.NoError(t, err) - - var hash hexutil.Bytes - err = json.Unmarshal(rpcRes.Result, &hash) - require.NoError(t, err) -} - -func TestEth_SendTransaction_ContractDeploy_no_gas_param(t *testing.T) { - t.Skip("Moved to tests/e2e/integration_test.go#TestSendTransactionContractDeploymentNoGas") - param := makeTestContractDeployParam(t, false) - _, err := callWithError("eth_sendTransaction", param) - // server returns internal error. - require.Error(t, err) -} - func TestEth_NewFilter(t *testing.T) { param := make([]map[string][]string, 1) param[0] = make(map[string][]string) @@ -521,97 +278,6 @@ func sendTestTransaction(t *testing.T) hexutil.Bytes { return hash } -func TestEth_GetTransactionReceipt(t *testing.T) { - hash := sendTestTransaction(t) - - receipt := waitForReceipt(t, hash) - - require.NotNil(t, receipt, "transaction failed") - require.Equal(t, "0x1", receipt["status"].(string)) - require.Equal(t, []interface{}{}, receipt["logs"].([]interface{})) -} - -// deployTestERC20Contract deploys a contract that emits an event in the constructor -func deployTestERC20Contract(t *testing.T) common.Address { - gasPrice := GetGasPrice(t) - - param := make([]map[string]string, 1) - param[0] = make(map[string]string) - param[0]["from"] = "0x" + fmt.Sprintf("%x", from) - - ctorArgs, err := evmtypes.ERC20Contract.ABI.Pack("", common.BytesToAddress(from), big.NewInt(100000000)) - require.NoError(t, err) - data := append(evmtypes.ERC20Contract.Bin, ctorArgs...) - param[0]["data"] = hexutil.Encode(data) - - param[0]["gas"] = "0x200000" - param[0]["gasPrice"] = gasPrice - - rpcRes := call(t, "eth_sendTransaction", param) - - var hash hexutil.Bytes - err = json.Unmarshal(rpcRes.Result, &hash) - require.NoError(t, err) - - receipt := expectSuccessReceipt(t, hash) - contractAddress := common.HexToAddress(receipt["contractAddress"].(string)) - require.NotEqual(t, common.Address{}, contractAddress) - - require.NotNil(t, receipt["logs"]) - - return contractAddress -} - -// sendTestERC20Transaction sends a typical erc20 transfer transaction -func sendTestERC20Transaction(t *testing.T, contract common.Address, amount *big.Int) hexutil.Bytes { - // transfer - gasPrice := GetGasPrice(t) - param := make([]map[string]string, 1) - param[0] = make(map[string]string) - param[0]["from"] = "0x" + fmt.Sprintf("%x", from) - param[0]["to"] = contract.Hex() - data, err := evmtypes.ERC20Contract.ABI.Pack("transfer", common.BigToAddress(big.NewInt(1)), amount) - require.NoError(t, err) - param[0]["data"] = hexutil.Encode(data) - param[0]["gas"] = "0x50000" - param[0]["gasPrice"] = gasPrice - - rpcRes := call(t, "eth_sendTransaction", param) - - var hash hexutil.Bytes - err = json.Unmarshal(rpcRes.Result, &hash) - require.NoError(t, err) - return hash -} - -func TestEth_GetTransactionReceipt_ERC20Transfer(t *testing.T) { - // deploy erc20 contract - contract := deployTestERC20Contract(t) - amount := big.NewInt(10) - hash := sendTestERC20Transaction(t, contract, amount) - receipt := expectSuccessReceipt(t, hash) - - require.Equal(t, 1, len(receipt["logs"].([]interface{}))) - log := receipt["logs"].([]interface{})[0].(map[string]interface{}) - - require.Equal(t, contract, common.HexToAddress(log["address"].(string))) - - valueBz, err := hexutil.Decode(log["data"].(string)) - require.NoError(t, err) - require.Equal(t, amount, big.NewInt(0).SetBytes(valueBz)) - - require.Equal(t, false, log["removed"].(bool)) - require.Equal(t, "0x0", log["logIndex"].(string)) - require.Equal(t, "0x0", log["transactionIndex"].(string)) - - expectedTopics := []interface{}{ - "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", - "0x000000000000000000000000" + fmt.Sprintf("%x", from), - "0x0000000000000000000000000000000000000000000000000000000000000001", - } - require.Equal(t, expectedTopics, log["topics"].([]interface{})) -} - // deployTestContract deploys a contract that emits an event in the constructor func deployTestContract(t *testing.T) (hexutil.Bytes, map[string]interface{}) { gasPrice := GetGasPrice(t) @@ -635,24 +301,6 @@ func deployTestContract(t *testing.T) (hexutil.Bytes, map[string]interface{}) { return hash, receipt } -func TestEth_GetTransactionReceipt_ContractDeployment(t *testing.T) { - nonce := getNonce(t) - _, receipt := deployTestContract(t) - - addrBz, err := hexutil.Decode(receipt["contractAddress"].(string)) - require.NoError(t, err) - - addr := common.BytesToAddress(addrBz) - require.Equal(t, crypto.CreateAddress(common.BytesToAddress(from), uint64(nonce)), addr) - require.Greater(t, len(receipt["logs"].([]interface{})), 0) - - rpcRes := call(t, "eth_getCode", []string{addr.Hex(), "latest"}) - var code hexutil.Bytes - err = code.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - require.NotEmpty(t, code) -} - func getTransactionReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} { param := []string{hash.String()} rpcRes := call(t, "eth_getTransactionReceipt", param) @@ -681,13 +329,6 @@ func waitForReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} { } } -func expectSuccessReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} { - receipt := waitForReceipt(t, hash) - require.NotNil(t, receipt, "transaction failed") - require.Equal(t, "0x1", receipt["status"].(string)) - return receipt -} - func TestEth_GetFilterChanges_NoTopics(t *testing.T) { rpcRes := call(t, "eth_blockNumber", []string{}) @@ -719,16 +360,6 @@ func TestEth_GetFilterChanges_NoTopics(t *testing.T) { require.Equal(t, 1, len(logs)) } -func TestEth_GetFilterChanges_Addresses(t *testing.T) { - t.Skip() - // TODO: need transaction receipts to determine contract deployment address -} - -func TestEth_GetFilterChanges_BlockHash(t *testing.T) { - t.Skip() - // TODO: need transaction receipts to determine tx block -} - // hash of Hello event var helloTopic = "0x775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd738898" @@ -838,11 +469,6 @@ func TestEth_GetFilterChanges_Topics_XB(t *testing.T) { require.Equal(t, 1, len(logs)) } -func TestEth_GetFilterChanges_Topics_XXC(t *testing.T) { - t.Skip() - // TODO: call test function, need tx receipts to determine contract address -} - func TestEth_PendingTransactionFilter(t *testing.T) { rpcRes := call(t, "eth_newPendingTransactionFilter", []string{}) @@ -865,52 +491,6 @@ func TestEth_PendingTransactionFilter(t *testing.T) { require.True(t, len(txs) >= 2, "could not get any txs", "changesRes.Result", string(changesRes.Result)) } -func getNonce(t *testing.T) hexutil.Uint64 { - param := []interface{}{hexutil.Bytes(from), "latest"} - rpcRes := call(t, "eth_getTransactionCount", param) - - var nonce hexutil.Uint64 - err := json.Unmarshal(rpcRes.Result, &nonce) - require.NoError(t, err) - return nonce -} - -func TestEth_EstimateGas(t *testing.T) { - param := make([]map[string]string, 1) - param[0] = make(map[string]string) - param[0]["from"] = "0x" + fmt.Sprintf("%x", from) - param[0]["to"] = "0x1122334455667788990011223344556677889900" - param[0]["value"] = "0x1" - param[0]["gas"] = "0x5209" - rpcRes := call(t, "eth_estimateGas", param) - require.NotNil(t, rpcRes) - - var gas string - err := json.Unmarshal(rpcRes.Result, &gas) - require.NoError(t, err, string(rpcRes.Result)) - require.Equal(t, "0x5208", gas) -} - -func TestEth_EstimateGas_ContractDeployment(t *testing.T) { - t.Skip("Moved to tests/e2e/integration_test.go#TestEstimateGasContractDeployment") - bytecode := "0x608060405234801561001057600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a260d08061004d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063eb8ac92114602d575b600080fd5b606060048036036040811015604157600080fd5b8101908080359060200190929190803590602001909291905050506062565b005b8160008190555080827ff3ca124a697ba07e8c5e80bebcfcc48991fc16a63170e8a9206e30508960d00360405160405180910390a3505056fea265627a7a723158201d94d2187aaf3a6790527b615fcc40970febf0385fa6d72a2344848ebd0df3e964736f6c63430005110032" - - param := make([]map[string]string, 1) - param[0] = make(map[string]string) - param[0]["from"] = "0x" + fmt.Sprintf("%x", from) - param[0]["data"] = bytecode - - rpcRes := call(t, "eth_estimateGas", param) - require.NotNil(t, rpcRes) - require.NotEmpty(t, rpcRes.Result) - - var gas hexutil.Uint64 - err := json.Unmarshal(rpcRes.Result, &gas) - require.NoError(t, err, string(rpcRes.Result)) - - require.Equal(t, "0x1879c", gas.String()) -} - func TestEth_ExportAccount_WithStorage(t *testing.T) { t.Skip("skipping TestEth_ExportAccount_WithStorage due to the server haven't implmented yet") @@ -957,78 +537,6 @@ func TestEth_ExportAccount_WithStorage(t *testing.T) { require.NotEqual(t, evmtypes.Storage(nil), account.Storage) } -func TestEth_GetBlockByHash(t *testing.T) { - param := []interface{}{"0x1", false} - rpcRes := call(t, "eth_getBlockByNumber", param) - - block := make(map[string]interface{}) - err := json.Unmarshal(rpcRes.Result, &block) - require.NoError(t, err) - blockHash := block["hash"].(string) - - param = []interface{}{blockHash, false} - rpcRes = call(t, "eth_getBlockByHash", param) - block = make(map[string]interface{}) - err = json.Unmarshal(rpcRes.Result, &block) - require.NoError(t, err) - require.Equal(t, "0x1", block["number"].(string)) -} - -func TestEth_GetBlockByHash_BlockHashNotFound(t *testing.T) { - anyBlockHash := "0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35" - param := []interface{}{anyBlockHash, false} - rpcRes := call(t, "eth_getBlockByHash", param) - - var result interface{} - err := json.Unmarshal(rpcRes.Result, &result) - require.NoError(t, err) - require.Nil(t, result) -} - -func TestEth_GetBlockByNumber(t *testing.T) { - param := []interface{}{"0x1", false} - rpcRes := call(t, "eth_getBlockByNumber", param) - - block := make(map[string]interface{}) - err := json.Unmarshal(rpcRes.Result, &block) - require.NoError(t, err) - require.Equal(t, "0x", block["extraData"].(string)) - require.Equal(t, []interface{}{}, block["uncles"].([]interface{})) -} - -func TestEth_GetLogs(t *testing.T) { - rpcRes := call(t, "eth_blockNumber", []string{}) - - var res hexutil.Uint64 - err := res.UnmarshalJSON(rpcRes.Result) - require.NoError(t, err) - - param := make([]map[string]interface{}, 1) - param[0] = make(map[string]interface{}) - param[0]["topics"] = []string{helloTopic, worldTopic} - param[0]["fromBlock"] = res.String() - - deployTestContractWithFunction(t) - - // get filter changes - logRes := call(t, "eth_getLogs", param) - - var logs []*ethtypes.Log - err = json.Unmarshal(logRes.Result, &logs) - require.NoError(t, err) - - require.Equal(t, 1, len(logs)) - - // filter log with address - param[0] = make(map[string]interface{}) - param[0]["address"] = "0x" + fmt.Sprintf("%x", from) - param[0]["fromBlock"] = res.String() - err = json.Unmarshal(logRes.Result, &logs) - require.NoError(t, err) - - require.Equal(t, 1, len(logs)) -} - func makeEthTxParam() []map[string]string { param := make([]map[string]string, 1) param[0] = make(map[string]string) @@ -1041,20 +549,6 @@ func makeEthTxParam() []map[string]string { return param } -func makeTestContractDeployParam(t *testing.T, withGas bool) []map[string]string { - param := make([]map[string]string, 1) - param[0] = make(map[string]string) - param[0]["from"] = "0x" + fmt.Sprintf("%x", from) - param[0]["data"] = "0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029" - if withGas { - gasPrice := GetGasPrice(t) - param[0]["gas"] = "0x200000" - param[0]["gasPrice"] = gasPrice - } - - return param -} - func TestEth_EthResend(t *testing.T) { tx := make(map[string]string) tx["from"] = "0x" + fmt.Sprintf("%x", from) diff --git a/x/evm/types/SimpleStorageContract.json b/x/evm/types/SimpleStorageContract.json new file mode 100644 index 00000000..4d8bb0af --- /dev/null +++ b/x/evm/types/SimpleStorageContract.json @@ -0,0 +1,4 @@ +{ + "abi": "[\n\t{\n\t\t\"inputs\": [],\n\t\t\"name\": \"get\",\n\t\t\"outputs\": [\n\t\t\t{\n\t\t\t\t\"internalType\": \"uint160\",\n\t\t\t\t\"name\": \"\",\n\t\t\t\t\"type\": \"uint160\"\n\t\t\t}\n\t\t],\n\t\t\"stateMutability\": \"view\",\n\t\t\"type\": \"function\"\n\t},\n\t{\n\t\t\"inputs\": [\n\t\t\t{\n\t\t\t\t\"internalType\": \"uint160\",\n\t\t\t\t\"name\": \"input\",\n\t\t\t\t\"type\": \"uint160\"\n\t\t\t}\n\t\t],\n\t\t\"name\": \"store\",\n\t\t\"outputs\": [],\n\t\t\"stateMutability\": \"nonpayable\",\n\t\t\"type\": \"function\"\n\t}\n]", + "bin": "608060405234801561001057600080fd5b506101bf806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80636d4ce63c1461003b578063d04ad49514610059575b600080fd5b610043610075565b6040516100509190610132565b60405180910390f35b610073600480360381019061006e91906100f6565b61009e565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000813590506100f081610172565b92915050565b60006020828403121561010c5761010b61016d565b5b600061011a848285016100e1565b91505092915050565b61012c8161014d565b82525050565b60006020820190506101476000830184610123565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600080fd5b61017b8161014d565b811461018657600080fd5b5056fea26469706673582212204c98c8f28598d29acc328cb34578de54cbed70b20bf9364897d48b2381f0c78b64736f6c63430008070033" +} diff --git a/x/evm/types/compiled_contract.go b/x/evm/types/compiled_contract.go index e36704fc..081d815b 100644 --- a/x/evm/types/compiled_contract.go +++ b/x/evm/types/compiled_contract.go @@ -74,6 +74,12 @@ var ( // ERC20Contract is the compiled test erc20 contract ERC20Contract CompiledContract + //go:embed SimpleStorageContract.json + simpleStorageJSON []byte + + // SimpleStorageContract is the compiled test simple storage contract + SimpleStorageContract CompiledContract + //go:embed TestMessageCall.json testMessageCallJSON []byte @@ -99,4 +105,13 @@ func init() { if len(TestMessageCall.Bin) == 0 { panic("load contract failed") } + + err = json.Unmarshal(simpleStorageJSON, &SimpleStorageContract) + if err != nil { + panic(err) + } + + if len(TestMessageCall.Bin) == 0 { + panic("load contract failed") + } }