From 7a015d46c2a36495c0dffc4521d529989390276d Mon Sep 17 00:00:00 2001 From: Tei Im Date: Wed, 7 Feb 2024 14:27:48 +0900 Subject: [PATCH] Remove cannon dependencies --- go.mod | 2 +- go.sum | 4 +- rvgo/cmd/load_elf.go | 4 +- rvgo/cmd/log.go | 56 +++++++++++++ rvgo/cmd/process_preimage_oracle.go | 120 ++++++++++++++++++++++++++++ rvgo/cmd/run.go | 25 +++--- rvgo/cmd/witness.go | 3 +- 7 files changed, 197 insertions(+), 17 deletions(-) create mode 100644 rvgo/cmd/log.go create mode 100644 rvgo/cmd/process_preimage_oracle.go diff --git a/go.mod b/go.mod index dce94bd9..65a3df82 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 toolchain go1.21.1 // dev -replace github.com/ethereum-optimism/optimism v1.5.0-rc.3.0.20240131040122-c874ecc9f195 => github.com/testinprod-io/optimism v0.2.1-0.20240205073531-4904d6a711dc +replace github.com/ethereum-optimism/optimism v1.5.0-rc.3.0.20240131040122-c874ecc9f195 => github.com/testinprod-io/optimism v0.2.1-0.20240207052458-cb3cb29a1a0b replace github.com/ethereum/go-ethereum v1.13.5 => github.com/ethereum-optimism/op-geth v1.101305.3-rc.2.0.20240130011842-33cb3315f498 diff --git a/go.sum b/go.sum index d06090df..e15ad336 100644 --- a/go.sum +++ b/go.sum @@ -198,8 +198,8 @@ github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbe github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/testinprod-io/optimism v0.2.1-0.20240205073531-4904d6a711dc h1:XSeA1e7AozzChNWEImuHmYY0UgAGFmsOU9wFUhbfAjA= -github.com/testinprod-io/optimism v0.2.1-0.20240205073531-4904d6a711dc/go.mod h1:oYNJlRzj4BcANKRyYDfvEWdM3b+X/9nOfx6/KlWP0yg= +github.com/testinprod-io/optimism v0.2.1-0.20240207052458-cb3cb29a1a0b h1:n0gf6QU3PBSNqfHR+ZqAm5FqHPDouIvdCJQdG6Djdto= +github.com/testinprod-io/optimism v0.2.1-0.20240207052458-cb3cb29a1a0b/go.mod h1:oYNJlRzj4BcANKRyYDfvEWdM3b+X/9nOfx6/KlWP0yg= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= diff --git a/rvgo/cmd/load_elf.go b/rvgo/cmd/load_elf.go index d51b9e84..2e97c9bc 100644 --- a/rvgo/cmd/load_elf.go +++ b/rvgo/cmd/load_elf.go @@ -3,8 +3,8 @@ package cmd import ( "debug/elf" "fmt" - cannon "github.com/ethereum-optimism/optimism/cannon/cmd" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" "github.com/urfave/cli/v2" "github.com/ethereum-optimism/asterisc/rvgo/fast" @@ -27,7 +27,7 @@ func LoadELF(ctx *cli.Context) error { if err != nil { return fmt.Errorf("failed to patch VM") } - return cannon.WriteJSON[*fast.VMState](ctx.Path(cannon.LoadELFOutFlag.Name), state) + return jsonutil.WriteJSON[*fast.VMState](ctx.Path(cannon.LoadELFOutFlag.Name), state, OutFilePerm) } var LoadELFCommand = &cli.Command{ diff --git a/rvgo/cmd/log.go b/rvgo/cmd/log.go new file mode 100644 index 00000000..2a81599b --- /dev/null +++ b/rvgo/cmd/log.go @@ -0,0 +1,56 @@ +package cmd + +import ( + "fmt" + "io" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/log" +) + +func Logger(w io.Writer, lvl log.Lvl) log.Logger { + h := log.StreamHandler(w, log.LogfmtFormat()) + h = log.SyncHandler(h) + h = log.LvlFilterHandler(lvl, h) + l := log.New() + l.SetHandler(h) + return l +} + +// LoggingWriter is a simple util to wrap a logger, +// and expose an io Writer interface, +// for the program running within the VM to write to. +type LoggingWriter struct { + Name string + Log log.Logger +} + +func logAsText(b string) bool { + for _, c := range b { + if (c < 0x20 || c >= 0x7F) && (c != '\n' && c != '\t') { + return false + } + } + return true +} + +func (lw *LoggingWriter) Write(b []byte) (int, error) { + t := string(b) + if logAsText(t) { + lw.Log.Info("", "text", t) + } else { + lw.Log.Info("", "data", hexutil.Bytes(b)) + } + return len(b), nil +} + +// HexU32 to lazy-format integer attributes for logging +type HexU32 uint32 + +func (v HexU32) String() string { + return fmt.Sprintf("%08x", uint32(v)) +} + +func (v HexU32) MarshalText() ([]byte, error) { + return []byte(v.String()), nil +} diff --git a/rvgo/cmd/process_preimage_oracle.go b/rvgo/cmd/process_preimage_oracle.go new file mode 100644 index 00000000..864e3256 --- /dev/null +++ b/rvgo/cmd/process_preimage_oracle.go @@ -0,0 +1,120 @@ +package cmd + +import ( + "context" + "fmt" + "os" + "os/exec" + "time" + + preimage "github.com/ethereum-optimism/optimism/op-preimage" +) + +type rawHint string + +func (rh rawHint) Hint() string { + return string(rh) +} + +type rawKey [32]byte + +func (rk rawKey) PreimageKey() [32]byte { + return rk +} + +type ProcessPreimageOracle struct { + pCl *preimage.OracleClient + hCl *preimage.HintWriter + cmd *exec.Cmd + waitErr chan error + cancelIO context.CancelCauseFunc +} + +const clientPollTimeout = time.Second * 15 + +func NewProcessPreimageOracle(name string, args []string) (*ProcessPreimageOracle, error) { + if name == "" { + return &ProcessPreimageOracle{}, nil + } + + pClientRW, pOracleRW, err := preimage.CreateBidirectionalChannel() + if err != nil { + return nil, err + } + hClientRW, hOracleRW, err := preimage.CreateBidirectionalChannel() + if err != nil { + return nil, err + } + + cmd := exec.Command(name, args...) // nosemgrep + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.ExtraFiles = []*os.File{ + hOracleRW.Reader(), + hOracleRW.Writer(), + pOracleRW.Reader(), + pOracleRW.Writer(), + } + + // Note that the client file descriptors are not closed when the pre-image server exits. + // So we use the FilePoller to ensure that we don't get stuck in a blocking read/write. + ctx, cancelIO := context.WithCancelCause(context.Background()) + preimageClientIO := preimage.NewFilePoller(ctx, pClientRW, clientPollTimeout) + hostClientIO := preimage.NewFilePoller(ctx, hClientRW, clientPollTimeout) + out := &ProcessPreimageOracle{ + pCl: preimage.NewOracleClient(preimageClientIO), + hCl: preimage.NewHintWriter(hostClientIO), + cmd: cmd, + waitErr: make(chan error), + cancelIO: cancelIO, + } + return out, nil +} + +func (p *ProcessPreimageOracle) Hint(v []byte) { + if p.hCl == nil { // no hint processor + return + } + p.hCl.Hint(rawHint(v)) +} + +func (p *ProcessPreimageOracle) GetPreimage(k [32]byte) []byte { + if p.pCl == nil { + panic("no pre-image retriever available") + } + return p.pCl.Get(rawKey(k)) +} + +func (p *ProcessPreimageOracle) GetCmd() *exec.Cmd { + return p.cmd +} + +func (p *ProcessPreimageOracle) Start() error { + if p.cmd == nil { + return nil + } + err := p.cmd.Start() + go p.wait() + return err +} + +func (p *ProcessPreimageOracle) Close() error { + if p.cmd == nil { + return nil + } + // Give the pre-image server time to exit cleanly before killing it. + time.Sleep(time.Second * 1) + _ = p.cmd.Process.Signal(os.Interrupt) + return <-p.waitErr +} + +func (p *ProcessPreimageOracle) wait() { + err := p.cmd.Wait() + var waitErr error + if err, ok := err.(*exec.ExitError); !ok || !err.Success() { + waitErr = err + } + p.cancelIO(fmt.Errorf("%w: pre-image server has exited", waitErr)) + p.waitErr <- waitErr + close(p.waitErr) +} diff --git a/rvgo/cmd/run.go b/rvgo/cmd/run.go index d37ee393..011951bd 100644 --- a/rvgo/cmd/run.go +++ b/rvgo/cmd/run.go @@ -14,6 +14,7 @@ import ( cannon "github.com/ethereum-optimism/optimism/cannon/cmd" preimage "github.com/ethereum-optimism/optimism/op-preimage" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" "github.com/ethereum-optimism/asterisc/rvgo/fast" ) @@ -48,21 +49,23 @@ func Guard(proc *os.ProcessState, fn StepFn) StepFn { } } -var _ fast.PreimageOracle = (*cannon.ProcessPreimageOracle)(nil) +var _ fast.PreimageOracle = (*ProcessPreimageOracle)(nil) + +var OutFilePerm = os.FileMode(0o755) func Run(ctx *cli.Context) error { if ctx.Bool(cannon.RunPProfCPU.Name) { defer profile.Start(profile.NoShutdownHook, profile.ProfilePath("."), profile.CPUProfile).Stop() } - state, err := cannon.LoadJSON[fast.VMState](ctx.Path(cannon.RunInputFlag.Name)) + state, err := jsonutil.LoadJSON[fast.VMState](ctx.Path(cannon.RunInputFlag.Name)) if err != nil { return err } - l := cannon.Logger(os.Stderr, log.LvlInfo) - outLog := &cannon.LoggingWriter{Name: "program std-out", Log: l} - errLog := &cannon.LoggingWriter{Name: "program std-err", Log: l} + l := Logger(os.Stderr, log.LvlInfo) + outLog := &LoggingWriter{Name: "program std-out", Log: l} + errLog := &LoggingWriter{Name: "program std-err", Log: l} stopAtPreimageType := ctx.String(cannon.RunStopAtPreimageTypeFlag.Name) if stopAtPreimageType != "" && stopAtPreimageType != "any" && stopAtPreimageType != "local" && stopAtPreimageType != "global" { @@ -82,7 +85,7 @@ func Run(ctx *cli.Context) error { args = []string{""} } - po, err := cannon.NewProcessPreimageOracle(args[0], args[1:]) + po, err := NewProcessPreimageOracle(args[0], args[1:]) if err != nil { return fmt.Errorf("failed to create pre-image oracle process: %w", err) } @@ -126,8 +129,8 @@ func Run(ctx *cli.Context) error { delta := time.Since(start) l.Info("processing", "step", step, - "pc", cannon.HexU32(state.PC), - "insn", cannon.HexU32(state.Instr()), + "pc", HexU32(state.PC), + "insn", HexU32(state.Instr()), "ips", float64(step-startStep)/(float64(delta)/float64(time.Second)), "pages", state.Memory.PageCount(), "mem", state.Memory.Usage(), @@ -139,7 +142,7 @@ func Run(ctx *cli.Context) error { } if snapshotAt(state) { - if err := cannon.WriteJSON(fmt.Sprintf(snapshotFmt, step), state); err != nil { + if err := jsonutil.WriteJSON(fmt.Sprintf(snapshotFmt, step), state, OutFilePerm); err != nil { return fmt.Errorf("failed to write state snapshot: %w", err) } } @@ -171,7 +174,7 @@ func Run(ctx *cli.Context) error { proof.OracleValue = witness.PreimageValue proof.OracleOffset = witness.PreimageOffset } - if err := cannon.WriteJSON(fmt.Sprintf(proofFmt, step), proof); err != nil { + if err := jsonutil.WriteJSON(fmt.Sprintf(proofFmt, step), proof, OutFilePerm); err != nil { return fmt.Errorf("failed to write proof data: %w", err) } } else { @@ -200,7 +203,7 @@ func Run(ctx *cli.Context) error { } } - if err := cannon.WriteJSON(ctx.Path(cannon.RunOutputFlag.Name), state); err != nil { + if err := jsonutil.WriteJSON(ctx.Path(cannon.RunOutputFlag.Name), state, OutFilePerm); err != nil { return fmt.Errorf("failed to write state output: %w", err) } return nil diff --git a/rvgo/cmd/witness.go b/rvgo/cmd/witness.go index c66c9c21..c1118105 100644 --- a/rvgo/cmd/witness.go +++ b/rvgo/cmd/witness.go @@ -5,6 +5,7 @@ import ( "os" cannon "github.com/ethereum-optimism/optimism/cannon/cmd" + "github.com/ethereum-optimism/optimism/op-service/jsonutil" "github.com/urfave/cli/v2" "github.com/ethereum-optimism/asterisc/rvgo/fast" @@ -13,7 +14,7 @@ import ( func Witness(ctx *cli.Context) error { input := ctx.Path(cannon.WitnessInputFlag.Name) output := ctx.Path(cannon.WitnessOutputFlag.Name) - state, err := cannon.LoadJSON[fast.VMState](input) + state, err := jsonutil.LoadJSON[fast.VMState](input) if err != nil { return fmt.Errorf("invalid input state (%v): %w", input, err) }