Commit db10999f authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

Add integration test for apply (#11910)

* Add integration test for apply

Adds an integration test for OP Deployer's `apply` method. This test uses Kurtosis to spin up an in-memory L1, deploy the contracts using OP Deployer, then asserts that there is code at all reported addresses.

* Review updates
parent 4af1fe6e
......@@ -849,6 +849,64 @@ jobs:
paths:
- "/root/.cache/golangci-lint"
go-test-kurtosis:
parameters:
module:
description: Go Module Name
type: string
uses_artifacts:
description: Uses contract artifacts
type: boolean
default: false
test_directory:
description: Test directory
type: string
default: "./..."
machine:
image: <<pipeline.parameters.base_image>> # only used to enable codecov.
resource_class: xlarge
steps:
- run:
name: Install components
command: |
go version
go install gotest.tools/gotestsum@v1.11.0
- run:
name: Install Kurtosis
command: |
echo "deb [trusted=yes] https://apt.fury.io/kurtosis-tech/ /" | sudo tee /etc/apt/sources.list.d/kurtosis.list
sudo apt update
sudo apt install kurtosis-cli
kurtosis engine start
- checkout
- when:
condition: <<parameters.uses_artifacts>>
steps:
- attach_workspace: { at: "." }
- run:
name: prep results dir
command: |
# Make sure the workspace is properly owned
sudo chown -R $USER:$USER .
mkdir -p /tmp/test-results
mkdir -p /tmp/testlogs
- run:
name: run tests
command: |
ENABLE_KURTOSIS=true gotestsum \
--format=testname \
--junitfile=/tmp/test-results/<<parameters.module>>.xml \
--jsonfile=/tmp/testlogs/log.json \
-- -parallel=8 \
-coverpkg=github.com/ethereum-optimism/optimism/... \
-coverprofile=coverage.out <<parameters.test_directory>>
working_directory: <<parameters.module>>
- store_test_results:
path: /tmp/test-results
- store_artifacts:
path: /tmp/testlogs
when: always
go-test:
parameters:
module:
......@@ -881,10 +939,6 @@ jobs:
key: golang-build-cache-test-<<parameters.module>>-{{ checksum "go.sum" }}
paths:
- "/root/.cache/go-build"
# TODO(CLI-148): Fix codecov
#- run:
#name: upload coverage
#command: codecov --verbose --clean --flags bedrock-go-tests
- store_test_results:
path: /tmp/test-results
- store_artifacts:
......@@ -1011,53 +1065,6 @@ jobs:
- notify-failures-on-develop:
mentions: "<<parameters.mentions>>"
go-lint-test-build:
parameters:
binary_name:
description: Binary name to build
type: string
working_directory:
description: Working directory
type: string
build:
description: Whether or not to build the binary
type: boolean
default: true
dependencies:
description: Regex matching dependent packages
type: string
default: this-package-does-not-exist
docker:
- image: <<pipeline.parameters.ci_builder_image>>
resource_class: medium
steps:
- checkout
- check-changed:
patterns: <<parameters.working_directory>>,<<parameters.dependencies>>
- run:
name: Lint
command: make lint
working_directory: <<parameters.working_directory>>
- run:
name: Test
command: |
mkdir -p /test-results
gotestsum --format=testname --junitfile /test-results/tests.xml --jsonfile /test-results/log.json -- -parallel=2
working_directory: <<parameters.working_directory>>
- store_test_results:
path: /test-results
- store_artifacts:
path: /testlogs
when: always
- when:
condition:
equal: [ true, <<parameters.build>> ]
steps:
- run:
name: Build
command: make <<parameters.binary_name>>
working_directory: <<parameters.working_directory>>
cannon-prestate:
docker:
- image: <<pipeline.parameters.ci_builder_image>>
......@@ -1664,7 +1671,12 @@ workflows:
- go-test:
name: op-chain-ops-tests
module: op-chain-ops
requires: ["go-mod-download"]
- go-test-kurtosis:
name: op-chain-ops-integration
module: op-chain-ops
test_directory: ./deployer/integration_test
uses_artifacts: true
requires: ["contracts-bedrock-build"]
- go-test:
name: op-node-tests
module: op-node
......@@ -1740,6 +1752,7 @@ workflows:
- go-mod-download
- op-batcher-tests
- op-chain-ops-tests
- op-chain-ops-integration
- op-node-tests
- op-proposer-tests
- op-challenger-tests
......
......@@ -26,6 +26,7 @@ require (
github.com/ipfs/go-datastore v0.6.0
github.com/ipfs/go-ds-leveldb v0.5.0
github.com/klauspost/compress v1.17.9
github.com/kurtosis-tech/kurtosis/api/golang v1.2.0
github.com/libp2p/go-libp2p v0.36.2
github.com/libp2p/go-libp2p-mplex v0.9.0
github.com/libp2p/go-libp2p-pubsub v0.12.0
......@@ -53,8 +54,10 @@ require (
require (
github.com/DataDog/zstd v1.5.6-0.20230824185856-869dae002e5e // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect
github.com/adrg/xdg v0.4.0 // indirect
github.com/allegro/bigcache v1.2.1 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
......@@ -85,6 +88,7 @@ require (
github.com/docker/go-units v0.5.0 // indirect
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0 // indirect
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/elastic/gosigar v0.14.3 // indirect
github.com/ethereum/c-kzg-4844 v1.0.0 // indirect
......@@ -96,15 +100,18 @@ require (
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
github.com/getsentry/sentry-go v0.27.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-yaml/yaml v2.1.0+incompatible // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/google/uuid v1.6.0 // indirect
......@@ -136,6 +143,11 @@ require (
github.com/koron/go-ssdp v0.0.4 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kurtosis-tech/kurtosis-portal/api/golang v0.0.0-20230818182330-1a86869414d2 // indirect
github.com/kurtosis-tech/kurtosis/contexts-config-store v0.0.0-20230818184218-f4e3e773463b // indirect
github.com/kurtosis-tech/kurtosis/grpc-file-transfer/golang v0.0.0-20230803130419-099ee7a4e3dc // indirect
github.com/kurtosis-tech/kurtosis/path-compression v0.0.0-20240307154559-64d2929cd265 // indirect
github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
......@@ -148,6 +160,7 @@ require (
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mholt/archiver v3.1.1+incompatible // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
......@@ -166,11 +179,13 @@ require (
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/onsi/ginkgo/v2 v2.20.0 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pion/datachannel v1.5.8 // indirect
github.com/pion/dtls/v2 v2.2.12 // indirect
github.com/pion/ice/v2 v2.3.34 // indirect
......@@ -199,11 +214,12 @@ require (
github.com/quic-go/webtransport-go v0.8.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/cors v1.11.0 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/status-im/keycard-go v0.2.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
......@@ -212,7 +228,9 @@ require (
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/wlynxg/anet v0.0.4 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.etcd.io/bbolt v1.3.5 // indirect
......@@ -227,6 +245,10 @@ require (
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/tools v0.24.0 // indirect
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/grpc v1.57.1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
......
This diff is collapsed.
......@@ -6,6 +6,8 @@ import (
"fmt"
"strings"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/state"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/pipeline"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum-optimism/optimism/op-service/ctxinterrupt"
......@@ -92,7 +94,6 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
env := &pipeline.Env{
Workdir: cfg.Workdir,
L1RPCUrl: cfg.L1RPCUrl,
L1Client: l1Client,
Logger: cfg.Logger,
Signer: signer,
......@@ -113,6 +114,24 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
return err
}
if err := ApplyPipeline(ctx, env, intent, st); err != nil {
return err
}
st.AppliedIntent = intent
if err := env.WriteState(st); err != nil {
return err
}
return nil
}
func ApplyPipeline(
ctx context.Context,
env *pipeline.Env,
intent *state.Intent,
st *state.State,
) error {
pline := []struct {
name string
stage pipeline.Stage
......@@ -125,11 +144,5 @@ func Apply(ctx context.Context, cfg ApplyConfig) error {
return fmt.Errorf("error in pipeline stage: %w", err)
}
}
st.AppliedIntent = intent
if err := env.WriteState(st); err != nil {
return err
}
return nil
}
......@@ -30,11 +30,12 @@ type KeyedBroadcaster struct {
}
type KeyedBroadcasterOpts struct {
Logger log.Logger
ChainID *big.Int
Client *ethclient.Client
Signer opcrypto.SignerFn
From common.Address
Logger log.Logger
ChainID *big.Int
Client *ethclient.Client
Signer opcrypto.SignerFn
From common.Address
TXManagerLogger log.Logger
}
func NewKeyedBroadcaster(cfg KeyedBroadcasterOpts) (*KeyedBroadcaster, error) {
......@@ -66,9 +67,14 @@ func NewKeyedBroadcaster(cfg KeyedBroadcasterOpts) (*KeyedBroadcaster, error) {
mgrCfg.MinTipCap.Store(minTipCap)
mgrCfg.MinTipCap.Store(minBaseFee)
txmLogger := log.NewLogger(log.DiscardHandler())
if cfg.TXManagerLogger != nil {
txmLogger = cfg.TXManagerLogger
}
mgr, err := txmgr.NewSimpleTxManagerFromConfig(
"transactor",
log.NewLogger(log.DiscardHandler()),
txmLogger,
&metrics.NoopTxMetrics{},
mgrCfg,
)
......
package integration_test
import (
"context"
"fmt"
"log/slog"
"math/big"
"net/url"
"path"
"runtime"
"testing"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/pipeline"
"github.com/ethereum-optimism/optimism/op-chain-ops/deployer/state"
"github.com/ethereum-optimism/optimism/op-chain-ops/devkeys"
opcrypto "github.com/ethereum-optimism/optimism/op-service/crypto"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum-optimism/optimism/op-service/testutils/kurtosisutil"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/stretchr/testify/require"
)
const TestParams = `
participants:
- el_type: geth
cl_type: lighthouse
network_params:
prefunded_accounts: '{ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": { "balance": "1000000ETH" } }'
network_id: "77799777"
seconds_per_slot: 3
`
type deployerKey struct{}
func (d *deployerKey) HDPath() string {
return "m/44'/60'/0'/0/0"
}
func (d *deployerKey) String() string {
return "deployer-key"
}
func TestEndToEndApply(t *testing.T) {
kurtosisutil.Test(t)
lgr := testlog.Logger(t, slog.LevelInfo)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
_, testFilename, _, ok := runtime.Caller(0)
require.Truef(t, ok, "failed to get test filename")
monorepoDir := path.Join(path.Dir(testFilename), "..", "..", "..")
artifactsDir := path.Join(monorepoDir, "packages", "contracts-bedrock", "forge-artifacts")
enclaveCtx := kurtosisutil.StartEnclave(t, ctx, lgr, "github.com/ethpandaops/ethereum-package", TestParams)
service, err := enclaveCtx.GetServiceContext("el-1-geth-lighthouse")
require.NoError(t, err)
ip := service.GetMaybePublicIPAddress()
ports := service.GetPublicPorts()
rpcURL := fmt.Sprintf("http://%s:%d", ip, ports["rpc"].GetNumber())
l1Client, err := ethclient.Dial(rpcURL)
require.NoError(t, err)
artifactsURL, err := url.Parse(fmt.Sprintf("file://%s", artifactsDir))
require.NoError(t, err)
depKey := new(deployerKey)
l1ChainID := big.NewInt(77799777)
dk, err := devkeys.NewMnemonicDevKeys(devkeys.TestMnemonic)
require.NoError(t, err)
pk, err := dk.Secret(depKey)
require.NoError(t, err)
signer := opcrypto.SignerFnFromBind(opcrypto.PrivateKeySignerFn(pk, l1ChainID))
addrFor := func(key devkeys.Key) common.Address {
addr, err := dk.Address(key)
require.NoError(t, err)
return addr
}
env := &pipeline.Env{
Workdir: t.TempDir(),
L1Client: l1Client,
Signer: signer,
Deployer: addrFor(depKey),
Logger: lgr,
}
intent := &state.Intent{
L1ChainID: l1ChainID.Uint64(),
SuperchainRoles: state.SuperchainRoles{
ProxyAdminOwner: addrFor(devkeys.L1ProxyAdminOwnerRole.Key(l1ChainID)),
ProtocolVersionsOwner: addrFor(devkeys.SuperchainDeployerKey.Key(l1ChainID)),
Guardian: addrFor(devkeys.SuperchainConfigGuardianKey.Key(l1ChainID)),
},
UseFaultProofs: true,
FundDevAccounts: true,
ContractArtifactsURL: (*state.ArtifactsURL)(artifactsURL),
}
st := &state.State{
Version: 1,
}
require.NoError(t, deployer.ApplyPipeline(
ctx,
env,
intent,
st,
))
addrs := []common.Address{
st.SuperchainDeployment.ProxyAdminAddress,
st.SuperchainDeployment.SuperchainConfigProxyAddress,
st.SuperchainDeployment.SuperchainConfigImplAddress,
st.SuperchainDeployment.ProtocolVersionsProxyAddress,
st.SuperchainDeployment.ProtocolVersionsImplAddress,
}
for _, addr := range addrs {
code, err := l1Client.CodeAt(ctx, addr, nil)
require.NoError(t, err)
require.NotEmpty(t, code)
}
}
......@@ -16,7 +16,6 @@ import (
type Env struct {
Workdir string
L1Client *ethclient.Client
L1RPCUrl string
Signer opcrypto.SignerFn
Deployer common.Address
Logger log.Logger
......
package kurtosisutil
import (
"os"
"testing"
)
func Test(t *testing.T) {
if os.Getenv("ENABLE_KURTOSIS") == "" {
t.Skip("skipping Kurtosis test")
}
}
package kurtosisutil
import (
"context"
"fmt"
"testing"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/kurtosis-tech/kurtosis/api/golang/core/lib/enclaves"
"github.com/kurtosis-tech/kurtosis/api/golang/core/lib/starlark_run_config"
"github.com/kurtosis-tech/kurtosis/api/golang/engine/lib/kurtosis_context"
"github.com/stretchr/testify/require"
)
func StartEnclave(t *testing.T, ctx context.Context, lgr log.Logger, pkg string, params string) *enclaves.EnclaveContext {
kurtosisCtx, err := kurtosis_context.NewKurtosisContextFromLocalEngine()
require.NoError(t, err)
enclaveID := fmt.Sprintf("kurtosis-%s", t.Name())
enclaveCtx, err := kurtosisCtx.CreateEnclave(ctx, enclaveID)
require.NoError(t, err)
t.Cleanup(func() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err = kurtosisCtx.DestroyEnclave(ctx, enclaveID)
if err != nil {
lgr.Error("Error destroying enclave", "err", err)
}
})
stream, _, err := enclaveCtx.RunStarlarkRemotePackage(
ctx,
pkg,
&starlark_run_config.StarlarkRunConfig{
SerializedParams: params,
},
)
require.NoError(t, err)
logKurtosisOutput := func(msg string) {
lgr.Info(fmt.Sprintf("[KURTOSIS] %s", msg))
}
for responseLine := range stream {
if responseLine.GetProgressInfo() != nil {
stepInfo := responseLine.GetProgressInfo().CurrentStepInfo
logKurtosisOutput(stepInfo[len(stepInfo)-1])
} else if responseLine.GetInstruction() != nil {
logKurtosisOutput(responseLine.GetInstruction().Description)
} else if responseLine.GetError() != nil {
if responseLine.GetError().GetInterpretationError() != nil {
t.Fatalf("interpretation error: %s", responseLine.GetError().GetInterpretationError().String())
} else if responseLine.GetError().GetValidationError() != nil {
t.Fatalf("validation error: %s", responseLine.GetError().GetValidationError().String())
} else if responseLine.GetError().GetExecutionError() != nil {
t.Fatalf("execution error: %s", responseLine.GetError().GetExecutionError().String())
}
}
}
return enclaveCtx
}
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