Commit 5c54f884 authored by Axel Kingsley's avatar Axel Kingsley Committed by GitHub

interop: Fix AtLeastAsSafe ; Geth Mempool Filter E2E Test (#12823)

* interop: Geth Mempool Filter E2E Test

* use latest op-geth rc

* fix AtLeastAsSafe

* fix test
parent dad10877
...@@ -250,7 +250,7 @@ require ( ...@@ -250,7 +250,7 @@ require (
rsc.io/tmplfunc v0.0.3 // indirect rsc.io/tmplfunc v0.0.3 // indirect
) )
replace github.com/ethereum/go-ethereum v1.14.11 => github.com/ethereum-optimism/op-geth v1.101411.1-rc.5 replace github.com/ethereum/go-ethereum v1.14.11 => github.com/ethereum-optimism/op-geth v1.101411.1-rc.6
//replace github.com/ethereum/go-ethereum => ../go-ethereum //replace github.com/ethereum/go-ethereum => ../go-ethereum
......
...@@ -187,8 +187,8 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u ...@@ -187,8 +187,8 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/u
github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs= github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
github.com/ethereum-optimism/op-geth v1.101411.1-rc.5 h1:LDSP85xTczjDYMBK0mOF5mzpZifLGz1TTW/6NgQsytc= github.com/ethereum-optimism/op-geth v1.101411.1-rc.6 h1:VvUBIVFbnU9486CWHa9Js5XYY3o6OsdQcI8gE3XjCDE=
github.com/ethereum-optimism/op-geth v1.101411.1-rc.5/go.mod h1:7S4pp8KHBmEmKkRjL1BPOc6jY9hW+64YeMUjR3RVLw4= github.com/ethereum-optimism/op-geth v1.101411.1-rc.6/go.mod h1:7S4pp8KHBmEmKkRjL1BPOc6jY9hW+64YeMUjR3RVLw4=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac h1:hCIrLuOPV3FJfMDvXeOhCC3uQNvFoMIIlkT2mN2cfeg= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac h1:hCIrLuOPV3FJfMDvXeOhCC3uQNvFoMIIlkT2mN2cfeg=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M= github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M=
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
......
...@@ -20,12 +20,13 @@ import ( ...@@ -20,12 +20,13 @@ import (
"github.com/ethereum-optimism/optimism/op-chain-ops/interopgen" "github.com/ethereum-optimism/optimism/op-chain-ops/interopgen"
"github.com/ethereum-optimism/optimism/op-e2e/system/helpers" "github.com/ethereum-optimism/optimism/op-e2e/system/helpers"
"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types" "github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
gethCore "github.com/ethereum/go-ethereum/core"
gethTypes "github.com/ethereum/go-ethereum/core/types" gethTypes "github.com/ethereum/go-ethereum/core/types"
) )
// setupAndRun is a helper function that sets up a SuperSystem // setupAndRun is a helper function that sets up a SuperSystem
// which contains two L2 Chains, and two users on each chain. // which contains two L2 Chains, and two users on each chain.
func setupAndRun(t *testing.T, fn func(*testing.T, SuperSystem)) { func setupAndRun(t *testing.T, config SuperSystemConfig, fn func(*testing.T, SuperSystem)) {
recipe := interopgen.InteropDevRecipe{ recipe := interopgen.InteropDevRecipe{
L1ChainID: 900100, L1ChainID: 900100,
L2ChainIDs: []uint64{900200, 900201}, L2ChainIDs: []uint64{900200, 900201},
...@@ -38,7 +39,7 @@ func setupAndRun(t *testing.T, fn func(*testing.T, SuperSystem)) { ...@@ -38,7 +39,7 @@ func setupAndRun(t *testing.T, fn func(*testing.T, SuperSystem)) {
// create a super system from the recipe // create a super system from the recipe
// and get the L2 IDs for use in the test // and get the L2 IDs for use in the test
s2 := NewSuperSystem(t, &recipe, worldResources) s2 := NewSuperSystem(t, &recipe, worldResources, config)
// create two users on all L2 chains // create two users on all L2 chains
s2.AddUser("Alice") s2.AddUser("Alice")
...@@ -98,13 +99,16 @@ func TestInterop_IsolatedChains(t *testing.T) { ...@@ -98,13 +99,16 @@ func TestInterop_IsolatedChains(t *testing.T) {
expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10) expectedBalance, _ = big.NewInt(0).SetString("10000000000000000000000000", 10)
require.Equal(t, expectedBalance, bobBalance) require.Equal(t, expectedBalance, bobBalance)
} }
setupAndRun(t, test) config := SuperSystemConfig{
mempoolFiltering: false,
}
setupAndRun(t, config, test)
} }
// TestInteropTrivial_EmitLogs tests a simple interop scenario // TestInterop_EmitLogs tests a simple interop scenario
// Chains A and B exist, but no messages are sent between them. // Chains A and B exist, but no messages are sent between them.
// A contract is deployed on each chain, and logs are emitted repeatedly. // A contract is deployed on each chain, and logs are emitted repeatedly.
func TestInteropTrivial_EmitLogs(t *testing.T) { func TestInterop_EmitLogs(t *testing.T) {
test := func(t *testing.T, s2 SuperSystem) { test := func(t *testing.T, s2 SuperSystem) {
ids := s2.L2IDs() ids := s2.L2IDs()
chainA := ids[0] chainA := ids[0]
...@@ -195,7 +199,10 @@ func TestInteropTrivial_EmitLogs(t *testing.T) { ...@@ -195,7 +199,10 @@ func TestInteropTrivial_EmitLogs(t *testing.T) {
requireMessage(chainB, log, types.CrossSafe, nil) requireMessage(chainB, log, types.CrossSafe, nil)
} }
} }
setupAndRun(t, test) config := SuperSystemConfig{
mempoolFiltering: false,
}
setupAndRun(t, config, test)
} }
func TestInteropBlockBuilding(t *testing.T) { func TestInteropBlockBuilding(t *testing.T) {
...@@ -271,12 +278,18 @@ func TestInteropBlockBuilding(t *testing.T) { ...@@ -271,12 +278,18 @@ func TestInteropBlockBuilding(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
defer cancel() defer cancel()
// Send an executing message, but with different payload. // Send an executing message, but with different payload.
// We expect the miner to be unable to include this tx, and confirmation to thus time out. if s2.(*interopE2ESystem).config.mempoolFiltering {
_, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, invalidPayload) // We expect the traqnsaction to be filtered out by the mempool if mempool filtering is enabled.
require.NotNil(t, err) // ExecuteMessage the ErrTxFilteredOut error is checked when sending the tx.
_, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, invalidPayload, gethCore.ErrTxFilteredOut)
require.ErrorContains(t, err, gethCore.ErrTxFilteredOut.Error())
} else {
// We expect the miner to be unable to include this tx, and confirmation to thus time out, if mempool filtering is disabled.
_, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, invalidPayload, nil)
require.ErrorIs(t, err, ctx.Err()) require.ErrorIs(t, err, ctx.Err())
require.ErrorIs(t, ctx.Err(), context.DeadlineExceeded) require.ErrorIs(t, ctx.Err(), context.DeadlineExceeded)
} }
}
t.Log("Testing valid message now") t.Log("Testing valid message now")
{ {
...@@ -284,11 +297,25 @@ func TestInteropBlockBuilding(t *testing.T) { ...@@ -284,11 +297,25 @@ func TestInteropBlockBuilding(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
defer cancel() defer cancel()
// Send an executing message with the correct identifier / payload // Send an executing message with the correct identifier / payload
rec, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, msgPayload) rec, err := s2.ExecuteMessage(ctx, chainB, "Alice", identifier, bobAddr, msgPayload, nil)
require.NoError(t, err, "expecting tx to be confirmed") require.NoError(t, err, "expecting tx to be confirmed")
t.Logf("confirmed executing msg in block %s", rec.BlockNumber) t.Logf("confirmed executing msg in block %s", rec.BlockNumber)
} }
t.Log("Done") t.Log("Done")
} }
setupAndRun(t, test)
t.Run("without mempool filtering", func(t *testing.T) {
config := SuperSystemConfig{
mempoolFiltering: false,
}
setupAndRun(t, config, test)
})
t.Run("with mempool filtering", func(t *testing.T) {
config := SuperSystemConfig{
mempoolFiltering: true,
}
// run again with mempool filtering to observe the behavior of the mempool filter
setupAndRun(t, config, test)
})
} }
...@@ -114,14 +114,18 @@ type SuperSystem interface { ...@@ -114,14 +114,18 @@ type SuperSystem interface {
msgIdentifier supervisortypes.Identifier, msgIdentifier supervisortypes.Identifier,
target common.Address, target common.Address,
message []byte, message []byte,
expectedError error,
) (*types.Receipt, error) ) (*types.Receipt, error)
// Access a contract on a network by name // Access a contract on a network by name
Contract(network string, contractName string) interface{} Contract(network string, contractName string) interface{}
} }
type SuperSystemConfig struct {
mempoolFiltering bool
}
// NewSuperSystem creates a new SuperSystem from a recipe. It creates an interopE2ESystem. // NewSuperSystem creates a new SuperSystem from a recipe. It creates an interopE2ESystem.
func NewSuperSystem(t *testing.T, recipe *interopgen.InteropDevRecipe, w worldResourcePaths) SuperSystem { func NewSuperSystem(t *testing.T, recipe *interopgen.InteropDevRecipe, w worldResourcePaths, config SuperSystemConfig) SuperSystem {
s2 := &interopE2ESystem{recipe: recipe} s2 := &interopE2ESystem{recipe: recipe, config: &config}
s2.prepare(t, w) s2.prepare(t, w)
return s2 return s2
} }
...@@ -144,6 +148,7 @@ type interopE2ESystem struct { ...@@ -144,6 +148,7 @@ type interopE2ESystem struct {
l2GethClients map[string]*ethclient.Client l2GethClients map[string]*ethclient.Client
supervisor *supervisor.SupervisorService supervisor *supervisor.SupervisorService
superClient *sources.SupervisorClient superClient *sources.SupervisorClient
config *SuperSystemConfig
} }
// l2Set is a set of resources for an L2 chain // l2Set is a set of resources for an L2 chain
...@@ -263,6 +268,7 @@ func (s *interopE2ESystem) newGethForL2(id string, l2Out *interopgen.L2Output) * ...@@ -263,6 +268,7 @@ func (s *interopE2ESystem) newGethForL2(id string, l2Out *interopgen.L2Output) *
l2Geth, err := geth.InitL2(name, l2Out.Genesis, jwtPath, l2Geth, err := geth.InitL2(name, l2Out.Genesis, jwtPath,
func(ethCfg *ethconfig.Config, nodeCfg *gn.Config) error { func(ethCfg *ethconfig.Config, nodeCfg *gn.Config) error {
ethCfg.InteropMessageRPC = s.supervisor.RPC() ethCfg.InteropMessageRPC = s.supervisor.RPC()
ethCfg.InteropMempoolFiltering = s.config.mempoolFiltering
return nil return nil
}) })
require.NoError(s.t, err) require.NoError(s.t, err)
...@@ -721,6 +727,10 @@ func (s *interopE2ESystem) SendL2Tx( ...@@ -721,6 +727,10 @@ func (s *interopE2ESystem) SendL2Tx(
newApply) newApply)
} }
// ExecuteMessage calls the CrossL2Inbox executeMessage function
// it uses the L2's chain ID, username key, and geth client.
// expectedError represents the error returned by `ExecuteMessage` if it is expected.
// the returned err is related to `WaitMined`
func (s *interopE2ESystem) ExecuteMessage( func (s *interopE2ESystem) ExecuteMessage(
ctx context.Context, ctx context.Context,
id string, id string,
...@@ -728,6 +738,7 @@ func (s *interopE2ESystem) ExecuteMessage( ...@@ -728,6 +738,7 @@ func (s *interopE2ESystem) ExecuteMessage(
msgIdentifier supervisortypes.Identifier, msgIdentifier supervisortypes.Identifier,
target common.Address, target common.Address,
message []byte, message []byte,
expectedError error,
) (*types.Receipt, error) { ) (*types.Receipt, error) {
secret := s.UserKey(id, sender) secret := s.UserKey(id, sender)
auth, err := bind.NewKeyedTransactorWithChainID(&secret, s.l2s[id].chainID) auth, err := bind.NewKeyedTransactorWithChainID(&secret, s.l2s[id].chainID)
...@@ -746,7 +757,12 @@ func (s *interopE2ESystem) ExecuteMessage( ...@@ -746,7 +757,12 @@ func (s *interopE2ESystem) ExecuteMessage(
ChainId: msgIdentifier.ChainID.ToBig(), ChainId: msgIdentifier.ChainID.ToBig(),
} }
tx, err := contract.InboxTransactor.ExecuteMessage(auth, identifier, target, message) tx, err := contract.InboxTransactor.ExecuteMessage(auth, identifier, target, message)
if expectedError != nil {
require.ErrorContains(s.t, err, expectedError.Error())
return nil, err
} else {
require.NoError(s.t, err) require.NoError(s.t, err)
}
s.logger.Info("Executing message", "tx", tx.Hash(), "to", tx.To(), "target", target, "data", hexutil.Bytes(tx.Data())) s.logger.Info("Executing message", "tx", tx.Hash(), "to", tx.To(), "target", target, "data", hexutil.Bytes(tx.Data()))
return bind.WaitMined(ctx, s.L2GethClient(id), tx) return bind.WaitMined(ctx, s.L2GethClient(id), tx)
} }
......
...@@ -131,19 +131,27 @@ func (lvl *SafetyLevel) UnmarshalText(text []byte) error { ...@@ -131,19 +131,27 @@ func (lvl *SafetyLevel) UnmarshalText(text []byte) error {
} }
// AtLeastAsSafe returns true if the receiver is at least as safe as the other SafetyLevel. // AtLeastAsSafe returns true if the receiver is at least as safe as the other SafetyLevel.
// Safety levels are assumed to graduate from LocalUnsafe to LocalSafe to CrossUnsafe to CrossSafe, with Finalized as the strongest.
func (lvl *SafetyLevel) AtLeastAsSafe(min SafetyLevel) bool { func (lvl *SafetyLevel) AtLeastAsSafe(min SafetyLevel) bool {
switch min { relativeSafety := map[SafetyLevel]int{
case Invalid: Invalid: 0,
return true LocalUnsafe: 1,
case CrossUnsafe: LocalSafe: 2,
return *lvl != Invalid CrossUnsafe: 3,
case CrossSafe: CrossSafe: 4,
return *lvl == CrossSafe || *lvl == Finalized Finalized: 5,
case Finalized: }
return *lvl == Finalized // if either level is not recognized, return false
default: _, ok := relativeSafety[*lvl]
if !ok {
return false
}
_, ok = relativeSafety[min]
if !ok {
return false return false
} }
// compare the relative safety levels to determine if the receiver is at least as safe as the other
return relativeSafety[*lvl] >= relativeSafety[min]
} }
const ( const (
......
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