Skip to content

Commit

Permalink
[EVM] Add new RPC endpoint eth_getBlockReceipts (#1270)
Browse files Browse the repository at this point in the history
* Add new endpoint GetBlockReceipt

* Remove prints

* Fix endpoint name

* Fix comment

* Fix unit test

* Fix unit test

* Fix import

* Fix unit test
  • Loading branch information
yzang2019 authored and udpatil committed Feb 28, 2024
1 parent 41dad99 commit c857eb8
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 54 deletions.
58 changes: 56 additions & 2 deletions evmrpc/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"context"
"errors"
"math/big"
"strings"
"sync"
"time"

tmtypes "github.com/tendermint/tendermint/types"

"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
Expand All @@ -19,6 +19,7 @@ import (
"github.com/sei-protocol/sei-chain/x/evm/types"
rpcclient "github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/coretypes"
tmtypes "github.com/tendermint/tendermint/types"
)

type BlockAPI struct {
Expand Down Expand Up @@ -88,6 +89,59 @@ func (a *BlockAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber,
return EncodeTmBlock(a.ctxProvider(LatestCtxHeight), block, blockRes, a.keeper, a.txConfig.TxDecoder(), fullTx)
}

func (a *BlockAPI) GetBlockReceipts(ctx context.Context, number rpc.BlockNumber) (result []map[string]interface{}, returnErr error) {
startTime := time.Now()
defer recordMetrics("eth_getBlockReceipts", startTime, returnErr == nil)
// Get height from params
heightPtr, err := getBlockNumber(ctx, a.tmClient, number)
if err != nil {
return nil, err
}
// Get the block by height
block, err := blockWithRetry(ctx, a.tmClient, heightPtr)
if err != nil {
return nil, err
}
// Get all tx hashes for the block
height := LatestCtxHeight
if heightPtr != nil {
height = *heightPtr
}
txHashes := a.keeper.GetTxHashesOnHeight(a.ctxProvider(height), height)
// Get tx receipts for all hashes in parallel
wg := sync.WaitGroup{}
mtx := sync.Mutex{}
allReceipts := make([]map[string]interface{}, len(txHashes))
for i, hash := range txHashes {
wg.Add(1)
go func(i int, hash common.Hash) {
defer wg.Done()
receipt, err := a.keeper.GetReceipt(a.ctxProvider(height), hash)
if err != nil {
// When the transaction doesn't exist, skip it
if !strings.Contains(err.Error(), "not found") {
mtx.Lock()
returnErr = err
mtx.Unlock()
}
} else {
encodedReceipt, err := encodeReceipt(receipt, block.BlockID.Hash)
if err != nil {
mtx.Lock()
returnErr = err
mtx.Unlock()
}
allReceipts[i] = encodedReceipt
}
}(i, hash)
}
wg.Wait()
if returnErr != nil {
return nil, returnErr
}
return allReceipts, nil
}

func EncodeTmBlock(
ctx sdk.Context,
block *coretypes.ResultBlock,
Expand Down
19 changes: 19 additions & 0 deletions evmrpc/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,25 @@ func TestGetBlockTransactionCount(t *testing.T) {
require.Equal(t, "0x1", resObj["result"])
}

func TestGetBlockReceipts(t *testing.T) {
resObj := sendRequestGood(t, "getBlockReceipts", "0x2")
result := resObj["result"].([]interface{})
require.Equal(t, 3, len(result))
receipt1 := result[0].(map[string]interface{})
require.Equal(t, "0x2", receipt1["blockNumber"])
require.Equal(t, "0x0", receipt1["transactionIndex"])
require.Equal(t, "0x0123456789012345678902345678901234567890123456789012345678900001", receipt1["transactionHash"])
receipt2 := result[1].(map[string]interface{})
require.Equal(t, "0x2", receipt2["blockNumber"])
require.Equal(t, "0x1", receipt2["transactionIndex"])
require.Equal(t, "0x0123456789012345678902345678901234567890123456789012345678900002", receipt2["transactionHash"])
receipt3 := result[2].(map[string]interface{})
require.Equal(t, "0x2", receipt3["blockNumber"])
require.Equal(t, "0x2", receipt3["transactionIndex"])
require.Equal(t, "0x0123456789012345678902345678901234567890123456789012345678900003", receipt3["transactionHash"])

}

func verifyBlockResult(t *testing.T, resObj map[string]interface{}) {
resObj = resObj["result"].(map[string]interface{})
require.Equal(t, "0x0", resObj["difficulty"])
Expand Down
2 changes: 1 addition & 1 deletion evmrpc/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ func (f *LogFetcher) FindLogsByBloom(height int64, filters [][]bloomIndexes) (re
ctx.Logger().Error(fmt.Sprintf("FindLogsByBloom: unable to find receipt for hash %s", hash.Hex()))
continue
}
if MatchFilters(ethtypes.Bloom(receipt.LogsBloom), filters) {
if len(receipt.LogsBloom) > 0 && MatchFilters(ethtypes.Bloom(receipt.LogsBloom), filters) {
res = append(res, keeper.GetLogsForTx(receipt)...)
}
}
Expand Down
6 changes: 3 additions & 3 deletions evmrpc/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ func TestFilterGetLogs(t *testing.T) {
common.HexToAddress("0x1111111111111111111111111111111111111113"),
},
topics: [][]common.Hash{
{common.Hash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"))},
{common.Hash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"))},
{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123")},
{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456")},
},
wantErr: false,
check: func(t *testing.T, log map[string]interface{}) {
Expand All @@ -155,7 +155,7 @@ func TestFilterGetLogs(t *testing.T) {
toBlock: "0x2",
topics: [][]common.Hash{
{},
{common.Hash(common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"))},
{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456")},
},
wantErr: false,
check: func(t *testing.T, log map[string]interface{}) {
Expand Down
101 changes: 53 additions & 48 deletions evmrpc/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"testing"
"time"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/hd"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -337,6 +338,7 @@ func init() {
panic(err)
}
testApp.Commit(context.Background())
// Start good http server
goodConfig := evmrpc.DefaultConfig
goodConfig.HTTPPort = TestPort
goodConfig.WSPort = TestWSPort
Expand All @@ -352,6 +354,8 @@ func init() {
if err := HttpServer.Start(); err != nil {
panic(err)
}

// Start bad http server
badConfig := evmrpc.DefaultConfig
badConfig.HTTPPort = TestBadPort
badConfig.FilterTimeout = 500 * time.Millisecond
Expand All @@ -362,6 +366,8 @@ func init() {
if err := badHTTPServer.Start(); err != nil {
panic(err)
}

// Start ws server
wsServer, err := evmrpc.NewEVMWebSocketServer(infoLog, goodConfig, &MockClient{}, EVMKeeper, func(int64) sdk.Context { return Ctx }, TxConfig, "")
if err != nil {
panic(err)
Expand All @@ -372,43 +378,26 @@ func init() {
fmt.Printf("wsServer started with config = %+v\n", goodConfig)
time.Sleep(1 * time.Second)

// Generate data
generateTxData()

// Setup logs
setupLogs()
}

func generateTxData() {
chainId := big.NewInt(types.DefaultChainID.Int64())
to := common.HexToAddress("010203")
txData := ethtypes.DynamicFeeTx{
txBuilder, tx := buildTx(ethtypes.DynamicFeeTx{
Nonce: 1,
GasFeeCap: big.NewInt(10),
Gas: 1000,
To: &to,
Value: big.NewInt(1000),
Data: []byte("abc"),
ChainID: chainId,
}
mnemonic := "fish mention unlock february marble dove vintage sand hub ordinary fade found inject room embark supply fabric improve spike stem give current similar glimpse"
derivedPriv, _ := hd.Secp256k1.Derive()(mnemonic, "", "")
privKey := hd.Secp256k1.Generate()(derivedPriv)
testPrivHex := hex.EncodeToString(privKey.Bytes())
key, _ := crypto.HexToECDSA(testPrivHex)
evmParams := EVMKeeper.GetParams(Ctx)
ethCfg := evmParams.GetChainConfig().EthereumConfig(chainId)
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(Ctx.BlockHeight()), uint64(Ctx.BlockTime().Unix()))
tx := ethtypes.NewTx(&txData)
tx, err = ethtypes.SignTx(tx, signer, key)
if err != nil {
panic(err)
}
typedTx, err := ethtx.NewDynamicFeeTx(tx)
if err != nil {
panic(err)
}
msg, err := types.NewMsgEVMTransaction(typedTx)
if err != nil {
panic(err)
}
b := TxConfig.NewTxBuilder()
if err := b.SetMsgs(msg); err != nil {
panic(err)
}
Tx = b.GetTx()
})
Tx = txBuilder.GetTx()
TxNonEvm = app.TestTx{}
if err := EVMKeeper.SetReceipt(Ctx, tx.Hash(), &types.Receipt{
From: "0x1234567890123456789012345678901234567890",
Expand All @@ -429,7 +418,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 All @@ -452,36 +441,47 @@ func init() {
common.HexToAddress("0x1df809C639027b465B931BD63Ce71c8E5834D9d6"),
)
EVMKeeper.SetNonce(Ctx, common.HexToAddress("0x1234567890123456789012345678901234567890"), 1)

unconfirmedTxData := ethtypes.DynamicFeeTx{
unconfirmedTxBuilder, _ := buildTx(ethtypes.DynamicFeeTx{
Nonce: 2,
GasFeeCap: big.NewInt(10),
Gas: 1000,
To: &to,
Value: big.NewInt(2000),
Data: []byte("abc"),
ChainID: chainId,
}
tx = ethtypes.NewTx(&unconfirmedTxData)
tx, err = ethtypes.SignTx(tx, signer, key)
})
UnconfirmedTx = unconfirmedTxBuilder.GetTx()
}

func buildTx(txData ethtypes.DynamicFeeTx) (client.TxBuilder, *ethtypes.Transaction) {
chainId := big.NewInt(types.DefaultChainID.Int64())
mnemonic := "fish mention unlock february marble dove vintage sand hub ordinary fade found inject room embark supply fabric improve spike stem give current similar glimpse"
derivedPriv, _ := hd.Secp256k1.Derive()(mnemonic, "", "")
privKey := hd.Secp256k1.Generate()(derivedPriv)
testPrivHex := hex.EncodeToString(privKey.Bytes())
key, _ := crypto.HexToECDSA(testPrivHex)
evmParams := EVMKeeper.GetParams(Ctx)
ethCfg := evmParams.GetChainConfig().EthereumConfig(chainId)
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(Ctx.BlockHeight()), uint64(Ctx.BlockTime().Unix()))
tx := ethtypes.NewTx(&txData)
tx, err := ethtypes.SignTx(tx, signer, key)
if err != nil {
panic(err)
}
typedTx, err = ethtx.NewDynamicFeeTx(tx)

typedTx, err := ethtx.NewDynamicFeeTx(tx)
if err != nil {
panic(err)
}
msg, err = types.NewMsgEVMTransaction(typedTx)
msg, err := types.NewMsgEVMTransaction(typedTx)
if err != nil {
panic(err)
}
b = TxConfig.NewTxBuilder()
if err := b.SetMsgs(msg); err != nil {
builder := TxConfig.NewTxBuilder()
if err := builder.SetMsgs(msg); err != nil {
panic(err)
}
UnconfirmedTx = b.GetTx()

setupLogs()
return builder, tx
}

func setupLogs() {
Expand All @@ -499,8 +499,10 @@ func setupLogs() {
},
}}}})
EVMKeeper.SetReceipt(Ctx, common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900001"), &types.Receipt{
BlockNumber: 2,
LogsBloom: bloom1[:],
BlockNumber: 2,
TransactionIndex: 0,
TxHashHex: "0x123456789012345678902345678901234567890123456789012345678900001",
LogsBloom: bloom1[:],
Logs: []*types.Log{{
Address: "0x1111111111111111111111111111111111111112",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"},
Expand All @@ -517,8 +519,10 @@ func setupLogs() {
},
}}}})
EVMKeeper.SetReceipt(Ctx, common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900002"), &types.Receipt{
BlockNumber: 2,
LogsBloom: bloom2[:],
BlockNumber: 2,
TransactionIndex: 1,
TxHashHex: "0x123456789012345678902345678901234567890123456789012345678900002",
LogsBloom: bloom2[:],
Logs: []*types.Log{{
Address: "0x1111111111111111111111111111111111111113",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"},
Expand All @@ -532,8 +536,10 @@ func setupLogs() {
},
}}}})
EVMKeeper.SetReceipt(Ctx, common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900003"), &types.Receipt{
BlockNumber: 2,
LogsBloom: bloom3[:],
BlockNumber: 2,
TransactionIndex: 2,
TxHashHex: "0x123456789012345678902345678901234567890123456789012345678900003",
LogsBloom: bloom3[:],
Logs: []*types.Log{{
Address: "0x1111111111111111111111111111111111111114",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123", "0x0000000000000000000000000000000000000000000000000000000000000456"},
Expand All @@ -545,7 +551,6 @@ func setupLogs() {
common.HexToHash("0x123456789012345678902345678901234567890123456789012345678900003"),
})
EVMKeeper.SetBlockBloom(Ctx, 2, []ethtypes.Bloom{bloom1, bloom2, bloom3})

}

//nolint:deadcode
Expand Down

0 comments on commit c857eb8

Please sign in to comment.