Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions devnet-sdk/descriptors/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package descriptors

import (
"encoding/json"
"fmt"
"net/http"

"github.com/ethereum-optimism/optimism/devnet-sdk/types"
Expand All @@ -10,13 +11,22 @@ import (

type PortInfo struct {
Host string `json:"host"`
Path string `json:"path,omitempty"`
Scheme string `json:"scheme,omitempty"`
Port int `json:"port,omitempty"`
PrivatePort int `json:"private_port,omitempty"`

ReverseProxyHeader http.Header `json:"reverse_proxy_header,omitempty"`
}

func AppendPath(baseURL, path string) string {
url := baseURL
if path != "" {
url += fmt.Sprintf("/%s", path)
}
return url
}

// EndpointMap is a map of service names to their endpoints.
type EndpointMap map[string]*PortInfo

Expand Down
14 changes: 14 additions & 0 deletions op-acceptance-tests/tests/interop/message/init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package msg

import (
"testing"

"github.com/ethereum-optimism/optimism/op-devstack/presets"
)

var SimpleInterop presets.TestSetup[*presets.SimpleInterop]

func TestMain(m *testing.M) {
SimpleInterop = presets.NewSimpleInterop
presets.DoMain(m, presets.ConfigureSimpleInterop())
}
27 changes: 27 additions & 0 deletions op-acceptance-tests/tests/interop/message/interop_msg_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package msg

import (
"math/rand"
"testing"

"github.com/ethereum-optimism/optimism/op-acceptance-tests/tests/interop"
"github.com/ethereum-optimism/optimism/op-devstack/devtest"
"github.com/ethereum-optimism/optimism/op-service/eth"
)

// TestInitExecMsg tests basic interop messaging
func TestInitExecMsg(gt *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! I added a todo for me to merge this with TestInteropHappyTx from #15662 as they are almost equivalent in tests/checks, with this one being a lot more readable / succinct.

t := devtest.SerialT(gt)
sys := SimpleInterop(t)
rng := rand.New(rand.NewSource(1234))
alice := sys.FunderA.NewFundedEOA(eth.ThousandEther)
bob := sys.FunderB.NewFundedEOA(eth.ThousandEther)

eventLoggerAddress := alice.DeployEventLogger()
// Trigger random init message at chain A
initIntent, _ := alice.SendInitMessage(interop.RandomInitTrigger(rng, eventLoggerAddress, rng.Intn(5), rng.Intn(30)))
// Make sure supervisor indexs block which includes init message
sys.Supervisor.AdvanceUnsafeHead(alice.ChainID(), 2)
// Single event in tx so index is 0
bob.SendExecMessage(initIntent, 0)
}
34 changes: 34 additions & 0 deletions op-devstack/dsl/eoa.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"

"github.com/ethereum-optimism/optimism/devnet-sdk/contracts/bindings"
"github.com/ethereum-optimism/optimism/devnet-sdk/contracts/constants"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/retry"
"github.com/ethereum-optimism/optimism/op-service/txintent"
"github.com/ethereum-optimism/optimism/op-service/txplan"
)

Expand Down Expand Up @@ -115,3 +119,33 @@ func (u *EOA) VerifyBalanceExact(v eth.ETH) {
actual := u.balance()
u.t.Require().Equal(v, actual, "must have expected balance")
}

func (u *EOA) DeployEventLogger() common.Address {
tx := txplan.NewPlannedTx(u.Plan(), txplan.WithData(common.FromHex(bindings.EventloggerBin)))
res, err := tx.Included.Eval(u.ctx)
u.t.Require().NoError(err, "failed to deploy EventLogger")
eventLoggerAddress := res.ContractAddress
u.log.Info("deployed EventLogger", "chainID", tx.ChainID.Value(), "address", eventLoggerAddress)
return eventLoggerAddress
}

func (u *EOA) SendInitMessage(trigger *txintent.InitTrigger) (*txintent.IntentTx[*txintent.InitTrigger, *txintent.InteropOutput], *types.Receipt) {
tx := txintent.NewIntent[*txintent.InitTrigger, *txintent.InteropOutput](u.Plan())
tx.Content.Set(trigger)
receipt, err := tx.PlannedTx.Included.Eval(u.ctx)
u.t.Require().NoError(err, "init msg receipt not found")
u.log.Info("init message included", "chain", u.ChainID(), "block", receipt.BlockNumber)
return tx, receipt
}

func (u *EOA) SendExecMessage(initIntent *txintent.IntentTx[*txintent.InitTrigger, *txintent.InteropOutput], eventIdx int) (*txintent.IntentTx[*txintent.ExecTrigger, *txintent.InteropOutput], *types.Receipt) {
tx := txintent.NewIntent[*txintent.ExecTrigger, *txintent.InteropOutput](u.Plan())
tx.Content.DependOn(&initIntent.Result)
tx.Content.Fn(txintent.ExecuteIndexed(constants.CrossL2Inbox, &initIntent.Result, eventIdx))
receipt, err := tx.PlannedTx.Included.Eval(u.ctx)
u.t.Require().NoError(err, "exec msg receipt not found")
u.log.Info("exec message included", "chain", u.ChainID(), "block", receipt.BlockNumber)
// Check single ExecutingMessage triggered
u.t.Require().Equal(1, len(receipt.Logs))
return tx, receipt
}
21 changes: 21 additions & 0 deletions op-devstack/dsl/supervisor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dsl
import (
"context"
"errors"
"fmt"
"time"

"github.com/ethereum-optimism/optimism/op-devstack/stack"
Expand Down Expand Up @@ -100,3 +101,23 @@ func (s *Supervisor) SafeBlockID(chainID eth.ChainID) eth.BlockID {

return syncStatus.Chains[chainID].CrossSafe
}

func (s *Supervisor) AdvanceUnsafeHead(chainID eth.ChainID, block uint64) {
initial := s.FetchSyncStatus()
chInitial, ok := initial.Chains[chainID]
s.require.True(ok, fmt.Sprintf("chain sync status not found: chain id: %d", chainID))
required := chInitial.LocalUnsafe.Number + block
attempts := int(block + 3) // intentionally allow few more attempts for avoid flaking
err := retry.Do0(s.ctx, attempts, &retry.FixedStrategy{Dur: 2 * time.Second},
func() error {
chStatus := s.FetchSyncStatus().Chains[chainID]
s.log.Info("Supervisor view of unsafe head", "chain", chainID, "unsafe", chStatus.LocalUnsafe)
if chStatus.LocalUnsafe.Number < required {
s.log.Info("Unsafe head sync status not ready",
"chain", chainID, "initialUnsafe", chInitial.LocalUnsafe, "currentUnsafe", chStatus.LocalUnsafe, "minRequired", required)
return fmt.Errorf("expected head to advance")
}
return nil
})
s.require.NoError(err)
}
5 changes: 3 additions & 2 deletions op-devstack/sysext/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,15 @@ func (orch *Orchestrator) findProtocolService(service *descriptors.Service, prot
for proto, endpoint := range service.Endpoints {
if proto == protocol {
if orch.env.Env.ReverseProxyURL != "" && !orch.useDirectCnx {
return orch.env.Env.ReverseProxyURL, endpoint.ReverseProxyHeader, nil
return descriptors.AppendPath(orch.env.Env.ReverseProxyURL, endpoint.Path), endpoint.ReverseProxyHeader, nil
}

port := endpoint.Port
if orch.usePrivatePorts {
port = endpoint.PrivatePort
}
return fmt.Sprintf("http://%s:%d", endpoint.Host, port), nil, nil
url := descriptors.AppendPath(fmt.Sprintf("http://%s:%d", endpoint.Host, port), endpoint.Path)
return url, nil, nil
}
}
return "", nil, fmt.Errorf("protocol %s not found", protocol)
Expand Down
5 changes: 5 additions & 0 deletions op-devstack/sysext/l1.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package sysext

import (
"fmt"

"github.com/ethereum-optimism/optimism/op-devstack/shim"
"github.com/ethereum-optimism/optimism/op-devstack/stack"
"github.com/ethereum-optimism/optimism/op-service/eth"
Expand Down Expand Up @@ -52,6 +54,9 @@ func (o *Orchestrator) hydrateL1(system stack.ExtensibleSystem) {
}

if faucet, ok := env.Env.L1.Services["faucet"]; ok {
for _, endpoint := range faucet.Endpoints {
endpoint.Path = fmt.Sprintf("chain/%s", l1.ChainID().String())
}
l1.AddFaucet(shim.NewFaucet(shim.FaucetConfig{
CommonConfig: commonConfig,
Client: o.rpcClient(t, faucet, RPCProtocol),
Expand Down
4 changes: 4 additions & 0 deletions op-devstack/sysext/l2.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package sysext

import (
"fmt"
"strings"

"github.com/ethereum-optimism/optimism/devnet-sdk/descriptors"
Expand Down Expand Up @@ -57,6 +58,9 @@ func (o *Orchestrator) hydrateL2(net *descriptors.L2Chain, system stack.Extensib
o.hydrateL2ProxydMaybe(net, l2)

if faucet, ok := net.Services["faucet"]; ok {
for _, endpoint := range faucet.Endpoints {
endpoint.Path = fmt.Sprintf("chain/%s", l2.ChainID().String())
}
l2.AddFaucet(shim.NewFaucet(shim.FaucetConfig{
CommonConfig: commonConfig,
Client: o.rpcClient(t, faucet, RPCProtocol),
Expand Down