Skip to content

Commit

Permalink
Handle pruned heights in RPC gracefully (#1271)
Browse files Browse the repository at this point in the history
* Handle pruned heights in RPC gracefully

* tests
  • Loading branch information
codchen authored and udpatil committed Mar 4, 2024
1 parent 03be332 commit 6a7ebc7
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 6 deletions.
10 changes: 8 additions & 2 deletions evmrpc/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,22 @@ func (i *InfoAPI) FeeHistory(ctx context.Context, blockCount math.HexOrDecimal64
result.OldestBlock = (*hexutil.Big)(big.NewInt(lastBlockNumber - int64(blockCount) + 1))
}

result.Reward = [][]*hexutil.Big{}
// Potentially parallelize the following logic
for blockNum := result.OldestBlock.ToInt().Int64(); blockNum <= lastBlockNumber; blockNum++ {
result.GasUsedRatio = append(result.GasUsedRatio, GasUsedRatio)
sdkCtx := i.ctxProvider(blockNum)
if CheckVersion(sdkCtx, i.keeper) != nil {
// either height is pruned or before EVM is introduced. Skipping
continue
}
result.GasUsedRatio = append(result.GasUsedRatio, GasUsedRatio)
baseFee := i.keeper.GetBaseFeePerGas(sdkCtx).BigInt()
result.BaseFee = append(result.BaseFee, (*hexutil.Big)(baseFee))
height := blockNum
block, err := i.tmClient.Block(ctx, &height)
if err != nil {
return nil, err
// block pruned from tendermint store. Skipping
continue
}
rewards, err := i.getRewards(block, baseFee, rewardPercentiles)
if err != nil {
Expand Down
8 changes: 7 additions & 1 deletion evmrpc/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,17 @@ func TestAccounts(t *testing.T) {
}

func TestCoinbase(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)
resObj := sendRequestGood(t, "coinbase")
Ctx = Ctx.WithBlockHeight(8)
result := resObj["result"].(string)
require.Equal(t, "0x27f7b8b8b5a4e71e8e9aa671f4e4031e3773303f", result)
}

func TestGasPrice(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)
resObj := sendRequestGood(t, "gasPrice")
Ctx = Ctx.WithBlockHeight(8)
result := resObj["result"].(string)
require.Equal(t, "0xa", result)
}
Expand All @@ -65,7 +69,8 @@ func TestFeeHistory(t *testing.T) {
bodyByEarliest := []interface{}{"0x1", "earliest", []interface{}{0.5}}
bodyOld := []interface{}{"0x1", "0x1", []interface{}{0.5}}
bodyFuture := []interface{}{"0x1", "0x9", []interface{}{0.5}}
expectedOldest := []string{"0x8", "0x8", "0x1", "0x1", "0x8"}
expectedOldest := []string{"0x1", "0x1", "0x1", "0x1", "0x1"}
Ctx = Ctx.WithBlockHeight(1)
for i, body := range [][]interface{}{
bodyByNumber, bodyByLatest, bodyByEarliest, bodyOld, bodyFuture,
} {
Expand Down Expand Up @@ -94,6 +99,7 @@ func TestFeeHistory(t *testing.T) {
errMap := resObj["error"].(map[string]interface{})
require.Equal(t, "invalid reward percentiles: must be ascending and between 0 and 100", errMap["message"].(string))
}
Ctx = Ctx.WithBlockHeight(8)
}

func TestCalculatePercentiles(t *testing.T) {
Expand Down
22 changes: 19 additions & 3 deletions evmrpc/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ import (
"github.com/gorilla/websocket"
"github.com/sei-protocol/sei-chain/app"
"github.com/sei-protocol/sei-chain/evmrpc"
testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper"
"github.com/sei-protocol/sei-chain/utils"
"github.com/sei-protocol/sei-chain/x/evm/keeper"
"github.com/sei-protocol/sei-chain/x/evm/types"
evmtypes "github.com/sei-protocol/sei-chain/x/evm/types"
"github.com/sei-protocol/sei-chain/x/evm/types/ethtx"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
Expand Down Expand Up @@ -320,7 +320,23 @@ var Ctx sdk.Context

func init() {
types.RegisterInterfaces(EncodingConfig.InterfaceRegistry)
EVMKeeper, Ctx = testkeeper.MockEVMKeeper()
testApp := app.Setup(false, false)
Ctx = testApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(8)
EVMKeeper = &testApp.EvmKeeper
EVMKeeper.InitGenesis(Ctx, *evmtypes.DefaultGenesis())
seiAddr, err := sdk.AccAddressFromHex(common.Bytes2Hex([]byte("seiAddr")))
if err != nil {
panic(err)
}
err = testApp.BankKeeper.MintCoins(Ctx, "evm", sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10))))
if err != nil {
panic(err)
}
err = testApp.BankKeeper.SendCoinsFromModuleToAccount(Ctx, "evm", seiAddr, sdk.NewCoins(sdk.NewCoin("usei", sdk.NewInt(10))))
if err != nil {
panic(err)
}
testApp.Commit(context.Background())
goodConfig := evmrpc.DefaultConfig
goodConfig.HTTPPort = TestPort
goodConfig.WSPort = TestWSPort
Expand Down Expand Up @@ -413,7 +429,7 @@ func init() {
}); err != nil {
panic(err)
}
seiAddr, err := sdk.AccAddressFromHex(common.Bytes2Hex([]byte("seiAddr")))
seiAddr, err = sdk.AccAddressFromHex(common.Bytes2Hex([]byte("seiAddr")))
if err != nil {
panic(err)
}
Expand Down
4 changes: 4 additions & 0 deletions evmrpc/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ func (b *Backend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHas
if err != nil {
return nil, nil, err
}
sdkCtx := b.ctxProvider(height)
if err := CheckVersion(sdkCtx, b.keeper); err != nil {
return nil, nil, err
}
return state.NewDBImpl(b.ctxProvider(height), b.keeper, true), b.getHeader(big.NewInt(height)), nil
}

Expand Down
11 changes: 11 additions & 0 deletions evmrpc/simulate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
)

func TestEstimateGas(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)
// transfer
_, from := testkeeper.MockAddressPair()
_, to := testkeeper.MockAddressPair()
Expand Down Expand Up @@ -62,9 +63,13 @@ func TestEstimateGas(t *testing.T) {
resObj = sendRequestGood(t, "estimateGas", txArgs, nil, map[string]interface{}{})
result = resObj["result"].(string)
require.Equal(t, "0x53f3", result) // 21491

Ctx = Ctx.WithBlockHeight(8)
}

func TestCreateAccessList(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)

_, from := testkeeper.MockAddressPair()
_, contractAddr := testkeeper.MockAddressPair()
code, err := os.ReadFile("../example/contracts/simplestorage/SimpleStorage.bin")
Expand Down Expand Up @@ -94,9 +99,13 @@ func TestCreateAccessList(t *testing.T) {
resObj = sendRequestBad(t, "createAccessList", txArgs, "latest")
result = resObj["error"].(map[string]interface{})
require.Equal(t, "error block", result["message"])

Ctx = Ctx.WithBlockHeight(8)
}

func TestCall(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)

_, from := testkeeper.MockAddressPair()
_, contractAddr := testkeeper.MockAddressPair()
code, err := os.ReadFile("../example/contracts/simplestorage/SimpleStorage.bin")
Expand All @@ -119,6 +128,8 @@ func TestCall(t *testing.T) {
resObj := sendRequestGood(t, "call", txArgs, nil, map[string]interface{}{}, map[string]interface{}{})
result := resObj["result"].(string)
require.Equal(t, "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c806360fe47b1146100385780636d4ce63c14610054575b5f80fd5b610052600480360381019061004d91906100f1565b610072565b005b61005c6100b2565b604051610069919061012b565b60405180910390f35b805f819055507f0de2d86113046b9e8bb6b785e96a6228f6803952bf53a40b68a36dce316218c1816040516100a7919061012b565b60405180910390a150565b5f8054905090565b5f80fd5b5f819050919050565b6100d0816100be565b81146100da575f80fd5b50565b5f813590506100eb816100c7565b92915050565b5f60208284031215610106576101056100ba565b5b5f610113848285016100dd565b91505092915050565b610125816100be565b82525050565b5f60208201905061013e5f83018461011c565b9291505056fea26469706673582212205b2eaa3bd967fbbfe4490610612964348d1d0b2a793d2b0d117fe05ccb02d1e364736f6c63430008150033", result) // 21325

Ctx = Ctx.WithBlockHeight(8)
}

func TestNewRevertError(t *testing.T) {
Expand Down
12 changes: 12 additions & 0 deletions evmrpc/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ func (a *StateAPI) GetBalance(ctx context.Context, address common.Address, block
sdkCtx := a.ctxProvider(LatestCtxHeight)
if block != nil {
sdkCtx = a.ctxProvider(*block)
if err := CheckVersion(sdkCtx, a.keeper); err != nil {
return nil, err
}
}
statedb := state.NewDBImpl(sdkCtx, a.keeper, true)
return (*hexutil.Big)(statedb.GetBalance(address)), nil
Expand All @@ -58,6 +61,9 @@ func (a *StateAPI) GetCode(ctx context.Context, address common.Address, blockNrO
sdkCtx := a.ctxProvider(LatestCtxHeight)
if block != nil {
sdkCtx = a.ctxProvider(*block)
if err := CheckVersion(sdkCtx, a.keeper); err != nil {
return nil, err
}
}
code := a.keeper.GetCode(sdkCtx, address)
return code, nil
Expand All @@ -73,6 +79,9 @@ func (a *StateAPI) GetStorageAt(ctx context.Context, address common.Address, hex
sdkCtx := a.ctxProvider(LatestCtxHeight)
if block != nil {
sdkCtx = a.ctxProvider(*block)
if err := CheckVersion(sdkCtx, a.keeper); err != nil {
return nil, err
}
}
key, _, err := decodeHash(hexKey)
if err != nil {
Expand Down Expand Up @@ -110,6 +119,9 @@ func (a *StateAPI) GetProof(ctx context.Context, address common.Address, storage
return nil, err
}
sdkCtx := a.ctxProvider(block.Block.Height)
if err := CheckVersion(sdkCtx, a.keeper); err != nil {
return nil, err
}
var iavl *iavlstore.Store
s := sdkCtx.MultiStore().GetKVStore((a.keeper.GetStoreKey()))
OUTER:
Expand Down
6 changes: 6 additions & 0 deletions evmrpc/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
)

func TestGetBalance(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)
tests := []struct {
name string
addr string
Expand Down Expand Up @@ -87,9 +88,11 @@ func TestGetBalance(t *testing.T) {
}
})
}
Ctx = Ctx.WithBlockHeight(8)
}

func TestGetCode(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)
wantKey := "0x" + hex.EncodeToString([]byte("abc"))
tests := []struct {
name string
Expand Down Expand Up @@ -141,9 +144,11 @@ func TestGetCode(t *testing.T) {
}
})
}
Ctx = Ctx.WithBlockHeight(8)
}

func TestGetStorageAt(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)
hexValue := common.BytesToHash([]byte("value"))
wantValue := "0x" + hex.EncodeToString(hexValue[:])
tests := []struct {
Expand Down Expand Up @@ -197,6 +202,7 @@ func TestGetStorageAt(t *testing.T) {
}
})
}
Ctx = Ctx.WithBlockHeight(8)
}

func TestGetProof(t *testing.T) {
Expand Down
3 changes: 3 additions & 0 deletions evmrpc/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ func (t *TransactionAPI) GetTransactionCount(ctx context.Context, address common

if blkNr != nil {
sdkCtx = t.ctxProvider(*blkNr)
if err := CheckVersion(sdkCtx, t.keeper); err != nil {
return nil, err
}
}

nonce := t.keeper.CalculateNextNonce(sdkCtx, address, pending)
Expand Down
2 changes: 2 additions & 0 deletions evmrpc/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ func TestGetPendingTransactionByHash(t *testing.T) {
}

func TestGetTransactionCount(t *testing.T) {
Ctx = Ctx.WithBlockHeight(1)
// happy path
bodyByNumber := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionCount\",\"params\":[\"0x1234567890123456789012345678901234567890\",\"0x8\"],\"id\":\"test\"}"
bodyByHash := "{\"jsonrpc\": \"2.0\",\"method\": \"eth_getTransactionCount\",\"params\":[\"0x1234567890123456789012345678901234567890\",\"0x3030303030303030303030303030303030303030303030303030303030303031\"],\"id\":\"test\"}"
Expand Down Expand Up @@ -202,6 +203,7 @@ func TestGetTransactionCount(t *testing.T) {
errMsg := errMap["message"].(string)
require.Equal(t, errStr, errMsg)
}
Ctx = Ctx.WithBlockHeight(8)
}

func TestGetTransactionError(t *testing.T) {
Expand Down
19 changes: 19 additions & 0 deletions evmrpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"crypto/ecdsa"
"encoding/hex"
"fmt"
"math/big"
"time"

Expand Down Expand Up @@ -283,3 +284,21 @@ func recordMetrics(apiMethod string, startTime time.Time, success bool) {
metrics.IncrementRpcRequestCounter(apiMethod, success)
metrics.MeasureRpcRequestLatency(apiMethod, startTime)
}

func CheckVersion(ctx sdk.Context, k *keeper.Keeper) error {
if !evmExists(ctx, k) {
return fmt.Errorf("evm module does not exist on height %d", ctx.BlockHeight())
}
if !bankExists(ctx, k) {
return fmt.Errorf("bank module does not exist on height %d", ctx.BlockHeight())
}
return nil
}

func bankExists(ctx sdk.Context, k *keeper.Keeper) bool {
return ctx.KVStore(k.BankKeeper().GetStoreKey()).VersionExists(ctx.BlockHeight())
}

func evmExists(ctx sdk.Context, k *keeper.Keeper) bool {
return ctx.KVStore(k.GetStoreKey()).VersionExists(ctx.BlockHeight())
}
20 changes: 20 additions & 0 deletions evmrpc/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package evmrpc_test

import (
"context"
"testing"

"github.com/sei-protocol/sei-chain/app"
"github.com/sei-protocol/sei-chain/evmrpc"
"github.com/stretchr/testify/require"
)

func TestCheckVersion(t *testing.T) {
testApp := app.Setup(false, false)
k := &testApp.EvmKeeper
ctx := testApp.GetContextForDeliverTx([]byte{}).WithBlockHeight(1)
testApp.Commit(context.Background()) // bump store version to 1
require.Nil(t, evmrpc.CheckVersion(ctx, k))
ctx = ctx.WithBlockHeight(2)
require.NotNil(t, evmrpc.CheckVersion(ctx, k))
}

0 comments on commit 6a7ebc7

Please sign in to comment.