Skip to content

fix: avoid unnecessary block result in header related api call #340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rpc/backend/account_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (b *Backend) GetProof(address common.Address, storageKeys []string, blockNr

height := int64(blockNum)

_, err = b.TendermintBlockByNumber(blockNum)
_, err = b.TendermintHeaderByNumber(blockNum)
if err != nil {
// the error message imitates geth behavior
return nil, errors.New("header not found")
Expand Down Expand Up @@ -155,7 +155,7 @@ func (b *Backend) GetBalance(address common.Address, blockNrOrHash rpctypes.Bloc
Address: address.String(),
}

_, err = b.TendermintBlockByNumber(blockNum)
_, err = b.TendermintHeaderByNumber(blockNum)
if err != nil {
return nil, err
}
Expand Down
64 changes: 43 additions & 21 deletions rpc/backend/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
tmrpctypes "github.com/cometbft/cometbft/rpc/core/types"

rpctypes "github.com/cosmos/evm/rpc/types"
cosmosevmtypes "github.com/cosmos/evm/types"
evmtypes "github.com/cosmos/evm/x/vm/types"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -155,14 +156,9 @@ func (b *Backend) GetBlockTransactionCount(block *tmrpctypes.ResultBlock) *hexut
// TendermintBlockByNumber returns a Tendermint-formatted block for a given
// block number
func (b *Backend) TendermintBlockByNumber(blockNum rpctypes.BlockNumber) (*tmrpctypes.ResultBlock, error) {
height := blockNum.Int64()
if height <= 0 {
// fetch the latest block number from the app state, more accurate than the tendermint block store state.
n, err := b.BlockNumber()
if err != nil {
return nil, err
}
height = int64(n) //#nosec G115 -- checked for int overflow already
height, err := b.getHeightByBlockNum(blockNum)
if err != nil {
return nil, err
}
resBlock, err := b.RPCClient.Block(b.Ctx, &height)
if err != nil {
Expand All @@ -178,6 +174,32 @@ func (b *Backend) TendermintBlockByNumber(blockNum rpctypes.BlockNumber) (*tmrpc
return resBlock, nil
}

func (b *Backend) getHeightByBlockNum(blockNum rpctypes.BlockNumber) (int64, error) {
height := blockNum.Int64()
if height <= 0 {
// fetch the latest block number from the app state, more accurate than the tendermint block store state.
n, err := b.BlockNumber()
if err != nil {
return 0, err
}
height, err = cosmosevmtypes.SafeHexToInt64(n)
if err != nil {
return 0, err
}
}
return height, nil
}

// TendermintHeaderByNumber returns a Tendermint-formatted header for a given
// block number
func (b *Backend) TendermintHeaderByNumber(blockNum rpctypes.BlockNumber) (*tmrpctypes.ResultHeader, error) {
height, err := b.getHeightByBlockNum(blockNum)
if err != nil {
return nil, err
}
return b.RPCClient.Header(b.Ctx, &height)
}

// TendermintBlockResultByNumber returns a Tendermint-formatted block result
// by block number
func (b *Backend) TendermintBlockResultByNumber(height *int64) (*tmrpctypes.ResultBlockResults, error) {
Expand Down Expand Up @@ -225,16 +247,16 @@ func (b *Backend) BlockNumberFromTendermint(blockNrOrHash rpctypes.BlockNumberOr

// BlockNumberFromTendermintByHash returns the block height of given block hash
func (b *Backend) BlockNumberFromTendermintByHash(blockHash common.Hash) (*big.Int, error) {
resBlock, err := b.RPCClient.HeaderByHash(b.Ctx, blockHash.Bytes())
resHeader, err := b.RPCClient.HeaderByHash(b.Ctx, blockHash.Bytes())
if err != nil {
return nil, err
}

if resBlock == nil {
return nil, errors.Errorf("block not found for hash %s", blockHash.Hex())
if resHeader == nil || resHeader.Header == nil {
return nil, errors.Errorf("header not found for hash %s", blockHash.Hex())
}

return big.NewInt(resBlock.Header.Height), nil
return big.NewInt(resHeader.Header.Height), nil
}

// EthMsgsFromTendermintBlock returns all real MsgEthereumTxs from a
Expand Down Expand Up @@ -281,32 +303,32 @@ func (b *Backend) EthMsgsFromTendermintBlock(

// HeaderByNumber returns the block header identified by height.
func (b *Backend) HeaderByNumber(blockNum rpctypes.BlockNumber) (*ethtypes.Header, error) {
resBlock, err := b.TendermintBlockByNumber(blockNum)
resBlock, err := b.TendermintHeaderByNumber(blockNum)
if err != nil {
return nil, err
}

if resBlock == nil {
return nil, errors.Errorf("block not found for height %d", blockNum)
if resBlock == nil || resBlock.Header == nil {
return nil, errors.Errorf("header not found for height %d", blockNum)
}

blockRes, err := b.RPCClient.BlockResults(b.Ctx, &resBlock.Block.Height)
blockRes, err := b.TendermintBlockResultByNumber(&resBlock.Header.Height)
if err != nil {
return nil, errors.Errorf("block result not found for height %d", resBlock.Block.Height)
return nil, fmt.Errorf("header result not found for height %d", resBlock.Header.Height)
}

bloom, err := b.BlockBloom(blockRes)
if err != nil {
b.Logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Block.Height)
b.Logger.Debug("HeaderByNumber BlockBloom failed", "height", resBlock.Header.Height)
}

baseFee, err := b.BaseFee(blockRes)
if err != nil {
// handle the error for pruned node.
b.Logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", resBlock.Block.Height, "error", err)
b.Logger.Error("failed to fetch Base Fee from prunned block. Check node prunning configuration", "height", resBlock.Header.Height, "error", err)
}

ethHeader := rpctypes.EthHeaderFromTendermint(resBlock.Block.Header, bloom, baseFee)
ethHeader := rpctypes.EthHeaderFromTendermint(*resBlock.Header, bloom, baseFee)
return ethHeader, nil
}

Expand All @@ -317,7 +339,7 @@ func (b *Backend) HeaderByHash(blockHash common.Hash) (*ethtypes.Header, error)
return nil, err
}

if resHeader == nil {
if resHeader == nil || resHeader.Header == nil {
return nil, errors.Errorf("header not found for hash %s", blockHash.Hex())
}

Expand Down
8 changes: 4 additions & 4 deletions rpc/backend/call_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ func (b *Backend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rp
return 0, err
}

header, err := b.TendermintBlockByNumber(blockNr)
header, err := b.TendermintHeaderByNumber(blockNr)
if err != nil {
// the error message imitates geth behavior
return 0, errors.New("header not found")
Expand All @@ -307,7 +307,7 @@ func (b *Backend) EstimateGas(args evmtypes.TransactionArgs, blockNrOptional *rp
req := evmtypes.EthCallRequest{
Args: bz,
GasCap: b.RPCGasCap(),
ProposerAddress: sdk.ConsAddress(header.Block.ProposerAddress),
ProposerAddress: sdk.ConsAddress(header.Header.ProposerAddress),
ChainId: b.EvmChainID.Int64(),
}

Expand All @@ -333,7 +333,7 @@ func (b *Backend) DoCall(
if err != nil {
return nil, err
}
header, err := b.TendermintBlockByNumber(blockNr)
header, err := b.TendermintHeaderByNumber(blockNr)
if err != nil {
// the error message imitates geth behavior
return nil, errors.New("header not found")
Expand All @@ -342,7 +342,7 @@ func (b *Backend) DoCall(
req := evmtypes.EthCallRequest{
Args: bz,
GasCap: b.RPCGasCap(),
ProposerAddress: sdk.ConsAddress(header.Block.ProposerAddress),
ProposerAddress: sdk.ConsAddress(header.Header.ProposerAddress),
ChainId: b.EvmChainID.Int64(),
}

Expand Down
56 changes: 28 additions & 28 deletions tests/integration/rpc/backend/test_account_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ func (s *TestSuite) TestGetProof() {
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := s.backend.ClientCtx.Client.(*mocks.Client)
_, err := RegisterBlock(client, bn.Int64(), nil)
s.Require().NoError(err)
height := bn.Int64()
RegisterHeader(client, &height, nil)
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterAccount(QueryClient, addr, blockNrInvalid.Int64())
},
Expand All @@ -115,7 +115,8 @@ func (s *TestSuite) TestGetProof() {
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrInvalid},
func(bn rpctypes.BlockNumber, _ common.Address) {
client := s.backend.ClientCtx.Client.(*mocks.Client)
RegisterBlockError(client, bn.Int64())
height := bn.Int64()
RegisterHeaderError(client, &height)
},
false,
&rpctypes.AccountResult{},
Expand All @@ -126,13 +127,12 @@ func (s *TestSuite) TestGetProof() {
[]string{"0x0"},
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
s.backend.Ctx = rpctypes.ContextWithHeight(bn.Int64())

height := bn.Int64()
s.backend.Ctx = rpctypes.ContextWithHeight(height)
client := s.backend.ClientCtx.Client.(*mocks.Client)
_, err := RegisterBlock(client, bn.Int64(), nil)
s.Require().NoError(err)
RegisterHeader(client, &height, nil)
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterAccount(QueryClient, addr, bn.Int64())
RegisterAccount(QueryClient, addr, height)

// Use the IAVL height if a valid tendermint height is passed in.
iavlHeight := bn.Int64()
Expand Down Expand Up @@ -174,18 +174,17 @@ func (s *TestSuite) TestGetProof() {
[]string{"0x0"},
rpctypes.BlockNumberOrHash{BlockNumber: &blockNrZero},
func(bn rpctypes.BlockNumber, addr common.Address) {
s.backend.Ctx = rpctypes.ContextWithHeight(4)

height := int64(4)
s.backend.Ctx = rpctypes.ContextWithHeight(height)
client := s.backend.ClientCtx.Client.(*mocks.Client)
_, err := RegisterBlock(client, 4, nil)
s.Require().NoError(err)
RegisterHeader(client, &height, nil)
queryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterAccount(queryClient, addr, 4)
RegisterAccount(queryClient, addr, height)
var header metadata.MD
RegisterParams(queryClient, &header, 4)
RegisterParams(queryClient, &header, height)

// Use the IAVL height if a valid tendermint height is passed in.
var iavlHeight int64 = 4
iavlHeight := height
RegisterABCIQueryWithOptions(
client,
iavlHeight,
Expand Down Expand Up @@ -324,7 +323,8 @@ func (s *TestSuite) TestGetBalance() {
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, _ common.Address) {
client := s.backend.ClientCtx.Client.(*mocks.Client)
RegisterBlockError(client, bn.Int64())
height := bn.Int64()
RegisterHeaderError(client, &height)
},
false,
nil,
Expand All @@ -335,10 +335,10 @@ func (s *TestSuite) TestGetBalance() {
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := s.backend.ClientCtx.Client.(*mocks.Client)
_, err := RegisterBlock(client, bn.Int64(), nil)
s.Require().NoError(err)
height := bn.Int64()
RegisterHeader(client, &height, nil)
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalanceError(QueryClient, addr, bn.Int64())
RegisterBalanceError(QueryClient, addr, height)
},
false,
nil,
Expand All @@ -349,10 +349,10 @@ func (s *TestSuite) TestGetBalance() {
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := s.backend.ClientCtx.Client.(*mocks.Client)
_, err := RegisterBlock(client, bn.Int64(), nil)
s.Require().NoError(err)
height := bn.Int64()
RegisterHeader(client, &height, nil)
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalanceInvalid(QueryClient, addr, bn.Int64())
RegisterBalanceInvalid(QueryClient, addr, height)
},
false,
nil,
Expand All @@ -363,10 +363,10 @@ func (s *TestSuite) TestGetBalance() {
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := s.backend.ClientCtx.Client.(*mocks.Client)
_, err := RegisterBlock(client, bn.Int64(), nil)
s.Require().NoError(err)
height := bn.Int64()
RegisterHeader(client, &height, nil)
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalanceNegative(QueryClient, addr, bn.Int64())
RegisterBalanceNegative(QueryClient, addr, height)
},
false,
nil,
Expand All @@ -377,10 +377,10 @@ func (s *TestSuite) TestGetBalance() {
rpctypes.BlockNumberOrHash{BlockNumber: &blockNr},
func(bn rpctypes.BlockNumber, addr common.Address) {
client := s.backend.ClientCtx.Client.(*mocks.Client)
_, err := RegisterBlock(client, bn.Int64(), nil)
s.Require().NoError(err)
height := bn.Int64()
RegisterHeader(client, &height, nil)
QueryClient := s.backend.QueryClient.QueryClient.(*mocks.EVMQueryClient)
RegisterBalance(QueryClient, addr, bn.Int64())
RegisterBalance(QueryClient, addr, height)
},
true,
(*hexutil.Big)(big.NewInt(1)),
Expand Down
Loading
Loading