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:
parent
556c2cc8a3
commit
c25669c761
@ -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.
|
||||
|
38
rpc/apis.go
38
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,
|
||||
|
114
rpc/backend/backend.go
Normal file
114
rpc/backend/backend.go
Normal 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,
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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)
|
@ -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
|
||||
}
|
@ -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{
|
@ -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)
|
@ -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"
|
||||
|
@ -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"
|
@ -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:
|
@ -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,
|
@ -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()
|
||||
|
@ -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.
|
@ -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"
|
||||
)
|
||||
|
@ -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"
|
||||
)
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user