Skip to content

Commit

Permalink
fix(e2e): fix challenge e2e tests not working properly
Browse files Browse the repository at this point in the history
  • Loading branch information
seolaoh committed Mar 18, 2024
1 parent 646eb95 commit fa0f72d
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 48 deletions.
71 changes: 67 additions & 4 deletions kroma-chain-ops/genesis/layer_one.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
gstate "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/crypto"

"github.com/kroma-network/kroma/kroma-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-chain-ops/state"
"github.com/kroma-network/kroma/kroma-bindings/bindings"
)

var (
Expand Down Expand Up @@ -120,9 +121,10 @@ func PostProcessL1DeveloperGenesis(stateDB *state.MemoryStateDB, deployments *L1
slot := common.BigToHash(big.NewInt(int64(entry.Slot)))

stateDB.SetState(deployments.KromaPortalProxy, slot, common.Hash{})
log.Info("Post process update", "address", deployments.KromaPortalProxy, "slot", slot.Hex(), "value", common.Hash{}.Hex())
log.Info("Post process update", "name", "KromaPortal", "address", deployments.KromaPortalProxy, "slot", slot.Hex(), "value", common.Hash{}.Hex())

// [Kroma: START] Transfer ownership of SystemConfig to ProxyAdminOwner for test
// [Kroma: START]
// Transfer ownership of SystemConfig to ProxyAdminOwner for test
if !stateDB.Exist(deployments.SystemConfigProxy) {
return fmt.Errorf("sysCfg proxy doesn't exist at %s", deployments.SystemConfigProxy)
}
Expand All @@ -140,7 +142,68 @@ func PostProcessL1DeveloperGenesis(stateDB *state.MemoryStateDB, deployments *L1
val := stateDB.GetState(deployments.ProxyAdmin, common.BigToHash(common.Big0))

stateDB.SetState(deployments.SystemConfigProxy, slot, val)
log.Info("Post process update", "address", deployments.SystemConfigProxy, "slot", slot.Hex(), "value", val.Hex())
log.Info("Post process update", "name", "SystemConfig", "address", deployments.SystemConfigProxy, "slot", slot.Hex(), "value", val.Hex())

// Change the key of _quorumNumeratorHistory in UpgradeGovernor to 1 which means that quorumNumerator has been set at L1 block number 1 for guardian test
if !stateDB.Exist(deployments.UpgradeGovernorProxy) {
return fmt.Errorf("upgardeGovernor proxy doesn't exist at %s", deployments.UpgradeGovernorProxy)
}

layout, err = bindings.GetStorageLayout("UpgradeGovernor")
if err != nil {
return errors.New("failed to get storage layout for UpgradeGovernor")
}

entry, err = layout.GetStorageLayoutEntry("_quorumNumeratorHistory")
if err != nil {
return errors.New("failed to get storage layout entry for UpgradeGovernor._quorumNumeratorHistory")
}
slot = common.BigToHash(big.NewInt(int64(entry.Slot)))
slot = crypto.Keccak256Hash(slot.Bytes())

beforeVal := stateDB.GetState(deployments.UpgradeGovernorProxy, slot)
ckptVal := make([]byte, 28)
copy(ckptVal, beforeVal[:28])
ckptKey := [4]byte{}
ckptKey[3] = 0x01
val = common.BytesToHash(append(ckptVal, ckptKey[:]...))

stateDB.SetState(deployments.UpgradeGovernorProxy, slot, val)
afterVal := stateDB.GetState(deployments.UpgradeGovernorProxy, slot)
log.Info("Post process update", "name", "UpgradeGovernor", "address", deployments.UpgradeGovernorProxy, "slot", slot.Hex(), "beforeVal", beforeVal.Hex(), "afterVal", afterVal.Hex())

// Change the keys of _totalCheckpoints in SecurityCouncilToken to 1 which means that tokens have been minted at L1 block number 1 for guardian test
if !stateDB.Exist(deployments.SecurityCouncilTokenProxy) {
return fmt.Errorf("securityCouncilToken proxy doesn't exist at %s", deployments.SecurityCouncilTokenProxy)
}

layout, err = bindings.GetStorageLayout("SecurityCouncilToken")
if err != nil {
return errors.New("failed to get storage layout for SecurityCouncilToken")
}

entry, err = layout.GetStorageLayoutEntry("_totalCheckpoints")
if err != nil {
return errors.New("failed to get storage layout entry for SecurityCouncilToken._totalCheckpoints")
}
slot = common.BigToHash(big.NewInt(int64(entry.Slot)))
startSlot := new(big.Int).SetBytes(crypto.Keccak256(slot.Bytes()))

mintedNum := stateDB.GetState(deployments.SecurityCouncilTokenProxy, slot).Big().Uint64()
for i := 0; uint64(i) < mintedNum; i++ {
slot = common.BigToHash(new(big.Int).Add(startSlot, big.NewInt(int64(i))))

beforeVal = stateDB.GetState(deployments.SecurityCouncilTokenProxy, slot)
ckptVal = make([]byte, 28)
copy(ckptVal, beforeVal[:28])
ckptKey = [4]byte{}
ckptKey[3] = 0x01
val = common.BytesToHash(append(ckptVal, ckptKey[:]...))

stateDB.SetState(deployments.SecurityCouncilTokenProxy, slot, val)
afterVal = stateDB.GetState(deployments.SecurityCouncilTokenProxy, slot)
log.Info("Post process update", "name", "SecurityCouncilToken", "address", deployments.SecurityCouncilTokenProxy, "slot", slot.Hex(), "beforeVal", beforeVal.Hex(), "afterVal", afterVal.Hex())
}
// [Kroma: END]
return nil
}
20 changes: 10 additions & 10 deletions kroma-validator/guardian.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func (g *Guardian) inspectOutput(outputIndex, fromBlock, toBlock *big.Int) {
retry := func() bool {
cCtx, cCancel := context.WithTimeout(g.ctx, g.cfg.NetworkTimeout)
defer cCancel()
isFinalized, err := g.IsOutputFinalized(cCtx, outputIndex)
isFinalized, err := g.isOutputFinalized(g.ctx, outputIndex)
if err != nil {
g.log.Error("unable to check if the output is finalized or not", "err", err, "outputIndex", outputIndex)
return true
Expand Down Expand Up @@ -416,7 +416,7 @@ func (g *Guardian) tryConfirmRequestValidationTx(event *bindings.SecurityCouncil
return fmt.Errorf("failed to get output index after. (l2BlockNumber: %d): %w", event.L2BlockNumber.Int64(), err)
}

needConfirm, err := g.checkConfirmCondition(event.TransactionId, outputIndex)
needConfirm, err := g.CheckConfirmCondition(g.ctx, event.TransactionId, outputIndex)
if err != nil {
return fmt.Errorf("failed to check confirm condition. (transactionId: %d): %w", event.TransactionId.Int64(), err)
}
Expand Down Expand Up @@ -448,7 +448,7 @@ func (g *Guardian) tryConfirmRequestValidationTx(event *bindings.SecurityCouncil
}

func (g *Guardian) tryConfirmRequestDeletionTx(event *bindings.SecurityCouncilDeletionRequested) error {
needConfirm, err := g.checkConfirmCondition(event.TransactionId, event.OutputIndex)
needConfirm, err := g.CheckConfirmCondition(g.ctx, event.TransactionId, event.OutputIndex)
if err != nil {
return fmt.Errorf("failed to check confirm condition. (transactionId: %d): %w", event.TransactionId.Int64(), err)
}
Expand Down Expand Up @@ -486,8 +486,8 @@ func (g *Guardian) tryConfirmRequestDeletionTx(event *bindings.SecurityCouncilDe
return nil
}

func (g *Guardian) checkConfirmCondition(transactionId *big.Int, outputIndex *big.Int) (bool, error) {
outputFinalized, err := g.IsOutputFinalized(g.ctx, outputIndex)
func (g *Guardian) CheckConfirmCondition(ctx context.Context, transactionId *big.Int, outputIndex *big.Int) (bool, error) {
outputFinalized, err := g.isOutputFinalized(ctx, outputIndex)
if err != nil {
return true, fmt.Errorf("failed to get if output is finalized. (outputIndex: %d): %w", outputIndex.Int64(), err)
}
Expand All @@ -496,7 +496,7 @@ func (g *Guardian) checkConfirmCondition(transactionId *big.Int, outputIndex *bi
return false, nil
}

isConfirmed, err := g.isTransactionConfirmed(transactionId)
isConfirmed, err := g.isTransactionConfirmed(ctx, transactionId)
if err != nil {
return true, fmt.Errorf("failed to get confirmation. (transactionId: %d): %w", transactionId.Int64(), err)
}
Expand All @@ -505,7 +505,7 @@ func (g *Guardian) checkConfirmCondition(transactionId *big.Int, outputIndex *bi
return false, nil
}

cCtx, cCancel := context.WithTimeout(g.ctx, g.cfg.NetworkTimeout)
cCtx, cCancel := context.WithTimeout(ctx, g.cfg.NetworkTimeout)
defer cCancel()
executionTx, err := g.securityCouncilContract.Transactions(optsutils.NewSimpleCallOpts(cCtx), transactionId)
if err != nil {
Expand Down Expand Up @@ -602,14 +602,14 @@ func (g *Guardian) getL2OutputIndexAfter(l2BlockNumber *big.Int) (*big.Int, erro
return g.l2ooContract.GetL2OutputIndexAfter(optsutils.NewSimpleCallOpts(cCtx), l2BlockNumber)
}

func (g *Guardian) IsOutputFinalized(ctx context.Context, outputIndex *big.Int) (bool, error) {
func (g *Guardian) isOutputFinalized(ctx context.Context, outputIndex *big.Int) (bool, error) {
cCtx, cCancel := context.WithTimeout(ctx, g.cfg.NetworkTimeout)
defer cCancel()
return g.l2ooContract.IsFinalized(optsutils.NewSimpleCallOpts(cCtx), outputIndex)
}

func (g *Guardian) isTransactionConfirmed(transactionId *big.Int) (bool, error) {
cCtx, cCancel := context.WithTimeout(g.ctx, g.cfg.NetworkTimeout)
func (g *Guardian) isTransactionConfirmed(ctx context.Context, transactionId *big.Int) (bool, error) {
cCtx, cCancel := context.WithTimeout(ctx, g.cfg.NetworkTimeout)
defer cCancel()
return g.securityCouncilContract.IsConfirmed(optsutils.NewSimpleCallOpts(cCtx), transactionId)
}
6 changes: 4 additions & 2 deletions op-e2e/actions/l2_challenger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,11 +328,13 @@ interaction:
outputDeleted := val.IsOutputDeleted(remoteOutput.OutputRoot)
require.True(rt.t, outputDeleted, "output is not deleted")

// guardian validates deleted output by challenger is invalid after challenge is proven
// guardian validates deleted output by challenger is valid, so confirm the transaction to roll back the challenge
needConfirm := rt.guardian.ActCheckConfirmCondition(rt.t, rt.outputIndex, transactionId)
require.True(rt.t, needConfirm, "confirmation condition is not met")
outputBlockNum := rt.outputOnL1.L2BlockNumber.Uint64()
isEqual := rt.guardian.ActValidateL2Output(rt.t, rt.outputOnL1.OutputRoot, outputBlockNum)
require.True(rt.t, isEqual, "deleted output is expected equal but actually not equal")
rt.txHash = rt.guardian.ActConfirmTransaction(rt.t, rt.outputIndex, transactionId)
rt.txHash = rt.guardian.ActConfirmTransaction(rt.t, transactionId)
rt.IncludeL1Block(rt.guardian.address)
break interaction
default:
Expand Down
12 changes: 7 additions & 5 deletions op-e2e/actions/l2_guardian.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ import (
"github.com/ethereum-optimism/optimism/op-service/eth"
)

func (v *L2Validator) ActCheckConfirmCondition(t Testing, outputIndex *big.Int, transactionId *big.Int) bool {
needConfirm, err := v.guardian.CheckConfirmCondition(t.Ctx(), transactionId, outputIndex)
require.NoError(t, err, "unable to check confirm condition")
return needConfirm
}

func (v *L2Validator) ActValidateL2Output(t Testing, outputRoot eth.Bytes32, l2BlockNumber uint64) bool {
isEqual, err := v.guardian.ValidateL2Output(t.Ctx(), outputRoot, l2BlockNumber)
require.NoError(t, err, "unable to validate l2Output")
return isEqual
}

func (v *L2Validator) ActConfirmTransaction(t Testing, outputIndex *big.Int, transactionId *big.Int) common.Hash {
outputFinalized, err := v.guardian.IsOutputFinalized(t.Ctx(), outputIndex)
require.NoError(t, err, "unable to get if output is finalized")
require.False(t, outputFinalized, "output is already finalized")

func (v *L2Validator) ActConfirmTransaction(t Testing, transactionId *big.Int) common.Hash {
tx, err := v.guardian.ConfirmTransaction(t.Ctx(), transactionId)
require.NoError(t, err, "unable to confirm transaction")

Expand Down
1 change: 1 addition & 0 deletions op-e2e/actions/l2_runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ 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) Runtime {
t := NewDefaultTesting(gt)
dp := e2eutils.MakeDeployParams(t, defaultRollupTestParams)
Expand Down
34 changes: 19 additions & 15 deletions op-e2e/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net"
"os"
"path"
"reflect"
"sort"
"strings"
"sync/atomic"
Expand Down Expand Up @@ -562,28 +563,31 @@ func (cfg SystemConfig) Start(t *testing.T, _opts ...SystemConfigOption) (*Syste
}
}

// [Kroma: START]
// Geth Clients
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
l1Srv, err := l1Node.RPCHandler()
if err != nil {
return nil, err
}
rawL1Client := rpc.DialInProc(l1Srv)
l1Client := ethclient.NewClient(rawL1Client)
sys.Clients["l1"] = l1Client
sys.RawClients["l1"] = rawL1Client
for name, ethInst := range sys.EthInstances {
rawClient, err := rpc.DialContext(ctx, ethInst.WSEndpoint())
if err != nil {
return nil, err
var rawClient *rpc.Client
if reflect.TypeOf(ethInst) == reflect.TypeOf(&GethInstance{}) {
rpcHandler, err := ethInst.(*GethInstance).Node.RPCHandler()
if err != nil {
return nil, err
}
rawClient = rpc.DialInProc(rpcHandler)
} else {
rawClient, err = rpc.DialContext(ctx, ethInst.WSEndpoint())
if err != nil {
return nil, err
}
}
client := ethclient.NewClient(rawClient)
sys.Clients[name] = ethclient.NewClient(rawClient)
sys.RawClients[name] = rawClient
sys.Clients[name] = client
}

_, err = geth.WaitForBlock(big.NewInt(2), l1Client, 6*time.Second*time.Duration(cfg.DeployConfig.L1BlockTime))
_, err = geth.WaitForBlock(big.NewInt(2), sys.Clients["l1"], 6*time.Second*time.Duration(cfg.DeployConfig.L1BlockTime))
// [Kroma: END]

if err != nil {
return nil, fmt.Errorf("waiting for blocks: %w", err)
}
Expand Down Expand Up @@ -1024,7 +1028,7 @@ func (cfg SystemConfig) SendTransferTx(l2Seq *ethclient.Client, l2Sync *ethclien

receipt, err := geth.WaitForL2Transaction(tx.Hash(), l2Sync, 4*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
if err != nil {
return nil, fmt.Errorf("failed to wait L2 tx on verifier: %w", err)
return nil, fmt.Errorf("failed to wait L2 tx on verifㅋier: %w", err)
}

return receipt, nil
Expand Down
53 changes: 41 additions & 12 deletions op-e2e/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import (
"github.com/stretchr/testify/require"
"golang.org/x/exp/slices"

"github.com/kroma-network/kroma/kroma-bindings/bindings"
"github.com/kroma-network/kroma/kroma-bindings/predeploys"
"github.com/ethereum-optimism/optimism/op-e2e/config"
gethutils "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/geth"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
Expand All @@ -45,6 +43,8 @@ import (
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/ethereum-optimism/optimism/op-service/sources"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/kroma-network/kroma/kroma-bindings/bindings"
"github.com/kroma-network/kroma/kroma-bindings/predeploys"

val "github.com/kroma-network/kroma/kroma-validator"
chal "github.com/kroma-network/kroma/kroma-validator/challenge"
Expand Down Expand Up @@ -1469,10 +1469,12 @@ func TestChallenge(t *testing.T) {
// SecurityCouncil is already deployed
securityCouncil, err := bindings.NewSecurityCouncilCaller(cfg.L1Deployments.SecurityCouncilProxy, l1Client)
require.NoError(t, err)
securityCouncilABI, err := bindings.SecurityCouncilMetaData.GetAbi()
require.NoError(t, err)

targetOutputOracleIndex := uint64(math.Ceil(float64(testdata.TargetBlockNumber) / float64(cfg.DeployConfig.L2OutputOracleSubmissionInterval)))

// set a timeout for one cycle of challenge
// set a timeout for waiting READY_TO_PROVE of challenge
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Second)
defer cancel()

Expand All @@ -1496,24 +1498,49 @@ func TestChallenge(t *testing.T) {
}
cancel()

// set a timeout for security council to validate output
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
findTransactionId := func() *big.Int {
validationRequestedEvent := securityCouncilABI.Events["ValidationRequested"]
eventIDTopic := []common.Hash{validationRequestedEvent.ID}
toBlock := latestBlock(t, l1Client)

query := ethereum.FilterQuery{
ToBlock: big.NewInt(int64(toBlock)),
Addresses: []common.Address{cfg.L1Deployments.SecurityCouncilProxy},
Topics: [][]common.Hash{eventIDTopic},
}

cCtx, cCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cCancel()
logs, err := l1Client.FilterLogs(cCtx, query)
require.NoError(t, err)
require.Equal(t, len(logs), 1)

return new(big.Int).SetBytes(logs[0].Topics[1][:])
}

// set a timeout for security council to validate output (provingTimeout + buffer)
provingTimeout, err := colosseum.PROVINGTIMEOUT(&bind.CallOpts{})
ctx, cancel = context.WithTimeout(context.Background(), time.Duration(provingTimeout.Uint64()+5)*time.Second)
defer cancel()

numCheck := 0
for ; ; <-ticker.C {
select {
case <-ctx.Done():
// after security council timed out, the challenge is regarded to be correct
// after enough time for security council elapsed, the challenge is regarded to be correct
require.True(t, numCheck >= 5, "at least 5 sec should be elapsed after challenge succeed")
return
default:
challengeStatus, err := colosseum.GetStatus(&bind.CallOpts{}, new(big.Int).SetUint64(targetOutputOracleIndex), cfg.Secrets.Addresses().Challenger1)
require.NoError(t, err)

// after challenge is proven, status is NONE
if challengeStatus == chal.StatusNone {
// check tx not executed
tx, err := securityCouncil.Transactions(&bind.CallOpts{}, new(big.Int).SetUint64(0))
// check validation request tx exists and not executed
transactionId := findTransactionId()
tx, err := securityCouncil.Transactions(&bind.CallOpts{}, transactionId)
require.NoError(t, err)
require.NotEqual(t, tx.Target, common.Address{})
require.False(t, tx.Executed)

// check output is deleted by challenger
Expand All @@ -1522,15 +1549,17 @@ func TestChallenge(t *testing.T) {
require.Equal(t, output.Submitter, cfg.Secrets.Addresses().Challenger1)
outputDeleted := val.IsOutputDeleted(output.OutputRoot)
require.True(t, outputDeleted)

numCheck++

if numCheck >= 5 {
return
}
}
}
}
}

func safeAddBig(a *big.Int, b *big.Int) *big.Int {
return new(big.Int).Add(a, b)
}

func TestBatcherMultiTx(t *testing.T) {
InitParallel(t)

Expand Down

0 comments on commit fa0f72d

Please sign in to comment.