Skip to content

Commit 7b0e5c2

Browse files
authored
proof: add lru cache for trees (#109)
1 parent 9b9efe8 commit 7b0e5c2

File tree

4 files changed

+50
-11
lines changed

4 files changed

+50
-11
lines changed

api/api.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import (
1010
"time"
1111

1212
"github.com/contextwtf/lanyard/api/tracing"
13+
"github.com/ethereum/go-ethereum/common"
1314

15+
lru "github.com/hashicorp/golang-lru/v2"
1416
"github.com/jackc/pgx/v4/pgxpool"
1517
"github.com/rs/cors"
1618
"github.com/rs/zerolog"
@@ -20,12 +22,18 @@ import (
2022
)
2123

2224
type Server struct {
23-
db *pgxpool.Pool
25+
db *pgxpool.Pool
26+
tlru *lru.Cache[common.Hash, cachedTree]
2427
}
2528

2629
func New(db *pgxpool.Pool) *Server {
30+
l, err := lru.New[common.Hash, cachedTree](1000)
31+
if err != nil {
32+
log.Fatal().Err(err).Msg("failed to create lru cache")
33+
}
2734
return &Server{
28-
db: db,
35+
db: db,
36+
tlru: l,
2937
}
3038
}
3139

api/proof.go

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package api
22

33
import (
44
"bytes"
5+
"context"
56
"errors"
67
"net/http"
78

@@ -16,10 +17,41 @@ type getProofResp struct {
1617
Proof []hexutil.Bytes `json:"proof"`
1718
}
1819

20+
type cachedTree struct {
21+
r getTreeResp
22+
t merkle.Tree
23+
}
24+
25+
func (s *Server) getCachedTree(ctx context.Context, root common.Hash) (cachedTree, error) {
26+
r, ok := s.tlru.Get(root)
27+
if ok {
28+
return r, nil
29+
}
30+
31+
td, err := getTree(ctx, s.db, root.Bytes())
32+
if err != nil {
33+
return cachedTree{}, err
34+
}
35+
36+
leaves := [][]byte{}
37+
for _, l := range td.UnhashedLeaves {
38+
leaves = append(leaves, l[:])
39+
}
40+
41+
t := merkle.New(leaves)
42+
ct := cachedTree{
43+
r: td,
44+
t: t,
45+
}
46+
47+
s.tlru.Add(root, ct)
48+
return ct, nil
49+
}
50+
1951
func (s *Server) GetProof(w http.ResponseWriter, r *http.Request) {
2052
var (
2153
ctx = r.Context()
22-
root = common.FromHex(r.URL.Query().Get("root"))
54+
root = common.HexToHash(r.URL.Query().Get("root"))
2355
leaf = common.FromHex(r.URL.Query().Get("unhashedLeaf"))
2456
addr = common.FromHex(r.URL.Query().Get("address"))
2557
)
@@ -33,7 +65,7 @@ func (s *Server) GetProof(w http.ResponseWriter, r *http.Request) {
3365
return
3466
}
3567

36-
td, err := getTree(ctx, s.db, root)
68+
ct, err := s.getCachedTree(ctx, root)
3769
if errors.Is(err, pgx.ErrNoRows) {
3870
s.sendJSONError(r, w, nil, http.StatusNotFound, "tree not found")
3971
w.Header().Set("Cache-Control", "public, max-age=60")
@@ -44,22 +76,19 @@ func (s *Server) GetProof(w http.ResponseWriter, r *http.Request) {
4476
}
4577

4678
var (
47-
leaves [][]byte
4879
target []byte
4980
)
5081
// check if leaf is in tree and error if not
51-
for _, l := range td.UnhashedLeaves {
82+
for _, l := range ct.r.UnhashedLeaves {
5283
if len(target) == 0 {
5384
if len(leaf) > 0 {
5485
if bytes.Equal(l, leaf) {
5586
target = l
5687
}
57-
} else if bytes.Equal(leaf2Addr(l, td.Ltd, td.Packed), addr) {
88+
} else if bytes.Equal(leaf2Addr(l, ct.r.Ltd, ct.r.Packed), addr) {
5889
target = l
5990
}
6091
}
61-
62-
leaves = append(leaves, l)
6392
}
6493

6594
if len(target) == 0 {
@@ -68,8 +97,7 @@ func (s *Server) GetProof(w http.ResponseWriter, r *http.Request) {
6897
}
6998

7099
var (
71-
mt = merkle.New(leaves)
72-
p = mt.Proof(mt.Index(target))
100+
p = ct.t.Proof(ct.t.Index(target))
73101
phex = []hexutil.Bytes{}
74102
)
75103

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.19
55
require (
66
github.com/contextwtf/migrate v0.0.1
77
github.com/ethereum/go-ethereum v1.10.21
8+
github.com/hashicorp/golang-lru/v2 v2.0.4
89
github.com/jackc/pgx/v4 v4.16.1
910
github.com/lib/pq v1.10.9
1011
github.com/opentracing/opentracing-go v1.2.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA
311311
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
312312
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
313313
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
314+
github.com/hashicorp/golang-lru/v2 v2.0.4 h1:7GHuZcgid37q8o5i3QI9KMT4nCWQQ3Kx3Ov6bb9MfK0=
315+
github.com/hashicorp/golang-lru/v2 v2.0.4/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
314316
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
315317
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
316318
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=

0 commit comments

Comments
 (0)