forked from cerc-io/laconicd-deprecated
tests: Add unit tests for rpc client endpoints (#1409)
* test: add preliminary unit tests and additional mocks for chain_info, account_info and filters * tests: added additional mocked client calls * tests: bumped coverage of call_tx to 56% and chain_info to 77% * tests: bumped call_tx coverage to 70.2% and added additional mock client calls * tests: tx_info preliminary tests added for debugging. * tests: added test coverage for sign_tx and additional mocks * tests: tx_info test coverage bumped to 60.3% * test: coverage for tracing_tests now at 72% * tests: added fee makert query client mocks and bumped chain_info to 87.6% coverage. * tests: failing Cosmos auth module account query. * tests: added FeeMarket Params mock to call_tx_test * cleanup some unused code * tests: added helper function to test suite for signing a Tx and bumped coverage of tx_info to 71.2% * test: commented GetAccount error case and bumped chain_info to 90.3% coverage * test: cleanup of tests in node_info, sign_tx and account_info * Clean up print Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> * Apply suggestions from code review * fix import issues Co-authored-by: Vladislav Varadinov <vlad@evmos.org> Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Freddy Caceres <facs95@gmail.com>
This commit is contained in:
parent
d450bed61c
commit
9e5f4aaa73
@ -103,6 +103,18 @@ func (suite *BackendTestSuite) TestGetProof() {
|
|||||||
false,
|
false,
|
||||||
&rpctypes.AccountResult{},
|
&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",
|
"pass",
|
||||||
address1,
|
address1,
|
||||||
@ -351,6 +363,27 @@ func (suite *BackendTestSuite) TestGetTransactionCount() {
|
|||||||
true,
|
true,
|
||||||
hexutil.Uint64(0),
|
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 {
|
for _, tc := range testCases {
|
||||||
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"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/crypto/keyring"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
@ -16,12 +15,10 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
"github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||||
"github.com/evmos/ethermint/crypto/hd"
|
|
||||||
rpctypes "github.com/evmos/ethermint/rpc/types"
|
rpctypes "github.com/evmos/ethermint/rpc/types"
|
||||||
"github.com/evmos/ethermint/server/config"
|
"github.com/evmos/ethermint/server/config"
|
||||||
ethermint "github.com/evmos/ethermint/types"
|
ethermint "github.com/evmos/ethermint/types"
|
||||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
"github.com/spf13/viper"
|
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
)
|
)
|
||||||
@ -162,23 +159,6 @@ func NewBackend(
|
|||||||
panic(err)
|
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{
|
return &Backend{
|
||||||
ctx: context.Background(),
|
ctx: context.Background(),
|
||||||
clientCtx: clientCtx,
|
clientCtx: clientCtx,
|
||||||
|
@ -3,6 +3,7 @@ package backend
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -33,6 +34,7 @@ type BackendTestSuite struct {
|
|||||||
suite.Suite
|
suite.Suite
|
||||||
backend *Backend
|
backend *Backend
|
||||||
acc sdk.AccAddress
|
acc sdk.AccAddress
|
||||||
|
signer keyring.Signer
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBackendTestSuite(t *testing.T) {
|
func TestBackendTestSuite(t *testing.T) {
|
||||||
@ -61,6 +63,10 @@ func (suite *BackendTestSuite) SetupTest() {
|
|||||||
Seq: uint64(1),
|
Seq: uint64(1),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv, err := ethsecp256k1.GenerateKey()
|
||||||
|
suite.signer = tests.NewSigner(priv)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
|
||||||
clientCtx := client.Context{}.WithChainID("ethermint_9000-1").
|
clientCtx := client.Context{}.WithChainID("ethermint_9000-1").
|
||||||
WithHeight(1).
|
WithHeight(1).
|
||||||
@ -70,13 +76,18 @@ func (suite *BackendTestSuite) SetupTest() {
|
|||||||
WithAccountRetriever(client.TestAccountRetriever{Accounts: accounts})
|
WithAccountRetriever(client.TestAccountRetriever{Accounts: accounts})
|
||||||
|
|
||||||
allowUnprotectedTxs := false
|
allowUnprotectedTxs := false
|
||||||
|
|
||||||
idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx)
|
idxer := indexer.NewKVIndexer(dbm.NewMemDB(), ctx.Logger, clientCtx)
|
||||||
|
|
||||||
suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer)
|
suite.backend = NewBackend(ctx, ctx.Logger, clientCtx, allowUnprotectedTxs, idxer)
|
||||||
suite.backend.queryClient.QueryClient = mocks.NewEVMQueryClient(suite.T())
|
suite.backend.queryClient.QueryClient = mocks.NewEVMQueryClient(suite.T())
|
||||||
suite.backend.clientCtx.Client = mocks.NewClient(suite.T())
|
suite.backend.clientCtx.Client = mocks.NewClient(suite.T())
|
||||||
|
suite.backend.queryClient.FeeMarket = mocks.NewFeeMarketQueryClient(suite.T())
|
||||||
suite.backend.ctx = rpctypes.ContextWithHeight(1)
|
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
|
// buildEthereumTx returns an example legacy Ethereum transaction
|
||||||
@ -158,3 +169,25 @@ func (suite *BackendTestSuite) generateTestKeyring(clientDir string) (keyring.Ke
|
|||||||
encCfg := encoding.MakeConfig(app.ModuleBasics)
|
encCfg := encoding.MakeConfig(app.ModuleBasics)
|
||||||
return keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, encCfg.Codec, []keyring.Option{hd.EthSecp256k1Option()}...)
|
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",
|
"fail - invalid block header height",
|
||||||
func() {
|
func() {
|
||||||
height := int64(1)
|
|
||||||
var header metadata.MD
|
var header metadata.MD
|
||||||
|
height := int64(1)
|
||||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||||
RegisterParamsInvalidHeight(queryClient, &header, int64(height))
|
RegisterParamsInvalidHeight(queryClient, &header, int64(height))
|
||||||
},
|
},
|
||||||
@ -41,8 +41,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
|
|||||||
{
|
{
|
||||||
"fail - invalid block header",
|
"fail - invalid block header",
|
||||||
func() {
|
func() {
|
||||||
height := int64(1)
|
|
||||||
var header metadata.MD
|
var header metadata.MD
|
||||||
|
height := int64(1)
|
||||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||||
RegisterParamsInvalidHeader(queryClient, &header, int64(height))
|
RegisterParamsInvalidHeader(queryClient, &header, int64(height))
|
||||||
},
|
},
|
||||||
@ -52,8 +52,8 @@ func (suite *BackendTestSuite) TestBlockNumber() {
|
|||||||
{
|
{
|
||||||
"pass - app state header height 1",
|
"pass - app state header height 1",
|
||||||
func() {
|
func() {
|
||||||
height := int64(1)
|
|
||||||
var header metadata.MD
|
var header metadata.MD
|
||||||
|
height := int64(1)
|
||||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||||
RegisterParams(queryClient, &header, int64(height))
|
RegisterParams(queryClient, &header, int64(height))
|
||||||
},
|
},
|
||||||
@ -552,8 +552,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
|
|||||||
"fail - blockNum < 0 with app state height error",
|
"fail - blockNum < 0 with app state height error",
|
||||||
ethrpc.BlockNumber(-1),
|
ethrpc.BlockNumber(-1),
|
||||||
func(_ ethrpc.BlockNumber) {
|
func(_ ethrpc.BlockNumber) {
|
||||||
appHeight := int64(1)
|
|
||||||
var header metadata.MD
|
var header metadata.MD
|
||||||
|
appHeight := int64(1)
|
||||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||||
RegisterParamsError(queryClient, &header, appHeight)
|
RegisterParamsError(queryClient, &header, appHeight)
|
||||||
},
|
},
|
||||||
@ -564,8 +564,8 @@ func (suite *BackendTestSuite) TestTendermintBlockByNumber() {
|
|||||||
"pass - blockNum < 0 with app state height >= 1",
|
"pass - blockNum < 0 with app state height >= 1",
|
||||||
ethrpc.BlockNumber(-1),
|
ethrpc.BlockNumber(-1),
|
||||||
func(blockNum ethrpc.BlockNumber) {
|
func(blockNum ethrpc.BlockNumber) {
|
||||||
appHeight := int64(1)
|
|
||||||
var header metadata.MD
|
var header metadata.MD
|
||||||
|
appHeight := int64(1)
|
||||||
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient)
|
||||||
RegisterParams(queryClient, &header, appHeight)
|
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"
|
"fmt"
|
||||||
"math/big"
|
"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"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/tendermint/tendermint/abci/types"
|
"github.com/tendermint/tendermint/abci/types"
|
||||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"testing"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
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/ethereum/go-ethereum/common"
|
||||||
"github.com/evmos/ethermint/rpc/backend/mocks"
|
"github.com/evmos/ethermint/rpc/backend/mocks"
|
||||||
rpc "github.com/evmos/ethermint/rpc/types"
|
rpc "github.com/evmos/ethermint/rpc/types"
|
||||||
|
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||||
mock "github.com/stretchr/testify/mock"
|
mock "github.com/stretchr/testify/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
@ -15,6 +18,7 @@ import (
|
|||||||
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
|
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
|
||||||
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client defines a mocked object that implements the Tendermint JSON-RPC Client
|
// 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.
|
// To use a mock method it has to be registered in a given test.
|
||||||
var _ tmrpcclient.Client = &mocks.Client{}
|
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
|
// 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(
|
func RegisterBlock(
|
||||||
client *mocks.Client,
|
client *mocks.Client,
|
||||||
height int64,
|
height int64,
|
||||||
@ -34,16 +105,14 @@ func RegisterBlock(
|
|||||||
if tx == nil {
|
if tx == nil {
|
||||||
emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil)
|
emptyBlock := types.MakeBlock(height, []types.Tx{}, nil, nil)
|
||||||
resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock}
|
resBlock := &tmrpctypes.ResultBlock{Block: emptyBlock}
|
||||||
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
|
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
|
||||||
Return(resBlock, nil)
|
|
||||||
return resBlock, nil
|
return resBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// with tx
|
// with tx
|
||||||
block := types.MakeBlock(height, []types.Tx{tx}, nil, nil)
|
block := types.MakeBlock(height, []types.Tx{tx}, nil, nil)
|
||||||
resBlock := &tmrpctypes.ResultBlock{Block: block}
|
resBlock := &tmrpctypes.ResultBlock{Block: block}
|
||||||
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).
|
client.On("Block", rpc.ContextWithHeight(height), mock.AnythingOfType("*int64")).Return(resBlock, nil)
|
||||||
Return(resBlock, nil)
|
|
||||||
return resBlock, nil
|
return resBlock, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +170,26 @@ func TestRegisterConsensusParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BlockResults
|
// 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(
|
func RegisterBlockResults(
|
||||||
client *mocks.Client,
|
client *mocks.Client,
|
||||||
height int64,
|
height int64,
|
||||||
@ -167,3 +256,22 @@ func RegisterABCIQueryWithOptions(client *mocks.Client, height int64, path strin
|
|||||||
},
|
},
|
||||||
}, nil)
|
}, 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
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
||||||
@ -19,6 +18,8 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// QueryClient defines a mocked object that implements the ethermint GRPC
|
// 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.
|
// To use a mock method it has to be registered in a given test.
|
||||||
var _ evmtypes.QueryClient = &mocks.EVMQueryClient{}
|
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
|
// Params
|
||||||
func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
func RegisterParams(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
||||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
|
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) {
|
func RegisterParamsInvalidHeader(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
||||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
|
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
|
||||||
Return(&evmtypes.QueryParamsResponse{}, nil).
|
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
|
// Params returns error
|
||||||
func RegisterParamsError(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
func RegisterParamsError(queryClient *mocks.EVMQueryClient, header *metadata.MD, height int64) {
|
||||||
queryClient.On("Params", rpc.ContextWithHeight(height), &evmtypes.QueryParamsRequest{}, grpc.Header(header)).
|
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) {
|
func TestRegisterParams(t *testing.T) {
|
||||||
queryClient := mocks.NewEVMQueryClient(t)
|
|
||||||
var header metadata.MD
|
var header metadata.MD
|
||||||
|
queryClient := mocks.NewEVMQueryClient(t)
|
||||||
|
|
||||||
height := int64(1)
|
height := int64(1)
|
||||||
RegisterParams(queryClient, &header, height)
|
RegisterParams(queryClient, &header, height)
|
||||||
|
|
||||||
@ -91,6 +135,26 @@ func TestRegisterParamsError(t *testing.T) {
|
|||||||
require.Error(t, err)
|
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
|
// BaseFee
|
||||||
func RegisterBaseFee(queryClient *mocks.EVMQueryClient, baseFee sdk.Int) {
|
func RegisterBaseFee(queryClient *mocks.EVMQueryClient, baseFee sdk.Int) {
|
||||||
queryClient.On("BaseFee", rpc.ContextWithHeight(1), &evmtypes.QueryBaseFeeRequest{}).
|
queryClient.On("BaseFee", rpc.ContextWithHeight(1), &evmtypes.QueryBaseFeeRequest{}).
|
||||||
@ -137,12 +201,7 @@ func TestRegisterBaseFeeDisabled(t *testing.T) {
|
|||||||
// ValidatorAccount
|
// ValidatorAccount
|
||||||
func RegisterValidatorAccount(queryClient *mocks.EVMQueryClient, validator sdk.AccAddress) {
|
func RegisterValidatorAccount(queryClient *mocks.EVMQueryClient, validator sdk.AccAddress) {
|
||||||
queryClient.On("ValidatorAccount", rpc.ContextWithHeight(1), &evmtypes.QueryValidatorAccountRequest{}).
|
queryClient.On("ValidatorAccount", rpc.ContextWithHeight(1), &evmtypes.QueryValidatorAccountRequest{}).
|
||||||
Return(
|
Return(&evmtypes.QueryValidatorAccountResponse{AccountAddress: validator.String()}, nil)
|
||||||
&evmtypes.QueryValidatorAccountResponse{
|
|
||||||
AccountAddress: validator.String(),
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterValidatorAccountError(queryClient *mocks.EVMQueryClient) {
|
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 {
|
if resBlock == nil {
|
||||||
return nil, errors.Errorf("block not found for hash %s", hash)
|
return nil, errors.Errorf("block not found for hash %s", hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
return b.GetLogsByHeight(&resBlock.Block.Header.Height)
|
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
|
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
|
// executes all the transactions contained within. The return value will be one item
|
||||||
// per transaction, dependent on the requested tracer.
|
// per transaction, dependent on the requested tracer.
|
||||||
func (b *Backend) TraceBlock(height rpctypes.BlockNumber,
|
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)
|
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) {
|
func (b *Backend) GetTransactionByBlockAndIndex(block *tmrpctypes.ResultBlock, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) {
|
||||||
blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height)
|
blockRes, err := b.TendermintBlockResultByNumber(&block.Block.Height)
|
||||||
if err != nil {
|
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...)
|
blockLogs = append(blockLogs, logs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return blockLogs, nil
|
return blockLogs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user