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:
preimage-reproducibility:
docker:
- image: <<pipeline.parameters.ci_builder_image>>
parameters:
version:
type: string
steps:
- checkout
- setup_remote_docker
- run:
name: Set expected prestate hash
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
make -C op-program verify-reproducibility
- notify-failures-on-develop:
mentions: "@proofs-team"
......@@ -1699,19 +1665,5 @@ workflows:
- equal: [ true, << pipeline.parameters.reproducibility_dispatch >> ]
jobs:
- 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:
slack
......@@ -42,6 +42,12 @@ reproducible-prestate:
@cat ./bin/prestate-proof-mt.json | jq -r .pre
.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:
rm -rf bin "$(COMPAT_DIR)"
......
......@@ -18,7 +18,7 @@ type Release struct {
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) {
var releases []Release
err := json.Unmarshal(releasesJSON, &releases)
......
......@@ -31,14 +31,21 @@
},
{
"version": "1.1.0",
"hash": "0x03e69d3de5155f4a80da99dd534561cbddd4f9dd56c9ecc704d6886625711d2b",
"governanceApproved": true
"hash": "0x03e69d3de5155f4a80da99dd534561cbddd4f9dd56c9ecc704d6886625711d2b"
},
{
"version": "1.0.1",
"hash": "0x0398bdd93e2e9313befdf82beb709da6a4daf35ce1abb42d8a998ec9bc1c572e"
},
{
"version": "1.0.0",
"hash": "0x037ef3c1a487960b0e633d3e513df020c43432769f41a634d18a9595cbf53c55",
"governanceApproved": true
},
{
"version": "0.3.1",
"hash": "0x037ef3c1a487960b0e633d3e513df020c43432769f41a634d18a9595cbf53c55"
},
{
"version": "0.3.0",
"hash": "0x034c8cc69f22c35ae386a97136715dd48aaf97fd190942a111bfa680c2f2f421"
......@@ -50,5 +57,9 @@
{
"version": "0.1.0",
"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"
LOGS_DIR="${SCRIPTS_DIR}/../temp/logs"
REPO_DIR="${TMP_DIR}/optimism"
BIN_DIR="${REPO_DIR}/op-program/bin/"
VERSIONS_FILE="${STATES_DIR}/versions.json"
mkdir -p "${STATES_DIR}" "${LOGS_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}
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}"
git checkout "${VERSION}" > "${LOG_FILE}" 2>&1
rm -rf "${BIN_DIR}"
......@@ -39,7 +43,10 @@ do
else
cp "${BIN_DIR}/prestate.json" "${STATES_DIR}/${HASH}.json"
fi
VERSIONS_JSON=$(echo "${VERSIONS_JSON}" | jq ". += [{\"version\": \"${SHORT_VERSION}\", \"hash\": \"${HASH}\"}]")
echo "Built ${VERSION}: ${HASH}"
done
echo "${VERSIONS_JSON}" > "${VERSIONS_FILE}"
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