Skip to content
This repository has been archived by the owner on May 11, 2024. It is now read-only.

Commit

Permalink
feat(prover): update ZkevmRpcdProducer to make it connecting to a r…
Browse files Browse the repository at this point in the history
…eal proverd service (#121)

Co-authored-by: alexshliu <[email protected]>
  • Loading branch information
davidtaikocha and alexshliu authored Feb 14, 2023
1 parent 6c00fc5 commit 8c8ee9c
Show file tree
Hide file tree
Showing 11 changed files with 460 additions and 20 deletions.
12 changes: 12 additions & 0 deletions cmd/flags/prover.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ var (
"`lowerBound-upperBound` (e.g. `30m-1h`), testing purposes only",
Category: proverCategory,
}
ProverIdx = cli.UintFlag{
Name: "proverIdx",
Value: 0,
Category: proverCategory,
}
TotalProvers = cli.UintFlag{
Name: "totalProvers",
Value: 0,
Category: proverCategory,
}
)

// All prover flags.
Expand All @@ -64,4 +74,6 @@ var ProverFlags = MergeFlags(CommonFlags, []cli.Flag{
&MaxConcurrentProvingJobs,
&Dummy,
&RandomDummyProofDelay,
&ProverIdx,
&TotalProvers,
})
4 changes: 4 additions & 0 deletions prover/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ type Config struct {
Dummy bool
RandomDummyProofDelayLowerBound *time.Duration
RandomDummyProofDelayUpperBound *time.Duration
Idx uint
Total uint
}

// NewConfigFromCliContext creates a new config instance from command line flags.
Expand Down Expand Up @@ -85,5 +87,7 @@ func NewConfigFromCliContext(c *cli.Context) (*Config, error) {
Dummy: c.Bool(flags.Dummy.Name),
RandomDummyProofDelayLowerBound: randomDummyProofDelayLowerBound,
RandomDummyProofDelayUpperBound: randomDummyProofDelayUpperBound,
Idx: c.Uint(flags.ProverIdx.Name),
Total: c.Uint(flags.TotalProvers.Name),
}, nil
}
153 changes: 153 additions & 0 deletions prover/proof_producer/zkevm_cmd_producer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package producer

import (
"bytes"
"encoding/json"
"fmt"
"math/big"
"os"
"os/exec"
"path/filepath"
"strings"
"time"

"github.com/cenkalti/backoff/v4"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/taikoxyz/taiko-client/bindings"
)

// ZkevmCmdProducer is responsible for generating zk proofs from the given command line binary file.
type ZkevmCmdProducer struct {
CmdPath string
L2Endpoint string // a L2 execution engine's RPC endpoint
}

// NewZkevmCmdProducer creates a new NewZkevmCmdProducer instance.
func NewZkevmCmdProducer(
cmdPath string,
l2Endpoint string,
) (*ZkevmCmdProducer, error) {
return &ZkevmCmdProducer{cmdPath, l2Endpoint}, nil
}

// RequestProof implements the ProofProducer interface.
func (d *ZkevmCmdProducer) RequestProof(
opts *ProofRequestOptions,
blockID *big.Int,
meta *bindings.TaikoDataBlockMetadata,
header *types.Header,
resultCh chan *ProofWithHeader,
) error {
log.Info(
"Request proof from ZKEVM CMD",
"blockID", blockID,
"beneficiary", meta.Beneficiary,
"height", header.Number,
"hash", header.Hash(),
"cmd", d.CmdPath,
)

var (
proof []byte
err error
)
if err := backoff.Retry(func() error {
if proof, err = d.ExecProverCmd(opts.Height); err != nil {
log.Error("Execute prover cmd error", "error", err)
return err
}

return nil
}, backoff.NewConstantBackOff(3*time.Second)); err != nil {
log.Error("Failed to generate proof", "error", err)
}

resultCh <- &ProofWithHeader{
BlockID: blockID,
Header: header,
Meta: meta,
ZkProof: proof,
}

return nil
}

type ProverCmdOutput struct {
Instances []string `json:"instances"`
Proof []byte `json:"proof"`
}

func (d *ZkevmCmdProducer) ExecProverCmd(height *big.Int) ([]byte, error) {
start := time.Now()
cmd := exec.Command(d.CmdPath, d.L2Endpoint, height.String())

var stdout, stderr bytes.Buffer

cmd.Stdout = &stdout
cmd.Stderr = &stderr

if err := cmd.Run(); err != nil {
log.Info("Exec output", "stdout", stdout.String(), "stderr", stderr.String())
return nil, err
}

wd, err := os.Getwd()
if err != nil {
return nil, err
}
outputPath := filepath.Join(wd, fmt.Sprintf("./block-%s_proof.json", height))

log.Info("Exec prover cmd finished", "outputPath", outputPath, "time", time.Since(start))

if _, err := os.Stat(outputPath); err != nil {
return nil, err
}

defer func() {
if err := os.Remove(outputPath); err != nil {
log.Warn("Remove prover cmd output file error", "error", err)
}
}()

outputJSONBytes, err := os.ReadFile(outputPath)
if err != nil {
return nil, err
}

var proverCmdOutput ProverCmdOutput
if err := json.Unmarshal(outputJSONBytes, &proverCmdOutput); err != nil {
return nil, err
}

return d.outputToCalldata(&proverCmdOutput), nil
}

func (d *ZkevmCmdProducer) outputToCalldata(output *ProverCmdOutput) []byte {
calldata := []byte{}
bufLen := len(output.Instances)*32 + len(output.Proof)

for i := 0; i < len(output.Instances); i++ {
uint256Bytes := [32]byte{}
evenHexLen := len(output.Instances[i]) - 2 + (len(output.Instances[i]) % 2)
instanceHex := output.Instances[i][2:]
if len(instanceHex) < evenHexLen {
instanceHex = strings.Repeat("0", evenHexLen-len(instanceHex)) + instanceHex
}
instanceBytes := common.Hex2Bytes(instanceHex)

for j := 0; j < len(instanceBytes); j++ {
uint256Bytes[31-j] = instanceBytes[len(instanceBytes)-1-j]
}
for k := 0; k < 32; k++ {
calldata = append(calldata, uint256Bytes[k])
}
}

for i := 0; i < len(output.Proof); i++ {
calldata = append(calldata, output.Proof...)
}

return calldata[:bufLen]
}
26 changes: 26 additions & 0 deletions prover/proof_producer/zkevm_cmd_producer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package producer

import (
"encoding/json"
"os"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
)

func TestZkevmCmdProducerOutputToCalldata(t *testing.T) {
output, err := os.ReadFile("../../testutils/testdata/block-5_proof.json")
require.Nil(t, err)

var (
testCalldataHexHash = common.HexToHash("0xfbc74eec1aa02cadd59cf2fdfb8c311b199a4f83d0046fd20a1a53081bb0de22")
proverCmdOutput ProverCmdOutput
)
require.Nil(t, json.Unmarshal(output, &proverCmdOutput))

calldata := new(ZkevmCmdProducer).outputToCalldata(&proverCmdOutput)

require.Equal(t, testCalldataHexHash, crypto.Keccak256Hash(calldata))
}
Loading

0 comments on commit 8c8ee9c

Please sign in to comment.