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

refactor: implement cli #25

Merged
merged 8 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
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
Loading