Commit 641691db authored by Andreas Bigger's avatar Andreas Bigger

Load the prestate from the mipsevm state json

parent 3b9fa36e
...@@ -14,6 +14,11 @@ COPY ./go.mod /app/go.mod ...@@ -14,6 +14,11 @@ COPY ./go.mod /app/go.mod
COPY ./go.sum /app/go.sum COPY ./go.sum /app/go.sum
COPY ./.git /app/.git COPY ./.git /app/.git
# Copy cannon and its dependencies
COPY ./cannon /app/cannon
COPY ./op-preimage /app/op-preimage
COPY ./op-chain-ops /app/op-chain-ops
WORKDIR /app/op-challenger WORKDIR /app/op-challenger
RUN go mod download RUN go mod download
......
...@@ -57,8 +57,9 @@ func (ap *AlphabetTraceProvider) Get(ctx context.Context, i uint64) (common.Hash ...@@ -57,8 +57,9 @@ func (ap *AlphabetTraceProvider) Get(ctx context.Context, i uint64) (common.Hash
return crypto.Keccak256Hash(claimBytes), nil return crypto.Keccak256Hash(claimBytes), nil
} }
func (ap *AlphabetTraceProvider) AbsolutePreState(ctx context.Context) []byte { // AbsolutePreState returns the absolute pre-state for the alphabet trace.
return common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000060") func (ap *AlphabetTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, error) {
return common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000060"), nil
} }
// BuildAlphabetPreimage constructs the claim bytes for the index and state item. // BuildAlphabetPreimage constructs the claim bytes for the index and state item.
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types" "github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -34,12 +35,14 @@ type ProofGenerator interface { ...@@ -34,12 +35,14 @@ type ProofGenerator interface {
type CannonTraceProvider struct { type CannonTraceProvider struct {
dir string dir string
prestate string
generator ProofGenerator generator ProofGenerator
} }
func NewTraceProvider(logger log.Logger, cfg *config.Config) *CannonTraceProvider { func NewTraceProvider(logger log.Logger, cfg *config.Config) *CannonTraceProvider {
return &CannonTraceProvider{ return &CannonTraceProvider{
dir: cfg.CannonDatadir, dir: cfg.CannonDatadir,
prestate: cfg.CannonAbsolutePreState,
generator: NewExecutor(logger, cfg), generator: NewExecutor(logger, cfg),
} }
} }
...@@ -82,8 +85,19 @@ func (p *CannonTraceProvider) GetPreimage(ctx context.Context, i uint64) ([]byte ...@@ -82,8 +85,19 @@ func (p *CannonTraceProvider) GetPreimage(ctx context.Context, i uint64) ([]byte
return value, data, nil return value, data, nil
} }
func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) []byte { func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, error) {
panic("absolute prestate not yet supported") path := filepath.Join(p.dir, p.prestate)
file, err := os.Open(path)
if err != nil {
return []byte{}, fmt.Errorf("cannot open state file (%v): %w", path, err)
}
defer file.Close()
var state mipsevm.State
err = json.NewDecoder(file).Decode(&state)
if err != nil {
return []byte{}, fmt.Errorf("invalid mipsevm state (%v): %w", path, err)
}
return state.EncodeWitness(), nil
} }
func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofData, error) { func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofData, error) {
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -16,9 +17,9 @@ import ( ...@@ -16,9 +17,9 @@ import (
var testData embed.FS var testData embed.FS
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
dataDir := setupTestData(t) dataDir, prestate := setupTestData(t)
t.Run("ExistingProof", func(t *testing.T) { t.Run("ExistingProof", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
value, err := provider.Get(context.Background(), 0) value, err := provider.Get(context.Background(), 0)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, common.HexToHash("0x45fd9aa59768331c726e719e76aa343e73123af888804604785ae19506e65e87"), value) require.Equal(t, common.HexToHash("0x45fd9aa59768331c726e719e76aa343e73123af888804604785ae19506e65e87"), value)
...@@ -26,21 +27,21 @@ func TestGet(t *testing.T) { ...@@ -26,21 +27,21 @@ func TestGet(t *testing.T) {
}) })
t.Run("ProofUnavailable", func(t *testing.T) { t.Run("ProofUnavailable", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
_, err := provider.Get(context.Background(), 7) _, err := provider.Get(context.Background(), 7)
require.ErrorIs(t, err, os.ErrNotExist) require.ErrorIs(t, err, os.ErrNotExist)
require.Contains(t, generator.generated, 7, "should have tried to generate the proof") require.Contains(t, generator.generated, 7, "should have tried to generate the proof")
}) })
t.Run("MissingPostHash", func(t *testing.T) { t.Run("MissingPostHash", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
_, err := provider.Get(context.Background(), 1) _, err := provider.Get(context.Background(), 1)
require.ErrorContains(t, err, "missing post hash") require.ErrorContains(t, err, "missing post hash")
require.Empty(t, generator.generated) require.Empty(t, generator.generated)
}) })
t.Run("IgnoreUnknownFields", func(t *testing.T) { t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
value, err := provider.Get(context.Background(), 2) value, err := provider.Get(context.Background(), 2)
require.NoError(t, err) require.NoError(t, err)
expected := common.HexToHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") expected := common.HexToHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
...@@ -50,9 +51,9 @@ func TestGet(t *testing.T) { ...@@ -50,9 +51,9 @@ func TestGet(t *testing.T) {
} }
func TestGetOracleData(t *testing.T) { func TestGetOracleData(t *testing.T) {
dataDir := setupTestData(t) dataDir, prestate := setupTestData(t)
t.Run("ExistingProof", func(t *testing.T) { t.Run("ExistingProof", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
oracleData, err := provider.GetOracleData(context.Background(), 420) oracleData, err := provider.GetOracleData(context.Background(), 420)
require.NoError(t, err) require.NoError(t, err)
require.False(t, oracleData.IsLocal) require.False(t, oracleData.IsLocal)
...@@ -64,14 +65,14 @@ func TestGetOracleData(t *testing.T) { ...@@ -64,14 +65,14 @@ func TestGetOracleData(t *testing.T) {
}) })
t.Run("ProofUnavailable", func(t *testing.T) { t.Run("ProofUnavailable", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
_, err := provider.GetOracleData(context.Background(), 7) _, err := provider.GetOracleData(context.Background(), 7)
require.ErrorIs(t, err, os.ErrNotExist) require.ErrorIs(t, err, os.ErrNotExist)
require.Contains(t, generator.generated, 7, "should have tried to generate the proof") require.Contains(t, generator.generated, 7, "should have tried to generate the proof")
}) })
t.Run("IgnoreUnknownFields", func(t *testing.T) { t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
oracleData, err := provider.GetOracleData(context.Background(), 421) oracleData, err := provider.GetOracleData(context.Background(), 421)
require.NoError(t, err) require.NoError(t, err)
require.False(t, oracleData.IsLocal) require.False(t, oracleData.IsLocal)
...@@ -84,9 +85,9 @@ func TestGetOracleData(t *testing.T) { ...@@ -84,9 +85,9 @@ func TestGetOracleData(t *testing.T) {
} }
func TestGetPreimage(t *testing.T) { func TestGetPreimage(t *testing.T) {
dataDir := setupTestData(t) dataDir, prestate := setupTestData(t)
t.Run("ExistingProof", func(t *testing.T) { t.Run("ExistingProof", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
value, proof, err := provider.GetPreimage(context.Background(), 0) value, proof, err := provider.GetPreimage(context.Background(), 0)
require.NoError(t, err) require.NoError(t, err)
expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000") expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000")
...@@ -97,21 +98,21 @@ func TestGetPreimage(t *testing.T) { ...@@ -97,21 +98,21 @@ func TestGetPreimage(t *testing.T) {
}) })
t.Run("ProofUnavailable", func(t *testing.T) { t.Run("ProofUnavailable", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
_, _, err := provider.GetPreimage(context.Background(), 7) _, _, err := provider.GetPreimage(context.Background(), 7)
require.ErrorIs(t, err, os.ErrNotExist) require.ErrorIs(t, err, os.ErrNotExist)
require.Contains(t, generator.generated, 7, "should have tried to generate the proof") require.Contains(t, generator.generated, 7, "should have tried to generate the proof")
}) })
t.Run("MissingStateData", func(t *testing.T) { t.Run("MissingStateData", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
_, _, err := provider.GetPreimage(context.Background(), 1) _, _, err := provider.GetPreimage(context.Background(), 1)
require.ErrorContains(t, err, "missing state data") require.ErrorContains(t, err, "missing state data")
require.Empty(t, generator.generated) require.Empty(t, generator.generated)
}) })
t.Run("IgnoreUnknownFields", func(t *testing.T) { t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir) provider, generator := setupWithTestData(dataDir, prestate)
value, proof, err := provider.GetPreimage(context.Background(), 2) value, proof, err := provider.GetPreimage(context.Background(), 2)
require.NoError(t, err) require.NoError(t, err)
expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc") expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")
...@@ -122,7 +123,58 @@ func TestGetPreimage(t *testing.T) { ...@@ -122,7 +123,58 @@ func TestGetPreimage(t *testing.T) {
}) })
} }
func setupTestData(t *testing.T) string { func TestAbsolutePreState(t *testing.T) {
dataDir := t.TempDir()
_ = os.Mkdir(dataDir, 0o777)
prestate := "state.json"
t.Run("StateUnavailable", func(t *testing.T) {
provider, _ := setupWithTestData("/dir/does/not/exist", prestate)
_, err := provider.AbsolutePreState(context.Background())
require.ErrorIs(t, err, os.ErrNotExist)
})
t.Run("InvalidStateFile", func(t *testing.T) {
setupPreState(t, dataDir, "invalid.json")
provider, _ := setupWithTestData(dataDir, prestate)
_, err := provider.AbsolutePreState(context.Background())
require.ErrorContains(t, err, "invalid mipsevm state")
})
t.Run("ExpectedAbsolutePreState", func(t *testing.T) {
setupPreState(t, dataDir, "state.json")
provider, _ := setupWithTestData(dataDir, prestate)
preState, err := provider.AbsolutePreState(context.Background())
require.NoError(t, err)
state := mipsevm.State{
Memory: mipsevm.NewMemory(),
PreimageKey: common.HexToHash("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"),
PreimageOffset: 0,
PC: 0,
NextPC: 1,
LO: 0,
HI: 0,
Heap: 0,
ExitCode: 0,
Exited: false,
Step: 0,
Registers: [32]uint32{},
}
require.Equal(t, state.EncodeWitness(), preState)
})
}
func setupPreState(t *testing.T, dataDir string, filename string) {
srcDir := filepath.Join("test_data")
path := filepath.Join(srcDir, filename)
file, err := testData.ReadFile(path)
require.NoErrorf(t, err, "reading %v", path)
err = os.WriteFile(filepath.Join(dataDir, "state.json"), file, 0o644)
require.NoErrorf(t, err, "writing %v", path)
}
func setupTestData(t *testing.T) (string, string) {
srcDir := filepath.Join("test_data", "proofs") srcDir := filepath.Join("test_data", "proofs")
entries, err := testData.ReadDir(srcDir) entries, err := testData.ReadDir(srcDir)
require.NoError(t, err) require.NoError(t, err)
...@@ -132,17 +184,18 @@ func setupTestData(t *testing.T) string { ...@@ -132,17 +184,18 @@ func setupTestData(t *testing.T) string {
path := filepath.Join(srcDir, entry.Name()) path := filepath.Join(srcDir, entry.Name())
file, err := testData.ReadFile(path) file, err := testData.ReadFile(path)
require.NoErrorf(t, err, "reading %v", path) require.NoErrorf(t, err, "reading %v", path)
err = os.WriteFile(filepath.Join(dataDir, "proofs", entry.Name()), file, 0o644) err = os.WriteFile(filepath.Join(dataDir, proofsDir, entry.Name()), file, 0o644)
require.NoErrorf(t, err, "writing %v", path) require.NoErrorf(t, err, "writing %v", path)
} }
return dataDir return dataDir, "state.json"
} }
func setupWithTestData(dataDir string) (*CannonTraceProvider, *stubGenerator) { func setupWithTestData(dataDir string, prestate string) (*CannonTraceProvider, *stubGenerator) {
generator := &stubGenerator{} generator := &stubGenerator{}
return &CannonTraceProvider{ return &CannonTraceProvider{
dir: dataDir, dir: dataDir,
generator: generator, generator: generator,
prestate: prestate,
}, generator }, generator
} }
......
{
"memory": [],
"preimageKey": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"preimageOffset": 0,
"pc": 0,
"nextPC": 1,
"lo": 0,
"hi": 0,
"heap": 0,
"exit": 0,
"exited": false,
"step": 0,
"registers": []
}
...@@ -73,7 +73,11 @@ func (s *Solver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithCl ...@@ -73,7 +73,11 @@ func (s *Solver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithCl
var proofData []byte var proofData []byte
// If we are attacking index 0, we provide the absolute pre-state, not an intermediate state // If we are attacking index 0, we provide the absolute pre-state, not an intermediate state
if index == 0 && !claimCorrect { if index == 0 && !claimCorrect {
preState = s.trace.AbsolutePreState(ctx) state, err := s.trace.AbsolutePreState(ctx)
if err != nil {
return StepData{}, err
}
preState = state
} else { } else {
// If attacking, get the state just before, other get the state after // If attacking, get the state just before, other get the state after
if !claimCorrect { if !claimCorrect {
......
...@@ -113,6 +113,9 @@ func TestAttemptStep(t *testing.T) { ...@@ -113,6 +113,9 @@ func TestAttemptStep(t *testing.T) {
ctx := context.Background() ctx := context.Background()
preState, err := builder.CorrectTraceProvider().AbsolutePreState(ctx)
require.NoError(t, err)
tests := []struct { tests := []struct {
name string name string
claim types.Claim claim types.Claim
...@@ -129,7 +132,7 @@ func TestAttemptStep(t *testing.T) { ...@@ -129,7 +132,7 @@ func TestAttemptStep(t *testing.T) {
name: "AttackFirstTraceIndex", name: "AttackFirstTraceIndex",
claim: builder.CreateLeafClaim(0, false), claim: builder.CreateLeafClaim(0, false),
expectAttack: true, expectAttack: true,
expectPreState: builder.CorrectTraceProvider().AbsolutePreState(ctx), expectPreState: preState,
expectProofData: nil, expectProofData: nil,
expectedOracleKey: []byte{byte(0)}, expectedOracleKey: []byte{byte(0)},
expectedOracleData: []byte{byte(0)}, expectedOracleData: []byte{byte(0)},
......
...@@ -60,7 +60,7 @@ type TraceProvider interface { ...@@ -60,7 +60,7 @@ type TraceProvider interface {
GetPreimage(ctx context.Context, i uint64) (preimage []byte, proofData []byte, err error) GetPreimage(ctx context.Context, i uint64) (preimage []byte, proofData []byte, err error)
// AbsolutePreState is the pre-image value of the trace that transitions to the trace value at index 0 // AbsolutePreState is the pre-image value of the trace that transitions to the trace value at index 0
AbsolutePreState(ctx context.Context) []byte AbsolutePreState(ctx context.Context) ([]byte, error)
} }
// ClaimData is the core of a claim. It must be unique inside a specific game. // ClaimData is the core of a claim. It must be unique inside a specific game.
......
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