Commit bb6de071 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-program: Automatically verify the prestate hash for all op-program tags (#12538)

Generates a versions.json to record which prestate came from each tag and compares it to the releases.json.
Adds a couple of releases missed from releases.json and removes governanceApproved from some releases which were not deployed to op-mainnet or submitted to governance.
parent e372a2d3
...@@ -996,45 +996,11 @@ jobs: ...@@ -996,45 +996,11 @@ jobs:
preimage-reproducibility: preimage-reproducibility:
docker: docker:
- image: <<pipeline.parameters.ci_builder_image>> - image: <<pipeline.parameters.ci_builder_image>>
parameters:
version:
type: string
steps: steps:
- checkout - checkout
- setup_remote_docker - setup_remote_docker
- run: - run:
name: Set expected prestate hash make -C op-program verify-reproducibility
command: |
find_prestate_hash() {
jq -r --arg version "<<parameters.version>>" '.[] | select(.version == $version) | .hash' "$1"
}
prestate_hash=$(find_prestate_hash "op-program/prestates/releases.json")
if [ -z "$prestate_hash" ]; then
echo "Unknown prestate version <<parameters.version>>"
exit 1
fi
echo "export EXPECTED_PRESTATE_HASH=$prestate_hash" >> $BASH_ENV
- run:
name: Switch to tag
command: |
git fetch
git checkout "op-program/v<<parameters.version>>"
git submodule update --init --recursive
- run:
name: Build prestate
command: make reproducible-prestate
- run:
name: Verify prestate
command: |
ACTUAL=$(jq -r .pre ./op-program/bin/prestate-proof.json)
echo "Expected: ${EXPECTED_PRESTATE_HASH}"
echo "Actual: ${ACTUAL}"
if [[ "${EXPECTED_PRESTATE_HASH}" != "${ACTUAL}" ]]
then
echo "Prestate did not match expected"
exit 1
fi
- notify-failures-on-develop: - notify-failures-on-develop:
mentions: "@proofs-team" mentions: "@proofs-team"
...@@ -1699,19 +1665,5 @@ workflows: ...@@ -1699,19 +1665,5 @@ workflows:
- equal: [ true, << pipeline.parameters.reproducibility_dispatch >> ] - equal: [ true, << pipeline.parameters.reproducibility_dispatch >> ]
jobs: jobs:
- preimage-reproducibility: - preimage-reproducibility:
matrix:
parameters:
version:
- "0.1.0"
- "0.2.0"
- "0.3.0"
- "1.0.0"
- "1.1.0"
- "1.2.0"
- "1.3.0-rc.1"
- "1.3.0-rc.2"
- "1.3.0-rc.3"
- "1.3.1-rc.1"
- "1.3.1-rc.2"
context: context:
slack slack
...@@ -42,6 +42,12 @@ reproducible-prestate: ...@@ -42,6 +42,12 @@ reproducible-prestate:
@cat ./bin/prestate-proof-mt.json | jq -r .pre @cat ./bin/prestate-proof-mt.json | jq -r .pre
.PHONY: reproducible-prestate .PHONY: reproducible-prestate
verify-reproducibility:
rm -rf temp/states
./scripts/build-prestates.sh
env GO111MODULE=on go run ./prestates/verify/verify.go --input temp/states/versions.json
.PHONY: verify-reproducibility
clean: clean:
rm -rf bin "$(COMPAT_DIR)" rm -rf bin "$(COMPAT_DIR)"
......
...@@ -18,7 +18,7 @@ type Release struct { ...@@ -18,7 +18,7 @@ type Release struct {
GovernanceApproved bool `json:"governanceApproved"` GovernanceApproved bool `json:"governanceApproved"`
} }
// Reads the contents of the releases.json file // GetReleases reads the contents of the releases.json file
func GetReleases() ([]Release, error) { func GetReleases() ([]Release, error) {
var releases []Release var releases []Release
err := json.Unmarshal(releasesJSON, &releases) err := json.Unmarshal(releasesJSON, &releases)
......
...@@ -31,14 +31,21 @@ ...@@ -31,14 +31,21 @@
}, },
{ {
"version": "1.1.0", "version": "1.1.0",
"hash": "0x03e69d3de5155f4a80da99dd534561cbddd4f9dd56c9ecc704d6886625711d2b", "hash": "0x03e69d3de5155f4a80da99dd534561cbddd4f9dd56c9ecc704d6886625711d2b"
"governanceApproved": true },
{
"version": "1.0.1",
"hash": "0x0398bdd93e2e9313befdf82beb709da6a4daf35ce1abb42d8a998ec9bc1c572e"
}, },
{ {
"version": "1.0.0", "version": "1.0.0",
"hash": "0x037ef3c1a487960b0e633d3e513df020c43432769f41a634d18a9595cbf53c55", "hash": "0x037ef3c1a487960b0e633d3e513df020c43432769f41a634d18a9595cbf53c55",
"governanceApproved": true "governanceApproved": true
}, },
{
"version": "0.3.1",
"hash": "0x037ef3c1a487960b0e633d3e513df020c43432769f41a634d18a9595cbf53c55"
},
{ {
"version": "0.3.0", "version": "0.3.0",
"hash": "0x034c8cc69f22c35ae386a97136715dd48aaf97fd190942a111bfa680c2f2f421" "hash": "0x034c8cc69f22c35ae386a97136715dd48aaf97fd190942a111bfa680c2f2f421"
...@@ -50,5 +57,9 @@ ...@@ -50,5 +57,9 @@
{ {
"version": "0.1.0", "version": "0.1.0",
"hash": "0x038942ec840131a63c49fa514a3f0577ae401fd5584d56ad50cdf5a8b41d4538" "hash": "0x038942ec840131a63c49fa514a3f0577ae401fd5584d56ad50cdf5a8b41d4538"
},
{
"version": "0.0.1",
"hash": "0x03babef4b4c6d866d56e6356d961839fd9475931d11e0ea507420a87b0cadbdd"
} }
] ]
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"slices"
"github.com/ethereum-optimism/optimism/op-program/prestates"
)
func main() {
var inputFile string
flag.StringVar(&inputFile, "input", "", "Releases JSON file to verify")
flag.Parse()
if inputFile == "" {
_, _ = fmt.Fprintln(os.Stderr, "Must specify --input")
os.Exit(2)
}
in, err := os.OpenFile(inputFile, os.O_RDONLY, 0o644)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Failed to open input file: %v\n", err.Error())
os.Exit(2)
}
defer in.Close()
input, err := os.ReadFile(inputFile)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Failed to read input file: %v\n", err.Error())
os.Exit(2)
}
var actual []prestates.Release
err = json.Unmarshal(input, &actual)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Failed to parse JSON: %v\n", err.Error())
os.Exit(2)
}
expected, err := prestates.GetReleases()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Failed to load expected releases: %v\n", err.Error())
os.Exit(2)
}
sortFunc := func(a, b prestates.Release) int {
if a.Version > b.Version {
return 1
} else if a.Version == b.Version {
return 0
}
return -1
}
slices.SortFunc(actual, sortFunc)
slices.SortFunc(expected, sortFunc)
differs := false
report := ""
for i := 0; i < max(len(actual), len(expected)); i++ {
get := func(arr []prestates.Release, idx int) string {
if i >= len(arr) {
return "<missing>"
} else {
return formatRelease(arr[i])
}
}
expectedStr := get(expected, i)
actualStr := get(actual, i)
releaseDiffers := expectedStr != actualStr
marker := "✅"
if releaseDiffers {
marker = "❌"
}
report += fmt.Sprintf("%v %d\tExpected: %v\tActual: %v\n", marker, i, expectedStr, actualStr)
differs = differs || releaseDiffers
}
fmt.Println(report)
if differs {
os.Exit(1)
}
}
func formatRelease(release prestates.Release) string {
return fmt.Sprintf("%-13v %s", release.Version, release.Hash)
}
...@@ -18,16 +18,20 @@ STATES_DIR="${SCRIPTS_DIR}/../temp/states" ...@@ -18,16 +18,20 @@ STATES_DIR="${SCRIPTS_DIR}/../temp/states"
LOGS_DIR="${SCRIPTS_DIR}/../temp/logs" LOGS_DIR="${SCRIPTS_DIR}/../temp/logs"
REPO_DIR="${TMP_DIR}/optimism" REPO_DIR="${TMP_DIR}/optimism"
BIN_DIR="${REPO_DIR}/op-program/bin/" BIN_DIR="${REPO_DIR}/op-program/bin/"
VERSIONS_FILE="${STATES_DIR}/versions.json"
mkdir -p "${STATES_DIR}" "${LOGS_DIR}" mkdir -p "${STATES_DIR}" "${LOGS_DIR}"
cd "${REPO_DIR}" cd "${REPO_DIR}"
VERSIONS=$(git tag | grep 'op-program\/v') VERSIONS_JSON="[]"
VERSIONS=$(git tag --list 'op-program/v*' --sort taggerdate)
for VERSION in ${VERSIONS} for VERSION in ${VERSIONS}
do do
LOG_FILE="${LOGS_DIR}/build-$(echo "${VERSION}" | cut -c 12-).txt" SHORT_VERSION=$(echo "${VERSION}" | cut -c 13-)
LOG_FILE="${LOGS_DIR}/build-${SHORT_VERSION}.txt"
echo "Building Version: ${VERSION} Logs: ${LOG_FILE}" echo "Building Version: ${VERSION} Logs: ${LOG_FILE}"
git checkout "${VERSION}" > "${LOG_FILE}" 2>&1 git checkout "${VERSION}" > "${LOG_FILE}" 2>&1
rm -rf "${BIN_DIR}" rm -rf "${BIN_DIR}"
...@@ -39,7 +43,10 @@ do ...@@ -39,7 +43,10 @@ do
else else
cp "${BIN_DIR}/prestate.json" "${STATES_DIR}/${HASH}.json" cp "${BIN_DIR}/prestate.json" "${STATES_DIR}/${HASH}.json"
fi fi
VERSIONS_JSON=$(echo "${VERSIONS_JSON}" | jq ". += [{\"version\": \"${SHORT_VERSION}\", \"hash\": \"${HASH}\"}]")
echo "Built ${VERSION}: ${HASH}" echo "Built ${VERSION}: ${HASH}"
done done
echo "${VERSIONS_JSON}" > "${VERSIONS_FILE}"
echo "All prestates successfully built and available in ${STATES_DIR}" echo "All prestates successfully built and available in ${STATES_DIR}"
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