diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index c030b6e8af2..f2409da77ce 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -44,7 +44,7 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly + version: nightly-654c8f01721e43dbc8a53c7a3b022548cb82b2f9 # same as for the nix environment - name: Install dasel run: | diff --git a/.github/workflows/espresso-devnet-tests.yaml b/.github/workflows/espresso-devnet-tests.yaml index 98ce409195c..6705523a652 100644 --- a/.github/workflows/espresso-devnet-tests.yaml +++ b/.github/workflows/espresso-devnet-tests.yaml @@ -51,7 +51,7 @@ jobs: docker compose build # - name: Run Devnet tests - # run: go test -timeout 30m -p 1 -count 1 -v ./espresso/devnet-tests/... + # run: go test -timeout 30m -p 1 -count 1 -v ./espresso/devnet-tests/... - name: Save Nix cache uses: nix-community/cache-nix-action/save@v6 diff --git a/README_ESPRESSO.md b/README_ESPRESSO.md index c3d8bb1d8aa..2ab569ba2a1 100644 --- a/README_ESPRESSO.md +++ b/README_ESPRESSO.md @@ -33,6 +33,12 @@ Provide Docker with the PAT. > echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin ``` +Run docker as a non root user: +```console +> sudo add group docker +> sudo usermod -aG docker $USER +``` + ### Run the tests Run the Espresso smoke tests: diff --git a/espresso/.env b/espresso/.env index 2f7f1164279..e118a8de685 100644 --- a/espresso/.env +++ b/espresso/.env @@ -34,6 +34,9 @@ OPERATOR_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf # cast wallet address --private-key $OPERATOR_PRIVATE_KEY OPERATOR_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +# cast wallet address --mnemonic "test test ... junk" --hd-path "m/44'/60'/0'/0/1" +PROPOSER_ADDRESS=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 + L1_CHAIN_ID=11155111 L2_CHAIN_ID=22266222 diff --git a/espresso/devnet-tests/batcher_restart_test.go b/espresso/devnet-tests/batcher_restart_test.go index aea44b4c0b1..2088f317e88 100644 --- a/espresso/devnet-tests/batcher_restart_test.go +++ b/espresso/devnet-tests/batcher_restart_test.go @@ -13,7 +13,7 @@ func TestBatcherRestart(t *testing.T) { defer cancel() d := NewDevnet(ctx, t) - require.NoError(t, d.Up(testing.Verbose())) + require.NoError(t, d.Up()) defer func() { require.NoError(t, d.Down()) }() diff --git a/espresso/devnet-tests/challenge_test.go b/espresso/devnet-tests/challenge_test.go new file mode 100644 index 00000000000..b4ca7d61516 --- /dev/null +++ b/espresso/devnet-tests/challenge_test.go @@ -0,0 +1,50 @@ +package devnet_tests + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestChallengeGame(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + d := NewDevnet(ctx, t) + require.NoError(t, d.Up()) + defer func() { + require.NoError(t, d.Down()) + }() + + // Wait for the proposer to make a claim. + var games []ChallengeGame + for len(games) == 0 { + var err error + t.Logf("waiting for a challenge game") + time.Sleep(5 * time.Second) + games, err = d.ListChallengeGames() + require.NoError(t, err) + } + t.Logf("game created: %v", games[0]) + require.Equal(t, uint64(1), games[0].Claims) + + // Attack the first claimed state. + t.Logf("attacking game") + require.NoError(t, d.OpChallenger("move", "--attack", "--game-address", games[0].Address.Hex())) + + // Check that the proposer correctly responds. + CLAIMS_NUMBER := uint64(3) // First claim by the proposer + attack + response + for { + updatedGames, err := d.ListChallengeGames() + require.NoError(t, err) + if updatedGames[0].Claims == CLAIMS_NUMBER { + require.Equal(t, updatedGames[0].OutputRoot, games[0].OutputRoot) + break + } + + t.Logf("waiting for a response") + time.Sleep(time.Second) + } +} diff --git a/espresso/devnet-tests/devnet_tools.go b/espresso/devnet-tests/devnet_tools.go index 6e735e0ef65..2368636368f 100644 --- a/espresso/devnet-tests/devnet_tools.go +++ b/espresso/devnet-tests/devnet_tools.go @@ -5,6 +5,7 @@ import ( "context" "encoding/hex" "fmt" + "io" "math/big" "os" "os/exec" @@ -50,9 +51,15 @@ func NewDevnet(ctx context.Context, t *testing.T) *Devnet { d := new(Devnet) d.ctx = ctx - d.secrets = *secrets.DefaultSecrets - var err error + mnemonics := *secrets.DefaultMnemonicConfig + mnemonics.Batcher = "m/44'/60'/0'/0/0" + secrets, err := mnemonics.Secrets() + if err != nil { + panic(fmt.Sprintf("failed to create default secrets: %e", err)) + } + d.secrets = *secrets + if outageTime, ok := os.LookupEnv("ESPRESSO_DEVNET_TESTS_OUTAGE_PERIOD"); ok { d.outageTime, err = time.ParseDuration(outageTime) if err != nil { @@ -73,7 +80,7 @@ func NewDevnet(ctx context.Context, t *testing.T) *Devnet { return d } -func (d *Devnet) Up(verbose bool) (err error) { +func (d *Devnet) Up() (err error) { cmd := exec.CommandContext( d.ctx, "docker", "compose", "up", "-d", @@ -107,7 +114,7 @@ func (d *Devnet) Up(verbose bool) (err error) { } }() - if verbose { + if testing.Verbose() { // Stream logs to stdout while the test runs. This goroutine will automatically exit when // the context is cancelled. go func() { @@ -376,6 +383,161 @@ func (d *Devnet) Down() error { return cmd.Run() } +type TaggedWriter struct { + inner io.Writer + tag string + newline bool +} + +func NewTaggedWriter(tag string, inner io.Writer) *TaggedWriter { + return &TaggedWriter{ + inner: inner, + tag: tag, + newline: true, + } +} + +// Implementation of io.Write interface for TaggedWriter. +// Allows to prepend a tag to each line of output. +// The `p` parameter is the tag to add at the beginning of each line. +func (w *TaggedWriter) Write(p []byte) (int, error) { + if w.newline { + if _, err := fmt.Fprintf(w.inner, "%s | ", w.tag); err != nil { + return 0, err + } + w.newline = false + } + + written := 0 + for i := range len(p) { + // Buffer bytes until we hit a newline. + if p[i] == '\n' { + // Print everything we've buffered up to and including the newline. + line := p[written : i+1] + n, err := w.inner.Write(line) + written += n + if err != nil || n < len(line) { + return written, err + } + + // If that's the end of the output, return, but make a note that the buffer ended with a + // newline and we need to print the tag before the next message. + if written == len(p) { + w.newline = true + return written, nil + } + + // Otherwise print the tag now before proceeding with the next line in `p`. + if _, err := fmt.Fprintf(w.inner, "%s | ", w.tag); err != nil { + return written, err + } + } + } + + // Print anything that was buffered after the final newline. + if written < len(p) { + line := p[written:] + n, err := w.inner.Write(line) + written += n + if err != nil || n < len(line) { + return written, err + } + } + + return written, nil +} + +func (d *Devnet) OpChallenger(opts ...string) error { + return d.opChallengerCmd(opts...).Run() +} + +type ChallengeGame struct { + Index uint64 + Address common.Address + OutputRoot []byte + Claims uint64 +} + +func ParseChallengeGame(s string) (ChallengeGame, error) { + fields := strings.Fields(s) + if len(fields) < 8 { + return ChallengeGame{}, fmt.Errorf("challenge game is missing fields; expected at least 8 but got only %v", len(fields)) + } + + index, err := strconv.ParseUint(fields[0], 10, 64) + if err != nil { + return ChallengeGame{}, fmt.Errorf("index invalid: %w", err) + } + + address := common.HexToAddress(fields[1]) + + outputRoot := common.Hex2Bytes(fields[6]) + + claims, err := strconv.ParseUint(fields[7], 10, 64) + if err != nil { + return ChallengeGame{}, fmt.Errorf("claims count invalid: %w", err) + } + + return ChallengeGame{ + Index: index, + Address: address, + OutputRoot: outputRoot, + Claims: claims, + }, nil +} + +func (d *Devnet) ListChallengeGames() ([]ChallengeGame, error) { + output, err := d.OpChallengerOutput("list-games") + if err != nil { + return nil, err + } + + var games []ChallengeGame + for i, line := range strings.Split(output, "\n") { + if i == 0 { + // Ignore header. + continue + } + line = strings.TrimSpace(line) + if len(line) == 0 { + // Ignore empty lines (e.g. trailing newline) + continue + } + + game, err := ParseChallengeGame(line) + if err != nil { + return nil, fmt.Errorf("game %v is invalid: %w", i, err) + } + games = append(games, game) + } + return games, nil +} + +func (d *Devnet) OpChallengerOutput(opts ...string) (string, error) { + cmd := d.opChallengerCmd(opts...) + buf := new(bytes.Buffer) + cmd.Stdout = buf + if err := cmd.Run(); err != nil { + return "", err + } + return buf.String(), nil +} + +func (d *Devnet) opChallengerCmd(opts ...string) *exec.Cmd { + opts = append([]string{"compose", "exec", "op-challenger", "entrypoint.sh", "op-challenger"}, opts...) + cmd := exec.CommandContext( + d.ctx, + "docker", + opts..., + ) + if testing.Verbose() { + cmd.Stdout = NewTaggedWriter("op-challenger-cmd", os.Stdout) + cmd.Stderr = NewTaggedWriter("op-challenger-cmd", os.Stderr) + } + log.Info("invoking op-challenger", "cmd", cmd) + return cmd +} + // Get the host port mapped to `privatePort` for the given Docker service. func (d *Devnet) hostPort(service string, privatePort uint16) (uint16, error) { buf := new(bytes.Buffer) diff --git a/espresso/devnet-tests/key_rotation_test.go b/espresso/devnet-tests/key_rotation_test.go index a47d1d8cfc0..e9d3084b751 100644 --- a/espresso/devnet-tests/key_rotation_test.go +++ b/espresso/devnet-tests/key_rotation_test.go @@ -19,7 +19,7 @@ func TestRotateBatcherKey(t *testing.T) { // We're going to change batcher key to Bob's, verify that it won't be a no-op require.NotEqual(t, d.secrets.Batcher, d.secrets.Bob) - require.NoError(t, d.Up(testing.Verbose())) + require.NoError(t, d.Up()) defer func() { require.NoError(t, d.Down()) }() @@ -57,7 +57,7 @@ func TestChangeBatchInboxOwner(t *testing.T) { d := NewDevnet(ctx, t) - require.NoError(t, d.Up(testing.Verbose())) + require.NoError(t, d.Up()) defer func() { require.NoError(t, d.Down()) }() diff --git a/espresso/docker-compose.yml b/espresso/docker-compose.yml index 175c44048ff..aae279323ae 100644 --- a/espresso/docker-compose.yml +++ b/espresso/docker-compose.yml @@ -2,6 +2,7 @@ services: l1-genesis: + user: ${U_ID:-1000}:${GID:-1000} restart: on-failure build: context: ../ @@ -80,7 +81,7 @@ services: l1-genesis: condition: service_completed_successfully healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:${L1_HTTP_PORT}"] + test: [ "CMD", "curl", "-f", "http://localhost:${L1_HTTP_PORT}" ] interval: 3s timeout: 2s retries: 40 @@ -121,6 +122,7 @@ services: - ./deployment/deployer:/deployer:ro l2-genesis: + user: "${U_ID:-1000}:${GID:-1000}" restart: on-failure build: context: ../ @@ -172,7 +174,7 @@ services: dockerfile: espresso/docker/op-stack/Dockerfile target: op-node-target healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:${ROLLUP_PORT}"] + test: [ "CMD", "curl", "-f", "http://localhost:${ROLLUP_PORT}" ] interval: 3s timeout: 2s retries: 40 @@ -189,11 +191,13 @@ services: OP_NODE_L1_BEACON: http://l1-beacon:${L1_BEACON_PORT} OP_NODE_L2_ENGINE_RPC: http://op-geth-sequencer:${OP_ENGINE_PORT} OP_NODE_RPC_PORT: ${ROLLUP_PORT} + OP_NODE_SAFEDB_PATH: /data/safedb ports: - "${ROLLUP_PORT}:${ROLLUP_PORT}" volumes: - ./deployment/l2-config:/config:ro - /etc/localtime:/etc/localtime:ro + - op-node-seq:/data command: - op-node - --l2.jwt-secret=/config/jwt.txt @@ -211,7 +215,7 @@ services: dockerfile: espresso/docker/op-stack/Dockerfile target: op-node-target healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:${VERIFIER_PORT}"] + test: [ "CMD", "curl", "-f", "http://localhost:${VERIFIER_PORT}" ] interval: 3s timeout: 2s retries: 40 @@ -248,7 +252,7 @@ services: dockerfile: espresso/docker/op-stack/Dockerfile target: op-node-target healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:${CAFF_PORT}"] + test: [ "CMD", "curl", "-f", "http://localhost:${CAFF_PORT}" ] interval: 3s timeout: 2s retries: 40 @@ -293,7 +297,7 @@ services: restart: "no" op-batcher: - profiles: ["default"] + profiles: [ "default" ] build: context: ../ dockerfile: espresso/docker/op-stack/Dockerfile @@ -322,8 +326,8 @@ services: command: - op-batcher - --espresso-light-client-addr=0x703848f4c85f18e3acd8196c8ec91eb0b7bd0797 - - --testing-espresso-batcher-private-key=${OP_TESTING_BATCHER_PRIVATE_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80} # Default value for testing - - --private-key=${OP_BATCHER_PRIVATE_KEY:-"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"} # Arbitrary value for testing + - --testing-espresso-batcher-private-key=${OP_TESTING_BATCHER_PRIVATE_KEY:-$OPERATOR_PRIVATE_KEY} + - --private-key=${OP_BATCHER_PRIVATE_KEY:-$OPERATOR_PRIVATE_KEY} - --throttle-threshold=0 - --max-channel-duration=2 - --target-num-frames=1 @@ -335,13 +339,7 @@ services: http-proxy: image: alpine:latest command: > - sh -c " - apk add --no-cache tinyproxy && - echo 'Allow 127.0.0.1' >> /etc/tinyproxy/tinyproxy.conf && - echo 'Allow 0.0.0.0/0' >> /etc/tinyproxy/tinyproxy.conf && - echo 'DisableViaHeader Yes' >> /etc/tinyproxy/tinyproxy.conf && - tinyproxy -d - " + sh -c " apk add --no-cache tinyproxy && echo 'Allow 127.0.0.1' >> /etc/tinyproxy/tinyproxy.conf && echo 'Allow 0.0.0.0/0' >> /etc/tinyproxy/tinyproxy.conf && echo 'DisableViaHeader Yes' >> /etc/tinyproxy/tinyproxy.conf && tinyproxy -d " ports: - "3128:8888" networks: @@ -350,18 +348,14 @@ services: - proxy op-batcher-tee: - profiles: ["tee"] + profiles: [ "tee" ] build: context: ../ dockerfile: espresso/docker/op-stack/Dockerfile target: op-batcher-enclave-target image: op-batcher-tee:espresso healthcheck: - test: - [ - "CMD-SHELL", - "test -f /tmp/enclave-tools.pid && kill -0 $(cat /tmp/enclave-tools.pid) 2>/dev/null || exit 1", - ] + test: [ "CMD-SHELL", "test -f /tmp/enclave-tools.pid && kill -0 $(cat /tmp/enclave-tools.pid) 2>/dev/null || exit 1" ] interval: 30s timeout: 10s retries: 3 @@ -409,7 +403,7 @@ services: /source/espresso/docker/op-batcher-tee/run-enclave.sh op-proposer: - profiles: ["default"] + profiles: [ "default" ] build: context: ../ dockerfile: espresso/docker/op-stack/Dockerfile @@ -422,23 +416,48 @@ services: condition: service_started op-batcher: condition: service_started + volumes: + - ../packages/contracts-bedrock/lib/superchain-registry/ops/testdata/monorepo:/config + - ./deployment/deployer:/deployer environment: OP_PROPOSER_L1_ETH_RPC: http://l1-geth:${L1_HTTP_PORT} OP_PROPOSER_ROLLUP_RPC: http://op-node-sequencer:${ROLLUP_PORT} + OP_PROPOSER_PROPOSAL_INTERVAL: 6s + OP_PROPOSER_MNEMONIC: "test test test test test test test test test test test junk" + OP_PROPOSER_HD_PATH: "m/44'/60'/0'/0/1" + OP_PROPOSER_GAME_TYPE: '1' + + op-challenger: + profiles: [ "default" ] + build: + context: ../ + dockerfile: espresso/docker/op-stack/Dockerfile + target: op-challenger-target + image: op-challenger:espresso + depends_on: + l1-geth: + condition: service_started + l1-beacon: + condition: service_started + op-node-sequencer: + condition: service_started + op-geth-sequencer: + condition: service_started volumes: - - ../packages/contracts-bedrock/lib/superchain-registry/ops/testdata/monorepo:/config - - ./deployment/deployer:/deployer - command: - - sh - - -c - - | - GAME_FACTORY=$(jq -r '.opChainDeployments[0].disputeGameFactoryProxyAddress' ./deployer/state.json) - op-proposer \ - --proposal-interval 6s \ - --mnemonic "test test test test test test test test test test test junk" \ - --hd-path "m/44'/60'/0'/0/0" \ - --game-type 1 \ - --game-factory-address $$GAME_FACTORY + - ./deployment/deployer:/deployer:ro + - ./deployment/l2-config:/config:ro + - op-data-challenger:/data + environment: + OP_CHALLENGER_L1_ETH_RPC: http://l1-geth:${L1_HTTP_PORT} + OP_CHALLENGER_L1_BEACON: http://l1-beacon:${L1_BEACON_PORT} + OP_CHALLENGER_ROLLUP_RPC: http://op-node-sequencer:${ROLLUP_PORT} + OP_CHALLENGER_L2_ETH_RPC: http://op-geth-sequencer:${OP_HTTP_PORT} + OP_CHALLENGER_MNEMONIC: "test test test test test test test test test test test junk" + OP_CHALLENGER_HD_PATH: "m/44'/60'/0'/0/1" + OP_CHALLENGER_DATADIR: /data + OP_CHALLENGER_CANNON_ROLLUP_CONFIG: /config/rollup.json + OP_CHALLENGER_CANNON_L2_GENESIS: /config/genesis.json + OP_CHALLENGER_TRACE_TYPE: permissioned espresso-dev-node: image: ghcr.io/espressosystems/espresso-sequencer/espresso-dev-node:release-colorful-snake @@ -468,4 +487,6 @@ volumes: op-data-seq: op-data-verifier: op-data-caff-node: + op-data-challenger: + op-node-seq: espresso-data: diff --git a/espresso/docker/op-stack/Dockerfile b/espresso/docker/op-stack/Dockerfile index d7ccca045c5..e6f8176f6c5 100644 --- a/espresso/docker/op-stack/Dockerfile +++ b/espresso/docker/op-stack/Dockerfile @@ -64,7 +64,6 @@ FROM alpine:3.22 AS op-cgo-builder RUN apk add musl-dev gcc go g++ curl tar gzip make gcc linux-headers git jq bash yq # Install just from mise COPY ./mise.toml . -RUN uname -m RUN case $(uname -m) in \ "arm64"|"aarch64") JUST_ARCH="aarch64" ;; \ *) JUST_ARCH="x86_64" ;; \ @@ -108,6 +107,10 @@ FROM builder AS op-proposer-builder ARG OP_PROPOSER_VERSION=v0.0.0 RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build cd op-proposer && make op-proposer \ GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROPOSER_VERSION" +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build cd op-challenger && make op-challenger \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROPOSER_VERSION" +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build make cannon-prestate \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROPOSER_VERSION" FROM golang:1.24-alpine AS deployment-utils-builder ENV GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE @@ -159,10 +162,31 @@ CMD ["enclave-tools"] FROM $TARGET_BASE_IMAGE AS op-proposer-target RUN apk add jq +COPY espresso/docker/op-stack/entrypoint.sh /bin/entrypoint.sh +RUN chmod +x /bin/entrypoint.sh COPY --from=op-proposer-builder /app/op-proposer/bin/op-proposer /usr/local/bin/ COPY --from=op-proposer-builder /app/espresso/deployment/deployer /deployer +ENV ENV_PREFIX OP_PROPOSER +ENTRYPOINT [ "/bin/entrypoint.sh" ] CMD ["op-proposer"] +FROM $TARGET_BASE_IMAGE AS op-challenger-target +RUN apk add jq +COPY espresso/docker/op-stack/entrypoint.sh /bin/entrypoint.sh +RUN chmod +x /bin/entrypoint.sh +COPY --from=op-proposer-builder /app/op-challenger/bin/op-challenger /usr/local/bin +COPY --from=op-proposer-builder /app/cannon/bin/cannon /usr/local/bin +COPY --from=op-proposer-builder /app/op-program/bin/op-program /usr/local/bin +COPY --from=op-proposer-builder /app/op-program/bin/prestate-proof.json /app/prestate-proof.json + +ENV OP_CHALLENGER_CANNON_BIN /usr/local/bin/cannon +ENV OP_CHALLENGER_CANNON_SERVER /usr/local/bin/op-program +ENV OP_CHALLENGER_CANNON_PRESTATE /app/prestate-proof.json +ENV ENV_PREFIX OP_CHALLENGER + +ENTRYPOINT [ "/bin/entrypoint.sh" ] +CMD ["op-challenger"] + FROM $TARGET_BASE_IMAGE AS op-deployer-target RUN apk add jq curl bash openssl COPY --from=deployment-utils-builder /go/bin/dasel /usr/local/bin/ diff --git a/espresso/docker/op-stack/entrypoint.sh b/espresso/docker/op-stack/entrypoint.sh new file mode 100644 index 00000000000..e1133afd354 --- /dev/null +++ b/espresso/docker/op-stack/entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +export "${ENV_PREFIX}_GAME_FACTORY_ADDRESS"=$(jq -r '.opChainDeployments[0].disputeGameFactoryProxyAddress' ./deployer/state.json) + +"$@" diff --git a/espresso/scripts/prepare-allocs.sh b/espresso/scripts/prepare-allocs.sh index b50700f17e1..053050b5934 100755 --- a/espresso/scripts/prepare-allocs.sh +++ b/espresso/scripts/prepare-allocs.sh @@ -81,7 +81,7 @@ dasel put -f "${DEPLOYER_DIR}/intent.toml" -s .chains.[0].sequencerFeeVaultRecip dasel put -f "${DEPLOYER_DIR}/intent.toml" -s .chains.[0].roles.systemConfigOwner -v "${OPERATOR_ADDRESS}" dasel put -f "${DEPLOYER_DIR}/intent.toml" -s .chains.[0].roles.unsafeBlockSigner -v "${OPERATOR_ADDRESS}" dasel put -f "${DEPLOYER_DIR}/intent.toml" -s .chains.[0].roles.batcher -v "${OPERATOR_ADDRESS}" -dasel put -f "${DEPLOYER_DIR}/intent.toml" -s .chains.[0].roles.proposer -v "${OPERATOR_ADDRESS}" +dasel put -f "${DEPLOYER_DIR}/intent.toml" -s .chains.[0].roles.proposer -v "${PROPOSER_ADDRESS}" # Fill in a specified create2Salt for the deployer, in order to ensure that the # contract addresses are deterministic. diff --git a/justfile b/justfile index 27478639e7f..4dbc314393e 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,7 @@ +# Variable +gid := `id -g` +uid := `id -u` + # Run the tests tests: ./run_all_tests.sh @@ -6,11 +10,12 @@ fast-tests: ./run_fast_tests.sh devnet-tests: build-devnet - go test -timeout 30m -p 1 -count 1 -v ./espresso/devnet-tests/... + U_ID={{uid}} GID={{gid}} go test -timeout 30m -p 1 -count 1 -skip 'TestRotateBatcherKey|TestChangeBatchInboxOwner' -v ./espresso/devnet-tests/... build-devnet: compile-contracts + rm -Rf espresso/deployment (cd op-deployer && just) - (cd espresso && ./scripts/prepare-allocs.sh && docker compose build) + (cd espresso && U_ID={{uid}} GID={{gid}} ./scripts/prepare-allocs.sh && docker compose build) golint: golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 5m -e "errors.As" -e "errors.Is" ./... @@ -62,6 +67,9 @@ smoke-tests: compile-contracts nuke: make nuke +# Stop the containers +stop-containers: + (cd espresso && U_ID={{uid}} GID={{gid}} docker compose down -v) # Checks that TODO comments have corresponding issues. todo-checker: diff --git a/op-batcher/batcher/espresso.go b/op-batcher/batcher/espresso.go index d7c8e70962e..d4e0b3426ad 100644 --- a/op-batcher/batcher/espresso.go +++ b/op-batcher/batcher/espresso.go @@ -933,10 +933,6 @@ func (l *BlockLoader) nextBlockRange(newSyncStatus *eth.SyncStatus) (inclusiveBl return inclusiveBlockRange{}, ActionReset } - if newSyncStatus.UnsafeL2.Number <= lastQueuedBlock.Number+1 { - return inclusiveBlockRange{}, ActionRetry - } - if safeL2.Number > firstQueuedBlock.Number { numFinalizedBlocks := safeL2.Number - firstQueuedBlock.Number l.batcher.Log.Warn(