Skip to content

Commit df2b3cd

Browse files
eth/filters: fix for eth_getLogs failing with finalized- and safe tag (#25922)
Prior to this change, f.begin (and possibly end) stay negative, leading to strange results later in the code. With this change, filters using "safe" and "finalized" block produce results consistent w/ the overall behavior of this RPC method. Co-authored-by: Martin Holst Swende <[email protected]>
1 parent 9cddfe9 commit df2b3cd

File tree

4 files changed

+120
-59
lines changed

4 files changed

+120
-59
lines changed

accounts/abi/bind/backends/simulated.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -844,11 +844,28 @@ func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db }
844844

845845
func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
846846

847-
func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
848-
if block == rpc.LatestBlockNumber {
847+
func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
848+
switch number {
849+
case rpc.PendingBlockNumber:
850+
if block := fb.backend.pendingBlock; block != nil {
851+
return block.Header(), nil
852+
}
853+
return nil, nil
854+
case rpc.LatestBlockNumber:
849855
return fb.bc.CurrentHeader(), nil
856+
case rpc.FinalizedBlockNumber:
857+
if block := fb.bc.CurrentFinalizedBlock(); block != nil {
858+
return block.Header(), nil
859+
}
860+
return nil, errors.New("finalized block not found")
861+
case rpc.SafeBlockNumber:
862+
if block := fb.bc.CurrentSafeBlock(); block != nil {
863+
return block.Header(), nil
864+
}
865+
return nil, errors.New("safe block not found")
866+
default:
867+
return fb.bc.GetHeaderByNumber(uint64(number.Int64())), nil
850868
}
851-
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
852869
}
853870

854871
func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {

eth/filters/filter.go

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,20 +119,44 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
119119
return nil, nil
120120
}
121121
var (
122-
head = header.Number.Uint64()
123-
end = uint64(f.end)
122+
err error
123+
head = header.Number.Int64()
124124
pending = f.end == rpc.PendingBlockNumber.Int64()
125125
)
126-
if f.begin == rpc.LatestBlockNumber.Int64() {
127-
f.begin = int64(head)
126+
resolveSpecial := func(number int64) (int64, error) {
127+
var hdr *types.Header
128+
switch number {
129+
case rpc.LatestBlockNumber.Int64():
130+
return head, nil
131+
case rpc.PendingBlockNumber.Int64():
132+
// we should return head here since we've already captured
133+
// that we need to get the pending logs in the pending boolean above
134+
return head, nil
135+
case rpc.FinalizedBlockNumber.Int64():
136+
hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
137+
if hdr == nil {
138+
return 0, errors.New("finalized header not found")
139+
}
140+
case rpc.SafeBlockNumber.Int64():
141+
hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber)
142+
if hdr == nil {
143+
return 0, errors.New("safe header not found")
144+
}
145+
default:
146+
return number, nil
147+
}
148+
return hdr.Number.Int64(), nil
128149
}
129-
if f.end == rpc.LatestBlockNumber.Int64() || f.end == rpc.PendingBlockNumber.Int64() {
130-
end = head
150+
if f.begin, err = resolveSpecial(f.begin); err != nil {
151+
return nil, err
152+
}
153+
if f.end, err = resolveSpecial(f.end); err != nil {
154+
return nil, err
131155
}
132156
// Gather all indexed logs, and finish with non indexed ones
133157
var (
134158
logs []*types.Log
135-
err error
159+
end = uint64(f.end)
136160
size, sections = f.sys.backend.BloomStatus()
137161
)
138162
if indexed := sections * size; indexed > uint64(f.begin) {

eth/filters/filter_system_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package filters
1818

1919
import (
2020
"context"
21+
"errors"
2122
"fmt"
2223
"math/big"
2324
"math/rand"
@@ -58,14 +59,24 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumbe
5859
hash common.Hash
5960
num uint64
6061
)
61-
if blockNr == rpc.LatestBlockNumber {
62+
switch blockNr {
63+
case rpc.LatestBlockNumber:
6264
hash = rawdb.ReadHeadBlockHash(b.db)
6365
number := rawdb.ReadHeaderNumber(b.db, hash)
6466
if number == nil {
6567
return nil, nil
6668
}
6769
num = *number
68-
} else {
70+
case rpc.FinalizedBlockNumber:
71+
hash = rawdb.ReadFinalizedBlockHash(b.db)
72+
number := rawdb.ReadHeaderNumber(b.db, hash)
73+
if number == nil {
74+
return nil, nil
75+
}
76+
num = *number
77+
case rpc.SafeBlockNumber:
78+
return nil, errors.New("safe block not found")
79+
default:
6980
num = uint64(blockNr)
7081
hash = rawdb.ReadCanonicalHash(b.db, num)
7182
}

eth/filters/filter_test.go

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package filters
1919
import (
2020
"context"
2121
"math/big"
22+
"reflect"
2223
"testing"
2324

2425
"github.com/ethereum/go-ethereum/common"
@@ -170,58 +171,66 @@ func TestFilters(t *testing.T) {
170171
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
171172
}
172173

173-
filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
174+
// Set block 998 as Finalized (-3)
175+
rawdb.WriteFinalizedBlockHash(db, chain[998].Hash())
174176

177+
filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
175178
logs, _ := filter.Logs(context.Background())
176179
if len(logs) != 4 {
177180
t.Error("expected 4 log, got", len(logs))
178181
}
179182

180-
filter = sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
181-
logs, _ = filter.Logs(context.Background())
182-
if len(logs) != 1 {
183-
t.Error("expected 1 log, got", len(logs))
184-
}
185-
if len(logs) > 0 && logs[0].Topics[0] != hash3 {
186-
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
187-
}
188-
189-
filter = sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
190-
logs, _ = filter.Logs(context.Background())
191-
if len(logs) != 1 {
192-
t.Error("expected 1 log, got", len(logs))
193-
}
194-
if len(logs) > 0 && logs[0].Topics[0] != hash3 {
195-
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
196-
}
197-
198-
filter = sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}})
199-
200-
logs, _ = filter.Logs(context.Background())
201-
if len(logs) != 2 {
202-
t.Error("expected 2 log, got", len(logs))
203-
}
204-
205-
failHash := common.BytesToHash([]byte("fail"))
206-
filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}})
207-
208-
logs, _ = filter.Logs(context.Background())
209-
if len(logs) != 0 {
210-
t.Error("expected 0 log, got", len(logs))
211-
}
212-
213-
failAddr := common.BytesToAddress([]byte("failmenow"))
214-
filter = sys.NewRangeFilter(0, -1, []common.Address{failAddr}, nil)
215-
216-
logs, _ = filter.Logs(context.Background())
217-
if len(logs) != 0 {
218-
t.Error("expected 0 log, got", len(logs))
219-
}
220-
221-
filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
222-
223-
logs, _ = filter.Logs(context.Background())
224-
if len(logs) != 0 {
225-
t.Error("expected 0 log, got", len(logs))
183+
for i, tc := range []struct {
184+
f *Filter
185+
wantHashes []common.Hash
186+
}{
187+
{
188+
sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}),
189+
[]common.Hash{hash3},
190+
}, {
191+
sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}),
192+
[]common.Hash{hash3},
193+
}, {
194+
sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}),
195+
[]common.Hash{hash1, hash2},
196+
}, {
197+
sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}),
198+
nil,
199+
}, {
200+
sys.NewRangeFilter(0, -1, []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil),
201+
nil,
202+
}, {
203+
sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}),
204+
nil,
205+
}, {
206+
sys.NewRangeFilter(-1, -1, nil, nil), []common.Hash{hash4},
207+
}, {
208+
sys.NewRangeFilter(-3, -1, nil, nil), []common.Hash{hash3, hash4},
209+
}, {
210+
sys.NewRangeFilter(-3, -3, nil, nil), []common.Hash{hash3},
211+
}, {
212+
sys.NewRangeFilter(-1, -3, nil, nil), nil,
213+
}, {
214+
sys.NewRangeFilter(-4, -1, nil, nil), nil,
215+
}, {
216+
sys.NewRangeFilter(-4, -4, nil, nil), nil,
217+
}, {
218+
sys.NewRangeFilter(-1, -4, nil, nil), nil,
219+
},
220+
} {
221+
logs, _ := tc.f.Logs(context.Background())
222+
var haveHashes []common.Hash
223+
for _, l := range logs {
224+
haveHashes = append(haveHashes, l.Topics[0])
225+
}
226+
if have, want := len(haveHashes), len(tc.wantHashes); have != want {
227+
t.Fatalf("test %d, have %d logs, want %d", i, have, want)
228+
}
229+
if len(haveHashes) == 0 {
230+
continue
231+
}
232+
if !reflect.DeepEqual(tc.wantHashes, haveHashes) {
233+
t.Fatalf("test %d, have %v want %v", i, haveHashes, tc.wantHashes)
234+
}
226235
}
227236
}

0 commit comments

Comments
 (0)