Skip to content
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

RPC endpoints for excluding tracing failures #1995

Merged
merged 20 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
113 changes: 75 additions & 38 deletions evmrpc/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,50 @@
includeShellReceipts bool
}

func NewBlockAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txConfig client.TxConfig, connectionType ConnectionType, namespace string) *BlockAPI {
type SeiBlockAPI struct {
*BlockAPI
isPanicTx func(ctx context.Context, hash common.Hash) (bool, error)
}

func NewBlockAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txConfig client.TxConfig, connectionType ConnectionType) *BlockAPI {
return &BlockAPI{
tmClient: tmClient,
keeper: k,
ctxProvider: ctxProvider,
txConfig: txConfig,
connectionType: connectionType,
namespace: namespace,
includeShellReceipts: shouldIncludeSynthetic(namespace),
includeShellReceipts: false,
namespace: "eth",
}
}

func NewSeiBlockAPI(
tmClient rpcclient.Client,
k *keeper.Keeper,
ctxProvider func(int64) sdk.Context,
txConfig client.TxConfig,
connectionType ConnectionType,
isPanicTx func(ctx context.Context, hash common.Hash) (bool, error),
) *SeiBlockAPI {
blockAPI := &BlockAPI{
tmClient: tmClient,
keeper: k,
ctxProvider: ctxProvider,
txConfig: txConfig,
connectionType: connectionType,
includeShellReceipts: true,
namespace: "sei",
}
return &SeiBlockAPI{
BlockAPI: blockAPI,
isPanicTx: isPanicTx,
}

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
}

func (a *SeiBlockAPI) GetBlockByNumberExcludePanicTx(ctx context.Context, number rpc.BlockNumber, fullTx bool) (result map[string]interface{}, returnErr error) {
return a.getBlockByNumber(ctx, number, fullTx, false, a.isPanicTx)
}

func (a *BlockAPI) GetBlockTransactionCountByNumber(ctx context.Context, number rpc.BlockNumber) (result *hexutil.Uint, returnErr error) {
startTime := time.Now()
defer recordMetrics(fmt.Sprintf("%s_getBlockTransactionCountByNumber", a.namespace), a.connectionType, startTime, returnErr == nil)
Expand All @@ -63,7 +95,7 @@
return nil, err
}
return a.getEvmTxCount(block.Block.Txs), nil
}

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism

func (a *BlockAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) (result *hexutil.Uint, returnErr error) {
startTime := time.Now()
Expand All @@ -76,56 +108,47 @@
}

func (a *BlockAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (result map[string]interface{}, returnErr error) {
startTime := time.Now()
defer recordMetrics(fmt.Sprintf("%s_getBlockByHash", a.namespace), a.connectionType, startTime, returnErr == nil)
return a.getBlockByHash(ctx, blockHash, fullTx)
return a.getBlockByHash(ctx, blockHash, fullTx, true, nil)
}

func (a *SeiBlockAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (result map[string]interface{}, returnErr error) {
return a.getBlockByHash(ctx, blockHash, fullTx, true, nil)
}

func (a *BlockAPI) getBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (result map[string]interface{}, returnErr error) {
func (a *SeiBlockAPI) GetBlockByHashExcludePanicTx(ctx context.Context, blockHash common.Hash, fullTx bool) (result map[string]interface{}, returnErr error) {
return a.getBlockByHash(ctx, blockHash, fullTx, false, a.isPanicTx)
}

func (a *BlockAPI) getBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool, includePanicTx bool, isPanicTx func(ctx context.Context, hash common.Hash) (bool, error)) (result map[string]interface{}, returnErr error) {
startTime := time.Now()
defer recordMetrics(fmt.Sprintf("%s_getBlockByHash", a.namespace), a.connectionType, startTime, returnErr == nil)
block, err := blockByHashWithRetry(ctx, a.tmClient, blockHash[:], 1)
if err != nil {
return nil, err
}
fmt.Println("in getBlockByHash, block.Block.Height", block.Block.Height)
blockRes, err := blockResultsWithRetry(ctx, a.tmClient, &block.Block.Height)
if err != nil {
return nil, err
}
blockBloom := a.keeper.GetBlockBloom(a.ctxProvider(block.Block.Height))
return EncodeTmBlock(a.ctxProvider(block.Block.Height), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx, a.includeShellReceipts)
return EncodeTmBlock(a.ctxProvider(block.Block.Height), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx, a.includeShellReceipts, includePanicTx, isPanicTx)
}

func (a *BlockAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (result map[string]interface{}, returnErr error) {
startTime := time.Now()
defer recordMetrics(fmt.Sprintf("%s_getBlockByNumber", a.namespace), a.connectionType, startTime, returnErr == nil)
if number == 0 {
// for compatibility with the graph, always return genesis block
return map[string]interface{}{
"number": (*hexutil.Big)(big.NewInt(0)),
"hash": common.HexToHash("F9D3845DF25B43B1C6926F3CEDA6845C17F5624E12212FD8847D0BA01DA1AB9E"),
"parentHash": common.Hash{},
"nonce": ethtypes.BlockNonce{}, // inapplicable to Sei
"mixHash": common.Hash{}, // inapplicable to Sei
"sha3Uncles": ethtypes.EmptyUncleHash, // inapplicable to Sei
"logsBloom": ethtypes.Bloom{},
"stateRoot": common.Hash{},
"miner": common.Address{},
"difficulty": (*hexutil.Big)(big.NewInt(0)), // inapplicable to Sei
"extraData": hexutil.Bytes{}, // inapplicable to Sei
"gasLimit": hexutil.Uint64(0),
"gasUsed": hexutil.Uint64(0),
"timestamp": hexutil.Uint64(0),
"transactionsRoot": common.Hash{},
"receiptsRoot": common.Hash{},
"size": hexutil.Uint64(0),
"uncles": []common.Hash{}, // inapplicable to Sei
"transactions": []interface{}{},
"baseFeePerGas": (*hexutil.Big)(big.NewInt(0)),
}, nil
}
return a.getBlockByNumber(ctx, number, fullTx)
res, err := a.getBlockByNumber(ctx, number, fullTx, true, nil)
return res, err
}

func (a *BlockAPI) getBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (result map[string]interface{}, returnErr error) {
func (a *BlockAPI) getBlockByNumber(
ctx context.Context,
number rpc.BlockNumber,
fullTx bool,
includePanicTx bool,
isPanicTx func(ctx context.Context, hash common.Hash) (bool, error),
) (result map[string]interface{}, returnErr error) {
startTime := time.Now()

Check warning

Code scanning / CodeQL

Calling the system time Warning

Calling the system time may be a possible source of non-determinism
defer recordMetrics(fmt.Sprintf("%s_getBlockByNumber", a.namespace), a.connectionType, startTime, returnErr == nil)
numberPtr, err := getBlockNumber(ctx, a.tmClient, number)
if err != nil {
return nil, err
Expand All @@ -139,7 +162,7 @@
return nil, err
}
blockBloom := a.keeper.GetBlockBloom(a.ctxProvider(block.Block.Height))
return EncodeTmBlock(a.ctxProvider(block.Block.Height), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx, a.includeShellReceipts)
return EncodeTmBlock(a.ctxProvider(block.Block.Height), block, blockRes, blockBloom, a.keeper, a.txConfig.TxDecoder(), fullTx, a.includeShellReceipts, includePanicTx, isPanicTx)
}

func (a *BlockAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (result []map[string]interface{}, returnErr error) {
Expand All @@ -151,14 +174,17 @@
return nil, err
}

// fmt.Println("in getBlockReceipts, heightPtr height", *heightPtr)
block, err := blockByNumberWithRetry(ctx, a.tmClient, heightPtr, 1)
if err != nil {
return nil, err
}

// Get all tx hashes for the block
height := block.Block.Header.Height
fmt.Println("in getBlockReceipts, height", height)
txHashes := getTxHashesFromBlock(block, a.txConfig, shouldIncludeSynthetic(a.namespace))
fmt.Println("in getBlockReceipts, txHashes", txHashes)
// Get tx receipts for all hashes in parallel
wg := sync.WaitGroup{}
mtx := sync.Mutex{}
Expand Down Expand Up @@ -215,6 +241,8 @@
txDecoder sdk.TxDecoder,
fullTx bool,
includeSyntheticTxs bool,
includePanicTx bool,
isPanicTx func(ctx context.Context, hash common.Hash) (bool, error),
) (map[string]interface{}, error) {
number := big.NewInt(block.Block.Height)
blockhash := common.HexToHash(block.BlockID.Hash.String())
Expand Down Expand Up @@ -253,6 +281,15 @@
if !includeSyntheticTxs && receipt.TxType == ShellEVMTxType {
continue
}
if !includePanicTx {
panic, err := isPanicTx(ctx.Context(), hash)
if err != nil {
return nil, fmt.Errorf("failed to check if tx is panic tx: %w", err)
}
if panic {
continue
}
}
newTx := ethapi.NewRPCTransaction(ethtx, blockhash, number.Uint64(), uint64(blockTime.Second()), uint64(receipt.TransactionIndex), baseFeePerGas, chainConfig)
transactions = append(transactions, newTx)
}
Expand Down
30 changes: 10 additions & 20 deletions evmrpc/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package evmrpc_test

import (
"crypto/sha256"
"fmt"
"math/big"
"testing"
"time"
Expand Down Expand Up @@ -96,7 +97,7 @@ func TestGetBlockReceipts(t *testing.T) {
require.Equal(t, 6, len(result))

// Query by block hash
resObj2 := sendRequestGood(t, "getBlockReceipts", "0x0000000000000000000000000000000000000000000000000000000000000002")
resObj2 := sendRequestGood(t, "getBlockReceipts", MultiTxBlockHash)
result = resObj2["result"].([]interface{})
require.Equal(t, 3, len(result))
receipt1 = result[0].(map[string]interface{})
Expand All @@ -119,27 +120,16 @@ func TestGetBlockReceipts(t *testing.T) {
}

func verifyGenesisBlockResult(t *testing.T, resObj map[string]interface{}) {
fmt.Println("In verifyGenesisBlockResult, resObj", resObj)
resObj = resObj["result"].(map[string]interface{})
require.Equal(t, "0x0", resObj["baseFeePerGas"])
require.Equal(t, "0x3b9aca00", resObj["baseFeePerGas"])
require.Equal(t, "0x0", resObj["difficulty"])
require.Equal(t, "0x", resObj["extraData"])
require.Equal(t, "0x0", resObj["gasLimit"])
require.Equal(t, "0xbebc200", resObj["gasLimit"])
require.Equal(t, "0x0", resObj["gasUsed"])
require.Equal(t, "0xf9d3845df25b43b1c6926f3ceda6845c17f5624e12212fd8847d0ba01da1ab9e", resObj["hash"])
require.Equal(t, "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", resObj["logsBloom"])
require.Equal(t, "0x0000000000000000000000000000000000000000", resObj["miner"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["mixHash"])
require.Equal(t, TestBlockHash, resObj["hash"])
require.Equal(t, "0x0000000000000000", resObj["nonce"])
require.Equal(t, "0x0", resObj["number"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["parentHash"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["receiptsRoot"])
require.Equal(t, "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", resObj["sha3Uncles"])
require.Equal(t, "0x0", resObj["size"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["stateRoot"])
require.Equal(t, "0x0", resObj["timestamp"])
require.Equal(t, []interface{}{}, resObj["transactions"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["transactionsRoot"])
require.Equal(t, []interface{}{}, resObj["uncles"])
require.Equal(t, "0x1", resObj["number"])
}

func verifyBlockResult(t *testing.T, resObj map[string]interface{}) {
Expand Down Expand Up @@ -210,7 +200,7 @@ func TestEncodeTmBlock_EmptyTransactions(t *testing.T) {
}

// Call EncodeTmBlock with empty transactions
result, err := evmrpc.EncodeTmBlock(ctx, block, blockRes, ethtypes.Bloom{}, k, Decoder, true, false)
result, err := evmrpc.EncodeTmBlock(ctx, block, blockRes, ethtypes.Bloom{}, k, Decoder, true, false, true, nil)
require.Nil(t, err)

// Assert txHash is equal to ethtypes.EmptyTxsHash
Expand Down Expand Up @@ -256,7 +246,7 @@ func TestEncodeBankMsg(t *testing.T) {
},
},
}
res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, ethtypes.Bloom{}, k, Decoder, true, false)
res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, ethtypes.Bloom{}, k, Decoder, true, false, true, nil)
require.Nil(t, err)
txs := res["transactions"].([]interface{})
require.Equal(t, 0, len(txs))
Expand Down Expand Up @@ -304,7 +294,7 @@ func TestEncodeWasmExecuteMsg(t *testing.T) {
},
},
}
res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, ethtypes.Bloom{}, k, Decoder, true, true)
res, err := evmrpc.EncodeTmBlock(ctx, &resBlock, &resBlockRes, ethtypes.Bloom{}, k, Decoder, true, true, true, nil)
require.Nil(t, err)
txs := res["transactions"].([]interface{})
require.Equal(t, 1, len(txs))
Expand Down
25 changes: 20 additions & 5 deletions evmrpc/server.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package evmrpc

import (
"context"
"strings"

"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rpc"
evmCfg "github.com/sei-protocol/sei-chain/x/evm/config"
"github.com/sei-protocol/sei-chain/x/evm/keeper"
Expand Down Expand Up @@ -46,7 +48,12 @@ func NewEVMHTTPServer(
ctx := ctxProvider(LatestCtxHeight)

txAPI := NewTransactionAPI(tmClient, k, ctxProvider, txConfig, homeDir, ConnectionTypeHTTP)
// filterAPI := NewFilterAPI(tmClient, &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider}, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP)
debugAPI := NewDebugAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), simulateConfig, ConnectionTypeHTTP)
isPanicTxFunc := func(ctx context.Context, hash common.Hash) (bool, error) {
return debugAPI.isPanicTx(ctx, hash)
}
seiTxAPI := NewSeiTransactionAPI(tmClient, k, ctxProvider, txConfig, homeDir, ConnectionTypeHTTP, isPanicTxFunc)
seiDebugAPI := NewSeiDebugAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), simulateConfig, ConnectionTypeHTTP)

apis := []rpc.API{
{
Expand All @@ -55,16 +62,20 @@ func NewEVMHTTPServer(
},
{
Namespace: "eth",
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeHTTP, "eth"),
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeHTTP),
},
{
Namespace: "sei",
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeHTTP, "sei"),
Service: NewSeiBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeHTTP, isPanicTxFunc),
},
{
Namespace: "eth",
Service: txAPI,
},
{
Namespace: "sei",
Service: seiTxAPI,
},
{
Namespace: "eth",
Service: NewStateAPI(tmClient, k, ctxProvider, ConnectionTypeHTTP),
Expand Down Expand Up @@ -107,7 +118,11 @@ func NewEVMHTTPServer(
},
{
Namespace: "debug",
Service: NewDebugAPI(tmClient, k, ctxProvider, txConfig.TxDecoder(), simulateConfig, ConnectionTypeHTTP),
Service: debugAPI,
},
{
Namespace: "sei",
Service: seiDebugAPI,
},
}
// Test API can only exist on non-live chain IDs. These APIs instrument certain overrides.
Expand Down Expand Up @@ -156,7 +171,7 @@ func NewEVMWebSocketServer(
},
{
Namespace: "eth",
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeWS, "eth"),
Service: NewBlockAPI(tmClient, k, ctxProvider, txConfig, ConnectionTypeWS),
},
{
Namespace: "eth",
Expand Down
Loading
Loading