Skip to content

Commit 71f7160

Browse files
noel2004lispcVelacielageorgehao
authored
[Feat] Support "proxy" arch between coordinator and prover (#1701)
Co-authored-by: Zhang Zhuo <mycinbrin@gmail.com> Co-authored-by: Velaciela <git.rover@outlook.com> Co-authored-by: georgehao <haohongfan@gmail.com>
1 parent 167f26e commit 71f7160

42 files changed

Lines changed: 3194 additions & 140 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/docker.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,49 @@ jobs:
360360
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
361361
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
362362
363+
coordinator-proxy:
364+
runs-on:
365+
group: scroll-reth-runner-group
366+
steps:
367+
- name: Checkout code
368+
uses: actions/checkout@v4
369+
- name: Set up QEMU
370+
uses: docker/setup-qemu-action@v2
371+
- name: Set up Docker Buildx
372+
uses: docker/setup-buildx-action@v2
373+
- name: Login to Docker Hub
374+
uses: docker/login-action@v2
375+
with:
376+
username: ${{ secrets.DOCKERHUB_USERNAME }}
377+
password: ${{ secrets.DOCKERHUB_TOKEN }}
378+
- name: Configure AWS credentials
379+
uses: aws-actions/configure-aws-credentials@v4
380+
with:
381+
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
382+
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
383+
aws-region: ${{ env.AWS_REGION }}
384+
- name: Login to Amazon ECR
385+
id: login-ecr
386+
uses: aws-actions/amazon-ecr-login@v2
387+
- name: check repo and create it if not exist
388+
env:
389+
REPOSITORY: coordinator-proxy
390+
run: |
391+
aws --region ${{ env.AWS_REGION }} ecr describe-repositories --repository-names ${{ env.REPOSITORY }} && : || aws --region ${{ env.AWS_REGION }} ecr create-repository --repository-name ${{ env.REPOSITORY }}
392+
- name: Build and push
393+
uses: docker/build-push-action@v3
394+
env:
395+
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
396+
REPOSITORY: coordinator-proxy
397+
IMAGE_TAG: ${{ github.ref_name }}
398+
with:
399+
context: .
400+
file: ./build/dockerfiles/coordinator-proxy.Dockerfile
401+
push: true
402+
tags: |
403+
scrolltech/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
404+
${{ env.ECR_REGISTRY }}/${{ env.REPOSITORY }}:${{ env.IMAGE_TAG }}
405+
363406
coordinator-cron:
364407
runs-on:
365408
group: scroll-reth-runner-group
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Download Go dependencies
2+
FROM scrolltech/go-rust-builder:go-1.22.12-rust-nightly-2025-02-14 as base
3+
WORKDIR /src
4+
COPY go.work* ./
5+
COPY ./rollup/go.* ./rollup/
6+
COPY ./common/go.* ./common/
7+
COPY ./coordinator/go.* ./coordinator/
8+
COPY ./database/go.* ./database/
9+
COPY ./tests/integration-test/go.* ./tests/integration-test/
10+
COPY ./bridge-history-api/go.* ./bridge-history-api/
11+
RUN go mod download -x
12+
13+
14+
# Build coordinator proxy
15+
FROM base as builder
16+
COPY . .
17+
RUN cd ./coordinator && CGO_LDFLAGS="-Wl,--no-as-needed -ldl" make coordinator_proxy && mv ./build/bin/coordinator_proxy /bin/coordinator_proxy
18+
19+
# Pull coordinator proxy into a second stage deploy ubuntu container
20+
FROM ubuntu:20.04
21+
ENV CGO_LDFLAGS="-Wl,--no-as-needed -ldl"
22+
RUN apt update && apt install vim netcat-openbsd net-tools curl jq -y
23+
COPY --from=builder /bin/coordinator_proxy /bin/
24+
RUN /bin/coordinator_proxy --version
25+
WORKDIR /app
26+
ENTRYPOINT ["/bin/coordinator_proxy"]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
assets/
2+
contracts/
3+
docs/
4+
l2geth/
5+
rpc-gateway/
6+
*target/*
7+
8+
permissionless-batches/conf/

common/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
github.com/gin-gonic/gin v1.9.1
1313
github.com/mattn/go-colorable v0.1.13
1414
github.com/mattn/go-isatty v0.0.20
15+
github.com/mitchellh/mapstructure v1.5.0
1516
github.com/modern-go/reflect2 v1.0.2
1617
github.com/orcaman/concurrent-map v1.0.0
1718
github.com/prometheus/client_golang v1.19.0
@@ -147,7 +148,6 @@ require (
147148
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
148149
github.com/miekg/pkcs11 v1.1.1 // indirect
149150
github.com/mitchellh/copystructure v1.2.0 // indirect
150-
github.com/mitchellh/mapstructure v1.5.0 // indirect
151151
github.com/mitchellh/pointerstructure v1.2.0 // indirect
152152
github.com/mitchellh/reflectwalk v1.0.2 // indirect
153153
github.com/mmcloughlin/addchain v0.4.0 // indirect

common/observability/server.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/urfave/cli/v2"
1717
"gorm.io/gorm"
1818

19+
"scroll-tech/common/types"
1920
"scroll-tech/common/utils"
2021
)
2122

@@ -33,9 +34,17 @@ func Server(c *cli.Context, db *gorm.DB) {
3334
promhttp.Handler().ServeHTTP(context.Writer, context.Request)
3435
})
3536

36-
probeController := NewProbesController(db)
37-
r.GET("/health", probeController.HealthCheck)
38-
r.GET("/ready", probeController.Ready)
37+
if db != nil {
38+
probeController := NewProbesController(db)
39+
r.GET("/health", probeController.HealthCheck)
40+
r.GET("/ready", probeController.Ready)
41+
} else {
42+
dummyOk := func(context *gin.Context) {
43+
types.RenderSuccess(context, nil)
44+
}
45+
r.GET("/health", dummyOk)
46+
r.GET("/ready", dummyOk)
47+
}
3948

4049
address := fmt.Sprintf(":%s", c.String(utils.MetricsPort.Name))
4150
server := &http.Server{

common/types/response.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"net/http"
55

66
"github.com/gin-gonic/gin"
7+
"github.com/mitchellh/mapstructure"
78
)
89

910
// Response the response schema
@@ -13,6 +14,19 @@ type Response struct {
1314
Data interface{} `json:"data"`
1415
}
1516

17+
func (resp *Response) DecodeData(out interface{}) error {
18+
// Decode generically unmarshaled JSON (map[string]any, []any) into a typed struct
19+
// honoring `json` tags and allowing weak type conversions.
20+
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
21+
TagName: "json",
22+
Result: out,
23+
})
24+
if err != nil {
25+
return err
26+
}
27+
return dec.Decode(resp.Data)
28+
}
29+
1630
// RenderJSON renders response with json
1731
func RenderJSON(ctx *gin.Context, errCode int, err error, data interface{}) {
1832
var errMsg string

coordinator/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ coordinator_cron:
3434
coordinator_tool:
3535
go build -ldflags "-X scroll-tech/common/version.ZkVersion=${ZK_VERSION}" -o $(PWD)/build/bin/coordinator_tool ./cmd/tool
3636

37+
coordinator_proxy:
38+
go build -ldflags "-X scroll-tech/common/version.ZkVersion=${ZK_VERSION}" -tags="mock_prover mock_verifier" -o $(PWD)/build/bin/coordinator_proxy ./cmd/proxy
39+
40+
3741
localsetup: coordinator_api ## Local setup: build coordinator_api, copy config, and setup releases
3842
mkdir -p build/bin/conf
3943
@echo "Copying configuration files..."

coordinator/cmd/proxy/app/app.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package app
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
"os"
9+
"os/signal"
10+
"time"
11+
12+
"github.com/gin-gonic/gin"
13+
"github.com/prometheus/client_golang/prometheus"
14+
"github.com/scroll-tech/go-ethereum/log"
15+
"github.com/urfave/cli/v2"
16+
"gorm.io/gorm"
17+
18+
"scroll-tech/common/database"
19+
"scroll-tech/common/observability"
20+
"scroll-tech/common/utils"
21+
"scroll-tech/common/version"
22+
23+
"scroll-tech/coordinator/internal/config"
24+
"scroll-tech/coordinator/internal/controller/proxy"
25+
"scroll-tech/coordinator/internal/route"
26+
)
27+
28+
var app *cli.App
29+
30+
func init() {
31+
// Set up coordinator app info.
32+
app = cli.NewApp()
33+
app.Action = action
34+
app.Name = "coordinator proxy"
35+
app.Usage = "Proxy for multiple Scroll L2 Coordinators"
36+
app.Version = version.Version
37+
app.Flags = append(app.Flags, utils.CommonFlags...)
38+
app.Flags = append(app.Flags, apiFlags...)
39+
app.Before = func(ctx *cli.Context) error {
40+
return utils.LogSetup(ctx)
41+
}
42+
// Register `coordinator-test` app for integration-test.
43+
utils.RegisterSimulation(app, utils.CoordinatorAPIApp)
44+
}
45+
46+
func action(ctx *cli.Context) error {
47+
cfgFile := ctx.String(utils.ConfigFileFlag.Name)
48+
cfg, err := config.NewProxyConfig(cfgFile)
49+
if err != nil {
50+
log.Crit("failed to load config file", "config file", cfgFile, "error", err)
51+
}
52+
53+
var db *gorm.DB
54+
if dbCfg := cfg.ProxyManager.DB; dbCfg != nil {
55+
log.Info("Apply persistent storage")
56+
db, err = database.InitDB(cfg.ProxyManager.DB)
57+
if err != nil {
58+
log.Crit("failed to init db connection", "err", err)
59+
}
60+
defer func() {
61+
if err = database.CloseDB(db); err != nil {
62+
log.Error("can not close db connection", "error", err)
63+
}
64+
}()
65+
}
66+
registry := prometheus.DefaultRegisterer
67+
observability.Server(ctx, db)
68+
69+
apiSrv := server(ctx, cfg, db, registry)
70+
71+
log.Info(
72+
"Start coordinator proxy successfully.",
73+
"version", version.Version,
74+
)
75+
76+
// Catch CTRL-C to ensure a graceful shutdown.
77+
interrupt := make(chan os.Signal, 1)
78+
signal.Notify(interrupt, os.Interrupt)
79+
80+
// Wait until the interrupt signal is received from an OS signal.
81+
<-interrupt
82+
log.Info("start shutdown coordinator proxy server ...")
83+
84+
closeCtx, cancelExit := context.WithTimeout(context.Background(), 5*time.Second)
85+
defer cancelExit()
86+
if err = apiSrv.Shutdown(closeCtx); err != nil {
87+
log.Warn("shutdown coordinator proxy server failure", "error", err)
88+
return nil
89+
}
90+
91+
<-closeCtx.Done()
92+
log.Info("coordinator proxy server exiting success")
93+
return nil
94+
}
95+
96+
func server(ctx *cli.Context, cfg *config.ProxyConfig, db *gorm.DB, reg prometheus.Registerer) *http.Server {
97+
router := gin.New()
98+
proxy.InitController(cfg, db, reg)
99+
route.ProxyRoute(router, cfg, reg)
100+
port := ctx.String(httpPortFlag.Name)
101+
srv := &http.Server{
102+
Addr: fmt.Sprintf(":%s", port),
103+
Handler: router,
104+
ReadHeaderTimeout: time.Minute,
105+
}
106+
107+
go func() {
108+
if runServerErr := srv.ListenAndServe(); runServerErr != nil && !errors.Is(runServerErr, http.ErrServerClosed) {
109+
log.Crit("run coordinator proxy http server failure", "error", runServerErr)
110+
}
111+
}()
112+
return srv
113+
}
114+
115+
// Run coordinator.
116+
func Run() {
117+
// RunApp the coordinator.
118+
if err := app.Run(os.Args); err != nil {
119+
_, _ = fmt.Fprintln(os.Stderr, err)
120+
os.Exit(1)
121+
}
122+
}

coordinator/cmd/proxy/app/flags.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package app
2+
3+
import "github.com/urfave/cli/v2"
4+
5+
var (
6+
apiFlags = []cli.Flag{
7+
// http flags
8+
&httpEnabledFlag,
9+
&httpListenAddrFlag,
10+
&httpPortFlag,
11+
}
12+
// httpEnabledFlag enable rpc server.
13+
httpEnabledFlag = cli.BoolFlag{
14+
Name: "http",
15+
Usage: "Enable the HTTP-RPC server",
16+
Value: false,
17+
}
18+
// httpListenAddrFlag set the http address.
19+
httpListenAddrFlag = cli.StringFlag{
20+
Name: "http.addr",
21+
Usage: "HTTP-RPC server listening interface",
22+
Value: "localhost",
23+
}
24+
// httpPortFlag set http.port.
25+
httpPortFlag = cli.IntFlag{
26+
Name: "http.port",
27+
Usage: "HTTP-RPC server listening port",
28+
Value: 8590,
29+
}
30+
)

coordinator/cmd/proxy/main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package main
2+
3+
import "scroll-tech/coordinator/cmd/proxy/app"
4+
5+
func main() {
6+
app.Run()
7+
}

0 commit comments

Comments
 (0)