Commit 6eb98a75 authored by OptimismBot's avatar OptimismBot Committed by GitHub

Merge pull request #7185 from ethereum-optimism/refcell/position-tp-port

feat(op-challenger): Trace Provider Position Type Port
parents 9223f920 63d34acb
......@@ -80,7 +80,7 @@ func NewGamePlayer(
var updater types.OracleUpdater
switch cfg.TraceType {
case config.TraceTypeCannon:
cannonProvider, err := cannon.NewTraceProvider(ctx, logger, m, cfg, client, dir, addr)
cannonProvider, err := cannon.NewTraceProvider(ctx, logger, m, cfg, client, dir, addr, gameDepth)
if err != nil {
return nil, fmt.Errorf("create cannon trace provider: %w", err)
}
......
......@@ -200,10 +200,10 @@ func newMockTraceProvider(prestateErrors bool, prestate []byte) *mockTraceProvid
prestate: prestate,
}
}
func (m *mockTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, error) {
func (m *mockTraceProvider) Get(ctx context.Context, i types.Position) (common.Hash, error) {
panic("not implemented")
}
func (m *mockTraceProvider) GetStepData(ctx context.Context, i uint64) (prestate []byte, proofData []byte, preimageData *types.PreimageOracleData, err error) {
func (m *mockTraceProvider) GetStepData(ctx context.Context, i types.Position) (prestate []byte, proofData []byte, preimageData *types.PreimageOracleData, err error) {
panic("not implemented")
}
func (m *mockTraceProvider) AbsolutePreState(ctx context.Context) ([]byte, error) {
......
......@@ -97,22 +97,20 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty
if err != nil {
return StepData{}, err
}
index := claim.TraceIndex(s.gameDepth)
var preState []byte
var proofData []byte
var oracleData *types.PreimageOracleData
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)
preState, proofData, oracleData, err = s.trace.GetStepData(ctx, claim.Position)
if err != nil {
return StepData{}, err
}
} else {
// We agree with the claim so Defend and use this claim as the starting point to execute the step after
// Thus we need the pre-state of the next step
// 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)
// We agree with the claim so Defend and use this claim as the starting point to
// execute the step after. Thus we need the pre-state of the next step.
preState, proofData, oracleData, err = s.trace.GetStepData(ctx, claim.MoveRight())
if err != nil {
return StepData{}, err
}
......@@ -166,9 +164,7 @@ func (s *claimSolver) agreeWithClaim(ctx context.Context, claim types.ClaimData)
// traceAtPosition returns the [common.Hash] from internal [TraceProvider] at the given [Position].
func (s *claimSolver) traceAtPosition(ctx context.Context, p types.Position) (common.Hash, error) {
index := p.TraceIndex(s.gameDepth)
hash, err := s.trace.Get(ctx, index)
return hash, err
return s.trace.Get(ctx, p)
}
// agreeWithClaimPath returns true if the every other claim in the path to root is correct according to the internal [TraceProvider].
......
......@@ -11,6 +11,7 @@ import (
func NewAlphabetWithProofProvider(t *testing.T, maxDepth int, oracleError error) *alphabetWithProofProvider {
return &alphabetWithProofProvider{
alphabet.NewTraceProvider("abcdefghijklmnopqrstuvwxyz", uint64(maxDepth)),
uint64(maxDepth),
oracleError,
}
}
......@@ -22,14 +23,16 @@ func NewAlphabetClaimBuilder(t *testing.T, maxDepth int) *ClaimBuilder {
type alphabetWithProofProvider struct {
*alphabet.AlphabetTraceProvider
depth uint64
OracleError error
}
func (a *alphabetWithProofProvider) GetStepData(ctx context.Context, i uint64) ([]byte, []byte, *types.PreimageOracleData, error) {
func (a *alphabetWithProofProvider) GetStepData(ctx context.Context, i types.Position) ([]byte, []byte, *types.PreimageOracleData, error) {
preimage, _, _, err := a.AlphabetTraceProvider.GetStepData(ctx, i)
if err != nil {
return nil, nil, nil, err
}
data := types.NewPreimageOracleData([]byte{byte(i)}, []byte{byte(i - 1)}, uint32(i-1))
return preimage, []byte{byte(i - 1)}, data, nil
traceIndex := i.TraceIndex(int(a.depth))
data := types.NewPreimageOracleData([]byte{byte(traceIndex)}, []byte{byte(traceIndex - 1)}, uint32(traceIndex-1))
return preimage, []byte{byte(traceIndex - 1)}, data, nil
}
......@@ -31,54 +31,50 @@ func (c *ClaimBuilder) CorrectTraceProvider() types.TraceProvider {
return c.correct
}
// CorrectClaim returns the canonical claim at a specified trace index
func (c *ClaimBuilder) CorrectClaim(idx uint64) common.Hash {
value, err := c.correct.Get(context.Background(), idx)
c.require.NoError(err)
return value
}
// CorrectClaimAtPosition returns the canonical claim at a specified position
func (c *ClaimBuilder) CorrectClaimAtPosition(pos types.Position) common.Hash {
value, err := c.correct.Get(context.Background(), pos.TraceIndex(c.maxDepth))
value, err := c.correct.Get(context.Background(), pos)
c.require.NoError(err)
return value
}
// 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 {
preimage, _, _, err := c.correct.GetStepData(context.Background(), idx)
pos := types.NewPosition(c.maxDepth, int(idx))
preimage, _, _, err := c.correct.GetStepData(context.Background(), pos)
c.require.NoError(err)
return preimage
}
// CorrectProofData returns the proof-data required to execute the valid step at the specified trace index
func (c *ClaimBuilder) CorrectProofData(idx uint64) []byte {
_, proof, _, err := c.correct.GetStepData(context.Background(), idx)
pos := types.NewPosition(c.maxDepth, int(idx))
_, proof, _, err := c.correct.GetStepData(context.Background(), pos)
c.require.NoError(err)
return proof
}
func (c *ClaimBuilder) CorrectOracleData(idx uint64) *types.PreimageOracleData {
_, _, data, err := c.correct.GetStepData(context.Background(), idx)
pos := types.NewPosition(c.maxDepth, int(idx))
_, _, data, err := c.correct.GetStepData(context.Background(), pos)
c.require.NoError(err)
return data
}
func (c *ClaimBuilder) incorrectClaim(idx uint64) common.Hash {
return common.BigToHash(new(big.Int).SetUint64(idx))
func (c *ClaimBuilder) incorrectClaim(pos types.Position) common.Hash {
return common.BigToHash(new(big.Int).SetUint64(pos.TraceIndex(c.maxDepth)))
}
func (c *ClaimBuilder) claim(idx uint64, correct bool) common.Hash {
func (c *ClaimBuilder) claim(pos types.Position, correct bool) common.Hash {
if correct {
return c.CorrectClaim(idx)
return c.CorrectClaimAtPosition(pos)
} else {
return c.incorrectClaim(idx)
return c.incorrectClaim(pos)
}
}
func (c *ClaimBuilder) CreateRootClaim(correct bool) types.Claim {
value := c.claim((1<<c.maxDepth)-1, correct)
value := c.claim(types.NewPositionFromGIndex(1), correct)
claim := types.Claim{
ClaimData: types.ClaimData{
Value: value,
......@@ -93,11 +89,11 @@ func (c *ClaimBuilder) CreateLeafClaim(traceIndex uint64, correct bool) types.Cl
pos := types.NewPosition(c.maxDepth, int(traceIndex))
return types.Claim{
ClaimData: types.ClaimData{
Value: c.claim(pos.TraceIndex(c.maxDepth), correct),
Value: c.claim(pos, correct),
Position: pos,
},
Parent: types.ClaimData{
Value: c.claim(parentPos.TraceIndex(c.maxDepth), !correct),
Value: c.claim(parentPos, !correct),
Position: parentPos,
},
}
......@@ -107,7 +103,7 @@ func (c *ClaimBuilder) AttackClaim(claim types.Claim, correct bool) types.Claim
pos := claim.Position.Attack()
return types.Claim{
ClaimData: types.ClaimData{
Value: c.claim(pos.TraceIndex(c.maxDepth), correct),
Value: c.claim(pos, correct),
Position: pos,
},
Parent: claim.ClaimData,
......@@ -131,7 +127,7 @@ func (c *ClaimBuilder) DefendClaim(claim types.Claim, correct bool) types.Claim
pos := claim.Position.Defend()
return types.Claim{
ClaimData: types.ClaimData{
Value: c.claim(pos.TraceIndex(c.maxDepth), correct),
Value: c.claim(pos, correct),
Position: pos,
},
Parent: claim.ClaimData,
......
......@@ -20,6 +20,7 @@ var (
// indices in the given trace.
type AlphabetTraceProvider struct {
state []string
depth uint64
maxLen uint64
}
......@@ -27,12 +28,14 @@ type AlphabetTraceProvider struct {
func NewTraceProvider(state string, depth uint64) *AlphabetTraceProvider {
return &AlphabetTraceProvider{
state: strings.Split(state, ""),
depth: depth,
maxLen: uint64(1 << depth),
}
}
func (ap *AlphabetTraceProvider) GetStepData(ctx context.Context, i uint64) ([]byte, []byte, *types.PreimageOracleData, error) {
if i == 0 {
func (ap *AlphabetTraceProvider) GetStepData(ctx context.Context, i types.Position) ([]byte, []byte, *types.PreimageOracleData, error) {
traceIndex := i.TraceIndex(int(ap.depth))
if traceIndex == 0 {
prestate, err := ap.AbsolutePreState(ctx)
if err != nil {
return nil, nil, nil, err
......@@ -40,22 +43,23 @@ func (ap *AlphabetTraceProvider) GetStepData(ctx context.Context, i uint64) ([]b
return prestate, []byte{}, nil, nil
}
// We want the pre-state which is the value prior to the one requested
i--
traceIndex--
// The index cannot be larger than the maximum index as computed by the depth.
if i >= ap.maxLen {
if traceIndex >= ap.maxLen {
return nil, nil, nil, ErrIndexTooLarge
}
// We extend the deepest hash to the maximum depth if the trace is not expansive.
if i >= uint64(len(ap.state)) {
return ap.GetStepData(ctx, uint64(len(ap.state)))
if traceIndex >= uint64(len(ap.state)) {
return ap.GetStepData(ctx, types.NewPosition(int(ap.depth), len(ap.state)))
}
return BuildAlphabetPreimage(i, ap.state[i]), []byte{}, nil, nil
return BuildAlphabetPreimage(traceIndex, ap.state[traceIndex]), []byte{}, nil, nil
}
// 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 types.Position) (common.Hash, error) {
// Step data returns the pre-state, so add 1 to get the state for index i
claimBytes, _, _, err := ap.GetStepData(ctx, i+1)
postPosition := types.NewPosition(int(ap.depth), int(i.TraceIndex(int(ap.depth)))+1)
claimBytes, _, _, err := ap.GetStepData(ctx, postPosition)
if err != nil {
return common.Hash{}, err
}
......
......@@ -5,6 +5,7 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"
)
......@@ -16,23 +17,24 @@ func alphabetClaim(index uint64, letter string) common.Hash {
// TestAlphabetProvider_Get_ClaimsByTraceIndex tests the [fault.AlphabetProvider] Get function.
func TestAlphabetProvider_Get_ClaimsByTraceIndex(t *testing.T) {
// Create a new alphabet provider.
canonicalProvider := NewTraceProvider("abcdefgh", uint64(3))
depth := 3
canonicalProvider := NewTraceProvider("abcdefgh", uint64(depth))
// Build a list of traces.
traces := []struct {
traceIndex uint64
traceIndex types.Position
expectedHash common.Hash
}{
{
7,
types.NewPosition(depth, 7),
alphabetClaim(7, "h"),
},
{
3,
types.NewPosition(depth, 3),
alphabetClaim(3, "d"),
},
{
5,
types.NewPosition(depth, 5),
alphabetClaim(5, "f"),
},
}
......@@ -58,9 +60,11 @@ func FuzzIndexToBytes(f *testing.F) {
// TestGetPreimage_Succeeds tests the GetPreimage function
// returns the correct pre-image for a index.
func TestGetStepData_Succeeds(t *testing.T) {
ap := NewTraceProvider("abc", 2)
depth := 2
ap := NewTraceProvider("abc", uint64(depth))
expected := BuildAlphabetPreimage(0, "a")
retrieved, proof, data, err := ap.GetStepData(context.Background(), uint64(1))
pos := types.NewPosition(depth, 1)
retrieved, proof, data, err := ap.GetStepData(context.Background(), pos)
require.NoError(t, err)
require.Equal(t, expected, retrieved)
require.Empty(t, proof)
......@@ -70,15 +74,19 @@ func TestGetStepData_Succeeds(t *testing.T) {
// TestGetPreimage_TooLargeIndex_Fails tests the GetPreimage
// function errors if the index is too large.
func TestGetStepData_TooLargeIndex_Fails(t *testing.T) {
ap := NewTraceProvider("abc", 2)
_, _, _, err := ap.GetStepData(context.Background(), 5)
depth := 2
ap := NewTraceProvider("abc", uint64(depth))
pos := types.NewPosition(depth, 5)
_, _, _, err := ap.GetStepData(context.Background(), pos)
require.ErrorIs(t, err, ErrIndexTooLarge)
}
// TestGet_Succeeds tests the Get function.
func TestGet_Succeeds(t *testing.T) {
ap := NewTraceProvider("abc", 2)
claim, err := ap.Get(context.Background(), 0)
depth := 2
ap := NewTraceProvider("abc", uint64(depth))
pos := types.NewPosition(depth, 0)
claim, err := ap.Get(context.Background(), pos)
require.NoError(t, err)
expected := alphabetClaim(0, "a")
require.Equal(t, expected, claim)
......@@ -87,16 +95,20 @@ func TestGet_Succeeds(t *testing.T) {
// TestGet_IndexTooLarge tests the Get function with an index
// greater than the number of indices: 2^depth - 1.
func TestGet_IndexTooLarge(t *testing.T) {
ap := NewTraceProvider("abc", 2)
_, err := ap.Get(context.Background(), 4)
depth := 2
ap := NewTraceProvider("abc", uint64(depth))
pos := types.NewPosition(depth, 4)
_, err := ap.Get(context.Background(), pos)
require.ErrorIs(t, err, ErrIndexTooLarge)
}
// TestGet_Extends tests the Get function with an index that is larger
// than the trace, but smaller than the maximum depth.
func TestGet_Extends(t *testing.T) {
ap := NewTraceProvider("abc", 2)
claim, err := ap.Get(context.Background(), 3)
depth := 2
ap := NewTraceProvider("abc", uint64(depth))
pos := types.NewPosition(depth, 3)
claim, err := ap.Get(context.Background(), pos)
require.NoError(t, err)
expected := alphabetClaim(2, "c")
require.Equal(t, expected, claim)
......
......@@ -49,13 +49,14 @@ type CannonTraceProvider struct {
dir string
prestate string
generator ProofGenerator
gameDepth uint64
// 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.
lastStep uint64
}
func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, l1Client bind.ContractCaller, dir string, gameAddr common.Address) (*CannonTraceProvider, error) {
func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, l1Client bind.ContractCaller, dir string, gameAddr common.Address, gameDepth uint64) (*CannonTraceProvider, error) {
l2Client, err := ethclient.DialContext(ctx, cfg.CannonL2)
if err != nil {
return nil, fmt.Errorf("dial l2 client %v: %w", cfg.CannonL2, err)
......@@ -69,20 +70,25 @@ func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer,
if err != nil {
return nil, fmt.Errorf("fetch local game inputs: %w", err)
}
return NewTraceProviderFromInputs(logger, m, cfg, localInputs, dir), nil
return NewTraceProviderFromInputs(logger, m, cfg, localInputs, dir, gameDepth), nil
}
func NewTraceProviderFromInputs(logger log.Logger, m CannonMetricer, cfg *config.Config, localInputs LocalGameInputs, dir string) *CannonTraceProvider {
func NewTraceProviderFromInputs(logger log.Logger, m CannonMetricer, cfg *config.Config, localInputs LocalGameInputs, dir string, gameDepth uint64) *CannonTraceProvider {
return &CannonTraceProvider{
logger: logger,
dir: dir,
prestate: cfg.CannonAbsolutePreState,
generator: NewExecutor(logger, m, cfg, localInputs),
gameDepth: gameDepth,
}
}
func (p *CannonTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, error) {
proof, err := p.loadProof(ctx, i)
func (p *CannonTraceProvider) SetMaxDepth(gameDepth uint64) {
p.gameDepth = gameDepth
}
func (p *CannonTraceProvider) Get(ctx context.Context, pos types.Position) (common.Hash, error) {
proof, err := p.loadProof(ctx, pos.TraceIndex(int(p.gameDepth)))
if err != nil {
return common.Hash{}, err
}
......@@ -94,8 +100,8 @@ func (p *CannonTraceProvider) Get(ctx context.Context, i uint64) (common.Hash, e
return value, nil
}
func (p *CannonTraceProvider) GetStepData(ctx context.Context, i uint64) ([]byte, []byte, *types.PreimageOracleData, error) {
proof, err := p.loadProof(ctx, i)
func (p *CannonTraceProvider) GetStepData(ctx context.Context, pos types.Position) ([]byte, []byte, *types.PreimageOracleData, error) {
proof, err := p.loadProof(ctx, pos.TraceIndex(int(p.gameDepth)))
if err != nil {
return nil, nil, nil, err
}
......
......@@ -22,11 +22,15 @@ import (
//go:embed test_data
var testData embed.FS
func PositionFromTraceIndex(provider *CannonTraceProvider, idx int) types.Position {
return types.NewPosition(int(provider.gameDepth), idx)
}
func TestGet(t *testing.T) {
dataDir, prestate := setupTestData(t)
t.Run("ExistingProof", func(t *testing.T) {
provider, generator := setupWithTestData(t, dataDir, prestate)
value, err := provider.Get(context.Background(), 0)
value, err := provider.Get(context.Background(), PositionFromTraceIndex(provider, 0))
require.NoError(t, err)
require.Equal(t, common.HexToHash("0x45fd9aa59768331c726e719e76aa343e73123af888804604785ae19506e65e87"), value)
require.Empty(t, generator.generated)
......@@ -39,7 +43,7 @@ func TestGet(t *testing.T) {
Step: 10,
Exited: true,
}
value, err := provider.Get(context.Background(), 7000)
value, err := provider.Get(context.Background(), PositionFromTraceIndex(provider, 7000))
require.NoError(t, err)
require.Contains(t, generator.generated, 7000, "should have tried to generate the proof")
stateHash, err := generator.finalState.EncodeWitness().StateHash()
......@@ -49,14 +53,14 @@ func TestGet(t *testing.T) {
t.Run("MissingPostHash", func(t *testing.T) {
provider, generator := setupWithTestData(t, dataDir, prestate)
_, err := provider.Get(context.Background(), 1)
_, err := provider.Get(context.Background(), PositionFromTraceIndex(provider, 1))
require.ErrorContains(t, err, "missing post hash")
require.Empty(t, generator.generated)
})
t.Run("IgnoreUnknownFields", func(t *testing.T) {
provider, generator := setupWithTestData(t, dataDir, prestate)
value, err := provider.Get(context.Background(), 2)
value, err := provider.Get(context.Background(), PositionFromTraceIndex(provider, 2))
require.NoError(t, err)
expected := common.HexToHash("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
require.Equal(t, expected, value)
......@@ -68,7 +72,7 @@ func TestGetStepData(t *testing.T) {
t.Run("ExistingProof", func(t *testing.T) {
dataDir, prestate := setupTestData(t)
provider, generator := setupWithTestData(t, dataDir, prestate)
value, proof, data, err := provider.GetStepData(context.Background(), 0)
value, proof, data, err := provider.GetStepData(context.Background(), PositionFromTraceIndex(provider, 0))
require.NoError(t, err)
expected := common.Hex2Bytes("b8f068de604c85ea0e2acd437cdb47add074a2d70b81d018390c504b71fe26f400000000000000000000000000000000000000000000000000000000000000000000000000")
require.Equal(t, expected, value)
......@@ -95,7 +99,7 @@ func TestGetStepData(t *testing.T) {
OracleValue: []byte{0xdd},
OracleOffset: 10,
}
preimage, proof, data, err := provider.GetStepData(context.Background(), 4)
preimage, proof, data, err := provider.GetStepData(context.Background(), PositionFromTraceIndex(provider, 4))
require.NoError(t, err)
require.Contains(t, generator.generated, 4, "should have tried to generate the proof")
......@@ -121,7 +125,7 @@ func TestGetStepData(t *testing.T) {
OracleValue: []byte{0xdd},
OracleOffset: 10,
}
preimage, proof, data, err := provider.GetStepData(context.Background(), 7000)
preimage, proof, data, err := provider.GetStepData(context.Background(), PositionFromTraceIndex(provider, 7000))
require.NoError(t, err)
require.Contains(t, generator.generated, 7000, "should have tried to generate the proof")
......@@ -147,7 +151,7 @@ func TestGetStepData(t *testing.T) {
OracleValue: []byte{0xdd},
OracleOffset: 10,
}
_, _, _, err := provider.GetStepData(context.Background(), 7000)
_, _, _, err := provider.GetStepData(context.Background(), PositionFromTraceIndex(provider, 7000))
require.NoError(t, err)
require.Contains(t, initGenerator.generated, 7000, "should have tried to generate the proof")
......@@ -162,7 +166,7 @@ func TestGetStepData(t *testing.T) {
StateData: []byte{0xbb},
ProofData: []byte{0xcc},
}
preimage, proof, data, err := provider.GetStepData(context.Background(), 7000)
preimage, proof, data, err := provider.GetStepData(context.Background(), PositionFromTraceIndex(provider, 7000))
require.NoError(t, err)
require.Empty(t, generator.generated, "should not have to generate the proof again")
......@@ -174,7 +178,7 @@ func TestGetStepData(t *testing.T) {
t.Run("MissingStateData", func(t *testing.T) {
dataDir, prestate := setupTestData(t)
provider, generator := setupWithTestData(t, dataDir, prestate)
_, _, _, err := provider.GetStepData(context.Background(), 1)
_, _, _, err := provider.GetStepData(context.Background(), PositionFromTraceIndex(provider, 1))
require.ErrorContains(t, err, "missing state data")
require.Empty(t, generator.generated)
})
......@@ -182,7 +186,7 @@ func TestGetStepData(t *testing.T) {
t.Run("IgnoreUnknownFields", func(t *testing.T) {
dataDir, prestate := setupTestData(t)
provider, generator := setupWithTestData(t, dataDir, prestate)
value, proof, data, err := provider.GetStepData(context.Background(), 2)
value, proof, data, err := provider.GetStepData(context.Background(), PositionFromTraceIndex(provider, 2))
require.NoError(t, err)
expected := common.Hex2Bytes("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")
require.Equal(t, expected, value)
......@@ -266,6 +270,7 @@ func setupWithTestData(t *testing.T, dataDir string, prestate string) (*CannonTr
dir: dataDir,
generator: generator,
prestate: filepath.Join(dataDir, prestate),
gameDepth: 63,
}, generator
}
......
......@@ -18,6 +18,13 @@ func NewPositionFromGIndex(x uint64) Position {
return NewPosition(depth, int(indexAtDepth))
}
func (p Position) MoveRight() Position {
return Position{
depth: p.depth,
indexAtDepth: int(p.indexAtDepth + 1),
}
}
func (p Position) Depth() int {
return p.depth
}
......
......@@ -64,13 +64,13 @@ type OracleUpdater interface {
type TraceProvider interface {
// Get returns the claim value at the requested index.
// Get(i) = Keccak256(GetPreimage(i))
Get(ctx context.Context, i uint64) (common.Hash, error)
Get(ctx context.Context, i Position) (common.Hash, error)
// GetStepData returns the data required to execute the step at the specified trace index.
// This includes the pre-state of the step (not hashed), the proof data required during step execution
// and any pre-image data that needs to be loaded into the oracle prior to execution (may be nil)
// 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)
GetStepData(ctx context.Context, i Position) (prestate []byte, proofData []byte, preimageData *PreimageOracleData, err error)
// AbsolutePreState is the pre-image value of the trace that transitions to the trace value at index 0
AbsolutePreState(ctx context.Context) (preimage []byte, err error)
......
......@@ -41,7 +41,8 @@ func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, rollupCfg *rol
opts = append(opts, options...)
cfg := challenger.NewChallengerConfig(g.t, l1Endpoint, opts...)
logger := testlog.Logger(g.t, log.LvlInfo).New("role", "CorrectTrace")
provider, err := cannon.NewTraceProvider(ctx, logger, metrics.NoopMetrics, cfg, l1Client, filepath.Join(cfg.Datadir, "honest"), g.addr)
maxDepth := g.MaxDepth(ctx)
provider, err := cannon.NewTraceProvider(ctx, logger, metrics.NoopMetrics, cfg, l1Client, filepath.Join(cfg.Datadir, "honest"), g.addr, uint64(maxDepth))
g.require.NoError(err, "create cannon trace provider")
return &HonestHelper{
......
......@@ -141,6 +141,11 @@ func (g *FaultGameHelper) getClaim(ctx context.Context, claimIdx int64) Contract
return claimData
}
// getClaimPosition retrieves the [types.Position] of a claim at a specific index.
func (g *FaultGameHelper) getClaimPosition(ctx context.Context, claimIdx int64) types.Position {
return types.NewPositionFromGIndex(g.getClaim(ctx, claimIdx).Position.Uint64())
}
func (g *FaultGameHelper) WaitForClaimAtDepth(ctx context.Context, depth int) {
g.waitForClaim(
ctx,
......
......@@ -4,7 +4,6 @@ import (
"context"
"encoding/binary"
"fmt"
"math"
"math/big"
"testing"
"time"
......@@ -15,6 +14,7 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/l2oo"
......@@ -36,6 +36,9 @@ const cannonGameType uint8 = 0
const alphabetGameDepth = 4
const lastAlphabetTraceIndex = 1<<alphabetGameDepth - 1
// rootPosition is the position of the root claim.
var rootPosition = faultTypes.NewPositionFromGIndex(1)
type Status uint8
const (
......@@ -104,7 +107,8 @@ func (h *FactoryHelper) StartAlphabetGame(ctx context.Context, claimedAlphabet s
defer cancel()
trace := alphabet.NewTraceProvider(claimedAlphabet, alphabetGameDepth)
rootClaim, err := trace.Get(ctx, lastAlphabetTraceIndex)
pos := faultTypes.NewPosition(alphabetGameDepth, lastAlphabetTraceIndex)
rootClaim, err := trace.Get(ctx, pos)
h.require.NoError(err, "get root claim")
extraData := make([]byte, 64)
binary.BigEndian.PutUint64(extraData[24:], l2BlockNumber)
......@@ -172,14 +176,33 @@ func (h *FactoryHelper) StartCannonGameWithCorrectRoot(ctx context.Context, roll
L2Claim: challengedOutput.OutputRoot,
L2BlockNumber: challengedOutput.L2BlockNumber,
}
provider := cannon.NewTraceProviderFromInputs(testlog.Logger(h.t, log.LvlInfo).New("role", "CorrectTrace"), metrics.NoopMetrics, cfg, inputs, cfg.Datadir)
rootClaim, err := provider.Get(ctx, math.MaxUint64)
cannonTypeAddr, err := h.factory.GameImpls(opts, cannonGameType)
h.require.NoError(err, "fetch cannon game type impl")
gameImpl, err := bindings.NewFaultDisputeGameCaller(cannonTypeAddr, h.client)
h.require.NoError(err, "bind fault dispute game caller")
maxDepth, err := gameImpl.MAXGAMEDEPTH(opts)
h.require.NoError(err, "fetch max game depth")
provider := cannon.NewTraceProviderFromInputs(
testlog.Logger(h.t, log.LvlInfo).New("role", "CorrectTrace"),
metrics.NoopMetrics,
cfg,
inputs,
cfg.Datadir,
maxDepth.Uint64(),
)
rootClaim, err := provider.Get(ctx, rootPosition)
h.require.NoError(err, "Compute correct root hash")
// Override the VM status to claim the root is invalid
// Otherwise creating the game will fail
rootClaim[0] = mipsevm.VMStatusInvalid
game := h.createCannonGame(ctx, l2BlockNumber, l1Head, rootClaim)
correctMaxDepth := game.MaxDepth(ctx)
provider.SetMaxDepth(uint64(correctMaxDepth))
honestHelper := &HonestHelper{
t: h.t,
require: h.require,
......
......@@ -22,10 +22,9 @@ func (h *HonestHelper) Attack(ctx context.Context, claimIdx int64) {
claim := h.game.getClaim(ctx, claimIdx)
pos := types.NewPositionFromGIndex(claim.Position.Uint64())
attackPos := pos.Attack()
traceIdx := attackPos.TraceIndex(int(h.game.MaxDepth(ctx)))
h.t.Logf("Attacking at position %v using correct trace from index %v", attackPos.ToGIndex(), traceIdx)
value, err := h.correctTrace.Get(ctx, traceIdx)
h.require.NoErrorf(err, "Get correct claim at trace index %v", traceIdx)
h.t.Logf("Attacking at position %v with g index %v", attackPos, attackPos.ToGIndex())
value, err := h.correctTrace.Get(ctx, attackPos)
h.require.NoErrorf(err, "Get correct claim at position %v with g index %v", attackPos, attackPos.ToGIndex())
h.t.Log("Performing attack")
h.game.Attack(ctx, claimIdx, value)
h.t.Log("Attack complete")
......@@ -37,23 +36,20 @@ func (h *HonestHelper) Defend(ctx context.Context, claimIdx int64) {
claim := h.game.getClaim(ctx, claimIdx)
pos := types.NewPositionFromGIndex(claim.Position.Uint64())
defendPos := pos.Defend()
traceIdx := defendPos.TraceIndex(int(h.game.MaxDepth(ctx)))
value, err := h.correctTrace.Get(ctx, traceIdx)
h.game.require.NoErrorf(err, "Get correct claim at trace index %v", traceIdx)
value, err := h.correctTrace.Get(ctx, defendPos)
h.game.require.NoErrorf(err, "Get correct claim at position %v with g index %v", defendPos, defendPos.ToGIndex())
h.game.Defend(ctx, claimIdx, value)
}
func (h *HonestHelper) StepFails(ctx context.Context, claimIdx int64, isAttack bool) {
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
claim := h.game.getClaim(ctx, claimIdx)
pos := types.NewPositionFromGIndex(claim.Position.Uint64())
traceIdx := pos.TraceIndex(int(h.game.MaxDepth(ctx)))
pos := h.game.getClaimPosition(ctx, claimIdx)
if !isAttack {
// If we're defending, then the step will be from the trace to the next one
traceIdx += 1
pos = pos.MoveRight()
}
prestate, proofData, _, err := h.correctTrace.GetStepData(ctx, traceIdx)
prestate, proofData, _, err := h.correctTrace.GetStepData(ctx, pos)
h.require.NoError(err, "Get step data")
h.game.StepFails(claimIdx, isAttack, prestate, proofData)
}
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