Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(e2e): replace challege testdata and enable zkVM challenge e2e test #408

Merged
merged 8 commits into from
Dec 19, 2024
1 change: 1 addition & 0 deletions kroma-bindings/artifacts.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"ProxyAdmin",
"SecurityCouncil",
"SecurityCouncilToken",
"SP1Verifier",
"StandardBridge",
"SystemConfig",
"TimeLock",
Expand Down
356 changes: 356 additions & 0 deletions kroma-bindings/bindings/sp1verifier.go

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions kroma-bindings/bindings/sp1verifier_more.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion kroma-bindings/bindings/zkproofverifier.go

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions kroma-bindings/bindings/zkproofverifier_more.go

Large diffs are not rendered by default.

63 changes: 19 additions & 44 deletions op-e2e/actions/l2_challenger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

var challengerTests = []struct {
name string
f func(ft *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType)
f func(ft *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8)
}{
{"ChallengeBasic", ChallengeBasic},
{"ChallengeAsserterBisectTimeout", ChallengeAsserterBisectTimeout},
Expand All @@ -32,15 +32,15 @@ func TestChallengerBatchType(t *testing.T) {
for _, test := range challengerTests {
test := test
t.Run(test.name+"_SingularBatch", func(t *testing.T) {
test.f(t, nil, valhelper.ValidatorV1, testdata.DefaultProofType)
test.f(t, nil, valhelper.ValidatorV1)
})
}

deltaTimeOffset := hexutil.Uint64(0)
for _, test := range challengerTests {
test := test
t.Run(test.name+"_SpanBatch", func(t *testing.T) {
test.f(t, &deltaTimeOffset, valhelper.ValidatorV1, testdata.DefaultProofType)
test.f(t, &deltaTimeOffset, valhelper.ValidatorV1)
})
}
}
Expand All @@ -50,39 +50,19 @@ func TestValidatorSystemVersion(t *testing.T) {
for _, test := range challengerTests {
test := test
t.Run(test.name+"_ValidatorPool", func(t *testing.T) {
test.f(t, nil, valhelper.ValidatorV1, testdata.DefaultProofType)
test.f(t, nil, valhelper.ValidatorV1)
})
}
for _, test := range challengerTests {
test := test
t.Run(test.name+"_ValidatorManager", func(t *testing.T) {
test.f(t, nil, valhelper.ValidatorV2, testdata.DefaultProofType)
test.f(t, nil, valhelper.ValidatorV2)
})
}
}

// TestChallengerProofType run each challenge test case in zkEVM version and zkVM version.
func TestChallengerProofType(t *testing.T) {
t.Skip("Temporarily skip, enable when test data added") // TODO(seolaoh)

for _, test := range challengerTests {
test := test
t.Run(test.name+"_zkEVM", func(t *testing.T) {
test.f(t, nil, valhelper.ValidatorV1, testdata.ZkEVMType)
})
}

deltaTimeOffset := hexutil.Uint64(0)
for _, test := range challengerTests {
test := test
t.Run(test.name+"_zkVM", func(t *testing.T) {
test.f(t, &deltaTimeOffset, valhelper.ValidatorV1, testdata.ZkVMType)
})
}
}

func ChallengeBasic(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset, proofType)
func ChallengeBasic(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset)

if version == valhelper.ValidatorV2 {
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down Expand Up @@ -169,9 +149,8 @@ interaction:
}
}

func ChallengeAsserterBisectTimeout(
t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset, proofType)
func ChallengeAsserterBisectTimeout(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset)

if version == valhelper.ValidatorV2 {
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down Expand Up @@ -253,9 +232,8 @@ interaction:
}
}

func ChallengeChallengerBisectTimeout(
t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset, proofType)
func ChallengeChallengerBisectTimeout(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset)

if version == valhelper.ValidatorV2 {
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down Expand Up @@ -335,9 +313,8 @@ interaction:
}
}

func ChallengeChallengerProvingTimeout(
t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset, proofType)
func ChallengeChallengerProvingTimeout(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset)

if version == valhelper.ValidatorV2 {
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down Expand Up @@ -421,9 +398,8 @@ interaction:
}
}

func ChallengeInvalidProofFail(
t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset, proofType)
func ChallengeInvalidProofFail(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset)

if version == valhelper.ValidatorV2 {
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down Expand Up @@ -538,9 +514,8 @@ interaction:
}
}

func ChallengeForceDeleteOutputBySecurityCouncil(
t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset, proofType)
func ChallengeForceDeleteOutputBySecurityCouncil(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset)

if version == valhelper.ValidatorV2 {
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down Expand Up @@ -633,8 +608,8 @@ interaction:
}
}

func MultipleChallenges(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8, proofType testdata.ProofType) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset, proofType)
func MultipleChallenges(t *testing.T, deltaTimeOffset *hexutil.Uint64, version uint8) {
rt := defaultRuntime(t, setupSequencerTest, deltaTimeOffset)

if version == valhelper.ValidatorV2 {
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down
73 changes: 8 additions & 65 deletions op-e2e/actions/l2_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -57,7 +56,6 @@ type Runtime struct {
assetMgrContract *bindings.AssetManagerCaller
assetTokenContract *bindings.GovernanceTokenCaller
targetInvalidBlockNumber uint64
ChallengeProofType testdata.ProofType
outputIndex *big.Int
outputOnL1 bindings.TypesCheckpointOutput
txHash common.Hash
Expand All @@ -68,37 +66,23 @@ type Runtime struct {
type SetupSequencerTestFunc = func(t Testing, sd *e2eutils.SetupData, log log.Logger) (*L1Miner, *L2Engine, *L2Sequencer)

// defaultRuntime is currently only used for l2_challenger_test.
func defaultRuntime(
gt *testing.T, setupSequencerTest SetupSequencerTestFunc, deltaTimeOffset *hexutil.Uint64, proofType testdata.ProofType,
) Runtime {
func defaultRuntime(gt *testing.T, setupSequencerTest SetupSequencerTestFunc, deltaTimeOffset *hexutil.Uint64) Runtime {
t := NewDefaultTesting(gt)
dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams)
if proofType == testdata.ZkVMType {
genesisActivation := hexutil.Uint64(0)
deltaTimeOffset = &genesisActivation
mptTimeOffset := hexutil.Uint64(2)
dp.DeployConfig.L2GenesisEcotoneTimeOffset = deltaTimeOffset
dp.DeployConfig.L2GenesisKromaMPTTimeOffset = &mptTimeOffset
}
dp.DeployConfig.L2GenesisDeltaTimeOffset = deltaTimeOffset
sd := e2eutils.Setup(t, dp, defaultAlloc)
l := testlog.Logger(t, log.LvlDebug)
rt := Runtime{
t: t,
dp: dp,
sd: sd,
l: l,
l1BlockDelta: 6,
ChallengeProofType: proofType,
t: t,
dp: dp,
sd: sd,
l: l,
l1BlockDelta: 6,
}

rt.miner, rt.seqEngine, rt.sequencer = setupSequencerTest(rt.t, rt.sd, rt.l)
rt.setupBatcher(dp)

if proofType == testdata.ZkVMType {
rt.assertReplaceWithMockColosseum()
}

return rt
}

Expand Down Expand Up @@ -149,13 +133,13 @@ func (rt *Runtime) setupValidator(pk *ecdsa.PrivateKey, setInvalidBlockNumber bo
var validatorRollupClient *sources.RollupClient
if isMalicious {
// setup mockup rpc for returning invalid output
validatorRPC, err := e2eutils.NewMaliciousL2RPC(rt.sequencer.RPCClient(), rt.ChallengeProofType)
validatorRPC, err := e2eutils.NewMaliciousL2RPC(rt.sequencer.RPCClient(), testdata.DefaultProofType)
require.NoError(rt.t, err)
validatorRPC.SetTargetBlockNumber(rt.targetInvalidBlockNumber)
validatorRollupClient = sources.NewRollupClient(validatorRPC)
} else {
// setup mockup rpc for returning valid output
validatorRPC, err := e2eutils.NewHonestL2RPC(rt.sequencer.RPCClient(), rt.ChallengeProofType)
validatorRPC, err := e2eutils.NewHonestL2RPC(rt.sequencer.RPCClient(), testdata.DefaultProofType)
require.NoError(rt.t, err)
if setInvalidBlockNumber {
validatorRPC.SetTargetBlockNumber(rt.targetInvalidBlockNumber)
Expand Down Expand Up @@ -229,31 +213,6 @@ func (rt *Runtime) assertRedeployValPoolToTerminate(newTerminationIndex *big.Int
require.Equal(rt.t, types.ReceiptStatusSuccessful, receipt.Status, "upgrade tx submission failed")
}

// assertReplaceWithMockColosseum deploys MockColosseum which has setL1Head function and upgrades proxy for challenge test.
// It also asserts that the deploying and upgrade tx is successful.
func (rt *Runtime) assertReplaceWithMockColosseum() {
deployTx, upgradeTx, err := e2eutils.ReplaceWithMockColosseum(
rt.miner.EthClient(),
rt.dp.Secrets.SysCfgOwner,
rt.sd.RollupCfg.L1ChainID,
rt.sd.DeploymentsL1,
rt.dp.DeployConfig,
)
require.NoError(rt.t, err)

// Check deploy tx submission was successful
rt.includeL1BlockByTx(deployTx.Hash())
receipt, err := rt.miner.EthClient().TransactionReceipt(rt.t.Ctx(), deployTx.Hash())
require.NoError(rt.t, err)
require.Equal(rt.t, types.ReceiptStatusSuccessful, receipt.Status, "deploy tx submission failed")

// Check upgrade tx submission was successful
rt.includeL1BlockByTx(upgradeTx.Hash())
receipt, err = rt.miner.EthClient().TransactionReceipt(rt.t.Ctx(), upgradeTx.Hash())
require.NoError(rt.t, err)
require.Equal(rt.t, types.ReceiptStatusSuccessful, receipt.Status, "upgrade tx submission failed")
}

// setupOutputSubmitted sets output submission by validator.
func (rt *Runtime) setupOutputSubmitted(version uint8) {
// NOTE(chokobole): It is necessary to wait for one finalized (or safe if AllowNonFinalized
Expand Down Expand Up @@ -326,22 +285,6 @@ func (rt *Runtime) setupChallenge(challenger *L2Validator, version uint8) {
require.NoError(rt.t, err)
require.NotNil(rt.t, challenge, "challenge not found")

// mock challenge.l1Head for zkVM challenge test
if rt.ChallengeProofType == testdata.ZkVMType {
txOpts, err := bind.NewKeyedTransactorWithChainID(rt.dp.Secrets.Alice, rt.sd.RollupCfg.L1ChainID)
require.NoError(rt.t, err)
tx, err := rt.colosseumContract.SetL1Head(txOpts, rt.outputIndex, challenger.address, testdata.ChallengeL1Head)
require.NoError(rt.t, err)

// include tx on L1
rt.includeL1BlockByTx(tx.Hash())

// Check whether the submission was successful
receipt, err := rt.miner.EthClient().TransactionReceipt(rt.t.Ctx(), tx.Hash())
require.NoError(rt.t, err)
require.Equal(rt.t, types.ReceiptStatusSuccessful, receipt.Status, "failed to set L1 head")
}

if version == valhelper.ValidatorV1 {
// check pending bond amount after create challenge
pendingBond, err := rt.valPoolContract.GetPendingBond(nil, rt.outputIndex, challenger.address)
Expand Down
5 changes: 2 additions & 3 deletions op-e2e/actions/l2_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/kroma-network/kroma/kroma-bindings/bindings"
"github.com/kroma-network/kroma/op-e2e/e2eutils/validator"
"github.com/kroma-network/kroma/op-e2e/testdata"
)

// TestValidatorBatchType run each validator-related test case in singular batch mode and span batch mode.
Expand Down Expand Up @@ -40,7 +39,7 @@ func TestValidatorBatchType(t *testing.T) {
}

func RunValidatorPoolTest(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
rt := defaultRuntime(gt, setupSequencerTest, deltaTimeOffset, testdata.DefaultProofType)
rt := defaultRuntime(gt, setupSequencerTest, deltaTimeOffset)
rt.setupHonestValidator(false)

// bind contracts
Expand All @@ -53,7 +52,7 @@ func RunValidatorPoolTest(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
}

func RunValidatorManagerTest(gt *testing.T, deltaTimeOffset *hexutil.Uint64) {
rt := defaultRuntime(gt, setupSequencerTest, deltaTimeOffset, testdata.DefaultProofType)
rt := defaultRuntime(gt, setupSequencerTest, deltaTimeOffset)

// Redeploy and upgrade ValidatorPool to set the termination index to a smaller value for ValidatorManager test
rt.assertRedeployValPoolToTerminate(defaultValPoolTerminationIndex)
Expand Down
2 changes: 1 addition & 1 deletion op-e2e/e2eutils/mock_proof_fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (m *MockRPC) getWitness() *chal.WitnessResponse {
func (m *MockRPC) getProof() *chal.ZkVMProofResponse {
return &chal.ZkVMProofResponse{
VKeyHash: testdata.ZkVMVKeyHash,
PublicValues: testdata.ZkVMPublicVaules,
PublicValues: testdata.ZkVMPublicValues,
Proof: testdata.ZkVMProof,
}
}
Expand Down
66 changes: 66 additions & 0 deletions op-e2e/e2eutils/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,4 +379,70 @@ func ReplaceWithMockColosseum(
return
}

// DeploySP1Verifier deploys a SP1VerifierPlonk contract which is used in ZKProofVerifier.
func DeploySP1Verifier(
l1Client *ethclient.Client,
sysCfgOwner *ecdsa.PrivateKey,
l1ChainID *big.Int,
) (address common.Address, deployTx *types.Transaction, err error) {
txOpts, err := bind.NewKeyedTransactorWithChainID(sysCfgOwner, l1ChainID)
if err != nil {
return
}

// Deploy a SP1Verifier implementation
address, deployTx, _, err = bindings.DeploySP1Verifier(
txOpts,
l1Client,
)
if err != nil {
return
}

return
}

// RedeployZKProofVerifier deploys a new ZKProofVerifier with given SP1Verifier.
func RedeployZKProofVerifier(
l1Client *ethclient.Client,
sysCfgOwner *ecdsa.PrivateKey,
l1ChainID *big.Int,
l1Deployments *genesis.L1Deployments,
deployConfig *genesis.DeployConfig,
sp1Verifier common.Address,
zkVmProgramVKey [32]byte,
) (deployTx, upgradeTx *types.Transaction, err error) {
txOpts, err := bind.NewKeyedTransactorWithChainID(sysCfgOwner, l1ChainID)
if err != nil {
return
}

// Deploy a ZKProofVerifier implementation
implAddr, deployTx, _, err := bindings.DeployZKProofVerifier(
txOpts,
l1Client,
l1Deployments.ZKVerifier,
deployConfig.ColosseumDummyHash,
new(big.Int).SetUint64(deployConfig.ColosseumMaxTxs),
l1Deployments.ZKMerkleTrie,
sp1Verifier,
zkVmProgramVKey,
)
if err != nil {
return
}

// Upgrade ZKProofVerifierProxy to the deployed implementation address
proxyAdmin, err := bindings.NewProxyAdminTransactor(l1Deployments.ProxyAdmin, l1Client)
if err != nil {
return
}
upgradeTx, err = proxyAdmin.Upgrade(txOpts, l1Deployments.ZKProofVerifierProxy, implAddr)
if err != nil {
return
}

return
}

// [Kroma: END]
Loading