Skip to content

Commit

Permalink
refactor: implement cli (#25)
Browse files Browse the repository at this point in the history
* refactor: implement cli

* update processing logic

* update Dockerfile with correct cmd args

* fix makefile

* fix lint error

* add docker compose file

* add arb config

* add prevBatch committee root check
  • Loading branch information
kashishshah authored Jul 9, 2024
1 parent d05a36e commit ed30c0a
Show file tree
Hide file tree
Showing 15 changed files with 836 additions and 153 deletions.
3 changes: 0 additions & 3 deletions .env

This file was deleted.

20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
FROM golang:1.21-alpine AS build

RUN apk add --no-cache --update gcc g++ make

ENV CGO_CFLAGS="-O -D__BLST_PORTABLE__"
ENV CGO_CFLAGS_ALLOW="-O -D__BLST_PORTABLE__"

WORKDIR /src

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

COPY . .

RUN make build

FROM alpine:edge
COPY ./config.toml /app/config.toml
COPY --from=build /src/dist/lsc-state-verifier /app/lsc-state-verifier
CMD ["/app/lsc-state-verifier", "db", "--config", "/app/config.toml"]
40 changes: 39 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
VERSION := $(shell git describe --tags --always)
GITREV := $(shell git rev-parse --short HEAD)
GITBRANCH := $(shell git rev-parse --abbrev-ref HEAD)
DATE := $(shell LANG=US date +"%a, %d %b %Y %X %z")

GOBASE := $(shell pwd)
GOBIN := $(GOBASE)/dist
GOARCH := $(ARCH)
GOENVVARS := GOBIN=$(GOBIN) CGO_ENABLED=1 GOOS=$(OS) GOARCH=$(GOARCH)
GOBINARY := lsc-state-verifier
GOCMD := $(GOBASE)/cmd/

LDFLAGS += -X 'github.com/Lagrange-Labs/lagrange-state-verifier.Version=$(VERSION)'
LDFLAGS += -X 'github.com/Lagrange-Labs/lagrange-state-verifier.GitRev=$(GITREV)'
LDFLAGS += -X 'github.com/Lagrange-Labs/lagrange-state-verifier.GitBranch=$(GITBRANCH)'
LDFLAGS += -X 'github.com/Lagrange-Labs/lagrange-state-verifier.BuildDate=$(DATE)'

STOP := docker compose down --remove-orphans

# Building the docker image and the binary
build: ## Builds the binary locally into ./dist
$(GOENVVARS) go build -ldflags "all=$(LDFLAGS)" -o $(GOBIN)/$(GOBINARY) $(GOCMD)
.PHONY: build

docker-build: ## Builds a docker image with the binary
docker build -t lsc-state-verifier -f ./Dockerfile .
.PHONY: docker-build

# Linting, Teseting, Benchmarking
golangci_lint_cmd=github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.2

Expand All @@ -12,4 +40,14 @@ lint:

test:
go test ./... --timeout=10m -v --race
.PHONY: test
.PHONY: test
run: build
./dist/$(GOBINARY) db

localnet-start: stop
echo "Starting localnet"
docker compose up

stop:
$(STOP)
.PHONY: localnet-start stop
111 changes: 111 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package main

import (
"fmt"
"os"
"runtime"
"sync"

"github.com/Lagrange-Labs/lagrange-node/logger"
"github.com/Lagrange-Labs/state-verifier/config"
"github.com/Lagrange-Labs/state-verifier/db"
"github.com/Lagrange-Labs/state-verifier/utils"
"github.com/urfave/cli/v2"
)

var (
configFileFlag = &cli.StringFlag{
Name: config.FlagCfg,
Value: "./config.toml",
Usage: "Configuration `FILE`",
Aliases: []string{"c"},
}
)

func main() {
app := cli.NewApp()
app.Name = "State Committee Verifier"

app.Commands = []*cli.Command{
{
Name: "version",
Usage: "Prints the version of the State Committee Verifier",
Action: func(c *cli.Context) error {
w := os.Stdout
fmt.Fprintf(w, "Version: %s\n", "v0.1.0")
fmt.Fprintf(w, "Go version: %s\n", runtime.Version())
fmt.Fprintf(w, "OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
return nil
},
},
{
Name: "api",
Usage: "Uses API to get state proof data",
Flags: []cli.Flag{
configFileFlag,
},
Action: fetchStateProofFromAPI,
},
{
Name: "db",
Usage: "Uses db call to get state proof data",
Flags: []cli.Flag{
configFileFlag,
},
Action: fetchStateProofFromDB,
},
}
err := app.Run(os.Args)

if err != nil {
logger.Fatalf("Error running app: ", err)
os.Exit(1)
}
}

func fetchStateProofFromAPI(c *cli.Context) error {
cfg, err := config.LoadCLIConfig(c)
if err != nil {
logger.Fatalf("Error loading config: %s", err)
}

var wg sync.WaitGroup
for _, chain := range cfg.Chains {
wg.Add(1)
go func(chain config.ChainConfig) {
defer wg.Done()
err := utils.ProcessChainUsingAPI(cfg.ApiUrl, cfg.ApiKey, chain)
if err != nil {
logger.Errorf("Error processing chain ID %d: %s", chain.ChainID, err)
}
}(chain)
}
wg.Wait()
return nil
}

func fetchStateProofFromDB(c *cli.Context) error {
cfg, err := config.LoadCLIConfig(c)
if err != nil {
logger.Fatalf("Error loading config: %s", err)
}

mongoDB, err := db.NewMongoDatabase(cfg.DatabaseURI)
if err != nil {
logger.Fatalf("Error creating MongoDB client: %s", err)
}

var wg sync.WaitGroup
for _, chain := range cfg.Chains {
wg.Add(1)
go func(chain config.ChainConfig) {
defer wg.Done()
err := utils.ProcessChainUsingDB(mongoDB, chain)
if err != nil {
logger.Errorf("Error processing chain ID %d: %s", chain.ChainID, err)
}
}(chain)
}
wg.Wait()
return nil
}
15 changes: 15 additions & 0 deletions config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
api_url = "https://api-statecommittee.lagrange.dev"
api_key = "your_api_key"
database_uri = "mongodb://localhost:27017"

[[chains]]
chain_id = 10
from_batch_number = 1

[[chains]]
chain_id = 8453
from_batch_number = 1

[[chains]]
chain_id = 42161
from_batch_number = 1
68 changes: 68 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package config

import (
"fmt"
"path/filepath"
"strings"

"github.com/Lagrange-Labs/lagrange-node/logger"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
"github.com/urfave/cli/v2"
)

const FlagCfg = "config"

type ChainConfig struct {
ChainID int64 `mapstructure:"chain_id"`
FromBatchNumber int64 `mapstructure:"from_batch_number"`
}

type CLIConfig struct {
ApiUrl string `mapstructure:"api_url"`
ApiKey string `mapstructure:"api_key"`
Chains []ChainConfig `mapstructure:"chains"`
DatabaseURI string `mapstructure:"database_uri"`
}

// LoadCLIConfig loads the State Committee Verifier configuration.
func LoadCLIConfig(ctx *cli.Context) (*CLIConfig, error) {
var cfg CLIConfig
viper.SetConfigType("toml")

configFilePath := ctx.String(FlagCfg)
if configFilePath != "" {
dirName, fileName := filepath.Split(configFilePath)

fileExtension := strings.TrimPrefix(filepath.Ext(fileName), ".")
fileNameWithoutExtension := strings.TrimSuffix(fileName, "."+fileExtension)

viper.AddConfigPath(dirName)
viper.SetConfigName(fileNameWithoutExtension)
viper.SetConfigType(fileExtension)
}
viper.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
viper.SetEnvPrefix("STATE_VERIFIER")
if err := viper.ReadInConfig(); err != nil {
_, ok := err.(viper.ConfigFileNotFoundError)
if !ok {
return nil, err
} else if len(configFilePath) > 0 {
logger.Warnf("config file `%s` not found, the path should be absolute or relative to the current working directory like `./config.toml`", configFilePath)
return nil, fmt.Errorf("config file not found: %s", err)
}
}

decodeHooks := []viper.DecoderConfigOption{
// this allows arrays to be decoded from env var separated by ",", example: MY_VAR="value1,value2,value3"
viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(mapstructure.TextUnmarshallerHookFunc(), mapstructure.StringToSliceHookFunc(","))),
}

if err := viper.Unmarshal(&cfg, decodeHooks...); err != nil {
return nil, err
}

return &cfg, nil
}
Loading

0 comments on commit ed30c0a

Please sign in to comment.