refactor prove/setup args (#288)

* refactor prove/setup args

* refac contain global variables in the main package

* refactor eliminate unnecessary arguments
This commit is contained in:
Arya Tabaie
2024-11-19 15:47:55 -06:00
committed by GitHub
parent 93366e5b02
commit 0615fa37b9
4 changed files with 131 additions and 129 deletions

View File

@@ -12,68 +12,53 @@ import (
"github.com/consensys/linea-monorepo/prover/backend/execution"
"github.com/consensys/linea-monorepo/prover/backend/files"
"github.com/consensys/linea-monorepo/prover/config"
"github.com/spf13/cobra"
)
var (
fInput string
fOutput string
fLarge bool
)
// proveCmd represents the prove command
var proveCmd = &cobra.Command{
Use: "prove",
Short: "prove process a request, creates a proof with the adequate circuit and writes the proof to a file",
RunE: cmdProve,
type ProverArgs struct {
Input string
Output string
Large bool
ConfigFile string
}
func init() {
rootCmd.AddCommand(proveCmd)
proveCmd.Flags().StringVar(&fInput, "in", "", "input file")
proveCmd.Flags().StringVar(&fOutput, "out", "", "output file")
proveCmd.Flags().BoolVar(&fLarge, "large", false, "run the large execution circuit")
}
func cmdProve(cmd *cobra.Command, args []string) error {
func Prove(args ProverArgs) error {
const cmdName = "prove"
// TODO @gbotrel with a specific flag, we could compile the circuit and compare with the checksum of the
// asset we deserialize, to make sure we are using the circuit associated with the compiled binary and the setup.
// read config
cfg, err := config.NewConfigFromFile(fConfigFile)
cfg, err := config.NewConfigFromFile(args.ConfigFile)
if err != nil {
return fmt.Errorf("%s failed to read config file: %w", cmd.Name(), err)
return fmt.Errorf("%s failed to read config file: %w", cmdName, err)
}
// discover the type of the job from the input file name
jobExecution := strings.Contains(fInput, "getZkProof")
jobBlobDecompression := strings.Contains(fInput, "getZkBlobCompressionProof")
jobAggregation := strings.Contains(fInput, "getZkAggregatedProof")
jobExecution := strings.Contains(args.Input, "getZkProof")
jobBlobDecompression := strings.Contains(args.Input, "getZkBlobCompressionProof")
jobAggregation := strings.Contains(args.Input, "getZkAggregatedProof")
if jobExecution {
req := &execution.Request{}
if err := readRequest(fInput, req); err != nil {
return fmt.Errorf("could not read the input file (%v): %w", fInput, err)
if err := readRequest(args.Input, req); err != nil {
return fmt.Errorf("could not read the input file (%v): %w", args.Input, err)
}
// we use the large traces in 2 cases;
// 1. the user explicitly asked for it (fLarge)
// 1. the user explicitly asked for it (args.Large)
// 2. the job contains the large suffix and we are a large machine (cfg.Execution.CanRunLarge)
large := fLarge || (strings.Contains(fInput, "large") && cfg.Execution.CanRunFullLarge)
large := args.Large || (strings.Contains(args.Input, "large") && cfg.Execution.CanRunFullLarge)
resp, err := execution.Prove(cfg, req, large)
if err != nil {
return fmt.Errorf("could not prove the execution: %w", err)
}
return writeResponse(fOutput, resp)
return writeResponse(args.Output, resp)
}
if jobBlobDecompression {
req := &blobdecompression.Request{}
if err := readRequest(fInput, req); err != nil {
return fmt.Errorf("could not read the input file (%v): %w", fInput, err)
if err := readRequest(args.Input, req); err != nil {
return fmt.Errorf("could not read the input file (%v): %w", args.Input, err)
}
resp, err := blobdecompression.Prove(cfg, req)
@@ -81,13 +66,13 @@ func cmdProve(cmd *cobra.Command, args []string) error {
return fmt.Errorf("could not prove the blob decompression: %w", err)
}
return writeResponse(fOutput, resp)
return writeResponse(args.Output, resp)
}
if jobAggregation {
req := &aggregation.Request{}
if err := readRequest(fInput, req); err != nil {
return fmt.Errorf("could not read the input file (%v): %w", fInput, err)
if err := readRequest(args.Input, req); err != nil {
return fmt.Errorf("could not read the input file (%v): %w", args.Input, err)
}
resp, err := aggregation.Prove(cfg, req)
@@ -95,7 +80,7 @@ func cmdProve(cmd *cobra.Command, args []string) error {
return fmt.Errorf("could not prove the aggregation: %w", err)
}
return writeResponse(fOutput, resp)
return writeResponse(args.Output, resp)
}
return errors.New("unknown job type")

View File

@@ -1,36 +0,0 @@
package cmd
import (
"os"
"github.com/consensys/gnark/logger"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
)
var fConfigFile string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "prover",
Short: "run pre-compute or compute proofs for Linea circuits",
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
rootCmd.PersistentFlags().StringVar(&fConfigFile, "config", "", "config file")
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "15:04:05", NoColor: true}
l := zerolog.New(output).With().Timestamp().Logger()
// Set global log level for gnark
logger.Set(l)
}

View File

@@ -16,6 +16,7 @@ import (
"github.com/sirupsen/logrus"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/plonk"
"github.com/consensys/linea-monorepo/prover/circuits"
"github.com/consensys/linea-monorepo/prover/circuits/aggregation"
v0 "github.com/consensys/linea-monorepo/prover/circuits/blobdecompression/v0"
@@ -26,27 +27,17 @@ import (
"github.com/consensys/linea-monorepo/prover/config"
"github.com/consensys/linea-monorepo/prover/utils"
"github.com/consensys/linea-monorepo/prover/zkevm"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/consensys/gnark/backend/plonk"
)
var (
fForce bool
fCircuits string
fDictPath string
fAssetsDir string
)
// setupCmd represents the setup command
var setupCmd = &cobra.Command{
Use: "setup",
Short: "pre compute assets for Linea circuits",
RunE: cmdSetup,
type SetupArgs struct {
Force bool
Circuits string
DictPath string
AssetsDir string
ConfigFile string
}
var allCircuits = []string{
var AllCircuits = []string{
string(circuits.ExecutionCircuitID),
string(circuits.ExecutionLargeCircuitID),
string(circuits.BlobDecompressionV0CircuitID),
@@ -57,39 +48,30 @@ var allCircuits = []string{
string(circuits.EmulationDummyCircuitID), // we want to generate Verifier.sol for this one
}
func init() {
rootCmd.AddCommand(setupCmd)
setupCmd.Flags().BoolVar(&fForce, "force", false, "overwrites existing files")
setupCmd.Flags().StringVar(&fCircuits, "circuits", strings.Join(allCircuits, ","), "comma separated list of circuits to setup")
setupCmd.Flags().StringVar(&fDictPath, "dict", "", "path to the dictionary file used in blob (de)compression")
setupCmd.Flags().StringVar(&fAssetsDir, "assets-dir", "", "path to the directory where the assets are stored (override conf)")
viper.BindPFlag("assets_dir", setupCmd.Flags().Lookup("assets-dir"))
}
func cmdSetup(cmd *cobra.Command, args []string) error {
func Setup(context context.Context, args SetupArgs) error {
const cmdName = "setup"
// read config
cfg, err := config.NewConfigFromFile(fConfigFile)
cfg, err := config.NewConfigFromFile(args.ConfigFile)
if err != nil {
return fmt.Errorf("%s failed to read config file: %w", cmd.Name(), err)
return fmt.Errorf("%s failed to read config file: %w", cmdName, err)
}
if fDictPath != "" {
if args.DictPath != "" {
// fail early if the dictionary file is not found but was specified.
if _, err := os.Stat(fDictPath); err != nil {
return fmt.Errorf("%s dictionary file not found: %w", cmd.Name(), err)
if _, err := os.Stat(args.DictPath); err != nil {
return fmt.Errorf("%s dictionary file not found: %w", cmdName, err)
}
}
// parse inCircuits
inCircuits := make(map[circuits.CircuitID]bool)
for _, c := range allCircuits {
for _, c := range AllCircuits {
inCircuits[circuits.CircuitID(c)] = false
}
_inCircuits := strings.Split(fCircuits, ",")
_inCircuits := strings.Split(args.Circuits, ",")
for _, c := range _inCircuits {
if _, ok := inCircuits[circuits.CircuitID(c)]; !ok {
return fmt.Errorf("%s unknown circuit: %s", cmd.Name(), c)
return fmt.Errorf("%s unknown circuit: %s", cmdName, c)
}
inCircuits[circuits.CircuitID(c)] = true
}
@@ -101,7 +83,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
var srsProvider circuits.SRSProvider
srsProvider, err = circuits.NewSRSStore(cfg.PathForSRS())
if err != nil {
return fmt.Errorf("%s failed to create SRS provider: %w", cmd.Name(), err)
return fmt.Errorf("%s failed to create SRS provider: %w", cmdName, err)
}
// for each circuit, we start by compiling the circuit
@@ -128,9 +110,9 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
zkEvm := zkevm.FullZkEvm(&limits)
builder = execution.NewBuilder(zkEvm)
case circuits.BlobDecompressionV0CircuitID, circuits.BlobDecompressionV1CircuitID:
dict, err = os.ReadFile(fDictPath)
dict, err = os.ReadFile(args.DictPath)
if err != nil {
return fmt.Errorf("%s failed to read dictionary file: %w", cmd.Name(), err)
return fmt.Errorf("%s failed to read dictionary file: %w", cmdName, err)
}
if c == circuits.BlobDecompressionV0CircuitID {
@@ -151,14 +133,14 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
continue // dummy, aggregation, emulation or public input circuits are handled later
}
if err := updateSetup(cmd.Context(), cfg, srsProvider, c, builder, extraFlags); err != nil {
if err := updateSetup(context, cfg, args.Force, srsProvider, c, builder, extraFlags); err != nil {
return err
}
if dict != nil {
// we save the dictionary to disk
dictPath := filepath.Join(cfg.PathForSetup(string(c)), config.DictionaryFileName)
if err := os.WriteFile(dictPath, dict, 0600); err != nil {
return fmt.Errorf("%s failed to write dictionary file: %w", cmd.Name(), err)
return fmt.Errorf("%s failed to write dictionary file: %w", cmdName, err)
}
}
@@ -172,7 +154,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
// get verifying key for public-input circuit
piSetup, err := circuits.LoadSetup(cfg, circuits.PublicInputInterconnectionCircuitID)
if err != nil {
return fmt.Errorf("%s failed to load public input interconnection setup: %w", cmd.Name(), err)
return fmt.Errorf("%s failed to load public input interconnection setup: %w", cmdName, err)
}
// first, we need to collect the verifying keys
@@ -196,7 +178,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
return fmt.Errorf("unknown dummy circuit: %s", allowedInput)
}
vk, err := getDummyCircuitVK(cmd.Context(), cfg, srsProvider, circuits.CircuitID(allowedInput), dummy.NewBuilder(mockID, curveID.ScalarField()))
vk, err := getDummyCircuitVK(context, cfg, srsProvider, circuits.CircuitID(allowedInput), dummy.NewBuilder(mockID, curveID.ScalarField()))
if err != nil {
return err
}
@@ -209,7 +191,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
vkPath := filepath.Join(setupPath, config.VerifyingKeyFileName)
vk := plonk.NewVerifyingKey(ecc.BLS12_377)
if err := circuits.ReadVerifyingKey(vkPath, vk); err != nil {
return fmt.Errorf("%s failed to read verifying key for circuit %s: %w", cmd.Name(), allowedInput, err)
return fmt.Errorf("%s failed to read verifying key for circuit %s: %w", cmdName, allowedInput, err)
}
allowedVkForAggregation = append(allowedVkForAggregation, vk)
@@ -217,7 +199,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
// we need to compute the digest of the verifying keys & store them in the manifest
// for the aggregation circuits to be able to check compatibility at run time with the proofs
allowedVkForAggregationDigests := listOfCheckum(allowedVkForAggregation)
allowedVkForAggregationDigests := listOfChecksums(allowedVkForAggregation)
extraFlagsForAggregationCircuit := map[string]any{
"allowedVkForAggregationDigests": allowedVkForAggregationDigests,
}
@@ -229,7 +211,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
logrus.Infof("setting up %s (numProofs=%d)", c, numProofs)
builder := aggregation.NewBuilder(numProofs, cfg.Aggregation.AllowedInputs, piSetup, allowedVkForAggregation)
if err := updateSetup(cmd.Context(), cfg, srsProvider, c, builder, extraFlagsForAggregationCircuit); err != nil {
if err := updateSetup(context, cfg, args.Force, srsProvider, c, builder, extraFlagsForAggregationCircuit); err != nil {
return err
}
@@ -238,7 +220,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
vkPath := filepath.Join(setupPath, config.VerifyingKeyFileName)
vk := plonk.NewVerifyingKey(ecc.BW6_761)
if err := circuits.ReadVerifyingKey(vkPath, vk); err != nil {
return fmt.Errorf("%s failed to read verifying key for circuit %s: %w", cmd.Name(), c, err)
return fmt.Errorf("%s failed to read verifying key for circuit %s: %w", cmdName, c, err)
}
allowedVkForEmulation = append(allowedVkForEmulation, vk)
@@ -248,7 +230,7 @@ func cmdSetup(cmd *cobra.Command, args []string) error {
c := circuits.EmulationCircuitID
logrus.Infof("setting up %s", c)
builder := emulation.NewBuilder(allowedVkForEmulation)
return updateSetup(cmd.Context(), cfg, srsProvider, c, builder, nil)
return updateSetup(context, cfg, args.Force, srsProvider, c, builder, nil)
}
@@ -281,7 +263,7 @@ func getDummyCircuitVK(ctx context.Context, cfg *config.Config, srsProvider circ
// and if so, if the checksums match.
// if the files already exist and the checksums match, it skips the setup.
// else it does the setup and writes the assets to disk.
func updateSetup(ctx context.Context, cfg *config.Config, srsProvider circuits.SRSProvider, circuit circuits.CircuitID, builder circuits.Builder, extraFlags map[string]any) error {
func updateSetup(ctx context.Context, cfg *config.Config, force bool, srsProvider circuits.SRSProvider, circuit circuits.CircuitID, builder circuits.Builder, extraFlags map[string]any) error {
if extraFlags == nil {
extraFlags = make(map[string]any)
}
@@ -297,7 +279,7 @@ func updateSetup(ctx context.Context, cfg *config.Config, srsProvider circuits.S
setupPath := cfg.PathForSetup(string(circuit))
manifestPath := filepath.Join(setupPath, config.ManifestFileName)
if !fForce {
if !force {
// we may want to skip setup if the files already exist
// and the checksums match
// read manifest if already exists
@@ -325,12 +307,13 @@ func updateSetup(ctx context.Context, cfg *config.Config, srsProvider circuits.S
return setup.WriteTo(setupPath)
}
// listOfCheckum Computes a list of SHA256 checksums for a list of assets, the result is given
// listOfChecksums Computes a list of SHA256 checksums for a list of assets, the result is given
// in hexstring.
func listOfCheckum[T io.WriterTo](assets []T) []string {
func listOfChecksums[T io.WriterTo](assets []T) []string {
res := make([]string, len(assets))
h := sha256.New()
for i := range assets {
h := sha256.New()
h.Reset()
_, err := assets[i].WriteTo(h)
if err != nil {
// It is unexpected that writing in a hasher could possibly fail.

View File

@@ -1,7 +1,77 @@
package main
import "github.com/consensys/linea-monorepo/prover/cmd/prover/cmd"
import (
"github.com/consensys/gnark/logger"
"github.com/consensys/linea-monorepo/prover/cmd/prover/cmd"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"os"
"strings"
)
var (
// rootCmd represents the base command when called without any subcommands
rootCmd = &cobra.Command{
Use: "prover",
Short: "run pre-compute or compute proofs for Linea circuits",
}
fConfigFile string
// setupCmd represents the setup command
setupCmd = &cobra.Command{
Use: "setup",
Short: "pre compute assets for Linea circuits",
RunE: cmdSetup,
}
setupArgs cmd.SetupArgs
// proveCmd represents the prove command
proveCmd = &cobra.Command{
Use: "prove",
Short: "prove process a request, creates a proof with the adequate circuit and writes the proof to a file",
RunE: cmdProve,
}
proverArgs cmd.ProverArgs
)
func main() {
cmd.Execute()
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
rootCmd.PersistentFlags().StringVar(&fConfigFile, "config", "", "config file")
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: "15:04:05", NoColor: true}
l := zerolog.New(output).With().Timestamp().Logger()
// Set global log level for gnark
logger.Set(l)
rootCmd.AddCommand(setupCmd)
setupCmd.Flags().BoolVar(&setupArgs.Force, "force", false, "overwrites existing files")
setupCmd.Flags().StringVar(&setupArgs.Circuits, "circuits", strings.Join(cmd.AllCircuits, ","), "comma separated list of circuits to setup")
setupCmd.Flags().StringVar(&setupArgs.DictPath, "dict", "", "path to the dictionary file used in blob (de)compression")
setupCmd.Flags().StringVar(&setupArgs.AssetsDir, "assets-dir", "", "path to the directory where the assets are stored (override conf)")
viper.BindPFlag("assets_dir", setupCmd.Flags().Lookup("assets-dir"))
rootCmd.AddCommand(proveCmd)
proveCmd.Flags().StringVar(&proverArgs.Input, "in", "", "input file")
proveCmd.Flags().StringVar(&proverArgs.Output, "out", "", "output file")
proveCmd.Flags().BoolVar(&proverArgs.Large, "large", false, "run the large execution circuit")
}
func cmdSetup(_cmd *cobra.Command, _ []string) error {
setupArgs.ConfigFile = fConfigFile
return cmd.Setup(_cmd.Context(), setupArgs)
}
func cmdProve(*cobra.Command, []string) error {
proverArgs.ConfigFile = fConfigFile
return cmd.Prove(proverArgs)
}