Skip to content

Commit

Permalink
cannon: Add support for --type mt to enable multithreaded cannon
Browse files Browse the repository at this point in the history
  • Loading branch information
ajsutton committed Aug 9, 2024
1 parent bf4693e commit 8b34c08
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 22 deletions.
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ cannon-prestate: op-program cannon ## Generates prestate using cannon and op-pro
mv op-program/bin/0.json op-program/bin/prestate-proof.json
.PHONY: cannon-prestate

cannon-prestate-mt: op-program cannon ## Generates prestate using cannon and op-program in the multithreaded cannon format
./cannon/bin/cannon load-elf --type mt --path op-program/bin/op-program-client.elf --out op-program/bin/prestate-mt.json --meta op-program/bin/meta-mt.json
./cannon/bin/cannon run --type mt --proof-at '=0' --stop-at '=1' --input op-program/bin/prestate-mt.json --meta op-program/bin/meta-mt.json --proof-fmt 'op-program/bin/%d-mt.json' --output ""
mv op-program/bin/0-mt.json op-program/bin/prestate-proof-mt.json
.PHONY: cannon-prestate

mod-tidy: ## Cleans up unused dependencies in Go modules
# Below GOPRIVATE line allows mod-tidy to be run immediately after
# releasing new versions. This bypasses the Go modules proxy, which
Expand Down
29 changes: 27 additions & 2 deletions cannon/cmd/load_elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"debug/elf"
"fmt"

"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded"
"github.com/urfave/cli/v2"

"github.com/ethereum-optimism/optimism/cannon/mipsevm/program"
Expand Down Expand Up @@ -39,6 +41,28 @@ var (
)

func LoadELF(ctx *cli.Context) error {
var createInitialState func(f *elf.File) (mipsevm.FPVMState, error)
var writeState func(path string, state mipsevm.FPVMState) error

if vmType, err := vmTypeFromString(ctx); err != nil {
return err
} else if vmType == cannonVMType {
createInitialState = func(f *elf.File) (mipsevm.FPVMState, error) {
return program.LoadELF(f, singlethreaded.CreateInitialState)
}
writeState = func(path string, state mipsevm.FPVMState) error {
return jsonutil.WriteJSON[*singlethreaded.State](path, state.(*singlethreaded.State), OutFilePerm)
}
} else if vmType == mtVMType {
createInitialState = func(f *elf.File) (mipsevm.FPVMState, error) {
return program.LoadELF(f, multithreaded.CreateInitialState)
}
writeState = func(path string, state mipsevm.FPVMState) error {
return jsonutil.WriteJSON[*multithreaded.State](path, state.(*multithreaded.State), OutFilePerm)
}
} else {
return fmt.Errorf("invalid VM type: %q", vmType)
}
elfPath := ctx.Path(LoadELFPathFlag.Name)
elfProgram, err := elf.Open(elfPath)
if err != nil {
Expand All @@ -47,7 +71,7 @@ func LoadELF(ctx *cli.Context) error {
if elfProgram.Machine != elf.EM_MIPS {
return fmt.Errorf("ELF is not big-endian MIPS R3000, but got %q", elfProgram.Machine.String())
}
state, err := program.LoadELF(elfProgram, singlethreaded.CreateInitialState)
state, err := createInitialState(elfProgram)
if err != nil {
return fmt.Errorf("failed to load ELF data into VM state: %w", err)
}
Expand All @@ -71,7 +95,7 @@ func LoadELF(ctx *cli.Context) error {
if err := jsonutil.WriteJSON[*program.Metadata](ctx.Path(LoadELFMetaFlag.Name), meta, OutFilePerm); err != nil {
return fmt.Errorf("failed to output metadata: %w", err)
}
return jsonutil.WriteJSON[*singlethreaded.State](ctx.Path(LoadELFOutFlag.Name), state, OutFilePerm)
return writeState(ctx.Path(LoadELFOutFlag.Name), state)
}

var LoadELFCommand = &cli.Command{
Expand All @@ -80,6 +104,7 @@ var LoadELFCommand = &cli.Command{
Description: "Load ELF file into Cannon JSON state, optionally patch out functions",
Action: LoadELF,
Flags: []cli.Flag{
VMTypeFlag,
LoadELFPathFlag,
LoadELFPatchFlag,
LoadELFOutFlag,
Expand Down
39 changes: 22 additions & 17 deletions cannon/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"strings"
"time"

"github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
Expand All @@ -24,13 +25,6 @@ import (
)

var (
RunType = &cli.StringFlag{
Name: "type",
Usage: "VM type to run. Options are 'cannon' (default)",
Value: "cannon",
// TODO(client-pod#903): This should be required once we have additional vm types
Required: false,
}
RunInputFlag = &cli.PathFlag{
Name: "input",
Usage: "path of input JSON state. Stdin if left empty.",
Expand Down Expand Up @@ -258,20 +252,14 @@ func Guard(proc *os.ProcessState, fn StepFn) StepFn {

var _ mipsevm.PreimageOracle = (*ProcessPreimageOracle)(nil)

type VMType string

var cannonVMType VMType = "cannon"

func Run(ctx *cli.Context) error {
if ctx.Bool(RunPProfCPU.Name) {
defer profile.Start(profile.NoShutdownHook, profile.ProfilePath("."), profile.CPUProfile).Stop()
}

var vmType VMType
if vmTypeStr := ctx.String(RunType.Name); vmTypeStr == string(cannonVMType) {
vmType = cannonVMType
} else {
return fmt.Errorf("unknown VM type %q", vmType)
vmType, err := vmTypeFromString(ctx)
if err != nil {
return err
}

guestLogger := Logger(os.Stderr, log.LevelInfo)
Expand Down Expand Up @@ -366,6 +354,7 @@ func Run(ctx *cli.Context) error {
var vm mipsevm.FPVM
var debugProgram bool
if vmType == cannonVMType {
l.Info("Using cannon VM")
cannon, err := singlethreaded.NewInstrumentedStateFromFile(ctx.Path(RunInputFlag.Name), po, outLog, errLog, meta)
if err != nil {
return err
Expand All @@ -380,6 +369,22 @@ func Run(ctx *cli.Context) error {
}
}
vm = cannon
} else if vmType == mtVMType {
l.Info("Using cannon multithreaded VM")
cannon, err := multithreaded.NewInstrumentedStateFromFile(ctx.Path(RunInputFlag.Name), po, outLog, errLog, l)
if err != nil {
return err
}
debugProgram = ctx.Bool(RunDebugFlag.Name)
if debugProgram {
if metaPath := ctx.Path(RunMetaFlag.Name); metaPath == "" {
return fmt.Errorf("cannot enable debug mode without a metadata file")
}
if err := cannon.InitDebug(meta); err != nil {
return fmt.Errorf("failed to initialize debug mode: %w", err)
}
}
vm = cannon
} else {
return fmt.Errorf("unknown VM type %q", vmType)
}
Expand Down Expand Up @@ -503,7 +508,7 @@ var RunCommand = &cli.Command{
Description: "Run VM step(s) and generate proof data to replicate onchain. See flags to match when to output a proof, a snapshot, or to stop early.",
Action: Run,
Flags: []cli.Flag{
RunType,
VMTypeFlag,
RunInputFlag,
RunOutputFlag,
RunProofAtFlag,
Expand Down
29 changes: 29 additions & 0 deletions cannon/cmd/vmtype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cmd

import (
"fmt"

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

type VMType string

var cannonVMType VMType = "cannon"
var mtVMType VMType = "mt"

var VMTypeFlag = &cli.StringFlag{
Name: "type",
Usage: "VM type to create state for. Options are 'cannon' (default), 'mt'",
Value: "cannon",
Required: false,
}

func vmTypeFromString(ctx *cli.Context) (VMType, error) {
if vmTypeStr := ctx.String(VMTypeFlag.Name); vmTypeStr == string(cannonVMType) {
return cannonVMType, nil
} else if vmTypeStr == string(mtVMType) {
return mtVMType, nil
} else {
return "", fmt.Errorf("unknown VM type %q", vmTypeStr)
}
}
22 changes: 19 additions & 3 deletions cannon/cmd/witness.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"os"

"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded"
"github.com/urfave/cli/v2"

"github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded"
Expand All @@ -27,10 +29,23 @@ var (
func Witness(ctx *cli.Context) error {
input := ctx.Path(WitnessInputFlag.Name)
output := ctx.Path(WitnessOutputFlag.Name)
state, err := jsonutil.LoadJSON[singlethreaded.State](input)
if err != nil {
return fmt.Errorf("invalid input state (%v): %w", input, err)
var state mipsevm.FPVMState
if vmType, err := vmTypeFromString(ctx); err != nil {
return err
} else if vmType == cannonVMType {
state, err = jsonutil.LoadJSON[singlethreaded.State](input)
if err != nil {
return fmt.Errorf("invalid input state (%v): %w", input, err)
}
} else if vmType == mtVMType {
state, err = jsonutil.LoadJSON[multithreaded.State](input)
if err != nil {
return fmt.Errorf("invalid input state (%v): %w", input, err)
}
} else {
return fmt.Errorf("invalid VM type: %q", vmType)
}

witness, h := state.EncodeWitness()
if output != "" {
if err := os.WriteFile(output, witness, 0755); err != nil {
Expand All @@ -47,6 +62,7 @@ var WitnessCommand = &cli.Command{
Description: "Convert a Cannon JSON state into a binary witness. The hash of the witness is written to stdout",
Action: Witness,
Flags: []cli.Flag{
VMTypeFlag,
WitnessInputFlag,
WitnessOutputFlag,
},
Expand Down

0 comments on commit 8b34c08

Please sign in to comment.