rpc: refactor rpc packages and backend to support cosmos namespace (#1070)

* rpc: refactor rpc packages and backend to support cosmos namespace

* changelog

* typo
This commit is contained in:
Federico Kunze Küllmer 2022-05-02 08:26:24 +02:00 committed by GitHub
parent 556c2cc8a3
commit c25669c761
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 582 additions and 539 deletions

View File

@ -38,6 +38,15 @@ Ref: https://keepachangelog.com/en/1.0.0/
## Unreleased ## 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 ### Bug Fixes
* (rpc) [tharsis#1059](https://github.com/tharsis/ethermint/pull/1059) Remove unnecessary event filtering logic on the `eth_baseFee` JSON-RPC endpoint. * (rpc) [tharsis#1059](https://github.com/tharsis/ethermint/pull/1059) Remove unnecessary event filtering logic on the `eth_baseFee` JSON-RPC endpoint.

View File

@ -10,22 +10,28 @@ import (
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/tharsis/ethermint/rpc/ethereum/backend" "github.com/tharsis/ethermint/rpc/backend"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/debug" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/debug"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/eth" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/eth"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/eth/filters" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/eth/filters"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/miner" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/miner"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/net" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/net"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/personal" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/personal"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/txpool" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/txpool"
"github.com/tharsis/ethermint/rpc/ethereum/namespaces/web3" "github.com/tharsis/ethermint/rpc/namespaces/ethereum/web3"
"github.com/tharsis/ethermint/rpc/ethereum/types" "github.com/tharsis/ethermint/rpc/types"
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client" rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
) )
// RPC namespaces and API version // RPC namespaces and API version
const ( const (
// Cosmos namespaces
CosmosNamespace = "cosmos"
// Ethereum namespaces
Web3Namespace = "web3" Web3Namespace = "web3"
EthNamespace = "eth" EthNamespace = "eth"
PersonalNamespace = "personal" PersonalNamespace = "personal"
@ -37,17 +43,17 @@ const (
apiVersion = "1.0" 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 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 var apiCreators map[string]APICreator
func init() { func init() {
apiCreators = map[string]APICreator{ apiCreators = map[string]APICreator{
EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API { EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
nonceLock := new(types.AddrLocker) nonceLock := new(types.AddrLocker)
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx) evmBackend := backend.NewBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{ return []rpc.API{
{ {
Namespace: EthNamespace, Namespace: EthNamespace,
@ -84,7 +90,7 @@ func init() {
} }
}, },
PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API { 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{ return []rpc.API{
{ {
Namespace: PersonalNamespace, Namespace: PersonalNamespace,
@ -105,7 +111,7 @@ func init() {
} }
}, },
DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API { 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{ return []rpc.API{
{ {
Namespace: DebugNamespace, Namespace: DebugNamespace,
@ -116,7 +122,7 @@ func init() {
} }
}, },
MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API { 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{ return []rpc.API{
{ {
Namespace: MinerNamespace, Namespace: MinerNamespace,

114
rpc/backend/backend.go Normal file
View File

@ -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,
}
}

View File

@ -6,27 +6,47 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"sort"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types" ethtypes "github.com/ethereum/go-ethereum/core/types"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log" "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/types"
"github.com/tharsis/ethermint/rpc/ethereum/types"
evmtypes "github.com/tharsis/ethermint/x/evm/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 // SetTxDefaults populates tx message with default values in case they are not
// provided on the args // 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) { if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
return args, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") return args, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
} }
head := e.CurrentHeader() head := b.CurrentHeader()
if head == nil { if head == nil {
return args, errors.New("latest header is 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. // In this clause, user left some fields unspecified.
if head.BaseFee != nil && args.GasPrice == nil { if head.BaseFee != nil && args.GasPrice == nil {
if args.MaxPriorityFeePerGas == nil { if args.MaxPriorityFeePerGas == nil {
tip, err := e.SuggestGasTipCap(head.BaseFee) tip, err := b.SuggestGasTipCap(head.BaseFee)
if err != nil { if err != nil {
return args, err return args, err
} }
@ -62,7 +82,7 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran
} }
if args.GasPrice == nil { if args.GasPrice == nil {
price, err := e.SuggestGasTipCap(head.BaseFee) price, err := b.SuggestGasTipCap(head.BaseFee)
if err != nil { if err != nil {
return args, err return args, err
} }
@ -88,7 +108,7 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran
if args.Nonce == nil { if args.Nonce == nil {
// get the nonce from the account retriever // get the nonce from the account retriever
// ignore error in case tge account doesn't exist yet // 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) args.Nonce = (*hexutil.Uint64)(&nonce)
} }
@ -131,16 +151,16 @@ func (e *EVMBackend) SetTxDefaults(args evmtypes.TransactionArgs) (evmtypes.Tran
} }
blockNr := types.NewBlockNumber(big.NewInt(0)) blockNr := types.NewBlockNumber(big.NewInt(0))
estimated, err := e.EstimateGas(callArgs, &blockNr) estimated, err := b.EstimateGas(callArgs, &blockNr)
if err != nil { if err != nil {
return args, err return args, err
} }
args.Gas = &estimated 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 { if args.ChainID == nil {
args.ChainID = (*hexutil.Big)(e.chainID) args.ChainID = (*hexutil.Big)(b.chainID)
} }
return args, nil 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) // If the pending value is true, it will iterate over the mempool (pending)
// txs in order to compute and return the pending tx sequence. // txs in order to compute and return the pending tx sequence.
// Todo: include the ability to specify a blockNumber // Todo: include the ability to specify a blockNumber
func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, height int64, logger log.Logger) (uint64, error) { func (b *Backend) getAccountNonce(accAddr common.Address, pending bool, height int64, logger log.Logger) (uint64, error) {
queryClient := authtypes.NewQueryClient(e.clientCtx) queryClient := authtypes.NewQueryClient(b.clientCtx)
res, err := queryClient.Account(types.ContextWithHeight(height), &authtypes.QueryAccountRequest{Address: sdk.AccAddress(accAddr.Bytes()).String()}) res, err := queryClient.Account(types.ContextWithHeight(height), &authtypes.QueryAccountRequest{Address: sdk.AccAddress(accAddr.Bytes()).String()})
if err != nil { if err != nil {
return 0, err return 0, err
} }
var acc authtypes.AccountI 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 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 // the account retriever doesn't include the uncommitted transactions on the nonce so we need to
// to manually add them. // to manually add them.
pendingTxs, err := e.PendingTransactions() pendingTxs, err := b.PendingTransactions()
if err != nil { if err != nil {
logger.Error("failed to fetch pending transactions", "error", err.Error()) logger.Error("failed to fetch pending transactions", "error", err.Error())
return nonce, nil return nonce, nil
@ -185,7 +205,7 @@ func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, heigh
break break
} }
sender, err := ethMsg.GetSender(e.chainID) sender, err := ethMsg.GetSender(b.chainID)
if err != nil { if err != nil {
continue continue
} }
@ -198,6 +218,104 @@ func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, heigh
return nonce, nil 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 // AllTxLogsFromEvents parses all ethereum logs from cosmos events
func AllTxLogsFromEvents(events []abci.Event) ([][]*ethtypes.Log, error) { func AllTxLogsFromEvents(events []abci.Event) ([][]*ethtypes.Log, error) {
allLogs := make([][]*ethtypes.Log, 0, 4) allLogs := make([][]*ethtypes.Log, 0, 4)

View File

@ -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, &ethBlock, 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
}

View File

@ -28,8 +28,8 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
"github.com/tharsis/ethermint/rpc/ethereum/backend" "github.com/tharsis/ethermint/rpc/backend"
rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" rpctypes "github.com/tharsis/ethermint/rpc/types"
) )
// HandlerT keeps track of the cpu profiler and trace execution // HandlerT keeps track of the cpu profiler and trace execution
@ -45,7 +45,7 @@ type HandlerT struct {
type API struct { type API struct {
ctx *server.Context ctx *server.Context
logger log.Logger logger log.Logger
backend backend.Backend backend backend.EVMBackend
clientCtx client.Context clientCtx client.Context
queryClient *rpctypes.QueryClient queryClient *rpctypes.QueryClient
handler *HandlerT handler *HandlerT
@ -54,7 +54,7 @@ type API struct {
// NewAPI creates a new API definition for the tracing methods of the Ethereum service. // NewAPI creates a new API definition for the tracing methods of the Ethereum service.
func NewAPI( func NewAPI(
ctx *server.Context, ctx *server.Context,
backend backend.Backend, backend backend.EVMBackend,
clientCtx client.Context, clientCtx client.Context,
) *API { ) *API {
return &API{ return &API{

View File

@ -36,8 +36,8 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/tharsis/ethermint/crypto/hd" "github.com/tharsis/ethermint/crypto/hd"
"github.com/tharsis/ethermint/rpc/ethereum/backend" "github.com/tharsis/ethermint/rpc/backend"
rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" rpctypes "github.com/tharsis/ethermint/rpc/types"
ethermint "github.com/tharsis/ethermint/types" ethermint "github.com/tharsis/ethermint/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types" evmtypes "github.com/tharsis/ethermint/x/evm/types"
) )
@ -49,7 +49,7 @@ type PublicAPI struct {
queryClient *rpctypes.QueryClient queryClient *rpctypes.QueryClient
chainIDEpoch *big.Int chainIDEpoch *big.Int
logger log.Logger logger log.Logger
backend backend.Backend backend backend.EVMBackend
nonceLock *rpctypes.AddrLocker nonceLock *rpctypes.AddrLocker
signer ethtypes.Signer signer ethtypes.Signer
} }
@ -58,7 +58,7 @@ type PublicAPI struct {
func NewPublicAPI( func NewPublicAPI(
logger log.Logger, logger log.Logger,
clientCtx client.Context, clientCtx client.Context,
backend backend.Backend, backend backend.EVMBackend,
nonceLock *rpctypes.AddrLocker, nonceLock *rpctypes.AddrLocker,
) *PublicAPI { ) *PublicAPI {
eip155ChainID, err := ethermint.ParseChainID(clientCtx.ChainID) eip155ChainID, err := ethermint.ParseChainID(clientCtx.ChainID)

View File

@ -7,7 +7,7 @@ import (
"time" "time"
"github.com/cosmos/cosmos-sdk/client" "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" "github.com/tendermint/tendermint/libs/log"

View File

@ -5,7 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"math/big" "math/big"
"github.com/tharsis/ethermint/rpc/ethereum/types" "github.com/tharsis/ethermint/rpc/types"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"

View File

@ -31,7 +31,7 @@ func (s Subscription) ID() rpc.ID {
} }
// Unsubscribe from the current subscription to Tendermint Websocket. It sends an error to the // 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) { func (s *Subscription) Unsubscribe(es *EventSystem) {
go func() { go func() {
uninstallLoop: uninstallLoop:

View File

@ -21,8 +21,8 @@ import (
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types" tmtypes "github.com/tendermint/tendermint/types"
"github.com/tharsis/ethermint/rpc/ethereum/backend" "github.com/tharsis/ethermint/rpc/backend"
rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types" rpctypes "github.com/tharsis/ethermint/rpc/types"
"github.com/tharsis/ethermint/server/config" "github.com/tharsis/ethermint/server/config"
) )
@ -31,14 +31,14 @@ type API struct {
ctx *server.Context ctx *server.Context
logger log.Logger logger log.Logger
clientCtx client.Context clientCtx client.Context
backend backend.Backend backend backend.EVMBackend
} }
// NewPrivateAPI creates an instance of the Miner API. // NewPrivateAPI creates an instance of the Miner API.
func NewPrivateAPI( func NewPrivateAPI(
ctx *server.Context, ctx *server.Context,
clientCtx client.Context, clientCtx client.Context,
backend backend.Backend, backend backend.EVMBackend,
) *API { ) *API {
return &API{ return &API{
ctx: ctx, ctx: ctx,

View File

@ -6,7 +6,7 @@ import (
"os" "os"
"time" "time"
"github.com/tharsis/ethermint/rpc/ethereum/backend" "github.com/tharsis/ethermint/rpc/backend"
"github.com/cosmos/cosmos-sdk/client" "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. // PrivateAccountAPI is the personal_ prefixed set of APIs in the Web3 JSON-RPC spec.
type PrivateAccountAPI struct { type PrivateAccountAPI struct {
clientCtx client.Context clientCtx client.Context
backend backend.Backend backend backend.EVMBackend
logger log.Logger logger log.Logger
hdPathIter ethermint.HDPathIterator hdPathIter ethermint.HDPathIterator
} }
// NewAPI creates an instance of the public Personal Eth API. // 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() cfg := sdk.GetConfig()
basePath := cfg.GetFullBIP44Path() basePath := cfg.GetFullBIP44Path()

View File

@ -5,7 +5,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "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. // PublicAPI offers and API for the transaction pool. It only operates on data that is non-confidential.

View File

@ -26,9 +26,9 @@ import (
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client" rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
tmtypes "github.com/tendermint/tendermint/types" 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/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" "github.com/tharsis/ethermint/server/config"
evmtypes "github.com/tharsis/ethermint/x/evm/types" evmtypes "github.com/tharsis/ethermint/x/evm/types"
) )

View File

@ -41,7 +41,7 @@ import (
storetypes "github.com/cosmos/cosmos-sdk/store/types" storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/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" "github.com/tharsis/ethermint/server/config"
srvflags "github.com/tharsis/ethermint/server/flags" srvflags "github.com/tharsis/ethermint/server/flags"
) )

View File

@ -4,12 +4,13 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"math/big"
"testing"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"
codectypes "github.com/cosmos/cosmos-sdk/codec/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/tharsis/ethermint/rpc/ethereum/types" "github.com/tharsis/ethermint/rpc/types"
"math/big"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types" evmtypes "github.com/tharsis/ethermint/x/evm/types"
@ -641,7 +642,6 @@ func (s *IntegrationTestSuite) transferERC20Transaction(contractAddr, to common.
receipt := s.expectSuccessReceipt(ercTransferTx.AsTransaction().Hash()) receipt := s.expectSuccessReceipt(ercTransferTx.AsTransaction().Hash())
s.Require().NotEmpty(receipt.Logs) s.Require().NotEmpty(receipt.Logs)
return ercTransferTx.AsTransaction().Hash() return ercTransferTx.AsTransaction().Hash()
} }
func (s *IntegrationTestSuite) storeValueStorageContract(contractAddr common.Address, amount *big.Int) common.Hash { func (s *IntegrationTestSuite) storeValueStorageContract(contractAddr common.Address, amount *big.Int) common.Hash {

View File

@ -15,7 +15,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require" "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) { // func TestMain(m *testing.M) {

View File

@ -17,7 +17,7 @@ import (
"github.com/stretchr/testify/require" "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" ethermint "github.com/tharsis/ethermint/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types" evmtypes "github.com/tharsis/ethermint/x/evm/types"

View File

@ -2,7 +2,7 @@ package cli
import ( import (
"github.com/spf13/cobra" "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"
"github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/flags"

View File

@ -12,7 +12,7 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "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" "github.com/tharsis/ethermint/x/evm/types"
) )

View File

@ -16,7 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/types/rest"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/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" feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"