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
COPY ./go.sum /app/go.sum
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
RUN go mod download
......
......@@ -57,8 +57,9 @@ func (ap *AlphabetTraceProvider) Get(ctx context.Context, i uint64) (common.Hash
return crypto.Keccak256Hash(claimBytes), nil
}
func (ap *AlphabetTraceProvider) AbsolutePreState(ctx context.Context) []byte {
return common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000060")
// AbsolutePreState returns the absolute pre-state for the alphabet trace.
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.
......
......@@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum/go-ethereum/common"
......@@ -34,12 +35,14 @@ type ProofGenerator interface {
type CannonTraceProvider struct {
dir string
prestate string
generator ProofGenerator
}
func NewTraceProvider(logger log.Logger, cfg *config.Config) *CannonTraceProvider {
return &CannonTraceProvider{
dir: cfg.CannonDatadir,
prestate: cfg.CannonAbsolutePreState,
generator: NewExecutor(logger, cfg),
}
}
......@@ -82,8 +85,19 @@ func (p *CannonTraceProvider) GetPreimage(ctx context.Context, i uint64) ([]byte
return value, data, nil
}
func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) []byte {
panic("absolute prestate not yet supported")
func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, error) {
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) {
......
......@@ -8,6 +8,7 @@ import (
"path/filepath"
"testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
......@@ -16,9 +17,9 @@ import (
var testData embed.FS
func TestGet(t *testing.T) {
dataDir := setupTestData(t)
dataDir, prestate := setupTestData(t)
t.Run("ExistingProof", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir)
provider, generator := setupWithTestData(dataDir, prestate)
value, err := provider.Get(context.Background(), 0)
require.NoError(t, err)
require.Equal(t, common.HexToHash("0x45fd9aa59768331c726e719e76aa343e73123af888804604785ae19506e65e87"), value)
......@@ -26,21 +27,21 @@ func TestGet(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)
require.ErrorIs(t, err, os.ErrNotExist)
require.Contains(t, generator.generated, 7, "should have tried to generate the proof")
})
t.Run("MissingPostHash", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir)
provider, generator := setupWithTestData(dataDir, prestate)
_, err := provider.Get(context.Background(), 1)
require.ErrorContains(t, err, "missing post hash")
require.Empty(t, generator.generated)
})
t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir)
provider, generator := setupWithTestData(dataDir, prestate)
value, err := provider.Get(context.Background(), 2)
require.NoError(t, err)
expected := common.HexToHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
......@@ -50,9 +51,9 @@ func TestGet(t *testing.T) {
}
func TestGetOracleData(t *testing.T) {
dataDir := setupTestData(t)
dataDir, prestate := setupTestData(t)
t.Run("ExistingProof", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir)
provider, generator := setupWithTestData(dataDir, prestate)
oracleData, err := provider.GetOracleData(context.Background(), 420)
require.NoError(t, err)
require.False(t, oracleData.IsLocal)
......@@ -64,14 +65,14 @@ func TestGetOracleData(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)
require.ErrorIs(t, err, os.ErrNotExist)
require.Contains(t, generator.generated, 7, "should have tried to generate the proof")
})
t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir)
provider, generator := setupWithTestData(dataDir, prestate)
oracleData, err := provider.GetOracleData(context.Background(), 421)
require.NoError(t, err)
require.False(t, oracleData.IsLocal)
......@@ -84,9 +85,9 @@ func TestGetOracleData(t *testing.T) {
}
func TestGetPreimage(t *testing.T) {
dataDir := setupTestData(t)
dataDir, prestate := setupTestData(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)
require.NoError(t, err)
expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000")
......@@ -97,21 +98,21 @@ func TestGetPreimage(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)
require.ErrorIs(t, err, os.ErrNotExist)
require.Contains(t, generator.generated, 7, "should have tried to generate the proof")
})
t.Run("MissingStateData", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir)
provider, generator := setupWithTestData(dataDir, prestate)
_, _, err := provider.GetPreimage(context.Background(), 1)
require.ErrorContains(t, err, "missing state data")
require.Empty(t, generator.generated)
})
t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(dataDir)
provider, generator := setupWithTestData(dataDir, prestate)
value, proof, err := provider.GetPreimage(context.Background(), 2)
require.NoError(t, err)
expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")
......@@ -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")
entries, err := testData.ReadDir(srcDir)
require.NoError(t, err)
......@@ -132,17 +184,18 @@ func setupTestData(t *testing.T) string {
path := filepath.Join(srcDir, entry.Name())
file, err := testData.ReadFile(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)
}
return dataDir
return dataDir, "state.json"
}
func setupWithTestData(dataDir string) (*CannonTraceProvider, *stubGenerator) {
func setupWithTestData(dataDir string, prestate string) (*CannonTraceProvider, *stubGenerator) {
generator := &stubGenerator{}
return &CannonTraceProvider{
dir: dataDir,
generator: generator,
prestate: prestate,
}, 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
var proofData []byte
// If we are attacking index 0, we provide the absolute pre-state, not an intermediate state
if index == 0 && !claimCorrect {
preState = s.trace.AbsolutePreState(ctx)
state, err := s.trace.AbsolutePreState(ctx)
if err != nil {
return StepData{}, err
}
preState = state
} else {
// If attacking, get the state just before, other get the state after
if !claimCorrect {
......
......@@ -113,6 +113,9 @@ func TestAttemptStep(t *testing.T) {
ctx := context.Background()
preState, err := builder.CorrectTraceProvider().AbsolutePreState(ctx)
require.NoError(t, err)
tests := []struct {
name string
claim types.Claim
......@@ -129,7 +132,7 @@ func TestAttemptStep(t *testing.T) {
name: "AttackFirstTraceIndex",
claim: builder.CreateLeafClaim(0, false),
expectAttack: true,
expectPreState: builder.CorrectTraceProvider().AbsolutePreState(ctx),
expectPreState: preState,
expectProofData: nil,
expectedOracleKey: []byte{byte(0)},
expectedOracleData: []byte{byte(0)},
......
......@@ -60,7 +60,7 @@ type TraceProvider interface {
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(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.
......
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