diff --git a/CHANGELOG.md b/CHANGELOG.md index 98dd6905..d5f30640 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,15 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### API Breaking + +* (rpc) [tharsis#1070](https://github.com/tharsis/ethermint/pull/1070) Refactor `rpc/` package: + * `Backend` interface is now `BackendI`, which implements `EVMBackend` (for Ethereum namespaces) and `CosmosBackend` (for Cosmos namespaces) + * Previous `EVMBackend` type is now `Backend`, which is the concrete implementation of `BackendI` + * Move `rpc/ethereum/types` -> `rpc/types` + * Move `rpc/ethereum/backend` -> `rpc/backend` + * Move `rpc/ethereum/namespaces` -> `rpc/namespaces/ethereum` + ### Bug Fixes * (rpc) [tharsis#1059](https://github.com/tharsis/ethermint/pull/1059) Remove unnecessary event filtering logic on the `eth_baseFee` JSON-RPC endpoint. diff --git a/rpc/apis.go b/rpc/apis.go index e437c431..4eb0438e 100644 --- a/rpc/apis.go +++ b/rpc/apis.go @@ -10,22 +10,28 @@ import ( "github.com/ethereum/go-ethereum/rpc" - "github.com/tharsis/ethermint/rpc/ethereum/backend" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/debug" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/eth" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/eth/filters" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/miner" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/net" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/personal" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/txpool" - "github.com/tharsis/ethermint/rpc/ethereum/namespaces/web3" - "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/backend" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/debug" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/eth" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/eth/filters" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/miner" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/net" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/personal" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/txpool" + "github.com/tharsis/ethermint/rpc/namespaces/ethereum/web3" + "github.com/tharsis/ethermint/rpc/types" rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client" ) // RPC namespaces and API version const ( + // Cosmos namespaces + + CosmosNamespace = "cosmos" + + // Ethereum namespaces + Web3Namespace = "web3" EthNamespace = "eth" PersonalNamespace = "personal" @@ -37,17 +43,17 @@ const ( apiVersion = "1.0" ) -// APICreator creates the json-rpc api implementations. +// APICreator creates the JSON-RPC API implementations. type APICreator = func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API -// apiCreators defines the json-rpc api namespaces. +// apiCreators defines the JSON-RPC API namespaces. var apiCreators map[string]APICreator func init() { apiCreators = map[string]APICreator{ EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API { nonceLock := new(types.AddrLocker) - evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx) return []rpc.API{ { Namespace: EthNamespace, @@ -84,7 +90,7 @@ func init() { } }, PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API { - evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx) return []rpc.API{ { Namespace: PersonalNamespace, @@ -105,7 +111,7 @@ func init() { } }, DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API { - evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx) return []rpc.API{ { Namespace: DebugNamespace, @@ -116,7 +122,7 @@ func init() { } }, MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API { - evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx) + evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx) return []rpc.API{ { Namespace: MinerNamespace, diff --git a/rpc/backend/backend.go b/rpc/backend/backend.go new file mode 100644 index 00000000..e9692c8d --- /dev/null +++ b/rpc/backend/backend.go @@ -0,0 +1,114 @@ +package backend + +import ( + "context" + "math/big" + "time" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/server" + 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" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" + "github.com/tendermint/tendermint/libs/log" + tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" + "github.com/tharsis/ethermint/rpc/types" + "github.com/tharsis/ethermint/server/config" + ethermint "github.com/tharsis/ethermint/types" + evmtypes "github.com/tharsis/ethermint/x/evm/types" +) + +// BackendI implements the Cosmos and EVM backend. +type BackendI interface { // nolint: revive + CosmosBackend + EVMBackend +} + +// CosmosBackend implements the functionality shared within cosmos namespaces +// as defined by Wallet Connect V2: https://docs.walletconnect.com/2.0/json-rpc/cosmos. +// Implemented by Backend. +type CosmosBackend interface { + // TODO: define + // GetAccounts() + // SignDirect() + // SignAmino() +} + +// EVMBackend implements the functionality shared within ethereum namespaces +// as defined by EIP-1474: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1474.md +// Implemented by Backend. +type EVMBackend interface { + // General Ethereum API + RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection + RPCEVMTimeout() time.Duration // global timeout for eth_call over rpc: DoS protection + RPCTxFeeCap() float64 // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for send-transaction variants. The unit is ether. + + RPCMinGasPrice() int64 + SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) + + // Blockchain API + BlockNumber() (hexutil.Uint64, error) + GetTendermintBlockByNumber(blockNum types.BlockNumber) (*tmrpctypes.ResultBlock, error) + GetTendermintBlockByHash(blockHash common.Hash) (*tmrpctypes.ResultBlock, error) + GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) (map[string]interface{}, error) + GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) + BlockByNumber(blockNum types.BlockNumber) (*ethtypes.Block, error) + BlockByHash(blockHash common.Hash) (*ethtypes.Block, error) + CurrentHeader() *ethtypes.Header + HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Header, error) + HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error) + PendingTransactions() ([]*sdk.Tx, error) + GetTransactionCount(address common.Address, blockNum types.BlockNumber) (*hexutil.Uint64, error) + SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) + GetCoinbase() (sdk.AccAddress, error) + GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error) + GetTxByEthHash(txHash common.Hash) (*tmrpctypes.ResultTx, error) + GetTxByTxIndex(height int64, txIndex uint) (*tmrpctypes.ResultTx, error) + EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error) + BaseFee(height int64) (*big.Int, error) + + // Fee API + FeeHistory(blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*types.FeeHistoryResult, error) + + // Filter API + BloomStatus() (uint64, uint64) + GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) + GetLogsByHeight(height *int64) ([][]*ethtypes.Log, error) + ChainConfig() *params.ChainConfig + SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error) + GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults) []*evmtypes.MsgEthereumTx +} + +var _ BackendI = (*Backend)(nil) + +// Backend implements the BackendI interface +type Backend struct { + ctx context.Context + clientCtx client.Context + queryClient *types.QueryClient // gRPC query client + logger log.Logger + chainID *big.Int + cfg config.Config +} + +// NewBackend creates a new Backend instance for cosmos and ethereum namespaces +func NewBackend(ctx *server.Context, logger log.Logger, clientCtx client.Context) *Backend { + chainID, err := ethermint.ParseChainID(clientCtx.ChainID) + if err != nil { + panic(err) + } + + appConf := config.GetConfig(ctx.Viper) + + return &Backend{ + ctx: context.Background(), + clientCtx: clientCtx, + queryClient: types.NewQueryClient(clientCtx), + logger: logger.With("module", "backend"), + chainID: chainID, + cfg: appConf, + } +} diff --git a/rpc/ethereum/backend/backend.go b/rpc/backend/evm_backend.go similarity index 60% rename from rpc/ethereum/backend/backend.go rename to rpc/backend/evm_backend.go index 567f4e56..619afd1b 100644 --- a/rpc/ethereum/backend/backend.go +++ b/rpc/backend/evm_backend.go @@ -2,126 +2,46 @@ package backend import ( "bytes" - "context" "encoding/json" "fmt" "math/big" "strconv" "time" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/server" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/ethereum/go-ethereum/accounts/keystore" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" - tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" - + "github.com/pkg/errors" "google.golang.org/grpc" "google.golang.org/grpc/metadata" - "github.com/pkg/errors" - "github.com/tendermint/tendermint/libs/log" - tmtypes "github.com/tendermint/tendermint/types" - - "github.com/cosmos/cosmos-sdk/client" - sdk "github.com/cosmos/cosmos-sdk/types" - grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" - "github.com/tharsis/ethermint/rpc/ethereum/types" - "github.com/tharsis/ethermint/server/config" + tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client/flags" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + grpctypes "github.com/cosmos/cosmos-sdk/types/grpc" + + "github.com/tharsis/ethermint/rpc/types" ethermint "github.com/tharsis/ethermint/types" evmtypes "github.com/tharsis/ethermint/x/evm/types" feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types" ) -// Backend implements the functionality shared within namespaces. -// Implemented by EVMBackend. -type Backend interface { - // Fee API - FeeHistory(blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*types.FeeHistoryResult, error) - - // General Ethereum API - RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection - RPCEVMTimeout() time.Duration // global timeout for eth_call over rpc: DoS protection - RPCTxFeeCap() float64 // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for send-transaction variants. The unit is ether. - - RPCMinGasPrice() int64 - SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) - - // Blockchain API - BlockNumber() (hexutil.Uint64, error) - GetTendermintBlockByNumber(blockNum types.BlockNumber) (*tmrpctypes.ResultBlock, error) - GetTendermintBlockByHash(blockHash common.Hash) (*tmrpctypes.ResultBlock, error) - GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) (map[string]interface{}, error) - GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) - BlockByNumber(blockNum types.BlockNumber) (*ethtypes.Block, error) - BlockByHash(blockHash common.Hash) (*ethtypes.Block, error) - CurrentHeader() *ethtypes.Header - HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Header, error) - HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error) - PendingTransactions() ([]*sdk.Tx, error) - GetTransactionCount(address common.Address, blockNum types.BlockNumber) (*hexutil.Uint64, error) - SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) - GetCoinbase() (sdk.AccAddress, error) - GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error) - GetTxByEthHash(txHash common.Hash) (*tmrpctypes.ResultTx, error) - GetTxByTxIndex(height int64, txIndex uint) (*tmrpctypes.ResultTx, error) - EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error) - BaseFee(height int64) (*big.Int, error) - - // Filter API - BloomStatus() (uint64, uint64) - GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) - GetLogsByHeight(height *int64) ([][]*ethtypes.Log, error) - ChainConfig() *params.ChainConfig - SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error) - GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults) []*evmtypes.MsgEthereumTx -} - -var _ Backend = (*EVMBackend)(nil) - var bAttributeKeyEthereumBloom = []byte(evmtypes.AttributeKeyEthereumBloom) -// EVMBackend implements the Backend interface -type EVMBackend struct { - ctx context.Context - clientCtx client.Context - queryClient *types.QueryClient // gRPC query client - logger log.Logger - chainID *big.Int - cfg config.Config -} - -// NewEVMBackend creates a new EVMBackend instance -func NewEVMBackend(ctx *server.Context, logger log.Logger, clientCtx client.Context) *EVMBackend { - chainID, err := ethermint.ParseChainID(clientCtx.ChainID) - if err != nil { - panic(err) - } - - appConf := config.GetConfig(ctx.Viper) - - return &EVMBackend{ - ctx: context.Background(), - clientCtx: clientCtx, - queryClient: types.NewQueryClient(clientCtx), - logger: logger.With("module", "evm-backend"), - chainID: chainID, - cfg: appConf, - } -} - // BlockNumber returns the current block number in abci app state. // Because abci app state could lag behind from tendermint latest block, it's more stable // for the client to use the latest block number in abci app state than tendermint rpc. -func (e *EVMBackend) BlockNumber() (hexutil.Uint64, error) { +func (b *Backend) BlockNumber() (hexutil.Uint64, error) { // do any grpc query, ignore the response and use the returned block height var header metadata.MD - _, err := e.queryClient.Params(e.ctx, &evmtypes.QueryParamsRequest{}, grpc.Header(&header)) + _, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}, grpc.Header(&header)) if err != nil { return hexutil.Uint64(0), err } @@ -140,8 +60,8 @@ func (e *EVMBackend) BlockNumber() (hexutil.Uint64, error) { } // GetBlockByNumber returns the block identified by number. -func (e *EVMBackend) GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) (map[string]interface{}, error) { - resBlock, err := e.GetTendermintBlockByNumber(blockNum) +func (b *Backend) GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) (map[string]interface{}, error) { + resBlock, err := b.GetTendermintBlockByNumber(blockNum) if err != nil { return nil, err } @@ -151,9 +71,9 @@ func (e *EVMBackend) GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) ( return nil, nil } - res, err := e.EthBlockFromTendermint(resBlock.Block, fullTx) + res, err := b.EthBlockFromTendermint(resBlock.Block, fullTx) if err != nil { - e.logger.Debug("EthBlockFromTendermint failed", "height", blockNum, "error", err.Error()) + b.logger.Debug("EthBlockFromTendermint failed", "height", blockNum, "error", err.Error()) return nil, err } @@ -161,33 +81,33 @@ func (e *EVMBackend) GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) ( } // GetBlockByHash returns the block identified by hash. -func (e *EVMBackend) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) { - resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes()) +func (b *Backend) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) { + resBlock, err := b.clientCtx.Client.BlockByHash(b.ctx, hash.Bytes()) if err != nil { - e.logger.Debug("BlockByHash block not found", "hash", hash.Hex(), "error", err.Error()) + b.logger.Debug("BlockByHash block not found", "hash", hash.Hex(), "error", err.Error()) return nil, err } if resBlock == nil || resBlock.Block == nil { - e.logger.Debug("BlockByHash block not found", "hash", hash.Hex()) + b.logger.Debug("BlockByHash block not found", "hash", hash.Hex()) return nil, nil } - return e.EthBlockFromTendermint(resBlock.Block, fullTx) + return b.EthBlockFromTendermint(resBlock.Block, fullTx) } // BlockByNumber returns the block identified by number. -func (e *EVMBackend) BlockByNumber(blockNum types.BlockNumber) (*ethtypes.Block, error) { +func (b *Backend) BlockByNumber(blockNum types.BlockNumber) (*ethtypes.Block, error) { height := blockNum.Int64() switch blockNum { case types.EthLatestBlockNumber: - currentBlockNumber, _ := e.BlockNumber() + currentBlockNumber, _ := b.BlockNumber() if currentBlockNumber > 0 { height = int64(currentBlockNumber) } case types.EthPendingBlockNumber: - currentBlockNumber, _ := e.BlockNumber() + currentBlockNumber, _ := b.BlockNumber() if currentBlockNumber > 0 { height = int64(currentBlockNumber) } @@ -199,9 +119,9 @@ func (e *EVMBackend) BlockByNumber(blockNum types.BlockNumber) (*ethtypes.Block, } } - resBlock, err := e.clientCtx.Client.Block(e.ctx, &height) + resBlock, err := b.clientCtx.Client.Block(b.ctx, &height) if err != nil { - e.logger.Debug("HeaderByNumber failed", "height", height) + b.logger.Debug("HeaderByNumber failed", "height", height) return nil, err } @@ -209,14 +129,14 @@ func (e *EVMBackend) BlockByNumber(blockNum types.BlockNumber) (*ethtypes.Block, return nil, errors.Errorf("block not found for height %d", height) } - return e.EthBlockFromTm(resBlock.Block) + return b.EthBlockFromTm(resBlock.Block) } // BlockByHash returns the block identified by hash. -func (e *EVMBackend) BlockByHash(hash common.Hash) (*ethtypes.Block, error) { - resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes()) +func (b *Backend) BlockByHash(hash common.Hash) (*ethtypes.Block, error) { + resBlock, err := b.clientCtx.Client.BlockByHash(b.ctx, hash.Bytes()) if err != nil { - e.logger.Debug("HeaderByHash failed", "hash", hash.Hex()) + b.logger.Debug("HeaderByHash failed", "hash", hash.Hex()) return nil, err } @@ -224,19 +144,19 @@ func (e *EVMBackend) BlockByHash(hash common.Hash) (*ethtypes.Block, error) { return nil, errors.Errorf("block not found for hash %s", hash) } - return e.EthBlockFromTm(resBlock.Block) + return b.EthBlockFromTm(resBlock.Block) } -func (e *EVMBackend) EthBlockFromTm(block *tmtypes.Block) (*ethtypes.Block, error) { +func (b *Backend) EthBlockFromTm(block *tmtypes.Block) (*ethtypes.Block, error) { height := block.Height - bloom, err := e.BlockBloom(&height) + bloom, err := b.BlockBloom(&height) if err != nil { - e.logger.Debug("HeaderByNumber BlockBloom failed", "height", height) + b.logger.Debug("HeaderByNumber BlockBloom failed", "height", height) } - baseFee, err := e.BaseFee(height) + baseFee, err := b.BaseFee(height) if err != nil { - e.logger.Debug("HeaderByNumber BaseFee failed", "height", height, "error", err.Error()) + b.logger.Debug("HeaderByNumber BaseFee failed", "height", height, "error", err.Error()) return nil, err } @@ -244,9 +164,9 @@ func (e *EVMBackend) EthBlockFromTm(block *tmtypes.Block) (*ethtypes.Block, erro var txs []*ethtypes.Transaction for _, txBz := range block.Txs { - tx, err := e.clientCtx.TxConfig.TxDecoder()(txBz) + tx, err := b.clientCtx.TxConfig.TxDecoder()(txBz) if err != nil { - e.logger.Debug("failed to decode transaction in block", "height", height, "error", err.Error()) + b.logger.Debug("failed to decode transaction in block", "height", height, "error", err.Error()) continue } @@ -267,9 +187,9 @@ func (e *EVMBackend) EthBlockFromTm(block *tmtypes.Block) (*ethtypes.Block, erro } // GetTendermintBlockByNumber returns a Tendermint format block by block number -func (e *EVMBackend) GetTendermintBlockByNumber(blockNum types.BlockNumber) (*tmrpctypes.ResultBlock, error) { +func (b *Backend) GetTendermintBlockByNumber(blockNum types.BlockNumber) (*tmrpctypes.ResultBlock, error) { height := blockNum.Int64() - currentBlockNumber, _ := e.BlockNumber() + currentBlockNumber, _ := b.BlockNumber() switch blockNum { case types.EthLatestBlockNumber: @@ -291,16 +211,16 @@ func (e *EVMBackend) GetTendermintBlockByNumber(blockNum types.BlockNumber) (*tm } } - resBlock, err := e.clientCtx.Client.Block(e.ctx, &height) + resBlock, err := b.clientCtx.Client.Block(b.ctx, &height) if err != nil { - if resBlock, err = e.clientCtx.Client.Block(e.ctx, nil); err != nil { - e.logger.Debug("tendermint client failed to get latest block", "height", height, "error", err.Error()) + if resBlock, err = b.clientCtx.Client.Block(b.ctx, nil); err != nil { + b.logger.Debug("tendermint client failed to get latest block", "height", height, "error", err.Error()) return nil, nil } } if resBlock.Block == nil { - e.logger.Debug("GetBlockByNumber block not found", "height", height) + b.logger.Debug("GetBlockByNumber block not found", "height", height) return nil, nil } @@ -308,14 +228,14 @@ func (e *EVMBackend) GetTendermintBlockByNumber(blockNum types.BlockNumber) (*tm } // GetTendermintBlockByHash returns a Tendermint format block by block number -func (e *EVMBackend) GetTendermintBlockByHash(blockHash common.Hash) (*tmrpctypes.ResultBlock, error) { - resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, blockHash.Bytes()) +func (b *Backend) GetTendermintBlockByHash(blockHash common.Hash) (*tmrpctypes.ResultBlock, error) { + resBlock, err := b.clientCtx.Client.BlockByHash(b.ctx, blockHash.Bytes()) if err != nil { - e.logger.Debug("tendermint client failed to get block", "blockHash", blockHash.Hex(), "error", err.Error()) + b.logger.Debug("tendermint client failed to get block", "blockHash", blockHash.Hex(), "error", err.Error()) } if resBlock == nil || resBlock.Block == nil { - e.logger.Debug("GetBlockByNumber block not found", "blockHash", blockHash.Hex()) + b.logger.Debug("GetBlockByNumber block not found", "blockHash", blockHash.Hex()) return nil, nil } @@ -323,8 +243,8 @@ func (e *EVMBackend) GetTendermintBlockByHash(blockHash common.Hash) (*tmrpctype } // BlockBloom query block bloom filter from block results -func (e *EVMBackend) BlockBloom(height *int64) (ethtypes.Bloom, error) { - result, err := e.clientCtx.Client.BlockResults(e.ctx, height) +func (b *Backend) BlockBloom(height *int64) (ethtypes.Bloom, error) { + result, err := b.clientCtx.Client.BlockResults(b.ctx, height) if err != nil { return ethtypes.Bloom{}, err } @@ -343,7 +263,7 @@ func (e *EVMBackend) BlockBloom(height *int64) (ethtypes.Bloom, error) { } // EthBlockFromTendermint returns a JSON-RPC compatible Ethereum block from a given Tendermint block and its block result. -func (e *EVMBackend) EthBlockFromTendermint( +func (b *Backend) EthBlockFromTendermint( block *tmtypes.Block, fullTx bool, ) (map[string]interface{}, error) { @@ -351,12 +271,12 @@ func (e *EVMBackend) EthBlockFromTendermint( ctx := types.ContextWithHeight(block.Height) - baseFee, err := e.BaseFee(block.Height) + baseFee, err := b.BaseFee(block.Height) if err != nil { return nil, err } - resBlockResult, err := e.clientCtx.Client.BlockResults(ctx, &block.Height) + resBlockResult, err := b.clientCtx.Client.BlockResults(ctx, &block.Height) if err != nil { return nil, err } @@ -365,9 +285,9 @@ func (e *EVMBackend) EthBlockFromTendermint( txIndex := uint64(0) for i, txBz := range block.Txs { - tx, err := e.clientCtx.TxConfig.TxDecoder()(txBz) + tx, err := b.clientCtx.TxConfig.TxDecoder()(txBz) if err != nil { - e.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) + b.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error()) continue } @@ -381,7 +301,7 @@ func (e *EVMBackend) EthBlockFromTendermint( // check tx exists on EVM by cross checking with blockResults if txResults[i].Code != 0 { - e.logger.Debug("invalid tx result code", "hash", tx.Hash().Hex()) + b.logger.Debug("invalid tx result code", "hash", tx.Hash().Hex()) continue } @@ -399,7 +319,7 @@ func (e *EVMBackend) EthBlockFromTendermint( baseFee, ) if err != nil { - e.logger.Debug("NewTransactionFromData for receipt failed", "hash", tx.Hash().Hex(), "error", err.Error()) + b.logger.Debug("NewTransactionFromData for receipt failed", "hash", tx.Hash().Hex(), "error", err.Error()) continue } ethRPCTxs = append(ethRPCTxs, rpcTx) @@ -407,18 +327,18 @@ func (e *EVMBackend) EthBlockFromTendermint( } } - bloom, err := e.BlockBloom(&block.Height) + bloom, err := b.BlockBloom(&block.Height) if err != nil { - e.logger.Debug("failed to query BlockBloom", "height", block.Height, "error", err.Error()) + b.logger.Debug("failed to query BlockBloom", "height", block.Height, "error", err.Error()) } req := &evmtypes.QueryValidatorAccountRequest{ ConsAddress: sdk.ConsAddress(block.Header.ProposerAddress).String(), } - res, err := e.queryClient.ValidatorAccount(ctx, req) + res, err := b.queryClient.ValidatorAccount(ctx, req) if err != nil { - e.logger.Debug( + b.logger.Debug( "failed to query validator operator address", "height", block.Height, "cons-address", req.ConsAddress, @@ -434,9 +354,9 @@ func (e *EVMBackend) EthBlockFromTendermint( validatorAddr := common.BytesToAddress(addr) - gasLimit, err := types.BlockMaxGasFromConsensusParams(ctx, e.clientCtx, block.Height) + gasLimit, err := types.BlockMaxGasFromConsensusParams(ctx, b.clientCtx, block.Height) if err != nil { - e.logger.Error("failed to query consensus params", "error", err.Error()) + b.logger.Error("failed to query consensus params", "error", err.Error()) } gasUsed := uint64(0) @@ -459,23 +379,23 @@ func (e *EVMBackend) EthBlockFromTendermint( } // CurrentHeader returns the latest block header -func (e *EVMBackend) CurrentHeader() *ethtypes.Header { - header, _ := e.HeaderByNumber(types.EthLatestBlockNumber) +func (b *Backend) CurrentHeader() *ethtypes.Header { + header, _ := b.HeaderByNumber(types.EthLatestBlockNumber) return header } // HeaderByNumber returns the block header identified by height. -func (e *EVMBackend) HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Header, error) { +func (b *Backend) HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Header, error) { height := blockNum.Int64() switch blockNum { case types.EthLatestBlockNumber: - currentBlockNumber, _ := e.BlockNumber() + currentBlockNumber, _ := b.BlockNumber() if currentBlockNumber > 0 { height = int64(currentBlockNumber) } case types.EthPendingBlockNumber: - currentBlockNumber, _ := e.BlockNumber() + currentBlockNumber, _ := b.BlockNumber() if currentBlockNumber > 0 { height = int64(currentBlockNumber) } @@ -487,20 +407,20 @@ func (e *EVMBackend) HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Heade } } - resBlock, err := e.clientCtx.Client.Block(e.ctx, &height) + resBlock, err := b.clientCtx.Client.Block(b.ctx, &height) if err != nil { - e.logger.Debug("HeaderByNumber failed") + b.logger.Debug("HeaderByNumber failed") return nil, err } - bloom, err := e.BlockBloom(&resBlock.Block.Height) + bloom, err := b.BlockBloom(&resBlock.Block.Height) if err != nil { - e.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height) + b.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height) } - baseFee, err := e.BaseFee(resBlock.Block.Height) + baseFee, err := b.BaseFee(resBlock.Block.Height) if err != nil { - e.logger.Debug("HeaderByNumber BaseFee failed", "height", resBlock.Block.Height, "error", err.Error()) + b.logger.Debug("HeaderByNumber BaseFee failed", "height", resBlock.Block.Height, "error", err.Error()) return nil, err } @@ -509,10 +429,10 @@ func (e *EVMBackend) HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Heade } // HeaderByHash returns the block header identified by hash. -func (e *EVMBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error) { - resBlock, err := e.clientCtx.Client.BlockByHash(e.ctx, blockHash.Bytes()) +func (b *Backend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error) { + resBlock, err := b.clientCtx.Client.BlockByHash(b.ctx, blockHash.Bytes()) if err != nil { - e.logger.Debug("HeaderByHash failed", "hash", blockHash.Hex()) + b.logger.Debug("HeaderByHash failed", "hash", blockHash.Hex()) return nil, err } @@ -520,14 +440,14 @@ func (e *EVMBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, erro return nil, errors.Errorf("block not found for hash %s", blockHash.Hex()) } - bloom, err := e.BlockBloom(&resBlock.Block.Height) + bloom, err := b.BlockBloom(&resBlock.Block.Height) if err != nil { - e.logger.Debug("HeaderByHash BlockBloom failed", "height", resBlock.Block.Height) + b.logger.Debug("HeaderByHash BlockBloom failed", "height", resBlock.Block.Height) } - baseFee, err := e.BaseFee(resBlock.Block.Height) + baseFee, err := b.BaseFee(resBlock.Block.Height) if err != nil { - e.logger.Debug("HeaderByHash BaseFee failed", "height", resBlock.Block.Height, "error", err.Error()) + b.logger.Debug("HeaderByHash BaseFee failed", "height", resBlock.Block.Height, "error", err.Error()) return nil, err } @@ -537,15 +457,15 @@ func (e *EVMBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, erro // PendingTransactions returns the transactions that are in the transaction pool // and have a from address that is one of the accounts this node manages. -func (e *EVMBackend) PendingTransactions() ([]*sdk.Tx, error) { - res, err := e.clientCtx.Client.UnconfirmedTxs(e.ctx, nil) +func (b *Backend) PendingTransactions() ([]*sdk.Tx, error) { + res, err := b.clientCtx.Client.UnconfirmedTxs(b.ctx, nil) if err != nil { return nil, err } result := make([]*sdk.Tx, 0, len(res.Txs)) for _, txBz := range res.Txs { - tx, err := e.clientCtx.TxConfig.TxDecoder()(txBz) + tx, err := b.clientCtx.TxConfig.TxDecoder()(txBz) if err != nil { return nil, err } @@ -556,9 +476,9 @@ func (e *EVMBackend) PendingTransactions() ([]*sdk.Tx, error) { } // GetLogsByHeight returns all the logs from all the ethereum transactions in a block. -func (e *EVMBackend) GetLogsByHeight(height *int64) ([][]*ethtypes.Log, error) { +func (b *Backend) GetLogsByHeight(height *int64) ([][]*ethtypes.Log, error) { // NOTE: we query the state in case the tx result logs are not persisted after an upgrade. - blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, height) + blockRes, err := b.clientCtx.Client.BlockResults(b.ctx, height) if err != nil { return nil, err } @@ -577,25 +497,25 @@ func (e *EVMBackend) GetLogsByHeight(height *int64) ([][]*ethtypes.Log, error) { } // GetLogs returns all the logs from all the ethereum transactions in a block. -func (e *EVMBackend) GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) { - block, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes()) +func (b *Backend) GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) { + block, err := b.clientCtx.Client.BlockByHash(b.ctx, hash.Bytes()) if err != nil { return nil, err } - return e.GetLogsByHeight(&block.Block.Header.Height) + return b.GetLogsByHeight(&block.Block.Header.Height) } -func (e *EVMBackend) GetLogsByNumber(blockNum types.BlockNumber) ([][]*ethtypes.Log, error) { +func (b *Backend) GetLogsByNumber(blockNum types.BlockNumber) ([][]*ethtypes.Log, error) { height := blockNum.Int64() switch blockNum { case types.EthLatestBlockNumber: - currentBlockNumber, _ := e.BlockNumber() + currentBlockNumber, _ := b.BlockNumber() if currentBlockNumber > 0 { height = int64(currentBlockNumber) } case types.EthPendingBlockNumber: - currentBlockNumber, _ := e.BlockNumber() + currentBlockNumber, _ := b.BlockNumber() if currentBlockNumber > 0 { height = int64(currentBlockNumber) } @@ -607,23 +527,23 @@ func (e *EVMBackend) GetLogsByNumber(blockNum types.BlockNumber) ([][]*ethtypes. } } - return e.GetLogsByHeight(&height) + return b.GetLogsByHeight(&height) } // BloomStatus returns the BloomBitsBlocks and the number of processed sections maintained // by the chain indexer. -func (e *EVMBackend) BloomStatus() (uint64, uint64) { +func (b *Backend) BloomStatus() (uint64, uint64) { return 4096, 0 } // GetCoinbase is the address that staking rewards will be send to (alias for Etherbase). -func (e *EVMBackend) GetCoinbase() (sdk.AccAddress, error) { - node, err := e.clientCtx.GetNode() +func (b *Backend) GetCoinbase() (sdk.AccAddress, error) { + node, err := b.clientCtx.GetNode() if err != nil { return nil, err } - status, err := node.Status(e.ctx) + status, err := node.Status(b.ctx) if err != nil { return nil, err } @@ -632,7 +552,7 @@ func (e *EVMBackend) GetCoinbase() (sdk.AccAddress, error) { ConsAddress: sdk.ConsAddress(status.ValidatorInfo.Address).String(), } - res, err := e.queryClient.ValidatorAccount(e.ctx, req) + res, err := b.queryClient.ValidatorAccount(b.ctx, req) if err != nil { return nil, err } @@ -642,14 +562,14 @@ func (e *EVMBackend) GetCoinbase() (sdk.AccAddress, error) { } // GetTransactionByHash returns the Ethereum format transaction identified by Ethereum transaction hash -func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error) { - res, err := e.GetTxByEthHash(txHash) +func (b *Backend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error) { + res, err := b.GetTxByEthHash(txHash) hexTx := txHash.Hex() if err != nil { // try to find tx in mempool - txs, err := e.PendingTransactions() + txs, err := b.PendingTransactions() if err != nil { - e.logger.Debug("tx not found", "hash", hexTx, "error", err.Error()) + b.logger.Debug("tx not found", "hash", hexTx, "error", err.Error()) return nil, nil } @@ -666,7 +586,7 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac common.Hash{}, uint64(0), uint64(0), - e.chainID, + b.chainID, ) if err != nil { return nil, err @@ -675,7 +595,7 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac } } - e.logger.Debug("tx not found", "hash", hexTx) + b.logger.Debug("tx not found", "hash", hexTx) return nil, nil } @@ -688,7 +608,7 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac return nil, fmt.Errorf("ethereum tx not found in msgs: %s", hexTx) } - tx, err := e.clientCtx.TxConfig.TxDecoder()(res.Tx) + tx, err := b.clientCtx.TxConfig.TxDecoder()(res.Tx) if err != nil { return nil, err } @@ -699,9 +619,9 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac return nil, errors.New("invalid ethereum tx") } - block, err := e.clientCtx.Client.Block(e.ctx, &res.Height) + block, err := b.clientCtx.Client.Block(b.ctx, &res.Height) if err != nil { - e.logger.Debug("block not found", "height", res.Height, "error", err.Error()) + b.logger.Debug("block not found", "height", res.Height, "error", err.Error()) return nil, err } @@ -712,11 +632,11 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac found = true } else { // Fallback to find tx index by iterating all valid eth transactions - blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, &block.Block.Height) + blockRes, err := b.clientCtx.Client.BlockResults(b.ctx, &block.Block.Height) if err != nil { return nil, nil } - msgs := e.GetEthereumMsgsFromTendermintBlock(block, blockRes) + msgs := b.GetEthereumMsgsFromTendermintBlock(block, blockRes) for i := range msgs { if msgs[i].Hash == hexTx { txIndex = uint64(i) @@ -734,16 +654,16 @@ func (e *EVMBackend) GetTransactionByHash(txHash common.Hash) (*types.RPCTransac common.BytesToHash(block.BlockID.Hash.Bytes()), uint64(res.Height), txIndex, - e.chainID, + b.chainID, ) } // GetTxByEthHash uses `/tx_query` to find transaction by ethereum tx hash // TODO: Don't need to convert once hashing is fixed on Tendermint // https://github.com/tendermint/tendermint/issues/6539 -func (e *EVMBackend) GetTxByEthHash(hash common.Hash) (*tmrpctypes.ResultTx, error) { +func (b *Backend) GetTxByEthHash(hash common.Hash) (*tmrpctypes.ResultTx, error) { query := fmt.Sprintf("%s.%s='%s'", evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyEthereumTxHash, hash.Hex()) - resTxs, err := e.clientCtx.Client.TxSearch(e.ctx, query, false, nil, nil, "") + resTxs, err := b.clientCtx.Client.TxSearch(b.ctx, query, false, nil, nil, "") if err != nil { return nil, err } @@ -754,12 +674,12 @@ func (e *EVMBackend) GetTxByEthHash(hash common.Hash) (*tmrpctypes.ResultTx, err } // GetTxByTxIndex uses `/tx_query` to find transaction by tx index of valid ethereum txs -func (e *EVMBackend) GetTxByTxIndex(height int64, index uint) (*tmrpctypes.ResultTx, error) { +func (b *Backend) GetTxByTxIndex(height int64, index uint) (*tmrpctypes.ResultTx, error) { query := fmt.Sprintf("tx.height=%d AND %s.%s=%d", height, evmtypes.TypeMsgEthereumTx, evmtypes.AttributeKeyTxIndex, index, ) - resTxs, err := e.clientCtx.Client.TxSearch(e.ctx, query, false, nil, nil, "") + resTxs, err := b.clientCtx.Client.TxSearch(b.ctx, query, false, nil, nil, "") if err != nil { return nil, err } @@ -769,58 +689,58 @@ func (e *EVMBackend) GetTxByTxIndex(height int64, index uint) (*tmrpctypes.Resul return resTxs.Txs[0], nil } -func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) { +func (b *Backend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash, error) { // Look up the wallet containing the requested signer - _, err := e.clientCtx.Keyring.KeyByAddress(sdk.AccAddress(args.From.Bytes())) + _, err := b.clientCtx.Keyring.KeyByAddress(sdk.AccAddress(args.From.Bytes())) if err != nil { - e.logger.Error("failed to find key in keyring", "address", args.From, "error", err.Error()) + b.logger.Error("failed to find key in keyring", "address", args.From, "error", err.Error()) return common.Hash{}, fmt.Errorf("%s; %s", keystore.ErrNoMatch, err.Error()) } - args, err = e.SetTxDefaults(args) + args, err = b.SetTxDefaults(args) if err != nil { return common.Hash{}, err } msg := args.ToTransaction() if err := msg.ValidateBasic(); err != nil { - e.logger.Debug("tx failed basic validation", "error", err.Error()) + b.logger.Debug("tx failed basic validation", "error", err.Error()) return common.Hash{}, err } - bn, err := e.BlockNumber() + bn, err := b.BlockNumber() if err != nil { - e.logger.Debug("failed to fetch latest block number", "error", err.Error()) + b.logger.Debug("failed to fetch latest block number", "error", err.Error()) return common.Hash{}, err } - signer := ethtypes.MakeSigner(e.ChainConfig(), new(big.Int).SetUint64(uint64(bn))) + signer := ethtypes.MakeSigner(b.ChainConfig(), new(big.Int).SetUint64(uint64(bn))) // Sign transaction - if err := msg.Sign(signer, e.clientCtx.Keyring); err != nil { - e.logger.Debug("failed to sign tx", "error", err.Error()) + if err := msg.Sign(signer, b.clientCtx.Keyring); err != nil { + b.logger.Debug("failed to sign tx", "error", err.Error()) return common.Hash{}, err } // Query params to use the EVM denomination - res, err := e.queryClient.QueryClient.Params(e.ctx, &evmtypes.QueryParamsRequest{}) + res, err := b.queryClient.QueryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}) if err != nil { - e.logger.Error("failed to query evm params", "error", err.Error()) + b.logger.Error("failed to query evm params", "error", err.Error()) return common.Hash{}, err } // Assemble transaction from fields - tx, err := msg.BuildTx(e.clientCtx.TxConfig.NewTxBuilder(), res.Params.EvmDenom) + tx, err := msg.BuildTx(b.clientCtx.TxConfig.NewTxBuilder(), res.Params.EvmDenom) if err != nil { - e.logger.Error("build cosmos tx failed", "error", err.Error()) + b.logger.Error("build cosmos tx failed", "error", err.Error()) return common.Hash{}, err } // Encode transaction by default Tx encoder - txEncoder := e.clientCtx.TxConfig.TxEncoder() + txEncoder := b.clientCtx.TxConfig.TxEncoder() txBytes, err := txEncoder(tx) if err != nil { - e.logger.Error("failed to encode eth tx using default encoder", "error", err.Error()) + b.logger.Error("failed to encode eth tx using default encoder", "error", err.Error()) return common.Hash{}, err } @@ -828,13 +748,13 @@ func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash // Broadcast transaction in sync mode (default) // NOTE: If error is encountered on the node, the broadcast will not return an error - syncCtx := e.clientCtx.WithBroadcastMode(flags.BroadcastSync) + syncCtx := b.clientCtx.WithBroadcastMode(flags.BroadcastSync) rsp, err := syncCtx.BroadcastTx(txBytes) if rsp != nil && rsp.Code != 0 { err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog) } if err != nil { - e.logger.Error("failed to broadcast tx", "error", err.Error()) + b.logger.Error("failed to broadcast tx", "error", err.Error()) return txHash, err } @@ -843,7 +763,7 @@ func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash } // EstimateGas returns an estimate of gas usage for the given smart contract call. -func (e *EVMBackend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error) { +func (b *Backend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *types.BlockNumber) (hexutil.Uint64, error) { blockNr := types.EthPendingBlockNumber if blockNrOptional != nil { blockNr = *blockNrOptional @@ -856,13 +776,13 @@ func (e *EVMBackend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional req := evmtypes.EthCallRequest{ Args: bz, - GasCap: e.RPCGasCap(), + GasCap: b.RPCGasCap(), } // From ContextWithHeight: if the provided height is 0, // it will return an empty context and the gRPC query will use // the latest block height for querying. - res, err := e.queryClient.EstimateGas(types.ContextWithHeight(blockNr.Int64()), &req) + res, err := b.queryClient.EstimateGas(types.ContextWithHeight(blockNr.Int64()), &req) if err != nil { return 0, err } @@ -870,12 +790,12 @@ func (e *EVMBackend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional } // GetTransactionCount returns the number of transactions at the given address up to the given block number. -func (e *EVMBackend) GetTransactionCount(address common.Address, blockNum types.BlockNumber) (*hexutil.Uint64, error) { +func (b *Backend) GetTransactionCount(address common.Address, blockNum types.BlockNumber) (*hexutil.Uint64, error) { // Get nonce (sequence) from account from := sdk.AccAddress(address.Bytes()) - accRet := e.clientCtx.AccountRetriever + accRet := b.clientCtx.AccountRetriever - err := accRet.EnsureExists(e.clientCtx, from) + err := accRet.EnsureExists(b.clientCtx, from) if err != nil { // account doesn't exist yet, return 0 n := hexutil.Uint64(0) @@ -883,7 +803,7 @@ func (e *EVMBackend) GetTransactionCount(address common.Address, blockNum types. } includePending := blockNum == types.EthPendingBlockNumber - nonce, err := e.getAccountNonce(address, includePending, blockNum.Int64(), e.logger) + nonce, err := b.getAccountNonce(address, includePending, blockNum.Int64(), b.logger) if err != nil { return nil, err } @@ -893,50 +813,50 @@ func (e *EVMBackend) GetTransactionCount(address common.Address, blockNum types. } // RPCGasCap is the global gas cap for eth-call variants. -func (e *EVMBackend) RPCGasCap() uint64 { - return e.cfg.JSONRPC.GasCap +func (b *Backend) RPCGasCap() uint64 { + return b.cfg.JSONRPC.GasCap } // RPCEVMTimeout is the global evm timeout for eth-call variants. -func (e *EVMBackend) RPCEVMTimeout() time.Duration { - return e.cfg.JSONRPC.EVMTimeout +func (b *Backend) RPCEVMTimeout() time.Duration { + return b.cfg.JSONRPC.EVMTimeout } // RPCGasCap is the global gas cap for eth-call variants. -func (e *EVMBackend) RPCTxFeeCap() float64 { - return e.cfg.JSONRPC.TxFeeCap +func (b *Backend) RPCTxFeeCap() float64 { + return b.cfg.JSONRPC.TxFeeCap } // RPCFilterCap is the limit for total number of filters that can be created -func (e *EVMBackend) RPCFilterCap() int32 { - return e.cfg.JSONRPC.FilterCap +func (b *Backend) RPCFilterCap() int32 { + return b.cfg.JSONRPC.FilterCap } // RPCFeeHistoryCap is the limit for total number of blocks that can be fetched -func (e *EVMBackend) RPCFeeHistoryCap() int32 { - return e.cfg.JSONRPC.FeeHistoryCap +func (b *Backend) RPCFeeHistoryCap() int32 { + return b.cfg.JSONRPC.FeeHistoryCap } // RPCLogsCap defines the max number of results can be returned from single `eth_getLogs` query. -func (e *EVMBackend) RPCLogsCap() int32 { - return e.cfg.JSONRPC.LogsCap +func (b *Backend) RPCLogsCap() int32 { + return b.cfg.JSONRPC.LogsCap } // RPCBlockRangeCap defines the max block range allowed for `eth_getLogs` query. -func (e *EVMBackend) RPCBlockRangeCap() int32 { - return e.cfg.JSONRPC.BlockRangeCap +func (b *Backend) RPCBlockRangeCap() int32 { + return b.cfg.JSONRPC.BlockRangeCap } // RPCMinGasPrice returns the minimum gas price for a transaction obtained from // the node config. If set value is 0, it will default to 20. -func (e *EVMBackend) RPCMinGasPrice() int64 { - evmParams, err := e.queryClient.Params(e.ctx, &evmtypes.QueryParamsRequest{}) +func (b *Backend) RPCMinGasPrice() int64 { + evmParams, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}) if err != nil { return ethermint.DefaultGasPrice } - minGasPrice := e.cfg.GetMinGasPrices() + minGasPrice := b.cfg.GetMinGasPrices() amt := minGasPrice.AmountOf(evmParams.Params.EvmDenom).TruncateInt64() if amt == 0 { return ethermint.DefaultGasPrice @@ -945,26 +865,26 @@ func (e *EVMBackend) RPCMinGasPrice() int64 { return amt } -// ChainConfig return the latest ethereum chain configuration -func (e *EVMBackend) ChainConfig() *params.ChainConfig { - params, err := e.queryClient.Params(e.ctx, &evmtypes.QueryParamsRequest{}) +// ChainConfig returns the latest ethereum chain configuration +func (b *Backend) ChainConfig() *params.ChainConfig { + params, err := b.queryClient.Params(b.ctx, &evmtypes.QueryParamsRequest{}) if err != nil { return nil } - return params.Params.ChainConfig.EthereumConfig(e.chainID) + return params.Params.ChainConfig.EthereumConfig(b.chainID) } // SuggestGasTipCap returns the suggested tip cap // Although we don't support tx prioritization yet, but we return a positive value to help client to // mitigate the base fee changes. -func (e *EVMBackend) SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) { +func (b *Backend) SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) { if baseFee == nil { // london hardfork not enabled or feemarket not enabled return big.NewInt(0), nil } - params, err := e.queryClient.FeeMarket.Params(e.ctx, &feemarkettypes.QueryParamsRequest{}) + params, err := b.queryClient.FeeMarket.Params(b.ctx, &feemarkettypes.QueryParamsRequest{}) if err != nil { return nil, err } @@ -990,9 +910,9 @@ func (e *EVMBackend) SuggestGasTipCap(baseFee *big.Int) (*big.Int, error) { // If the base fee is not enabled globally, the query returns nil. // If the London hard fork is not activated at the current height, the query will // return nil. -func (e *EVMBackend) BaseFee(height int64) (*big.Int, error) { +func (b *Backend) BaseFee(height int64) (*big.Int, error) { // return BaseFee if London hard fork is activated and feemarket is enabled - res, err := e.queryClient.BaseFee(types.ContextWithHeight(height), &evmtypes.QueryBaseFeeRequest{}) + res, err := b.queryClient.BaseFee(types.ContextWithHeight(height), &evmtypes.QueryBaseFeeRequest{}) if err != nil { return nil, err } @@ -1004,9 +924,104 @@ func (e *EVMBackend) BaseFee(height int64) (*big.Int, error) { return res.BaseFee.BigInt(), nil } +// FeeHistory returns data relevant for fee estimation based on the specified range of blocks. +func (b *Backend) FeeHistory( + userBlockCount rpc.DecimalOrHex, // number blocks to fetch, maximum is 100 + lastBlock rpc.BlockNumber, // the block to start search , to oldest + rewardPercentiles []float64, // percentiles to fetch reward +) (*types.FeeHistoryResult, error) { + blockEnd := int64(lastBlock) + + if blockEnd <= 0 { + blockNumber, err := b.BlockNumber() + if err != nil { + return nil, err + } + blockEnd = int64(blockNumber) + } + userBlockCountInt := int64(userBlockCount) + maxBlockCount := int64(b.cfg.JSONRPC.FeeHistoryCap) + if userBlockCountInt > maxBlockCount { + return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", userBlockCountInt, maxBlockCount) + } + blockStart := blockEnd - userBlockCountInt + if blockStart < 0 { + blockStart = 0 + } + + blockCount := blockEnd - blockStart + + oldestBlock := (*hexutil.Big)(big.NewInt(blockStart)) + + // prepare space + reward := make([][]*hexutil.Big, blockCount) + rewardCount := len(rewardPercentiles) + for i := 0; i < int(blockCount); i++ { + reward[i] = make([]*hexutil.Big, rewardCount) + } + thisBaseFee := make([]*hexutil.Big, blockCount) + thisGasUsedRatio := make([]float64, blockCount) + + // rewards should only be calculated if reward percentiles were included + calculateRewards := rewardCount != 0 + + // fetch block + for blockID := blockStart; blockID < blockEnd; blockID++ { + index := int32(blockID - blockStart) + // eth block + ethBlock, err := b.GetBlockByNumber(types.BlockNumber(blockID), true) + if ethBlock == nil { + return nil, err + } + + // tendermint block + tendermintblock, err := b.GetTendermintBlockByNumber(types.BlockNumber(blockID)) + if tendermintblock == nil { + return nil, err + } + + // tendermint block result + tendermintBlockResult, err := b.clientCtx.Client.BlockResults(b.ctx, &tendermintblock.Block.Height) + if tendermintBlockResult == nil { + b.logger.Debug("block result not found", "height", tendermintblock.Block.Height, "error", err.Error()) + return nil, err + } + + oneFeeHistory := types.OneFeeHistory{} + err = b.processBlock(tendermintblock, ðBlock, rewardPercentiles, tendermintBlockResult, &oneFeeHistory) + if err != nil { + return nil, err + } + + // copy + thisBaseFee[index] = (*hexutil.Big)(oneFeeHistory.BaseFee) + thisGasUsedRatio[index] = oneFeeHistory.GasUsedRatio + if calculateRewards { + for j := 0; j < rewardCount; j++ { + reward[index][j] = (*hexutil.Big)(oneFeeHistory.Reward[j]) + if reward[index][j] == nil { + reward[index][j] = (*hexutil.Big)(big.NewInt(0)) + } + } + } + } + + feeHistory := types.FeeHistoryResult{ + OldestBlock: oldestBlock, + BaseFee: thisBaseFee, + GasUsedRatio: thisGasUsedRatio, + } + + if calculateRewards { + feeHistory.Reward = reward + } + + return &feeHistory, nil +} + // GetEthereumMsgsFromTendermintBlock returns all real MsgEthereumTxs from a Tendermint block. // It also ensures consistency over the correct txs indexes across RPC endpoints -func (e *EVMBackend) GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults) []*evmtypes.MsgEthereumTx { +func (b *Backend) GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.ResultBlock, blockRes *tmrpctypes.ResultBlockResults) []*evmtypes.MsgEthereumTx { var result []*evmtypes.MsgEthereumTx txResults := blockRes.TxsResults @@ -1014,13 +1029,13 @@ func (e *EVMBackend) GetEthereumMsgsFromTendermintBlock(block *tmrpctypes.Result for i, tx := range block.Block.Txs { // check tx exists on EVM by cross checking with blockResults if txResults[i].Code != 0 { - e.logger.Debug("invalid tx result code", "cosmos-hash", hexutil.Encode(tx.Hash())) + b.logger.Debug("invalid tx result code", "cosmos-hash", hexutil.Encode(tx.Hash())) continue } - tx, err := e.clientCtx.TxConfig.TxDecoder()(tx) + tx, err := b.clientCtx.TxConfig.TxDecoder()(tx) if err != nil { - e.logger.Debug("failed to decode transaction in block", "height", block.Block.Height, "error", err.Error()) + b.logger.Debug("failed to decode transaction in block", "height", block.Block.Height, "error", err.Error()) continue } diff --git a/rpc/ethereum/backend/utils.go b/rpc/backend/utils.go similarity index 62% rename from rpc/ethereum/backend/utils.go rename to rpc/backend/utils.go index 16e129f0..1453cc7c 100644 --- a/rpc/ethereum/backend/utils.go +++ b/rpc/backend/utils.go @@ -6,27 +6,47 @@ import ( "errors" "fmt" "math/big" + "sort" 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" ethtypes "github.com/ethereum/go-ethereum/core/types" + abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" + tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/types" evmtypes "github.com/tharsis/ethermint/x/evm/types" ) +type txGasAndReward struct { + gasUsed uint64 + reward *big.Int +} + +type sortGasAndReward []txGasAndReward + +func (s sortGasAndReward) Len() int { return len(s) } +func (s sortGasAndReward) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} + +func (s sortGasAndReward) Less(i, j int) bool { + return s[i].reward.Cmp(s[j].reward) < 0 +} + // SetTxDefaults populates tx message with default values in case they are not // provided on the args -func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error) { +func (b *Backend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.TransactionArgs, error) { if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { return args, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") } - head := e.CurrentHeader() + head := b.CurrentHeader() if head == nil { return args, errors.New("latest header is nil") } @@ -37,7 +57,7 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran // In this clause, user left some fields unspecified. if head.BaseFee != nil && args.GasPrice == nil { if args.MaxPriorityFeePerGas == nil { - tip, err := e.SuggestGasTipCap(head.BaseFee) + tip, err := b.SuggestGasTipCap(head.BaseFee) if err != nil { return args, err } @@ -62,7 +82,7 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran } if args.GasPrice == nil { - price, err := e.SuggestGasTipCap(head.BaseFee) + price, err := b.SuggestGasTipCap(head.BaseFee) if err != nil { return args, err } @@ -88,7 +108,7 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran if args.Nonce == nil { // get the nonce from the account retriever // ignore error in case tge account doesn't exist yet - nonce, _ := e.getAccountNonce(*args.From, true, 0, e.logger) + nonce, _ := b.getAccountNonce(*args.From, true, 0, b.logger) args.Nonce = (*hexutil.Uint64)(&nonce) } @@ -131,16 +151,16 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran } blockNr := types.NewBlockNumber(big.NewInt(0)) - estimated, err := e.EstimateGas(callArgs, &blockNr) + estimated, err := b.EstimateGas(callArgs, &blockNr) if err != nil { return args, err } args.Gas = &estimated - e.logger.Debug("estimate gas usage automatically", "gas", args.Gas) + b.logger.Debug("estimate gas usage automatically", "gas", args.Gas) } if args.ChainID == nil { - args.ChainID = (*hexutil.Big)(e.chainID) + args.ChainID = (*hexutil.Big)(b.chainID) } return args, nil @@ -150,14 +170,14 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran // If the pending value is true, it will iterate over the mempool (pending) // txs in order to compute and return the pending tx sequence. // Todo: include the ability to specify a blockNumber -func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, height int64, logger log.Logger) (uint64, error) { - queryClient := authtypes.NewQueryClient(e.clientCtx) +func (b *Backend) getAccountNonce(accAddr common.Address, pending bool, height int64, logger log.Logger) (uint64, error) { + queryClient := authtypes.NewQueryClient(b.clientCtx) res, err := queryClient.Account(types.ContextWithHeight(height), &authtypes.QueryAccountRequest{Address: sdk.AccAddress(accAddr.Bytes()).String()}) if err != nil { return 0, err } var acc authtypes.AccountI - if err := e.clientCtx.InterfaceRegistry.UnpackAny(res.Account, &acc); err != nil { + if err := b.clientCtx.InterfaceRegistry.UnpackAny(res.Account, &acc); err != nil { return 0, err } @@ -169,7 +189,7 @@ func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, heigh // the account retriever doesn't include the uncommitted transactions on the nonce so we need to // to manually add them. - pendingTxs, err := e.PendingTransactions() + pendingTxs, err := b.PendingTransactions() if err != nil { logger.Error("failed to fetch pending transactions", "error", err.Error()) return nonce, nil @@ -185,7 +205,7 @@ func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, heigh break } - sender, err := ethMsg.GetSender(e.chainID) + sender, err := ethMsg.GetSender(b.chainID) if err != nil { continue } @@ -198,6 +218,104 @@ func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, heigh return nonce, nil } +// output: targetOneFeeHistory +func (b *Backend) processBlock( + tendermintBlock *tmrpctypes.ResultBlock, + ethBlock *map[string]interface{}, + rewardPercentiles []float64, + tendermintBlockResult *tmrpctypes.ResultBlockResults, + targetOneFeeHistory *types.OneFeeHistory, +) error { + blockHeight := tendermintBlock.Block.Height + blockBaseFee, err := b.BaseFee(blockHeight) + if err != nil { + return err + } + + // set basefee + targetOneFeeHistory.BaseFee = blockBaseFee + + // set gas used ratio + gasLimitUint64, ok := (*ethBlock)["gasLimit"].(hexutil.Uint64) + if !ok { + return fmt.Errorf("invalid gas limit type: %T", (*ethBlock)["gasLimit"]) + } + + gasUsedBig, ok := (*ethBlock)["gasUsed"].(*hexutil.Big) + if !ok { + return fmt.Errorf("invalid gas used type: %T", (*ethBlock)["gasUsed"]) + } + + gasusedfloat, _ := new(big.Float).SetInt(gasUsedBig.ToInt()).Float64() + + if gasLimitUint64 <= 0 { + return fmt.Errorf("gasLimit of block height %d should be bigger than 0 , current gaslimit %d", blockHeight, gasLimitUint64) + } + + gasUsedRatio := gasusedfloat / float64(gasLimitUint64) + blockGasUsed := gasusedfloat + targetOneFeeHistory.GasUsedRatio = gasUsedRatio + + rewardCount := len(rewardPercentiles) + targetOneFeeHistory.Reward = make([]*big.Int, rewardCount) + for i := 0; i < rewardCount; i++ { + targetOneFeeHistory.Reward[i] = big.NewInt(0) + } + + // check tendermintTxs + tendermintTxs := tendermintBlock.Block.Txs + tendermintTxResults := tendermintBlockResult.TxsResults + tendermintTxCount := len(tendermintTxs) + + var sorter sortGasAndReward + + for i := 0; i < tendermintTxCount; i++ { + eachTendermintTx := tendermintTxs[i] + eachTendermintTxResult := tendermintTxResults[i] + + tx, err := b.clientCtx.TxConfig.TxDecoder()(eachTendermintTx) + if err != nil { + b.logger.Debug("failed to decode transaction in block", "height", blockHeight, "error", err.Error()) + continue + } + txGasUsed := uint64(eachTendermintTxResult.GasUsed) + for _, msg := range tx.GetMsgs() { + ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) + if !ok { + continue + } + tx := ethMsg.AsTransaction() + reward := tx.EffectiveGasTipValue(blockBaseFee) + if reward == nil { + reward = big.NewInt(0) + } + sorter = append(sorter, txGasAndReward{gasUsed: txGasUsed, reward: reward}) + } + } + + // return an all zero row if there are no transactions to gather data from + ethTxCount := len(sorter) + if ethTxCount == 0 { + return nil + } + + sort.Sort(sorter) + + var txIndex int + sumGasUsed := sorter[0].gasUsed + + for i, p := range rewardPercentiles { + thresholdGasUsed := uint64(blockGasUsed * p / 100) + for sumGasUsed < thresholdGasUsed && txIndex < ethTxCount-1 { + txIndex++ + sumGasUsed += sorter[txIndex].gasUsed + } + targetOneFeeHistory.Reward[i] = sorter[txIndex].reward + } + + return nil +} + // AllTxLogsFromEvents parses all ethereum logs from cosmos events func AllTxLogsFromEvents(events []abci.Event) ([][]*ethtypes.Log, error) { allLogs := make([][]*ethtypes.Log, 0, 4) diff --git a/rpc/ethereum/backend/feebackend.go b/rpc/ethereum/backend/feebackend.go deleted file mode 100644 index 50c37ea2..00000000 --- a/rpc/ethereum/backend/feebackend.go +++ /dev/null @@ -1,223 +0,0 @@ -package backend - -import ( - "fmt" - "math/big" - "sort" - - "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/rpc" - tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" - evmtypes "github.com/tharsis/ethermint/x/evm/types" -) - -type ( - txGasAndReward struct { - gasUsed uint64 - reward *big.Int - } - sortGasAndReward []txGasAndReward -) - -func (s sortGasAndReward) Len() int { return len(s) } -func (s sortGasAndReward) Swap(i, j int) { - s[i], s[j] = s[j], s[i] -} - -func (s sortGasAndReward) Less(i, j int) bool { - return s[i].reward.Cmp(s[j].reward) < 0 -} - -// output: targetOneFeeHistory -func (e *EVMBackend) processBlock( - tendermintBlock *tmrpctypes.ResultBlock, - ethBlock *map[string]interface{}, - rewardPercentiles []float64, - tendermintBlockResult *tmrpctypes.ResultBlockResults, - targetOneFeeHistory *rpctypes.OneFeeHistory, -) error { - blockHeight := tendermintBlock.Block.Height - blockBaseFee, err := e.BaseFee(blockHeight) - if err != nil { - return err - } - - // set basefee - targetOneFeeHistory.BaseFee = blockBaseFee - - // set gas used ratio - gasLimitUint64, ok := (*ethBlock)["gasLimit"].(hexutil.Uint64) - if !ok { - return fmt.Errorf("invalid gas limit type: %T", (*ethBlock)["gasLimit"]) - } - - gasUsedBig, ok := (*ethBlock)["gasUsed"].(*hexutil.Big) - if !ok { - return fmt.Errorf("invalid gas used type: %T", (*ethBlock)["gasUsed"]) - } - - gasusedfloat, _ := new(big.Float).SetInt(gasUsedBig.ToInt()).Float64() - - if gasLimitUint64 <= 0 { - return fmt.Errorf("gasLimit of block height %d should be bigger than 0 , current gaslimit %d", blockHeight, gasLimitUint64) - } - - gasUsedRatio := gasusedfloat / float64(gasLimitUint64) - blockGasUsed := gasusedfloat - targetOneFeeHistory.GasUsedRatio = gasUsedRatio - - rewardCount := len(rewardPercentiles) - targetOneFeeHistory.Reward = make([]*big.Int, rewardCount) - for i := 0; i < rewardCount; i++ { - targetOneFeeHistory.Reward[i] = big.NewInt(0) - } - - // check tendermintTxs - tendermintTxs := tendermintBlock.Block.Txs - tendermintTxResults := tendermintBlockResult.TxsResults - tendermintTxCount := len(tendermintTxs) - - var sorter sortGasAndReward - - for i := 0; i < tendermintTxCount; i++ { - eachTendermintTx := tendermintTxs[i] - eachTendermintTxResult := tendermintTxResults[i] - - tx, err := e.clientCtx.TxConfig.TxDecoder()(eachTendermintTx) - if err != nil { - e.logger.Debug("failed to decode transaction in block", "height", blockHeight, "error", err.Error()) - continue - } - txGasUsed := uint64(eachTendermintTxResult.GasUsed) - for _, msg := range tx.GetMsgs() { - ethMsg, ok := msg.(*evmtypes.MsgEthereumTx) - if !ok { - continue - } - tx := ethMsg.AsTransaction() - reward := tx.EffectiveGasTipValue(blockBaseFee) - if reward == nil { - reward = big.NewInt(0) - } - sorter = append(sorter, txGasAndReward{gasUsed: txGasUsed, reward: reward}) - } - } - - // return an all zero row if there are no transactions to gather data from - ethTxCount := len(sorter) - if ethTxCount == 0 { - return nil - } - - sort.Sort(sorter) - - var txIndex int - sumGasUsed := sorter[0].gasUsed - - for i, p := range rewardPercentiles { - thresholdGasUsed := uint64(blockGasUsed * p / 100) - for sumGasUsed < thresholdGasUsed && txIndex < ethTxCount-1 { - txIndex++ - sumGasUsed += sorter[txIndex].gasUsed - } - targetOneFeeHistory.Reward[i] = sorter[txIndex].reward - } - - return nil -} - -// FeeHistory returns data relevant for fee estimation based on the specified range of blocks. -func (e *EVMBackend) FeeHistory( - userBlockCount rpc.DecimalOrHex, // number blocks to fetch, maximum is 100 - lastBlock rpc.BlockNumber, // the block to start search , to oldest - rewardPercentiles []float64, // percentiles to fetch reward -) (*rpctypes.FeeHistoryResult, error) { - blockEnd := int64(lastBlock) - - if blockEnd <= 0 { - blockNumber, err := e.BlockNumber() - if err != nil { - return nil, err - } - blockEnd = int64(blockNumber) - } - userBlockCountInt := int64(userBlockCount) - maxBlockCount := int64(e.cfg.JSONRPC.FeeHistoryCap) - if userBlockCountInt > maxBlockCount { - return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", userBlockCountInt, maxBlockCount) - } - blockStart := blockEnd - userBlockCountInt - if blockStart < 0 { - blockStart = 0 - } - - blockCount := blockEnd - blockStart - - oldestBlock := (*hexutil.Big)(big.NewInt(blockStart)) - - // prepare space - reward := make([][]*hexutil.Big, blockCount) - rewardCount := len(rewardPercentiles) - for i := 0; i < int(blockCount); i++ { - reward[i] = make([]*hexutil.Big, rewardCount) - } - thisBaseFee := make([]*hexutil.Big, blockCount) - thisGasUsedRatio := make([]float64, blockCount) - - // rewards should only be calculated if reward percentiles were included - calculateRewards := rewardCount != 0 - - // fetch block - for blockID := blockStart; blockID < blockEnd; blockID++ { - index := int32(blockID - blockStart) - // eth block - ethBlock, err := e.GetBlockByNumber(rpctypes.BlockNumber(blockID), true) - if ethBlock == nil { - return nil, err - } - - // tendermint block - tendermintblock, err := e.GetTendermintBlockByNumber(rpctypes.BlockNumber(blockID)) - if tendermintblock == nil { - return nil, err - } - - // tendermint block result - tendermintBlockResult, err := e.clientCtx.Client.BlockResults(e.ctx, &tendermintblock.Block.Height) - if tendermintBlockResult == nil { - e.logger.Debug("block result not found", "height", tendermintblock.Block.Height, "error", err.Error()) - return nil, err - } - - oneFeeHistory := rpctypes.OneFeeHistory{} - err = e.processBlock(tendermintblock, ðBlock, rewardPercentiles, tendermintBlockResult, &oneFeeHistory) - if err != nil { - return nil, err - } - - // copy - thisBaseFee[index] = (*hexutil.Big)(oneFeeHistory.BaseFee) - thisGasUsedRatio[index] = oneFeeHistory.GasUsedRatio - if calculateRewards { - for j := 0; j < rewardCount; j++ { - reward[index][j] = (*hexutil.Big)(oneFeeHistory.Reward[j]) - if reward[index][j] == nil { - reward[index][j] = (*hexutil.Big)(big.NewInt(0)) - } - } - } - } - - feeHistory := rpctypes.FeeHistoryResult{ - OldestBlock: oldestBlock, - BaseFee: thisBaseFee, - GasUsedRatio: thisGasUsedRatio, - } - - if calculateRewards { - feeHistory.Reward = reward - } - - return &feeHistory, nil -} diff --git a/rpc/ethereum/namespaces/debug/api.go b/rpc/namespaces/ethereum/debug/api.go similarity index 98% rename from rpc/ethereum/namespaces/debug/api.go rename to rpc/namespaces/ethereum/debug/api.go index 03f8aa9f..4382480d 100644 --- a/rpc/ethereum/namespaces/debug/api.go +++ b/rpc/namespaces/ethereum/debug/api.go @@ -28,8 +28,8 @@ import ( "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/rlp" "github.com/tendermint/tendermint/libs/log" - "github.com/tharsis/ethermint/rpc/ethereum/backend" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/backend" + rpctypes "github.com/tharsis/ethermint/rpc/types" ) // HandlerT keeps track of the cpu profiler and trace execution @@ -45,7 +45,7 @@ type HandlerT struct { type API struct { ctx *server.Context logger log.Logger - backend backend.Backend + backend backend.EVMBackend clientCtx client.Context queryClient *rpctypes.QueryClient handler *HandlerT @@ -54,7 +54,7 @@ type API struct { // NewAPI creates a new API definition for the tracing methods of the Ethereum service. func NewAPI( ctx *server.Context, - backend backend.Backend, + backend backend.EVMBackend, clientCtx client.Context, ) *API { return &API{ diff --git a/rpc/ethereum/namespaces/debug/trace.go b/rpc/namespaces/ethereum/debug/trace.go similarity index 100% rename from rpc/ethereum/namespaces/debug/trace.go rename to rpc/namespaces/ethereum/debug/trace.go diff --git a/rpc/ethereum/namespaces/debug/trace_fallback.go b/rpc/namespaces/ethereum/debug/trace_fallback.go similarity index 100% rename from rpc/ethereum/namespaces/debug/trace_fallback.go rename to rpc/namespaces/ethereum/debug/trace_fallback.go diff --git a/rpc/ethereum/namespaces/debug/utils.go b/rpc/namespaces/ethereum/debug/utils.go similarity index 100% rename from rpc/ethereum/namespaces/debug/utils.go rename to rpc/namespaces/ethereum/debug/utils.go diff --git a/rpc/ethereum/namespaces/eth/api.go b/rpc/namespaces/ethereum/eth/api.go similarity index 99% rename from rpc/ethereum/namespaces/eth/api.go rename to rpc/namespaces/ethereum/eth/api.go index 2cbbb247..625739e9 100644 --- a/rpc/ethereum/namespaces/eth/api.go +++ b/rpc/namespaces/ethereum/eth/api.go @@ -36,8 +36,8 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/tharsis/ethermint/crypto/hd" - "github.com/tharsis/ethermint/rpc/ethereum/backend" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/backend" + rpctypes "github.com/tharsis/ethermint/rpc/types" ethermint "github.com/tharsis/ethermint/types" evmtypes "github.com/tharsis/ethermint/x/evm/types" ) @@ -49,7 +49,7 @@ type PublicAPI struct { queryClient *rpctypes.QueryClient chainIDEpoch *big.Int logger log.Logger - backend backend.Backend + backend backend.EVMBackend nonceLock *rpctypes.AddrLocker signer ethtypes.Signer } @@ -58,7 +58,7 @@ type PublicAPI struct { func NewPublicAPI( logger log.Logger, clientCtx client.Context, - backend backend.Backend, + backend backend.EVMBackend, nonceLock *rpctypes.AddrLocker, ) *PublicAPI { eip155ChainID, err := ethermint.ParseChainID(clientCtx.ChainID) diff --git a/rpc/ethereum/namespaces/eth/filters/api.go b/rpc/namespaces/ethereum/eth/filters/api.go similarity index 99% rename from rpc/ethereum/namespaces/eth/filters/api.go rename to rpc/namespaces/ethereum/eth/filters/api.go index 4c286312..7317d9ab 100644 --- a/rpc/ethereum/namespaces/eth/filters/api.go +++ b/rpc/namespaces/ethereum/eth/filters/api.go @@ -7,7 +7,7 @@ import ( "time" "github.com/cosmos/cosmos-sdk/client" - "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/types" "github.com/tendermint/tendermint/libs/log" diff --git a/rpc/ethereum/namespaces/eth/filters/filter_system.go b/rpc/namespaces/ethereum/eth/filters/filter_system.go similarity index 100% rename from rpc/ethereum/namespaces/eth/filters/filter_system.go rename to rpc/namespaces/ethereum/eth/filters/filter_system.go diff --git a/rpc/ethereum/namespaces/eth/filters/filters.go b/rpc/namespaces/ethereum/eth/filters/filters.go similarity index 99% rename from rpc/ethereum/namespaces/eth/filters/filters.go rename to rpc/namespaces/ethereum/eth/filters/filters.go index e9adb5a5..58a4a00e 100644 --- a/rpc/ethereum/namespaces/eth/filters/filters.go +++ b/rpc/namespaces/ethereum/eth/filters/filters.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "math/big" - "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/types" "github.com/pkg/errors" "github.com/tendermint/tendermint/libs/log" diff --git a/rpc/ethereum/namespaces/eth/filters/subscription.go b/rpc/namespaces/ethereum/eth/filters/subscription.go similarity index 96% rename from rpc/ethereum/namespaces/eth/filters/subscription.go rename to rpc/namespaces/ethereum/eth/filters/subscription.go index 87237740..b846f89d 100644 --- a/rpc/ethereum/namespaces/eth/filters/subscription.go +++ b/rpc/namespaces/ethereum/eth/filters/subscription.go @@ -31,7 +31,7 @@ func (s Subscription) ID() rpc.ID { } // Unsubscribe from the current subscription to Tendermint Websocket. It sends an error to the -// subscription error channel if unsubscription fails. +// subscription error channel if unsubscribe fails. func (s *Subscription) Unsubscribe(es *EventSystem) { go func() { uninstallLoop: diff --git a/rpc/ethereum/namespaces/eth/filters/utils.go b/rpc/namespaces/ethereum/eth/filters/utils.go similarity index 100% rename from rpc/ethereum/namespaces/eth/filters/utils.go rename to rpc/namespaces/ethereum/eth/filters/utils.go diff --git a/rpc/ethereum/namespaces/miner/api.go b/rpc/namespaces/ethereum/miner/api.go similarity index 97% rename from rpc/ethereum/namespaces/miner/api.go rename to rpc/namespaces/ethereum/miner/api.go index 3b82473c..ee3299b9 100644 --- a/rpc/ethereum/namespaces/miner/api.go +++ b/rpc/namespaces/ethereum/miner/api.go @@ -21,8 +21,8 @@ import ( "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" - "github.com/tharsis/ethermint/rpc/ethereum/backend" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/backend" + rpctypes "github.com/tharsis/ethermint/rpc/types" "github.com/tharsis/ethermint/server/config" ) @@ -31,14 +31,14 @@ type API struct { ctx *server.Context logger log.Logger clientCtx client.Context - backend backend.Backend + backend backend.EVMBackend } // NewPrivateAPI creates an instance of the Miner API. func NewPrivateAPI( ctx *server.Context, clientCtx client.Context, - backend backend.Backend, + backend backend.EVMBackend, ) *API { return &API{ ctx: ctx, diff --git a/rpc/ethereum/namespaces/miner/unsupported.go b/rpc/namespaces/ethereum/miner/unsupported.go similarity index 100% rename from rpc/ethereum/namespaces/miner/unsupported.go rename to rpc/namespaces/ethereum/miner/unsupported.go diff --git a/rpc/ethereum/namespaces/net/api.go b/rpc/namespaces/ethereum/net/api.go similarity index 100% rename from rpc/ethereum/namespaces/net/api.go rename to rpc/namespaces/ethereum/net/api.go diff --git a/rpc/ethereum/namespaces/personal/api.go b/rpc/namespaces/ethereum/personal/api.go similarity index 98% rename from rpc/ethereum/namespaces/personal/api.go rename to rpc/namespaces/ethereum/personal/api.go index 536b4516..0f39bc15 100644 --- a/rpc/ethereum/namespaces/personal/api.go +++ b/rpc/namespaces/ethereum/personal/api.go @@ -6,7 +6,7 @@ import ( "os" "time" - "github.com/tharsis/ethermint/rpc/ethereum/backend" + "github.com/tharsis/ethermint/rpc/backend" "github.com/cosmos/cosmos-sdk/client" @@ -31,13 +31,17 @@ import ( // PrivateAccountAPI is the personal_ prefixed set of APIs in the Web3 JSON-RPC spec. type PrivateAccountAPI struct { clientCtx client.Context - backend backend.Backend + backend backend.EVMBackend logger log.Logger hdPathIter ethermint.HDPathIterator } // NewAPI creates an instance of the public Personal Eth API. -func NewAPI(logger log.Logger, clientCtx client.Context, backend backend.Backend) *PrivateAccountAPI { +func NewAPI( + logger log.Logger, + clientCtx client.Context, + backend backend.EVMBackend, +) *PrivateAccountAPI { cfg := sdk.GetConfig() basePath := cfg.GetFullBIP44Path() diff --git a/rpc/ethereum/namespaces/txpool/api.go b/rpc/namespaces/ethereum/txpool/api.go similarity index 97% rename from rpc/ethereum/namespaces/txpool/api.go rename to rpc/namespaces/ethereum/txpool/api.go index bfc501d6..8d4725c8 100644 --- a/rpc/ethereum/namespaces/txpool/api.go +++ b/rpc/namespaces/ethereum/txpool/api.go @@ -5,7 +5,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/tharsis/ethermint/rpc/ethereum/types" + "github.com/tharsis/ethermint/rpc/types" ) // PublicAPI offers and API for the transaction pool. It only operates on data that is non-confidential. diff --git a/rpc/ethereum/namespaces/web3/api.go b/rpc/namespaces/ethereum/web3/api.go similarity index 100% rename from rpc/ethereum/namespaces/web3/api.go rename to rpc/namespaces/ethereum/web3/api.go diff --git a/rpc/ethereum/types/addrlock.go b/rpc/types/addrlock.go similarity index 100% rename from rpc/ethereum/types/addrlock.go rename to rpc/types/addrlock.go diff --git a/rpc/ethereum/types/block.go b/rpc/types/block.go similarity index 100% rename from rpc/ethereum/types/block.go rename to rpc/types/block.go diff --git a/rpc/ethereum/types/block_test.go b/rpc/types/block_test.go similarity index 100% rename from rpc/ethereum/types/block_test.go rename to rpc/types/block_test.go diff --git a/rpc/ethereum/types/query_client.go b/rpc/types/query_client.go similarity index 100% rename from rpc/ethereum/types/query_client.go rename to rpc/types/query_client.go diff --git a/rpc/ethereum/types/types.go b/rpc/types/types.go similarity index 100% rename from rpc/ethereum/types/types.go rename to rpc/types/types.go diff --git a/rpc/ethereum/types/utils.go b/rpc/types/utils.go similarity index 100% rename from rpc/ethereum/types/utils.go rename to rpc/types/utils.go diff --git a/rpc/websockets.go b/rpc/websockets.go index 24853a4a..b3663c57 100644 --- a/rpc/websockets.go +++ b/rpc/websockets.go @@ -26,9 +26,9 @@ import ( rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client" tmtypes "github.com/tendermint/tendermint/types" - rpcfilters "github.com/tharsis/ethermint/rpc/ethereum/namespaces/eth/filters" "github.com/tharsis/ethermint/rpc/ethereum/pubsub" - "github.com/tharsis/ethermint/rpc/ethereum/types" + rpcfilters "github.com/tharsis/ethermint/rpc/namespaces/ethereum/eth/filters" + "github.com/tharsis/ethermint/rpc/types" "github.com/tharsis/ethermint/server/config" evmtypes "github.com/tharsis/ethermint/x/evm/types" ) diff --git a/server/start.go b/server/start.go index 1a7db03d..028938a5 100644 --- a/server/start.go +++ b/server/start.go @@ -41,7 +41,7 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - ethdebug "github.com/tharsis/ethermint/rpc/ethereum/namespaces/debug" + ethdebug "github.com/tharsis/ethermint/rpc/namespaces/ethereum/debug" "github.com/tharsis/ethermint/server/config" srvflags "github.com/tharsis/ethermint/server/flags" ) diff --git a/tests/e2e/integration_test.go b/tests/e2e/integration_test.go index 520c8643..d9959b33 100644 --- a/tests/e2e/integration_test.go +++ b/tests/e2e/integration_test.go @@ -4,12 +4,13 @@ import ( "bytes" "context" "fmt" + "math/big" + "testing" + "github.com/cosmos/cosmos-sdk/client/flags" codectypes "github.com/cosmos/cosmos-sdk/codec/types" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" - "github.com/tharsis/ethermint/rpc/ethereum/types" - "math/big" - "testing" + "github.com/tharsis/ethermint/rpc/types" sdk "github.com/cosmos/cosmos-sdk/types" evmtypes "github.com/tharsis/ethermint/x/evm/types" @@ -147,7 +148,7 @@ func (s *IntegrationTestSuite) TestBlock() { s.Require().NoError(err) s.Require().NotNil(blockByHash) - //Compare blockByNumber and blockByHash results + // Compare blockByNumber and blockByHash results s.Require().Equal(blockByNum.Hash(), blockByHash.Hash()) s.Require().Equal(blockByNum.Transactions().Len(), blockByHash.Transactions().Len()) s.Require().Equal(blockByNum.ParentHash(), blockByHash.ParentHash()) @@ -382,7 +383,7 @@ func (s *IntegrationTestSuite) TestGetBalance() { } func (s *IntegrationTestSuite) TestGetLogs() { - //TODO create tests to cover different filterQuery params + // TODO create tests to cover different filterQuery params _, contractAddr := s.deployERC20Contract() blockNum, err := s.network.Validators[0].JSONRPCClient.BlockNumber(s.ctx) @@ -408,7 +409,7 @@ func (s *IntegrationTestSuite) TestGetLogs() { } func (s *IntegrationTestSuite) TestTransactionReceiptERC20Transfer() { - //start with clean block + // start with clean block err := s.network.WaitForNextBlock() s.Require().NoError(err) // deploy erc20 contract @@ -641,7 +642,6 @@ func (s *IntegrationTestSuite) transferERC20Transaction(contractAddr, to common. receipt := s.expectSuccessReceipt(ercTransferTx.AsTransaction().Hash()) s.Require().NotEmpty(receipt.Logs) return ercTransferTx.AsTransaction().Hash() - } func (s *IntegrationTestSuite) storeValueStorageContract(contractAddr common.Address, amount *big.Int) common.Hash { diff --git a/tests/rpc/rpc_pending_test.go b/tests/rpc/rpc_pending_test.go index 544ee08b..e7444bff 100644 --- a/tests/rpc/rpc_pending_test.go +++ b/tests/rpc/rpc_pending_test.go @@ -15,7 +15,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/stretchr/testify/require" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + rpctypes "github.com/tharsis/ethermint/rpc/types" ) // func TestMain(m *testing.M) { diff --git a/tests/rpc/rpc_test.go b/tests/rpc/rpc_test.go index 302c3513..e55f8867 100644 --- a/tests/rpc/rpc_test.go +++ b/tests/rpc/rpc_test.go @@ -17,7 +17,7 @@ import ( "github.com/stretchr/testify/require" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + rpctypes "github.com/tharsis/ethermint/rpc/types" ethermint "github.com/tharsis/ethermint/types" evmtypes "github.com/tharsis/ethermint/x/evm/types" diff --git a/x/evm/client/cli/query.go b/x/evm/client/cli/query.go index 72bda4ac..0ea7cd33 100644 --- a/x/evm/client/cli/query.go +++ b/x/evm/client/cli/query.go @@ -2,7 +2,7 @@ package cli import ( "github.com/spf13/cobra" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + rpctypes "github.com/tharsis/ethermint/rpc/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" diff --git a/x/evm/client/cli/tx.go b/x/evm/client/cli/tx.go index 200dc400..0fc0d178 100644 --- a/x/evm/client/cli/tx.go +++ b/x/evm/client/cli/tx.go @@ -12,7 +12,7 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + rpctypes "github.com/tharsis/ethermint/rpc/types" "github.com/tharsis/ethermint/x/evm/types" ) diff --git a/x/evm/client/rest/rest.go b/x/evm/client/rest/rest.go index 73e410fb..e296cc85 100644 --- a/x/evm/client/rest/rest.go +++ b/x/evm/client/rest/rest.go @@ -16,7 +16,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/rest" authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" - rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" + rpctypes "github.com/tharsis/ethermint/rpc/types" feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types" "github.com/ethereum/go-ethereum/common"