evm: remove tx logs and block bloom from chain state (#556)

Closes #452

fix unit tests

changelog and fix lint

fix unit test

Update ethereum/rpc/backend/backend.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

Update ethereum/rpc/backend/utils.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

changelog

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
yihuang
2021-09-15 09:45:03 +00:00
committed by GitHub
co-authored by Federico Kunze Küllmer
parent 3f1eeb30b6
commit 116de54617
28 changed files with 1972 additions and 3406 deletions
+45 -48
View File
@@ -1,11 +1,11 @@
package backend
import (
"bytes"
"context"
"encoding/json"
"fmt"
"math/big"
"regexp"
"strconv"
"github.com/cosmos/cosmos-sdk/client/flags"
@@ -48,7 +48,8 @@ type Backend interface {
GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error)
GetTransactionCount(address common.Address, blockNum types.BlockNumber) (*hexutil.Uint64, error)
SendTransaction(args types.SendTxArgs) (common.Hash, error)
GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, error)
GetLogsByHeight(height *int64) ([][]*ethtypes.Log, error)
GetLogs(hash common.Hash) ([][]*ethtypes.Log, error)
BloomStatus() (uint64, uint64)
GetCoinbase() (sdk.AccAddress, error)
GetTransactionByHash(txHash common.Hash) (*types.RPCTransaction, error)
@@ -188,6 +189,26 @@ func (e *EVMBackend) GetTendermintBlockByNumber(blockNum types.BlockNumber) (*tm
return resBlock, nil
}
// BlockBloom query block bloom filter from block results
func (e *EVMBackend) BlockBloom(height *int64) (ethtypes.Bloom, error) {
result, err := e.clientCtx.Client.BlockResults(e.ctx, height)
if err != nil {
return ethtypes.Bloom{}, err
}
for _, event := range result.EndBlockEvents {
if event.Type != evmtypes.EventTypeBlockBloom {
continue
}
for _, attr := range event.Attributes {
if bytes.Equal(attr.Key, []byte(evmtypes.AttributeKeyEthereumBloom)) {
return ethtypes.BytesToBloom(attr.Value), nil
}
}
}
return ethtypes.Bloom{}, errors.New("block bloom event is not found")
}
// EthBlockFromTendermint returns a JSON-RPC compatible Ethereum block from a given Tendermint block and its block result.
func (e *EVMBackend) EthBlockFromTendermint(
block *tmtypes.Block,
@@ -244,11 +265,9 @@ func (e *EVMBackend) EthBlockFromTendermint(
}
}
blockBloomResp, err := e.queryClient.BlockBloom(types.ContextWithHeight(block.Height), &evmtypes.QueryBlockBloomRequest{Height: block.Height})
bloom, err := e.BlockBloom(&block.Height)
if err != nil {
e.logger.Debug("failed to query BlockBloom", "height", block.Height, "error", err.Error())
blockBloomResp = &evmtypes.QueryBlockBloomResponse{Bloom: ethtypes.Bloom{}.Bytes()}
}
req := &evmtypes.QueryValidatorAccountRequest{
@@ -268,8 +287,6 @@ func (e *EVMBackend) EthBlockFromTendermint(
validatorAddr := common.BytesToAddress(addr)
bloom := ethtypes.BytesToBloom(blockBloomResp.Bloom)
gasLimit, err := types.BlockMaxGasFromConsensusParams(types.ContextWithHeight(block.Height), e.clientCtx)
if err != nil {
e.logger.Error("failed to query consensus params", "error", err.Error())
@@ -319,16 +336,13 @@ func (e *EVMBackend) HeaderByNumber(blockNum types.BlockNumber) (*ethtypes.Heade
return nil, err
}
req := &evmtypes.QueryBlockBloomRequest{Height: resBlock.Block.Height}
blockBloomResp, err := e.queryClient.BlockBloom(types.ContextWithHeight(resBlock.Block.Height), req)
bloom, err := e.BlockBloom(&resBlock.Block.Height)
if err != nil {
e.logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height)
blockBloomResp = &evmtypes.QueryBlockBloomResponse{Bloom: ethtypes.Bloom{}.Bytes()}
}
ethHeader := types.EthHeaderFromTendermint(resBlock.Block.Header)
ethHeader.Bloom = ethtypes.BytesToBloom(blockBloomResp.Bloom)
ethHeader.Bloom = bloom
return ethHeader, nil
}
@@ -344,16 +358,13 @@ func (e *EVMBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, erro
return nil, errors.Errorf("block not found for hash %s", blockHash.Hex())
}
req := &evmtypes.QueryBlockBloomRequest{Height: resBlock.Block.Height}
blockBloomResp, err := e.queryClient.BlockBloom(types.ContextWithHeight(resBlock.Block.Height), req)
bloom, err := e.BlockBloom(&resBlock.Block.Height)
if err != nil {
e.logger.Debug("HeaderByHash BlockBloom failed", "height", resBlock.Block.Height)
blockBloomResp = &evmtypes.QueryBlockBloomResponse{Bloom: ethtypes.Bloom{}.Bytes()}
}
ethHeader := types.EthHeaderFromTendermint(resBlock.Block.Header)
ethHeader.Bloom = ethtypes.BytesToBloom(blockBloomResp.Bloom)
ethHeader.Bloom = bloom
return ethHeader, nil
}
@@ -361,17 +372,11 @@ func (e *EVMBackend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, erro
// 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)
tx, err := e.clientCtx.Client.Tx(e.ctx, txHash.Bytes(), false)
if err != nil {
e.logger.Debug("TxLogs failed", "tx-hash", req.Hash)
return nil, err
}
return evmtypes.LogsToEthereum(res.Logs), nil
return TxLogsFromEvents(e.clientCtx.Codec, tx.TxResult.Events), nil
}
// PendingTransactions returns the transactions that are in the transaction pool
@@ -394,29 +399,31 @@ func (e *EVMBackend) PendingTransactions() ([]*sdk.Tx, error) {
return result, nil
}
// GetLogs returns all the logs from all the ethereum transactions in a block.
func (e *EVMBackend) GetLogs(blockHash common.Hash) ([][]*ethtypes.Log, error) {
// GetLogsByHeight returns all the logs from all the ethereum transactions in a block.
func (e *EVMBackend) GetLogsByHeight(height *int64) ([][]*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)
blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, height)
if err != nil {
e.logger.Debug("BlockLogs failed", "hash", req.Hash)
return nil, err
}
blockLogs := [][]*ethtypes.Log{}
for _, txLog := range res.TxLogs {
blockLogs = append(blockLogs, txLog.EthLogs())
for _, txResult := range blockRes.TxsResults {
logs := TxLogsFromEvents(e.clientCtx.Codec, txResult.Events)
blockLogs = append(blockLogs, logs)
}
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)`)
// GetLogs returns all the logs from all the ethereum transactions in a block.
func (e *EVMBackend) GetLogs(hash common.Hash) ([][]*ethtypes.Log, error) {
block, err := e.clientCtx.Client.BlockByHash(e.ctx, hash.Bytes())
if err != nil {
return nil, err
}
return e.GetLogsByHeight(&block.Block.Header.Height)
}
func (e *EVMBackend) GetLogsByNumber(blockNum types.BlockNumber) ([][]*ethtypes.Log, error) {
height := blockNum.Int64()
@@ -439,17 +446,7 @@ func (e *EVMBackend) GetLogsByNumber(blockNum types.BlockNumber) ([][]*ethtypes.
}
}
resBlock, err := e.clientCtx.Client.Block(e.ctx, &height)
if err != nil {
if regexpMissingHeight.MatchString(err.Error()) {
return [][]*ethtypes.Log{}, nil
}
e.logger.Debug("failed to query block", "height", height)
return nil, err
}
return e.GetLogs(common.BytesToHash(resBlock.BlockID.Hash))
return e.GetLogsByHeight(&height)
}
// BloomStatus returns the BloomBitsBlocks and the number of processed sections maintained
+23
View File
@@ -5,9 +5,12 @@ import (
"errors"
"math/big"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
"github.com/ethereum/go-ethereum/common/hexutil"
@@ -130,3 +133,23 @@ func (e *EVMBackend) getAccountNonce(accAddr common.Address, pending bool, heigh
return nonce, nil
}
// TxLogsFromEvents parses ethereum logs from cosmos events
func TxLogsFromEvents(codec codec.Codec, events []abci.Event) []*ethtypes.Log {
logs := make([]*evmtypes.Log, 0)
for _, event := range events {
if event.Type != evmtypes.EventTypeTxLog {
continue
}
for _, attr := range event.Attributes {
if !bytes.Equal(attr.Key, []byte(evmtypes.AttributeKeyTxLog)) {
continue
}
var log evmtypes.Log
codec.MustUnmarshal(attr.Value, &log)
logs = append(logs, &log)
}
}
return evmtypes.LogsToEthereum(logs)
}
+1 -4
View File
@@ -646,14 +646,11 @@ func (e *PublicAPI) GetTransactionReceipt(hash common.Hash) (map[string]interfac
return nil, err
}
resLogs, err := e.queryClient.TxLogs(e.ctx, &evmtypes.QueryTxLogsRequest{Hash: hash.Hex()})
logs, err := e.backend.GetTransactionLogs(hash)
if err != nil {
e.logger.Debug("logs not found", "hash", hash.Hex(), "error", err.Error())
resLogs = &evmtypes.QueryTxLogsResponse{Logs: []*evmtypes.Log{}}
}
logs := evmtypes.LogsToEthereum(resLogs.Logs)
receipt := map[string]interface{}{
// Consensus fields: These fields are defined by the Yellow Paper
"status": status,