Skip to content

Commit e29dca4

Browse files
test: sysgo-powered e2e testing infra for fault-proof proposer (succinctlabs#708)
* feat: setup fault-proof e2e * chore: reorg /e2e * refactor: shared preset * feat: dispute game factory binding * refactor: resuable call function in adapters * test: L2DfgDeployedAndUp * ci: add faultproof mode * test: detect first game created * chore: gen binding for OPSuccinctFaultDisputeGame * nit: naming * fix: add FailNow if timeout passed * refactor: benefit from ethCaller * refactor: WaitForGameCount * test: check first game's parentId * test: verify rootClaim * chore: define opts * fix: update /optimism rev * chore: update /optimism rev * fix: require.Equal in _L2DgfDeployedAndUp
1 parent 4344e05 commit e29dca4

11 files changed

Lines changed: 3690 additions & 108 deletions

File tree

.github/workflows/e2e-sysgo.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
strategy:
2727
fail-fast: false
2828
matrix:
29-
mode: ["validity"]
29+
mode: ["validity", "faultproof"]
3030

3131
steps:
3232
- name: Checkout sources

tests/bindings/disputegamefactory.go

Lines changed: 1405 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/bindings/opsuccinctfaultdisputegame.go

Lines changed: 1954 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"math"
6+
"testing"
7+
"time"
8+
9+
"github.com/ethereum-optimism/optimism/op-devstack/devtest"
10+
"github.com/ethereum-optimism/optimism/op-devstack/presets"
11+
"github.com/ethereum-optimism/optimism/op-devstack/sysgo"
12+
"github.com/ethereum-optimism/optimism/op-service/eth"
13+
opspresets "github.com/succinctlabs/op-succinct/presets"
14+
"github.com/succinctlabs/op-succinct/utils"
15+
)
16+
17+
func TestMain(m *testing.M) {
18+
presets.DoMain(m,
19+
opspresets.WithSuccinctFaultProofProposer(&sysgo.DefaultSingleChainInteropSystemIDs{}),
20+
presets.WithSafeDBEnabled(),
21+
)
22+
}
23+
24+
func TestFaultProofProposer_L2DgfDeployedAndUp(gt *testing.T) {
25+
t := devtest.SerialT(gt)
26+
sys := presets.NewMinimalWithProposer(t)
27+
require := t.Require()
28+
logger := t.Logger()
29+
30+
dgfAddr := sys.L2Chain.Escape().Deployment().DisputeGameFactoryProxyAddr()
31+
logger.Info("Dispute Game Factory Address:", "address", dgfAddr.Hex())
32+
33+
dgf, err := utils.NewDgfClient(sys.L1EL.EthClient(), dgfAddr)
34+
require.NoError(err, "failed to create DGF client")
35+
36+
gameCount, err := dgf.GameCount(t.Ctx())
37+
require.NoError(err, "failed to get game count from DGF")
38+
logger.Info("Dispute Game Count:", "count", gameCount)
39+
require.Equal(uint64(0), gameCount, "expected zero dispute games initially")
40+
}
41+
42+
func TestFaultProofProposer_DetectsFirstGameCreated(gt *testing.T) {
43+
t := devtest.SerialT(gt)
44+
sys := presets.NewMinimalWithProposer(t)
45+
require := t.Require()
46+
logger := t.Logger()
47+
ctx, cancel := context.WithTimeout(t.Ctx(), 5*time.Minute)
48+
defer cancel()
49+
50+
dgfAddr := sys.L2Chain.Escape().Deployment().DisputeGameFactoryProxyAddr()
51+
logger.Info("Dispute Game Factory Address:", "address", dgfAddr.Hex())
52+
dgf, err := utils.NewDgfClient(sys.L1EL.EthClient(), dgfAddr)
53+
require.NoError(err, "failed to create Dispute Game Factory client")
54+
55+
utils.WaitForGameCount(ctx, t, dgf, 1)
56+
57+
// Get first game
58+
game, err := dgf.GameAtIndex(ctx, 0)
59+
require.NoError(err, "failed to get first game from factory")
60+
logger.Info("First game created", "gameType", game.GameType, "timestamp", game.Timestamp, "proxy", game.Proxy.Hex())
61+
fdg, err := utils.NewFdgClient(sys.L1EL.EthClient(), game.Proxy)
62+
require.NoError(err, "failed to create Fault Dispute Game client")
63+
64+
// Verify parent index
65+
parentIdx, err := fdg.ParentIndex(ctx)
66+
require.NoError(err, "failed to read parentIndex")
67+
t.Logger().Info("Fault dispute game parent index", "parentIndex", parentIdx)
68+
require.Equal(uint32(math.MaxUint32), parentIdx, "unexpected parent index")
69+
70+
// Verify root claim
71+
l2BlockNumber, err := fdg.L2BlockNumber(ctx)
72+
require.NoError(err, "failed to read L2 block number")
73+
logger.Info("Fault dispute game L2 block number", "l2BlockNumber", l2BlockNumber)
74+
output, err := sys.L2EL.Escape().L2EthClient().OutputV0AtBlockNumber(ctx, l2BlockNumber)
75+
require.NoError(err, "failed to get output root at L2 block number")
76+
rootClaim, err := fdg.RootClaim(ctx)
77+
require.NoError(err, "failed to read root claim")
78+
expectedRoot := eth.OutputRoot(output)
79+
logger.Info("Fault dispute game root claim", "rootClaim", rootClaim)
80+
require.Equal(expectedRoot, rootClaim, "unexpected root claim")
81+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestMain(m *testing.M) {
2121

2222
func TestValidityProposer_L2OODeployedAndUp(gt *testing.T) {
2323
t := devtest.SerialT(gt)
24-
sys := presets.NewMinimal(t)
24+
sys := presets.NewMinimalWithProposer(t)
2525

2626
l2ooAddr := sys.L2Chain.Escape().Deployment().OPSuccinctL2OutputOracleAddr()
2727
t.Logger().Info("L2 Output Oracle Address:", "address", l2ooAddr.Hex())
@@ -37,7 +37,7 @@ func TestValidityProposer_L2OODeployedAndUp(gt *testing.T) {
3737

3838
func TestValidityProposer_ProveSingleRange(gt *testing.T) {
3939
t := devtest.SerialT(gt)
40-
sys := presets.NewMinimal(t)
40+
sys := presets.NewMinimalWithProposer(t)
4141

4242
l2ooAddr := sys.L2Chain.Escape().Deployment().OPSuccinctL2OutputOracleAddr()
4343
t.Logger().Info("L2 Output Oracle Address:", "address", l2ooAddr.Hex())

tests/justfile

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,25 @@ test-e2e-sysgo BINARY FILTER="" : unzip-contract-artifacts
88
export FILTER="-run {{FILTER}}"
99
fi
1010

11+
export DEVSTACK_ORCHESTRATOR=sysgo
1112
export OP_DEPLOYER_ARTIFACTS="{{SOURCE}}/artifacts/src/forge-artifacts"
1213
export DISABLE_OP_E2E_LEGACY=true
1314

1415
if [ "{{BINARY}}" = "validity" ]; then
1516
export VALIDITY_PROPOSER_EXEC_PATH="{{ROOT}}/target/release/validity"
16-
export DEVSTACK_ORCHESTRATOR=sysgo
1717
echo "Building validity proposer..."
1818
cd .. && cargo build --bin validity --release
19+
elif [ "{{BINARY}}" = "faultproof" ]; then
20+
export FAULT_PROOF_PROPOSER_EXEC_PATH="{{ROOT}}/target/release/proposer"
21+
echo "Building fault-proof proposer..."
22+
cd .. && cargo build --bin proposer --release
1923
else
20-
echo "Invalid BINARY specified. Must be either 'validity' or 'fault-proof'."
24+
echo "Invalid BINARY specified. Must be either 'validity' or 'faultproof'."
2125
exit 1
2226
fi
2327

2428
# Run the test with count=1 to avoid caching the test results.
25-
cd {{SOURCE}} && go test -count=1 -timeout 40m -v ./e2e $FILTER
29+
cd {{SOURCE}} && go test -count=1 -timeout 40m -v ./e2e/{{BINARY}} $FILTER
2630

2731
unzip-contract-artifacts DEST_DIR="":
2832
#!/bin/bash

tests/presets/faultproof.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package presets
2+
3+
import (
4+
"github.com/ethereum-optimism/optimism/op-devstack/stack"
5+
"github.com/ethereum-optimism/optimism/op-devstack/sysgo"
6+
"github.com/ethereum-optimism/optimism/op-service/eth"
7+
)
8+
9+
func WithSuccinctFaultProofProposer(dest *sysgo.DefaultSingleChainInteropSystemIDs) stack.CommonOption {
10+
return withSuccinctPreset(dest, func(opt *stack.CombinedOption[*sysgo.Orchestrator], ids sysgo.DefaultSingleChainInteropSystemIDs, l2ChainID eth.ChainID) {
11+
opt.Add(sysgo.WithSuperDeploySP1MockVerifier(ids.L1EL, l2ChainID))
12+
opt.Add(sysgo.WithSuperDeployOPSuccinctFaultDisputeGame(ids.L1CL, ids.L1EL, ids.L2ACL, ids.L2AEL, sysgo.WithFdgL2StartingBlockNumber(1)))
13+
opt.Add(sysgo.WithSuperSuccinctFaultProofProposer(ids.L2AProposer, ids.L1CL, ids.L1EL, ids.L2ACL, ids.L2AEL,
14+
sysgo.WithFdgProposalIntervalInBlocks(5),
15+
sysgo.WithFdgFetchInterval(1)))
16+
})
17+
}

tests/presets/shared.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package presets
2+
3+
import (
4+
"os"
5+
6+
"github.com/ethereum-optimism/optimism/op-chain-ops/devkeys"
7+
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
8+
"github.com/ethereum-optimism/optimism/op-devstack/devtest"
9+
"github.com/ethereum-optimism/optimism/op-devstack/stack"
10+
"github.com/ethereum-optimism/optimism/op-devstack/sysgo"
11+
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/intentbuilder"
12+
"github.com/ethereum-optimism/optimism/op-service/eth"
13+
)
14+
15+
const (
16+
DefaultL1ID = 900
17+
DefaultL2ID = 901
18+
)
19+
20+
type succinctConfigurator func(*stack.CombinedOption[*sysgo.Orchestrator], sysgo.DefaultSingleChainInteropSystemIDs, eth.ChainID)
21+
22+
func withSuccinctPreset(dest *sysgo.DefaultSingleChainInteropSystemIDs, configure succinctConfigurator) stack.CommonOption {
23+
l1ChainID := eth.ChainIDFromUInt64(DefaultL1ID)
24+
l2ChainID := eth.ChainIDFromUInt64(DefaultL2ID)
25+
ids := sysgo.NewDefaultSingleChainInteropSystemIDs(l1ChainID, l2ChainID)
26+
27+
opt := stack.Combine[*sysgo.Orchestrator]()
28+
opt.Add(stack.BeforeDeploy(func(o *sysgo.Orchestrator) {
29+
o.P().Logger().Info("Setting up")
30+
}))
31+
32+
opt.Add(sysgo.WithMnemonicKeys(devkeys.TestMnemonic))
33+
34+
artifactsPath := os.Getenv("OP_DEPLOYER_ARTIFACTS")
35+
if artifactsPath == "" {
36+
panic("OP_DEPLOYER_ARTIFACTS is not set")
37+
}
38+
39+
opt.Add(sysgo.WithDeployer(),
40+
sysgo.WithDeployerPipelineOption(
41+
sysgo.WithDeployerCacheDir(artifactsPath),
42+
),
43+
sysgo.WithDeployerOptions(
44+
func(_ devtest.P, _ devkeys.Keys, builder intentbuilder.Builder) {
45+
builder.WithGlobalOverride("l2BlockTime", uint64(1))
46+
builder.WithL1ContractsLocator(artifacts.MustNewFileLocator(artifactsPath))
47+
builder.WithL2ContractsLocator(artifacts.MustNewFileLocator(artifactsPath))
48+
},
49+
sysgo.WithCommons(ids.L1.ChainID()),
50+
sysgo.WithPrefundedL2(ids.L1.ChainID(), ids.L2A.ChainID()),
51+
),
52+
)
53+
54+
opt.Add(sysgo.WithL1Nodes(ids.L1EL, ids.L1CL))
55+
56+
opt.Add(sysgo.WithSupervisor(ids.Supervisor, ids.Cluster, ids.L1EL))
57+
opt.Add(sysgo.WithL2ELNode(ids.L2AEL, sysgo.L2ELWithSupervisor(ids.Supervisor)))
58+
opt.Add(sysgo.WithL2CLNode(ids.L2ACL, ids.L1CL, ids.L1EL, ids.L2AEL, sysgo.L2CLSequencer(), sysgo.L2CLIndexing()))
59+
opt.Add(sysgo.WithManagedBySupervisor(ids.L2ACL, ids.Supervisor))
60+
61+
opt.Add(sysgo.WithBatcher(ids.L2ABatcher, ids.L1EL, ids.L2ACL, ids.L2AEL))
62+
opt.Add(sysgo.WithTestSequencer(ids.TestSequencer, ids.L1CL, ids.L2ACL, ids.L1EL, ids.L2AEL))
63+
opt.Add(sysgo.WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL}))
64+
65+
configure(&opt, ids, l2ChainID)
66+
67+
opt.Add(sysgo.WithL2MetricsDashboard())
68+
opt.Add(stack.Finally(func(orch *sysgo.Orchestrator) {
69+
*dest = ids
70+
}))
71+
72+
return stack.MakeCommon(opt)
73+
}

tests/presets/validity.go

Lines changed: 5 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,15 @@
11
package presets
22

33
import (
4-
"os"
5-
6-
"github.com/ethereum-optimism/optimism/op-chain-ops/devkeys"
7-
"github.com/ethereum-optimism/optimism/op-deployer/pkg/deployer/artifacts"
8-
"github.com/ethereum-optimism/optimism/op-devstack/devtest"
94
"github.com/ethereum-optimism/optimism/op-devstack/stack"
105
"github.com/ethereum-optimism/optimism/op-devstack/sysgo"
11-
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/intentbuilder"
126
"github.com/ethereum-optimism/optimism/op-service/eth"
137
)
148

15-
const DefaultL1ID = 900
16-
const DefaultL2ID = 901
17-
189
func WithSuccinctValidityProposer(dest *sysgo.DefaultSingleChainInteropSystemIDs) stack.CommonOption {
19-
l1ChainID := eth.ChainIDFromUInt64(DefaultL1ID)
20-
l2ChainID := eth.ChainIDFromUInt64(DefaultL2ID)
21-
ids := sysgo.NewDefaultSingleChainInteropSystemIDs(l1ChainID, l2ChainID)
22-
23-
opt := stack.Combine[*sysgo.Orchestrator]()
24-
opt.Add(stack.BeforeDeploy(func(o *sysgo.Orchestrator) {
25-
o.P().Logger().Info("Setting up")
26-
}))
27-
28-
opt.Add(sysgo.WithMnemonicKeys(devkeys.TestMnemonic))
29-
30-
artifactsPath := os.Getenv("OP_DEPLOYER_ARTIFACTS")
31-
if artifactsPath == "" {
32-
panic("OP_DEPLOYER_ARTIFACTS is not set")
33-
}
34-
35-
opt.Add(sysgo.WithDeployer(),
36-
sysgo.WithDeployerPipelineOption(
37-
sysgo.WithDeployerCacheDir(artifactsPath),
38-
),
39-
sysgo.WithDeployerOptions(
40-
func(_ devtest.P, _ devkeys.Keys, builder intentbuilder.Builder) {
41-
builder.WithGlobalOverride("l2BlockTime", uint64(1))
42-
builder.WithL1ContractsLocator(artifacts.MustNewFileLocator(artifactsPath))
43-
builder.WithL2ContractsLocator(artifacts.MustNewFileLocator(artifactsPath))
44-
},
45-
sysgo.WithCommons(ids.L1.ChainID()),
46-
sysgo.WithPrefundedL2(ids.L1.ChainID(), ids.L2A.ChainID()),
47-
),
48-
)
49-
50-
opt.Add(sysgo.WithL1Nodes(ids.L1EL, ids.L1CL))
51-
52-
opt.Add(sysgo.WithSupervisor(ids.Supervisor, ids.Cluster, ids.L1EL))
53-
opt.Add(sysgo.WithL2ELNode(ids.L2AEL, sysgo.L2ELWithSupervisor(ids.Supervisor)))
54-
opt.Add(sysgo.WithL2CLNode(ids.L2ACL, ids.L1CL, ids.L1EL, ids.L2AEL, sysgo.L2CLSequencer(), sysgo.L2CLIndexing()))
55-
opt.Add(sysgo.WithManagedBySupervisor(ids.L2ACL, ids.Supervisor))
56-
57-
opt.Add(sysgo.WithBatcher(ids.L2ABatcher, ids.L1EL, ids.L2ACL, ids.L2AEL))
58-
opt.Add(sysgo.WithTestSequencer(ids.TestSequencer, ids.L1CL, ids.L2ACL, ids.L1EL, ids.L2AEL))
59-
opt.Add(sysgo.WithFaucets([]stack.L1ELNodeID{ids.L1EL}, []stack.L2ELNodeID{ids.L2AEL}))
60-
61-
opt.Add(sysgo.WithSuperDeploySP1MockVerifier(ids.L1EL, l2ChainID))
62-
opt.Add(sysgo.WithSuperDeployOpSuccinctL2OutputOracle(ids.L1CL, ids.L1EL, ids.L2ACL, ids.L2AEL, sysgo.WithL2OOStartingBlockNumber(1)))
63-
opt.Add(sysgo.WithSuperSuccinctValidityProposer(ids.L2AProposer, ids.L1CL, ids.L1EL, ids.L2ACL, ids.L2AEL))
64-
65-
opt.Add(sysgo.WithL2MetricsDashboard())
66-
opt.Add(stack.Finally(func(orch *sysgo.Orchestrator) {
67-
*dest = ids
68-
}))
69-
70-
return stack.MakeCommon(opt)
10+
return withSuccinctPreset(dest, func(opt *stack.CombinedOption[*sysgo.Orchestrator], ids sysgo.DefaultSingleChainInteropSystemIDs, l2ChainID eth.ChainID) {
11+
opt.Add(sysgo.WithSuperDeploySP1MockVerifier(ids.L1EL, l2ChainID))
12+
opt.Add(sysgo.WithSuperDeployOpSuccinctL2OutputOracle(ids.L1CL, ids.L1EL, ids.L2ACL, ids.L2AEL, sysgo.WithL2OOStartingBlockNumber(1)))
13+
opt.Add(sysgo.WithSuperSuccinctValidityProposer(ids.L2AProposer, ids.L1CL, ids.L1EL, ids.L2ACL, ids.L2AEL))
14+
})
7115
}

0 commit comments

Comments
 (0)