diff --git a/Makefile b/Makefile index e93167a4de79..99557e84a0b0 100644 --- a/Makefile +++ b/Makefile @@ -90,6 +90,10 @@ cannon: make -C ./cannon cannon .PHONY: cannon +reproducible-prestate: + make -C ./op-program reproducible-prestate +.PHONY: reproducible-prestate + cannon-prestate: op-program cannon ./cannon/bin/cannon load-elf --path op-program/bin/op-program-client.elf --out op-program/bin/prestate.json --meta op-program/bin/meta.json ./cannon/bin/cannon run --proof-at '=0' --stop-at '=1' --input op-program/bin/prestate.json --meta op-program/bin/meta.json --proof-fmt 'op-program/bin/%d.json' --output "" diff --git a/op-program/Dockerfile.repro b/op-program/Dockerfile.repro new file mode 100644 index 000000000000..7d9dfc807240 --- /dev/null +++ b/op-program/Dockerfile.repro @@ -0,0 +1,51 @@ +FROM golang:1.21.3-alpine3.18 as builder + +RUN apk add --no-cache make gcc musl-dev linux-headers git jq bash + +COPY ./go.mod /app/go.mod +COPY ./go.sum /app/go.sum + +WORKDIR /app + +RUN echo "go mod cache: $(go env GOMODCACHE)" +RUN echo "go build cache: $(go env GOCACHE)" + +RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/go-build go mod download + +COPY . /app + +# We avoid copying the full .git dir into the build for just some metadata. +# Instead, specify: +# --build-arg GIT_COMMIT=$(git rev-parse HEAD) +# --build-arg GIT_DATE=$(git show -s --format='%ct') +ARG GIT_COMMIT +ARG GIT_DATE + +ARG CANNON_VERSION=v0.0.0 +ARG OP_PROGRAM_VERSION=v0.0.0 + +ARG TARGETOS TARGETARCH + +# Build the cannon, op-program, and op-program-client.elf binaries. +RUN --mount=type=cache,target=/root/.cache/go-build cd cannon && make cannon \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$CANNON_VERSION" +RUN --mount=type=cache,target=/root/.cache/go-build cd op-program && make op-program-host \ + GOOS=$TARGETOS GOARCH=$TARGETARCH GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROGRAM_VERSION" +RUN --mount=type=cache,target=/root/.cache/go-build cd op-program && make op-program-client-mips \ + GOOS=linux GOARCH=mips GOMIPS=softfloat GITCOMMIT=$GIT_COMMIT GITDATE=$GIT_DATE VERSION="$OP_PROGRAM_VERSION" + +# Run the op-program-client.elf binary directly through cannon's load-elf subcommand. +RUN /app/cannon/bin/cannon load-elf --path /app/op-program/bin/op-program-client.elf --out /app/op-program/bin/prestate.json --meta "" + +# Generate the prestate proof containing the absolute pre-state hash. +RUN /app/cannon/bin/cannon run --proof-at '=0' --stop-at '=1' --input /app/op-program/bin/prestate.json --meta "" --proof-fmt '/app/op-program/bin/%d.json' --output "" +RUN mv /app/op-program/bin/0.json /app/op-program/bin/prestate-proof.json + +# Exports files to the specified output location. +# Writing files to host requires buildkit to be enabled. +# e.g. `BUILDKIT=1 docker build ...` +FROM scratch AS export-stage +COPY --from=builder /app/op-program/bin/op-program . +COPY --from=builder /app/op-program/bin/op-program-client.elf . +COPY --from=builder /app/op-program/bin/prestate.json . +COPY --from=builder /app/op-program/bin/prestate-proof.json . diff --git a/op-program/Makefile b/op-program/Makefile index a085f4b0eae5..bda07489a8d7 100644 --- a/op-program/Makefile +++ b/op-program/Makefile @@ -26,6 +26,12 @@ op-program-client-mips: # verify output with: readelf -h bin/op-program-client.elf # result is mips32, big endian, R3000 +reproducible-prestate: + @docker build --output ./bin/ --progress plain -f Dockerfile.repro ../ + @echo "Absolute prestate hash:" + @cat ./bin/prestate-proof.json | jq -r .pre +.PHONY: reproducible-prestate + clean: rm -rf bin "$(COMPAT_DIR)" diff --git a/op-program/README.md b/op-program/README.md index a9641ed697ff..78c121457974 100644 --- a/op-program/README.md +++ b/op-program/README.md @@ -32,3 +32,23 @@ From within the `op-program` directory, options can be reviewed with: ```shell ./bin/op-program --help ``` + +## Generating the Absolute Prestate + +The absolute pre-state of the op-program can be generated by executing the makefile +`reproducible-prestate` target. Effectively, this builds a docker image specified +by [Dockerfile.repro](./Dockerfile.repro) pinned with the following dependencies: +- golang version `1.21.3` +- alpine `3.18` + +After running `make reproducible-prestate`, the following files can be found in +[./bin/](./bin/): +- [`op-program`](./bin/op-program) +- [`op-program-client.elf`](./bin/op-program-client.elf) +- [`prestate.json`](./bin/prestate.json) +- [`prestate-proof.json`](./bin/prestate-proof.json) + +The `prestate-proof.json` file is what contains the absolute pre-state hash under +the `.pre` key that is also used by the [contracts][ctb] deploy script. + +[ctb]: ../packages/contracts-bedrock/