Browse Source

Update prover & add test

feature/sql-semaphore1
laisolizq 4 years ago
committed by Eduard S
parent
commit
4ad67a3d18
3 changed files with 174 additions and 27 deletions
  1. +28
    -0
      prover/README.md
  2. +63
    -27
      prover/prover.go
  3. +83
    -0
      prover/prover_test.go

+ 28
- 0
prover/README.md

@ -0,0 +1,28 @@
## Test Prover
### Server Proof API
It is necessary to have a docker with server locally.
The instructions in the following link can be followed:
https://github.com/hermeznetwork/test-info/tree/main/cli-prover
> It is necessary to consult the pre-requirements to follow the steps of the next summary
A summary of the steps to follow to run docker would be:
- Clone the repository: https://github.com/hermeznetwork/test-info
- `cd cli-prover`
- `./cli-prover.sh -s localhost -v ~/prover_data -r 22`
- To enter docker: `docker exec -ti docker_cusnarks bash`
- Inside the docker: `cd cusnarks; make docker_all FORCE_CPU=1`
- Inside the docker: `cd config; python3 cusnarks_config.py 22 BN256`
- To exit docker: `exit`
- Now, the server API can be used. Helper can be consulted with: `./cli-prover.sh -h`
- Is necessary to initialize the server with: `./cli-prover.sh --post-start <session>`
- When `./cli-prover.sh --get-status <session>` is `ready` can be run the test.
> The session can be consulted with `tmux ls`. The session will be the number of the last session on the list.
### Test
`INTEGRATION=1 go test`

+ 63
- 27
prover/prover.go

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"mime/multipart" "mime/multipart"
@ -13,18 +14,21 @@ import (
"github.com/dghubble/sling" "github.com/dghubble/sling"
"github.com/hermeznetwork/hermez-node/common" "github.com/hermeznetwork/hermez-node/common"
"github.com/hermeznetwork/hermez-node/log"
"github.com/hermeznetwork/tracerr" "github.com/hermeznetwork/tracerr"
) )
// Proof TBD this type will be received from the proof server // Proof TBD this type will be received from the proof server
type Proof struct { type Proof struct {
PiA []string `json:"pi_a"`
PiB [][]string `json:"pi_b"`
PiC []string `json:"pi_c"`
Protocol string `json:"protocol"`
} }
// Client is the interface to a ServerProof that calculates zk proofs // Client is the interface to a ServerProof that calculates zk proofs
type Client interface { type Client interface {
// Non-blocking // Non-blocking
CalculateProof(zkInputs *common.ZKInputs) error
CalculateProof(ctx context.Context, zkInputs *common.ZKInputs) error
// Blocking // Blocking
GetProof(ctx context.Context) (*Proof, error) GetProof(ctx context.Context) (*Proof, error)
// Non-Blocking // Non-Blocking
@ -105,23 +109,22 @@ const (
GET apiMethod = "GET" GET apiMethod = "GET"
// POST is an HTTP POST with maybe JSON body // POST is an HTTP POST with maybe JSON body
POST apiMethod = "POST" POST apiMethod = "POST"
// POSTFILE is an HTTP POST with a form file
POSTFILE apiMethod = "POSTFILE"
) )
// ProofServerClient contains the data related to a ProofServerClient // ProofServerClient contains the data related to a ProofServerClient
type ProofServerClient struct { type ProofServerClient struct {
URL string
client *sling.Sling
URL string
client *sling.Sling
timeCons time.Duration
} }
// NewProofServerClient creates a new ServerProof // NewProofServerClient creates a new ServerProof
func NewProofServerClient(URL string) *ProofServerClient {
func NewProofServerClient(URL string, timeCons time.Duration) *ProofServerClient {
if URL[len(URL)-1] != '/' { if URL[len(URL)-1] != '/' {
URL += "/" URL += "/"
} }
client := sling.New().Base(URL) client := sling.New().Base(URL)
return &ProofServerClient{URL: URL, client: client}
return &ProofServerClient{URL: URL, client: client, timeCons: timeCons}
} }
//nolint:unused //nolint:unused
@ -170,15 +173,6 @@ func (p *ProofServerClient) apiRequest(ctx context.Context, method apiMethod, pa
req, err = p.client.New().Get(path).Request() req, err = p.client.New().Get(path).Request()
case POST: case POST:
req, err = p.client.New().Post(path).BodyJSON(body).Request() req, err = p.client.New().Post(path).BodyJSON(body).Request()
case POSTFILE:
provider, err := newFormFileProvider(body)
if err != nil {
return tracerr.Wrap(err)
}
req, err = p.client.New().Post(path).BodyProvider(provider).Request()
if err != nil {
return tracerr.Wrap(err)
}
default: default:
return tracerr.Wrap(fmt.Errorf("invalid http method: %v", method)) return tracerr.Wrap(fmt.Errorf("invalid http method: %v", method))
} }
@ -215,7 +209,7 @@ func (p *ProofServerClient) apiCancel(ctx context.Context) error {
//nolint:unused //nolint:unused
func (p *ProofServerClient) apiInput(ctx context.Context, zkInputs *common.ZKInputs) error { func (p *ProofServerClient) apiInput(ctx context.Context, zkInputs *common.ZKInputs) error {
if err := p.apiRequest(ctx, POSTFILE, "/input", zkInputs, nil); err != nil {
if err := p.apiRequest(ctx, POST, "/input", zkInputs, nil); err != nil {
return tracerr.Wrap(err) return tracerr.Wrap(err)
} }
return nil return nil
@ -223,28 +217,70 @@ func (p *ProofServerClient) apiInput(ctx context.Context, zkInputs *common.ZKInp
// CalculateProof sends the *common.ZKInputs to the ServerProof to compute the // CalculateProof sends the *common.ZKInputs to the ServerProof to compute the
// Proof // Proof
func (p *ProofServerClient) CalculateProof(zkInputs *common.ZKInputs) error {
log.Error("TODO")
return tracerr.Wrap(common.ErrTODO)
func (p *ProofServerClient) CalculateProof(ctx context.Context, zkInputs *common.ZKInputs) error {
err := p.apiInput(ctx, zkInputs)
if err != nil {
return tracerr.Wrap(err)
}
return nil
} }
// GetProof retreives the Proof from the ServerProof, blocking until the proof // GetProof retreives the Proof from the ServerProof, blocking until the proof
// is ready. // is ready.
func (p *ProofServerClient) GetProof(ctx context.Context) (*Proof, error) { func (p *ProofServerClient) GetProof(ctx context.Context) (*Proof, error) {
log.Error("TODO")
return nil, tracerr.Wrap(common.ErrTODO)
status, err := p.apiStatus(ctx)
if err != nil {
return nil, tracerr.Wrap(err)
}
if status.Status == StatusCodeSuccess {
var proof Proof
err := json.Unmarshal([]byte(status.Proof), &proof)
if err != nil {
return nil, tracerr.Wrap(err)
}
return &proof, nil
} else {
return nil, errors.New("State is not Success")
}
} }
// Cancel cancels any current proof computation // Cancel cancels any current proof computation
func (p *ProofServerClient) Cancel(ctx context.Context) error { func (p *ProofServerClient) Cancel(ctx context.Context) error {
log.Error("TODO")
return tracerr.Wrap(common.ErrTODO)
err := p.apiCancel(ctx)
if err != nil {
return tracerr.Wrap(err)
}
return nil
} }
// WaitReady waits until the serverProof is ready // WaitReady waits until the serverProof is ready
func (p *ProofServerClient) WaitReady(ctx context.Context) error { func (p *ProofServerClient) WaitReady(ctx context.Context) error {
log.Error("TODO")
return tracerr.Wrap(common.ErrTODO)
status, err := p.apiStatus(ctx)
if err != nil {
return tracerr.Wrap(err)
}
if !status.Status.IsInitialized() {
err := errors.New("Proof Server is not initialized")
return err
} else {
if status.Status.IsReady() {
return nil
}
for {
select {
case <-ctx.Done():
return tracerr.Wrap(common.ErrDone)
case <-time.After(p.timeCons):
status, err := p.apiStatus(ctx)
if err != nil {
return tracerr.Wrap(err)
}
if status.Status.IsReady() {
return nil
}
}
}
}
} }
// MockClient is a mock ServerProof to be used in tests. It doesn't calculate anything // MockClient is a mock ServerProof to be used in tests. It doesn't calculate anything

+ 83
- 0
prover/prover_test.go

@ -0,0 +1,83 @@
package prover
import (
"context"
"math/big"
"os"
"testing"
"time"
"github.com/hermeznetwork/hermez-node/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const apiURL = "http://localhost:3000/api"
const timeCons = 1 * time.Second
var proofServerClient *ProofServerClient
func TestMain(m *testing.M) {
exitVal := 0
if os.Getenv("INTEGRATION") != "" {
proofServerClient = NewProofServerClient(apiURL, timeCons)
err := proofServerClient.WaitReady(context.Background())
if err != nil {
panic(err)
}
exitVal = m.Run()
}
os.Exit(exitVal)
}
func TestApiServer(t *testing.T) {
t.Run("testAPIStatus", testAPIStatus)
t.Run("testCalculateProof", testCalculateProof)
time.Sleep(time.Second / 4)
err := proofServerClient.WaitReady(context.Background())
require.NoError(t, err)
t.Run("testGetProof", testGetProof)
t.Run("testCancel", testCancel)
}
func testAPIStatus(t *testing.T) {
status, err := proofServerClient.apiStatus(context.Background())
require.NoError(t, err)
assert.Equal(t, true, status.Status.IsReady())
}
func testCalculateProof(t *testing.T) {
var zkInputs *common.ZKInputs
zkInputs = common.NewZKInputs(100, 16, 512, 24, 32, big.NewInt(1))
err := proofServerClient.CalculateProof(context.Background(), zkInputs)
require.NoError(t, err)
}
func testGetProof(t *testing.T) {
proof, err := proofServerClient.GetProof(context.Background())
require.NoError(t, err)
require.NotNil(t, proof)
require.NotNil(t, proof.PiA)
require.NotNil(t, proof.PiB)
require.NotNil(t, proof.PiC)
require.NotNil(t, proof.Protocol)
}
func testCancel(t *testing.T) {
var zkInputs *common.ZKInputs
zkInputs = common.NewZKInputs(100, 16, 512, 24, 32, big.NewInt(1))
err := proofServerClient.CalculateProof(context.Background(), zkInputs)
require.NoError(t, err)
// TODO: remove sleep when the server has been reviewed
time.Sleep(time.Second / 4)
err = proofServerClient.Cancel(context.Background())
require.NoError(t, err)
status, err := proofServerClient.apiStatus(context.Background())
require.NoError(t, err)
for status.Status == StatusCodeBusy {
time.Sleep(proofServerClient.timeCons)
status, err = proofServerClient.apiStatus(context.Background())
require.NoError(t, err)
}
assert.Equal(t, StatusCodeAborted, status.Status)
}

Loading…
Cancel
Save