forked from maticnetwork/bor
/
bor_filter.go
150 lines (127 loc) · 4.88 KB
/
bor_filter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2014 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package filters
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rpc"
)
// BorBlockLogsFilter can be used to retrieve and filter logs.
type BorBlockLogsFilter struct {
backend Backend
sprint uint64
db ethdb.Database
addresses []common.Address
topics [][]common.Hash
block common.Hash // Block hash if filtering a single block
begin, end int64 // Range interval if filtering multiple blocks
}
// NewBorBlockLogsRangeFilter creates a new filter which uses a bloom filter on blocks to
// figure out whether a particular block is interesting or not.
func NewBorBlockLogsRangeFilter(backend Backend, sprint uint64, begin, end int64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
// Create a generic filter and convert it into a range filter
filter := newBorBlockLogsFilter(backend, sprint, addresses, topics)
filter.begin = begin
filter.end = end
return filter
}
// NewBorBlockLogsFilter creates a new filter which directly inspects the contents of
// a block to figure out whether it is interesting or not.
func NewBorBlockLogsFilter(backend Backend, sprint uint64, block common.Hash, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
// Create a generic filter and convert it into a block filter
filter := newBorBlockLogsFilter(backend, sprint, addresses, topics)
filter.block = block
return filter
}
// newBorBlockLogsFilter creates a generic filter that can either filter based on a block hash,
// or based on range queries. The search criteria needs to be explicitly set.
func newBorBlockLogsFilter(backend Backend, sprint uint64, addresses []common.Address, topics [][]common.Hash) *BorBlockLogsFilter {
return &BorBlockLogsFilter{
backend: backend,
sprint: sprint,
addresses: addresses,
topics: topics,
db: backend.ChainDb(),
}
}
// Logs searches the blockchain for matching log entries, returning all from the
// first block that contains matches, updating the start of the filter accordingly.
func (f *BorBlockLogsFilter) Logs(ctx context.Context) ([]*types.Log, error) {
// If we're doing singleton block filtering, execute and return
if f.block != (common.Hash{}) {
receipt, _ := f.backend.GetBorBlockReceipt(ctx, f.block)
if receipt == nil {
return nil, nil
}
return f.borBlockLogs(ctx, receipt)
}
// Figure out the limits of the filter range
header, _ := f.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber)
if header == nil {
return nil, nil
}
head := header.Number.Uint64()
if f.begin == -1 {
f.begin = int64(head)
}
// adjust begin for sprint
f.begin = currentSprintEnd(f.sprint, f.begin)
end := f.end
if f.end == -1 {
end = int64(head)
}
// Gather all indexed logs, and finish with non indexed ones
return f.unindexedLogs(ctx, uint64(end))
}
// unindexedLogs returns the logs matching the filter criteria based on raw block
// iteration and bloom matching.
func (f *BorBlockLogsFilter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
var logs []*types.Log
for ; f.begin <= int64(end); f.begin = f.begin + int64(f.sprint) {
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin))
if header == nil || err != nil {
return logs, err
}
// get bor block receipt
receipt, err := f.backend.GetBorBlockReceipt(ctx, header.Hash())
if receipt == nil || err != nil {
continue
}
// filter bor block logs
found, err := f.borBlockLogs(ctx, receipt)
if err != nil {
return logs, err
}
logs = append(logs, found...)
}
return logs, nil
}
// borBlockLogs returns the logs matching the filter criteria within a single block.
func (f *BorBlockLogsFilter) borBlockLogs(ctx context.Context, receipt *types.Receipt) (logs []*types.Log, err error) {
if bloomFilter(receipt.Bloom, f.addresses, f.topics) {
logs = filterLogs(receipt.Logs, nil, nil, f.addresses, f.topics)
}
return logs, nil
}
func currentSprintEnd(sprint uint64, n int64) int64 {
m := n % int64(sprint)
if m == 0 {
return n
}
return n + int64(sprint) - m
}