Skip to content

Commit

Permalink
First iteration of zkprover mock tool (0xPolygonHermez#937)
Browse files Browse the repository at this point in the history
* zkprover mock tool

* unhappy path test cases

* push zkprover-mock

* fix image build

* use expectedRoot slice
  • Loading branch information
fgimenez authored Jul 27, 2022
1 parent beb9b73 commit df7eeb5
Show file tree
Hide file tree
Showing 11 changed files with 452 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/push-docker-develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,22 @@ jobs:
push: true
tags: |
hermeznetwork/zkevm-mock-prover:latest
- name: Check changes in zkevmprovermock
id: zkevmprovermock_changes
uses: dorny/paths-filter@v2
with:
filters: |
zkevmprovermock:
- 'zkevmprovermock/**'
- name: Build and push zkevmprovermock
if: steps.zkevmprovermock_changes.outputs.zkevmprovermock == 'true'
id: docker_build_zkevmprovermock
uses: docker/build-push-action@v2
with:
context: ./zkevmprovermock
platforms: linux/amd64,linux/arm64
push: true
tags: |
hermeznetwork/zkprover-mock:latest
19 changes: 19 additions & 0 deletions .github/workflows/push-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,22 @@ jobs:
push: true
tags: |
hermeznetwork/zkevm-mock-prover:latest
- name: Check changes in zkevmprovermock
id: zkevmprovermock_changes
uses: dorny/paths-filter@v2
with:
filters: |
zkevmprovermock:
- 'zkevmprovermock/**'
- name: Build and push zkevmprovermock
if: steps.zkevmprovermock_changes.outputs.zkevmprovermock == 'true'
id: docker_build_zkevmprovermock
uses: docker/build-push-action@v2
with:
context: ./zkevmprovermock
platforms: linux/amd64,linux/arm64
push: true
tags: |
hermeznetwork/zkprover-mock:latest
21 changes: 21 additions & 0 deletions test/operations/wait.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ import (
"fmt"
"io/ioutil"
"net/http"
"os"
"os/signal"
"time"

"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/proverclient/pb"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -209,3 +212,21 @@ func txMinedCondition(ctx context.Context, client *ethclient.Client, hash common
}
return done, nil
}

// WaitSignal blocks until an Interrupt or Kill signal is received, then it
// executes the given cleanup functions and returns.
func WaitSignal(cleanupFuncs ...func()) {
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)

for sig := range signals {
switch sig {
case os.Interrupt, os.Kill:
log.Info("terminating application gracefully...")
for _, cleanup := range cleanupFuncs {
cleanup()
}
return
}
}
}
12 changes: 12 additions & 0 deletions zkevmprovermock/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM golang:1.17-alpine AS build

ENV CGO_ENABLED=0
WORKDIR /app
COPY . .
RUN apk add --no-cache build-base && \
go build -ldflags '-extldflags "-static"' -o ./zkprover-mock ./zkevmprovermock/cmd/...

FROM alpine:3.16.0
COPY --from=build /app/zkprover-mock /app/zkprover-mock
EXPOSE 50061 50071
CMD ["/bin/sh", "-c", "/app/zkprover-mock server"]
12 changes: 12 additions & 0 deletions zkevmprovermock/cmd/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/urfave/cli/v2"
)

func runClient(cliCtx *cli.Context) error {
log.Info("Running zkEVM Prover Client mock...")

return nil
}
77 changes: 77 additions & 0 deletions zkevmprovermock/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"fmt"
"log"
"os"

"github.com/urfave/cli/v2"
)

const (
defaultStateDBPort = 50061
defaultExecutorPort = 50071
defaultTestVectorPath = "../../test/vectors/src/merkle-tree/"
)

func main() {
app := cli.NewApp()
serverFlags := []cli.Flag{
&cli.UintFlag{
Name: "statedb-port",
Usage: "StateDB server port",
Required: false,
Value: defaultStateDBPort,
},
&cli.UintFlag{
Name: "executor-port",
Usage: "Executor server port",
Required: false,
Value: defaultExecutorPort,
},
&cli.StringFlag{
Name: "test-vector-path",
Usage: "Test vector path",
Required: false,
Value: defaultTestVectorPath,
},
&cli.StringFlag{
Name: "host",
Usage: "Server host",
Required: false,
Value: "0.0.0.0",
},
}
clientFlags := []cli.Flag{
&cli.StringFlag{
Name: "state-db-serveruri",
Usage: "StateDB server URI",
Required: false,
Value: fmt.Sprintf("127.0.0.1:%d", defaultStateDBPort),
},
&cli.StringFlag{
Name: "executor-serveruri",
Usage: "Executor server URI",
Required: false,
Value: fmt.Sprintf("127.0.0.1:%d", defaultExecutorPort),
},
}
app.Commands = []*cli.Command{
{
Name: "server",
Usage: "Run zkEVM Prover mock server",
Action: runServer,
Flags: serverFlags,
},
{
Name: "client",
Usage: "Run zkEVM Prover mock client",
Action: runClient,
Flags: clientFlags,
},
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
46 changes: 46 additions & 0 deletions zkevmprovermock/cmd/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package main

import (
"fmt"

"github.com/0xPolygonHermez/zkevm-node/log"
stateDBPpb "github.com/0xPolygonHermez/zkevm-node/merkletree/pb"
executorPb "github.com/0xPolygonHermez/zkevm-node/state/runtime/executor/pb"
"github.com/0xPolygonHermez/zkevm-node/test/operations"
"github.com/0xPolygonHermez/zkevm-node/zkevmprovermock/server"
"github.com/0xPolygonHermez/zkevm-node/zkevmprovermock/testvector"
"github.com/spf13/afero"
"github.com/urfave/cli/v2"
"google.golang.org/grpc"
)

func runServer(cliCtx *cli.Context) error {
log.Info("Running zkEVM Prover Server mock...")

s := grpc.NewServer()

aferoFs := afero.NewOsFs()

tvContainer, err := testvector.NewContainer(cliCtx.String("test-vector-path"), aferoFs)
if err != nil {
log.Fatalf("Could not create test vector container: %v", err)
}

stateDBAddress := fmt.Sprintf("%s:%d", cliCtx.String("host"), cliCtx.Uint("statedb-port"))
stateDBSrv := server.NewStateDBMock(stateDBAddress, tvContainer)

stateDBPpb.RegisterStateDBServiceServer(s, stateDBSrv)
go stateDBSrv.Start()

executorAddress := fmt.Sprintf("%s:%d", cliCtx.String("host"), cliCtx.Uint("executor-port"))
executorSrv := server.NewExecutorMock(executorAddress, tvContainer)

executorPb.RegisterExecutorServiceServer(s, executorSrv)
go executorSrv.Start()

operations.WaitSignal(func() {
stateDBSrv.Stop()
executorSrv.Stop()
})
return nil
}
55 changes: 55 additions & 0 deletions zkevmprovermock/server/executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package server

import (
"net"

"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/state/runtime/executor/pb"
"github.com/0xPolygonHermez/zkevm-node/zkevmprovermock/testvector"
"google.golang.org/grpc"
)

// ExecutorMock represents and Executor mock server
type ExecutorMock struct {
// address is the address on which the gRPC server will listen, eg. 0.0.0.0:50061
address string

tvContainer *testvector.Container

// srv is an insance of the gRPC server.
srv *grpc.Server

// embedding an instance of pb.UnimplementedExecutorServiceServer will allow us
// to implement all the required method interfaces.
pb.UnimplementedExecutorServiceServer
}

// NewExecutorMock is the ExecutorMock constructor.
func NewExecutorMock(address string, tvContainer *testvector.Container) *ExecutorMock {
return &ExecutorMock{
address: address,
tvContainer: tvContainer,
}
}

// Start sets up the stateDB server to process requests.
func (server *ExecutorMock) Start() {
lis, err := net.Listen("tcp", server.address)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}

server.srv = grpc.NewServer()
pb.RegisterExecutorServiceServer(server.srv, server)

log.Infof("Executor mock server: listening at %s", server.address)
if err := server.srv.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

// Stop stops the server.
func (server *ExecutorMock) Stop() {
log.Info("Executor mock server: stopping...")
server.srv.Stop()
}
54 changes: 54 additions & 0 deletions zkevmprovermock/server/statedb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package server

import (
"net"

"github.com/0xPolygonHermez/zkevm-node/log"
"github.com/0xPolygonHermez/zkevm-node/merkletree/pb"
"github.com/0xPolygonHermez/zkevm-node/zkevmprovermock/testvector"
"google.golang.org/grpc"
)

// StateDBMock represents a StateDB mock server.
type StateDBMock struct {
// address is the address on which the gRPC server will listen, eg. 0.0.0.0:50061
address string

tvContainer *testvector.Container

// srv is an insance of the gRPC server.
srv *grpc.Server
// embedding an instance of pb.UnimplementedStateDBServiceServer will allow us
// to implement all the required method interfaces.
pb.UnimplementedStateDBServiceServer
}

// NewStateDBMock is the StateDBMock constructor.
func NewStateDBMock(address string, tvContainer *testvector.Container) *StateDBMock {
return &StateDBMock{
address: address,
tvContainer: tvContainer,
}
}

// Start sets up the stateDB server to process requests.
func (server *StateDBMock) Start() {
lis, err := net.Listen("tcp", server.address)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}

server.srv = grpc.NewServer()
pb.RegisterStateDBServiceServer(server.srv, server)

log.Infof("StateDB mock server: listening at %s", server.address)
if err := server.srv.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}

// Stop stops the server.
func (server *StateDBMock) Stop() {
log.Info("StateDB mock server: stopping...")
server.srv.Stop()
}
50 changes: 50 additions & 0 deletions zkevmprovermock/testvector/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package testvector

import (
"encoding/json"
"path/filepath"

"github.com/spf13/afero"
)

// StateDBRaw contains raw test vector for state db.
type StateDBRaw struct {
Entries []*StateDBRawEntry
}

// StateDBRawEntry contains raw test vector for state db.
type StateDBRawEntry struct {
Keys []string
Values []string
ExpectedRoot []string
}

// Container is a wrapper for test vectors.
type Container struct {
StateDBRaw *StateDBRaw
}

// NewContainer is the Container constructor.
func NewContainer(testVectorPath string, aferoFs afero.Fs) (*Container, error) {
stateDBRaw, err := getStateDBRaw(testVectorPath, aferoFs)
if err != nil {
return nil, err
}

return &Container{
StateDBRaw: stateDBRaw,
}, nil
}

func getStateDBRaw(testVectorPath string, aferoFs afero.Fs) (*StateDBRaw, error) {
filePath := filepath.Join(testVectorPath, "merkle-tree/smt-raw.json")
contents, err := afero.ReadFile(aferoFs, filePath)
if err != nil {
return nil, err
}
var stateDBRaw StateDBRaw
if err := json.Unmarshal(contents, &stateDBRaw.Entries); err != nil {
return nil, err
}
return &stateDBRaw, nil
}
Loading

0 comments on commit df7eeb5

Please sign in to comment.