Skip to content

Commit

Permalink
Use tendermint store to get Tx hashes instead of storing explicitly (#…
Browse files Browse the repository at this point in the history
…1913)

* Use tendermint store to get Tx hashes instead of storing explicitly

* refactor

* fix tests
  • Loading branch information
codchen authored Nov 5, 2024
1 parent 38418af commit ddcb1e6
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 43 deletions.
6 changes: 1 addition & 5 deletions evmrpc/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,9 @@ func (a *BlockAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.Block
return nil, err
}

if block == nil {
return nil, errors.New("could not retrieve block requested")
}

// Get all tx hashes for the block
height := block.Block.Header.Height
txHashes := a.keeper.GetTxHashesOnHeight(a.ctxProvider(height), height)
txHashes := getEvmTxHashesFromBlock(block, a.txConfig)
// Get tx receipts for all hashes in parallel
wg := sync.WaitGroup{}
mtx := sync.Mutex{}
Expand Down
34 changes: 10 additions & 24 deletions evmrpc/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,52 +80,38 @@ func TestGetBlockReceipts(t *testing.T) {
// Query by block height
resObj := sendRequestGood(t, "getBlockReceipts", "0x2")
result := resObj["result"].([]interface{})
require.Equal(t, 3, len(result))
require.Equal(t, 6, len(result))
receipt1 := result[0].(map[string]interface{})
require.Equal(t, "0x2", receipt1["blockNumber"])
require.Equal(t, "0x0", receipt1["transactionIndex"])
require.Equal(t, multiTxBlockTx1.Hash().Hex(), receipt1["transactionHash"])
require.Equal(t, "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", receipt1["transactionHash"])
receipt2 := result[1].(map[string]interface{})
require.Equal(t, "0x2", receipt2["blockNumber"])
require.Equal(t, "0x1", receipt2["transactionIndex"])
require.Equal(t, multiTxBlockTx2.Hash().Hex(), receipt2["transactionHash"])
require.Equal(t, multiTxBlockTx1.Hash().Hex(), receipt2["transactionHash"])
receipt3 := result[2].(map[string]interface{})
require.Equal(t, "0x2", receipt3["blockNumber"])
require.Equal(t, "0x2", receipt3["transactionIndex"])
require.Equal(t, multiTxBlockTx3.Hash().Hex(), receipt3["transactionHash"])
require.Equal(t, "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", receipt3["transactionHash"])

// Query by block hash
resObj2 := sendRequestGood(t, "getBlockReceipts", "0x0000000000000000000000000000000000000000000000000000000000000002")
result = resObj2["result"].([]interface{})
require.Equal(t, 3, len(result))
require.Equal(t, 6, len(result))
receipt1 = result[0].(map[string]interface{})
require.Equal(t, "0x2", receipt1["blockNumber"])
require.Equal(t, "0x0", receipt1["transactionIndex"])
require.Equal(t, multiTxBlockTx1.Hash().Hex(), receipt1["transactionHash"])
require.Equal(t, "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", receipt1["transactionHash"])
receipt2 = result[1].(map[string]interface{})
require.Equal(t, "0x2", receipt2["blockNumber"])
require.Equal(t, "0x1", receipt2["transactionIndex"])
require.Equal(t, multiTxBlockTx2.Hash().Hex(), receipt2["transactionHash"])
require.Equal(t, multiTxBlockTx1.Hash().Hex(), receipt2["transactionHash"])
receipt3 = result[2].(map[string]interface{})
require.Equal(t, "0x2", receipt3["blockNumber"])
require.Equal(t, "0x2", receipt3["transactionIndex"])
require.Equal(t, multiTxBlockTx3.Hash().Hex(), receipt3["transactionHash"])
require.Equal(t, "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", receipt3["transactionHash"])

// Query by tag latest => retrieves block 8
resObj3 := sendRequestGood(t, "getBlockReceipts", "latest")
result = resObj3["result"].([]interface{})
require.Equal(t, 2, len(result))
receipt1 = result[0].(map[string]interface{})
require.Equal(t, "0x8", receipt1["blockNumber"])
require.Equal(t, "0x0", receipt1["transactionIndex"])
require.Equal(t, multiTxBlockTx4.Hash().Hex(), receipt1["transactionHash"])
receiptWithSyntheticLog := result[1].(map[string]interface{})
require.Equal(t, "0x8", receiptWithSyntheticLog["blockNumber"])
logs := receiptWithSyntheticLog["logs"].([]interface{})
firstLog := logs[0].(map[string]interface{})
topics := firstLog["topics"].([]interface{})
syntheticLogFirstTopic := "0x0000000000000000000000000000000000000000000000000000000000000234"
require.Equal(t, syntheticLogFirstTopic, topics[0].(string))
require.Equal(t, tx1.Hash().Hex(), receipt1["transactionHash"])
}

func verifyGenesisBlockResult(t *testing.T, resObj map[string]interface{}) {
Expand Down Expand Up @@ -160,7 +146,7 @@ func verifyBlockResult(t *testing.T, resObj map[string]interface{}) {
require.Equal(t, "0x5", resObj["gasUsed"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000001", resObj["hash"])
// see setup_tests.go, which have one transaction for block 0x8 (latest)
require.Equal(t, "0x00002000040000000000000000000080000000200000000000000000000000080000000000000000000000000000000000000000000000000800000000000000001000000000000000000000000000000000000000000000000000000000000100000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000200000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010200000000000000", resObj["logsBloom"])
require.Equal(t, "0x00002000040000000000000000000080000000200000000000002000000000080000000000000000000000000000000000000000000000000800000000000000001000000000000000000000000000000000020000000000000000000000000100000000000000002000000000200000000000000000000000000000000000100000000000000000000000000400000000000000200000000000000000000000000000000000000100000000000000020000200000000000000000002000000000000000000000000000000000000000000000000000000000000000000200000000010000000002000000000000000000000000000000010200000000000000", resObj["logsBloom"])
require.Equal(t, "0x0000000000000000000000000000000000000005", resObj["miner"])
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", resObj["mixHash"])
require.Equal(t, "0x0000000000000000", resObj["nonce"])
Expand Down
15 changes: 11 additions & 4 deletions evmrpc/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sync"
"time"

"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -63,8 +64,8 @@ type EventItemDataWrapper struct {
Value json.RawMessage `json:"value"`
}

func NewFilterAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, filterConfig *FilterConfig, connectionType ConnectionType, namespace string) *FilterAPI {
logFetcher := &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider, filterConfig: filterConfig, includeSyntheticReceipts: shouldIncludeSynthetic(namespace)}
func NewFilterAPI(tmClient rpcclient.Client, k *keeper.Keeper, ctxProvider func(int64) sdk.Context, txConfig client.TxConfig, filterConfig *FilterConfig, connectionType ConnectionType, namespace string) *FilterAPI {
logFetcher := &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider, txConfig: txConfig, filterConfig: filterConfig, includeSyntheticReceipts: shouldIncludeSynthetic(namespace)}
filters := make(map[ethrpc.ID]filter)
api := &FilterAPI{
namespace: namespace,
Expand Down Expand Up @@ -276,6 +277,7 @@ func (a *FilterAPI) UninstallFilter(
type LogFetcher struct {
tmClient rpcclient.Client
k *keeper.Keeper
txConfig client.TxConfig
ctxProvider func(int64) sdk.Context
filterConfig *FilterConfig
includeSyntheticReceipts bool
Expand Down Expand Up @@ -358,8 +360,13 @@ func (f *LogFetcher) FindBlockesByBloom(begin, end int64, filters [][]bloomIndex

func (f *LogFetcher) FindLogsByBloom(height int64, filters [][]bloomIndexes) (res []*ethtypes.Log) {
ctx := f.ctxProvider(LatestCtxHeight)
txHashes := f.k.GetTxHashesOnHeight(ctx, height)
for _, hash := range txHashes {
block, err := blockByNumberWithRetry(context.Background(), f.tmClient, &height, 1)
if err != nil {
fmt.Printf("error getting block when querying logs: %s\n", err)
return
}

for _, hash := range getEvmTxHashesFromBlock(block, f.txConfig) {
receipt, err := f.k.GetReceipt(ctx, hash)
if err != nil {
ctx.Logger().Error(fmt.Sprintf("FindLogsByBloom: unable to find receipt for hash %s", hash.Hex()))
Expand Down
6 changes: 3 additions & 3 deletions evmrpc/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ func getCommonFilterLogTests() []GetFilterLogTests {
},
{
name: "filter by single topic with default range",
topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123")}},
topics: [][]common.Hash{{common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111")}},
wantErr: false,
check: func(t *testing.T, log map[string]interface{}) {
require.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000123", log["topics"].([]interface{})[0].(string))
require.Equal(t, "0x1111111111111111111111111111111111111111111111111111111111111111", log["topics"].([]interface{})[0].(string))
},
wantLen: 1,
},
Expand Down Expand Up @@ -283,7 +283,7 @@ func TestFilterGetFilterLogs(t *testing.T) {

resObj = sendRequest(t, TestPort, "getFilterLogs", filterId)
logs := resObj["result"].([]interface{})
require.Equal(t, 4, len(logs))
require.Equal(t, 7, len(logs))
for _, log := range logs {
logObj := log.(map[string]interface{})
require.Equal(t, "0x2", logObj["blockNumber"].(string))
Expand Down
6 changes: 3 additions & 3 deletions evmrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ func NewEVMHTTPServer(
},
{
Namespace: "eth",
Service: NewFilterAPI(tmClient, k, ctxProvider, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP, "eth"),
Service: NewFilterAPI(tmClient, k, ctxProvider, txConfig, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP, "eth"),
},
{
Namespace: "sei",
Service: NewFilterAPI(tmClient, k, ctxProvider, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP, "sei"),
Service: NewFilterAPI(tmClient, k, ctxProvider, txConfig, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeHTTP, "sei"),
},
{
Namespace: "sei",
Expand Down Expand Up @@ -184,7 +184,7 @@ func NewEVMWebSocketServer(
},
{
Namespace: "eth",
Service: NewSubscriptionAPI(tmClient, &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider}, &SubscriptionConfig{subscriptionCapacity: 100, newHeadLimit: config.MaxSubscriptionsNewHead}, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeWS),
Service: NewSubscriptionAPI(tmClient, &LogFetcher{tmClient: tmClient, k: k, ctxProvider: ctxProvider, txConfig: txConfig}, &SubscriptionConfig{subscriptionCapacity: 100, newHeadLimit: config.MaxSubscriptionsNewHead}, &FilterConfig{timeout: config.FilterTimeout, maxLog: config.MaxLogNoBlock, maxBlock: config.MaxBlocksForLog}, ConnectionTypeWS),
},
{
Namespace: "web3",
Expand Down
36 changes: 32 additions & 4 deletions evmrpc/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package evmrpc_test

import (
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
Expand Down Expand Up @@ -76,6 +77,7 @@ var multiTxBlockSynthTx *ethtypes.Transaction

var DebugTraceTx sdk.Tx
var TxNonEvm sdk.Tx
var TxNonEvmWithSyntheticLog sdk.Tx
var UnconfirmedTx sdk.Tx

var SConfig = evmrpc.SimulateConfig{GasCap: 10000000}
Expand Down Expand Up @@ -176,7 +178,7 @@ func (c *MockClient) mockBlock(height int64) *coretypes.ResultBlock {
return bz
}(),
func() []byte {
bz, _ := Encoder(TxNonEvm)
bz, _ := Encoder(TxNonEvmWithSyntheticLog)
return bz
}(),
},
Expand Down Expand Up @@ -564,6 +566,12 @@ func generateTxData() {
MultiTxBlockSynthTx = synthTxBuilder.GetTx()
DebugTraceTx = debugTraceTxBuilder.GetTx()
TxNonEvm = app.TestTx{}
TxNonEvmWithSyntheticLog = app.TestTx{}
bloomTx1 := ethtypes.CreateBloom(ethtypes.Receipts{&ethtypes.Receipt{Logs: []*ethtypes.Log{{
Address: common.HexToAddress("0x1111111111111111111111111111111111111111"),
Topics: []common.Hash{common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111"),
common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111112")},
}}}})
if err := EVMKeeper.MockReceipt(Ctx, tx1.Hash(), &types.Receipt{
From: "0x1234567890123456789012345678901234567890",
To: "0x1234567890123456789012345678901234567890",
Expand All @@ -580,6 +588,7 @@ func generateTxData() {
Address: "0x1111111111111111111111111111111111111111",
Topics: []string{"0x1111111111111111111111111111111111111111111111111111111111111111", "0x1111111111111111111111111111111111111111111111111111111111111112"},
}},
LogsBloom: bloomTx1[:],
}); err != nil {
panic(err)
}
Expand Down Expand Up @@ -747,8 +756,8 @@ func setupLogs() {
},
}}}})
EVMKeeper.MockReceipt(Ctx, multiTxBlockSynthTx.Hash(), &types.Receipt{
BlockNumber: MockHeight,
TransactionIndex: 0,
BlockNumber: MultiTxBlockHeight,
TransactionIndex: 5,
TxHashHex: multiTxBlockSynthTx.Hash().Hex(),
LogsBloom: bloomSynth[:],
Logs: []*types.Log{{
Expand All @@ -763,6 +772,20 @@ func setupLogs() {
TransactionIndex: 0,
TxHashHex: DebugTraceHashHex,
})
txNonEvmBz, _ := Encoder(TxNonEvmWithSyntheticLog)
txNonEvmHash := sha256.Sum256(txNonEvmBz)
EVMKeeper.MockReceipt(Ctx, txNonEvmHash, &types.Receipt{
BlockNumber: MultiTxBlockHeight,
TransactionIndex: 1,
TxHashHex: common.Hash(txNonEvmHash).Hex(),
LogsBloom: bloomSynth[:],
Logs: []*types.Log{{
Address: "0x1111111111111111111111111111111111111116",
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000234", "0x0000000000000000000000000000000000000000000000000000000000000789"},
Synthetic: true,
}},
EffectiveGasPrice: 100,
})
EVMKeeper.SetTxHashesOnHeight(Ctx, MultiTxBlockHeight, []common.Hash{
multiTxBlockTx1.Hash(),
multiTxBlockTx2.Hash(),
Expand All @@ -772,8 +795,13 @@ func setupLogs() {
multiTxBlockTx4.Hash(),
multiTxBlockSynthTx.Hash(),
})
bloomTx1 := ethtypes.CreateBloom(ethtypes.Receipts{&ethtypes.Receipt{Logs: []*ethtypes.Log{{
Address: common.HexToAddress("0x1111111111111111111111111111111111111111"),
Topics: []common.Hash{common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111"),
common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111112")},
}}}})
EVMKeeper.SetBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3})
EVMKeeper.SetBlockBloom(Ctx, []ethtypes.Bloom{bloom4, bloomSynth})
EVMKeeper.SetBlockBloom(Ctx, []ethtypes.Bloom{bloom4, bloomSynth, bloomTx1})
}

//nolint:deadcode
Expand Down
27 changes: 27 additions & 0 deletions evmrpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package evmrpc
import (
"context"
"crypto/ecdsa"
"crypto/sha256"
"encoding/hex"
"fmt"
"math/big"
Expand All @@ -15,10 +16,12 @@ import (
"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rpc"
"github.com/sei-protocol/sei-chain/utils/metrics"
"github.com/sei-protocol/sei-chain/x/evm/keeper"
"github.com/sei-protocol/sei-chain/x/evm/types"
"github.com/tendermint/tendermint/libs/bytes"
rpcclient "github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/coretypes"
Expand Down Expand Up @@ -203,3 +206,27 @@ func shouldIncludeSynthetic(namespace string) bool {
}
return namespace == "sei"
}

func getEvmTxHashesFromBlock(block *coretypes.ResultBlock, txConfig client.TxConfig) []common.Hash {
txHashes := []common.Hash{}
for i, tx := range block.Block.Data.Txs {
sdkTx, err := txConfig.TxDecoder()(tx)
if err != nil {
fmt.Printf("error decoding tx %d in block %d, skipping\n", i, block.Block.Height)
continue
}
if len(sdkTx.GetMsgs()) == 0 {
txHashes = append(txHashes, sha256.Sum256(tx))
continue
}
if evmTx, ok := sdkTx.GetMsgs()[0].(*types.MsgEVMTransaction); ok {
if evmTx.IsAssociateTx() {
continue
}
ethtx, _ := evmTx.AsTransaction()
txHashes = append(txHashes, ethtx.Hash())
}
txHashes = append(txHashes, sha256.Sum256(tx))
}
return txHashes
}
2 changes: 2 additions & 0 deletions x/evm/keeper/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/sei-protocol/sei-chain/x/evm/types"
)

// deprecated
func (k *Keeper) GetTxHashesOnHeight(ctx sdk.Context, height int64) (res []common.Hash) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.TxHashesKey(height))
Expand All @@ -18,6 +19,7 @@ func (k *Keeper) GetTxHashesOnHeight(ctx sdk.Context, height int64) (res []commo
return
}

// deprecated
func (k *Keeper) SetTxHashesOnHeight(ctx sdk.Context, height int64, hashes []common.Hash) {
if len(hashes) == 0 {
return
Expand Down

0 comments on commit ddcb1e6

Please sign in to comment.