Commit 9f93d78b authored by Adrian Sutton's avatar Adrian Sutton

op-challenger: Fix provision of pre-state, proof and oracle data from cannon

Combines GetPreimage and GetOracleData into GetStepData. GetStepData returns the data needed to execute the step at the specified trace index, so the state is the pre-state rather than matching the claim at the specified index. The proof data contains proofs for data accessed while executing the step and oracle data the pre-images required to execute the step. This matches up correctly with the data in the cannon proof files and what is required when calling the step function.
parent 5e7efe5a
...@@ -134,23 +134,19 @@ func (a *Agent) step(ctx context.Context, claim types.Claim, game types.Game) er ...@@ -134,23 +134,19 @@ func (a *Agent) step(ctx context.Context, claim types.Claim, game types.Game) er
return nil return nil
} }
oracleData, err := a.solver.GetOracleData(ctx, claim)
if err != nil {
a.log.Debug("Failed to get oracle data", "err", err)
return nil
}
a.log.Info("Updating oracle data", "oracleKey", oracleData.OracleKey, "oracleData", oracleData.OracleData)
if err := a.updater.UpdateOracle(ctx, oracleData); err != nil {
return fmt.Errorf("failed to load oracle data: %w", err)
}
a.log.Info("Attempting step", "claim_depth", claim.Depth(), "maxDepth", a.maxDepth) a.log.Info("Attempting step", "claim_depth", claim.Depth(), "maxDepth", a.maxDepth)
step, err := a.solver.AttemptStep(ctx, claim, agreeWithClaimLevel) step, err := a.solver.AttemptStep(ctx, claim, agreeWithClaimLevel)
if err != nil { if err != nil {
return fmt.Errorf("attempt step: %w", err) return fmt.Errorf("attempt step: %w", err)
} }
if step.OracleData != nil {
a.log.Info("Updating oracle data", "oracleKey", step.OracleData.OracleKey, "oracleData", step.OracleData.OracleData)
if err := a.updater.UpdateOracle(ctx, step.OracleData); err != nil {
return fmt.Errorf("failed to load oracle data: %w", err)
}
}
a.log.Info("Performing step", "is_attack", step.IsAttack, a.log.Info("Performing step", "is_attack", step.IsAttack,
"depth", step.LeafClaim.Depth(), "index_at_depth", step.LeafClaim.IndexAtDepth(), "value", step.LeafClaim.Value) "depth", step.LeafClaim.Depth(), "index_at_depth", step.LeafClaim.IndexAtDepth(), "value", step.LeafClaim.Value)
callData := types.StepCallData{ callData := types.StepCallData{
......
...@@ -30,27 +30,31 @@ func NewTraceProvider(state string, depth uint64) *AlphabetTraceProvider { ...@@ -30,27 +30,31 @@ func NewTraceProvider(state string, depth uint64) *AlphabetTraceProvider {
} }
} }
// GetOracleData should not return any preimage oracle data for the alphabet provider. func (ap *AlphabetTraceProvider) GetStepData(ctx context.Context, i uint64) ([]byte, []byte, *types.PreimageOracleData, error) {
func (p *AlphabetTraceProvider) GetOracleData(ctx context.Context, i uint64) (*types.PreimageOracleData, error) { if i == 0 {
return &types.PreimageOracleData{}, nil prestate, err := ap.AbsolutePreState(ctx)
} if err != nil {
return nil, nil, nil, err
// GetPreimage returns the preimage for the given hash. }
func (ap *AlphabetTraceProvider) GetPreimage(ctx context.Context, i uint64) ([]byte, []byte, error) { return prestate, []byte{}, nil, nil
}
// We want the pre-state which is the value prior to the one requested
i--
// The index cannot be larger than the maximum index as computed by the depth. // The index cannot be larger than the maximum index as computed by the depth.
if i >= ap.maxLen { if i >= ap.maxLen {
return nil, nil, ErrIndexTooLarge return nil, nil, nil, ErrIndexTooLarge
} }
// We extend the deepest hash to the maximum depth if the trace is not expansive. // We extend the deepest hash to the maximum depth if the trace is not expansive.
if i >= uint64(len(ap.state)) { if i >= uint64(len(ap.state)) {
return ap.GetPreimage(ctx, uint64(len(ap.state))-1) return ap.GetStepData(ctx, uint64(len(ap.state)))
} }
return BuildAlphabetPreimage(i, ap.state[i]), []byte{}, nil return BuildAlphabetPreimage(i, ap.state[i]), []byte{}, nil, nil
} }
// Get returns the claim value at the given index in the trace. // Get returns the claim value at the given index in the trace.
func (ap *AlphabetTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, error) { func (ap *AlphabetTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, error) {
claimBytes, _, err := ap.GetPreimage(ctx, i) // Step data returns the pre-state, so add 1 to get the state for index i
claimBytes, _, _, err := ap.GetStepData(ctx, i+1)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
......
...@@ -58,20 +58,21 @@ func FuzzIndexToBytes(f *testing.F) { ...@@ -58,20 +58,21 @@ func FuzzIndexToBytes(f *testing.F) {
// TestGetPreimage_Succeeds tests the GetPreimage function // TestGetPreimage_Succeeds tests the GetPreimage function
// returns the correct pre-image for a index. // returns the correct pre-image for a index.
func TestGetPreimage_Succeeds(t *testing.T) { func TestGetStepData_Succeeds(t *testing.T) {
ap := NewTraceProvider("abc", 2) ap := NewTraceProvider("abc", 2)
expected := BuildAlphabetPreimage(0, "a'") expected := BuildAlphabetPreimage(0, "a'")
retrieved, proof, err := ap.GetPreimage(context.Background(), uint64(0)) retrieved, proof, data, err := ap.GetStepData(context.Background(), uint64(1))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expected, retrieved) require.Equal(t, expected, retrieved)
require.Empty(t, proof) require.Empty(t, proof)
require.Nil(t, data)
} }
// TestGetPreimage_TooLargeIndex_Fails tests the GetPreimage // TestGetPreimage_TooLargeIndex_Fails tests the GetPreimage
// function errors if the index is too large. // function errors if the index is too large.
func TestGetPreimage_TooLargeIndex_Fails(t *testing.T) { func TestGetStepData_TooLargeIndex_Fails(t *testing.T) {
ap := NewTraceProvider("abc", 2) ap := NewTraceProvider("abc", 2)
_, _, err := ap.GetPreimage(context.Background(), 4) _, _, _, err := ap.GetStepData(context.Background(), 5)
require.ErrorIs(t, err, ErrIndexTooLarge) require.ErrorIs(t, err, ErrIndexTooLarge)
} }
......
...@@ -8,7 +8,6 @@ import ( ...@@ -8,7 +8,6 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
"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"
...@@ -47,6 +46,8 @@ type CannonTraceProvider struct { ...@@ -47,6 +46,8 @@ type CannonTraceProvider struct {
// lastStep stores the last step in the actual trace if known. 0 indicates unknown. // lastStep stores the last step in the actual trace if known. 0 indicates unknown.
// Cached as an optimisation to avoid repeatedly attempting to execute beyond the end of the trace. // Cached as an optimisation to avoid repeatedly attempting to execute beyond the end of the trace.
lastStep uint64 lastStep uint64
// lastProof stores the proof data to use for all steps extended beyond lastStep
lastProof *proofData
} }
func NewTraceProvider(ctx context.Context, logger log.Logger, cfg *config.Config, l1Client bind.ContractCaller) (*CannonTraceProvider, error) { func NewTraceProvider(ctx context.Context, logger log.Logger, cfg *config.Config, l1Client bind.ContractCaller) (*CannonTraceProvider, error) {
...@@ -71,24 +72,11 @@ func NewTraceProvider(ctx context.Context, logger log.Logger, cfg *config.Config ...@@ -71,24 +72,11 @@ func NewTraceProvider(ctx context.Context, logger log.Logger, cfg *config.Config
}, nil }, nil
} }
func (p *CannonTraceProvider) GetOracleData(ctx context.Context, i uint64) (*types.PreimageOracleData, error) {
proof, err := p.loadProofData(ctx, i)
if err != nil {
return nil, err
}
data := types.NewPreimageOracleData(proof.OracleKey, proof.OracleValue, proof.OracleOffset)
return &data, nil
}
func (p *CannonTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, error) { func (p *CannonTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, error) {
proof, state, err := p.loadProof(ctx, i) proof, err := p.loadProof(ctx, i)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
if proof == nil && state != nil {
// Use the hash from the final state
return crypto.Keccak256Hash(state.EncodeWitness()), nil
}
value := common.BytesToHash(proof.ClaimValue) value := common.BytesToHash(proof.ClaimValue)
if value == (common.Hash{}) { if value == (common.Hash{}) {
...@@ -97,66 +85,46 @@ func (p *CannonTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, e ...@@ -97,66 +85,46 @@ func (p *CannonTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, e
return value, nil return value, nil
} }
func (p *CannonTraceProvider) GetPreimage(ctx context.Context, i uint64) ([]byte, []byte, error) { func (p *CannonTraceProvider) GetStepData(ctx context.Context, i uint64) ([]byte, []byte, *types.PreimageOracleData, error) {
proof, err := p.loadProofData(ctx, i) proof, err := p.loadProof(ctx, i)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
value := ([]byte)(proof.StateData) value := ([]byte)(proof.StateData)
if len(value) == 0 { if len(value) == 0 {
return nil, nil, errors.New("proof missing state data") return nil, nil, nil, errors.New("proof missing state data")
} }
data := ([]byte)(proof.ProofData) data := ([]byte)(proof.ProofData)
if len(data) == 0 { if data == nil {
return nil, nil, errors.New("proof missing proof data") return nil, nil, nil, errors.New("proof missing proof data")
}
var oracleData *types.PreimageOracleData
if len(proof.OracleKey) > 0 {
oracleData = types.NewPreimageOracleData(proof.OracleKey, proof.OracleValue, proof.OracleOffset)
} }
return value, data, nil return value, data, oracleData, nil
} }
func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, error) { func (p *CannonTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, error) {
state, err := parseState(p.prestate) state, err := parseState(p.prestate)
if err != nil { if err != nil {
return []byte{}, fmt.Errorf("cannot load absolute pre-state: %w", err) return nil, fmt.Errorf("cannot load absolute pre-state: %w", err)
} }
return state.EncodeWitness(), nil return state.EncodeWitness(), nil
} }
// loadProofData loads the proof data for the specified step.
// If the requested index is beyond the end of the actual trace, the proof data from the last step is returned.
// Cannon will be executed a second time if required to generate the full proof data.
func (p *CannonTraceProvider) loadProofData(ctx context.Context, i uint64) (*proofData, error) {
proof, state, err := p.loadProof(ctx, i)
if err != nil {
return nil, err
} else if proof == nil && state != nil {
p.logger.Info("Re-executing to generate proof for last step", "step", state.Step)
proof, _, err = p.loadProof(ctx, state.Step)
if err != nil {
return nil, err
}
if proof == nil {
return nil, fmt.Errorf("proof at step %v was not generated", i)
}
return proof, nil
}
return proof, nil
}
// loadProof will attempt to load or generate the proof data at the specified index // loadProof will attempt to load or generate the proof data at the specified index
// If the requested index is beyond the end of the actual trace: // If the requested index is beyond the end of the actual trace it is extended with no-op instructions.
// - When the actual trace length is known, the proof data from the last step is returned with nil state func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofData, error) {
// - When the actual trace length is not yet know, the state from after the last step is returned with nil proofData if p.lastProof != nil && i > p.lastStep {
// and the actual trace length is cached for future runs // If the requested index is after the last step in the actual trace, extend the final no-op step
func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofData, *mipsevm.State, error) { return p.lastProof, nil
if p.lastStep != 0 && i > p.lastStep {
// If the requested index is after the last step in the actual trace, use the last step
i = p.lastStep
} }
path := filepath.Join(p.dir, proofsDir, fmt.Sprintf("%d.json", i)) path := filepath.Join(p.dir, proofsDir, fmt.Sprintf("%d.json", i))
file, err := os.Open(path) file, err := os.Open(path)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
if err := p.generator.GenerateProof(ctx, p.dir, i); err != nil { if err := p.generator.GenerateProof(ctx, p.dir, i); err != nil {
return nil, nil, fmt.Errorf("generate cannon trace with proof at %v: %w", i, err) return nil, fmt.Errorf("generate cannon trace with proof at %v: %w", i, err)
} }
// Try opening the file again now and it should exist. // Try opening the file again now and it should exist.
file, err = os.Open(path) file, err = os.Open(path)
...@@ -164,27 +132,39 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofDa ...@@ -164,27 +132,39 @@ func (p *CannonTraceProvider) loadProof(ctx context.Context, i uint64) (*proofDa
// 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
state, err := parseState(filepath.Join(p.dir, finalState)) state, err := parseState(filepath.Join(p.dir, finalState))
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("cannot read final state: %w", err) return nil, fmt.Errorf("cannot read final state: %w", err)
} }
if state.Exited && state.Step < i { if state.Exited && state.Step <= i {
p.logger.Warn("Requested proof was after the program exited", "proof", i, "last", state.Step) p.logger.Warn("Requested proof was after the program exited", "proof", i, "last", state.Step)
// The final instruction has already been applied to this state, so the last step we can execute // The final instruction has already been applied to this state, so the last step we can execute
// is one before its Step value. // is one before its Step value.
p.lastStep = state.Step - 1 p.lastStep = state.Step - 1
return nil, state, nil // 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.
witness := state.EncodeWitness()
proof := &proofData{
ClaimValue: crypto.Keccak256(witness),
StateData: witness,
ProofData: []byte{},
OracleKey: nil,
OracleValue: nil,
OracleOffset: 0,
}
p.lastProof = proof
return proof, nil
} else { } else {
return nil, nil, fmt.Errorf("expected proof not generated but final state was not exited, requested step %v, final state at step %v", i, state.Step) return nil, fmt.Errorf("expected proof not generated but final state was not exited, requested step %v, final state at step %v", i, state.Step)
} }
} }
} }
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("cannot open proof file (%v): %w", path, err) return nil, fmt.Errorf("cannot open proof file (%v): %w", path, err)
} }
defer file.Close() defer file.Close()
var proof proofData var proof proofData
err = json.NewDecoder(file).Decode(&proof) err = json.NewDecoder(file).Decode(&proof)
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("failed to read proof (%v): %w", path, err) return nil, fmt.Errorf("failed to read proof (%v): %w", path, err)
} }
return &proof, nil, nil return &proof, nil
} }
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"testing" "testing"
"github.com/ethereum-optimism/optimism/cannon/mipsevm" "github.com/ethereum-optimism/optimism/cannon/mipsevm"
"github.com/ethereum-optimism/optimism/op-challenger/fault/types"
"github.com/ethereum-optimism/optimism/op-node/testlog" "github.com/ethereum-optimism/optimism/op-node/testlog"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
...@@ -61,21 +62,22 @@ func TestGet(t *testing.T) { ...@@ -61,21 +62,22 @@ func TestGet(t *testing.T) {
}) })
} }
func TestGetOracleData(t *testing.T) { func TestGetStepData(t *testing.T) {
dataDir, prestate := setupTestData(t) dataDir, prestate := setupTestData(t)
t.Run("ExistingProof", func(t *testing.T) { t.Run("ExistingProof", func(t *testing.T) {
provider, generator := setupWithTestData(t, dataDir, prestate) provider, generator := setupWithTestData(t, dataDir, prestate)
oracleData, err := provider.GetOracleData(context.Background(), 420) value, proof, data, err := provider.GetStepData(context.Background(), 0)
require.NoError(t, err) require.NoError(t, err)
require.False(t, oracleData.IsLocal) expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000")
expectedKey := common.Hex2Bytes("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee") require.Equal(t, expected, value)
require.Equal(t, expectedKey, oracleData.OracleKey) expectedProof := common.Hex2Bytes("08028e3c0000000000000000000000003c01000a24210b7c00200008000000008fa40004")
expectedData := common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") require.Equal(t, expectedProof, proof)
require.Equal(t, expectedData, oracleData.OracleData) // TODO: Need to add some oracle data
require.Nil(t, data)
require.Empty(t, generator.generated) require.Empty(t, generator.generated)
}) })
t.Run("ProofAfterEndOfTrace", func(t *testing.T) { t.Run("GenerateProof", func(t *testing.T) {
provider, generator := setupWithTestData(t, dataDir, prestate) provider, generator := setupWithTestData(t, dataDir, prestate)
generator.finalState = &mipsevm.State{ generator.finalState = &mipsevm.State{
Memory: &mipsevm.Memory{}, Memory: &mipsevm.Memory{},
...@@ -90,39 +92,14 @@ func TestGetOracleData(t *testing.T) { ...@@ -90,39 +92,14 @@ func TestGetOracleData(t *testing.T) {
OracleValue: []byte{0xdd}, OracleValue: []byte{0xdd},
OracleOffset: 10, OracleOffset: 10,
} }
oracleData, err := provider.GetOracleData(context.Background(), 7000) preimage, proof, data, err := provider.GetStepData(context.Background(), 4)
require.NoError(t, err)
require.Contains(t, generator.generated, 7000, "should have tried to generate the proof")
require.Contains(t, generator.generated, 9, "should have regenerated proof from last step")
require.False(t, oracleData.IsLocal)
require.EqualValues(t, generator.proof.OracleKey, oracleData.OracleKey)
require.EqualValues(t, generator.proof.OracleValue, oracleData.OracleData)
})
t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(t, dataDir, prestate)
oracleData, err := provider.GetOracleData(context.Background(), 421)
require.NoError(t, err) require.NoError(t, err)
require.False(t, oracleData.IsLocal) require.Contains(t, generator.generated, 4, "should have tried to generate the proof")
expectedKey := common.Hex2Bytes("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee")
require.Equal(t, expectedKey, oracleData.OracleKey)
expectedData := common.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
require.Equal(t, expectedData, oracleData.OracleData)
require.Empty(t, generator.generated)
})
}
func TestGetPreimage(t *testing.T) { require.EqualValues(t, generator.proof.StateData, preimage)
dataDir, prestate := setupTestData(t) require.EqualValues(t, generator.proof.ProofData, proof)
t.Run("ExistingProof", func(t *testing.T) { expectedData := types.NewPreimageOracleData(generator.proof.OracleKey, generator.proof.OracleValue, generator.proof.OracleOffset)
provider, generator := setupWithTestData(t, dataDir, prestate) require.EqualValues(t, expectedData, data)
value, proof, err := provider.GetPreimage(context.Background(), 0)
require.NoError(t, err)
expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000")
require.Equal(t, expected, value)
expectedProof := common.Hex2Bytes("08028e3c0000000000000000000000003c01000a24210b7c00200008000000008fa40004")
require.Equal(t, expectedProof, proof)
require.Empty(t, generator.generated)
}) })
t.Run("ProofAfterEndOfTrace", func(t *testing.T) { t.Run("ProofAfterEndOfTrace", func(t *testing.T) {
...@@ -140,30 +117,33 @@ func TestGetPreimage(t *testing.T) { ...@@ -140,30 +117,33 @@ func TestGetPreimage(t *testing.T) {
OracleValue: []byte{0xdd}, OracleValue: []byte{0xdd},
OracleOffset: 10, OracleOffset: 10,
} }
preimage, proof, err := provider.GetPreimage(context.Background(), 7000) preimage, proof, data, err := provider.GetStepData(context.Background(), 7000)
require.NoError(t, err) require.NoError(t, err)
require.Contains(t, generator.generated, 7000, "should have tried to generate the proof") require.Contains(t, generator.generated, 7000, "should have tried to generate the proof")
require.Contains(t, generator.generated, 9, "should have regenerated proof from last step")
require.EqualValues(t, generator.proof.StateData, preimage) witness := generator.finalState.EncodeWitness()
require.EqualValues(t, generator.proof.ProofData, proof) require.EqualValues(t, witness, preimage)
require.Equal(t, []byte{}, proof)
require.Nil(t, data)
}) })
t.Run("MissingStateData", func(t *testing.T) { t.Run("MissingStateData", func(t *testing.T) {
provider, generator := setupWithTestData(t, dataDir, prestate) provider, generator := setupWithTestData(t, dataDir, prestate)
_, _, err := provider.GetPreimage(context.Background(), 1) _, _, _, err := provider.GetStepData(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(t, dataDir, prestate) provider, generator := setupWithTestData(t, dataDir, prestate)
value, proof, err := provider.GetPreimage(context.Background(), 2) value, proof, data, err := provider.GetStepData(context.Background(), 2)
require.NoError(t, err) require.NoError(t, err)
expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc") expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")
require.Equal(t, expected, value) require.Equal(t, expected, value)
expectedProof := common.Hex2Bytes("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd") expectedProof := common.Hex2Bytes("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd")
require.Equal(t, expectedProof, proof) require.Equal(t, expectedProof, proof)
require.Empty(t, generator.generated) require.Empty(t, generator.generated)
require.Nil(t, data)
}) })
} }
......
...@@ -87,9 +87,6 @@ func NewOracleUpdaterWithOracle( ...@@ -87,9 +87,6 @@ func NewOracleUpdaterWithOracle(
// UpdateOracle updates the oracle with the given data. // UpdateOracle updates the oracle with the given data.
func (u *cannonUpdater) UpdateOracle(ctx context.Context, data *types.PreimageOracleData) error { func (u *cannonUpdater) UpdateOracle(ctx context.Context, data *types.PreimageOracleData) error {
if len(data.OracleKey) == 0 {
return nil
}
if data.IsLocal { if data.IsLocal {
return u.sendLocalOracleData(ctx, data) return u.sendLocalOracleData(ctx, data)
} }
......
...@@ -89,12 +89,6 @@ func TestCannonUpdater_UpdateOracle(t *testing.T) { ...@@ -89,12 +89,6 @@ func TestCannonUpdater_UpdateOracle(t *testing.T) {
})) }))
require.Equal(t, 1, mockTxMgr.failedSends) require.Equal(t, 1, mockTxMgr.failedSends)
}) })
t.Run("skip empty data", func(t *testing.T) {
updater, mockTxMgr := newTestCannonUpdater(t, true)
require.NoError(t, updater.UpdateOracle(context.Background(), &types.PreimageOracleData{}))
require.Equal(t, 0, mockTxMgr.sends)
})
} }
// TestCannonUpdater_BuildLocalOracleData tests the [cannonUpdater] // TestCannonUpdater_BuildLocalOracleData tests the [cannonUpdater]
......
...@@ -28,12 +28,6 @@ func NewSolver(gameDepth int, traceProvider types.TraceProvider) *Solver { ...@@ -28,12 +28,6 @@ func NewSolver(gameDepth int, traceProvider types.TraceProvider) *Solver {
} }
} }
// GetOracleData returns the oracle data for the provided claim.
// It passes through to the [TraceProvider] by finding the trace index for the claim.
func (s *Solver) GetOracleData(ctx context.Context, claim types.Claim) (*types.PreimageOracleData, error) {
return s.trace.GetOracleData(ctx, claim.TraceIndex(s.gameDepth))
}
// NextMove returns the next move to make given the current state of the game. // NextMove returns the next move to make given the current state of the game.
func (s *Solver) NextMove(ctx context.Context, claim types.Claim, agreeWithClaimLevel bool) (*types.Claim, error) { func (s *Solver) NextMove(ctx context.Context, claim types.Claim, agreeWithClaimLevel bool) (*types.Claim, error) {
if agreeWithClaimLevel { if agreeWithClaimLevel {
...@@ -58,7 +52,7 @@ type StepData struct { ...@@ -58,7 +52,7 @@ type StepData struct {
IsAttack bool IsAttack bool
PreState []byte PreState []byte
ProofData []byte ProofData []byte
OracleData types.PreimageOracleData OracleData *types.PreimageOracleData
} }
// AttemptStep determines what step should occur for a given leaf claim. // AttemptStep determines what step should occur for a given leaf claim.
...@@ -77,35 +71,30 @@ func (s *Solver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithCl ...@@ -77,35 +71,30 @@ func (s *Solver) AttemptStep(ctx context.Context, claim types.Claim, agreeWithCl
index := claim.TraceIndex(s.gameDepth) index := claim.TraceIndex(s.gameDepth)
var preState []byte var preState []byte
var proofData []byte var proofData []byte
// If we are attacking index 0, we provide the absolute pre-state, not an intermediate state var oracleData *types.PreimageOracleData
if index == 0 && !claimCorrect {
state, err := s.trace.AbsolutePreState(ctx) if !claimCorrect {
// Attack the claim by executing step index, so we need to get the pre-state of that index
preState, proofData, oracleData, err = s.trace.GetStepData(ctx, index)
if err != nil { if err != nil {
return StepData{}, err return StepData{}, err
} }
preState = state
} else { } else {
// If attacking, get the state just before, other get the state after // We agree with the claim so Defend and use this claim as the starting point to execute the step after
if !claimCorrect { // Thus we need the pre-state of the next step
index = index - 1 // Note: This makes our maximum depth 63 because we need to add 1 without overflowing.
} preState, proofData, oracleData, err = s.trace.GetStepData(ctx, index+1)
preState, proofData, err = s.trace.GetPreimage(ctx, index)
if err != nil { if err != nil {
return StepData{}, err return StepData{}, err
} }
} }
oracleData, err := s.trace.GetOracleData(ctx, index)
if err != nil {
return StepData{}, err
}
return StepData{ return StepData{
LeafClaim: claim, LeafClaim: claim,
IsAttack: !claimCorrect, IsAttack: !claimCorrect,
PreState: preState, PreState: preState,
ProofData: proofData, ProofData: proofData,
OracleData: *oracleData, OracleData: oracleData,
}, nil }, nil
} }
......
...@@ -113,9 +113,6 @@ func TestAttemptStep(t *testing.T) { ...@@ -113,9 +113,6 @@ 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
...@@ -124,63 +121,55 @@ func TestAttemptStep(t *testing.T) { ...@@ -124,63 +121,55 @@ func TestAttemptStep(t *testing.T) {
expectAttack bool expectAttack bool
expectPreState []byte expectPreState []byte
expectProofData []byte expectProofData []byte
expectedLocal bool expectedOracleData *types.PreimageOracleData
expectedOracleKey []byte
expectedOracleData []byte
}{ }{
{ {
name: "AttackFirstTraceIndex", name: "AttackFirstTraceIndex",
claim: builder.CreateLeafClaim(0, false), claim: builder.CreateLeafClaim(0, false),
expectAttack: true, expectAttack: true,
expectPreState: preState, expectPreState: builder.CorrectPreState(0),
expectProofData: nil, expectProofData: builder.CorrectProofData(0),
expectedOracleKey: []byte{byte(0)}, expectedOracleData: builder.CorrectOracleData(0),
expectedOracleData: []byte{byte(0)},
}, },
{ {
name: "DefendFirstTraceIndex", name: "DefendFirstTraceIndex",
claim: builder.CreateLeafClaim(0, true), claim: builder.CreateLeafClaim(0, true),
expectAttack: false, expectAttack: false,
expectPreState: builder.CorrectPreState(0), expectPreState: builder.CorrectPreState(1),
expectProofData: builder.CorrectProofData(0), expectProofData: builder.CorrectProofData(1),
expectedOracleKey: []byte{byte(0)}, expectedOracleData: builder.CorrectOracleData(1),
expectedOracleData: []byte{byte(0)},
}, },
{ {
name: "AttackMiddleTraceIndex", name: "AttackMiddleTraceIndex",
claim: builder.CreateLeafClaim(4, false), claim: builder.CreateLeafClaim(4, false),
expectAttack: true, expectAttack: true,
expectPreState: builder.CorrectPreState(3), expectPreState: builder.CorrectPreState(4),
expectProofData: builder.CorrectProofData(3), expectProofData: builder.CorrectProofData(4),
expectedOracleKey: []byte{byte(3)}, expectedOracleData: builder.CorrectOracleData(4),
expectedOracleData: []byte{byte(3)},
}, },
{ {
name: "DefendMiddleTraceIndex", name: "DefendMiddleTraceIndex",
claim: builder.CreateLeafClaim(4, true), claim: builder.CreateLeafClaim(4, true),
expectAttack: false, expectAttack: false,
expectPreState: builder.CorrectPreState(4), expectPreState: builder.CorrectPreState(5),
expectProofData: builder.CorrectProofData(4), expectProofData: builder.CorrectProofData(5),
expectedOracleKey: []byte{byte(4)}, expectedOracleData: builder.CorrectOracleData(5),
expectedOracleData: []byte{byte(4)},
}, },
{ {
name: "AttackLastTraceIndex", name: "AttackLastTraceIndex",
claim: builder.CreateLeafClaim(lastLeafTraceIndex, false), claim: builder.CreateLeafClaim(lastLeafTraceIndex, false),
expectAttack: true, expectAttack: true,
expectPreState: builder.CorrectPreState(lastLeafTraceIndex - 1), expectPreState: builder.CorrectPreState(lastLeafTraceIndex),
expectProofData: builder.CorrectProofData(lastLeafTraceIndex - 1), expectProofData: builder.CorrectProofData(lastLeafTraceIndex),
expectedOracleKey: []byte{byte(5)}, expectedOracleData: builder.CorrectOracleData(lastLeafTraceIndex),
expectedOracleData: []byte{byte(5)},
}, },
{ {
name: "DefendLastTraceIndex", name: "DefendLastTraceIndex",
claim: builder.CreateLeafClaim(lastLeafTraceIndex, true), claim: builder.CreateLeafClaim(lastLeafTraceIndex, true),
expectAttack: false, expectAttack: false,
expectPreState: builder.CorrectPreState(lastLeafTraceIndex), expectPreState: builder.CorrectPreState(lastLeafTraceIndex + 1),
expectProofData: builder.CorrectProofData(lastLeafTraceIndex), expectProofData: builder.CorrectProofData(lastLeafTraceIndex + 1),
expectedOracleKey: []byte{byte(6)}, expectedOracleData: builder.CorrectOracleData(lastLeafTraceIndex + 1),
expectedOracleData: []byte{byte(6)},
}, },
{ {
name: "CannotStepNonLeaf", name: "CannotStepNonLeaf",
...@@ -199,24 +188,6 @@ func TestAttemptStep(t *testing.T) { ...@@ -199,24 +188,6 @@ func TestAttemptStep(t *testing.T) {
agreeWithLevel: true, agreeWithLevel: true,
expectedErr: solver.ErrStepNonLeafNode, expectedErr: solver.ErrStepNonLeafNode,
}, },
{
name: "AttackLocalOracleData",
claim: builder.Seq(false).Attack(false).Attack(true).Defend(false).Get(),
expectAttack: true,
agreeWithLevel: false,
expectPreState: builder.CorrectPreState(1),
expectProofData: builder.CorrectProofData(1),
expectedLocal: true,
expectedOracleKey: []byte{0x01},
expectedOracleData: []byte{0x01},
expectedErr: nil,
},
{
name: "AttackStepOracleError",
claim: builder.Seq(false).Attack(false).Attack(false).Attack(false).Get(),
agreeWithLevel: false,
expectedErr: errProvider,
},
} }
for _, tableTest := range tests { for _, tableTest := range tests {
...@@ -235,9 +206,10 @@ func TestAttemptStep(t *testing.T) { ...@@ -235,9 +206,10 @@ func TestAttemptStep(t *testing.T) {
require.Equal(t, tableTest.expectAttack, step.IsAttack) require.Equal(t, tableTest.expectAttack, step.IsAttack)
require.Equal(t, tableTest.expectPreState, step.PreState) require.Equal(t, tableTest.expectPreState, step.PreState)
require.Equal(t, tableTest.expectProofData, step.ProofData) require.Equal(t, tableTest.expectProofData, step.ProofData)
require.Equal(t, tableTest.expectedLocal, step.OracleData.IsLocal) require.Equal(t, tableTest.expectedOracleData.IsLocal, step.OracleData.IsLocal)
require.Equal(t, tableTest.expectedOracleKey, step.OracleData.OracleKey) require.Equal(t, tableTest.expectedOracleData.OracleKey, step.OracleData.OracleKey)
require.Equal(t, tableTest.expectedOracleData, step.OracleData.OracleData) require.Equal(t, tableTest.expectedOracleData.OracleData, step.OracleData.OracleData)
require.Equal(t, tableTest.expectedOracleData.OracleOffset, step.OracleData.OracleOffset)
} else { } else {
require.ErrorIs(t, err, tableTest.expectedErr) require.ErrorIs(t, err, tableTest.expectedErr)
require.Equal(t, solver.StepData{}, step) require.Equal(t, solver.StepData{}, step)
......
...@@ -25,18 +25,11 @@ type alphabetWithProofProvider struct { ...@@ -25,18 +25,11 @@ type alphabetWithProofProvider struct {
OracleError error OracleError error
} }
func (a *alphabetWithProofProvider) GetPreimage(ctx context.Context, i uint64) ([]byte, []byte, error) { func (a *alphabetWithProofProvider) GetStepData(ctx context.Context, i uint64) ([]byte, []byte, *types.PreimageOracleData, error) {
preimage, _, err := a.AlphabetTraceProvider.GetPreimage(ctx, i) preimage, _, _, err := a.AlphabetTraceProvider.GetStepData(ctx, i)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
return preimage, []byte{byte(i)}, nil data := types.NewPreimageOracleData([]byte{byte(i)}, []byte{byte(i - 1)}, uint32(i-1))
} return preimage, []byte{byte(i - 1)}, data, nil
func (a *alphabetWithProofProvider) GetOracleData(ctx context.Context, i uint64) (*types.PreimageOracleData, error) {
if a.OracleError != nil {
return &types.PreimageOracleData{}, a.OracleError
}
data := types.NewPreimageOracleData([]byte{byte(i)}, []byte{byte(i)}, uint32(i))
return &data, nil
} }
...@@ -38,20 +38,26 @@ func (c *ClaimBuilder) CorrectClaim(idx uint64) common.Hash { ...@@ -38,20 +38,26 @@ func (c *ClaimBuilder) CorrectClaim(idx uint64) common.Hash {
return value return value
} }
// CorrectPreState returns the pre-image of the canonical claim at the specified trace index // CorrectPreState returns the pre-state (not hashed) required to execute the valid step at the specified trace index
func (c *ClaimBuilder) CorrectPreState(idx uint64) []byte { func (c *ClaimBuilder) CorrectPreState(idx uint64) []byte {
preimage, _, err := c.correct.GetPreimage(context.Background(), idx) preimage, _, _, err := c.correct.GetStepData(context.Background(), idx)
c.require.NoError(err) c.require.NoError(err)
return preimage return preimage
} }
// CorrectProofData returns the proof-data for the canonical claim at the specified trace index // CorrectProofData returns the proof-data required to execute the valid step at the specified trace index
func (c *ClaimBuilder) CorrectProofData(idx uint64) []byte { func (c *ClaimBuilder) CorrectProofData(idx uint64) []byte {
_, proof, err := c.correct.GetPreimage(context.Background(), idx) _, proof, _, err := c.correct.GetStepData(context.Background(), idx)
c.require.NoError(err) c.require.NoError(err)
return proof return proof
} }
func (c *ClaimBuilder) CorrectOracleData(idx uint64) *types.PreimageOracleData {
_, _, data, err := c.correct.GetStepData(context.Background(), idx)
c.require.NoError(err)
return data
}
func (c *ClaimBuilder) incorrectClaim(idx uint64) common.Hash { func (c *ClaimBuilder) incorrectClaim(idx uint64) common.Hash {
return common.BigToHash(new(big.Int).SetUint64(idx)) return common.BigToHash(new(big.Int).SetUint64(idx))
} }
......
...@@ -45,8 +45,8 @@ func (p *PreimageOracleData) GetPreimageWithoutSize() []byte { ...@@ -45,8 +45,8 @@ func (p *PreimageOracleData) GetPreimageWithoutSize() []byte {
} }
// NewPreimageOracleData creates a new [PreimageOracleData] instance. // NewPreimageOracleData creates a new [PreimageOracleData] instance.
func NewPreimageOracleData(key []byte, data []byte, offset uint32) PreimageOracleData { func NewPreimageOracleData(key []byte, data []byte, offset uint32) *PreimageOracleData {
return PreimageOracleData{ return &PreimageOracleData{
IsLocal: len(key) > 0 && key[0] == byte(1), IsLocal: len(key) > 0 && key[0] == byte(1),
OracleKey: key, OracleKey: key,
OracleData: data, OracleData: data,
...@@ -74,17 +74,14 @@ type TraceProvider interface { ...@@ -74,17 +74,14 @@ type TraceProvider interface {
// Get(i) = Keccak256(GetPreimage(i)) // Get(i) = Keccak256(GetPreimage(i))
Get(ctx context.Context, i uint64) (common.Hash, error) Get(ctx context.Context, i uint64) (common.Hash, error)
// GetOracleData returns preimage oracle data that can be submitted to the pre-image // GetStepData returns the data required to execute the step at the specified trace index.
// oracle and the dispute game contract. This function accepts a trace index for // This includes the pre-state of the step (not hashed), the proof data required during step execution
// which the provider returns needed preimage data. // and any pre-image data that needs to be loaded into the oracle prior to execution (may be nil)
GetOracleData(ctx context.Context, i uint64) (*PreimageOracleData, error) // The prestate returned from GetStepData for trace 10 should be the pre-image of the claim from trace 9
GetStepData(ctx context.Context, i uint64) (prestate []byte, proofData []byte, preimageData *PreimageOracleData, err error)
// GetPreimage returns the pre-image for a claim at the specified trace index, along
// with any associated proof data to assist in its verification.
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, error) AbsolutePreState(ctx context.Context) (preimage []byte, err 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.
......
File mode changed from 100644 to 100755
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
) )
...@@ -49,3 +50,7 @@ func (g *CannonGameHelper) StartChallenger(ctx context.Context, rollupCfg *rollu ...@@ -49,3 +50,7 @@ func (g *CannonGameHelper) StartChallenger(ctx context.Context, rollupCfg *rollu
}) })
return c return c
} }
func (g *FaultGameHelper) Address() common.Address {
return g.addr
}
...@@ -122,3 +122,29 @@ func (g *FaultGameHelper) Attack(ctx context.Context, claimIdx int64, claim comm ...@@ -122,3 +122,29 @@ func (g *FaultGameHelper) Attack(ctx context.Context, claimIdx int64, claim comm
_, err = utils.WaitReceiptOK(ctx, g.client, tx.Hash()) _, err = utils.WaitReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err, "Attack transaction was not OK") g.require.NoError(err, "Attack transaction was not OK")
} }
func (g *FaultGameHelper) Defend(ctx context.Context, claimIdx int64, claim common.Hash) {
tx, err := g.game.Defend(g.opts, big.NewInt(claimIdx), claim)
g.require.NoError(err, "Defend transaction did not send")
_, err = utils.WaitReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err, "Defend transaction was not OK")
}
func (g *FaultGameHelper) LogGameData(ctx context.Context) {
opts := &bind.CallOpts{Context: ctx}
maxDepth := int(g.MaxDepth(ctx))
claimCount, err := g.game.ClaimDataLen(opts)
info := fmt.Sprintf("Claim count: %v\n", claimCount)
g.require.NoError(err, "Fetching claim count")
for i := int64(0); i < claimCount.Int64(); i++ {
claim, err := g.game.ClaimData(opts, big.NewInt(i))
g.require.NoErrorf(err, "Fetch claim %v", i)
pos := types.NewPositionFromGIndex(claim.Position.Uint64())
info = info + fmt.Sprintf("%v - Position: %v, Depth: %v, IndexAtDepth: %v Trace Index: %v, Value: %v, Countered: %v\n",
i, claim.Position.Int64(), pos.Depth(), pos.IndexAtDepth(), pos.TraceIndex(maxDepth), common.Hash(claim.Claim).Hex(), claim.Countered)
}
status, err := g.game.Status(opts)
g.require.NoError(err, "Load game status")
g.t.Logf("Game %v:\n%v\nCurrent status: %v\n", g.addr, info, Status(status))
}
...@@ -147,36 +147,62 @@ func TestChallengerCompleteDisputeGame(t *testing.T) { ...@@ -147,36 +147,62 @@ func TestChallengerCompleteDisputeGame(t *testing.T) {
func TestCannonDisputeGame(t *testing.T) { func TestCannonDisputeGame(t *testing.T) {
InitParallel(t) InitParallel(t)
ctx := context.Background() tests := []struct {
sys, l1Client := startFaultDisputeSystem(t) name string
t.Cleanup(sys.Close) defendAtClaim int64
}{
disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.cfg.L1Deployments, l1Client) {"StepFirst", 0},
game := disputeGameFactory.StartCannonGame(ctx, common.Hash{0xaa}) {"StepMiddle", 28},
require.NotNil(t, game) {"StepInExtension", 2},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
InitParallel(t)
game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, sys.NodeEndpoint("l1"), sys.NodeEndpoint("sequencer"), "Challenger", func(c *config.Config) { ctx := context.Background()
c.AgreeWithProposedOutput = true // Agree with the proposed output, so disagree with the root claim sys, l1Client := startFaultDisputeSystem(t)
c.TxMgrConfig.PrivateKey = e2eutils.EncodePrivKeyToString(sys.cfg.Secrets.Alice) t.Cleanup(sys.Close)
})
maxDepth := game.MaxDepth(ctx) disputeGameFactory := disputegame.NewFactoryHelper(t, ctx, sys.cfg.L1Deployments, l1Client)
for claimCount := int64(1); claimCount < maxDepth; { game := disputeGameFactory.StartCannonGame(ctx, common.Hash{0xaa})
claimCount++ require.NotNil(t, game)
// Wait for the challenger to counter game.LogGameData(ctx)
game.WaitForClaimCount(ctx, claimCount)
// Post our own counter to the latest challenger claim game.StartChallenger(ctx, sys.RollupConfig, sys.L2GenesisCfg, sys.NodeEndpoint("l1"), sys.NodeEndpoint("sequencer"), "Challenger", func(c *config.Config) {
game.Attack(ctx, claimCount-1, common.Hash{byte(claimCount)}) c.AgreeWithProposedOutput = true // Agree with the proposed output, so disagree with the root claim
claimCount++ c.TxMgrConfig.PrivateKey = e2eutils.EncodePrivKeyToString(sys.cfg.Secrets.Alice)
game.WaitForClaimCount(ctx, claimCount) })
}
game.WaitForClaimAtMaxDepth(ctx, false)
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx)) maxDepth := game.MaxDepth(ctx)
require.NoError(t, utils.WaitNextBlock(ctx, l1Client)) for claimCount := int64(1); claimCount < maxDepth; {
game.LogGameData(ctx)
claimCount++
// Wait for the challenger to counter
game.WaitForClaimCount(ctx, claimCount)
// Post our own counter to the latest challenger claim
if claimCount == test.defendAtClaim {
// Defend one claim so we don't wind up executing from the absolute pre-state
game.Defend(ctx, claimCount-1, common.Hash{byte(claimCount)})
} else {
game.Attack(ctx, claimCount-1, common.Hash{byte(claimCount)})
}
claimCount++
game.WaitForClaimCount(ctx, claimCount)
}
game.LogGameData(ctx)
// Wait for the challenger to call step and counter our invalid claim
game.WaitForClaimAtMaxDepth(ctx, true)
sys.TimeTravelClock.AdvanceTime(game.GameDuration(ctx))
require.NoError(t, utils.WaitNextBlock(ctx, l1Client))
game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins) game.WaitForGameStatus(ctx, disputegame.StatusChallengerWins)
game.LogGameData(ctx)
})
}
} }
func startFaultDisputeSystem(t *testing.T) (*System, *ethclient.Client) { func startFaultDisputeSystem(t *testing.T) (*System, *ethclient.Client) {
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
"l1GenesisBlockTimestamp": "0x64c811bf", "l1GenesisBlockTimestamp": "0x64c811bf",
"l2GenesisRegolithTimeOffset": "0x0", "l2GenesisRegolithTimeOffset": "0x0",
"faultGameAbsolutePrestate": "0x41c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98", "faultGameAbsolutePrestate": "0x41c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
"faultGameMaxDepth": 31, "faultGameMaxDepth": 30,
"faultGameMaxDuration": 300, "faultGameMaxDuration": 300,
"systemConfigStartBlock": 0 "systemConfigStartBlock": 0
} }
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