From 3db0e611a6a008918f702f847e5c03c8712e2514 Mon Sep 17 00:00:00 2001 From: Jeremy Wei Date: Sun, 17 Nov 2024 08:55:52 -0500 Subject: [PATCH] bug fix: eth_getLogs missing events from early return (#1941) * change return for EffectiveGas=0 to continue * simplify * add a unit test * cleanup * cleanup --- evmrpc/block_test.go | 8 +++-- evmrpc/filter.go | 6 +--- evmrpc/filter_test.go | 33 +++++++++++++++----- evmrpc/setup_test.go | 72 +++++++++++++++++++++++++++++++++++-------- 4 files changed, 93 insertions(+), 26 deletions(-) diff --git a/evmrpc/block_test.go b/evmrpc/block_test.go index 4c394ead3b..88d82bb62a 100644 --- a/evmrpc/block_test.go +++ b/evmrpc/block_test.go @@ -80,7 +80,7 @@ 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, 5, len(result)) receipt1 := result[0].(map[string]interface{}) require.Equal(t, "0x2", receipt1["blockNumber"]) require.Equal(t, "0x0", receipt1["transactionIndex"]) @@ -94,10 +94,14 @@ func TestGetBlockReceipts(t *testing.T) { require.Equal(t, "0x2", receipt3["transactionIndex"]) require.Equal(t, multiTxBlockTx3.Hash().Hex(), receipt3["transactionHash"]) + resObjSei := sendSeiRequestGood(t, "getBlockReceipts", "0x2") + result = resObjSei["result"].([]interface{}) + require.Equal(t, 6, len(result)) + // Query by block hash resObj2 := sendRequestGood(t, "getBlockReceipts", "0x0000000000000000000000000000000000000000000000000000000000000002") result = resObj2["result"].([]interface{}) - require.Equal(t, 3, len(result)) + require.Equal(t, 5, len(result)) receipt1 = result[0].(map[string]interface{}) require.Equal(t, "0x2", receipt1["blockNumber"]) require.Equal(t, "0x0", receipt1["transactionIndex"]) diff --git a/evmrpc/filter.go b/evmrpc/filter.go index 167118ede7..2ffb77dd49 100644 --- a/evmrpc/filter.go +++ b/evmrpc/filter.go @@ -365,13 +365,9 @@ 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 includeShellReceipts is false, include receipts with synthetic logs but exclude shell tx receipts - if !f.includeSyntheticReceipts && receipt.TxType == ShellEVMTxType { + if !f.includeSyntheticReceipts && (receipt.TxType == ShellEVMTxType || receipt.EffectiveGasPrice == 0) { continue } - if !f.includeSyntheticReceipts && receipt.EffectiveGasPrice == 0 { - return - } if len(receipt.LogsBloom) > 0 && MatchFilters(ethtypes.Bloom(receipt.LogsBloom), filters) { res = append(res, keeper.GetLogsForTx(receipt)...) } diff --git a/evmrpc/filter_test.go b/evmrpc/filter_test.go index fa0a4f145f..217e74e2c9 100644 --- a/evmrpc/filter_test.go +++ b/evmrpc/filter_test.go @@ -130,9 +130,11 @@ func getCommonFilterLogTests() []GetFilterLogTests { wantLen: 4, }, { - name: "filter by single topic with default range", - topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123")}}, - wantErr: false, + name: "filter by single topic with block range", + fromBlock: "0x8", + toBlock: "0x8", + 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)) }, @@ -192,7 +194,7 @@ func TestFilterGetLogs(t *testing.T) { testFilterGetLogs(t, "eth", getCommonFilterLogTests()) } -func TestSeiFilterGetLogs(t *testing.T) { +func TestFilterSeiGetLogs(t *testing.T) { // make sure we pass all the eth_ namespace tests testFilterGetLogs(t, "sei", getCommonFilterLogTests()) @@ -221,10 +223,10 @@ func TestSeiFilterGetLogs(t *testing.T) { }) } -func TestEthEndpointCanReturnSyntheticLogs(t *testing.T) { +func TestFilterEthEndpointCanReturnSyntheticLogs(t *testing.T) { testFilterGetLogs(t, "eth", []GetFilterLogTests{ { - name: "filter by single topic with default range, exclude synethetic logs", + name: "filter by single topic with default range, still include synthetic logs", topics: [][]common.Hash{{common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000234")}}, wantErr: false, check: func(t *testing.T, log map[string]interface{}) { @@ -235,6 +237,23 @@ func TestEthEndpointCanReturnSyntheticLogs(t *testing.T) { }) } +func TestFilterEthEndpointReturnsNormalEvmLogEvenIfSyntheticLogIsInSameBlock(t *testing.T) { + testFilterGetLogs(t, "eth", []GetFilterLogTests{ + { + name: "normal evm log is returned even if synthetic log is in the same block", + fromBlock: "0x64", // 100 + toBlock: "0x64", + wantErr: false, + check: func(t *testing.T, log map[string]interface{}) { + // check that none of the events have the synthetic hash + syntheticHash := multiTxBlockSynthTx.Hash() + require.NotEqual(t, syntheticHash.Hex(), log["transactionHash"].(string)) + }, + wantLen: 2, + }, + }) +} + func testFilterGetLogs(t *testing.T, namespace string, tests []GetFilterLogTests) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -283,7 +302,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, 6, len(logs)) for _, log := range logs { logObj := log.(map[string]interface{}) require.Equal(t, "0x2", logObj["blockNumber"].(string)) diff --git a/evmrpc/setup_test.go b/evmrpc/setup_test.go index d252f31673..784852ed8f 100644 --- a/evmrpc/setup_test.go +++ b/evmrpc/setup_test.go @@ -49,6 +49,7 @@ const TestBadPort = 7779 const MockHeight = 8 const MultiTxBlockHeight = 2 const DebugTraceMockHeight = 101 +const SyntheticBlockHeight = 100 var DebugTraceHashHex = "0x1234567890123456789023456789012345678901234567890123456789000004" var DebugTraceBlockHash = "BE17E0261E539CB7E9A91E123A6D794E0163D656FCF9B8EAC07823F7ED28512B" @@ -165,6 +166,26 @@ func (c *MockClient) mockBlock(height int64) *coretypes.ResultBlock { }, } } + if height == SyntheticBlockHeight { + return &coretypes.ResultBlock{ + BlockID: MockBlockID, + Block: &tmtypes.Block{ + Header: mockBlockHeader(height), + Data: tmtypes.Data{ + Txs: []tmtypes.Tx{ + func() []byte { + bz, _ := Encoder(MultiTxBlockSynthTx) + return bz + }(), + func() []byte { + bz, _ := Encoder(MultiTxBlockTx1) + return bz + }(), + }, + }, + }, + } + } res := &coretypes.ResultBlock{ BlockID: MockBlockID, Block: &tmtypes.Block{ @@ -568,7 +589,7 @@ func generateTxData() { From: "0x1234567890123456789012345678901234567890", To: "0x1234567890123456789012345678901234567890", TransactionIndex: 0, - BlockNumber: 8, + BlockNumber: MockHeight, TxType: 1, ContractAddress: "0x1234567890123456789012345678901234567890", CumulativeGasUsed: 123, @@ -670,7 +691,8 @@ func setupLogs() { common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000123"), }, }}}}) - EVMKeeper.MockReceipt(Ctx, multiTxBlockTx1.Hash(), &types.Receipt{ + CtxMultiTx := Ctx.WithBlockHeight(MultiTxBlockHeight) + EVMKeeper.MockReceipt(CtxMultiTx, multiTxBlockTx1.Hash(), &types.Receipt{ BlockNumber: MultiTxBlockHeight, TransactionIndex: 1, // start at 1 bc 0 is the non-evm tx TxHashHex: multiTxBlockTx1.Hash().Hex(), @@ -691,7 +713,7 @@ func setupLogs() { common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), }, }}}}) - EVMKeeper.MockReceipt(Ctx, multiTxBlockTx2.Hash(), &types.Receipt{ + EVMKeeper.MockReceipt(CtxMultiTx, multiTxBlockTx2.Hash(), &types.Receipt{ BlockNumber: MultiTxBlockHeight, TransactionIndex: 3, TxHashHex: multiTxBlockTx2.Hash().Hex(), @@ -709,7 +731,7 @@ func setupLogs() { common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), }, }}}}) - EVMKeeper.MockReceipt(Ctx, multiTxBlockTx3.Hash(), &types.Receipt{ + EVMKeeper.MockReceipt(CtxMultiTx, multiTxBlockTx3.Hash(), &types.Receipt{ BlockNumber: MultiTxBlockHeight, TransactionIndex: 4, TxHashHex: multiTxBlockTx3.Hash().Hex(), @@ -727,9 +749,10 @@ func setupLogs() { common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), }, }}}}) - EVMKeeper.MockReceipt(Ctx, multiTxBlockTx4.Hash(), &types.Receipt{ + CtxMock := Ctx.WithBlockHeight(MockHeight) + EVMKeeper.MockReceipt(CtxMock, multiTxBlockTx4.Hash(), &types.Receipt{ BlockNumber: MockHeight, - TransactionIndex: 0, + TransactionIndex: 1, TxHashHex: multiTxBlockTx4.Hash().Hex(), LogsBloom: bloom4[:], Logs: []*types.Log{{ @@ -746,7 +769,8 @@ func setupLogs() { common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000456"), }, }}}}) - EVMKeeper.MockReceipt(Ctx, multiTxBlockSynthTx.Hash(), &types.Receipt{ + EVMKeeper.MockReceipt(CtxMock, multiTxBlockSynthTx.Hash(), &types.Receipt{ + TxType: evmrpc.ShellEVMTxType, BlockNumber: MockHeight, TransactionIndex: 0, TxHashHex: multiTxBlockSynthTx.Hash().Hex(), @@ -756,24 +780,48 @@ func setupLogs() { Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000234", "0x0000000000000000000000000000000000000000000000000000000000000789"}, Synthetic: true, }}, - EffectiveGasPrice: 100, + EffectiveGasPrice: 0, }) - EVMKeeper.MockReceipt(Ctx, common.HexToHash(DebugTraceHashHex), &types.Receipt{ + CtxDebugTrace := Ctx.WithBlockHeight(DebugTraceMockHeight) + EVMKeeper.MockReceipt(CtxDebugTrace, common.HexToHash(DebugTraceHashHex), &types.Receipt{ BlockNumber: DebugTraceMockHeight, TransactionIndex: 0, TxHashHex: DebugTraceHashHex, }) + txNonEvmBz, _ := Encoder(TxNonEvmWithSyntheticLog) + txNonEvmHash := sha256.Sum256(txNonEvmBz) + EVMKeeper.MockReceipt(CtxMultiTx, 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, + }) + + // block 8 EVMKeeper.SetTxHashesOnHeight(Ctx, MultiTxBlockHeight, []common.Hash{ multiTxBlockTx1.Hash(), multiTxBlockTx2.Hash(), multiTxBlockTx3.Hash(), }) + EVMKeeper.SetBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3}) + + // block 2 EVMKeeper.SetTxHashesOnHeight(Ctx, MockHeight, []common.Hash{ - multiTxBlockTx4.Hash(), multiTxBlockSynthTx.Hash(), + multiTxBlockTx4.Hash(), }) - EVMKeeper.SetBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3}) - EVMKeeper.SetBlockBloom(Ctx, []ethtypes.Bloom{bloom4, bloomSynth}) + bloomTx1 := ethtypes.CreateBloom(ethtypes.Receipts{ðtypes.Receipt{Logs: []*ethtypes.Log{{ + Address: common.HexToAddress("0x1111111111111111111111111111111111111111"), + Topics: []common.Hash{common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111"), + common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111112")}, + }}}}) + EVMKeeper.SetBlockBloom(Ctx, []ethtypes.Bloom{bloomSynth, bloom4, bloomTx1}) } //nolint:deadcode