Skip to content

Commit da54276

Browse files
blindchaserphilipsu522
authored andcommitted
fix: use evm only index in eth_getLogs (#2211)
* fix: use evm index in eth_getLogs
1 parent 74f9b9e commit da54276

File tree

2 files changed

+186
-0
lines changed

2 files changed

+186
-0
lines changed

evmrpc/filter.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,7 @@ func (f *LogFetcher) IsLogExactMatch(log *ethtypes.Log, crit filters.FilterCrite
823823
func (f *LogFetcher) collectLogs(block *coretypes.ResultBlock, crit filters.FilterCriteria, filters [][]bloomIndexes, collector logCollector, applyExactMatch bool) {
824824
ctx := f.ctxProvider(LatestCtxHeight)
825825
totalLogs := uint(0)
826+
evmTxIndex := 0
826827

827828
for _, hash := range getTxHashesFromBlock(block, f.txConfig, f.includeSyntheticReceipts) {
828829
receipt, found := getCachedReceipt(block.Block.Height, hash)
@@ -848,23 +849,27 @@ func (f *LogFetcher) collectLogs(block *coretypes.ResultBlock, crit filters.Filt
848849
allLogs := keeper.GetLogsForTx(receipt, totalLogs)
849850
if applyExactMatch {
850851
for _, log := range allLogs {
852+
log.TxIndex = uint(evmTxIndex)
851853
if f.IsLogExactMatch(log, crit) {
852854
collector.Append(log)
853855
}
854856
}
855857
} else {
856858
for _, log := range allLogs {
859+
log.TxIndex = uint(evmTxIndex)
857860
collector.Append(log)
858861
}
859862
}
860863
}
861864
} else {
862865
// No filter, return all logs
863866
for _, log := range keeper.GetLogsForTx(receipt, totalLogs) {
867+
log.TxIndex = uint(evmTxIndex)
864868
collector.Append(log)
865869
}
866870
}
867871
totalLogs += uint(len(receipt.Logs))
872+
evmTxIndex++
868873
}
869874
}
870875

evmrpc/filter_test.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package evmrpc_test
22

33
import (
4+
"strconv"
45
"testing"
56
"time"
67

78
"github.com/ethereum/go-ethereum/common"
9+
ethtypes "github.com/ethereum/go-ethereum/core/types"
10+
testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper"
11+
"github.com/sei-protocol/sei-chain/x/evm/keeper"
12+
evmtypes "github.com/sei-protocol/sei-chain/x/evm/types"
813
"github.com/stretchr/testify/require"
914
)
1015

@@ -433,3 +438,179 @@ func TestGetLogsBlockHashIsNotZero(t *testing.T) {
433438
"log %d should be from block 2", i)
434439
}
435440
}
441+
442+
func TestGetLogsTransactionIndexConsistency(t *testing.T) {
443+
t.Parallel()
444+
445+
// Test that eth_getLogs returns logs with transaction indices that match eth_getBlockByNumber
446+
// This is a regression test for the transaction index mismatch issue
447+
448+
// Try multiple blocks to find one with both logs and EVM transactions
449+
testBlocks := []string{"0x2", "0x8", "0x64", "0x67"} // Block 2, 8, 100, 103
450+
451+
var logs []interface{}
452+
var transactions []interface{}
453+
var blockHex string
454+
455+
for _, blockNum := range testBlocks {
456+
// Get logs for this block
457+
filterCriteria := map[string]interface{}{
458+
"fromBlock": blockNum,
459+
"toBlock": blockNum,
460+
}
461+
resObj := sendRequestGood(t, "getLogs", filterCriteria)
462+
blockLogs := resObj["result"].([]interface{})
463+
464+
if len(blockLogs) == 0 {
465+
continue // No logs in this block, try next
466+
}
467+
468+
// Get the block to see what transaction indices eth_getBlockByNumber returns
469+
blockRes := sendRequestGood(t, "getBlockByNumber", blockNum, true)
470+
block := blockRes["result"].(map[string]interface{})
471+
blockTxs := block["transactions"].([]interface{})
472+
473+
if len(blockTxs) > 0 {
474+
// Found a block with both logs and EVM transactions
475+
logs = blockLogs
476+
transactions = blockTxs
477+
blockHex = blockNum
478+
t.Logf("Using block %s with %d logs and %d EVM transactions", blockHex, len(logs), len(transactions))
479+
break
480+
}
481+
}
482+
483+
// Skip test if we can't find a suitable block (this might happen in minimal test environments)
484+
if len(logs) == 0 || len(transactions) == 0 {
485+
t.Skip("No block found with both logs and EVM transactions - skipping transaction index consistency test")
486+
return
487+
}
488+
489+
// Create a map of transaction hash to EVM transaction index from the block
490+
hashToEvmIndex := make(map[string]int)
491+
for i, txInterface := range transactions {
492+
tx := txInterface.(map[string]interface{})
493+
txHash := tx["hash"].(string)
494+
hashToEvmIndex[txHash] = i
495+
}
496+
497+
// Verify that each log's transactionIndex is a valid EVM index (0 to len(transactions)-1)
498+
for i, logInterface := range logs {
499+
log := logInterface.(map[string]interface{})
500+
txHash := log["transactionHash"].(string)
501+
logTxIndex := log["transactionIndex"].(string)
502+
503+
// Convert hex string to int for comparison
504+
logTxIndexInt, err := strconv.ParseInt(logTxIndex[2:], 16, 64)
505+
require.NoError(t, err, "should be able to parse transaction index from log %d", i)
506+
507+
// Key assertion: transactionIndex should be a valid EVM transaction index
508+
require.GreaterOrEqual(t, logTxIndexInt, int64(0),
509+
"log %d: transactionIndex %d should be >= 0", i, logTxIndexInt)
510+
require.Less(t, logTxIndexInt, int64(len(transactions)),
511+
"log %d: transactionIndex %d should be < %d (number of EVM transactions)",
512+
i, logTxIndexInt, len(transactions))
513+
514+
// If the transaction exists in the block, verify indices match
515+
if expectedEvmIndex, exists := hashToEvmIndex[txHash]; exists {
516+
require.Equal(t, int64(expectedEvmIndex), logTxIndexInt,
517+
"log %d: transactionIndex from eth_getLogs (%d) should match EVM transaction index from eth_getBlockByNumber (%d) for tx %s",
518+
i, logTxIndexInt, expectedEvmIndex, txHash)
519+
}
520+
}
521+
522+
// Additional check: ensure transaction indices are reasonable for the block structure
523+
// Block 8 should have mixed transaction types, so EVM transaction indices should be sequential
524+
txIndicesFound := make(map[int64]bool)
525+
for _, logInterface := range logs {
526+
log := logInterface.(map[string]interface{})
527+
logTxIndex := log["transactionIndex"].(string)
528+
logTxIndexInt, _ := strconv.ParseInt(logTxIndex[2:], 16, 64)
529+
txIndicesFound[logTxIndexInt] = true
530+
}
531+
532+
// We should not see indices that are >= number of EVM transactions
533+
for txIndex := range txIndicesFound {
534+
require.Less(t, txIndex, int64(len(transactions)),
535+
"no log should have transactionIndex %d when there are only %d EVM transactions",
536+
txIndex, len(transactions))
537+
}
538+
}
539+
540+
func TestCollectLogsEvmTransactionIndex(t *testing.T) {
541+
t.Parallel()
542+
543+
// This is a unit test for the core logic that collectLogs implements
544+
// It tests that transaction indices are set correctly for EVM transactions
545+
546+
// Set up the test environment - use the correct return values from MockEVMKeeper
547+
k, ctx := testkeeper.MockEVMKeeper()
548+
549+
// Create a mock block with mixed transaction types (similar to block 2 in our test data)
550+
// We'll simulate the transaction hashes that getTxHashesFromBlock would return
551+
evmTxHashes := []common.Hash{
552+
common.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111"), // EVM tx index 0
553+
common.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222"), // EVM tx index 1
554+
common.HexToHash("0x3333333333333333333333333333333333333333333333333333333333333333"), // EVM tx index 2
555+
}
556+
557+
// Create mock receipts with logs
558+
for i, txHash := range evmTxHashes {
559+
receipt := &evmtypes.Receipt{
560+
TxHashHex: txHash.Hex(),
561+
TransactionIndex: uint32(i + 10), // Use high absolute indices to simulate mixed tx types
562+
BlockNumber: 2,
563+
Logs: []*evmtypes.Log{
564+
{
565+
Address: "0x1111111111111111111111111111111111111112",
566+
Topics: []string{"0x0000000000000000000000000000000000000000000000000000000000000123"},
567+
Data: []byte("test data"),
568+
Index: 0,
569+
},
570+
},
571+
LogsBloom: make([]byte, 256), // Empty bloom for simplicity
572+
}
573+
574+
// Fill bloom filter to match our test filters
575+
receipt.LogsBloom[0] = 0xFF // Simple bloom that will match any filter
576+
577+
k.MockReceipt(ctx, txHash, receipt)
578+
}
579+
580+
// Test the core logic that collectLogs implements
581+
// This simulates what collectLogs does for each EVM transaction
582+
var collectedLogs []*ethtypes.Log
583+
evmTxIndex := 0
584+
totalLogs := uint(0)
585+
586+
for _, txHash := range evmTxHashes {
587+
receipt, err := k.GetReceipt(ctx, txHash)
588+
require.NoError(t, err, "should be able to get receipt for tx %s", txHash.Hex())
589+
590+
// This simulates keeper.GetLogsForTx
591+
logs := keeper.GetLogsForTx(receipt, totalLogs)
592+
593+
// This is the key part we're testing: setting the correct EVM transaction index
594+
for _, log := range logs {
595+
log.TxIndex = uint(evmTxIndex) // This should override receipt.TransactionIndex
596+
collectedLogs = append(collectedLogs, log)
597+
}
598+
599+
totalLogs += uint(len(receipt.Logs))
600+
evmTxIndex++
601+
}
602+
603+
// Verify that the transaction indices are set correctly
604+
require.Equal(t, len(evmTxHashes), len(collectedLogs), "should have one log per transaction")
605+
606+
for i, log := range collectedLogs {
607+
// This is the main assertion: TxIndex should be the EVM transaction index (0, 1, 2)
608+
// NOT the absolute transaction index (10, 11, 12)
609+
require.Equal(t, uint(i), log.TxIndex,
610+
"log %d should have EVM transaction index %d, but got %d", i, i, log.TxIndex)
611+
612+
// Verify it's NOT using the absolute transaction index
613+
require.NotEqual(t, uint(i+10), log.TxIndex,
614+
"log %d should not use absolute transaction index %d", i, i+10)
615+
}
616+
}

0 commit comments

Comments
 (0)