Skip to content

Commit 9e072c6

Browse files
authored
Merge pull request #53 from ethereum-optimism/tip/op-program-ci
op-program-test CI workflow
2 parents b00ff2b + 6232d77 commit 9e072c6

File tree

14 files changed

+303815
-3
lines changed

14 files changed

+303815
-3
lines changed

.github/scripts/check_versions.sh

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ echo "Version in go.mod: $go_list_version"
1111
cd $submodule_path
1212
submodule_version=$(git rev-parse HEAD)
1313
echo "Submodule commit: $submodule_version"
14-
cd ..
14+
cd ../../..
1515

1616
# Extract the commit hash from the go_list_version
1717
# This regex assumes the hash is always after the last hyphen, which is typical for pseudo-versions
@@ -34,8 +34,19 @@ submodule_commit_part=$(echo $submodule_version | cut -c 1-$length)
3434

3535
# Compare the two commit parts
3636
if [ "$go_list_commit" == "$submodule_commit_part" ]; then
37-
echo "Versions match."
37+
echo "git submodule and go mod versions match."
3838
else
39-
echo "Versions do not match."
39+
echo "git submodule and go mod versions do not match."
40+
exit 1
41+
fi
42+
43+
op_program_test_version=$(cat tests/op-program-test/VERSION)
44+
echo "op-program commit: $op_program_test_version"
45+
46+
# Compare the two commit parts
47+
if [ "$op_program_test_version" == "$submodule_version" ]; then
48+
echo "git submodule and op-program versions match."
49+
else
50+
echo "git submodule and op-program versions do not match."
4051
exit 1
4152
fi

.github/workflows/ci.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,21 @@ jobs:
8686
go-version: '1.21.x'
8787
- name: Check if optimism submodule version matches go.mod version
8888
run: ./.github/scripts/check_versions.sh
89+
90+
op-program-test:
91+
runs-on: ubuntu-latest
92+
timeout-minutes: 20
93+
steps:
94+
- uses: actions/checkout@v4
95+
- name: Submodule update
96+
run: git submodule update --init
97+
- uses: actions/setup-go@v5
98+
with:
99+
go-version: '1.21.x'
100+
- name: Build asterisc
101+
run: make build-rvgo && cp rvgo/bin/asterisc tests/op-program-test/
102+
- name: Build op-program
103+
run: make -C rvsol/lib/optimism/op-program op-program-host && cp rvsol/lib/optimism/op-program/bin/op-program tests/op-program-test/
104+
- name: Run op-program
105+
run: tar -xzvf ./preimages.tar.gz && ./local_cmd.sh
106+
working-directory: tests/op-program-test

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,7 @@ prestate: build-rvgo
7070
./rvgo/bin/asterisc run --proof-at '=0' --stop-at '=1' --input ./rvgo/bin/prestate.json --meta ./rvgo/bin/meta.json --proof-fmt './rvgo/bin/%d.json' --output ""
7171
mv ./rvgo/bin/0.json ./rvgo/bin/prestate-proof.json
7272
.PHONY: prestate
73+
74+
op-program-test-capture:
75+
./tests/op-program-test/capture.sh
76+
.PHONY: op-program-test-capture

tests/op-program-test/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# op-program-test
2+
3+
This directory has tools to run op-program-test in the CI workflow.
4+
5+
The purpose of the test is to confirm that Asterisc fast VM can run the current version of op-program on the local devnet.
6+
7+
To run op-program in CI, we need following requirements:
8+
- chain-artifacts: rollup config and L2 genesis of devnet
9+
- captured preimages: preimage key and values which are used by op-program
10+
11+
These requirements should be generated in the local machine when `rvsol/lib/optimism` submodule is updated.
12+
13+
To generate requirements, simply run `PYTHON_PATH={PYTHON_BIN_PATH} capture.sh` in the local machine,
14+
and commit all generated files!
15+
16+
## Prerequisites
17+
- All prerequisites to build the optimism monorepo and launch devnet. See https://github.com/ethereum-optimism/optimism/blob/develop/CONTRIBUTING.md#development-quick-start.
18+
- Python environment(>3.10) which has all dependencies in `requirements.txt`.

tests/op-program-test/VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3d27411a05472bc8eba15d93cfc4ba092d586bd6

tests/op-program-test/capture.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import asyncio
2+
import websockets
3+
import requests
4+
import json
5+
import os
6+
7+
L1_WS_ENDPOINT = "ws://localhost:8546"
8+
L2_HTTP_ENDPOINT = "http://localhost:9545"
9+
OUTPUT_PROPOSED_TOPIC = "0xa7aaf2512769da4e444e3de247be2564225c2e7a8f74cfe528e46e17d24868e2"
10+
11+
current_dir = os.path.dirname(os.path.abspath(__file__))
12+
project_root = os.path.dirname(os.path.dirname(current_dir))
13+
optimism_root = os.path.join(project_root, "rvsol/lib/optimism")
14+
15+
with open(os.path.join(optimism_root, ".devnet/addresses.json"), "r") as f:
16+
addrs = json.load(f)
17+
18+
logs = []
19+
l2_head = ""
20+
21+
22+
async def subscribe_logs():
23+
async with websockets.connect(L1_WS_ENDPOINT) as websocket:
24+
subscription_request = {
25+
"jsonrpc": "2.0",
26+
"method": "eth_subscribe",
27+
"params": ["logs", {"address": addrs["L2OutputOracleProxy"], "topics": [OUTPUT_PROPOSED_TOPIC]}],
28+
"id": 1
29+
}
30+
31+
await websocket.send(json.dumps(subscription_request))
32+
33+
print("Waiting OutputProposed logs...")
34+
while True:
35+
message = await websocket.recv()
36+
res = json.loads(message)
37+
if "params" in res:
38+
result = res["params"]["result"]
39+
logs.append({
40+
"outputRoot": result["topics"][1],
41+
"l2BlockNumber": int(result["topics"][3], base=16),
42+
"l1BlockNumber": int(result["blockNumber"], base=16),
43+
"l1BlockHash": result["blockHash"]
44+
})
45+
if len(logs) == 2:
46+
break
47+
48+
l2_block_reqeust = {
49+
"jsonrpc": "2.0",
50+
"method": "eth_getBlockByNumber",
51+
"params": [hex(logs[0]["l2BlockNumber"]), False],
52+
"id": 1
53+
}
54+
res = requests.post(L2_HTTP_ENDPOINT, json=l2_block_reqeust).json()
55+
56+
global l2_head
57+
l2_head = res["result"]["hash"]
58+
59+
asyncio.run(subscribe_logs())
60+
61+
local_cmd = f'''#!/bin/bash
62+
63+
./asterisc run \\
64+
--info-at '%10000000' \\
65+
--proof-at never \\
66+
--input ./state.json \\
67+
-- \\
68+
./op-program \\
69+
--rollup.config ./chain-artifacts/rollup.json \\
70+
--l2.genesis ./chain-artifacts/genesis-l2.json \\
71+
--l1.trustrpc \\
72+
--l1.rpckind debug_geth \\
73+
--l1.head {logs[1]["l1BlockHash"]} \\
74+
--l2.head {l2_head} \\
75+
--l2.outputroot {logs[0]["outputRoot"]} \\
76+
--l2.claim {logs[1]["outputRoot"]} \\
77+
--l2.blocknumber {logs[1]["l2BlockNumber"]} \\
78+
--datadir ./preimages \\
79+
--log.format terminal \\
80+
--server'''
81+
82+
capture_cmd = local_cmd + " --l1 http://127.0.0.1:8545 --l2 http://127.0.0.1:9545"
83+
84+
# Script to capture preimages from the local devnet
85+
with open(os.path.join(current_dir, "capture_cmd.sh"), "w") as f:
86+
f.write(capture_cmd)
87+
os.chmod("capture_cmd.sh", 0o755)
88+
89+
# Script to run op-program in offline mode
90+
with open(os.path.join(current_dir, "local_cmd.sh"), "w") as f:
91+
f.write(local_cmd)
92+
os.chmod("local_cmd.sh", 0o755)

tests/op-program-test/capture.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/bin/bash
2+
set -e
3+
4+
if [ -z "${PYTHON_PATH}" ]; then
5+
echo "PYTHON_PATH is not set. Must point Python binary to run capture.py"
6+
exit 1
7+
fi
8+
absolute_python_path="$(cd "$(dirname "$PYTHON_PATH")"; pwd)/$(basename "$PYTHON_PATH")"
9+
script_dir=$(cd "$(dirname $0)"; pwd)
10+
root_dir=$(dirname $(dirname $script_dir))
11+
optimism_dir=$root_dir/rvsol/lib/optimism
12+
13+
# Build asterisc binary
14+
cd $root_dir
15+
make build-rvgo
16+
cp ./rvgo/bin/asterisc $script_dir/
17+
18+
# Build op-program
19+
cd $optimism_dir
20+
git_commit_hash=$(git rev-parse HEAD)
21+
make -C op-program op-program-client-riscv
22+
make -C op-program op-program-host
23+
cp op-program/bin/op-program-client-riscv.elf $script_dir/
24+
cp op-program/bin/op-program $script_dir/
25+
26+
# Launch devnet
27+
make devnet-up
28+
29+
# Copy devnet artifacts
30+
cp .devnet/rollup.json $script_dir/chain-artifacts/
31+
cp .devnet/genesis-l2.json $script_dir/chain-artifacts/
32+
33+
# Load op-program RISCV binary
34+
cd $script_dir
35+
./asterisc load-elf --path=./op-program-client-riscv.elf
36+
37+
# Make op-program scripts
38+
$absolute_python_path capture.py
39+
40+
# Capture preimages
41+
rm -f ./preimages.tar.gz
42+
mkdir ./preimages
43+
./capture_cmd.sh
44+
tar -czvf preimages.tar.gz ./preimages
45+
46+
# Clean up
47+
rm -r ./preimages ./capture_cmd.sh ./asterisc ./op-program ./op-program-client-riscv.elf ./out.json
48+
49+
# Write optimism version
50+
echo $git_commit_hash > VERSION

0 commit comments

Comments
 (0)