Skip to content

Commit 907a082

Browse files
Darioush Jalaliceyonur
andauthored
eth/filters: move check for unfinalized queries (#1085)
* eth/filters: move check for unfinalized queries * eth/filters, eth/api: update rpc numbers in unfinalized query mode (#1086) * Align semantics of negative RPC numbers with upstream * nits (#1089) * nits * sort conditions * revert resolveSpecial changes --------- Co-authored-by: Ceyhun Onur <[email protected]> --------- Co-authored-by: Ceyhun Onur <[email protected]>
1 parent 2738329 commit 907a082

File tree

9 files changed

+128
-86
lines changed

9 files changed

+128
-86
lines changed

accounts/abi/bind/backends/simulated.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query interfaces.Filt
768768
to = query.ToBlock.Int64()
769769
}
770770
// Construct the range filter
771-
filter, _ = b.filterSystem.NewRangeFilter(from, to, query.Addresses, query.Topics)
771+
filter = b.filterSystem.NewRangeFilter(from, to, query.Addresses, query.Topics)
772772
}
773773
// Run the filter and return all the logs
774774
logs, err := filter.Logs(ctx)
@@ -911,7 +911,7 @@ func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
911911

912912
func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
913913
switch number {
914-
case rpc.PendingBlockNumber, rpc.AcceptedBlockNumber:
914+
case rpc.PendingBlockNumber, rpc.FinalizedBlockNumber:
915915
if block := fb.backend.acceptedBlock; block != nil {
916916
return block.Header(), nil
917917
}

eth/api.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,11 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
197197
}
198198
var header *types.Header
199199
if blockNr.IsAccepted() {
200-
header = api.eth.LastAcceptedBlock().Header()
200+
if api.eth.APIBackend.isLatestAndAllowed(blockNr) {
201+
header = api.eth.blockchain.CurrentHeader()
202+
} else {
203+
header = api.eth.LastAcceptedBlock().Header()
204+
}
201205
} else {
202206
block := api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
203207
if block == nil {
@@ -241,7 +245,11 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
241245
if number, ok := blockNrOrHash.Number(); ok {
242246
var header *types.Header
243247
if number.IsAccepted() {
244-
header = api.eth.LastAcceptedBlock().Header()
248+
if api.eth.APIBackend.isLatestAndAllowed(number) {
249+
header = api.eth.blockchain.CurrentHeader()
250+
} else {
251+
header = api.eth.LastAcceptedBlock().Header()
252+
}
245253
} else {
246254
block := api.eth.blockchain.GetBlockByNumber(uint64(number))
247255
if block == nil {

eth/api_backend.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
9292
// identically.
9393
acceptedBlock := b.eth.LastAcceptedBlock()
9494
if number.IsAccepted() {
95+
if b.isLatestAndAllowed(number) {
96+
return b.eth.blockchain.CurrentHeader(), nil
97+
}
9598
return acceptedBlock.Header(), nil
9699
}
97100

@@ -156,6 +159,10 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
156159
// identically.
157160
acceptedBlock := b.eth.LastAcceptedBlock()
158161
if number.IsAccepted() {
162+
if b.isLatestAndAllowed(number) {
163+
header := b.eth.blockchain.CurrentBlock()
164+
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
165+
}
159166
return acceptedBlock, nil
160167
}
161168

@@ -486,3 +493,7 @@ func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Blo
486493
func (b *EthAPIBackend) MinRequiredTip(ctx context.Context, header *types.Header) (*big.Int, error) {
487494
return dummy.MinRequiredTip(b.ChainConfig(), header)
488495
}
496+
497+
func (b *EthAPIBackend) isLatestAndAllowed(number rpc.BlockNumber) bool {
498+
return number.IsLatest() && b.IsAllowUnfinalizedQueries()
499+
}

eth/filters/api.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -439,11 +439,7 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type
439439
end = crit.ToBlock.Int64()
440440
}
441441
// Construct the range filter
442-
var err error
443-
filter, err = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics)
444-
if err != nil {
445-
return nil, err
446-
}
442+
filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics)
447443
}
448444
// Run the filter and return all the logs
449445
logs, err := filter.Logs(ctx)
@@ -497,11 +493,7 @@ func (api *FilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*types.Lo
497493
end = f.crit.ToBlock.Int64()
498494
}
499495
// Construct the range filter
500-
var err error
501-
filter, err = api.sys.NewRangeFilter(begin, end, f.crit.Addresses, f.crit.Topics)
502-
if err != nil {
503-
return nil, err
504-
}
496+
filter = api.sys.NewRangeFilter(begin, end, f.crit.Addresses, f.crit.Topics)
505497
}
506498
// Run the filter and return all the logs
507499
logs, err := filter.Logs(ctx)

eth/filters/bench_test.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import (
3838
"github.com/ethereum/go-ethereum/common"
3939
"github.com/ethereum/go-ethereum/common/bitutil"
4040
"github.com/ethereum/go-ethereum/ethdb"
41-
"github.com/stretchr/testify/require"
4241
)
4342

4443
func BenchmarkBloomBits512(b *testing.B) {
@@ -147,8 +146,7 @@ func benchmarkBloomBits(b *testing.B, sectionSize uint64) {
147146
var addr common.Address
148147
addr[0] = byte(i)
149148
addr[1] = byte(i / 256)
150-
filter, err := sys.NewRangeFilter(0, int64(cnt*sectionSize-1), []common.Address{addr}, nil)
151-
require.NoError(b, err)
149+
filter := sys.NewRangeFilter(0, int64(cnt*sectionSize-1), []common.Address{addr}, nil)
152150
if _, err := filter.Logs(context.Background()); err != nil {
153151
b.Error("filter.Logs error:", err)
154152
}
@@ -191,8 +189,7 @@ func BenchmarkNoBloomBits(b *testing.B) {
191189

192190
b.Log("Running filter benchmarks...")
193191
start := time.Now()
194-
filter, err := sys.NewRangeFilter(0, int64(*headNum), []common.Address{{}}, nil)
195-
require.NoError(b, err)
192+
filter := sys.NewRangeFilter(0, int64(*headNum), []common.Address{{}}, nil)
196193
filter.Logs(context.Background())
197194
d := time.Since(start)
198195
b.Log("Finished running filter benchmarks")

eth/filters/filter.go

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ type Filter struct {
5353

5454
// NewRangeFilter creates a new filter which uses a bloom filter on blocks to
5555
// figure out whether a particular block is interesting or not.
56-
func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Address, topics [][]common.Hash) (*Filter, error) {
57-
allowUnfinalizedQueries := sys.backend.IsAllowUnfinalizedQueries()
58-
acceptedBlock := sys.backend.LastAcceptedBlock()
59-
56+
func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter {
6057
// Flatten the address and topic filter clauses into a single bloombits filter
6158
// system. Since the bloombits are not positional, nil topics are permitted,
6259
// which get flattened into a nil byte slice.
@@ -77,24 +74,14 @@ func (sys *FilterSystem) NewRangeFilter(begin, end int64, addresses []common.Add
7774
}
7875
size, _ := sys.backend.BloomStatus()
7976

80-
if !allowUnfinalizedQueries && acceptedBlock != nil {
81-
lastAccepted := acceptedBlock.Number().Int64()
82-
if begin >= 0 && begin > lastAccepted {
83-
return nil, fmt.Errorf("requested from block %d after last accepted block %d", begin, lastAccepted)
84-
}
85-
if end >= 0 && end > lastAccepted {
86-
return nil, fmt.Errorf("requested to block %d after last accepted block %d", end, lastAccepted)
87-
}
88-
}
89-
9077
// Create a generic filter and convert it into a range filter
9178
filter := newFilter(sys, addresses, topics)
9279

9380
filter.matcher = bloombits.NewMatcher(size, filters)
9481
filter.begin = begin
9582
filter.end = end
9683

97-
return filter, nil
84+
return filter
9885
}
9986

10087
// NewBlockFilter creates a new filter which directly inspects the contents of
@@ -130,6 +117,21 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
130117
}
131118
return f.blockLogs(ctx, header)
132119
}
120+
121+
// Disallow blocks past the last accepted block if the backend does not
122+
// allow unfinalized queries.
123+
allowUnfinalizedQueries := f.sys.backend.IsAllowUnfinalizedQueries()
124+
acceptedBlock := f.sys.backend.LastAcceptedBlock()
125+
if !allowUnfinalizedQueries && acceptedBlock != nil {
126+
lastAccepted := acceptedBlock.Number().Int64()
127+
if f.begin >= 0 && f.begin > lastAccepted {
128+
return nil, fmt.Errorf("requested from block %d after last accepted block %d", f.begin, lastAccepted)
129+
}
130+
if f.end >= 0 && f.end > lastAccepted {
131+
return nil, fmt.Errorf("requested to block %d after last accepted block %d", f.end, lastAccepted)
132+
}
133+
}
134+
133135
// Short-cut if all we care about is pending logs
134136
if f.begin == rpc.PendingBlockNumber.Int64() {
135137
if f.end != rpc.PendingBlockNumber.Int64() {
@@ -149,14 +151,38 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
149151
return nil, nil
150152
}
151153
var (
152-
head = header.Number.Uint64()
153-
end = uint64(f.end)
154+
head = header.Number.Int64()
154155
)
155-
if f.begin < 0 {
156-
f.begin = int64(head)
156+
157+
resolveSpecial := func(number int64) (int64, error) {
158+
var hdr *types.Header
159+
switch number {
160+
case rpc.LatestBlockNumber.Int64():
161+
return head, nil
162+
case rpc.PendingBlockNumber.Int64():
163+
// we should return head here since we've already captured
164+
// that we need to get the pending logs in the pending boolean above
165+
return head, nil
166+
case rpc.FinalizedBlockNumber.Int64():
167+
hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
168+
if hdr == nil {
169+
return 0, errors.New("finalized header not found")
170+
}
171+
case rpc.SafeBlockNumber.Int64():
172+
hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber)
173+
if hdr == nil {
174+
return 0, errors.New("safe header not found")
175+
}
176+
default:
177+
return number, nil
178+
}
179+
return hdr.Number.Int64(), nil
157180
}
158-
if f.end < 0 {
159-
end = head
181+
if f.begin, err = resolveSpecial(f.begin); err != nil {
182+
return nil, err
183+
}
184+
if f.end, err = resolveSpecial(f.end); err != nil {
185+
return nil, err
160186
}
161187

162188
// When querying unfinalized data without a populated end block, it is
@@ -165,18 +191,19 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
165191
// We error in this case to prevent a bad UX where the caller thinks there
166192
// are no logs from the specified beginning to end (when in reality there may
167193
// be some).
168-
if end < uint64(f.begin) {
169-
return nil, fmt.Errorf("begin block %d is greater than end block %d", f.begin, end)
194+
if f.end < f.begin {
195+
return nil, fmt.Errorf("begin block %d is greater than end block %d", f.begin, f.end)
170196
}
171197

172198
// If the requested range of blocks exceeds the maximum number of blocks allowed by the backend
173199
// return an error instead of searching for the logs.
174-
if maxBlocks := f.sys.backend.GetMaxBlocksPerRequest(); int64(end)-f.begin >= maxBlocks && maxBlocks > 0 {
175-
return nil, fmt.Errorf("requested too many blocks from %d to %d, maximum is set to %d", f.begin, int64(end), maxBlocks)
200+
if maxBlocks := f.sys.backend.GetMaxBlocksPerRequest(); f.end-f.begin >= maxBlocks && maxBlocks > 0 {
201+
return nil, fmt.Errorf("requested too many blocks from %d to %d, maximum is set to %d", f.begin, f.end, maxBlocks)
176202
}
177203
// Gather all indexed logs, and finish with non indexed ones
178204
var (
179205
logs []*types.Log
206+
end = uint64(f.end)
180207
size, sections = f.sys.backend.BloomStatus()
181208
)
182209
if indexed := sections * size; indexed > uint64(f.begin) {

eth/filters/filter_system_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,26 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumbe
9595
num uint64
9696
)
9797
switch blockNr {
98-
case rpc.LatestBlockNumber, rpc.AcceptedBlockNumber:
98+
case rpc.FinalizedBlockNumber:
99+
var err error
100+
hash, err = rawdb.ReadAcceptorTip(b.db)
101+
if err != nil {
102+
return nil, err
103+
}
104+
number := rawdb.ReadHeaderNumber(b.db, hash)
105+
if number == nil {
106+
return nil, nil
107+
}
108+
num = *number
109+
case rpc.LatestBlockNumber, rpc.PendingBlockNumber:
99110
hash = rawdb.ReadHeadBlockHash(b.db)
100111
number := rawdb.ReadHeaderNumber(b.db, hash)
101112
if number == nil {
102113
return nil, nil
103114
}
104115
num = *number
116+
case rpc.SafeBlockNumber:
117+
return nil, errors.New("safe block not found")
105118
default:
106119
num = uint64(blockNr)
107120
hash = rawdb.ReadCanonicalHash(b.db, num)

eth/filters/filter_test.go

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ func BenchmarkFilters(b *testing.B) {
6363
addr4 = common.BytesToAddress([]byte("random addresses please"))
6464

6565
gspec = &core.Genesis{
66-
Config: params.TestChainConfig,
6766
Alloc: core.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
6867
BaseFee: big.NewInt(1),
68+
Config: params.TestChainConfig,
6969
}
7070
)
7171
defer db.Close()
@@ -94,6 +94,7 @@ func BenchmarkFilters(b *testing.B) {
9494
// and then import blocks. TODO(rjl493456442) try to get rid of the
9595
// manual database writes.
9696
gspec.MustCommit(db)
97+
9798
for i, block := range chain {
9899
rawdb.WriteBlock(db, block)
99100
rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
@@ -102,8 +103,7 @@ func BenchmarkFilters(b *testing.B) {
102103
}
103104
b.ResetTimer()
104105

105-
filter, err := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr1, addr2, addr3, addr4}, nil)
106-
require.NoError(b, err)
106+
filter := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr1, addr2, addr3, addr4}, nil)
107107

108108
for i := 0; i < b.N; i++ {
109109
filter.begin = 0
@@ -191,8 +191,12 @@ func TestFilters(t *testing.T) {
191191
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
192192
}
193193

194-
filter, err := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
194+
// Set block 998 as Finalized (-3)
195+
// rawdb.WriteFinalizedBlockHash(db, chain[998].Hash())
196+
err = rawdb.WriteAcceptorTip(db, chain[998].Hash())
195197
require.NoError(t, err)
198+
199+
filter := sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
196200
logs, _ := filter.Logs(context.Background())
197201
if len(logs) != 4 {
198202
t.Error("expected 4 log, got", len(logs))
@@ -203,46 +207,39 @@ func TestFilters(t *testing.T) {
203207
wantHashes []common.Hash
204208
}{
205209
{
206-
mustNewRangeFilter(t, sys, 900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}),
210+
sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}),
207211
[]common.Hash{hash3},
208212
}, {
209-
mustNewRangeFilter(t, sys, 990, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash3}}),
213+
sys.NewRangeFilter(990, int64(rpc.LatestBlockNumber), []common.Address{addr}, [][]common.Hash{{hash3}}),
210214
[]common.Hash{hash3},
211215
}, {
212-
mustNewRangeFilter(t, sys, 1, 10, nil, [][]common.Hash{{hash1, hash2}}),
216+
sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}),
213217
[]common.Hash{hash1, hash2},
214218
}, {
215-
mustNewRangeFilter(t, sys, 0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}),
219+
sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}),
216220
nil,
217221
}, {
218-
mustNewRangeFilter(t, sys, 0, int64(rpc.LatestBlockNumber), []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil),
222+
sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil),
219223
nil,
220224
}, {
221-
mustNewRangeFilter(t, sys, 0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}),
225+
sys.NewRangeFilter(0, int64(rpc.LatestBlockNumber), nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}),
222226
nil,
223227
}, {
224-
mustNewRangeFilter(t, sys, int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash4},
228+
sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash4},
225229
}, {
226-
// Note: modified from go-ethereum since we don't have FinalizedBlock
227-
mustNewRangeFilter(t, sys, int64(rpc.AcceptedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash4},
230+
sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash3, hash4},
228231
}, {
229-
// Note: modified from go-ethereum since we don't have FinalizedBlock
230-
mustNewRangeFilter(t, sys, int64(rpc.AcceptedBlockNumber), int64(rpc.AcceptedBlockNumber), nil, nil), []common.Hash{hash4},
232+
sys.NewRangeFilter(int64(rpc.FinalizedBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), []common.Hash{hash3},
231233
}, {
232-
// Note: modified from go-ethereum since we don't have FinalizedBlock
233-
mustNewRangeFilter(t, sys, int64(rpc.LatestBlockNumber), -3, nil, nil), []common.Hash{hash4},
234+
sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.FinalizedBlockNumber), nil, nil), nil,
234235
}, {
235-
// Note: modified from go-ethereum since we don't have SafeBlock
236-
mustNewRangeFilter(t, sys, int64(rpc.AcceptedBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), []common.Hash{hash4},
236+
sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.LatestBlockNumber), nil, nil), nil,
237237
}, {
238-
// Note: modified from go-ethereum since we don't have SafeBlock
239-
mustNewRangeFilter(t, sys, int64(rpc.AcceptedBlockNumber), int64(rpc.AcceptedBlockNumber), nil, nil), []common.Hash{hash4},
238+
sys.NewRangeFilter(int64(rpc.SafeBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), nil,
240239
}, {
241-
// Note: modified from go-ethereum since we don't have SafeBlock
242-
mustNewRangeFilter(t, sys, int64(rpc.LatestBlockNumber), int64(rpc.AcceptedBlockNumber), nil, nil), []common.Hash{hash4},
243-
},
244-
{
245-
mustNewRangeFilter(t, sys, int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), nil,
240+
sys.NewRangeFilter(int64(rpc.LatestBlockNumber), int64(rpc.SafeBlockNumber), nil, nil), nil,
241+
}, {
242+
sys.NewRangeFilter(int64(rpc.PendingBlockNumber), int64(rpc.PendingBlockNumber), nil, nil), nil,
246243
},
247244
} {
248245
logs, _ := tc.f.Logs(context.Background())
@@ -261,10 +258,3 @@ func TestFilters(t *testing.T) {
261258
}
262259
}
263260
}
264-
265-
func mustNewRangeFilter(t *testing.T, sys *FilterSystem, begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter {
266-
t.Helper()
267-
f, err := sys.NewRangeFilter(begin, end, addresses, topics)
268-
require.NoError(t, err)
269-
return f
270-
}

0 commit comments

Comments
 (0)