eth/filters: add global block logs cache (#25459)

This adds a cache for block logs which is shared by all filters. The cache
size of is configurable using the `--cache.blocklogs` flag.

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
Sina Mahmoodi
2022-08-19 11:14:59 +02:00
committed by GitHub
co-authored by Felix Lange
parent 77308cd6fc
commit 36874b63a1
21 changed files with 310 additions and 200 deletions
+32 -7
View File
@@ -450,12 +450,36 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs)
}
func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) {
receipt, err := t.getReceipt(ctx)
if err != nil || receipt == nil {
if _, err := t.resolve(ctx); err != nil {
return nil, err
}
ret := make([]*Log, 0, len(receipt.Logs))
for _, log := range receipt.Logs {
if t.block == nil {
return nil, nil
}
if _, ok := t.block.numberOrHash.Hash(); !ok {
header, err := t.r.backend.HeaderByNumberOrHash(ctx, *t.block.numberOrHash)
if err != nil {
return nil, err
}
hash := header.Hash()
t.block.numberOrHash.BlockHash = &hash
}
return t.getLogs(ctx)
}
// getLogs returns log objects for the given tx.
// Assumes block hash is resolved.
func (t *Transaction) getLogs(ctx context.Context) (*[]*Log, error) {
var (
hash, _ = t.block.numberOrHash.Hash()
filter = t.r.filterSystem.NewBlockFilter(hash, nil, nil)
logs, err = filter.Logs(ctx)
)
if err != nil {
return nil, err
}
ret := make([]*Log, 0, len(logs))
for _, log := range logs {
ret = append(ret, &Log{
r: t.r,
transaction: t,
@@ -978,7 +1002,7 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri
hash = header.Hash()
}
// Construct the range filter
filter := filters.NewBlockFilter(b.r.backend, hash, addresses, topics)
filter := b.r.filterSystem.NewBlockFilter(hash, addresses, topics)
// Run the filter and return all the logs
return runFilter(ctx, b.r, filter)
@@ -1137,7 +1161,8 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct {
// Resolver is the top-level object in the GraphQL hierarchy.
type Resolver struct {
backend ethapi.Backend
backend ethapi.Backend
filterSystem *filters.FilterSystem
}
func (r *Resolver) Block(ctx context.Context, args struct {
@@ -1284,7 +1309,7 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria
topics = *args.Filter.Topics
}
// Construct the range filter
filter := filters.NewRangeFilter(r.backend, begin, end, addresses, topics)
filter := r.filterSystem.NewRangeFilter(begin, end, addresses, topics)
return runFilter(ctx, r, filter)
}
+6 -3
View File
@@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
@@ -50,7 +51,7 @@ func TestBuildSchema(t *testing.T) {
}
defer stack.Close()
// Make sure the schema can be parsed and matched up to the object model.
if err := newHandler(stack, nil, []string{}, []string{}); err != nil {
if err := newHandler(stack, nil, nil, []string{}, []string{}); err != nil {
t.Errorf("Could not construct GraphQL handler: %v", err)
}
}
@@ -263,7 +264,8 @@ func createGQLService(t *testing.T, stack *node.Node) {
t.Fatalf("could not create import blocks: %v", err)
}
// create gql service
err = New(stack, ethBackend.APIBackend, []string{}, []string{})
filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{})
err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{})
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
@@ -348,7 +350,8 @@ func createGQLServiceWithTransactions(t *testing.T, stack *node.Node) {
t.Fatalf("could not create import blocks: %v", err)
}
// create gql service
err = New(stack, ethBackend.APIBackend, []string{}, []string{})
filterSystem := filters.NewFilterSystem(ethBackend.APIBackend, filters.Config{})
err = New(stack, ethBackend.APIBackend, filterSystem, []string{}, []string{})
if err != nil {
t.Fatalf("could not create graphql service: %v", err)
}
+5 -4
View File
@@ -20,6 +20,7 @@ import (
"encoding/json"
"net/http"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/node"
"github.com/graph-gophers/graphql-go"
@@ -55,14 +56,14 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
// New constructs a new GraphQL service instance.
func New(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error {
return newHandler(stack, backend, cors, vhosts)
func New(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error {
return newHandler(stack, backend, filterSystem, cors, vhosts)
}
// newHandler returns a new `http.Handler` that will answer GraphQL queries.
// It additionally exports an interactive query browser on the / endpoint.
func newHandler(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error {
q := Resolver{backend}
func newHandler(stack *node.Node, backend ethapi.Backend, filterSystem *filters.FilterSystem, cors, vhosts []string) error {
q := Resolver{backend, filterSystem}
s, err := graphql.ParseSchema(schema, &q)
if err != nil {