Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
22 changes: 21 additions & 1 deletion evmrpc/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,11 @@ func (a *FilterAPI) GetLogs(ctx context.Context, crit filters.FilterCriteria) (r
defer recordMetricsWithError(fmt.Sprintf("%s_getLogs", a.namespace), a.connectionType, time.Now(), err)
// Calculate block range
latest := a.logFetcher.ctxProvider(LatestCtxHeight).BlockHeight()
// get block number from hash and compare to latest
latestReceiptVersion, err := a.logFetcher.k.GetLatestReceiptVersion(a.logFetcher.ctxProvider(LatestCtxHeight))
if err != nil {
return nil, err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently if it returns an error, we should probably fall back to the previous approach to assume latestVersion=latestblock

}
begin, end := latest, latest
if crit.FromBlock != nil {
begin = getHeightFromBigIntBlockNumber(latest, crit.FromBlock)
Expand All @@ -526,7 +531,6 @@ func (a *FilterAPI) GetLogs(ctx context.Context, crit filters.FilterCriteria) (r
begin = end
}
}

blockRange := end - begin + 1

// Use config value instead of hardcoded constant
Expand All @@ -539,6 +543,22 @@ func (a *FilterAPI) GetLogs(ctx context.Context, crit filters.FilterCriteria) (r
return nil, fmt.Errorf("log query rate limit exceeded for large queries, please try again later")
}

if begin > latestReceiptVersion || end > latestReceiptVersion {
return nil, fmt.Errorf("block range includes unavailable block(s)")
}
if crit.BlockHash != nil {
header, err := a.tmClient.HeaderByHash(ctx, crit.BlockHash[:])
if err != nil {
return nil, err
}
if header == nil || header.Header == nil {
return nil, fmt.Errorf("block hash %s not found", crit.BlockHash.Hex())
}
if header.Header.Height > latestReceiptVersion {
return nil, fmt.Errorf("block hash %s isn't available yet", crit.BlockHash.Hex())
}
}

logs, _, err := a.logFetcher.GetLogsByFilters(ctx, crit, 0)
if err != nil {
return nil, err
Expand Down
61 changes: 61 additions & 0 deletions evmrpc/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,67 @@ func TestGetLogsBlockHashIsNotZero(t *testing.T) {
}
}

func TestFilterGetLogsBlockHashNotYetAvailable(t *testing.T) {
// Query for a block hash that corresponds to a block height (200)
// that is greater than the latest receipt version (103)
// This should return an error saying the block hash isn't available yet

filterCriteria := map[string]interface{}{
"blockHash": FutureBlockHash,
}
resObj := sendRequestGood(t, "getLogs", filterCriteria)

// Should return an error
errorObj, hasError := resObj["error"]
require.True(t, hasError, "Expected an error when querying for block hash with height > latest receipt version")

errorMap := errorObj.(map[string]interface{})
errorMessage := errorMap["message"].(string)
require.Contains(t, errorMessage, "isn't available yet", "Error message should indicate block hash isn't available yet")
}

func TestFilterGetLogsBlockRangeIncludesUnavailableBlock(t *testing.T) {
// Query for a block range where toBlock (200) is greater than the latest receipt version (103)
// This tests that querying a range with unavailable blocks doesn't cause issues
// and returns logs only for available blocks or returns an appropriate error

filterCriteria := map[string]interface{}{
"fromBlock": "0x64", // 100 in hex - this block exists
"toBlock": "0xc8", // 200 in hex - this block height > latest receipt version
}
resObj := sendRequestGood(t, "getLogs", filterCriteria)

// The behavior could be either:
// 1. Return an error indicating the range includes unavailable blocks
// 2. Return empty results (no logs found in the unavailable range)
// We check for both possibilities

errorObj, hasError := resObj["error"]
require.True(t, hasError, "Expected an error when querying for block range with unavailable block")
// If there's an error, it should mention the block range or unavailability
errorMap := errorObj.(map[string]interface{})
errorMessage := errorMap["message"].(string)
// The error could be about block range, system overload, or unavailability
require.Contains(t, errorMessage, "unavailable block(s)", "Error message should indicate block range includes unavailable block(s)")
}

func TestFilterGetLogsBlockRangePartiallyAvailable(t *testing.T) {
// Query for a block range that spans both available and unavailable blocks
// fromBlock: 100 (available), toBlock: 105 (should be available since it's < 200)

filterCriteria := map[string]interface{}{
"fromBlock": "0x64", // 100 in hex
"toBlock": "0x69", // 105 in hex - still within available range
}
resObj := sendRequestGood(t, "getLogs", filterCriteria)

// Success case - should return a valid array
result, ok := resObj["result"]
require.True(t, ok, "Result should exist")
_, isArray := result.([]interface{})
require.True(t, isArray, "Result should be an array")
}

func TestGetLogsTransactionIndexConsistency(t *testing.T) {
t.Parallel()

Expand Down
25 changes: 25 additions & 0 deletions evmrpc/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ const MockHeight2 = 2
const MockHeight103 = 103
const MockHeight101 = 101
const MockHeight100 = 100
const MockHeight200 = 200

var DebugTraceHashHex = "0x1234567890123456789023456789012345678901234567890123456789000004"
var DebugTraceBlockHash = "0xBE17E0261E539CB7E9A91E123A6D794E0163D656FCF9B8EAC07823F7ED28512B"
var DebugTracePanicBlockHash = "0x0000000000000000000000000000000000000000000000000000000000000003"
var MultiTxBlockHash = "0x0000000000000000000000000000000000000000000000000000000000000002"
var FutureBlockHash = "0x00000000000000000000000000000000000000000000000000000000000000C8"

var TestCosmosTxHash = "690D39ADF56D4C811B766DFCD729A415C36C4BFFE80D63E305373B9518EBFB14"
var TestEvmTxHash = "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e"
Expand Down Expand Up @@ -333,9 +335,22 @@ func (c *MockClient) BlockByHash(_ context.Context, hash bytes.HexBytes) (*coret
if hash.String() == MultiTxBlockHash[2:] {
return c.mockBlock(MockHeight2), nil
}
if hash.String() == FutureBlockHash[2:] {
return c.mockBlock(MockHeight200), nil
}
return c.mockBlock(MockHeight8), nil
}

func (c *MockClient) HeaderByHash(_ context.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) {
block, err := c.BlockByHash(context.Background(), hash)
if err != nil {
return nil, err
}
return &coretypes.ResultHeader{
Header: &block.Block.Header,
}, nil
}

func (c *MockClient) BlockResults(_ context.Context, height *int64) (*coretypes.ResultBlockResults, error) {
if *height == GenesisBlockHeight {
return &coretypes.ResultBlockResults{
Expand Down Expand Up @@ -1042,6 +1057,16 @@ func setupLogs() {
EffectiveGasPrice: 100,
})

// write mock receipt for height 199
CtxHeight199 := Ctx.WithBlockHeight(199)
EVMKeeper.MockReceipt(CtxHeight199, common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901999"), &types.Receipt{
BlockNumber: 199,
TransactionIndex: 0,
TxHashHex: "0x1234567890123456789012345678901234567890123456789012345678901999",
GasUsed: 21000,
EffectiveGasPrice: 100,
})

// block 2
EVMKeeper.SetBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3})
EVMKeeper.SetEvmOnlyBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3})
Expand Down
3 changes: 3 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ github.com/cloudflare/cloudflare-go v0.114.0 h1:ucoti4/7Exo0XQ+rzpn1H+IfVVe++zgi
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
Expand All @@ -413,6 +414,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbp
github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI=
github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/creachadair/command v0.0.0-20220426235536-a748effdf6a1/go.mod h1:bAM+qFQb/KwWyCc9MLC4U1jvn3XyakqP5QRkds5T6cY=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c h1:/ovYnF02fwL0kvspmy9AuyKg1JhdTRUgPw4nUxd9oZM=
github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8=
Expand Down Expand Up @@ -662,6 +664,7 @@ github.com/neilotoole/errgroup v0.1.5 h1:DxEGoIfFm5ooGicidR+okiHjoOaGRKFaSxDPVZu
github.com/oklog/oklog v0.3.2 h1:wVfs8F+in6nTBMkA7CbRw+zZMIB7nNM825cM1wuzoTk=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=
Expand Down
4 changes: 4 additions & 0 deletions x/evm/keeper/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ func (k *Keeper) DeleteTransientReceipt(ctx sdk.Context, txHash common.Hash, txI
store.Delete(types.NewTransientReceiptKey(txIndex, txHash))
}

func (k *Keeper) GetLatestReceiptVersion(ctx sdk.Context) (int64, error) {
return k.receiptStore.GetLatestVersion()
}

// GetReceipt returns a data structure that stores EVM specific transaction metadata.
// Many EVM applications (e.g. MetaMask) relies on being on able to query receipt
// by EVM transaction hash (not Sei transaction hash) to function properly.
Expand Down
14 changes: 14 additions & 0 deletions x/evm/keeper/receipt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func TestGetReceiptWithRetry(t *testing.T) {
func TestFlushTransientReceiptsSync(t *testing.T) {
k := &testkeeper.EVMTestApp.EvmKeeper
ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{})
ctx = ctx.WithBlockHeight(10)
txHash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
receipt := &types.Receipt{TxHashHex: txHash.Hex(), Status: 1}

Expand All @@ -72,6 +73,10 @@ func TestFlushTransientReceiptsSync(t *testing.T) {
err = k.FlushTransientReceiptsSync(ctx)
require.NoError(t, err)

version, err := k.GetLatestReceiptVersion(ctx)
require.NoError(t, err)
require.Equal(t, int64(10), version)

// Now should be retrievable from persistent store
pr, err := k.GetReceipt(ctx, txHash)
require.NoError(t, err)
Expand All @@ -81,9 +86,18 @@ func TestFlushTransientReceiptsSync(t *testing.T) {
_, _ = k.GetTransientReceipt(ctx, txHash, 0)
// Could be not found or still present depending on flush logic, so we don't assert error here

ctx = ctx.WithBlockHeight(11)
version, err = k.GetLatestReceiptVersion(ctx)
require.NoError(t, err)
require.Equal(t, int64(10), version) // should still be 10 because we haven't flushed yet

// Flushing with no receipts should not error
err = k.FlushTransientReceiptsSync(ctx)
require.NoError(t, err)

version, err = k.GetLatestReceiptVersion(ctx)
require.NoError(t, err)
require.Equal(t, int64(11), version) // now should be 11 because we flushed
}

func TestDeleteTransientReceipt(t *testing.T) {
Expand Down
Loading