Commit 368c1332 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger: Use witness subcommand instead of parsing cannon states (#12141)

* op-challenger: Use the cannon witness subcommand to read states instead of directly calling the parsing code.

* op-challenger: Use a context when downloading the prestate.
parent c8afa158
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum-optimism/optimism/op-service/jsonutil" "github.com/ethereum-optimism/optimism/op-service/jsonutil"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
...@@ -26,10 +27,11 @@ var ( ...@@ -26,10 +27,11 @@ var (
) )
type response struct { type response struct {
WitnessHash common.Hash `json:"witnessHash"` WitnessHash common.Hash `json:"witnessHash"`
Step uint64 `json:"step"` Witness hexutil.Bytes `json:"witness"`
Exited bool `json:"exited"` Step uint64 `json:"step"`
ExitCode uint8 `json:"exitCode"` Exited bool `json:"exited"`
ExitCode uint8 `json:"exitCode"`
} }
func Witness(ctx *cli.Context) error { func Witness(ctx *cli.Context) error {
...@@ -47,6 +49,7 @@ func Witness(ctx *cli.Context) error { ...@@ -47,6 +49,7 @@ func Witness(ctx *cli.Context) error {
} }
output := response{ output := response{
WitnessHash: h, WitnessHash: h,
Witness: witness,
Step: state.GetStep(), Step: state.GetStep(),
Exited: state.GetExited(), Exited: state.GetExited(),
ExitCode: state.GetExitCode(), ExitCode: state.GetExitCode(),
......
...@@ -35,7 +35,7 @@ type PrestateSource interface { ...@@ -35,7 +35,7 @@ type PrestateSource interface {
// PrestatePath returns the path to the prestate file to use for the game. // PrestatePath returns the path to the prestate file to use for the game.
// The provided prestateHash may be used to differentiate between different states but no guarantee is made that // The provided prestateHash may be used to differentiate between different states but no guarantee is made that
// the returned prestate matches the supplied hash. // the returned prestate matches the supplied hash.
PrestatePath(prestateHash common.Hash) (string, error) PrestatePath(ctx context.Context, prestateHash common.Hash) (string, error)
} }
type RollupClient interface { type RollupClient interface {
......
...@@ -33,7 +33,7 @@ type RegisterTask struct { ...@@ -33,7 +33,7 @@ type RegisterTask struct {
gameType faultTypes.GameType gameType faultTypes.GameType
skipPrestateValidation bool skipPrestateValidation bool
getPrestateProvider func(prestateHash common.Hash) (faultTypes.PrestateProvider, error) getPrestateProvider func(ctx context.Context, prestateHash common.Hash) (faultTypes.PrestateProvider, error)
newTraceAccessor func( newTraceAccessor func(
logger log.Logger, logger log.Logger,
m metrics.Metricer, m metrics.Metricer,
...@@ -49,7 +49,7 @@ type RegisterTask struct { ...@@ -49,7 +49,7 @@ type RegisterTask struct {
} }
func NewCannonRegisterTask(gameType faultTypes.GameType, cfg *config.Config, m caching.Metrics, serverExecutor vm.OracleServerExecutor) *RegisterTask { func NewCannonRegisterTask(gameType faultTypes.GameType, cfg *config.Config, m caching.Metrics, serverExecutor vm.OracleServerExecutor) *RegisterTask {
stateConverter := cannon.NewStateConverter() stateConverter := cannon.NewStateConverter(cfg.Cannon)
return &RegisterTask{ return &RegisterTask{
gameType: gameType, gameType: gameType,
// Don't validate the absolute prestate or genesis output root for permissioned games // Don't validate the absolute prestate or genesis output root for permissioned games
...@@ -63,7 +63,7 @@ func NewCannonRegisterTask(gameType faultTypes.GameType, cfg *config.Config, m c ...@@ -63,7 +63,7 @@ func NewCannonRegisterTask(gameType faultTypes.GameType, cfg *config.Config, m c
cfg.CannonAbsolutePreStateBaseURL, cfg.CannonAbsolutePreStateBaseURL,
cfg.CannonAbsolutePreState, cfg.CannonAbsolutePreState,
filepath.Join(cfg.Datadir, "cannon-prestates"), filepath.Join(cfg.Datadir, "cannon-prestates"),
func(path string) faultTypes.PrestateProvider { func(ctx context.Context, path string) faultTypes.PrestateProvider {
return vm.NewPrestateProvider(path, stateConverter) return vm.NewPrestateProvider(path, stateConverter)
}), }),
newTraceAccessor: func( newTraceAccessor: func(
...@@ -95,7 +95,7 @@ func NewAsteriscRegisterTask(gameType faultTypes.GameType, cfg *config.Config, m ...@@ -95,7 +95,7 @@ func NewAsteriscRegisterTask(gameType faultTypes.GameType, cfg *config.Config, m
cfg.AsteriscAbsolutePreStateBaseURL, cfg.AsteriscAbsolutePreStateBaseURL,
cfg.AsteriscAbsolutePreState, cfg.AsteriscAbsolutePreState,
filepath.Join(cfg.Datadir, "asterisc-prestates"), filepath.Join(cfg.Datadir, "asterisc-prestates"),
func(path string) faultTypes.PrestateProvider { func(ctx context.Context, path string) faultTypes.PrestateProvider {
return vm.NewPrestateProvider(path, stateConverter) return vm.NewPrestateProvider(path, stateConverter)
}), }),
newTraceAccessor: func( newTraceAccessor: func(
...@@ -127,7 +127,7 @@ func NewAsteriscKonaRegisterTask(gameType faultTypes.GameType, cfg *config.Confi ...@@ -127,7 +127,7 @@ func NewAsteriscKonaRegisterTask(gameType faultTypes.GameType, cfg *config.Confi
cfg.AsteriscKonaAbsolutePreStateBaseURL, cfg.AsteriscKonaAbsolutePreStateBaseURL,
cfg.AsteriscKonaAbsolutePreState, cfg.AsteriscKonaAbsolutePreState,
filepath.Join(cfg.Datadir, "asterisc-kona-prestates"), filepath.Join(cfg.Datadir, "asterisc-kona-prestates"),
func(path string) faultTypes.PrestateProvider { func(ctx context.Context, path string) faultTypes.PrestateProvider {
return vm.NewPrestateProvider(path, stateConverter) return vm.NewPrestateProvider(path, stateConverter)
}), }),
newTraceAccessor: func( newTraceAccessor: func(
...@@ -151,7 +151,7 @@ func NewAsteriscKonaRegisterTask(gameType faultTypes.GameType, cfg *config.Confi ...@@ -151,7 +151,7 @@ func NewAsteriscKonaRegisterTask(gameType faultTypes.GameType, cfg *config.Confi
func NewAlphabetRegisterTask(gameType faultTypes.GameType) *RegisterTask { func NewAlphabetRegisterTask(gameType faultTypes.GameType) *RegisterTask {
return &RegisterTask{ return &RegisterTask{
gameType: gameType, gameType: gameType,
getPrestateProvider: func(_ common.Hash) (faultTypes.PrestateProvider, error) { getPrestateProvider: func(_ context.Context, _ common.Hash) (faultTypes.PrestateProvider, error) {
return alphabet.PrestateProvider, nil return alphabet.PrestateProvider, nil
}, },
newTraceAccessor: func( newTraceAccessor: func(
...@@ -178,15 +178,15 @@ func cachePrestates( ...@@ -178,15 +178,15 @@ func cachePrestates(
prestateBaseURL *url.URL, prestateBaseURL *url.URL,
preStatePath string, preStatePath string,
prestateDir string, prestateDir string,
newPrestateProvider func(path string) faultTypes.PrestateProvider, newPrestateProvider func(ctx context.Context, path string) faultTypes.PrestateProvider,
) func(prestateHash common.Hash) (faultTypes.PrestateProvider, error) { ) func(ctx context.Context, prestateHash common.Hash) (faultTypes.PrestateProvider, error) {
prestateSource := prestates.NewPrestateSource(prestateBaseURL, preStatePath, prestateDir, stateConverter) prestateSource := prestates.NewPrestateSource(prestateBaseURL, preStatePath, prestateDir, stateConverter)
prestateProviderCache := prestates.NewPrestateProviderCache(m, fmt.Sprintf("prestates-%v", gameType), func(prestateHash common.Hash) (faultTypes.PrestateProvider, error) { prestateProviderCache := prestates.NewPrestateProviderCache(m, fmt.Sprintf("prestates-%v", gameType), func(ctx context.Context, prestateHash common.Hash) (faultTypes.PrestateProvider, error) {
prestatePath, err := prestateSource.PrestatePath(prestateHash) prestatePath, err := prestateSource.PrestatePath(ctx, prestateHash)
if err != nil { if err != nil {
return nil, fmt.Errorf("required prestate %v not available: %w", prestateHash, err) return nil, fmt.Errorf("required prestate %v not available: %w", prestateHash, err)
} }
return newPrestateProvider(prestatePath), nil return newPrestateProvider(ctx, prestatePath), nil
}) })
return prestateProviderCache.GetOrCreate return prestateProviderCache.GetOrCreate
} }
...@@ -219,7 +219,7 @@ func (e *RegisterTask) Register( ...@@ -219,7 +219,7 @@ func (e *RegisterTask) Register(
return nil, fmt.Errorf("failed to load prestate hash for game %v: %w", game.Proxy, err) return nil, fmt.Errorf("failed to load prestate hash for game %v: %w", game.Proxy, err)
} }
vmPrestateProvider, err := e.getPrestateProvider(requiredPrestatehash) vmPrestateProvider, err := e.getPrestateProvider(ctx, requiredPrestatehash)
if err != nil { if err != nil {
return nil, fmt.Errorf("required prestate %v not available for game %v: %w", requiredPrestatehash, game.Proxy, err) return nil, fmt.Errorf("required prestate %v not available for game %v: %w", requiredPrestatehash, game.Proxy, err)
} }
......
...@@ -125,7 +125,7 @@ func (p *AsteriscTraceProvider) loadProof(ctx context.Context, i uint64) (*utils ...@@ -125,7 +125,7 @@ func (p *AsteriscTraceProvider) loadProof(ctx context.Context, i uint64) (*utils
file, err = ioutil.OpenDecompressed(path) file, err = ioutil.OpenDecompressed(path)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
// Expected proof wasn't generated, check if we reached the end of execution // Expected proof wasn't generated, check if we reached the end of execution
proof, step, exited, err := p.stateConverter.ConvertStateToProof(vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots)) proof, step, exited, err := p.stateConverter.ConvertStateToProof(ctx, vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots))
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -185,7 +185,7 @@ func (p *AsteriscTraceProviderForTest) FindStep(ctx context.Context, start uint6 ...@@ -185,7 +185,7 @@ func (p *AsteriscTraceProviderForTest) FindStep(ctx context.Context, start uint6
return 0, fmt.Errorf("generate asterisc trace (until preimage read): %w", err) return 0, fmt.Errorf("generate asterisc trace (until preimage read): %w", err)
} }
// Load the step from the state asterisc finished with // Load the step from the state asterisc finished with
_, step, exited, err := p.stateConverter.ConvertStateToProof(vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots)) _, step, exited, err := p.stateConverter.ConvertStateToProof(ctx, vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots))
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to load final state: %w", err) return 0, fmt.Errorf("failed to load final state: %w", err)
} }
......
package asterisc package asterisc
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
...@@ -83,7 +84,7 @@ func NewStateConverter() *StateConverter { ...@@ -83,7 +84,7 @@ func NewStateConverter() *StateConverter {
return &StateConverter{} return &StateConverter{}
} }
func (c *StateConverter) ConvertStateToProof(statePath string) (*utils.ProofData, uint64, bool, error) { func (c *StateConverter) ConvertStateToProof(_ context.Context, statePath string) (*utils.ProofData, uint64, bool, error) {
state, err := parseState(statePath) state, err := parseState(statePath)
if err != nil { if err != nil {
return nil, 0, false, fmt.Errorf("cannot read final state: %w", err) return nil, 0, false, fmt.Errorf("cannot read final state: %w", err)
......
...@@ -50,7 +50,7 @@ func NewTraceProvider(logger log.Logger, m vm.Metricer, cfg vm.Config, vmCfg vm. ...@@ -50,7 +50,7 @@ func NewTraceProvider(logger log.Logger, m vm.Metricer, cfg vm.Config, vmCfg vm.
return kvstore.NewDiskKV(logger, vm.PreimageDir(dir), kvtypes.DataFormatFile) return kvstore.NewDiskKV(logger, vm.PreimageDir(dir), kvtypes.DataFormatFile)
}), }),
PrestateProvider: prestateProvider, PrestateProvider: prestateProvider,
stateConverter: &StateConverter{}, stateConverter: NewStateConverter(cfg),
cfg: cfg, cfg: cfg,
} }
} }
...@@ -125,7 +125,7 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*utils.P ...@@ -125,7 +125,7 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*utils.P
// Try opening the file again now and it should exist. // Try opening the file again now and it should exist.
file, err = ioutil.OpenDecompressed(path) file, err = ioutil.OpenDecompressed(path)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
proof, stateStep, exited, err := p.stateConverter.ConvertStateToProof(vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots)) proof, stateStep, exited, err := p.stateConverter.ConvertStateToProof(ctx, vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots))
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot create proof from final state: %w", err) return nil, fmt.Errorf("cannot create proof from final state: %w", err)
} }
...@@ -172,7 +172,7 @@ func NewTraceProviderForTest(logger log.Logger, m vm.Metricer, cfg *config.Confi ...@@ -172,7 +172,7 @@ func NewTraceProviderForTest(logger log.Logger, m vm.Metricer, cfg *config.Confi
preimageLoader: utils.NewPreimageLoader(func() (utils.PreimageSource, error) { preimageLoader: utils.NewPreimageLoader(func() (utils.PreimageSource, error) {
return kvstore.NewDiskKV(logger, vm.PreimageDir(dir), kvtypes.DataFormatFile) return kvstore.NewDiskKV(logger, vm.PreimageDir(dir), kvtypes.DataFormatFile)
}), }),
stateConverter: NewStateConverter(), stateConverter: NewStateConverter(cfg.Cannon),
cfg: cfg.Cannon, cfg: cfg.Cannon,
} }
return &CannonTraceProviderForTest{p} return &CannonTraceProviderForTest{p}
...@@ -185,7 +185,7 @@ func (p *CannonTraceProviderForTest) FindStep(ctx context.Context, start uint64, ...@@ -185,7 +185,7 @@ func (p *CannonTraceProviderForTest) FindStep(ctx context.Context, start uint64,
} }
// Load the step from the state cannon finished with // Load the step from the state cannon finished with
_, step, exited, err := p.stateConverter.ConvertStateToProof(vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots)) _, step, exited, err := p.stateConverter.ConvertStateToProof(ctx, vm.FinalStatePath(p.dir, p.cfg.BinarySnapshots))
if err != nil { if err != nil {
return 0, fmt.Errorf("failed to load final state: %w", err) return 0, fmt.Errorf("failed to load final state: %w", err)
} }
......
...@@ -244,7 +244,7 @@ func setupWithTestData(t *testing.T, dataDir string, prestate string) (*CannonTr ...@@ -244,7 +244,7 @@ func setupWithTestData(t *testing.T, dataDir string, prestate string) (*CannonTr
generator: generator, generator: generator,
prestate: filepath.Join(dataDir, prestate), prestate: filepath.Join(dataDir, prestate),
gameDepth: 63, gameDepth: 63,
stateConverter: &StateConverter{}, stateConverter: generator,
}, generator }, generator
} }
...@@ -252,6 +252,21 @@ type stubGenerator struct { ...@@ -252,6 +252,21 @@ type stubGenerator struct {
generated []int // Using int makes assertions easier generated []int // Using int makes assertions easier
finalState *singlethreaded.State finalState *singlethreaded.State
proof *utils.ProofData proof *utils.ProofData
finalStatePath string
}
func (e *stubGenerator) ConvertStateToProof(ctx context.Context, statePath string) (*utils.ProofData, uint64, bool, error) {
if statePath == e.finalStatePath {
witness, hash := e.finalState.EncodeWitness()
return &utils.ProofData{
ClaimValue: hash,
StateData: witness,
ProofData: []byte{},
}, e.finalState.Step, e.finalState.Exited, nil
} else {
return nil, 0, false, fmt.Errorf("loading unexpected state: %s, only support: %s", statePath, e.finalStatePath)
}
} }
func (e *stubGenerator) GenerateProof(ctx context.Context, dir string, i uint64) error { func (e *stubGenerator) GenerateProof(ctx context.Context, dir string, i uint64) error {
...@@ -262,6 +277,7 @@ func (e *stubGenerator) GenerateProof(ctx context.Context, dir string, i uint64) ...@@ -262,6 +277,7 @@ func (e *stubGenerator) GenerateProof(ctx context.Context, dir string, i uint64)
if e.finalState != nil && e.finalState.Step <= i { if e.finalState != nil && e.finalState.Step <= i {
// Requesting a trace index past the end of the trace // Requesting a trace index past the end of the trace
proofFile = vm.FinalStatePath(dir, false) proofFile = vm.FinalStatePath(dir, false)
e.finalStatePath = proofFile
data, err = json.Marshal(e.finalState) data, err = json.Marshal(e.finalState)
if err != nil { if err != nil {
return err return err
......
package cannon package cannon
import ( import (
"bytes"
"context"
"encoding/json"
"fmt" "fmt"
"os/exec"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/versions"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
) )
type stateData struct {
WitnessHash common.Hash `json:"witnessHash"`
Witness hexutil.Bytes `json:"witness"`
Step uint64 `json:"step"`
Exited bool `json:"exited"`
}
type StateConverter struct { type StateConverter struct {
vmConfig vm.Config
cmdExecutor func(ctx context.Context, binary string, args ...string) (stdOut string, stdErr string, err error)
} }
func NewStateConverter() *StateConverter { func NewStateConverter(vmConfig vm.Config) *StateConverter {
return &StateConverter{} return &StateConverter{
vmConfig: vmConfig,
cmdExecutor: runCmd,
}
} }
func (c *StateConverter) ConvertStateToProof(statePath string) (*utils.ProofData, uint64, bool, error) { func (c *StateConverter) ConvertStateToProof(ctx context.Context, statePath string) (*utils.ProofData, uint64, bool, error) {
state, err := parseState(statePath) stdOut, stdErr, err := c.cmdExecutor(ctx, c.vmConfig.VmBin, "witness", "--input", statePath)
if err != nil { if err != nil {
return nil, 0, false, fmt.Errorf("cannot read final state: %w", err) return nil, 0, false, fmt.Errorf("state conversion failed: %w (%s)", err, stdErr)
}
var data stateData
if err := json.Unmarshal([]byte(stdOut), &data); err != nil {
return nil, 0, false, fmt.Errorf("failed to parse state data: %w", err)
} }
// Extend the trace out to the full length using a no-op instruction that doesn't change any state // Extend the trace out to the full length using a no-op instruction that doesn't change any state
// No execution is done, so no proof-data or oracle values are required. // No execution is done, so no proof-data or oracle values are required.
witness, witnessHash := state.EncodeWitness()
return &utils.ProofData{ return &utils.ProofData{
ClaimValue: witnessHash, ClaimValue: data.WitnessHash,
StateData: witness, StateData: data.Witness,
ProofData: []byte{}, ProofData: []byte{},
OracleKey: nil, OracleKey: nil,
OracleValue: nil, OracleValue: nil,
OracleOffset: 0, OracleOffset: 0,
}, state.GetStep(), state.GetExited(), nil }, data.Step, data.Exited, nil
} }
func parseState(path string) (mipsevm.FPVMState, error) { func runCmd(ctx context.Context, binary string, args ...string) (stdOut string, stdErr string, err error) {
return versions.LoadStateFromFile(path) var outBuf bytes.Buffer
var errBuf bytes.Buffer
cmd := exec.CommandContext(ctx, binary, args...)
cmd.Stdout = &outBuf
cmd.Stderr = &errBuf
err = cmd.Run()
stdOut = outBuf.String()
stdErr = errBuf.String()
return
} }
package cannon package cannon
import ( import (
_ "embed" "context"
"path/filepath" "encoding/json"
"errors"
"testing" "testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/multithreaded" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/versions"
"github.com/ethereum-optimism/optimism/cannon/serialize"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/ethereum-optimism/optimism/cannon/mipsevm/singlethreaded"
) )
func TestLoadState(t *testing.T) { const testBinary = "./somewhere/cannon"
tests := []struct {
name string
creator func() mipsevm.FPVMState
supportsJSON bool
}{
{
name: "singlethreaded",
creator: func() mipsevm.FPVMState { return singlethreaded.CreateInitialState(234, 82) },
supportsJSON: true,
},
{
name: "multithreaded",
creator: func() mipsevm.FPVMState { return multithreaded.CreateInitialState(982, 492) },
supportsJSON: false,
},
}
for _, test := range tests {
test := test
loadExpectedState := func(t *testing.T) *versions.VersionedState {
state, err := versions.NewFromState(test.creator())
require.NoError(t, err)
return state
}
t.Run(test.name, func(t *testing.T) {
t.Run("Uncompressed", func(t *testing.T) {
if !test.supportsJSON {
t.Skip("JSON not supported by state version")
}
expected := loadExpectedState(t)
path := writeState(t, "state.json", expected)
state, err := parseState(path)
require.NoError(t, err)
require.Equal(t, expected, state)
})
t.Run("Gzipped", func(t *testing.T) {
if !test.supportsJSON {
t.Skip("JSON not supported by state version")
}
expected := loadExpectedState(t)
path := writeState(t, "state.json.gz", expected)
state, err := parseState(path)
require.NoError(t, err)
require.Equal(t, expected, state)
})
t.Run("Binary", func(t *testing.T) { func TestStateConverter(t *testing.T) {
expected := loadExpectedState(t) setup := func(t *testing.T) (*StateConverter, *capturingExecutor) {
vmCfg := vm.Config{
path := writeState(t, "state.bin", expected) VmBin: testBinary,
}
state, err := parseState(path) executor := &capturingExecutor{}
require.NoError(t, err) converter := NewStateConverter(vmCfg)
require.Equal(t, expected, state) converter.cmdExecutor = executor.exec
}) return converter, executor
}
t.Run("BinaryGzip", func(t *testing.T) { t.Run("Valid", func(t *testing.T) {
expected := loadExpectedState(t) converter, executor := setup(t)
data := stateData{
WitnessHash: common.Hash{0xab},
Witness: []byte{1, 2, 3, 4},
Step: 42,
Exited: true,
}
ser, err := json.Marshal(data)
require.NoError(t, err)
executor.stdOut = string(ser)
proof, step, exited, err := converter.ConvertStateToProof(context.Background(), "foo.json")
require.NoError(t, err)
require.Equal(t, data.Exited, exited)
require.Equal(t, data.Step, step)
require.Equal(t, data.WitnessHash, proof.ClaimValue)
require.Equal(t, data.Witness, proof.StateData)
require.NotNil(t, proof.ProofData, "later validations require this to be non-nil")
require.Equal(t, testBinary, executor.binary)
require.Equal(t, []string{"witness", "--input", "foo.json"}, executor.args)
})
t.Run("CommandError", func(t *testing.T) {
converter, executor := setup(t)
executor.err = errors.New("boom")
_, _, _, err := converter.ConvertStateToProof(context.Background(), "foo.json")
require.ErrorIs(t, err, executor.err)
})
t.Run("InvalidOutput", func(t *testing.T) {
converter, executor := setup(t)
executor.stdOut = "blah blah"
_, _, _, err := converter.ConvertStateToProof(context.Background(), "foo.json")
require.ErrorContains(t, err, "failed to parse state data")
})
}
path := writeState(t, "state.bin.gz", expected) type capturingExecutor struct {
binary string
args []string
state, err := parseState(path) stdOut string
require.NoError(t, err) stdErr string
require.Equal(t, expected, state) err error
})
})
}
} }
func writeState(t *testing.T, filename string, state *versions.VersionedState) string { func (c *capturingExecutor) exec(_ context.Context, binary string, args ...string) (string, string, error) {
dir := t.TempDir() c.binary = binary
path := filepath.Join(dir, filename) c.args = args
require.NoError(t, serialize.Write(path, state, 0644)) return c.stdOut, c.stdErr, c.err
return path
} }
package prestates package prestates
import ( import (
"context"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/sources/caching" "github.com/ethereum-optimism/optimism/op-service/sources/caching"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -10,27 +12,27 @@ type PrestateSource interface { ...@@ -10,27 +12,27 @@ type PrestateSource interface {
// PrestatePath returns the path to the prestate file to use for the game. // PrestatePath returns the path to the prestate file to use for the game.
// The provided prestateHash may be used to differentiate between different states but no guarantee is made that // The provided prestateHash may be used to differentiate between different states but no guarantee is made that
// the returned prestate matches the supplied hash. // the returned prestate matches the supplied hash.
PrestatePath(prestateHash common.Hash) (string, error) PrestatePath(ctx context.Context, prestateHash common.Hash) (string, error)
} }
type PrestateProviderCache struct { type PrestateProviderCache struct {
createProvider func(prestateHash common.Hash) (types.PrestateProvider, error) createProvider func(ctx context.Context, prestateHash common.Hash) (types.PrestateProvider, error)
cache *caching.LRUCache[common.Hash, types.PrestateProvider] cache *caching.LRUCache[common.Hash, types.PrestateProvider]
} }
func NewPrestateProviderCache(m caching.Metrics, label string, createProvider func(prestateHash common.Hash) (types.PrestateProvider, error)) *PrestateProviderCache { func NewPrestateProviderCache(m caching.Metrics, label string, createProvider func(ctx context.Context, prestateHash common.Hash) (types.PrestateProvider, error)) *PrestateProviderCache {
return &PrestateProviderCache{ return &PrestateProviderCache{
createProvider: createProvider, createProvider: createProvider,
cache: caching.NewLRUCache[common.Hash, types.PrestateProvider](m, label, 5), cache: caching.NewLRUCache[common.Hash, types.PrestateProvider](m, label, 5),
} }
} }
func (p *PrestateProviderCache) GetOrCreate(prestateHash common.Hash) (types.PrestateProvider, error) { func (p *PrestateProviderCache) GetOrCreate(ctx context.Context, prestateHash common.Hash) (types.PrestateProvider, error) {
provider, ok := p.cache.Get(prestateHash) provider, ok := p.cache.Get(prestateHash)
if ok { if ok {
return provider, nil return provider, nil
} }
provider, err := p.createProvider(prestateHash) provider, err := p.createProvider(ctx, prestateHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -11,26 +11,26 @@ import ( ...@@ -11,26 +11,26 @@ import (
) )
func TestPrestateProviderCache_CreateAndCache(t *testing.T) { func TestPrestateProviderCache_CreateAndCache(t *testing.T) {
cache := NewPrestateProviderCache(nil, "", func(prestateHash common.Hash) (types.PrestateProvider, error) { cache := NewPrestateProviderCache(nil, "", func(_ context.Context, prestateHash common.Hash) (types.PrestateProvider, error) {
return &stubPrestateProvider{commitment: prestateHash}, nil return &stubPrestateProvider{commitment: prestateHash}, nil
}) })
hash1 := common.Hash{0xaa} hash1 := common.Hash{0xaa}
hash2 := common.Hash{0xbb} hash2 := common.Hash{0xbb}
provider1a, err := cache.GetOrCreate(hash1) provider1a, err := cache.GetOrCreate(context.Background(), hash1)
require.NoError(t, err) require.NoError(t, err)
commitment, err := provider1a.AbsolutePreStateCommitment(context.Background()) commitment, err := provider1a.AbsolutePreStateCommitment(context.Background())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, hash1, commitment) require.Equal(t, hash1, commitment)
provider1b, err := cache.GetOrCreate(hash1) provider1b, err := cache.GetOrCreate(context.Background(), hash1)
require.NoError(t, err) require.NoError(t, err)
require.Same(t, provider1a, provider1b) require.Same(t, provider1a, provider1b)
commitment, err = provider1b.AbsolutePreStateCommitment(context.Background()) commitment, err = provider1b.AbsolutePreStateCommitment(context.Background())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, hash1, commitment) require.Equal(t, hash1, commitment)
provider2, err := cache.GetOrCreate(hash2) provider2, err := cache.GetOrCreate(context.Background(), hash2)
require.NoError(t, err) require.NoError(t, err)
require.NotSame(t, provider1a, provider2) require.NotSame(t, provider1a, provider2)
commitment, err = provider2.AbsolutePreStateCommitment(context.Background()) commitment, err = provider2.AbsolutePreStateCommitment(context.Background())
...@@ -41,10 +41,10 @@ func TestPrestateProviderCache_CreateAndCache(t *testing.T) { ...@@ -41,10 +41,10 @@ func TestPrestateProviderCache_CreateAndCache(t *testing.T) {
func TestPrestateProviderCache_CreateFails(t *testing.T) { func TestPrestateProviderCache_CreateFails(t *testing.T) {
hash1 := common.Hash{0xaa} hash1 := common.Hash{0xaa}
expectedErr := errors.New("boom") expectedErr := errors.New("boom")
cache := NewPrestateProviderCache(nil, "", func(prestateHash common.Hash) (types.PrestateProvider, error) { cache := NewPrestateProviderCache(nil, "", func(_ context.Context, prestateHash common.Hash) (types.PrestateProvider, error) {
return nil, expectedErr return nil, expectedErr
}) })
provider, err := cache.GetOrCreate(hash1) provider, err := cache.GetOrCreate(context.Background(), hash1)
require.ErrorIs(t, err, expectedErr) require.ErrorIs(t, err, expectedErr)
require.Nil(t, provider) require.Nil(t, provider)
} }
......
package prestates package prestates
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
...@@ -8,6 +9,7 @@ import ( ...@@ -8,6 +9,7 @@ import (
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/vm"
"github.com/ethereum-optimism/optimism/op-service/ioutil" "github.com/ethereum-optimism/optimism/op-service/ioutil"
...@@ -35,7 +37,7 @@ func NewMultiPrestateProvider(baseUrl *url.URL, dataDir string, stateConverter v ...@@ -35,7 +37,7 @@ func NewMultiPrestateProvider(baseUrl *url.URL, dataDir string, stateConverter v
} }
} }
func (m *MultiPrestateProvider) PrestatePath(hash common.Hash) (string, error) { func (m *MultiPrestateProvider) PrestatePath(ctx context.Context, hash common.Hash) (string, error) {
// First try to find a previously downloaded prestate // First try to find a previously downloaded prestate
for _, fileType := range supportedFileTypes { for _, fileType := range supportedFileTypes {
path := filepath.Join(m.dataDir, hash.Hex()+fileType) path := filepath.Join(m.dataDir, hash.Hex()+fileType)
...@@ -51,7 +53,7 @@ func (m *MultiPrestateProvider) PrestatePath(hash common.Hash) (string, error) { ...@@ -51,7 +53,7 @@ func (m *MultiPrestateProvider) PrestatePath(hash common.Hash) (string, error) {
var combinedErr error // Keep a track of each download attempt so we can report them if none work var combinedErr error // Keep a track of each download attempt so we can report them if none work
for _, fileType := range supportedFileTypes { for _, fileType := range supportedFileTypes {
path := filepath.Join(m.dataDir, hash.Hex()+fileType) path := filepath.Join(m.dataDir, hash.Hex()+fileType)
if err := m.fetchPrestate(hash, fileType, path); errors.Is(err, ErrPrestateUnavailable) { if err := m.fetchPrestate(ctx, hash, fileType, path); errors.Is(err, ErrPrestateUnavailable) {
combinedErr = errors.Join(combinedErr, err) combinedErr = errors.Join(combinedErr, err)
continue // Didn't find prestate in this format, try the next continue // Didn't find prestate in this format, try the next
} else if err != nil { } else if err != nil {
...@@ -62,12 +64,18 @@ func (m *MultiPrestateProvider) PrestatePath(hash common.Hash) (string, error) { ...@@ -62,12 +64,18 @@ func (m *MultiPrestateProvider) PrestatePath(hash common.Hash) (string, error) {
return "", errors.Join(ErrPrestateUnavailable, combinedErr) return "", errors.Join(ErrPrestateUnavailable, combinedErr)
} }
func (m *MultiPrestateProvider) fetchPrestate(hash common.Hash, fileType string, dest string) error { func (m *MultiPrestateProvider) fetchPrestate(ctx context.Context, hash common.Hash, fileType string, dest string) error {
if err := os.MkdirAll(m.dataDir, 0755); err != nil { if err := os.MkdirAll(m.dataDir, 0755); err != nil {
return fmt.Errorf("error creating prestate dir: %w", err) return fmt.Errorf("error creating prestate dir: %w", err)
} }
prestateUrl := m.baseUrl.JoinPath(hash.Hex() + fileType) prestateUrl := m.baseUrl.JoinPath(hash.Hex() + fileType)
resp, err := http.Get(prestateUrl.String()) tCtx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel()
req, err := http.NewRequestWithContext(tCtx, "GET", prestateUrl.String(), nil)
if err != nil {
return fmt.Errorf("failed to create prestate request: %w", err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil { if err != nil {
return fmt.Errorf("failed to fetch prestate from %v: %w", prestateUrl, err) return fmt.Errorf("failed to fetch prestate from %v: %w", prestateUrl, err)
} }
...@@ -91,7 +99,7 @@ func (m *MultiPrestateProvider) fetchPrestate(hash common.Hash, fileType string, ...@@ -91,7 +99,7 @@ func (m *MultiPrestateProvider) fetchPrestate(hash common.Hash, fileType string,
return fmt.Errorf("failed to close file %v: %w", dest, err) return fmt.Errorf("failed to close file %v: %w", dest, err)
} }
// Verify the prestate actually matches the expected hash before moving it into the final destination // Verify the prestate actually matches the expected hash before moving it into the final destination
proof, _, _, err := m.stateConverter.ConvertStateToProof(tmpFile) proof, _, _, err := m.stateConverter.ConvertStateToProof(ctx, tmpFile)
if err != nil || proof.ClaimValue != hash { if err != nil || proof.ClaimValue != hash {
// Treat invalid prestates as unavailable. Often servers return a 404 page with 200 status code // Treat invalid prestates as unavailable. Often servers return a 404 page with 200 status code
_ = os.Remove(tmpFile) // Best effort attempt to clean up the temporary file _ = os.Remove(tmpFile) // Best effort attempt to clean up the temporary file
......
package prestates package prestates
import ( import (
"context"
"errors" "errors"
"io" "io"
"net/http" "net/http"
...@@ -25,7 +26,7 @@ func TestDownloadPrestate(t *testing.T) { ...@@ -25,7 +26,7 @@ func TestDownloadPrestate(t *testing.T) {
defer server.Close() defer server.Close()
hash := common.Hash{0xaa} hash := common.Hash{0xaa}
provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash}) provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash})
path, err := provider.PrestatePath(hash) path, err := provider.PrestatePath(context.Background(), hash)
require.NoError(t, err) require.NoError(t, err)
in, err := os.Open(path) in, err := os.Open(path)
require.NoError(t, err) require.NoError(t, err)
...@@ -46,7 +47,7 @@ func TestCreateDirectory(t *testing.T) { ...@@ -46,7 +47,7 @@ func TestCreateDirectory(t *testing.T) {
defer server.Close() defer server.Close()
hash := common.Hash{0xaa} hash := common.Hash{0xaa}
provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash}) provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash})
path, err := provider.PrestatePath(hash) path, err := provider.PrestatePath(context.Background(), hash)
require.NoError(t, err) require.NoError(t, err)
in, err := os.Open(path) in, err := os.Open(path)
require.NoError(t, err) require.NoError(t, err)
...@@ -66,7 +67,7 @@ func TestExistingPrestate(t *testing.T) { ...@@ -66,7 +67,7 @@ func TestExistingPrestate(t *testing.T) {
err := ioutil.WriteCompressedBytes(expectedFile, []byte("expected content"), os.O_WRONLY|os.O_CREATE, 0o644) err := ioutil.WriteCompressedBytes(expectedFile, []byte("expected content"), os.O_WRONLY|os.O_CREATE, 0o644)
require.NoError(t, err) require.NoError(t, err)
path, err := provider.PrestatePath(hash) path, err := provider.PrestatePath(context.Background(), hash)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expectedFile, path) require.Equal(t, expectedFile, path)
in, err := ioutil.OpenDecompressed(path) in, err := ioutil.OpenDecompressed(path)
...@@ -87,7 +88,7 @@ func TestMissingPrestate(t *testing.T) { ...@@ -87,7 +88,7 @@ func TestMissingPrestate(t *testing.T) {
defer server.Close() defer server.Close()
hash := common.Hash{0xaa} hash := common.Hash{0xaa}
provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash}) provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash})
path, err := provider.PrestatePath(hash) path, err := provider.PrestatePath(context.Background(), hash)
require.ErrorIs(t, err, ErrPrestateUnavailable) require.ErrorIs(t, err, ErrPrestateUnavailable)
_, err = os.Stat(path) _, err = os.Stat(path)
require.ErrorIs(t, err, os.ErrNotExist) require.ErrorIs(t, err, os.ErrNotExist)
...@@ -115,7 +116,7 @@ func TestStorePrestateWithCorrectExtension(t *testing.T) { ...@@ -115,7 +116,7 @@ func TestStorePrestateWithCorrectExtension(t *testing.T) {
defer server.Close() defer server.Close()
hash := common.Hash{0xaa} hash := common.Hash{0xaa}
provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash}) provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash})
path, err := provider.PrestatePath(hash) path, err := provider.PrestatePath(context.Background(), hash)
require.NoError(t, err) require.NoError(t, err)
require.Truef(t, strings.HasSuffix(path, ext), "Expected path %v to have extension %v", path, ext) require.Truef(t, strings.HasSuffix(path, ext), "Expected path %v to have extension %v", path, ext)
in, err := os.Open(path) in, err := os.Open(path)
...@@ -136,7 +137,7 @@ func TestDetectInvalidPrestate(t *testing.T) { ...@@ -136,7 +137,7 @@ func TestDetectInvalidPrestate(t *testing.T) {
defer server.Close() defer server.Close()
hash := common.Hash{0xaa} hash := common.Hash{0xaa}
provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash, err: errors.New("boom")}) provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: hash, err: errors.New("boom")})
_, err := provider.PrestatePath(hash) _, err := provider.PrestatePath(context.Background(), hash)
require.ErrorIs(t, err, ErrPrestateUnavailable) require.ErrorIs(t, err, ErrPrestateUnavailable)
entries, err := os.ReadDir(dir) entries, err := os.ReadDir(dir)
require.NoError(t, err) require.NoError(t, err)
...@@ -152,7 +153,7 @@ func TestDetectPrestateWithWrongHash(t *testing.T) { ...@@ -152,7 +153,7 @@ func TestDetectPrestateWithWrongHash(t *testing.T) {
hash := common.Hash{0xaa} hash := common.Hash{0xaa}
actualHash := common.Hash{0xbb} actualHash := common.Hash{0xbb}
provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: actualHash}) provider := NewMultiPrestateProvider(parseURL(t, server.URL), dir, &stubStateConverter{hash: actualHash})
_, err := provider.PrestatePath(hash) _, err := provider.PrestatePath(context.Background(), hash)
require.ErrorIs(t, err, ErrPrestateUnavailable) require.ErrorIs(t, err, ErrPrestateUnavailable)
entries, err := os.ReadDir(dir) entries, err := os.ReadDir(dir)
require.NoError(t, err) require.NoError(t, err)
...@@ -180,7 +181,7 @@ type stubStateConverter struct { ...@@ -180,7 +181,7 @@ type stubStateConverter struct {
hash common.Hash hash common.Hash
} }
func (s *stubStateConverter) ConvertStateToProof(path string) (*utils.ProofData, uint64, bool, error) { func (s *stubStateConverter) ConvertStateToProof(_ context.Context, path string) (*utils.ProofData, uint64, bool, error) {
// Return an error if we're given the wrong path // Return an error if we're given the wrong path
if _, err := os.Stat(path); err != nil { if _, err := os.Stat(path); err != nil {
return nil, 0, false, err return nil, 0, false, err
......
package prestates package prestates
import "github.com/ethereum/go-ethereum/common" import (
"context"
"github.com/ethereum/go-ethereum/common"
)
type SinglePrestateSource struct { type SinglePrestateSource struct {
path string path string
...@@ -10,6 +14,6 @@ func NewSinglePrestateSource(path string) *SinglePrestateSource { ...@@ -10,6 +14,6 @@ func NewSinglePrestateSource(path string) *SinglePrestateSource {
return &SinglePrestateSource{path: path} return &SinglePrestateSource{path: path}
} }
func (s *SinglePrestateSource) PrestatePath(_ common.Hash) (string, error) { func (s *SinglePrestateSource) PrestatePath(_ context.Context, _ common.Hash) (string, error) {
return s.path, nil return s.path, nil
} }
package vm package vm
import "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils" import (
"context"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/utils"
)
type StateConverter interface { type StateConverter interface {
// ConvertStateToProof reads the state snapshot at the specified path and converts it to ProofData. // ConvertStateToProof reads the state snapshot at the specified path and converts it to ProofData.
// Returns the proof data, the VM step the state is from and whether or not the VM had exited. // Returns the proof data, the VM step the state is from and whether or not the VM had exited.
ConvertStateToProof(statePath string) (*utils.ProofData, uint64, bool, error) ConvertStateToProof(ctx context.Context, statePath string) (*utils.ProofData, uint64, bool, error)
} }
...@@ -25,11 +25,11 @@ func NewPrestateProvider(prestate string, converter StateConverter) *PrestatePro ...@@ -25,11 +25,11 @@ func NewPrestateProvider(prestate string, converter StateConverter) *PrestatePro
} }
} }
func (p *PrestateProvider) AbsolutePreStateCommitment(_ context.Context) (common.Hash, error) { func (p *PrestateProvider) AbsolutePreStateCommitment(ctx context.Context) (common.Hash, error) {
if p.prestateCommitment != (common.Hash{}) { if p.prestateCommitment != (common.Hash{}) {
return p.prestateCommitment, nil return p.prestateCommitment, nil
} }
proof, _, _, err := p.stateConverter.ConvertStateToProof(p.prestate) proof, _, _, err := p.stateConverter.ConvertStateToProof(ctx, p.prestate)
if err != nil { if err != nil {
return common.Hash{}, fmt.Errorf("cannot load absolute pre-state: %w", err) return common.Hash{}, fmt.Errorf("cannot load absolute pre-state: %w", err)
} }
......
...@@ -16,7 +16,7 @@ type stubConverter struct { ...@@ -16,7 +16,7 @@ type stubConverter struct {
hash common.Hash hash common.Hash
} }
func (s *stubConverter) ConvertStateToProof(statePath string) (*utils.ProofData, uint64, bool, error) { func (s *stubConverter) ConvertStateToProof(_ context.Context, _ string) (*utils.ProofData, uint64, bool, error) {
if s.err != nil { if s.err != nil {
return nil, 0, false, s.err return nil, 0, false, s.err
} }
......
package runner package runner
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"net/url" "net/url"
...@@ -18,6 +19,7 @@ import ( ...@@ -18,6 +19,7 @@ import (
) )
func createTraceProvider( func createTraceProvider(
ctx context.Context,
logger log.Logger, logger log.Logger,
m vm.Metricer, m vm.Metricer,
cfg *config.Config, cfg *config.Config,
...@@ -28,51 +30,51 @@ func createTraceProvider( ...@@ -28,51 +30,51 @@ func createTraceProvider(
) (types.TraceProvider, error) { ) (types.TraceProvider, error) {
switch traceType { switch traceType {
case types.TraceTypeCannon: case types.TraceTypeCannon:
vmConfig := vm.NewOpProgramServerExecutor() serverExecutor := vm.NewOpProgramServerExecutor()
stateConverter := cannon.NewStateConverter() stateConverter := cannon.NewStateConverter(cfg.Cannon)
prestate, err := getPrestate(prestateHash, cfg.CannonAbsolutePreStateBaseURL, cfg.CannonAbsolutePreState, dir, stateConverter) prestate, err := getPrestate(ctx, prestateHash, cfg.CannonAbsolutePreStateBaseURL, cfg.CannonAbsolutePreState, dir, stateConverter)
if err != nil { if err != nil {
return nil, err return nil, err
} }
prestateProvider := vm.NewPrestateProvider(prestate, stateConverter) prestateProvider := vm.NewPrestateProvider(prestate, stateConverter)
return cannon.NewTraceProvider(logger, m, cfg.Cannon, vmConfig, prestateProvider, prestate, localInputs, dir, 42), nil return cannon.NewTraceProvider(logger, m, cfg.Cannon, serverExecutor, prestateProvider, prestate, localInputs, dir, 42), nil
case types.TraceTypeAsterisc: case types.TraceTypeAsterisc:
vmConfig := vm.NewOpProgramServerExecutor() serverExecutor := vm.NewOpProgramServerExecutor()
stateConverter := asterisc.NewStateConverter() stateConverter := asterisc.NewStateConverter()
prestate, err := getPrestate(prestateHash, cfg.AsteriscAbsolutePreStateBaseURL, cfg.AsteriscAbsolutePreState, dir, stateConverter) prestate, err := getPrestate(ctx, prestateHash, cfg.AsteriscAbsolutePreStateBaseURL, cfg.AsteriscAbsolutePreState, dir, stateConverter)
if err != nil { if err != nil {
return nil, err return nil, err
} }
prestateProvider := vm.NewPrestateProvider(prestate, stateConverter) prestateProvider := vm.NewPrestateProvider(prestate, stateConverter)
return asterisc.NewTraceProvider(logger, m, cfg.Asterisc, vmConfig, prestateProvider, prestate, localInputs, dir, 42), nil return asterisc.NewTraceProvider(logger, m, cfg.Asterisc, serverExecutor, prestateProvider, prestate, localInputs, dir, 42), nil
case types.TraceTypeAsteriscKona: case types.TraceTypeAsteriscKona:
vmConfig := vm.NewKonaExecutor() serverExecutor := vm.NewKonaExecutor()
stateConverter := asterisc.NewStateConverter() stateConverter := asterisc.NewStateConverter()
prestate, err := getPrestate(prestateHash, cfg.AsteriscKonaAbsolutePreStateBaseURL, cfg.AsteriscKonaAbsolutePreState, dir, stateConverter) prestate, err := getPrestate(ctx, prestateHash, cfg.AsteriscKonaAbsolutePreStateBaseURL, cfg.AsteriscKonaAbsolutePreState, dir, stateConverter)
if err != nil { if err != nil {
return nil, err return nil, err
} }
prestateProvider := vm.NewPrestateProvider(prestate, stateConverter) prestateProvider := vm.NewPrestateProvider(prestate, stateConverter)
return asterisc.NewTraceProvider(logger, m, cfg.AsteriscKona, vmConfig, prestateProvider, prestate, localInputs, dir, 42), nil return asterisc.NewTraceProvider(logger, m, cfg.AsteriscKona, serverExecutor, prestateProvider, prestate, localInputs, dir, 42), nil
} }
return nil, errors.New("invalid trace type") return nil, errors.New("invalid trace type")
} }
func createMTTraceProvider( func createMTTraceProvider(
ctx context.Context,
logger log.Logger, logger log.Logger,
m vm.Metricer, m vm.Metricer,
vmConfig vm.Config, vmConfig vm.Config,
prestateHash common.Hash, prestateHash common.Hash,
absolutePrestateBaseURL *url.URL, absolutePrestateBaseURL *url.URL,
traceType types.TraceType,
localInputs utils.LocalGameInputs, localInputs utils.LocalGameInputs,
dir string, dir string,
) (types.TraceProvider, error) { ) (types.TraceProvider, error) {
executor := vm.NewOpProgramServerExecutor() executor := vm.NewOpProgramServerExecutor()
stateConverter := cannon.NewStateConverter() stateConverter := cannon.NewStateConverter(vmConfig)
prestateSource := prestates.NewMultiPrestateProvider(absolutePrestateBaseURL, filepath.Join(dir, "prestates"), cannon.NewStateConverter()) prestateSource := prestates.NewMultiPrestateProvider(absolutePrestateBaseURL, filepath.Join(dir, "prestates"), stateConverter)
prestatePath, err := prestateSource.PrestatePath(prestateHash) prestatePath, err := prestateSource.PrestatePath(ctx, prestateHash)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get prestate %v: %w", prestateHash, err) return nil, fmt.Errorf("failed to get prestate %v: %w", prestateHash, err)
} }
...@@ -80,14 +82,14 @@ func createMTTraceProvider( ...@@ -80,14 +82,14 @@ func createMTTraceProvider(
return cannon.NewTraceProvider(logger, m, vmConfig, executor, prestateProvider, prestatePath, localInputs, dir, 42), nil return cannon.NewTraceProvider(logger, m, vmConfig, executor, prestateProvider, prestatePath, localInputs, dir, 42), nil
} }
func getPrestate(prestateHash common.Hash, prestateBaseUrl *url.URL, prestatePath string, dataDir string, stateConverter vm.StateConverter) (string, error) { func getPrestate(ctx context.Context, prestateHash common.Hash, prestateBaseUrl *url.URL, prestatePath string, dataDir string, stateConverter vm.StateConverter) (string, error) {
prestateSource := prestates.NewPrestateSource( prestateSource := prestates.NewPrestateSource(
prestateBaseUrl, prestateBaseUrl,
prestatePath, prestatePath,
filepath.Join(dataDir, "prestates"), filepath.Join(dataDir, "prestates"),
stateConverter) stateConverter)
prestate, err := prestateSource.PrestatePath(prestateHash) prestate, err := prestateSource.PrestatePath(ctx, prestateHash)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get prestate %v: %w", prestateHash, err) return "", fmt.Errorf("failed to get prestate %v: %w", prestateHash, err)
} }
......
...@@ -172,7 +172,7 @@ func (r *Runner) runAndRecordOnce(ctx context.Context, traceType types.TraceType ...@@ -172,7 +172,7 @@ func (r *Runner) runAndRecordOnce(ctx context.Context, traceType types.TraceType
} }
func (r *Runner) runOnce(ctx context.Context, logger log.Logger, traceType types.TraceType, prestateHash common.Hash, localInputs utils.LocalGameInputs, dir string) error { func (r *Runner) runOnce(ctx context.Context, logger log.Logger, traceType types.TraceType, prestateHash common.Hash, localInputs utils.LocalGameInputs, dir string) error {
provider, err := createTraceProvider(logger, metrics.NewVmMetrics(r.m, traceType.String()), r.cfg, prestateHash, traceType, localInputs, dir) provider, err := createTraceProvider(ctx, logger, metrics.NewVmMetrics(r.m, traceType.String()), r.cfg, prestateHash, traceType, localInputs, dir)
if err != nil { if err != nil {
return fmt.Errorf("failed to create trace provider: %w", err) return fmt.Errorf("failed to create trace provider: %w", err)
} }
...@@ -187,7 +187,7 @@ func (r *Runner) runOnce(ctx context.Context, logger log.Logger, traceType types ...@@ -187,7 +187,7 @@ func (r *Runner) runOnce(ctx context.Context, logger log.Logger, traceType types
} }
func (r *Runner) runMTOnce(ctx context.Context, logger log.Logger, localInputs utils.LocalGameInputs, dir string) error { func (r *Runner) runMTOnce(ctx context.Context, logger log.Logger, localInputs utils.LocalGameInputs, dir string) error {
provider, err := createMTTraceProvider(logger, metrics.NewVmMetrics(r.m, mtCannonType), r.cfg.Cannon, r.addMTCannonPrestate, r.addMTCannonPrestateURL, types.TraceTypeCannon, localInputs, dir) provider, err := createMTTraceProvider(ctx, logger, metrics.NewVmMetrics(r.m, mtCannonType), r.cfg.Cannon, r.addMTCannonPrestate, r.addMTCannonPrestateURL, localInputs, dir)
if err != nil { if err != nil {
return fmt.Errorf("failed to create trace provider: %w", err) return fmt.Errorf("failed to create trace provider: %w", err)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment