Skip to content

Commit d4fc8cd

Browse files
committed
add availability checks to getLogs
1 parent 5a15103 commit d4fc8cd

File tree

6 files changed

+127
-0
lines changed

6 files changed

+127
-0
lines changed

evmrpc/filter.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,11 @@ func (a *FilterAPI) GetLogs(ctx context.Context, crit filters.FilterCriteria) (r
516516
defer recordMetricsWithError(fmt.Sprintf("%s_getLogs", a.namespace), a.connectionType, time.Now(), err)
517517
// Calculate block range
518518
latest := a.logFetcher.ctxProvider(LatestCtxHeight).BlockHeight()
519+
// get block number from hash and compare to latest
520+
latestReceiptVersion, err := a.logFetcher.k.GetLatestReceiptVersion(a.logFetcher.ctxProvider(LatestCtxHeight))
521+
if err != nil {
522+
return nil, err
523+
}
519524
begin, end := latest, latest
520525
if crit.FromBlock != nil {
521526
begin = getHeightFromBigIntBlockNumber(latest, crit.FromBlock)
@@ -526,6 +531,18 @@ func (a *FilterAPI) GetLogs(ctx context.Context, crit filters.FilterCriteria) (r
526531
begin = end
527532
}
528533
}
534+
if begin > latestReceiptVersion || end > latestReceiptVersion {
535+
return nil, fmt.Errorf("block range includes unavailable block(s)")
536+
}
537+
if crit.BlockHash != nil {
538+
header, err := a.tmClient.HeaderByHash(ctx, crit.BlockHash[:])
539+
if err != nil {
540+
return nil, err
541+
}
542+
if header.Header.Height > latestReceiptVersion {
543+
return nil, fmt.Errorf("block hash %s isn't available yet", crit.BlockHash.Hex())
544+
}
545+
}
529546

530547
blockRange := end - begin + 1
531548

evmrpc/filter_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,70 @@ func TestGetLogsBlockHashIsNotZero(t *testing.T) {
446446
}
447447
}
448448

449+
func TestFilterGetLogsBlockHashNotYetAvailable(t *testing.T) {
450+
t.Parallel()
451+
// Query for a block hash that corresponds to a block height (200)
452+
// that is greater than the latest receipt version (103)
453+
// This should return an error saying the block hash isn't available yet
454+
455+
filterCriteria := map[string]interface{}{
456+
"blockHash": FutureBlockHash,
457+
}
458+
resObj := sendRequestGood(t, "getLogs", filterCriteria)
459+
460+
// Should return an error
461+
errorObj, hasError := resObj["error"]
462+
require.True(t, hasError, "Expected an error when querying for block hash with height > latest receipt version")
463+
464+
errorMap := errorObj.(map[string]interface{})
465+
errorMessage := errorMap["message"].(string)
466+
require.Contains(t, errorMessage, "isn't available yet", "Error message should indicate block hash isn't available yet")
467+
}
468+
469+
func TestFilterGetLogsBlockRangeIncludesUnavailableBlock(t *testing.T) {
470+
t.Parallel()
471+
// Query for a block range where toBlock (200) is greater than the latest receipt version (103)
472+
// This tests that querying a range with unavailable blocks doesn't cause issues
473+
// and returns logs only for available blocks or returns an appropriate error
474+
475+
filterCriteria := map[string]interface{}{
476+
"fromBlock": "0x64", // 100 in hex - this block exists
477+
"toBlock": "0xc8", // 200 in hex - this block height > latest receipt version
478+
}
479+
resObj := sendRequestGood(t, "getLogs", filterCriteria)
480+
481+
// The behavior could be either:
482+
// 1. Return an error indicating the range includes unavailable blocks
483+
// 2. Return empty results (no logs found in the unavailable range)
484+
// We check for both possibilities
485+
486+
errorObj, hasError := resObj["error"]
487+
require.True(t, hasError, "Expected an error when querying for block range with unavailable block")
488+
// If there's an error, it should mention the block range or unavailability
489+
errorMap := errorObj.(map[string]interface{})
490+
errorMessage := errorMap["message"].(string)
491+
// The error could be about block range, system overload, or unavailability
492+
require.Contains(t, errorMessage, "unavailable block(s)", "Error message should indicate block range includes unavailable block(s)")
493+
}
494+
495+
func TestFilterGetLogsBlockRangePartiallyAvailable(t *testing.T) {
496+
t.Parallel()
497+
// Query for a block range that spans both available and unavailable blocks
498+
// fromBlock: 100 (available), toBlock: 105 (should be available since it's < 200)
499+
500+
filterCriteria := map[string]interface{}{
501+
"fromBlock": "0x64", // 100 in hex
502+
"toBlock": "0x69", // 105 in hex - still within available range
503+
}
504+
resObj := sendRequestGood(t, "getLogs", filterCriteria)
505+
506+
// Success case - should return a valid array
507+
result, ok := resObj["result"]
508+
require.True(t, ok, "Result should exist")
509+
_, isArray := result.([]interface{})
510+
require.True(t, isArray, "Result should be an array")
511+
}
512+
449513
func TestGetLogsTransactionIndexConsistency(t *testing.T) {
450514
t.Parallel()
451515

evmrpc/setup_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,13 @@ const MockHeight2 = 2
5555
const MockHeight103 = 103
5656
const MockHeight101 = 101
5757
const MockHeight100 = 100
58+
const MockHeight200 = 200
5859

5960
var DebugTraceHashHex = "0x1234567890123456789023456789012345678901234567890123456789000004"
6061
var DebugTraceBlockHash = "0xBE17E0261E539CB7E9A91E123A6D794E0163D656FCF9B8EAC07823F7ED28512B"
6162
var DebugTracePanicBlockHash = "0x0000000000000000000000000000000000000000000000000000000000000003"
6263
var MultiTxBlockHash = "0x0000000000000000000000000000000000000000000000000000000000000002"
64+
var FutureBlockHash = "0x00000000000000000000000000000000000000000000000000000000000000C8"
6365

6466
var TestCosmosTxHash = "690D39ADF56D4C811B766DFCD729A415C36C4BFFE80D63E305373B9518EBFB14"
6567
var TestEvmTxHash = "0xf02362077ac075a397344172496b28e913ce5294879d811bb0269b3be20a872e"
@@ -333,9 +335,22 @@ func (c *MockClient) BlockByHash(_ context.Context, hash bytes.HexBytes) (*coret
333335
if hash.String() == MultiTxBlockHash[2:] {
334336
return c.mockBlock(MockHeight2), nil
335337
}
338+
if hash.String() == FutureBlockHash[2:] {
339+
return c.mockBlock(MockHeight200), nil
340+
}
336341
return c.mockBlock(MockHeight8), nil
337342
}
338343

344+
func (c *MockClient) HeaderByHash(_ context.Context, hash bytes.HexBytes) (*coretypes.ResultHeader, error) {
345+
block, err := c.BlockByHash(context.Background(), hash)
346+
if err != nil {
347+
return nil, err
348+
}
349+
return &coretypes.ResultHeader{
350+
Header: &block.Block.Header,
351+
}, nil
352+
}
353+
339354
func (c *MockClient) BlockResults(_ context.Context, height *int64) (*coretypes.ResultBlockResults, error) {
340355
if *height == GenesisBlockHeight {
341356
return &coretypes.ResultBlockResults{
@@ -1042,6 +1057,16 @@ func setupLogs() {
10421057
EffectiveGasPrice: 100,
10431058
})
10441059

1060+
// write mock receipt for height 199
1061+
CtxHeight199 := Ctx.WithBlockHeight(199)
1062+
EVMKeeper.MockReceipt(CtxHeight199, common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901999"), &types.Receipt{
1063+
BlockNumber: 199,
1064+
TransactionIndex: 0,
1065+
TxHashHex: "0x1234567890123456789012345678901234567890123456789012345678901999",
1066+
GasUsed: 21000,
1067+
EffectiveGasPrice: 100,
1068+
})
1069+
10451070
// block 2
10461071
EVMKeeper.SetBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3})
10471072
EVMKeeper.SetEvmOnlyBlockBloom(MultiTxCtx, []ethtypes.Bloom{bloom1, bloom2, bloom3})

go.work.sum

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ github.com/cloudflare/cloudflare-go v0.114.0 h1:ucoti4/7Exo0XQ+rzpn1H+IfVVe++zgi
401401
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
402402
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
403403
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
404+
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
404405
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
405406
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
406407
github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s=
@@ -413,6 +414,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbp
413414
github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI=
414415
github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
415416
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
417+
github.com/creachadair/command v0.0.0-20220426235536-a748effdf6a1/go.mod h1:bAM+qFQb/KwWyCc9MLC4U1jvn3XyakqP5QRkds5T6cY=
416418
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
417419
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c h1:/ovYnF02fwL0kvspmy9AuyKg1JhdTRUgPw4nUxd9oZM=
418420
github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8=
@@ -662,6 +664,7 @@ github.com/neilotoole/errgroup v0.1.5 h1:DxEGoIfFm5ooGicidR+okiHjoOaGRKFaSxDPVZu
662664
github.com/oklog/oklog v0.3.2 h1:wVfs8F+in6nTBMkA7CbRw+zZMIB7nNM825cM1wuzoTk=
663665
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
664666
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
667+
github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=
665668
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
666669
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU=
667670
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=

x/evm/keeper/receipt.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ func (k *Keeper) DeleteTransientReceipt(ctx sdk.Context, txHash common.Hash, txI
5454
store.Delete(types.NewTransientReceiptKey(txIndex, txHash))
5555
}
5656

57+
func (k *Keeper) GetLatestReceiptVersion(ctx sdk.Context) (int64, error) {
58+
return k.receiptStore.GetLatestVersion()
59+
}
60+
5761
// GetReceipt returns a data structure that stores EVM specific transaction metadata.
5862
// Many EVM applications (e.g. MetaMask) relies on being on able to query receipt
5963
// by EVM transaction hash (not Sei transaction hash) to function properly.

x/evm/keeper/receipt_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func TestGetReceiptWithRetry(t *testing.T) {
5252
func TestFlushTransientReceiptsSync(t *testing.T) {
5353
k := &testkeeper.EVMTestApp.EvmKeeper
5454
ctx := testkeeper.EVMTestApp.GetContextForDeliverTx([]byte{})
55+
ctx = ctx.WithBlockHeight(10)
5556
txHash := common.HexToHash("0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
5657
receipt := &types.Receipt{TxHashHex: txHash.Hex(), Status: 1}
5758

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

76+
version, err := k.GetLatestReceiptVersion(ctx)
77+
require.NoError(t, err)
78+
require.Equal(t, int64(10), version)
79+
7580
// Now should be retrievable from persistent store
7681
pr, err := k.GetReceipt(ctx, txHash)
7782
require.NoError(t, err)
@@ -81,9 +86,18 @@ func TestFlushTransientReceiptsSync(t *testing.T) {
8186
_, _ = k.GetTransientReceipt(ctx, txHash, 0)
8287
// Could be not found or still present depending on flush logic, so we don't assert error here
8388

89+
ctx = ctx.WithBlockHeight(11)
90+
version, err = k.GetLatestReceiptVersion(ctx)
91+
require.NoError(t, err)
92+
require.Equal(t, int64(10), version) // should still be 10 because we haven't flushed yet
93+
8494
// Flushing with no receipts should not error
8595
err = k.FlushTransientReceiptsSync(ctx)
8696
require.NoError(t, err)
97+
98+
version, err = k.GetLatestReceiptVersion(ctx)
99+
require.NoError(t, err)
100+
require.Equal(t, int64(11), version) // now should be 11 because we flushed
87101
}
88102

89103
func TestDeleteTransientReceipt(t *testing.T) {

0 commit comments

Comments
 (0)