laconicd-deprecated/tests/e2e/integration_test.go
yihuang 29d3abcf09
!feat(deps): Upgrade cosmos-sdk to v0.46.0 (#1168)
* Reuse cosmos-sdk client library to create keyring

Extracted from https://github.com/evmos/ethermint/pull/1168
Cleanup cmd code for easier to migration to cosmos-sdk 0.46

* Update cosmos-sdk v0.46

prepare for implementing cosmos-sdk feemarket and tx prioritization

changelog

refactor cmd

use sdkmath

fix lint

fix unit tests

fix unit test genesis

fix unit tests

fix unit test env setup

fix unit tests

fix unit tests

register PrivKey impl

fix extension options

fix lint

fix unit tests

make HandlerOption.Validate private

gofumpt

fix msg response decoding

fix sim test

bump cosmos-sdk version

fix sim test

sdk 46

fix unit test

fix unit tests

update ibc-go
2022-07-28 15:43:49 +02:00

898 lines
29 KiB
Go

package e2e_test
import (
"bytes"
"context"
"fmt"
"math/big"
"testing"
"github.com/cosmos/cosmos-sdk/client/flags"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/evmos/ethermint/rpc/types"
sdk "github.com/cosmos/cosmos-sdk/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
// . "github.com/onsi/ginkgo/v2"
// . "github.com/onsi/gomega"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/suite"
"github.com/ethereum/go-ethereum"
"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/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/rpc"
"github.com/evmos/ethermint/server/config"
"github.com/evmos/ethermint/testutil/network"
ethermint "github.com/evmos/ethermint/types"
)
// var _ = Describe("E2e", func() {
// })
// func TestJsonRpc(t *testing.T) {
// RegisterFailHandler(Fail)
// RunSpecs(t, "JSON-RPC Suite")
// }
// TODO: migrate to Ginkgo BDD
type IntegrationTestSuite struct {
suite.Suite
ctx context.Context
cfg network.Config
network *network.Network
gethClient *gethclient.Client
ethSigner ethtypes.Signer
rpcClient *rpc.Client
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
var err error
cfg := network.DefaultConfig()
cfg.JSONRPCAddress = config.DefaultJSONRPCAddress
cfg.NumValidators = 1
s.ctx = context.Background()
s.cfg = cfg
s.network, err = network.New(s.T(), s.T().TempDir(), cfg)
s.Require().NoError(err)
s.Require().NotNil(s.network)
_, err = s.network.WaitForHeight(1)
s.Require().NoError(err)
address := fmt.Sprintf("http://%s", s.network.Validators[0].AppConfig.JSONRPC.Address)
if s.network.Validators[0].JSONRPCClient == nil {
s.network.Validators[0].JSONRPCClient, err = ethclient.Dial(address)
s.Require().NoError(err)
}
rpcClient, err := rpc.DialContext(s.ctx, address)
s.Require().NoError(err)
s.rpcClient = rpcClient
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() {
genesisRes, err := s.network.Validators[0].RPCClient.Genesis(s.ctx)
s.Require().NoError(err)
chainID, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx)
s.Require().NoError(err)
s.Require().NotNil(chainID)
s.T().Log(chainID.Int64())
eip155ChainID, err := ethermint.ParseChainID(s.network.Config.ChainID)
s.Require().NoError(err)
eip155ChainIDGen, err := ethermint.ParseChainID(genesisRes.Genesis.ChainID)
s.Require().NoError(err)
s.Require().Equal(chainID, eip155ChainID)
s.Require().Equal(eip155ChainID, eip155ChainIDGen)
}
func (s *IntegrationTestSuite) TestNodeInfo() {
// Not implemented
info, err := s.gethClient.GetNodeInfo(s.ctx)
s.Require().Error(err)
s.Require().Empty(info)
}
func (s *IntegrationTestSuite) TestCreateAccessList() {
// Not implemented
accessList, _, _, err := s.gethClient.CreateAccessList(s.ctx, ethereum.CallMsg{})
s.Require().Error(err)
s.Require().Nil(accessList)
}
func (s *IntegrationTestSuite) TestBlock() {
blockNum, err := s.network.Validators[0].JSONRPCClient.BlockNumber(s.ctx)
s.Require().NoError(err)
s.Require().NotZero(blockNum)
bn := int64(blockNum)
block, err := s.network.Validators[0].RPCClient.Block(s.ctx, &bn)
s.Require().NoError(err)
s.Require().NotNil(block)
blockByNum, err := s.network.Validators[0].JSONRPCClient.BlockByNumber(s.ctx, new(big.Int).SetUint64(blockNum))
s.Require().NoError(err)
s.Require().NotNil(blockByNum)
// compare the ethereum header with the tendermint header
s.Require().Equal(block.Block.LastBlockID.Hash.Bytes(), blockByNum.Header().ParentHash.Bytes())
hash := common.BytesToHash(block.Block.Hash())
block, err = s.network.Validators[0].RPCClient.BlockByHash(s.ctx, hash.Bytes())
s.Require().NoError(err)
s.Require().NotNil(block)
blockByHash, err := s.network.Validators[0].JSONRPCClient.BlockByHash(s.ctx, hash)
s.Require().NoError(err)
s.Require().NotNil(blockByHash)
// Compare blockByNumber and blockByHash results
s.Require().Equal(blockByNum.Hash(), blockByHash.Hash())
s.Require().Equal(blockByNum.Transactions().Len(), blockByHash.Transactions().Len())
s.Require().Equal(blockByNum.ParentHash(), blockByHash.ParentHash())
s.Require().Equal(blockByNum.Root(), blockByHash.Root())
// 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)
s.Require().NotZero(blockNum)
bn := int64(blockNum)
block, err := s.network.Validators[0].RPCClient.Block(s.ctx, &bn)
s.Require().NoError(err)
s.Require().NotNil(block)
hash := common.BytesToHash(block.Block.Hash())
headerByNum, err := s.network.Validators[0].JSONRPCClient.HeaderByNumber(s.ctx, new(big.Int).SetUint64(blockNum))
s.Require().NoError(err)
s.Require().NotNil(headerByNum)
headerByHash, err := s.network.Validators[0].JSONRPCClient.HeaderByHash(s.ctx, hash)
s.Require().NoError(err)
s.Require().NotNil(headerByHash)
s.Require().Equal(headerByNum, headerByHash)
// TODO: we need to convert the ethereum block and return the header
// header := rpctypes.EthHeaderFromTendermint(block.Block.Header, ethtypes.Bloom{}, headerByHash.BaseFee)
// s.Require().NotNil(header)
// s.Require().Equal(headerByHash, header)
}
func (s *IntegrationTestSuite) TestSendRawTransaction() {
testCases := []struct {
name string
data string
expEncodingErr bool
expError bool
}{
{
"rlp: expected input list for types.LegacyTx",
"0x85b7119c978b22ac5188a554916d5eb9000567b87b3b8a536222c3c2e6549b98",
true,
false,
},
{
"transaction type not supported",
"0x1238b01bfc01e946ffdf8ccb087a072298cf9f141899c5c586550cc910b8c5aa",
true,
false,
},
{
"rlp: element is larger than containing list",
"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
true,
false,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
var data hexutil.Bytes
err := data.UnmarshalText([]byte(tc.data))
s.Require().NoError(err, data)
tx := new(ethtypes.Transaction)
err = tx.UnmarshalBinary(data)
if tc.expEncodingErr {
s.Require().Error(err)
s.Require().Equal(tc.name, err.Error())
return
}
s.Require().NoError(err)
s.Require().NotEmpty(tx)
hash := tx.Hash()
err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, tx)
if tc.expError {
s.Require().Error(err)
return
}
s.Require().NoError(err)
err = s.network.WaitForNextBlock()
s.Require().NoError(err)
expTx, isPending, err := s.network.Validators[0].JSONRPCClient.TransactionByHash(s.ctx, hash)
if tc.expError {
s.Require().Error(err)
return
}
s.Require().NoError(err)
s.Require().False(isPending)
s.Require().Equal(tx, expTx)
})
}
}
func (s *IntegrationTestSuite) TestEstimateGasContractDeployment() {
bytecode := "0x608060405234801561001057600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a260d08061004d6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063eb8ac92114602d575b600080fd5b606060048036036040811015604157600080fd5b8101908080359060200190929190803590602001909291905050506062565b005b8160008190555080827ff3ca124a697ba07e8c5e80bebcfcc48991fc16a63170e8a9206e30508960d00360405160405180910390a3505056fea265627a7a723158201d94d2187aaf3a6790527b615fcc40970febf0385fa6d72a2344848ebd0df3e964736f6c63430005110032"
expectedGas := uint64(0x1879c)
var data hexutil.Bytes
err := data.UnmarshalText([]byte(bytecode))
s.Require().NoError(err, data)
gas, err := s.network.Validators[0].JSONRPCClient.EstimateGas(s.ctx, ethereum.CallMsg{
Data: data,
})
s.Require().NoError(err)
s.Require().Equal(expectedGas, gas)
}
func (s *IntegrationTestSuite) TestSendTransactionContractDeploymentNoGas() {
bytecode := "0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029"
var data hexutil.Bytes
err := data.UnmarshalText([]byte(bytecode))
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)
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 := sdkmath.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))
}
func (s *IntegrationTestSuite) TestWeb3Sha3() {
testCases := []struct {
name string
arg string
expected string
}{
{
"normal input",
"0xabcd1234567890",
"0x23e7488ec9097f0126b0338926bfaeb5264b01cb162a0fd4a6d76e1081c2b24a",
},
{
"0x case",
"0x",
"0x39bef1777deb3dfb14f64b9f81ced092c501fee72f90e93d03bb95ee89df9837",
},
{
"empty string case",
"",
"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
var result string
err := s.rpcClient.Call(&result, "web3_sha3", tc.arg)
s.Require().NoError(err)
s.Require().Equal(tc.expected, result)
})
}
}
func (s *IntegrationTestSuite) TestPendingTransactionFilter() {
var (
filterID string
filterResult []common.Hash
)
// create filter
err := s.rpcClient.Call(&filterID, "eth_newPendingTransactionFilter")
s.Require().NoError(err)
// check filter result is empty
err = s.rpcClient.Call(&filterResult, "eth_getFilterChanges", filterID)
s.Require().NoError(err)
s.Require().Empty(filterResult)
// send transaction
signedTx := s.signValidTx(common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec"), big.NewInt(10)).AsTransaction()
err = s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, signedTx)
s.Require().NoError(err)
s.waitForTransaction()
s.expectSuccessReceipt(signedTx.Hash())
// check filter changes match the tx hash
err = s.rpcClient.Call(&filterResult, "eth_getFilterChanges", filterID)
s.Require().NoError(err)
s.Require().Equal([]common.Hash{signedTx.Hash()}, filterResult)
}
// TODO: add transactionIndex tests once we have OpenRPC interfaces
func (s *IntegrationTestSuite) TestBatchETHTransactions() {
const ethTxs = 2
txBuilder := s.network.Validators[0].ClientCtx.TxConfig.NewTxBuilder()
builder, ok := txBuilder.(authtx.ExtensionOptionsTxBuilder)
s.Require().True(ok)
recipient := common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec")
accountNonce := s.getAccountNonce(recipient)
feeAmount := sdk.ZeroInt()
var gasLimit uint64
var msgs []sdk.Msg
for i := 0; i < ethTxs; i++ {
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 := accountNonce + uint64(i) + 1
msgTx := evmtypes.NewTx(
chainId,
nonce,
&recipient,
big.NewInt(10),
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)
// A valid msg should have empty `From`
msgTx.From = ""
msgs = append(msgs, msgTx.GetMsgs()...)
txData, err := evmtypes.UnpackTxData(msgTx.Data)
s.Require().NoError(err)
feeAmount = feeAmount.Add(sdkmath.NewIntFromBigInt(txData.Fee()))
gasLimit = gasLimit + txData.GetGas()
}
option, err := codectypes.NewAnyWithValue(&evmtypes.ExtensionOptionsEthereumTx{})
s.Require().NoError(err)
queryClient := types.NewQueryClient(s.network.Validators[0].ClientCtx)
res, err := queryClient.Params(s.ctx, &evmtypes.QueryParamsRequest{})
fees := make(sdk.Coins, 0)
if feeAmount.Sign() > 0 {
fees = fees.Add(sdk.Coin{Denom: res.Params.EvmDenom, Amount: feeAmount})
}
builder.SetExtensionOptions(option)
err = builder.SetMsgs(msgs...)
s.Require().NoError(err)
builder.SetFeeAmount(fees)
builder.SetGasLimit(gasLimit)
tx := builder.GetTx()
txEncoder := s.network.Validators[0].ClientCtx.TxConfig.TxEncoder()
txBytes, err := txEncoder(tx)
s.Require().NoError(err)
syncCtx := s.network.Validators[0].ClientCtx.WithBroadcastMode(flags.BroadcastBlock)
txResponse, err := syncCtx.BroadcastTx(txBytes)
s.Require().NoError(err)
s.Require().Equal(uint32(0), txResponse.Code)
block, err := s.network.Validators[0].JSONRPCClient.BlockByNumber(s.ctx, big.NewInt(txResponse.Height))
s.Require().NoError(err)
txs := block.Transactions()
s.Require().Len(txs, ethTxs)
for i, tx := range txs {
s.Require().Equal(accountNonce+uint64(i)+1, tx.Nonce())
}
}
func (s *IntegrationTestSuite) TestGasConsumptionOnNormalTransfer() {
testCases := []struct {
name string
gasLimit uint64
expectedGasUsed uint64
}{
{
"gas used is the same as gas limit",
21000,
21000,
},
{
"gas used is half of Gas limit",
70000,
35000,
},
{
"gas used is less than half of gasLimit",
30000,
21000,
},
}
recipient := common.HexToAddress("0x378c50D9264C63F3F92B806d4ee56E9D86FfB3Ec")
chainID, err := s.network.Validators[0].JSONRPCClient.ChainID(s.ctx)
s.Require().NoError(err)
from := common.BytesToAddress(s.network.Validators[0].Address)
for _, tc := range testCases {
s.Run(tc.name, func() {
nonce := s.getAccountNonce(from)
s.Require().NoError(err)
gasPrice := s.getGasPrice()
msgTx := evmtypes.NewTx(
chainID,
nonce,
&recipient,
nil,
tc.gasLimit,
gasPrice,
nil, nil,
nil,
nil,
)
msgTx.From = from.Hex()
err = msgTx.Sign(s.ethSigner, s.network.Validators[0].ClientCtx.Keyring)
s.Require().NoError(err)
err := s.network.Validators[0].JSONRPCClient.SendTransaction(s.ctx, msgTx.AsTransaction())
s.Require().NoError(err)
s.waitForTransaction()
receipt := s.expectSuccessReceipt(msgTx.AsTransaction().Hash())
s.Equal(receipt.GasUsed, tc.expectedGasUsed)
})
}
}