upgrade to ethermint v0.21.0 #99
@ -103,6 +103,18 @@ func (suite *BackendTestSuite) TestGetProof() {
|
||||
false,
|
||||
&rpctypes.AccountResult{},
|
||||
},
|
||||
{
|
||||
"fail - Block doesn't exist)",
|
||||
address1,
|
||||
[]string{},
|
||||
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
|
||||
func(bn rpctypes.BlockNumber, addr common.Address) {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockError(client, bn.Int64())
|
||||
},
|
||||
false,
|
||||
&rpctypes.AccountResult{},
|
||||
},
|
||||
{
|
||||
"pass",
|
||||
address1,
|
||||
@ -351,6 +363,27 @@ func (suite *BackendTestSuite) TestGetTransactionCount() {
|
||||
true,
|
||||
hexutil.Uint64(0),
|
||||
},
|
||||
// TODO: Error mocking the GetAccount call - problem with Any type
|
||||
//{
|
||||
// "pass - returns the number of transactions at the given address up to the given block number",
|
||||
// true,
|
||||
// rpctypes.NewBlockNumber(big.NewInt(1)),
|
||||
// func(addr common.Address, bn rpctypes.BlockNumber) {
|
||||
// client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
// account, err := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, suite.acc)
|
||||
// suite.Require().NoError(err)
|
||||
// request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(suite.acc.Bytes()).String()}
|
||||
// requestMarshal, _ := request.Marshal()
|
||||
// RegisterABCIQueryAccount(
|
||||
// client,
|
||||
// requestMarshal,
|
||||
// tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
|
||||
// account,
|
||||
// )
|
||||
// },
|
||||
// true,
|
||||
// hexutil.Uint64(0),
|
||||
//},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -16,12 +15,10 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||
"github.com/evmos/ethermint/crypto/hd"
|
||||
rpctypes "github.com/evmos/ethermint/rpc/types"
|
||||
"github.com/evmos/ethermint/server/config"
|
||||
ethermint "github.com/evmos/ethermint/types"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
)
|
||||
@ -162,23 +159,6 @@ func NewBackend(
|
||||
panic(err)
|
||||
}
|
||||
|
||||
algos, _ := clientCtx.Keyring.SupportedAlgorithms()
|
||||
if !algos.Contains(hd.EthSecp256k1) {
|
||||
kr, err := keyring.New(
|
||||
sdk.KeyringServiceName(),
|
||||
viper.GetString(flags.FlagKeyringBackend),
|
||||
clientCtx.KeyringDir,
|
||||
clientCtx.Input,
|
||||
clientCtx.Codec,
|
||||
hd.EthSecp256k1Option(),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
clientCtx = clientCtx.WithKeyring(kr)
|
||||
}
|
||||
|
||||
return &Backend{
|
||||
ctx: context.Background(),
|
||||
clientCtx: clientCtx,
|
||||
|
@ -3,6 +3,7 @@ package backend
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -33,6 +34,7 @@ type BackendTestSuite struct {
|
||||
suite.Suite
|
||||
backend *Backend
|
||||
acc sdk.AccAddress
|
||||
signer keyring.Signer
|
||||
}
|
||||
|
||||
func TestBackendTestSuite(t *testing.T) {
|
||||
@ -61,6 +63,10 @@ func (suite *BackendTestSuite) SetupTest() {
|
||||
Seq: uint64(1),
|
||||
}
|
||||
|
||||
priv, err := ethsecp256k1.GenerateKey()
|
||||
suite.signer = tests.NewSigner(priv)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
||||
clientCtx := client.Context{}.WithChainID("ethermint_9000-1").
|
||||
WithHeight(1).
|
||||
@ -70,13 +76,18 @@ func (suite *BackendTestSuite) SetupTest() {
|
||||
WithAccountRetriever(client.TestAccountRetriever{Accounts: accounts})
|
||||
|
||||
allowUnprotectedTxs := false
|
||||
|
||||
idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx)
|
||||
|
||||
suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer)
|
||||
suite.backend.queryClient.QueryClient = mocks.NewEVMQueryClient(suite.T())
|
||||
suite.backend.clientCtx.Client = mocks.NewClient(suite.T())
|
||||
suite.backend.queryClient.FeeMarket = mocks.NewFeeMarketQueryClient(suite.T())
|
||||
suite.backend.ctx = rpctypes.ContextWithHeight(1)
|
||||
|
||||
// Add codec
|
||||
encCfg := encoding.MakeConfig(app.ModuleBasics)
|
||||
suite.backend.clientCtx.Codec = encCfg.Codec
|
||||
|
||||
}
|
||||
|
||||
// buildEthereumTx returns an example legacy Ethereum transaction
|
||||
@ -158,3 +169,25 @@ func (suite *BackendTestSuite) generateTestKeyring(clientDir string) (keyring.Ke
|
||||
encCfg := encoding.MakeConfig(app.ModuleBasics)
|
||||
return keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, encCfg.Codec, []keyring.Option{hd.EthSecp256k1Option()}...)
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) signAndEncodeEthTx(msgEthereumTx *evmtypes.MsgEthereumTx) []byte {
|
||||
from, priv := tests.NewAddrKey()
|
||||
signer := tests.NewSigner(priv)
|
||||
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
|
||||
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
|
||||
msgEthereumTx.From = from.String()
|
||||
err := msgEthereumTx.Sign(ethSigner, signer)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
tx, err := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
||||
suite.Require().NoError(err)
|
||||
|
||||
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
|
||||
txBz, err := txEncoder(tx)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
return txBz
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
|
||||
{
|
||||
"fail - invalid block header height",
|
||||
func() {
|
||||
height := int64(1)
|
||||
var header metadata.MD
|
||||
height := int64(1)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsInvalidHeight(queryClient, &header, int64(height))
|
||||
},
|
||||
@ -41,8 +41,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
|
||||
{
|
||||
"fail - invalid block header",
|
||||
func() {
|
||||
height := int64(1)
|
||||
var header metadata.MD
|
||||
height := int64(1)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsInvalidHeader(queryClient, &header, int64(height))
|
||||
},
|
||||
@ -52,8 +52,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
|
||||
{
|
||||
"pass - app state header height 1",
|
||||
func() {
|
||||
height := int64(1)
|
||||
var header metadata.MD
|
||||
height := int64(1)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParams(queryClient, &header, int64(height))
|
||||
},
|
||||
@ -552,8 +552,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
|
||||
"fail - blockNum < 0 with app state height error",
|
||||
ethrpc.BlockNumber(-1),
|
||||
func(_ ethrpc.BlockNumber) {
|
||||
appHeight := int64(1)
|
||||
var header metadata.MD
|
||||
appHeight := int64(1)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsError(queryClient, &header, appHeight)
|
||||
},
|
||||
@ -564,8 +564,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
|
||||
"pass - blockNum < 0 with app state height >= 1",
|
||||
ethrpc.BlockNumber(-1),
|
||||
func(blockNum ethrpc.BlockNumber) {
|
||||
appHeight := int64(1)
|
||||
var header metadata.MD
|
||||
appHeight := int64(1)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParams(queryClient, &header, appHeight)
|
||||
|
||||
|
484
rpc/backend/call_tx_test.go
Normal file
484
rpc/backend/call_tx_test.go
Normal file
@ -0,0 +1,484 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
rpctypes "github.com/evmos/ethermint/rpc/types"
|
||||
"github.com/evmos/ethermint/tests"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func (suite *BackendTestSuite) TestResend() {
|
||||
txNonce := (hexutil.Uint64)(1)
|
||||
baseFee := sdk.NewInt(1)
|
||||
gasPrice := new(hexutil.Big)
|
||||
toAddr := tests.GenerateAddress()
|
||||
callArgs := evmtypes.TransactionArgs{
|
||||
From: nil,
|
||||
To: &toAddr,
|
||||
Gas: nil,
|
||||
GasPrice: nil,
|
||||
MaxFeePerGas: gasPrice,
|
||||
MaxPriorityFeePerGas: gasPrice,
|
||||
Value: gasPrice,
|
||||
Nonce: nil,
|
||||
Input: nil,
|
||||
Data: nil,
|
||||
AccessList: nil,
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
args evmtypes.TransactionArgs
|
||||
gasPrice *hexutil.Big
|
||||
gasLimit *hexutil.Uint64
|
||||
expHash common.Hash
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Missing transaction nonce ",
|
||||
func() {},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: nil,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - Can't set Tx defaults BaseFee disabled",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFeeDisabled(queryClient)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Can't set Tx defaults ",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterFeeMarketParams(feeMarketClient, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - MaxFeePerGas is nil",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFeeDisabled(queryClient)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
MaxPriorityFeePerGas: nil,
|
||||
GasPrice: nil,
|
||||
MaxFeePerGas: nil,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail - GasPrice and (MaxFeePerGas or MaxPriorityPerGas specified",
|
||||
func() {},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
MaxPriorityFeePerGas: nil,
|
||||
GasPrice: gasPrice,
|
||||
MaxFeePerGas: gasPrice,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Block error",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlockError(client, 1)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - MaxFeePerGas is nil",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
GasPrice: nil,
|
||||
MaxPriorityFeePerGas: gasPrice,
|
||||
MaxFeePerGas: gasPrice,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Chain Id is nil",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
MaxPriorityFeePerGas: gasPrice,
|
||||
ChainID: nil,
|
||||
},
|
||||
nil,
|
||||
nil,
|
||||
common.Hash{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail - Pending transactions error",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
RegisterEstimateGas(queryClient, callArgs)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
RegisterUnconfirmedTxsError(client, nil)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
To: &toAddr,
|
||||
MaxFeePerGas: gasPrice,
|
||||
MaxPriorityFeePerGas: gasPrice,
|
||||
Gas: nil,
|
||||
},
|
||||
gasPrice,
|
||||
nil,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Not Ethereum txs",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
RegisterEstimateGas(queryClient, callArgs)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
RegisterUnconfirmedTxsEmpty(client, nil)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
Nonce: &txNonce,
|
||||
To: &toAddr,
|
||||
MaxFeePerGas: gasPrice,
|
||||
MaxPriorityFeePerGas: gasPrice,
|
||||
Gas: nil,
|
||||
},
|
||||
gasPrice,
|
||||
nil,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
hash, err := suite.backend.Resend(tc.args, tc.gasPrice, tc.gasLimit)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expHash, hash)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestSendRawTransaction() {
|
||||
ethTx, bz := suite.buildEthereumTx()
|
||||
rlpEncodedBz, _ := rlp.EncodeToBytes(ethTx.AsTransaction())
|
||||
cosmosTx, _ := ethTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
||||
txBytes, _ := suite.backend.clientCtx.TxConfig.TxEncoder()(cosmosTx)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
rawTx []byte
|
||||
expHash common.Hash
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - empty bytes",
|
||||
func() {},
|
||||
[]byte{},
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - no RLP encoded bytes",
|
||||
func() {},
|
||||
bz,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - unprotected transactions",
|
||||
func() {
|
||||
suite.backend.allowUnprotectedTxs = false
|
||||
},
|
||||
rlpEncodedBz,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - failed to get evm params",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
suite.backend.allowUnprotectedTxs = true
|
||||
RegisterParamsWithoutHeaderError(queryClient, 1)
|
||||
},
|
||||
rlpEncodedBz,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - failed to broadcast transaction",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
suite.backend.allowUnprotectedTxs = true
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
RegisterBroadcastTxError(client, txBytes)
|
||||
},
|
||||
rlpEncodedBz,
|
||||
common.HexToHash(ethTx.Hash),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - Gets the correct transaction hash of the eth transaction",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
suite.backend.allowUnprotectedTxs = true
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
RegisterBroadcastTx(client, txBytes)
|
||||
},
|
||||
rlpEncodedBz,
|
||||
common.HexToHash(ethTx.Hash),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
hash, err := suite.backend.SendRawTransaction(tc.rawTx)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expHash, hash)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestDoCall() {
|
||||
_, bz := suite.buildEthereumTx()
|
||||
gasPrice := (*hexutil.Big)(big.NewInt(1))
|
||||
toAddr := tests.GenerateAddress()
|
||||
callArgs := evmtypes.TransactionArgs{
|
||||
From: nil,
|
||||
To: &toAddr,
|
||||
Gas: nil,
|
||||
GasPrice: nil,
|
||||
MaxFeePerGas: gasPrice,
|
||||
MaxPriorityFeePerGas: gasPrice,
|
||||
Value: gasPrice,
|
||||
Input: nil,
|
||||
Data: nil,
|
||||
AccessList: nil,
|
||||
}
|
||||
argsBz, err := json.Marshal(callArgs)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
blockNum rpctypes.BlockNumber
|
||||
callArgs evmtypes.TransactionArgs
|
||||
expEthTx *evmtypes.MsgEthereumTxResponse
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Invalid request",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterBlock(client, 1, bz)
|
||||
RegisterEthCallError(queryClient, &evmtypes.EthCallRequest{Args: argsBz})
|
||||
},
|
||||
|
||||
rpctypes.BlockNumber(1),
|
||||
callArgs,
|
||||
&evmtypes.MsgEthereumTxResponse{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - Returned transaction response",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterBlock(client, 1, bz)
|
||||
RegisterEthCall(queryClient, &evmtypes.EthCallRequest{Args: argsBz})
|
||||
},
|
||||
|
||||
rpctypes.BlockNumber(1),
|
||||
callArgs,
|
||||
&evmtypes.MsgEthereumTxResponse{},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
msgEthTx, err := suite.backend.DoCall(tc.callArgs, tc.blockNum)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expEthTx, msgEthTx)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGasPrice() {
|
||||
defaultGasPrice := (*hexutil.Big)(big.NewInt(1))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expGas *hexutil.Big
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - get the default gas price",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
|
||||
RegisterFeeMarketParams(feeMarketClient, 1)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, sdk.NewInt(1))
|
||||
},
|
||||
defaultGasPrice,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail - can't get gasFee, FeeMarketParams error",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
feeMarketClient := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
|
||||
RegisterFeeMarketParamsError(feeMarketClient, 1)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, sdk.NewInt(1))
|
||||
},
|
||||
defaultGasPrice,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
gasPrice, err := suite.backend.GasPrice()
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expGas, gasPrice)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -4,6 +4,12 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethrpc "github.com/ethereum/go-ethereum/rpc"
|
||||
rpc "github.com/evmos/ethermint/rpc/types"
|
||||
"github.com/evmos/ethermint/tests"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/tendermint/tendermint/abci/types"
|
||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
@ -144,3 +150,297 @@ func (suite *BackendTestSuite) TestBaseFee() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestChainId() {
|
||||
expChainId := (*hexutil.Big)(big.NewInt(9000))
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expChainId *hexutil.Big
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - block is at or past the EIP-155 replay-protection fork block, return chainID from config ",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsInvalidHeight(queryClient, &header, int64(1))
|
||||
|
||||
},
|
||||
expChainId,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
chainId, err := suite.backend.ChainID()
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expChainId, chainId)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetCoinbase() {
|
||||
validatorAcc := sdk.AccAddress(tests.GenerateAddress().Bytes())
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
accAddr sdk.AccAddress
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Can't retrieve status from node",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterStatusError(client)
|
||||
},
|
||||
validatorAcc,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Can't query validator account",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterStatus(client)
|
||||
RegisterValidatorAccountError(queryClient)
|
||||
},
|
||||
validatorAcc,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - Gets coinbase account",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterStatus(client)
|
||||
RegisterValidatorAccount(queryClient, validatorAcc)
|
||||
},
|
||||
validatorAcc,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
accAddr, err := suite.backend.GetCoinbase()
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.accAddr, accAddr)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestSuggestGasTipCap() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
baseFee *big.Int
|
||||
expGasTipCap *big.Int
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - London hardfork not enabled or feemarket not enabled ",
|
||||
func() {},
|
||||
nil,
|
||||
big.NewInt(0),
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Gets the suggest gas tip cap ",
|
||||
func() {},
|
||||
nil,
|
||||
big.NewInt(0),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
maxDelta, err := suite.backend.SuggestGasTipCap(tc.baseFee)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expGasTipCap, maxDelta)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGlobalMinGasPrice() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expMinGasPrice sdk.Dec
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Can't get FeeMarket params",
|
||||
func() {
|
||||
feeMarketCleint := suite.backend.queryClient.FeeMarket.(*mocks.FeeMarketQueryClient)
|
||||
RegisterFeeMarketParamsError(feeMarketCleint, int64(1))
|
||||
},
|
||||
sdk.ZeroDec(),
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
globalMinGasPrice, err := suite.backend.GlobalMinGasPrice()
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expMinGasPrice, globalMinGasPrice)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestFeeHistory() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func(validator sdk.AccAddress)
|
||||
userBlockCount ethrpc.DecimalOrHex
|
||||
latestBlock ethrpc.BlockNumber
|
||||
expFeeHistory *rpc.FeeHistoryResult
|
||||
validator sdk.AccAddress
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - can't get params ",
|
||||
func(validator sdk.AccAddress) {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
suite.backend.cfg.JSONRPC.FeeHistoryCap = 0
|
||||
RegisterParamsError(queryClient, &header, ethrpc.BlockNumber(1).Int64())
|
||||
},
|
||||
1,
|
||||
0,
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - user block count higher than max block count ",
|
||||
func(validator sdk.AccAddress) {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
suite.backend.cfg.JSONRPC.FeeHistoryCap = 0
|
||||
RegisterParams(queryClient, &header, ethrpc.BlockNumber(1).Int64())
|
||||
},
|
||||
1,
|
||||
0,
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Tendermint block fetching error ",
|
||||
func(validator sdk.AccAddress) {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
|
||||
RegisterBlockError(client, ethrpc.BlockNumber(1).Int64())
|
||||
},
|
||||
1,
|
||||
1,
|
||||
nil,
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Eth block fetching error",
|
||||
func(validator sdk.AccAddress) {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
|
||||
RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil)
|
||||
RegisterBlockResultsError(client, 1)
|
||||
},
|
||||
1,
|
||||
1,
|
||||
nil,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail - Invalid base fee",
|
||||
func(validator sdk.AccAddress) {
|
||||
//baseFee := sdk.NewInt(1)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
|
||||
RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFeeError(queryClient)
|
||||
RegisterValidatorAccount(queryClient, validator)
|
||||
RegisterConsensusParams(client, 1)
|
||||
},
|
||||
1,
|
||||
1,
|
||||
nil,
|
||||
sdk.AccAddress(tests.GenerateAddress().Bytes()),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - Valid FeeHistoryResults object",
|
||||
func(validator sdk.AccAddress) {
|
||||
baseFee := sdk.NewInt(1)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
suite.backend.cfg.JSONRPC.FeeHistoryCap = 2
|
||||
RegisterBlock(client, ethrpc.BlockNumber(1).Int64(), nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
RegisterValidatorAccount(queryClient, validator)
|
||||
RegisterConsensusParams(client, 1)
|
||||
},
|
||||
1,
|
||||
1,
|
||||
&rpc.FeeHistoryResult{
|
||||
OldestBlock: (*hexutil.Big)(big.NewInt(0)),
|
||||
BaseFee: []*hexutil.Big{(*hexutil.Big)(big.NewInt(1))},
|
||||
GasUsedRatio: []float64{0},
|
||||
Reward: [][]*hexutil.Big{{(*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0))}},
|
||||
},
|
||||
sdk.AccAddress(tests.GenerateAddress().Bytes()),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock(tc.validator)
|
||||
|
||||
feeHistory, err := suite.backend.FeeHistory(tc.userBlockCount, tc.latestBlock, []float64{25, 50, 75, 100})
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(feeHistory, tc.expFeeHistory)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,15 @@ package backend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
rpc "github.com/evmos/ethermint/rpc/types"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
@ -15,6 +18,7 @@ import (
|
||||
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Client defines a mocked object that implements the Tendermint JSON-RPC Client
|
||||
@ -24,7 +28,74 @@ import (
|
||||
// To use a mock method it has to be registered in a given test.
|
||||
var _ tmrpcclient.Client = &mocks.Client{}
|
||||
|
||||
// Tx Search
|
||||
func RegisterTxSearch(client *mocks.Client, query string, txBz []byte) {
|
||||
resulTxs := []*tmrpctypes.ResultTx{{Tx: txBz}}
|
||||
client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), "").
|
||||
Return(&tmrpctypes.ResultTxSearch{Txs: resulTxs, TotalCount: 1}, nil)
|
||||
}
|
||||
|
||||
func RegisterTxSearchEmpty(client *mocks.Client, query string) {
|
||||
client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), "").
|
||||
Return(&tmrpctypes.ResultTxSearch{}, nil)
|
||||
}
|
||||
|
||||
func RegisterTxSearchError(client *mocks.Client, query string) {
|
||||
client.On("TxSearch", rpc.ContextWithHeight(1), query, false, (*int)(nil), (*int)(nil), "").
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// Broadcast Tx
|
||||
func RegisterBroadcastTx(client *mocks.Client, tx types.Tx) {
|
||||
client.On("BroadcastTxSync", context.Background(), tx).
|
||||
Return(&tmrpctypes.ResultBroadcastTx{}, nil)
|
||||
}
|
||||
|
||||
func RegisterBroadcastTxError(client *mocks.Client, tx types.Tx) {
|
||||
client.On("BroadcastTxSync", context.Background(), tx).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// Unconfirmed Transactions
|
||||
func RegisterUnconfirmedTxs(client *mocks.Client, limit *int, txs []types.Tx) {
|
||||
client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit).
|
||||
Return(&tmrpctypes.ResultUnconfirmedTxs{Txs: txs}, nil)
|
||||
}
|
||||
|
||||
func RegisterUnconfirmedTxsEmpty(client *mocks.Client, limit *int) {
|
||||
client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit).
|
||||
Return(&tmrpctypes.ResultUnconfirmedTxs{
|
||||
Txs: make([]types.Tx, 2),
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func RegisterUnconfirmedTxsError(client *mocks.Client, limit *int) {
|
||||
client.On("UnconfirmedTxs", rpc.ContextWithHeight(1), limit).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// Status
|
||||
func RegisterStatus(client *mocks.Client) {
|
||||
client.On("Status", rpc.ContextWithHeight(1)).
|
||||
Return(&tmrpctypes.ResultStatus{}, nil)
|
||||
}
|
||||
|
||||
func RegisterStatusError(client *mocks.Client) {
|
||||
client.On("Status", rpc.ContextWithHeight(1)).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// Block
|
||||
func RegisterBlockMultipleTxs(
|
||||
client *mocks.Client,
|
||||
height int64,
|
||||
txs []types.Tx,
|
||||
) (*tmrpctypes.ResultBlock, error) {
|
||||
block := types.MakeBlock(height, txs, nil, nil)
|
||||
resBlock := &tmrpctypes.ResultBlock{Block: block}
|
||||
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
|
||||
return resBlock, nil
|
||||
}
|
||||
func RegisterBlock(
|
||||
client *mocks.Client,
|
||||
height int64,
|
||||
@ -34,16 +105,14 @@ func RegisterBlock(
|
||||
if tx == nil {
|
||||
emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil)
|
||||
resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock}
|
||||
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
|
||||
Return(resBlock, nil)
|
||||
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
|
||||
return resBlock, nil
|
||||
}
|
||||
|
||||
// with tx
|
||||
block := types.MakeBlock(height, []types.Tx{tx}, nil, nil)
|
||||
resBlock := &tmrpctypes.ResultBlock{Block: block}
|
||||
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
|
||||
Return(resBlock, nil)
|
||||
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
|
||||
return resBlock, nil
|
||||
}
|
||||
|
||||
@ -101,6 +170,26 @@ func TestRegisterConsensusParams(t *testing.T) {
|
||||
}
|
||||
|
||||
// BlockResults
|
||||
|
||||
func RegisterBlockResultsWithEventLog(client *mocks.Client, height int64) (*tmrpctypes.ResultBlockResults, error) {
|
||||
res := &tmrpctypes.ResultBlockResults{
|
||||
Height: height,
|
||||
TxsResults: []*abci.ResponseDeliverTx{
|
||||
{Code: 0, GasUsed: 0, Events: []abci.Event{{
|
||||
Type: evmtypes.EventTypeTxLog,
|
||||
Attributes: []abci.EventAttribute{{
|
||||
Key: []byte(evmtypes.AttributeKeyTxLog),
|
||||
Value: []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}, // Represents {"test": "hello"}
|
||||
Index: true,
|
||||
}},
|
||||
}}},
|
||||
},
|
||||
}
|
||||
client.On("BlockResults", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
|
||||
Return(res, nil)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func RegisterBlockResults(
|
||||
client *mocks.Client,
|
||||
height int64,
|
||||
@ -167,3 +256,22 @@ func RegisterABCIQueryWithOptions(client *mocks.Client, height int64, path strin
|
||||
},
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func RegisterABCIQueryWithOptionsError(clients *mocks.Client, path string, data bytes.HexBytes, opts tmrpcclient.ABCIQueryOptions) {
|
||||
clients.On("ABCIQueryWithOptions", context.Background(), path, data, opts).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
func RegisterABCIQueryAccount(clients *mocks.Client, data bytes.HexBytes, opts tmrpcclient.ABCIQueryOptions, acc client.Account) {
|
||||
baseAccount := authtypes.NewBaseAccount(acc.GetAddress(), acc.GetPubKey(), acc.GetAccountNumber(), acc.GetSequence())
|
||||
accAny, _ := codectypes.NewAnyWithValue(baseAccount)
|
||||
accResponse := authtypes.QueryAccountResponse{Account: accAny}
|
||||
respBz, _ := accResponse.Marshal()
|
||||
clients.On("ABCIQueryWithOptions", context.Background(), "/cosmos.auth.v1beta1.Query/Account", data, opts).
|
||||
Return(&tmrpctypes.ResultABCIQuery{
|
||||
Response: abci.ResponseQuery{
|
||||
Value: respBz,
|
||||
Height: 1,
|
||||
},
|
||||
}, nil)
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
||||
@ -19,6 +18,8 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// QueryClient defines a mocked object that implements the ethermint GRPC
|
||||
@ -28,6 +29,38 @@ import (
|
||||
// To use a mock method it has to be registered in a given test.
|
||||
var _ evmtypes.QueryClient = &mocks.EVMQueryClient{}
|
||||
|
||||
// TraceTransaction
|
||||
func RegisterTraceTransactionWithPredecessors(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx, predecessors []*evmtypes.MsgEthereumTx) {
|
||||
data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}
|
||||
queryClient.On("TraceTx", rpc.ContextWithHeight(1),
|
||||
&evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1, Predecessors: predecessors}).
|
||||
Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil)
|
||||
}
|
||||
|
||||
func RegisterTraceTransaction(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx) {
|
||||
data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}
|
||||
queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1}).
|
||||
Return(&evmtypes.QueryTraceTxResponse{Data: data}, nil)
|
||||
}
|
||||
|
||||
func RegisterTraceTransactionError(queryClient *mocks.EVMQueryClient, msgEthTx *evmtypes.MsgEthereumTx) {
|
||||
queryClient.On("TraceTx", rpc.ContextWithHeight(1), &evmtypes.QueryTraceTxRequest{Msg: msgEthTx, BlockNumber: 1}).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// TraceBlock
|
||||
func RegisterTraceBlock(queryClient *mocks.EVMQueryClient, txs []*evmtypes.MsgEthereumTx) {
|
||||
data := []byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}
|
||||
queryClient.On("TraceBlock", rpc.ContextWithHeight(1),
|
||||
&evmtypes.QueryTraceBlockRequest{Txs: txs, BlockNumber: 1, TraceConfig: &evmtypes.TraceConfig{}}).
|
||||
Return(&evmtypes.QueryTraceBlockResponse{Data: data}, nil)
|
||||
}
|
||||
|
||||
func RegisterTraceBlockError(queryClient *mocks.EVMQueryClient) {
|
||||
queryClient.On("TraceBlock", rpc.ContextWithHeight(1), &evmtypes.QueryTraceBlockRequest{}).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// Params
|
||||
func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
|
||||
@ -41,6 +74,11 @@ func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, heig
|
||||
})
|
||||
}
|
||||
|
||||
func RegisterParamsWithoutHeader(queryClient *mocks.EVMQueryClient, height int64) {
|
||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}).
|
||||
Return(&evmtypes.QueryParamsResponse{Params: evmtypes.DefaultParams()}, nil)
|
||||
}
|
||||
|
||||
func RegisterParamsInvalidHeader(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
|
||||
Return(&evmtypes.QueryParamsResponse{}, nil).
|
||||
@ -64,6 +102,11 @@ func RegisterParamsInvalidHeight(queryClient *mocks.EVMQueryClient, header *meta
|
||||
})
|
||||
}
|
||||
|
||||
func RegisterParamsWithoutHeaderError(queryClient *mocks.EVMQueryClient, height int64) {
|
||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// Params returns error
|
||||
func RegisterParamsError(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
|
||||
@ -71,8 +114,9 @@ func RegisterParamsError(queryClient *mocks.EVMQueryClient, header *metadata.MD,
|
||||
}
|
||||
|
||||
func TestRegisterParams(t *testing.T) {
|
||||
queryClient := mocks.NewEVMQueryClient(t)
|
||||
var header metadata.MD
|
||||
queryClient := mocks.NewEVMQueryClient(t)
|
||||
|
||||
height := int64(1)
|
||||
RegisterParams(queryClient, &header, height)
|
||||
|
||||
@ -91,6 +135,26 @@ func TestRegisterParamsError(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
// ETH Call
|
||||
func RegisterEthCall(queryClient *mocks.EVMQueryClient, request *evmtypes.EthCallRequest) {
|
||||
ctx, _ := context.WithCancel(rpc.ContextWithHeight(1))
|
||||
queryClient.On("EthCall", ctx, request).
|
||||
Return(&evmtypes.MsgEthereumTxResponse{}, nil)
|
||||
}
|
||||
|
||||
func RegisterEthCallError(queryClient *mocks.EVMQueryClient, request *evmtypes.EthCallRequest) {
|
||||
ctx, _ := context.WithCancel(rpc.ContextWithHeight(1))
|
||||
queryClient.On("EthCall", ctx, request).
|
||||
Return(nil, errortypes.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
// Estimate Gas
|
||||
func RegisterEstimateGas(queryClient *mocks.EVMQueryClient, args evmtypes.TransactionArgs) {
|
||||
bz, _ := json.Marshal(args)
|
||||
queryClient.On("EstimateGas", rpc.ContextWithHeight(1), &evmtypes.EthCallRequest{Args: bz}).
|
||||
Return(&evmtypes.EstimateGasResponse{}, nil)
|
||||
}
|
||||
|
||||
// BaseFee
|
||||
func RegisterBaseFee(queryClient *mocks.EVMQueryClient, baseFee sdk.Int) {
|
||||
queryClient.On("BaseFee", rpc.ContextWithHeight(1), &evmtypes.QueryBaseFeeRequest{}).
|
||||
@ -137,12 +201,7 @@ func TestRegisterBaseFeeDisabled(t *testing.T) {
|
||||
// ValidatorAccount
|
||||
func RegisterValidatorAccount(queryClient *mocks.EVMQueryClient, validator sdk.AccAddress) {
|
||||
queryClient.On("ValidatorAccount", rpc.ContextWithHeight(1), &evmtypes.QueryValidatorAccountRequest{}).
|
||||
Return(
|
||||
&evmtypes.QueryValidatorAccountResponse{
|
||||
AccountAddress: validator.String(),
|
||||
},
|
||||
nil,
|
||||
)
|
||||
Return(&evmtypes.QueryValidatorAccountResponse{AccountAddress: validator.String()}, nil)
|
||||
}
|
||||
|
||||
func RegisterValidatorAccountError(queryClient *mocks.EVMQueryClient) {
|
||||
|
21
rpc/backend/feemarket_query_client_test.go
Normal file
21
rpc/backend/feemarket_query_client_test.go
Normal file
@ -0,0 +1,21 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
rpc "github.com/evmos/ethermint/rpc/types"
|
||||
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
|
||||
)
|
||||
|
||||
var _ feemarkettypes.QueryClient = &mocks.FeeMarketQueryClient{}
|
||||
|
||||
// Params
|
||||
func RegisterFeeMarketParams(feeMarketClient *mocks.FeeMarketQueryClient, height int64) {
|
||||
feeMarketClient.On("Params", rpc.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{}).
|
||||
Return(&feemarkettypes.QueryParamsResponse{Params: feemarkettypes.DefaultParams()}, nil)
|
||||
}
|
||||
|
||||
func RegisterFeeMarketParamsError(feeMarketClient *mocks.FeeMarketQueryClient, height int64) {
|
||||
feeMarketClient.On("Params", rpc.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{}).
|
||||
Return(nil, sdkerrors.ErrInvalidRequest)
|
||||
}
|
@ -15,7 +15,6 @@ func (b *Backend) GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) {
|
||||
if resBlock == nil {
|
||||
return nil, errors.Errorf("block not found for hash %s", hash)
|
||||
}
|
||||
|
||||
return b.GetLogsByHeight(&resBlock.Block.Header.Height)
|
||||
}
|
||||
|
||||
|
117
rpc/backend/filters_test.go
Normal file
117
rpc/backend/filters_test.go
Normal file
@ -0,0 +1,117 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
ethrpc "github.com/evmos/ethermint/rpc/types"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func (suite *BackendTestSuite) TestGetLogs() {
|
||||
|
||||
_, bz := suite.buildEthereumTx()
|
||||
block := tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil)
|
||||
logs := make([]*evmtypes.Log, 0, 1)
|
||||
var log evmtypes.Log
|
||||
json.Unmarshal([]byte{0x7b, 0x22, 0x74, 0x65, 0x73, 0x74, 0x22, 0x3a, 0x20, 0x22, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x22, 0x7d}, &log)
|
||||
logs = append(logs, &log)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func(hash common.Hash)
|
||||
blockHash common.Hash
|
||||
expLogs [][]*ethtypes.Log
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - no block with that hash",
|
||||
func(hash common.Hash) {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockByHashNotFound(client, hash, bz)
|
||||
},
|
||||
common.Hash{},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - error fetching block by hash",
|
||||
func(hash common.Hash) {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockByHashError(client, hash, bz)
|
||||
},
|
||||
common.Hash{},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - error getting block results",
|
||||
func(hash common.Hash) {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockByHash(client, hash, bz)
|
||||
RegisterBlockResultsError(client, 1)
|
||||
},
|
||||
common.Hash{},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"success - getting logs with block hash",
|
||||
func(hash common.Hash) {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockByHash(client, hash, bz)
|
||||
RegisterBlockResultsWithEventLog(client, ethrpc.BlockNumber(1).Int64())
|
||||
},
|
||||
common.BytesToHash(block.Hash()),
|
||||
[][]*ethtypes.Log{evmtypes.LogsToEthereum(logs)},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
|
||||
tc.registerMock(tc.blockHash)
|
||||
logs, err := suite.backend.GetLogs(tc.blockHash)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expLogs, logs)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestBloomStatus() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expResult uint64
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - returns the BloomBitsBlocks and the number of processed sections maintained",
|
||||
func() {},
|
||||
4096,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest()
|
||||
|
||||
tc.registerMock()
|
||||
bloom, _ := suite.backend.BloomStatus()
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expResult, bloom)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
123
rpc/backend/mocks/feemarket_query_client.go
Normal file
123
rpc/backend/mocks/feemarket_query_client.go
Normal file
@ -0,0 +1,123 @@
|
||||
// Code generated by mockery v2.14.1. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
types "github.com/evmos/ethermint/x/feemarket/types"
|
||||
)
|
||||
|
||||
// FeeMarketQueryClient is an autogenerated mock type for the QueryClient type
|
||||
type FeeMarketQueryClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// BaseFee provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *FeeMarketQueryClient) BaseFee(ctx context.Context, in *types.QueryBaseFeeRequest, opts ...grpc.CallOption) (*types.QueryBaseFeeResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *types.QueryBaseFeeResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBaseFeeRequest, ...grpc.CallOption) *types.QueryBaseFeeResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.QueryBaseFeeResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.QueryBaseFeeRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// BlockGas provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *FeeMarketQueryClient) BlockGas(ctx context.Context, in *types.QueryBlockGasRequest, opts ...grpc.CallOption) (*types.QueryBlockGasResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *types.QueryBlockGasResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.QueryBlockGasRequest, ...grpc.CallOption) *types.QueryBlockGasResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.QueryBlockGasResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.QueryBlockGasRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Params provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *FeeMarketQueryClient) Params(ctx context.Context, in *types.QueryParamsRequest, opts ...grpc.CallOption) (*types.QueryParamsResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *types.QueryParamsResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) *types.QueryParamsResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*types.QueryParamsResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *types.QueryParamsRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTNewQueryClient interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewQueryClient creates a new instance of QueryClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFeeMarketQueryClient(t mockConstructorTestingTNewQueryClient) *FeeMarketQueryClient {
|
||||
mock := &FeeMarketQueryClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
355
rpc/backend/node_info_test.go
Normal file
355
rpc/backend/node_info_test.go
Normal file
@ -0,0 +1,355 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
ethermint "github.com/evmos/ethermint/types"
|
||||
"github.com/spf13/viper"
|
||||
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func (suite *BackendTestSuite) TestRPCMinGasPrice() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expMinGasPrice int64
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - default gas price",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsWithoutHeaderError(queryClient, 1)
|
||||
},
|
||||
ethermint.DefaultGasPrice,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - min gas price is 0",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
},
|
||||
ethermint.DefaultGasPrice,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
minPrice := suite.backend.RPCMinGasPrice()
|
||||
if tc.expPass {
|
||||
suite.Require().Equal(tc.expMinGasPrice, minPrice)
|
||||
} else {
|
||||
suite.Require().NotEqual(tc.expMinGasPrice, minPrice)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestSetGasPrice() {
|
||||
defaultGasPrice := (*hexutil.Big)(big.NewInt(1))
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
gasPrice hexutil.Big
|
||||
expOutput bool
|
||||
}{
|
||||
{
|
||||
"pass - cannot get server config",
|
||||
func() {
|
||||
suite.backend.clientCtx.Viper = viper.New()
|
||||
},
|
||||
*defaultGasPrice,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - cannot find coin denom",
|
||||
func() {
|
||||
suite.backend.clientCtx.Viper = viper.New()
|
||||
suite.backend.clientCtx.Viper.Set("telemetry.global-labels", []interface{}{})
|
||||
},
|
||||
*defaultGasPrice,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
output := suite.backend.SetGasPrice(tc.gasPrice)
|
||||
suite.Require().Equal(tc.expOutput, output)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Combine these 2 into one test since the code is identical
|
||||
func (suite *BackendTestSuite) TestListAccounts() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expAddr []common.Address
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - returns empty address",
|
||||
func() {},
|
||||
[]common.Address{},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
output, err := suite.backend.ListAccounts()
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expAddr, output)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestAccounts() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expAddr []common.Address
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - returns empty address",
|
||||
func() {},
|
||||
[]common.Address{},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
output, err := suite.backend.Accounts()
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expAddr, output)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestSyncing() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expResponse interface{}
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Can't get status",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterStatusError(client)
|
||||
},
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - Node not catching up",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterStatus(client)
|
||||
},
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Node is catching up",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterStatus(client)
|
||||
status, _ := client.Status(suite.backend.ctx)
|
||||
status.SyncInfo.CatchingUp = true
|
||||
|
||||
},
|
||||
map[string]interface{}{
|
||||
"startingBlock": hexutil.Uint64(0),
|
||||
"currentBlock": hexutil.Uint64(0),
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
output, err := suite.backend.Syncing()
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expResponse, output)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestSetEtherbase() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
etherbase common.Address
|
||||
expResult bool
|
||||
}{
|
||||
{
|
||||
"pass - Failed to get coinbase address",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterStatusError(client)
|
||||
},
|
||||
common.Address{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - the minimum fee is not set",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterStatus(client)
|
||||
RegisterValidatorAccount(queryClient, suite.acc)
|
||||
},
|
||||
common.Address{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - error querying for account ",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterStatus(client)
|
||||
RegisterValidatorAccount(queryClient, suite.acc)
|
||||
c := sdk.NewDecCoin("aphoton", sdk.NewIntFromBigInt(big.NewInt(1)))
|
||||
suite.backend.cfg.SetMinGasPrices(sdk.DecCoins{c})
|
||||
delAddr, _ := suite.backend.GetCoinbase()
|
||||
//account, _ := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, delAddr)
|
||||
delCommonAddr := common.BytesToAddress(delAddr.Bytes())
|
||||
request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(delCommonAddr.Bytes()).String()}
|
||||
requestMarshal, _ := request.Marshal()
|
||||
RegisterABCIQueryWithOptionsError(
|
||||
client,
|
||||
"/cosmos.auth.v1beta1.Query/Account",
|
||||
requestMarshal,
|
||||
tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
|
||||
)
|
||||
},
|
||||
common.Address{},
|
||||
false,
|
||||
},
|
||||
// TODO: Finish this test case once ABCIQuery GetAccount is fixed
|
||||
//{
|
||||
// "pass - set the etherbase for the miner",
|
||||
// func() {
|
||||
// client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
// queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
// RegisterStatus(client)
|
||||
// RegisterValidatorAccount(queryClient, suite.acc)
|
||||
// c := sdk.NewDecCoin("aphoton", sdk.NewIntFromBigInt(big.NewInt(1)))
|
||||
// suite.backend.cfg.SetMinGasPrices(sdk.DecCoins{c})
|
||||
// delAddr, _ := suite.backend.GetCoinbase()
|
||||
// account, _ := suite.backend.clientCtx.AccountRetriever.GetAccount(suite.backend.clientCtx, delAddr)
|
||||
// delCommonAddr := common.BytesToAddress(delAddr.Bytes())
|
||||
// request := &authtypes.QueryAccountRequest{Address: sdk.AccAddress(delCommonAddr.Bytes()).String()}
|
||||
// requestMarshal, _ := request.Marshal()
|
||||
// RegisterABCIQueryAccount(
|
||||
// client,
|
||||
// requestMarshal,
|
||||
// tmrpcclient.ABCIQueryOptions{Height: int64(1), Prove: false},
|
||||
// account,
|
||||
// )
|
||||
// },
|
||||
// common.Address{},
|
||||
// false,
|
||||
//},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
output := suite.backend.SetEtherbase(tc.etherbase)
|
||||
|
||||
suite.Require().Equal(tc.expResult, output)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestImportRawKey() {
|
||||
priv, _ := ethsecp256k1.GenerateKey()
|
||||
privHex := common.Bytes2Hex(priv.Bytes())
|
||||
pubAddr := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
privKey string
|
||||
password string
|
||||
expAddr common.Address
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - not a valid private key",
|
||||
func() {},
|
||||
"",
|
||||
"",
|
||||
common.Address{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - returning correct address",
|
||||
func() {},
|
||||
privHex,
|
||||
"",
|
||||
pubAddr,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
output, err := suite.backend.ImportRawKey(tc.privKey, tc.password)
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expAddr, output)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
260
rpc/backend/sign_tx_test.go
Normal file
260
rpc/backend/sign_tx_test.go
Normal file
@ -0,0 +1,260 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/crypto"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
goethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
"github.com/evmos/ethermint/tests"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
func (suite *BackendTestSuite) TestSendTransaction() {
|
||||
gasPrice := new(hexutil.Big)
|
||||
gas := hexutil.Uint64(1)
|
||||
zeroGas := hexutil.Uint64(0)
|
||||
toAddr := tests.GenerateAddress()
|
||||
priv, _ := ethsecp256k1.GenerateKey()
|
||||
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
||||
nonce := hexutil.Uint64(1)
|
||||
baseFee := sdk.NewInt(1)
|
||||
callArgsDefault := evmtypes.TransactionArgs{
|
||||
From: &from,
|
||||
To: &toAddr,
|
||||
GasPrice: gasPrice,
|
||||
Gas: &gas,
|
||||
Nonce: &nonce,
|
||||
}
|
||||
|
||||
hash := common.Hash{}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
args evmtypes.TransactionArgs
|
||||
expHash common.Hash
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Can't find account in Keyring",
|
||||
func() {},
|
||||
evmtypes.TransactionArgs{},
|
||||
hash,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Block error can't set Tx defaults",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
||||
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlockError(client, 1)
|
||||
},
|
||||
callArgsDefault,
|
||||
hash,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Cannot validate transaction gas set to 0",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
||||
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
},
|
||||
evmtypes.TransactionArgs{
|
||||
From: &from,
|
||||
To: &toAddr,
|
||||
GasPrice: gasPrice,
|
||||
Gas: &zeroGas,
|
||||
Nonce: &nonce,
|
||||
},
|
||||
hash,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Cannot broadcast transaction",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
||||
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
|
||||
msg := callArgsDefault.ToTransaction()
|
||||
msg.Sign(ethSigner, suite.backend.clientCtx.Keyring)
|
||||
tx, _ := msg.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
||||
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
|
||||
txBytes, _ := txEncoder(tx)
|
||||
RegisterBroadcastTxError(client, txBytes)
|
||||
},
|
||||
callArgsDefault,
|
||||
common.Hash{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - Return the transaction hash",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
||||
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterBlock(client, 1, nil)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, baseFee)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
|
||||
msg := callArgsDefault.ToTransaction()
|
||||
msg.Sign(ethSigner, suite.backend.clientCtx.Keyring)
|
||||
tx, _ := msg.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
||||
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
|
||||
txBytes, _ := txEncoder(tx)
|
||||
RegisterBroadcastTx(client, txBytes)
|
||||
},
|
||||
callArgsDefault,
|
||||
hash,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
if tc.expPass {
|
||||
// Sign the transaction and get the hash
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
|
||||
msg := callArgsDefault.ToTransaction()
|
||||
msg.Sign(ethSigner, suite.backend.clientCtx.Keyring)
|
||||
tc.expHash = msg.AsTransaction().Hash()
|
||||
}
|
||||
responseHash, err := suite.backend.SendTransaction(tc.args)
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expHash, responseHash)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestSign() {
|
||||
from, priv := tests.NewAddrKey()
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
fromAddr common.Address
|
||||
inputBz hexutil.Bytes
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - can't find key in Keyring",
|
||||
func() {},
|
||||
from,
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - sign nil data",
|
||||
func() {
|
||||
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
||||
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
||||
},
|
||||
from,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
responseBz, err := suite.backend.Sign(tc.fromAddr, tc.inputBz)
|
||||
if tc.expPass {
|
||||
signature, _, err := suite.backend.clientCtx.Keyring.SignByAddress((sdk.AccAddress)(from.Bytes()), tc.inputBz)
|
||||
signature[goethcrypto.RecoveryIDOffset] += 27
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal((hexutil.Bytes)(signature), responseBz)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestSignTypedData() {
|
||||
from, priv := tests.NewAddrKey()
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
fromAddr common.Address
|
||||
inputTypedData apitypes.TypedData
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - can't find key in Keyring",
|
||||
func() {},
|
||||
from,
|
||||
apitypes.TypedData{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - empty TypeData",
|
||||
func() {
|
||||
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
||||
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
||||
},
|
||||
from,
|
||||
apitypes.TypedData{},
|
||||
false,
|
||||
},
|
||||
// TODO: Generate a TypedData msg
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
responseBz, err := suite.backend.SignTypedData(tc.fromAddr, tc.inputTypedData)
|
||||
|
||||
if tc.expPass {
|
||||
sigHash, _, err := apitypes.TypedDataAndHash(tc.inputTypedData)
|
||||
signature, _, err := suite.backend.clientCtx.Keyring.SignByAddress((sdk.AccAddress)(from.Bytes()), sigHash)
|
||||
signature[goethcrypto.RecoveryIDOffset] += 27
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal((hexutil.Bytes)(signature), responseBz)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -112,7 +112,7 @@ func (b *Backend) TraceTransaction(hash common.Hash, config *evmtypes.TraceConfi
|
||||
return decodedResult, nil
|
||||
}
|
||||
|
||||
// traceBlock configures a new tracer according to the provided configuration, and
|
||||
// TraceBlock configures a new tracer according to the provided configuration, and
|
||||
// executes all the transactions contained within. The return value will be one item
|
||||
// per transaction, dependent on the requested tracer.
|
||||
func (b *Backend) TraceBlock(height rpctypes.BlockNumber,
|
||||
|
247
rpc/backend/tracing_test.go
Normal file
247
rpc/backend/tracing_test.go
Normal file
@ -0,0 +1,247 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/crypto"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||
"github.com/evmos/ethermint/indexer"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmlog "github.com/tendermint/tendermint/libs/log"
|
||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
func (suite *BackendTestSuite) TestTraceTransaction() {
|
||||
msgEthereumTx, _ := suite.buildEthereumTx()
|
||||
msgEthereumTx2, _ := suite.buildEthereumTx()
|
||||
|
||||
txHash := msgEthereumTx.AsTransaction().Hash()
|
||||
txHash2 := msgEthereumTx2.AsTransaction().Hash()
|
||||
|
||||
priv, _ := ethsecp256k1.GenerateKey()
|
||||
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
|
||||
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
|
||||
armor := crypto.EncryptArmorPrivKey(priv, "", "eth_secp256k1")
|
||||
suite.backend.clientCtx.Keyring.ImportPrivKey("test_key", armor, "")
|
||||
ethSigner := ethtypes.LatestSigner(suite.backend.ChainConfig())
|
||||
|
||||
txEncoder := suite.backend.clientCtx.TxConfig.TxEncoder()
|
||||
|
||||
msgEthereumTx.From = from.String()
|
||||
msgEthereumTx.Sign(ethSigner, suite.signer)
|
||||
tx, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
||||
txBz, _ := txEncoder(tx)
|
||||
|
||||
msgEthereumTx2.From = from.String()
|
||||
msgEthereumTx2.Sign(ethSigner, suite.signer)
|
||||
tx2, _ := msgEthereumTx.BuildTx(suite.backend.clientCtx.TxConfig.NewTxBuilder(), "aphoton")
|
||||
txBz2, _ := txEncoder(tx2)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
block *types.Block
|
||||
responseBlock []*abci.ResponseDeliverTx
|
||||
expResult interface{}
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - tx not found",
|
||||
func() {},
|
||||
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{}}},
|
||||
[]*abci.ResponseDeliverTx{
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("0")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
nil,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - block not found",
|
||||
func() {
|
||||
//var header metadata.MD
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockError(client, 1)
|
||||
},
|
||||
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
|
||||
[]*abci.ResponseDeliverTx{
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("0")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{"test": "hello"},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"pass - transaction found in a block with multiple transactions",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockMultipleTxs(client, 1, []types.Tx{txBz, txBz2})
|
||||
RegisterTraceTransactionWithPredecessors(queryClient, msgEthereumTx, []*evmtypes.MsgEthereumTx{msgEthereumTx})
|
||||
},
|
||||
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz, txBz2}}},
|
||||
[]*abci.ResponseDeliverTx{
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("0")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(txHash2.Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("1")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{"test": "hello"},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - transaction found",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlock(client, 1, txBz)
|
||||
RegisterTraceTransaction(queryClient, msgEthereumTx)
|
||||
},
|
||||
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
|
||||
[]*abci.ResponseDeliverTx{
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("0")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{"test": "hello"},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
db := dbm.NewMemDB()
|
||||
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
|
||||
|
||||
err := suite.backend.indexer.IndexBlock(tc.block, tc.responseBlock)
|
||||
txResult, err := suite.backend.TraceTransaction(txHash, nil)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expResult, txResult)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestTraceBlock() {
|
||||
msgEthTx, bz := suite.buildEthereumTx()
|
||||
emptyBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{}, nil, nil)
|
||||
filledBlock := tmtypes.MakeBlock(1, []tmtypes.Tx{bz}, nil, nil)
|
||||
resBlockEmpty := tmrpctypes.ResultBlock{Block: emptyBlock, BlockID: emptyBlock.LastBlockID}
|
||||
resBlockFilled := tmrpctypes.ResultBlock{Block: filledBlock, BlockID: filledBlock.LastBlockID}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
expTraceResults []*evmtypes.TxTraceResult
|
||||
resBlock *tmrpctypes.ResultBlock
|
||||
config *evmtypes.TraceConfig
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - no transaction returning empty array",
|
||||
func() {},
|
||||
[]*evmtypes.TxTraceResult{},
|
||||
&resBlockEmpty,
|
||||
&evmtypes.TraceConfig{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail - cannot unmarshal data",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterTraceBlock(queryClient, []*evmtypes.MsgEthereumTx{msgEthTx})
|
||||
|
||||
},
|
||||
[]*evmtypes.TxTraceResult{},
|
||||
&resBlockFilled,
|
||||
&evmtypes.TraceConfig{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(fmt.Sprintf("case %s", tc.name), func() {
|
||||
suite.SetupTest() // reset test and queries
|
||||
tc.registerMock()
|
||||
|
||||
traceResults, err := suite.backend.TraceBlock(1, tc.config, tc.resBlock)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(tc.expTraceResults, traceResults)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -342,7 +342,7 @@ func (b *Backend) queryTendermintTxIndexer(query string, txGetter func(*rpctypes
|
||||
return rpctypes.ParseTxIndexerResult(txResult, tx, txGetter)
|
||||
}
|
||||
|
||||
// getTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`.
|
||||
// GetTransactionByBlockAndIndex is the common code shared by `GetTransactionByBlockNumberAndIndex` and `GetTransactionByBlockHashAndIndex`.
|
||||
func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
||||
blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height)
|
||||
if err != nil {
|
||||
|
600
rpc/backend/tx_info_test.go
Normal file
600
rpc/backend/tx_info_test.go
Normal file
@ -0,0 +1,600 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/evmos/ethermint/indexer"
|
||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||
rpctypes "github.com/evmos/ethermint/rpc/types"
|
||||
ethermint "github.com/evmos/ethermint/types"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmlog "github.com/tendermint/tendermint/libs/log"
|
||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTransactionByHash() {
|
||||
msgEthereumTx, _ := suite.buildEthereumTx()
|
||||
txHash := msgEthereumTx.AsTransaction().Hash()
|
||||
|
||||
txBz := suite.signAndEncodeEthTx(msgEthereumTx)
|
||||
block := &types.Block{Header: types.Header{Height: 1, ChainID: "test"}, Data: types.Data{Txs: []types.Tx{txBz}}}
|
||||
responseDeliver := []*abci.ResponseDeliverTx{
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("0")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
tx *evmtypes.MsgEthereumTx
|
||||
expRPCTx *rpctypes.RPCTransaction
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Block error",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockError(client, 1)
|
||||
},
|
||||
msgEthereumTx,
|
||||
rpcTransaction,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fail - Block Result error",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlock(client, 1, txBz)
|
||||
RegisterBlockResultsError(client, 1)
|
||||
},
|
||||
msgEthereumTx,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Base fee error",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterBlock(client, 1, txBz)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFeeError(queryClient)
|
||||
},
|
||||
msgEthereumTx,
|
||||
rpcTransaction,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Transaction found and returned",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterBlock(client, 1, txBz)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, sdk.NewInt(1))
|
||||
},
|
||||
msgEthereumTx,
|
||||
rpcTransaction,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
db := dbm.NewMemDB()
|
||||
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
|
||||
err := suite.backend.indexer.IndexBlock(block, responseDeliver)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
rpcTx, err := suite.backend.GetTransactionByHash(common.HexToHash(tc.tx.Hash))
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(rpcTx, tc.expRPCTx)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTransactionsByHashPending() {
|
||||
msgEthereumTx, bz := suite.buildEthereumTx()
|
||||
rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
tx *evmtypes.MsgEthereumTx
|
||||
expRPCTx *rpctypes.RPCTransaction
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Pending transactions returns error",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterUnconfirmedTxsError(client, nil)
|
||||
},
|
||||
msgEthereumTx,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail - Tx not found return nil",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterUnconfirmedTxs(client, nil, nil)
|
||||
},
|
||||
msgEthereumTx,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Tx found and returned",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterUnconfirmedTxs(client, nil, types.Txs{bz})
|
||||
},
|
||||
msgEthereumTx,
|
||||
rpcTransaction,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
rpcTx, err := suite.backend.getTransactionByHashPending(common.HexToHash(tc.tx.Hash))
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(rpcTx, tc.expRPCTx)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTxByEthHash() {
|
||||
msgEthereumTx, bz := suite.buildEthereumTx()
|
||||
rpcTransaction, _ := rpctypes.NewRPCTransaction(msgEthereumTx.AsTransaction(), common.Hash{}, 0, 0, big.NewInt(1), suite.backend.chainID)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
tx *evmtypes.MsgEthereumTx
|
||||
expRPCTx *rpctypes.RPCTransaction
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Indexer disabled can't find transaction",
|
||||
func() {
|
||||
suite.backend.indexer = nil
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, common.HexToHash(msgEthereumTx.Hash).Hex())
|
||||
RegisterTxSearch(client, query, bz)
|
||||
},
|
||||
msgEthereumTx,
|
||||
rpcTransaction,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
rpcTx, err := suite.backend.GetTxByEthHash(common.HexToHash(tc.tx.Hash))
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(rpcTx, tc.expRPCTx)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTransactionByBlockHashAndIndex() {
|
||||
_, bz := suite.buildEthereumTx()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
blockHash common.Hash
|
||||
expRPCTx *rpctypes.RPCTransaction
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - block not found",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockByHashError(client, common.Hash{}, bz)
|
||||
},
|
||||
common.Hash{},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Block results error",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockByHash(client, common.Hash{}, bz)
|
||||
RegisterBlockResultsError(client, 1)
|
||||
},
|
||||
common.Hash{},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
rpcTx, err := suite.backend.GetTransactionByBlockHashAndIndex(tc.blockHash, 1)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(rpcTx, tc.expRPCTx)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTransactionByBlockAndIndex() {
|
||||
msgEthTx, bz := suite.buildEthereumTx()
|
||||
|
||||
defaultBlock := types.MakeBlock(1, []types.Tx{bz}, nil, nil)
|
||||
defaultResponseDeliverTx := []*abci.ResponseDeliverTx{
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(common.HexToHash(msgEthTx.Hash).Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("0")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
txFromMsg, _ := rpctypes.NewTransactionFromMsg(
|
||||
msgEthTx,
|
||||
common.BytesToHash(defaultBlock.Hash().Bytes()),
|
||||
1,
|
||||
0,
|
||||
big.NewInt(1),
|
||||
suite.backend.chainID,
|
||||
)
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
block *tmrpctypes.ResultBlock
|
||||
idx hexutil.Uint
|
||||
expRPCTx *rpctypes.RPCTransaction
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"pass - block txs index out of bound ",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockResults(client, 1)
|
||||
},
|
||||
&tmrpctypes.ResultBlock{Block: types.MakeBlock(1, []types.Tx{bz}, nil, nil)},
|
||||
1,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Can't fetch base fee",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFeeError(queryClient)
|
||||
},
|
||||
&tmrpctypes.ResultBlock{Block: defaultBlock},
|
||||
0,
|
||||
txFromMsg,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - Gets Tx by transaction index",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
db := dbm.NewMemDB()
|
||||
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
|
||||
txBz := suite.signAndEncodeEthTx(msgEthTx)
|
||||
block := &types.Block{Header: types.Header{Height: 1, ChainID: "test"}, Data: types.Data{Txs: []types.Tx{txBz}}}
|
||||
err := suite.backend.indexer.IndexBlock(block, defaultResponseDeliverTx)
|
||||
suite.Require().NoError(err)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, sdk.NewInt(1))
|
||||
},
|
||||
&tmrpctypes.ResultBlock{Block: defaultBlock},
|
||||
0,
|
||||
txFromMsg,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - returns the Ethereum format transaction by the Ethereum hash",
|
||||
func() {
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, sdk.NewInt(1))
|
||||
},
|
||||
&tmrpctypes.ResultBlock{Block: defaultBlock},
|
||||
0,
|
||||
txFromMsg,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
rpcTx, err := suite.backend.GetTransactionByBlockAndIndex(tc.block, tc.idx)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(rpcTx, tc.expRPCTx)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTransactionByBlockNumberAndIndex() {
|
||||
msgEthTx, bz := suite.buildEthereumTx()
|
||||
defaultBlock := types.MakeBlock(1, []types.Tx{bz}, nil, nil)
|
||||
txFromMsg, _ := rpctypes.NewTransactionFromMsg(
|
||||
msgEthTx,
|
||||
common.BytesToHash(defaultBlock.Hash().Bytes()),
|
||||
1,
|
||||
0,
|
||||
big.NewInt(1),
|
||||
suite.backend.chainID,
|
||||
)
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
blockNum rpctypes.BlockNumber
|
||||
idx hexutil.Uint
|
||||
expRPCTx *rpctypes.RPCTransaction
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - block not found return nil",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterBlockError(client, 1)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"pass - returns the transaction identified by block number and index",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
RegisterBlock(client, 1, bz)
|
||||
RegisterBlockResults(client, 1)
|
||||
RegisterBaseFee(queryClient, sdk.NewInt(1))
|
||||
},
|
||||
0,
|
||||
0,
|
||||
txFromMsg,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
rpcTx, err := suite.backend.GetTransactionByBlockNumberAndIndex(tc.blockNum, tc.idx)
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(rpcTx, tc.expRPCTx)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTransactionByTxIndex() {
|
||||
_, bz := suite.buildEthereumTx()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
height int64
|
||||
index uint
|
||||
expTxResult *ethermint.TxResult
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Ethereum tx with query not found",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
suite.backend.indexer = nil
|
||||
RegisterTxSearch(client, "tx.height=0 AND ethereum_tx.txIndex=0", bz)
|
||||
},
|
||||
0,
|
||||
0,
|
||||
ðermint.TxResult{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
txResults, err := suite.backend.GetTxByTxIndex(tc.height, tc.index)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(txResults, tc.expTxResult)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestQueryTendermintTxIndexer() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
txGetter func(*rpctypes.ParsedTxs) *rpctypes.ParsedTx
|
||||
query string
|
||||
expTxResult *ethermint.TxResult
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Ethereum tx with query not found",
|
||||
func() {
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterTxSearchEmpty(client, "")
|
||||
},
|
||||
func(txs *rpctypes.ParsedTxs) *rpctypes.ParsedTx {
|
||||
return &rpctypes.ParsedTx{}
|
||||
},
|
||||
"",
|
||||
ðermint.TxResult{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
txResults, err := suite.backend.queryTendermintTxIndexer(tc.query, tc.txGetter)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(txResults, tc.expTxResult)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *BackendTestSuite) TestGetTransactionReceipt() {
|
||||
msgEthereumTx, _ := suite.buildEthereumTx()
|
||||
txHash := msgEthereumTx.AsTransaction().Hash()
|
||||
|
||||
txBz := suite.signAndEncodeEthTx(msgEthereumTx)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
registerMock func()
|
||||
tx *evmtypes.MsgEthereumTx
|
||||
block *types.Block
|
||||
blockResult []*abci.ResponseDeliverTx
|
||||
expTxReceipt map[string]interface{}
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"fail - Receipts do not match ",
|
||||
func() {
|
||||
var header metadata.MD
|
||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||
client := suite.backend.clientCtx.Client.(*mocks.Client)
|
||||
RegisterParams(queryClient, &header, 1)
|
||||
RegisterParamsWithoutHeader(queryClient, 1)
|
||||
RegisterBlock(client, 1, txBz)
|
||||
RegisterBlockResults(client, 1)
|
||||
|
||||
},
|
||||
msgEthereumTx,
|
||||
&types.Block{Header: types.Header{Height: 1}, Data: types.Data{Txs: []types.Tx{txBz}}},
|
||||
[]*abci.ResponseDeliverTx{
|
||||
{
|
||||
Code: 0,
|
||||
Events: []abci.Event{
|
||||
{Type: evmtypes.EventTypeEthereumTx, Attributes: []abci.EventAttribute{
|
||||
{Key: []byte("ethereumTxHash"), Value: []byte(txHash.Hex())},
|
||||
{Key: []byte("txIndex"), Value: []byte("0")},
|
||||
{Key: []byte("amount"), Value: []byte("1000")},
|
||||
{Key: []byte("txGasUsed"), Value: []byte("21000")},
|
||||
{Key: []byte("txHash"), Value: []byte("")},
|
||||
{Key: []byte("recipient"), Value: []byte("0x775b87ef5D82ca211811C1a02CE0fE0CA3a455d7")},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}(nil),
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.SetupTest() // reset
|
||||
tc.registerMock()
|
||||
|
||||
db := dbm.NewMemDB()
|
||||
suite.backend.indexer = indexer.NewKVIndexer(db, tmlog.NewNopLogger(), suite.backend.clientCtx)
|
||||
err := suite.backend.indexer.IndexBlock(tc.block, tc.blockResult)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
txReceipt, err := suite.backend.GetTransactionReceipt(common.HexToHash(tc.tx.Hash))
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(txReceipt, tc.expTxReceipt)
|
||||
} else {
|
||||
suite.Require().NotEqual(txReceipt, tc.expTxReceipt)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -261,7 +261,6 @@ func GetLogsFromBlockResults(blockRes *tmrpctypes.ResultBlockResults) ([][]*etht
|
||||
|
||||
blockLogs = append(blockLogs, logs...)
|
||||
}
|
||||
|
||||
return blockLogs, nil
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user