mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 02:42:27 +00:00
eth/filters: support reverse ordered logs
This commit is contained in:
parent
27e3f96819
commit
b068f9d491
3 changed files with 79 additions and 24 deletions
|
|
@ -163,6 +163,12 @@ func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uin
|
||||||
}
|
}
|
||||||
sink := m.run(begin, end, cap(results), session)
|
sink := m.run(begin, end, cap(results), session)
|
||||||
|
|
||||||
|
start := begin
|
||||||
|
stop := end
|
||||||
|
if start > stop {
|
||||||
|
start, stop = stop, start
|
||||||
|
}
|
||||||
|
|
||||||
// Read the output from the result sink and deliver to the user
|
// Read the output from the result sink and deliver to the user
|
||||||
session.pend.Add(1)
|
session.pend.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -183,13 +189,14 @@ func (m *Matcher) Start(ctx context.Context, begin, end uint64, results chan uin
|
||||||
sectionStart := res.section * m.sectionSize
|
sectionStart := res.section * m.sectionSize
|
||||||
|
|
||||||
first := sectionStart
|
first := sectionStart
|
||||||
if begin > first {
|
if start > first {
|
||||||
first = begin
|
first = start
|
||||||
}
|
}
|
||||||
last := sectionStart + m.sectionSize - 1
|
last := sectionStart + m.sectionSize - 1
|
||||||
if end < last {
|
if stop < last {
|
||||||
last = end
|
last = stop
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all the blocks in the section and return the matching ones
|
// Iterate over all the blocks in the section and return the matching ones
|
||||||
for i := first; i <= last; i++ {
|
for i := first; i <= last; i++ {
|
||||||
// Skip the entire byte if no matches are found inside (and we're processing an entire byte!)
|
// Skip the entire byte if no matches are found inside (and we're processing an entire byte!)
|
||||||
|
|
@ -231,13 +238,24 @@ func (m *Matcher) run(begin, end uint64, buffer int, session *MatcherSession) ch
|
||||||
defer session.pend.Done()
|
defer session.pend.Done()
|
||||||
defer close(source)
|
defer close(source)
|
||||||
|
|
||||||
for i := begin / m.sectionSize; i <= end/m.sectionSize; i++ {
|
inc := int64(1)
|
||||||
|
if begin > end {
|
||||||
|
inc = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
i := int64(begin / m.sectionSize)
|
||||||
|
for ; i != int64(end/m.sectionSize); i += inc {
|
||||||
select {
|
select {
|
||||||
case <-session.quit:
|
case <-session.quit:
|
||||||
return
|
return
|
||||||
case source <- &partialMatches{i, bytes.Repeat([]byte{0xff}, int(m.sectionSize/8))}:
|
case source <- &partialMatches{uint64(i), bytes.Repeat([]byte{0xff}, int(m.sectionSize/8))}:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
select {
|
||||||
|
case <-session.quit:
|
||||||
|
return
|
||||||
|
case source <- &partialMatches{uint64(i), bytes.Repeat([]byte{0xff}, int(m.sectionSize/8))}:
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
// Assemble the daisy-chained filtering pipeline
|
// Assemble the daisy-chained filtering pipeline
|
||||||
next := source
|
next := source
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,9 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
|
||||||
}
|
}
|
||||||
head := header.Number.Uint64()
|
head := header.Number.Uint64()
|
||||||
|
|
||||||
|
begin := uint64(f.begin)
|
||||||
if f.begin == -1 {
|
if f.begin == -1 {
|
||||||
f.begin = int64(head)
|
begin = head
|
||||||
}
|
}
|
||||||
end := uint64(f.end)
|
end := uint64(f.end)
|
||||||
if f.end == -1 {
|
if f.end == -1 {
|
||||||
|
|
@ -145,31 +146,57 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
|
||||||
// Gather all indexed logs, and finish with non indexed ones
|
// Gather all indexed logs, and finish with non indexed ones
|
||||||
var (
|
var (
|
||||||
logs []*types.Log
|
logs []*types.Log
|
||||||
|
rest []*types.Log
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
size, sections := f.backend.BloomStatus()
|
size, sections := f.backend.BloomStatus()
|
||||||
if indexed := sections * size; indexed > uint64(f.begin) {
|
|
||||||
if indexed > end {
|
indexed := sections * size
|
||||||
logs, err = f.indexedLogs(ctx, end)
|
if begin > end {
|
||||||
} else {
|
rest, err = f.unindexedLogs(ctx, begin, indexed)
|
||||||
logs, err = f.indexedLogs(ctx, indexed-1)
|
if err != nil {
|
||||||
|
return rest, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if indexed > begin || indexed > end {
|
||||||
|
if indexed > begin && indexed > end {
|
||||||
|
logs, err = f.indexedLogs(ctx, begin, end)
|
||||||
|
} else if begin < end && end >= indexed {
|
||||||
|
logs, err = f.indexedLogs(ctx, begin, indexed-1)
|
||||||
|
} else if begin > end && begin >= indexed {
|
||||||
|
logs, err = f.indexedLogs(ctx, indexed-1, end)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if len(rest) > 0 {
|
||||||
|
logs = append(rest, logs...)
|
||||||
|
}
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rest, err := f.unindexedLogs(ctx, end)
|
|
||||||
logs = append(logs, rest...)
|
if end >= begin {
|
||||||
|
rest, err = f.unindexedLogs(ctx, uint64(f.begin), end)
|
||||||
|
logs = append(logs, rest...)
|
||||||
|
} else {
|
||||||
|
logs = append(rest, logs...)
|
||||||
|
}
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexedLogs returns the logs matching the filter criteria based on the bloom
|
// indexedLogs returns the logs matching the filter criteria based on the bloom
|
||||||
// bits indexed available locally or via the network.
|
// bits indexed available locally or via the network.
|
||||||
func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
|
func (f *Filter) indexedLogs(ctx context.Context, begin, end uint64) ([]*types.Log, error) {
|
||||||
// Create a matcher session and request servicing from the backend
|
// Create a matcher session and request servicing from the backend
|
||||||
matches := make(chan uint64, 64)
|
matches := make(chan uint64, 64)
|
||||||
|
|
||||||
session, err := f.matcher.Start(ctx, uint64(f.begin), end, matches)
|
start := int64(begin)
|
||||||
|
stop := int64(end)
|
||||||
|
inc := int64(1)
|
||||||
|
if start > stop {
|
||||||
|
inc = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
session, err := f.matcher.Start(ctx, uint64(start), uint64(stop), matches)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -187,11 +214,11 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err
|
||||||
if !ok {
|
if !ok {
|
||||||
err := session.Error()
|
err := session.Error()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f.begin = int64(end) + 1
|
f.begin = stop + inc
|
||||||
}
|
}
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
f.begin = int64(number) + 1
|
f.begin = int64(number) + inc
|
||||||
|
|
||||||
// Retrieve the suggested block and pull any truly matching logs
|
// Retrieve the suggested block and pull any truly matching logs
|
||||||
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(number))
|
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(number))
|
||||||
|
|
@ -212,11 +239,18 @@ func (f *Filter) indexedLogs(ctx context.Context, end uint64) ([]*types.Log, err
|
||||||
|
|
||||||
// indexedLogs returns the logs matching the filter criteria based on raw block
|
// indexedLogs returns the logs matching the filter criteria based on raw block
|
||||||
// iteration and bloom matching.
|
// iteration and bloom matching.
|
||||||
func (f *Filter) unindexedLogs(ctx context.Context, end uint64) ([]*types.Log, error) {
|
func (f *Filter) unindexedLogs(ctx context.Context, begin, end uint64) ([]*types.Log, error) {
|
||||||
var logs []*types.Log
|
var logs []*types.Log
|
||||||
|
|
||||||
for ; f.begin <= int64(end); f.begin++ {
|
start := int64(begin)
|
||||||
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(f.begin))
|
stop := int64(end)
|
||||||
|
inc := int64(1)
|
||||||
|
if start > stop {
|
||||||
|
inc = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; start != stop; start += inc {
|
||||||
|
header, err := f.backend.HeaderByNumber(ctx, rpc.BlockNumber(start))
|
||||||
if header == nil || err != nil {
|
if header == nil || err != nil {
|
||||||
return logs, err
|
return logs, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ func (es *EventSystem) subscribe(sub *subscription) *Subscription {
|
||||||
|
|
||||||
// SubscribeLogs creates a subscription that will write all logs matching the
|
// SubscribeLogs creates a subscription that will write all logs matching the
|
||||||
// given criteria to the given logs channel. Default value for the from and to
|
// given criteria to the given logs channel. Default value for the from and to
|
||||||
// block is "latest". If the fromBlock > toBlock an error is returned.
|
// block is "latest".
|
||||||
func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*types.Log) (*Subscription, error) {
|
func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*types.Log) (*Subscription, error) {
|
||||||
var from, to rpc.BlockNumber
|
var from, to rpc.BlockNumber
|
||||||
if crit.FromBlock == nil {
|
if crit.FromBlock == nil {
|
||||||
|
|
@ -217,7 +217,7 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
|
||||||
return es.subscribeLogs(crit, logs), nil
|
return es.subscribeLogs(crit, logs), nil
|
||||||
}
|
}
|
||||||
// only interested in mined logs within a specific block range
|
// only interested in mined logs within a specific block range
|
||||||
if from >= 0 && to >= 0 && to >= from {
|
if from >= 0 && to >= 0 {
|
||||||
return es.subscribeLogs(crit, logs), nil
|
return es.subscribeLogs(crit, logs), nil
|
||||||
}
|
}
|
||||||
// interested in mined logs from a specific block number, new logs and pending logs
|
// interested in mined logs from a specific block number, new logs and pending logs
|
||||||
|
|
@ -228,7 +228,10 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
|
||||||
if from >= 0 && to == rpc.LatestBlockNumber {
|
if from >= 0 && to == rpc.LatestBlockNumber {
|
||||||
return es.subscribeLogs(crit, logs), nil
|
return es.subscribeLogs(crit, logs), nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("invalid from and to block combination: from > to")
|
if to >= 0 && from == rpc.LatestBlockNumber {
|
||||||
|
return es.subscribeLogs(crit, logs), nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("invalid from and to block combination")
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribeMinedPendingLogs creates a subscription that returned mined and
|
// subscribeMinedPendingLogs creates a subscription that returned mined and
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue