Commit 39e9f1a4 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-e2e: Add action tests for challenger and stopping at the game timestamp (#13818)

* op-e2e: Add action test to confirm fault proof program stops when the agreed timestamp is already at the game timestamp

* op-e2e: Add action tests for the challenger super trace provider

Ensures that it generates super root/transition states that match the test expectations.
Update RootProvider interface to match the actual interface exposed by Supervisor

* op-e2e: Remove game inputs that are no longer required.
parent 05438612
......@@ -2,13 +2,18 @@ package interop
import (
"context"
"fmt"
"log/slog"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/super"
challengerTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
fpHelpers "github.com/ethereum-optimism/optimism/op-e2e/actions/proofs/helpers"
"github.com/ethereum-optimism/optimism/op-program/client/claim"
"github.com/ethereum-optimism/optimism/op-program/client/interop"
"github.com/ethereum-optimism/optimism/op-program/client/interop/types"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
......@@ -355,104 +360,129 @@ func TestInteropFaultProofs(gt *testing.T) {
tests := []*transitionTest{
{
name: "ClaimNoChange",
startTimestamp: startTimestamp,
agreedClaim: start.Marshal(),
disputedClaim: start.Marshal(),
disputedTraceIndex: 0,
expectValid: false,
},
{
name: "ClaimDirectToNextTimestamp",
startTimestamp: startTimestamp,
agreedClaim: start.Marshal(),
disputedClaim: end.Marshal(),
disputedTraceIndex: 0,
expectValid: false,
},
{
name: "FirstChainOptimisticBlock",
startTimestamp: startTimestamp,
agreedClaim: start.Marshal(),
disputedClaim: step1Expected,
disputedTraceIndex: 0,
expectValid: true,
},
{
name: "SecondChainOptimisticBlock",
startTimestamp: startTimestamp,
agreedClaim: step1Expected,
disputedClaim: step2Expected,
disputedTraceIndex: 1,
expectValid: true,
},
{
name: "FirstPaddingStep",
startTimestamp: startTimestamp,
agreedClaim: step2Expected,
disputedClaim: paddingStep(3),
disputedTraceIndex: 2,
expectValid: true,
},
{
name: "SecondPaddingStep",
startTimestamp: startTimestamp,
agreedClaim: paddingStep(3),
disputedClaim: paddingStep(4),
disputedTraceIndex: 3,
expectValid: true,
},
{
name: "LastPaddingStep",
startTimestamp: startTimestamp,
agreedClaim: paddingStep(1022),
disputedClaim: paddingStep(1023),
disputedTraceIndex: 1022,
expectValid: true,
},
{
name: "Consolidate",
startTimestamp: startTimestamp,
name: "Consolidate-AllValid",
agreedClaim: paddingStep(1023),
disputedClaim: end.Marshal(),
disputedTraceIndex: 1023,
expectValid: true,
},
{
name: "Consolidate-ReplaceInvalidBlock",
// Will need to generate an invalid block before this can be enabled
skipProgram: true,
skipChallenger: true,
},
{
name: "Consolidate-ReplaceBlockInvalidatedByFirstInvalidatedBlock",
// Will need to generate an invalid block before this can be enabled
// Check that if a block B depends on a log in block A, and block A is found to have an invalid message
// that block B is also replaced with a deposit only block because A no longer contains the log it needs
skipProgram: true,
skipChallenger: true,
},
{
name: "AlreadyAtClaimedTimestamp",
agreedClaim: end.Marshal(),
disputedClaim: end.Marshal(),
disputedTraceIndex: 5000,
expectValid: true,
},
{
name: "FirstChainReachesL1Head",
startTimestamp: startTimestamp,
agreedClaim: start.Marshal(),
disputedClaim: interop.InvalidTransition,
disputedTraceIndex: 0,
// The derivation reaches the L1 head before the next block can be created
l1Head: actors.L1Miner.L1Chain().Genesis().Hash(),
expectValid: true,
skipChallenger: true, // Challenger doesn't yet check if blocks were safe
},
{
name: "SecondChainReachesL1Head",
startTimestamp: startTimestamp,
agreedClaim: step1Expected,
disputedClaim: interop.InvalidTransition,
disputedTraceIndex: 1,
// The derivation reaches the L1 head before the next block can be created
l1Head: actors.L1Miner.L1Chain().Genesis().Hash(),
expectValid: true,
skipChallenger: true, // Challenger doesn't yet check if blocks were safe
},
{
name: "SuperRootInvalidIfUnsupportedByL1Data",
startTimestamp: startTimestamp,
agreedClaim: step1Expected,
disputedClaim: step2Expected,
disputedTraceIndex: 1,
// The derivation reaches the L1 head before the next block can be created
l1Head: actors.L1Miner.L1Chain().Genesis().Hash(),
expectValid: false,
skipChallenger: true, // Challenger doesn't yet check if blocks were safe
},
{
name: "FromInvalidTransitionHash",
startTimestamp: startTimestamp,
agreedClaim: interop.InvalidTransition,
disputedClaim: interop.InvalidTransition,
disputedTraceIndex: 2,
// The derivation reaches the L1 head before the next block can be created
l1Head: actors.L1Miner.L1Chain().Genesis().Hash(),
expectValid: true,
skipChallenger: true, // Challenger doesn't yet check if blocks were safe
},
}
for _, test := range tests {
test := test
gt.Run(test.name, func(gt *testing.T) {
gt.Run(fmt.Sprintf("%s-fpp", test.name), func(gt *testing.T) {
t := helpers.NewDefaultTesting(gt)
if test.skip {
if test.skipProgram {
t.Skip("Not yet implemented")
return
}
......@@ -474,6 +504,42 @@ func TestInteropFaultProofs(gt *testing.T) {
fpHelpers.WithL1Head(l1Head),
)
})
gt.Run(fmt.Sprintf("%s-challenger", test.name), func(gt *testing.T) {
t := helpers.NewDefaultTesting(gt)
if test.skipChallenger {
t.Skip("Not yet implemented")
return
}
logger := testlog.Logger(t, slog.LevelInfo)
prestateProvider := super.NewSuperRootPrestateProvider(&actors.Supervisor.QueryFrontend, startTimestamp)
var l1Head eth.BlockID
if test.l1Head == (common.Hash{}) {
l1Head = eth.ToBlockID(eth.HeaderBlockInfo(actors.L1Miner.L1Chain().CurrentBlock()))
} else {
l1Head = eth.ToBlockID(actors.L1Miner.L1Chain().GetBlockByHash(test.l1Head))
}
gameDepth := challengerTypes.Depth(30)
provider := super.NewSuperTraceProvider(logger, prestateProvider, &actors.Supervisor.QueryFrontend, l1Head, gameDepth, startTimestamp, endTimestamp)
var agreedPrestate []byte
if test.disputedTraceIndex > 0 {
agreedPrestate, err = provider.GetPreimageBytes(ctx, challengerTypes.NewPosition(gameDepth, big.NewInt(test.disputedTraceIndex-1)))
require.NoError(t, err)
} else {
superRoot, err := provider.AbsolutePreState(ctx)
require.NoError(t, err)
agreedPrestate = superRoot.Marshal()
}
require.Equal(t, test.agreedClaim, agreedPrestate)
disputedClaim, err := provider.GetPreimageBytes(ctx, challengerTypes.NewPosition(gameDepth, big.NewInt(test.disputedTraceIndex)))
require.NoError(t, err)
if test.expectValid {
require.Equal(t, test.disputedClaim, disputedClaim, "Claim is correct so should match challenger's opinion")
} else {
require.NotEqual(t, test.disputedClaim, disputedClaim, "Claim is incorrect so should not match challenger's opinion")
}
})
}
}
......@@ -485,10 +551,6 @@ func WithInteropEnabled(actors *InteropActors, agreedPrestate []byte, disputedCl
f.L2Claim = disputedClaim
f.L2BlockNumber = claimTimestamp
// TODO: Remove these once hints all specify the L2 chain ID
f.L2ChainID = actors.ChainA.ChainID.ToBig().Uint64()
f.L2Head = actors.ChainA.SequencerEngine.L2Chain().CurrentHeader().ParentHash
for _, chain := range []*Chain{actors.ChainA, actors.ChainB} {
f.L2Sources = append(f.L2Sources, &fpHelpers.FaultProofProgramL2Source{
Node: chain.Sequencer.L2Verifier,
......@@ -501,10 +563,11 @@ func WithInteropEnabled(actors *InteropActors, agreedPrestate []byte, disputedCl
type transitionTest struct {
name string
startTimestamp uint64
agreedClaim []byte
disputedClaim []byte
disputedTraceIndex int64
l1Head common.Hash // Defaults to current L1 head if not set
expectValid bool
skip bool
skipProgram bool
skipChallenger bool
}
......@@ -59,7 +59,7 @@ func (ib *InteropAPI) OutputV0AtTimestamp(ctx context.Context, timestamp uint64)
return ib.backend.OutputV0AtTimestamp(ctx, timestamp)
}
func (ib *InteropAPI) PendingOutputV0ATTimestamp(ctx context.Context, timestamp uint64) (*eth.OutputV0, error) {
func (ib *InteropAPI) PendingOutputV0AtTimestamp(ctx context.Context, timestamp uint64) (*eth.OutputV0, error) {
return ib.backend.PendingOutputV0AtTimestamp(ctx, timestamp)
}
......
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