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 <martin@swende.se>
This commit is contained in:
parent
9cddfe92a3
commit
df2b3cd2bd
@ -844,11 +844,28 @@ func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db }
|
|||||||
|
|
||||||
func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
|
func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
|
||||||
|
|
||||||
func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
|
func (fb *filterBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
|
||||||
if block == rpc.LatestBlockNumber {
|
switch number {
|
||||||
|
case rpc.PendingBlockNumber:
|
||||||
|
if block := fb.backend.pendingBlock; block != nil {
|
||||||
|
return block.Header(), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
case rpc.LatestBlockNumber:
|
||||||
return fb.bc.CurrentHeader(), nil
|
return fb.bc.CurrentHeader(), nil
|
||||||
|
case rpc.FinalizedBlockNumber:
|
||||||
|
if block := fb.bc.CurrentFinalizedBlock(); block != nil {
|
||||||
|
return block.Header(), nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("finalized block not found")
|
||||||
|
case rpc.SafeBlockNumber:
|
||||||
|
if block := fb.bc.CurrentSafeBlock(); block != nil {
|
||||||
|
return block.Header(), nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("safe block not found")
|
||||||
|
default:
|
||||||
|
return fb.bc.GetHeaderByNumber(uint64(number.Int64())), nil
|
||||||
}
|
}
|
||||||
return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
||||||
|
@ -119,20 +119,44 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
head = header.Number.Uint64()
|
err error
|
||||||
end = uint64(f.end)
|
head = header.Number.Int64()
|
||||||
pending = f.end == rpc.PendingBlockNumber.Int64()
|
pending = f.end == rpc.PendingBlockNumber.Int64()
|
||||||
)
|
)
|
||||||
if f.begin == rpc.LatestBlockNumber.Int64() {
|
resolveSpecial := func(number int64) (int64, error) {
|
||||||
f.begin = int64(head)
|
var hdr *types.Header
|
||||||
|
switch number {
|
||||||
|
case rpc.LatestBlockNumber.Int64():
|
||||||
|
return head, nil
|
||||||
|
case rpc.PendingBlockNumber.Int64():
|
||||||
|
// we should return head here since we've already captured
|
||||||
|
// that we need to get the pending logs in the pending boolean above
|
||||||
|
return head, nil
|
||||||
|
case rpc.FinalizedBlockNumber.Int64():
|
||||||
|
hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
|
||||||
|
if hdr == nil {
|
||||||
|
return 0, errors.New("finalized header not found")
|
||||||
|
}
|
||||||
|
case rpc.SafeBlockNumber.Int64():
|
||||||
|
hdr, _ = f.sys.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber)
|
||||||
|
if hdr == nil {
|
||||||
|
return 0, errors.New("safe header not found")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return number, nil
|
||||||
|
}
|
||||||
|
return hdr.Number.Int64(), nil
|
||||||
}
|
}
|
||||||
if f.end == rpc.LatestBlockNumber.Int64() || f.end == rpc.PendingBlockNumber.Int64() {
|
if f.begin, err = resolveSpecial(f.begin); err != nil {
|
||||||
end = head
|
return nil, err
|
||||||
|
}
|
||||||
|
if f.end, err = resolveSpecial(f.end); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
// 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
|
||||||
err error
|
end = uint64(f.end)
|
||||||
size, sections = f.sys.backend.BloomStatus()
|
size, sections = f.sys.backend.BloomStatus()
|
||||||
)
|
)
|
||||||
if indexed := sections * size; indexed > uint64(f.begin) {
|
if indexed := sections * size; indexed > uint64(f.begin) {
|
||||||
|
@ -18,6 +18,7 @@ package filters
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@ -58,14 +59,24 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumbe
|
|||||||
hash common.Hash
|
hash common.Hash
|
||||||
num uint64
|
num uint64
|
||||||
)
|
)
|
||||||
if blockNr == rpc.LatestBlockNumber {
|
switch blockNr {
|
||||||
|
case rpc.LatestBlockNumber:
|
||||||
hash = rawdb.ReadHeadBlockHash(b.db)
|
hash = rawdb.ReadHeadBlockHash(b.db)
|
||||||
number := rawdb.ReadHeaderNumber(b.db, hash)
|
number := rawdb.ReadHeaderNumber(b.db, hash)
|
||||||
if number == nil {
|
if number == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
num = *number
|
num = *number
|
||||||
} else {
|
case rpc.FinalizedBlockNumber:
|
||||||
|
hash = rawdb.ReadFinalizedBlockHash(b.db)
|
||||||
|
number := rawdb.ReadHeaderNumber(b.db, hash)
|
||||||
|
if number == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
num = *number
|
||||||
|
case rpc.SafeBlockNumber:
|
||||||
|
return nil, errors.New("safe block not found")
|
||||||
|
default:
|
||||||
num = uint64(blockNr)
|
num = uint64(blockNr)
|
||||||
hash = rawdb.ReadCanonicalHash(b.db, num)
|
hash = rawdb.ReadCanonicalHash(b.db, num)
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ package filters
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -170,58 +171,66 @@ func TestFilters(t *testing.T) {
|
|||||||
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
|
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
|
// Set block 998 as Finalized (-3)
|
||||||
|
rawdb.WriteFinalizedBlockHash(db, chain[998].Hash())
|
||||||
|
|
||||||
|
filter := sys.NewRangeFilter(0, -1, []common.Address{addr}, [][]common.Hash{{hash1, hash2, hash3, hash4}})
|
||||||
logs, _ := filter.Logs(context.Background())
|
logs, _ := filter.Logs(context.Background())
|
||||||
if len(logs) != 4 {
|
if len(logs) != 4 {
|
||||||
t.Error("expected 4 log, got", len(logs))
|
t.Error("expected 4 log, got", len(logs))
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}})
|
for i, tc := range []struct {
|
||||||
logs, _ = filter.Logs(context.Background())
|
f *Filter
|
||||||
if len(logs) != 1 {
|
wantHashes []common.Hash
|
||||||
t.Error("expected 1 log, got", len(logs))
|
}{
|
||||||
}
|
{
|
||||||
if len(logs) > 0 && logs[0].Topics[0] != hash3 {
|
sys.NewRangeFilter(900, 999, []common.Address{addr}, [][]common.Hash{{hash3}}),
|
||||||
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
[]common.Hash{hash3},
|
||||||
}
|
}, {
|
||||||
|
sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}}),
|
||||||
filter = sys.NewRangeFilter(990, -1, []common.Address{addr}, [][]common.Hash{{hash3}})
|
[]common.Hash{hash3},
|
||||||
logs, _ = filter.Logs(context.Background())
|
}, {
|
||||||
if len(logs) != 1 {
|
sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}}),
|
||||||
t.Error("expected 1 log, got", len(logs))
|
[]common.Hash{hash1, hash2},
|
||||||
}
|
}, {
|
||||||
if len(logs) > 0 && logs[0].Topics[0] != hash3 {
|
sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}}),
|
||||||
t.Errorf("expected log[0].Topics[0] to be %x, got %x", hash3, logs[0].Topics[0])
|
nil,
|
||||||
}
|
}, {
|
||||||
|
sys.NewRangeFilter(0, -1, []common.Address{common.BytesToAddress([]byte("failmenow"))}, nil),
|
||||||
filter = sys.NewRangeFilter(1, 10, nil, [][]common.Hash{{hash1, hash2}})
|
nil,
|
||||||
|
}, {
|
||||||
logs, _ = filter.Logs(context.Background())
|
sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{common.BytesToHash([]byte("fail"))}, {hash1}}),
|
||||||
if len(logs) != 2 {
|
nil,
|
||||||
t.Error("expected 2 log, got", len(logs))
|
}, {
|
||||||
}
|
sys.NewRangeFilter(-1, -1, nil, nil), []common.Hash{hash4},
|
||||||
|
}, {
|
||||||
failHash := common.BytesToHash([]byte("fail"))
|
sys.NewRangeFilter(-3, -1, nil, nil), []common.Hash{hash3, hash4},
|
||||||
filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}})
|
}, {
|
||||||
|
sys.NewRangeFilter(-3, -3, nil, nil), []common.Hash{hash3},
|
||||||
logs, _ = filter.Logs(context.Background())
|
}, {
|
||||||
if len(logs) != 0 {
|
sys.NewRangeFilter(-1, -3, nil, nil), nil,
|
||||||
t.Error("expected 0 log, got", len(logs))
|
}, {
|
||||||
}
|
sys.NewRangeFilter(-4, -1, nil, nil), nil,
|
||||||
|
}, {
|
||||||
failAddr := common.BytesToAddress([]byte("failmenow"))
|
sys.NewRangeFilter(-4, -4, nil, nil), nil,
|
||||||
filter = sys.NewRangeFilter(0, -1, []common.Address{failAddr}, nil)
|
}, {
|
||||||
|
sys.NewRangeFilter(-1, -4, nil, nil), nil,
|
||||||
logs, _ = filter.Logs(context.Background())
|
},
|
||||||
if len(logs) != 0 {
|
} {
|
||||||
t.Error("expected 0 log, got", len(logs))
|
logs, _ := tc.f.Logs(context.Background())
|
||||||
}
|
var haveHashes []common.Hash
|
||||||
|
for _, l := range logs {
|
||||||
filter = sys.NewRangeFilter(0, -1, nil, [][]common.Hash{{failHash}, {hash1}})
|
haveHashes = append(haveHashes, l.Topics[0])
|
||||||
|
}
|
||||||
logs, _ = filter.Logs(context.Background())
|
if have, want := len(haveHashes), len(tc.wantHashes); have != want {
|
||||||
if len(logs) != 0 {
|
t.Fatalf("test %d, have %d logs, want %d", i, have, want)
|
||||||
t.Error("expected 0 log, got", len(logs))
|
}
|
||||||
|
if len(haveHashes) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(tc.wantHashes, haveHashes) {
|
||||||
|
t.Fatalf("test %d, have %v want %v", i, haveHashes, tc.wantHashes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user