Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kondon #112

Open
wants to merge 75 commits into
base: r/handler
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
d7a10ec
merkle: document proofs for odd sized trees (#48)
ryandotsmith Aug 22, 2022
6274b8e
api,www: add endpoint for fetching a root from a given proof (#47)
worm-emoji Aug 22, 2022
34e0965
api: add `inserted_at` to trees table (#49)
worm-emoji Aug 22, 2022
f0c3736
www: make collab logos 12% smaller (#54)
worm-emoji Aug 25, 2022
d3e9f91
api: add a log for each request (#52)
worm-emoji Aug 25, 2022
122579b
api: fix error checking bug in IP code (#55)
worm-emoji Aug 25, 2022
140f3c3
misc: rename lanyard.build -> lanyard.org (#53)
worm-emoji Aug 26, 2022
2eb972a
www: brand update (#56)
malonehedges Aug 29, 2022
b23545d
www: update meta images (#57)
malonehedges Aug 29, 2022
0c1066d
api: make trees.packed not null (#60)
ryandotsmith Aug 30, 2022
76c9695
docs: remove null reference (#61)
worm-emoji Aug 30, 2022
4aa5c30
lanyard/client: add Golang API client for lanyard (#58)
worm-emoji Aug 30, 2022
32be597
client: add go.mod (#63)
worm-emoji Aug 30, 2022
a201d7d
client: remove client-specific go.mod (#65)
worm-emoji Aug 31, 2022
52ff3a8
client: add GetProofFromAddr function (#64)
worm-emoji Aug 31, 2022
d16ac8c
api: fix proof/root query to be more specific (#67)
worm-emoji Sep 1, 2022
535d3fd
www: add ens support (#62)
malonehedges Sep 1, 2022
d7d3789
api/fly: configure health checks (#68)
worm-emoji Sep 3, 2022
cf005c6
api: don't log requests to health endpoint (#70)
worm-emoji Sep 7, 2022
e40286f
api: don't log errors for 404s (#69)
worm-emoji Sep 7, 2022
1d2bf82
api: don't cache 404 responses (#71)
worm-emoji Sep 12, 2022
e383cd0
pgx: set a minimum connection count (#73)
worm-emoji Sep 12, 2022
210716b
example: misc fixes (#77)
malonehedges Sep 14, 2022
6f33646
api: fix root query to be correctly specific (#75)
worm-emoji Sep 14, 2022
68fbad5
api/main: remove pgx minconn (#76)
worm-emoji Sep 14, 2022
3298d38
api,client,www: add roots endpoint, deprecate root endpoint (#78)
worm-emoji Sep 19, 2022
d48e6d7
api: allow any origin for CORS (#79)
worm-emoji Sep 23, 2022
013c72c
api: cache responses (#74)
malonehedges Sep 26, 2022
a9e5ae2
api: update root endpoint to have correct query func (#80)
worm-emoji Sep 26, 2022
c4a1a62
api: accept uneven length hex strings (#81)
worm-emoji Oct 4, 2022
af265d9
api: generate proofs in parallel (#82)
ryandotsmith Oct 7, 2022
0665b47
api: generate index of proofs async (#83)
worm-emoji Oct 7, 2022
7fb7470
api: return early if tree is already in db (#84)
worm-emoji Oct 7, 2022
de6f156
clients: add npm package (#85)
worm-emoji Oct 10, 2022
901e6c6
lanyard/npm: allow for fetching proof by address (#86)
worm-emoji Oct 10, 2022
21ee773
example: update to use npm package (#87)
worm-emoji Oct 10, 2022
f7556a0
lanyard npm: handle missing responses better (#88)
worm-emoji Oct 10, 2022
a9403da
lanyard npm: update readme, bump version (#89)
worm-emoji Oct 10, 2022
5de6c53
www: add links to npm and go packages to docs (#91)
worm-emoji Oct 19, 2022
df4cde2
www: fix url to go client (#92)
worm-emoji Oct 19, 2022
2ef799e
go client: expose Leaf2Addr convenience function (#93)
worm-emoji Nov 17, 2022
2624004
go client: bump version in user agent (#94)
worm-emoji Nov 17, 2022
cbb8940
misc: update caniusedb
worm-emoji Feb 15, 2023
e738a96
www: change contact to Twitter DM (#95)
malonehedges Apr 19, 2023
b3b5d73
new deploy scheme
worm-emoji Apr 24, 2023
24fdf2d
with -> env
worm-emoji Apr 24, 2023
6a1f0c9
add checkout step
worm-emoji Apr 24, 2023
1920020
add install ruby step
worm-emoji Apr 24, 2023
764f255
fix ruby step
worm-emoji Apr 24, 2023
4ca17b9
lower instance size
worm-emoji Apr 24, 2023
f738ab2
don't use fancy size instance
worm-emoji Apr 24, 2023
fe4214f
use fqdn
worm-emoji Apr 24, 2023
46c2875
deploy api when config changes
worm-emoji Apr 24, 2023
670a600
use ip
worm-emoji Apr 24, 2023
c192f9c
use specific ts version with ssh
worm-emoji Apr 24, 2023
dcf8f6a
fix deploy ssh step
worm-emoji Apr 24, 2023
80d5458
fix deploy ssh step
worm-emoji Apr 24, 2023
ebb9cd3
add temp sleep step
worm-emoji Apr 24, 2023
09a7161
remove sleep
worm-emoji Apr 24, 2023
fc31983
reorder / bump build
malonehedges May 2, 2023
7a6f264
copyTrees: use for update skip locked to avoid deadlocks (#97)
worm-emoji Jun 14, 2023
6af5137
leaf2Addr: add support for address when it's in the last position
worm-emoji Jun 14, 2023
63acbae
copyTrees: add timeouts and order to sync function (#98)
worm-emoji Jun 22, 2023
f4f9d5e
start importing migrate from its own repo (#99)
worm-emoji Jun 23, 2023
82f3158
remove unneeded deploy + binary files (#100)
worm-emoji Jun 26, 2023
da76b8e
fix: simplify data model, proofs_hashes table (#101)
worm-emoji Jun 27, 2023
262e346
config: add additional host to deploy script (#102)
worm-emoji Jun 27, 2023
616c92f
cleanup: drop trees_proofs table + proofs columns (#103)
worm-emoji Jun 27, 2023
5f28063
trees: lower cache control from one hour to 5 seconds (#104)
worm-emoji Jun 27, 2023
8b608fc
add profiling runtime flag, improve merkle performance (#105)
worm-emoji Jun 27, 2023
04b06f2
build(deps): bump golang.org/x/text from 0.3.7 to 0.3.8 (#106)
dependabot[bot] Jun 27, 2023
9b9efe8
Update codeSnippets.ts (#108)
okwme Jul 6, 2023
7b0e5c2
proof: add lru cache for trees (#109)
worm-emoji Jul 14, 2023
6009f77
tree: longer ttl (#110)
worm-emoji Jul 21, 2023
52e2f64
www: merkle root lookup (#111)
malonehedges Jul 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions .github/workflows/deploy-al-prod.yml

This file was deleted.

34 changes: 34 additions & 0 deletions .github/workflows/integration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: tests

on:
push:
branches: [main]
paths:
- "cmd/api/**"
- "api/**"
- ".github/**"
- "**.go"
pull_request:
paths:
- "clients/**"

jobs:
build:
name: integration
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.19"
- uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: test
run: go test ./... --tags=integration
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ on: [pull_request]

jobs:
build:
name: all
name: packages
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: '1.19'
go-version: "1.19"
- uses: actions/cache@v3
with:
path: |
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
tmp/
.env
*.pprof
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM golang:1.20-alpine AS build
WORKDIR /go/src/app
ENV CGO_ENABLED=0

RUN apk --no-cache add ca-certificates

COPY go.mod go.sum ./
RUN go mod download

COPY . .
ARG GIT_SHA
RUN cd cmd/api && go build -ldflags="-X 'main.GitSHA=$GIT_SHA'" main.go && mv main /go/bin/app

FROM scratch
COPY --from=build /go/bin/app /app
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/app"]
EXPOSE 8080
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

Create an allow list in seconds that works across web3

[lanyard.build](https://lanyard.build)
[lanyard.org](https://lanyard.org)
107 changes: 87 additions & 20 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ package api
import (
"encoding/json"
"fmt"
"net"
"net/http"
"os"
"strings"
"time"

"github.com/contextwtf/lanyard/api/tracing"
"github.com/ethereum/go-ethereum/common"

lru "github.com/hashicorp/golang-lru/v2"
"github.com/jackc/pgx/v4/pgxpool"
"github.com/rs/cors"
"github.com/rs/zerolog"
Expand All @@ -17,46 +22,93 @@ import (
)

type Server struct {
db *pgxpool.Pool
db *pgxpool.Pool
tlru *lru.Cache[common.Hash, cachedTree]
}

func New(db *pgxpool.Pool) *Server {
l, err := lru.New[common.Hash, cachedTree](1000)
if err != nil {
log.Fatal().Err(err).Msg("failed to create lru cache")
}
return &Server{
db: db,
db: db,
tlru: l,
}
}

func (s *Server) Handler(env, gitSha string) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/api/v1/tree", s.TreeHandler)
mux.HandleFunc("/api/v1/proof", s.GetProof)
mux.HandleFunc("/api/v1/root", s.GetRoot)
mux.HandleFunc("/api/v1/roots", s.GetRoot)
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, gitSha)
})

h := http.Handler(mux)
h = versionHandler(h, gitSha)
h = tracingHandler(os.Getenv("DD_ENV"), os.Getenv("DD_SERVICE"), gitSha, h)
h = hlog.NewHandler(log.Logger)(h)
h = hlog.UserAgentHandler("user_agent")(h)
h = hlog.RefererHandler("referer")(h)
h = hlog.RequestIDHandler("req_id", "Request-Id")(h)
h = hlog.URLHandler("path")(h)
h = hlog.RequestHandler("req")(h)
h = hlog.MethodHandler("method")(h)
h = tracingHandler(os.Getenv("DD_ENV"), os.Getenv("DD_SERVICE"), gitSha, h)
h = RemoteAddrHandler("ip")(h)
h = hlog.NewHandler(log.Logger)(h) // needs to be last for log values to correctly be passed to context

if env == "production" {
return h
}

c := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:3000"},
AllowCredentials: true,
AllowedOrigins: []string{"*"},
AllowCredentials: false,
OptionsPassthrough: false,
})

h = c.Handler(h)

return h
}

func ipFromRequest(r *http.Request) string {
if r.Header.Get("fastly-client-ip") != "" {
return r.Header.Get("fastly-client-ip")
}

if r.Header.Get("x-forwarded-for") != "" {
group := strings.Split(r.Header.Get("x-forwarded-for"), ", ")
if len(group) > 0 {
return group[len(group)-1]
}
}

host, _, err := net.SplitHostPort(r.RemoteAddr)
if err == nil {
return host
}

return ""
}

func RemoteAddrHandler(fieldKey string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := ipFromRequest(r)
if ip != "" {
log := zerolog.Ctx(r.Context())
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("ip", ip)
})
}

next.ServeHTTP(w, r.WithContext(r.Context()))
})
}
}

func versionHandler(h http.Handler, sha string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("server-version", sha)
Expand All @@ -66,30 +118,40 @@ func versionHandler(h http.Handler, sha string) http.Handler {

func tracingHandler(env, service, sha string, h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/health" {
h.ServeHTTP(w, r)
return
}

span, ctx := tracing.SpanFromContext(r.Context(), "http.request")

defer span.Finish()
log := zerolog.Ctx(ctx)

log := zerolog.Ctx(r.Context())
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Uint64("dd.trace_id", span.Context().TraceID())
})
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("dd.service", service)
})
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("dd.env", env)
})
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Str("dd.version", sha)
})
if env != "" {
log.UpdateContext(func(c zerolog.Context) zerolog.Context {
return c.Uint64("dd.trace_id", span.Context().TraceID()).
Str("dd.service", service).
Str("dd.env", env).
Str("dd.version", sha)
})
}

span.SetTag(ext.ResourceName, r.URL.Path)
span.SetTag(ext.SpanType, ext.SpanTypeWeb)
span.SetTag(ext.HTTPMethod, r.Method)

sc := &statusCapture{ResponseWriter: w}

requestStart := time.Now()
h.ServeHTTP(sc, r.WithContext(ctx))

// log every request
log.Info().
Int("status", sc.status).
Dur("duration", time.Since(requestStart)).
Msg("")

span.SetTag(ext.HTTPCode, sc.status)
})
}
Expand Down Expand Up @@ -127,6 +189,11 @@ func (s *Server) sendJSONError(
customMessage string,
) {
w.Header().Set("Content-Type", "application/json")
if code == http.StatusNotFound && w.Header().Get("Cache-Control") == "" {
w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
}

// all headers need to be set before this line
w.WriteHeader(code)

if err != nil {
Expand Down
74 changes: 73 additions & 1 deletion api/migrations/migrations.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package migrations

import "github.com/contextwtf/lanyard/migrate"
import "github.com/contextwtf/migrate"

var Migrations = []migrate.Migration{
{
Expand Down Expand Up @@ -61,4 +61,76 @@ var Migrations = []migrate.Migration{
ALTER TABLE merkle_trees RENAME TO trees;
`,
},
{
Name: "2022-08-22.0.add-proof-idx.sql",
SQL: `
CREATE INDEX on trees USING gin(proofs jsonb_path_ops);
`,
},
{
Name: "2022-08-22.1.add-inserted-at.sql",
SQL: `
ALTER TABLE trees
ADD COLUMN "inserted_at" timestamptz NOT NULL DEFAULT now();
`,
},
{
Name: "2022-08-30.0.packed-bool.sql",
SQL: `
UPDATE trees SET packed = true
WHERE packed IS NULL;

ALTER TABLE trees
ALTER COLUMN packed
SET NOT NULL;
`,
},
{
Name: "2022-08-31.0.root-func-index.sql",
SQL: `
CREATE OR REPLACE FUNCTION proofs_array (data jsonb)
RETURNS text[]
AS $CODE$
BEGIN
RETURN ARRAY (
SELECT
jsonb_array_elements(data) ->> 'proof');
END
$CODE$
LANGUAGE plpgsql
IMMUTABLE;

CREATE INDEX proofs_arr_idx ON trees USING GIN ((proofs_array(proofs)));
DROP INDEX "trees_proofs_idx";
`,
},
{
Name: "2022-10-07.0.trees-proofs.sql",
SQL: `
DROP INDEX proofs_arr_idx;
CREATE TABLE trees_proofs (
root bytea PRIMARY KEY,
proofs jsonb,
inserted_at timestamp with time zone NOT NULL DEFAULT now()
);
CREATE INDEX proofs_arr_idx ON trees_proofs USING GIN ((proofs_array(proofs)));
`,
},
{
Name: "2023-06-26.0.proofs_hashes.sql",
SQL: `
CREATE TABLE IF NOT EXISTS proofs_hashes (
hash bytea,
root bytea
);
CREATE INDEX IF NOT EXISTS proofs_hashes_hash_idx ON proofs_hashes (hash);
`,
},
{
Name: "2023-06-26.1.drop_data.sql",
SQL: `
ALTER TABLE "trees" DROP COLUMN "proofs";
DROP TABLE "trees_proofs";
`,
},
}
Loading