2021-06-23 06:38:05 +00:00
|
|
|
package backend
|
2021-04-18 16:39:15 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-07-05 16:39:08 +00:00
|
|
|
"fmt"
|
2021-04-18 16:39:15 +00:00
|
|
|
"math/big"
|
|
|
|
"regexp"
|
2021-07-22 15:06:44 +00:00
|
|
|
"strconv"
|
2021-04-18 16:39:15 +00:00
|
|
|
|
2021-07-22 15:06:44 +00:00
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/metadata"
|
2021-04-18 16:39:15 +00:00
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2021-07-12 18:39:35 +00:00
|
|
|
"github.com/tendermint/tendermint/libs/log"
|
2021-04-18 16:39:15 +00:00
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
|
|
|
|
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
2021-07-09 08:34:49 +00:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2021-07-22 15:06:44 +00:00
|
|
|
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
2021-04-18 16:39:15 +00:00
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
|
|
|
2021-07-22 15:06:44 +00:00
|
|
|
"github.com/tharsis/ethermint/ethereum/rpc/types"
|
2021-06-22 10:49:18 +00:00
|
|
|
ethermint "github.com/tharsis/ethermint/types"
|
|
|
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
2021-04-18 16:39:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Backend implements the functionality needed to filter changes.
|
|
|
|
// Implemented by EVMBackend.
|
|
|
|
type Backend interface {
|
|
|
|
// Used by block filter; also used for polling
|
|
|
|
BlockNumber() (hexutil.Uint64, error)
|
|
|
|
HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Header, error)
|
|
|
|
HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error)
|
|
|
|
GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) (map[string]interface{}, error)
|
|
|
|
GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error)
|
|
|
|
|
|
|
|
// returns the logs of a given block
|
|
|
|
GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, error)
|
|
|
|
|
|
|
|
// Used by pending transaction filter
|
2021-07-09 08:34:49 +00:00
|
|
|
PendingTransactions() ([]*sdk.Tx, error)
|
2021-04-18 16:39:15 +00:00
|
|
|
|
|
|
|
// Used by log filter
|
|
|
|
GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error)
|
|
|
|
BloomStatus() (uint64, uint64)
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ Backend = (*EVMBackend)(nil)
|
|
|
|
|
2021-04-19 10:49:55 +00:00
|
|
|
// EVMBackend implements the Backend interface
|
2021-04-18 16:39:15 +00:00
|
|
|
type EVMBackend struct {
|
|
|
|
ctx context.Context
|
|
|
|
clientCtx client.Context
|
|
|
|
queryClient *types.QueryClient // gRPC query client
|
|
|
|
logger log.Logger
|
2021-07-02 09:34:15 +00:00
|
|
|
chainID *big.Int
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 10:49:55 +00:00
|
|
|
// NewEVMBackend creates a new EVMBackend instance
|
2021-07-12 18:39:35 +00:00
|
|
|
func NewEVMBackend(logger log.Logger, clientCtx client.Context) *EVMBackend {
|
2021-07-02 09:34:15 +00:00
|
|
|
chainID, err := ethermint.ParseChainID(clientCtx.ChainID)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2021-04-18 16:39:15 +00:00
|
|
|
return &EVMBackend{
|
|
|
|
ctx: context.Background(),
|
|
|
|
clientCtx: clientCtx,
|
|
|
|
queryClient: types.NewQueryClient(clientCtx),
|
2021-07-12 18:39:35 +00:00
|
|
|
logger: logger.With("module", "evm-backend"),
|
2021-07-02 09:34:15 +00:00
|
|
|
chainID: chainID,
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 15:06:44 +00:00
|
|
|
// 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.
|
2021-04-18 16:39:15 +00:00
|
|
|
func (e *EVMBackend) BlockNumber() (hexutil.Uint64, error) {
|
2021-07-22 15:06:44 +00:00
|
|
|
// 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))
|
2021-04-18 16:39:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return hexutil.Uint64(0), err
|
|
|
|
}
|
|
|
|
|
2021-07-22 15:06:44 +00:00
|
|
|
blockHeightHeader := header.Get(grpctypes.GRPCBlockHeightHeader)
|
|
|
|
if headerLen := len(blockHeightHeader); headerLen != 1 {
|
|
|
|
return 0, fmt.Errorf("unexpected '%s' gRPC header length; got %d, expected: %d", grpctypes.GRPCBlockHeightHeader, headerLen, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
height, err := strconv.ParseUint(blockHeightHeader[0], 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("failed to parse block height: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return hexutil.Uint64(height), nil
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockByNumber returns the block identified by number.
|
|
|
|
func (e *EVMBackend) GetBlockByNumber(blockNum types.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
|
|
|
height := blockNum.Int64()
|
|
|
|
currentBlockNumber, _ := e.BlockNumber()
|
|
|
|
|
|
|
|
switch blockNum {
|
|
|
|
case types.EthLatestBlockNumber:
|
|
|
|
if currentBlockNumber > 0 {
|
2021-07-15 11:07:23 +00:00
|
|
|
height = int64(currentBlockNumber)
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
case types.EthPendingBlockNumber:
|
|
|
|
if currentBlockNumber > 0 {
|
|
|
|
height = int64(currentBlockNumber)
|
|
|
|
}
|
|
|
|
case types.EthEarliestBlockNumber:
|
|
|
|
height = 1
|
|
|
|
default:
|
|
|
|
if blockNum < 0 {
|
|
|
|
err := errors.Errorf("incorrect block height: %d", height)
|
|
|
|
return nil, err
|
|
|
|
} else if height > int64(currentBlockNumber) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resBlock, err := e.clientCtx.Client.Block(e.ctx, &height)
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
// e.logger.Debug("GetBlockByNumber safely bumping down from %d to latest", height)
|
2021-04-18 16:39:15 +00:00
|
|
|
if resBlock, err = e.clientCtx.Client.Block(e.ctx, nil); err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("GetBlockByNumber failed to get latest block", "error", err.Error())
|
2021-04-18 16:39:15 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-12 12:45:13 +00:00
|
|
|
if resBlock.Block == nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("GetBlockByNumber block not found", "height", height)
|
2021-07-12 12:45:13 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2021-07-14 14:40:32 +00:00
|
|
|
res, err := e.EthBlockFromTendermint(resBlock.Block, fullTx)
|
2021-04-18 16:39:15 +00:00
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("EthBlockFromTendermint failed", "height", height, "error", err.Error())
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return res, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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())
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("BlockByHash block not found", "hash", hash.Hex(), "error", err.Error())
|
2021-04-18 16:39:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-07-12 12:45:13 +00:00
|
|
|
if resBlock.Block == nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("BlockByHash block not found", "hash", hash.Hex())
|
2021-07-12 12:45:13 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2021-07-14 14:40:32 +00:00
|
|
|
return e.EthBlockFromTendermint(resBlock.Block, fullTx)
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 10:49:55 +00:00
|
|
|
// EthBlockFromTendermint returns a JSON-RPC compatible Ethereum block from a given Tendermint block.
|
|
|
|
func (e *EVMBackend) EthBlockFromTendermint(
|
2021-04-18 16:39:15 +00:00
|
|
|
block *tmtypes.Block,
|
|
|
|
fullTx bool,
|
|
|
|
) (map[string]interface{}, error) {
|
2021-04-19 10:49:55 +00:00
|
|
|
|
2021-06-08 11:11:37 +00:00
|
|
|
gasUsed := uint64(0)
|
2021-04-19 10:49:55 +00:00
|
|
|
|
2021-06-08 11:11:37 +00:00
|
|
|
ethRPCTxs := []interface{}{}
|
2021-04-18 16:39:15 +00:00
|
|
|
|
2021-06-08 11:11:37 +00:00
|
|
|
for i, txBz := range block.Txs {
|
2021-07-08 08:23:59 +00:00
|
|
|
tx, err := e.clientCtx.TxConfig.TxDecoder()(txBz)
|
2021-07-05 16:39:08 +00:00
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("failed to decode transaction in block", "height", block.Height, "error", err.Error())
|
2021-07-05 16:39:08 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-07-08 08:23:59 +00:00
|
|
|
for _, msg := range tx.GetMsgs() {
|
|
|
|
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Todo: gasUsed does not consider the refund gas so it is incorrect, we need to extract it from the result
|
|
|
|
gasUsed += ethMsg.GetGas()
|
|
|
|
hash := ethMsg.AsTransaction().Hash()
|
|
|
|
if !fullTx {
|
|
|
|
ethRPCTxs = append(ethRPCTxs, hash)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// get full transaction from message data
|
|
|
|
from, err := ethMsg.GetSender(e.chainID)
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("failed to get sender from already included transaction", "hash", hash.Hex(), "error", err.Error())
|
2021-07-08 08:23:59 +00:00
|
|
|
from = common.HexToAddress(ethMsg.From)
|
|
|
|
}
|
|
|
|
|
|
|
|
txData, err := evmtypes.UnpackTxData(ethMsg.Data)
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("decoding failed", "error", err.Error())
|
2021-07-08 08:23:59 +00:00
|
|
|
return nil, fmt.Errorf("failed to unpack tx data: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ethTx, err := types.NewTransactionFromData(
|
|
|
|
txData,
|
|
|
|
from,
|
|
|
|
hash,
|
|
|
|
common.BytesToHash(block.Hash()),
|
|
|
|
uint64(block.Height),
|
|
|
|
uint64(i),
|
|
|
|
)
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("NewTransactionFromData for receipt failed", "hash", hash.Hex(), "error", err.Error())
|
2021-07-08 08:23:59 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
ethRPCTxs = append(ethRPCTxs, ethTx)
|
|
|
|
}
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
2021-07-20 15:16:02 +00:00
|
|
|
blockBloomResp, err := e.queryClient.BlockBloom(types.ContextWithHeight(block.Height), &evmtypes.QueryBlockBloomRequest{Height: block.Height})
|
2021-04-18 16:39:15 +00:00
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("failed to query BlockBloom", "height", block.Height, "error", err.Error())
|
2021-06-07 11:02:52 +00:00
|
|
|
|
|
|
|
blockBloomResp = &evmtypes.QueryBlockBloomResponse{Bloom: ethtypes.Bloom{}.Bytes()}
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
2021-07-14 14:40:32 +00:00
|
|
|
req := &evmtypes.QueryValidatorAccountRequest{
|
|
|
|
ConsAddress: sdk.ConsAddress(block.Header.ProposerAddress).String(),
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := e.queryClient.ValidatorAccount(e.ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
e.logger.Debug("failed to query validator operator address", "cons-address", req.ConsAddress, "error", err.Error())
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := sdk.AccAddressFromBech32(res.AccountAddress)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
validatorAddr := common.BytesToAddress(addr)
|
|
|
|
|
2021-04-18 16:39:15 +00:00
|
|
|
bloom := ethtypes.BytesToBloom(blockBloomResp.Bloom)
|
2021-07-19 01:52:44 +00:00
|
|
|
|
|
|
|
gasLimit, err := types.BlockMaxGasFromConsensusParams(types.ContextWithHeight(block.Height), e.clientCtx)
|
|
|
|
if err != nil {
|
|
|
|
e.logger.Error("failed to query consensus params", "error", err.Error())
|
|
|
|
}
|
|
|
|
formattedBlock := types.FormatBlock(block.Header, block.Size(), gasLimit, new(big.Int).SetUint64(gasUsed), ethRPCTxs, bloom, validatorAddr)
|
2021-04-18 16:39:15 +00:00
|
|
|
return formattedBlock, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// HeaderByNumber returns the block header identified by height.
|
|
|
|
func (e *EVMBackend) HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Header, error) {
|
|
|
|
height := blockNum.Int64()
|
|
|
|
currentBlockNumber, _ := e.BlockNumber()
|
|
|
|
|
|
|
|
switch blockNum {
|
|
|
|
case types.EthLatestBlockNumber:
|
|
|
|
if currentBlockNumber > 0 {
|
2021-07-15 11:07:23 +00:00
|
|
|
height = int64(currentBlockNumber)
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
case types.EthPendingBlockNumber:
|
|
|
|
if currentBlockNumber > 0 {
|
|
|
|
height = int64(currentBlockNumber)
|
|
|
|
}
|
|
|
|
case types.EthEarliestBlockNumber:
|
|
|
|
height = 1
|
|
|
|
default:
|
|
|
|
if blockNum < 0 {
|
2021-07-12 18:39:35 +00:00
|
|
|
return nil, errors.Errorf("incorrect block height: %d", height)
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resBlock, err := e.clientCtx.Client.Block(e.ctx, &height)
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("HeaderByNumber failed")
|
2021-04-18 16:39:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-07-20 15:16:02 +00:00
|
|
|
req := &evmtypes.QueryBlockBloomRequest{Height: resBlock.Block.Height}
|
2021-04-18 16:39:15 +00:00
|
|
|
|
2021-07-14 09:40:58 +00:00
|
|
|
blockBloomResp, err := e.queryClient.BlockBloom(types.ContextWithHeight(resBlock.Block.Height), req)
|
2021-04-18 16:39:15 +00:00
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height)
|
2021-07-14 09:40:58 +00:00
|
|
|
blockBloomResp = &evmtypes.QueryBlockBloomResponse{Bloom: ethtypes.Bloom{}.Bytes()}
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-10 16:34:00 +00:00
|
|
|
ethHeader := types.EthHeaderFromTendermint(resBlock.Block.Header)
|
2021-07-14 09:40:58 +00:00
|
|
|
ethHeader.Bloom = ethtypes.BytesToBloom(blockBloomResp.Bloom)
|
2021-04-18 16:39:15 +00:00
|
|
|
return ethHeader, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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())
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("HeaderByHash failed", "hash", blockHash.Hex())
|
2021-04-18 16:39:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-07-20 15:16:02 +00:00
|
|
|
req := &evmtypes.QueryBlockBloomRequest{Height: resBlock.Block.Height}
|
2021-04-18 16:39:15 +00:00
|
|
|
|
2021-07-14 09:40:58 +00:00
|
|
|
blockBloomResp, err := e.queryClient.BlockBloom(types.ContextWithHeight(resBlock.Block.Height), req)
|
2021-04-18 16:39:15 +00:00
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("HeaderByHash BlockBloom failed", "height", resBlock.Block.Height)
|
2021-07-14 09:40:58 +00:00
|
|
|
blockBloomResp = &evmtypes.QueryBlockBloomResponse{Bloom: ethtypes.Bloom{}.Bytes()}
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
2021-05-10 16:34:00 +00:00
|
|
|
ethHeader := types.EthHeaderFromTendermint(resBlock.Block.Header)
|
2021-07-14 09:40:58 +00:00
|
|
|
ethHeader.Bloom = ethtypes.BytesToBloom(blockBloomResp.Bloom)
|
2021-04-18 16:39:15 +00:00
|
|
|
return ethHeader, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransactionLogs returns the logs given a transaction hash.
|
|
|
|
// It returns an error if there's an encoding error.
|
|
|
|
// If no logs are found for the tx hash, the error is nil.
|
|
|
|
func (e *EVMBackend) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
|
|
|
|
req := &evmtypes.QueryTxLogsRequest{
|
|
|
|
Hash: txHash.String(),
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := e.queryClient.TxLogs(e.ctx, req)
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("TxLogs failed", "tx-hash", req.Hash)
|
2021-04-18 16:39:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return evmtypes.LogsToEthereum(res.Logs), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PendingTransactions returns the transactions that are in the transaction pool
|
|
|
|
// and have a from address that is one of the accounts this node manages.
|
2021-07-09 08:34:49 +00:00
|
|
|
func (e *EVMBackend) PendingTransactions() ([]*sdk.Tx, error) {
|
|
|
|
res, err := e.clientCtx.Client.UnconfirmedTxs(e.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)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result = append(result, &tx)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetLogs returns all the logs from all the ethereum transactions in a block.
|
|
|
|
func (e *EVMBackend) GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, error) {
|
|
|
|
// NOTE: we query the state in case the tx result logs are not persisted after an upgrade.
|
|
|
|
req := &evmtypes.QueryBlockLogsRequest{
|
|
|
|
Hash: blockHash.String(),
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := e.queryClient.BlockLogs(e.ctx, req)
|
|
|
|
if err != nil {
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("BlockLogs failed", "hash", req.Hash)
|
2021-04-18 16:39:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var blockLogs = [][]*ethtypes.Log{}
|
|
|
|
for _, txLog := range res.TxLogs {
|
|
|
|
blockLogs = append(blockLogs, txLog.EthLogs())
|
|
|
|
}
|
|
|
|
|
|
|
|
return blockLogs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is very brittle, see: https://github.com/tendermint/tendermint/issues/4740
|
|
|
|
var regexpMissingHeight = regexp.MustCompile(`height \d+ (must be less than or equal to|is not available)`)
|
|
|
|
|
|
|
|
func (e *EVMBackend) GetLogsByNumber(blockNum types.BlockNumber) ([][]*ethtypes.Log, error) {
|
|
|
|
height := blockNum.Int64()
|
|
|
|
currentBlockNumber, _ := e.BlockNumber()
|
|
|
|
|
|
|
|
switch blockNum {
|
|
|
|
case types.EthLatestBlockNumber:
|
|
|
|
if currentBlockNumber > 0 {
|
2021-07-15 11:07:23 +00:00
|
|
|
height = int64(currentBlockNumber)
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
case types.EthPendingBlockNumber:
|
|
|
|
if currentBlockNumber > 0 {
|
|
|
|
height = int64(currentBlockNumber)
|
|
|
|
}
|
|
|
|
case types.EthEarliestBlockNumber:
|
|
|
|
height = 1
|
|
|
|
default:
|
|
|
|
if blockNum < 0 {
|
2021-07-12 18:39:35 +00:00
|
|
|
return nil, errors.Errorf("incorrect block height: %d", height)
|
2021-04-18 16:39:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resBlock, err := e.clientCtx.Client.Block(e.ctx, &height)
|
|
|
|
if err != nil {
|
|
|
|
if regexpMissingHeight.MatchString(err.Error()) {
|
|
|
|
return [][]*ethtypes.Log{}, nil
|
|
|
|
}
|
|
|
|
|
2021-07-12 18:39:35 +00:00
|
|
|
e.logger.Debug("failed to query block", "height", height)
|
2021-04-18 16:39:15 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return e.GetLogs(common.BytesToHash(resBlock.BlockID.Hash))
|
|
|
|
}
|
|
|
|
|
|
|
|
// BloomStatus returns the BloomBitsBlocks and the number of processed sections maintained
|
|
|
|
// by the chain indexer.
|
|
|
|
func (e *EVMBackend) BloomStatus() (uint64, uint64) {
|
|
|
|
return 4096, 0
|
|
|
|
}
|