Skip to content

Commit 3ce01bc

Browse files
mh0ltclaude
andauthored
Add hive test skill (#19615)
This adds a claude skill to run hive tests, this allows a local agent to set-up and run the suite of hive tests we use for development to confim local changes don't cause regressions. claude can pretty much work out how to use hive on its own, but this skill adds a bit of scope and control to the process and also tells claude how to set-up ephemeral instances from branches and set-up tests on local code. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a3e8b40 commit 3ce01bc

File tree

1 file changed

+298
-0
lines changed

1 file changed

+298
-0
lines changed

.claude/skills/hive-test/SKILL.md

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
# Skill: hive-test
2+
3+
Run Ethereum Hive integration tests against a local Erigon build. Works from a clean
4+
environment -- no pre-existing hive installation required.
5+
6+
## Metadata
7+
- user-invocable: true
8+
- description: Run Hive integration tests (engine, rpc, eest) against local Erigon
9+
- allowed-tools: Bash, Read, Write, Edit, Glob, Grep
10+
11+
## Overview
12+
13+
This skill sets up an ephemeral Hive test environment, builds a local Erigon Docker
14+
image, runs the requested test suites, reports results, and cleans up containers.
15+
16+
## Arguments
17+
18+
The user may specify one or more test suites in any combination:
19+
20+
### Individual suites
21+
| Suite name | Simulator | Description |
22+
|-----------|-----------|-------------|
23+
| `exchange-capabilities` | ethereum/engine | Engine exchange-capabilities |
24+
| `withdrawals` | ethereum/engine | Engine withdrawals |
25+
| `cancun` | ethereum/engine | Engine cancun |
26+
| `api` | ethereum/engine | Engine API |
27+
| `auth` | ethereum/engine | Engine auth |
28+
| `rpc-compat` | ethereum/rpc | RPC compatibility |
29+
| `eest` | ethereum/eels/consume-engine | Execution Spec Tests (version auto-discovered) |
30+
| `eest-bal` | ethereum/eels/consume-engine | EEST BAL amsterdam fixtures (version auto-discovered) |
31+
32+
### Groups
33+
| Group name | Expands to |
34+
|-----------|------------|
35+
| `engine` | exchange-capabilities, withdrawals, cancun, api, auth |
36+
| `all` | Every suite listed above |
37+
38+
### Examples
39+
- `/hive-test api` - Run just the engine API suite
40+
- `/hive-test withdrawals api` - Run withdrawals and API suites
41+
- `/hive-test engine` - Run all engine suites
42+
- `/hive-test engine rpc-compat` - Run all engine suites plus rpc-compat
43+
- `/hive-test eest-bal` - Run BAL-specific EEST tests
44+
- `/hive-test all` - Run everything
45+
46+
### Options
47+
- **erigon-path** - Path to local erigon source (default: current working directory)
48+
- **branch=BRANCH** - Clone erigon from a remote branch instead of using the local
49+
working directory. The branch is cloned from `https://github.com/erigontech/erigon.git`
50+
into the hive client directory. Example: `/hive-test api branch=fix/my-feature`
51+
- **eest-version=VERSION** - Pin EEST fixtures version (e.g. `v5.3.0`). Default: auto-discover latest.
52+
- **bal-version=VERSION** - Pin BAL fixtures version (e.g. `bal@v5.1.0`). Default: auto-discover latest.
53+
54+
## Expected Failures (CI thresholds)
55+
56+
| Suite | Max Allowed Failures |
57+
|-------|---------------------|
58+
| exchange-capabilities | 0 |
59+
| withdrawals | 0 |
60+
| cancun | 3 |
61+
| api | 0 |
62+
| auth | 0 |
63+
| rpc-compat | 23 |
64+
| eest (consume-engine) | 0 |
65+
| eest-bal | 4 (upstream BPO2ToAmsterdamAtTime15k fork transition) |
66+
67+
Note: Failure counts are version-dependent and may change with newer fixtures.
68+
The eest-bal fork transition failures are a known upstream issue, not Erigon bugs.
69+
70+
## Procedure
71+
72+
### Phase 0: Discover Versions
73+
74+
Before setup, discover the latest EEST fixture versions from GitHub. Skip this phase
75+
if the user provided explicit version overrides (`eest-version=`, `bal-version=`).
76+
77+
```bash
78+
# Latest standard EEST fixtures (tag matching v*.*.*)
79+
EEST_VERSION=$(curl -s https://api.github.com/repos/ethereum/execution-spec-tests/releases \
80+
| jq -r '[.[] | select(.tag_name | test("^v[0-9]+\\.[0-9]+\\.[0-9]+$"))][0].tag_name')
81+
82+
# Latest BAL fixtures (tag matching bal@v*.*.*)
83+
BAL_TAG=$(curl -s https://api.github.com/repos/ethereum/execution-spec-tests/releases \
84+
| jq -r '[.[] | select(.tag_name | startswith("bal@"))][0].tag_name')
85+
BAL_BRANCH="tests-${BAL_TAG}"
86+
BAL_TAG_URLENC=$(echo "$BAL_TAG" | sed 's/@/%40/')
87+
BAL_FIXTURES_URL="https://github.com/ethereum/execution-spec-tests/releases/download/${BAL_TAG_URLENC}/fixtures_bal.tar.gz"
88+
```
89+
90+
Then check whether the EEST mapper at the discovered tag already has the exception
91+
entries Erigon needs. If not, the `disable_strict_exception_matching` workaround is
92+
required:
93+
94+
```bash
95+
MAPPER_URL="https://raw.githubusercontent.com/ethereum/execution-specs/refs/tags/${BAL_BRANCH}/packages/testing/src/execution_testing/client_clis/clis/erigon.py"
96+
if curl -sf "$MAPPER_URL" | grep -q "GAS_USED_OVERFLOW"; then
97+
DISABLE_STRICT=""
98+
echo "Mapper has BAL exception entries — strict matching enabled"
99+
else
100+
DISABLE_STRICT='--sim.buildarg disable_strict_exception_matching=erigon'
101+
echo "Mapper missing BAL exception entries — strict matching disabled for erigon"
102+
fi
103+
```
104+
105+
Log the discovered versions:
106+
```
107+
EEST: $EEST_VERSION | BAL: $BAL_TAG (branch: $BAL_BRANCH) | Strict matching: enabled/disabled
108+
```
109+
110+
### Phase 1: Setup
111+
112+
1. **Determine erigon source path.** Default is the current git working directory.
113+
Verify it contains a `Makefile` and `go.mod` with `erigontech/erigon`.
114+
115+
2. **Choose a work directory.** Use `mktemp -d /tmp/hive-test-XXXXXX` for isolation.
116+
117+
3. **Clone hive:**
118+
```bash
119+
WORKDIR=$(mktemp -d /tmp/hive-test-XXXXXX)
120+
cd "$WORKDIR"
121+
git clone --depth 1 https://github.com/ethereum/hive.git
122+
cd hive
123+
```
124+
125+
4. **Copy or clone the erigon source into hive:**
126+
127+
If `branch=BRANCH` was specified, clone that branch:
128+
```bash
129+
git clone --depth 1 --branch "$BRANCH" \
130+
https://github.com/erigontech/erigon.git clients/erigon/erigon
131+
```
132+
133+
Otherwise, copy the local source:
134+
```bash
135+
# Use rsync to copy, excluding build artifacts and .git
136+
rsync -a --exclude='.git' --exclude='build/' --exclude='temp/' \
137+
"$ERIGON_PATH/" clients/erigon/erigon/
138+
```
139+
140+
5. **Install Dockerfile.local** for local builds:
141+
Ensure `clients/erigon/Dockerfile.local` exists with the correct content.
142+
Key requirements:
143+
- Base image: `golang:1.25.0-trixie` (Debian, not Alpine)
144+
- Build command: `make EXTRA_BUILD_TAGS=nosilkworm erigon`
145+
- Runtime: `debian:13-slim` with `bash curl jq libstdc++6 libgcc-s1`
146+
- P2P protocol: `erigon.sh` must include `--p2p.protocol 68,69`
147+
148+
If `clients/erigon/Dockerfile.local` doesn't already exist or doesn't have
149+
`nosilkworm`, write the correct version:
150+
```dockerfile
151+
FROM golang:1.25.0-trixie as builder
152+
ARG local_path=erigon
153+
COPY $local_path erigon
154+
RUN apt-get update && apt-get install -y bash build-essential ca-certificates git \
155+
&& cd erigon && make EXTRA_BUILD_TAGS=nosilkworm erigon \
156+
&& cp build/bin/erigon /usr/local/bin/erigon
157+
158+
FROM debian:13-slim
159+
COPY --from=builder /usr/local/bin/erigon /usr/local/bin/
160+
RUN apt-get update && apt-get install -y bash curl jq libstdc++6 libgcc-s1 && rm -rf /var/lib/apt/lists/*
161+
RUN erigon --version | sed -e 's/erigon version \(.*\)/\1/' > /version.txt
162+
COPY genesis.json /genesis.json
163+
COPY mapper.jq /mapper.jq
164+
COPY erigon.sh /erigon.sh
165+
COPY enode.sh /hive-bin/enode.sh
166+
RUN chmod +x /erigon.sh /hive-bin/enode.sh
167+
EXPOSE 8545 8546 8551 30303 30303/udp
168+
ENTRYPOINT ["/erigon.sh"]
169+
```
170+
171+
6. **P2P protocol configuration:**
172+
Do NOT add `--p2p.protocol` flags to erigon.sh. The hive devp2p simulator
173+
does not yet support eth/69, so advertising it causes Fork ID test failures
174+
(`rlp: expected input list for devp2p.Disconnect`). Let erigon use its default
175+
protocol negotiation.
176+
177+
6b. **Parallel execution for Amsterdam (BAL) blocks:**
178+
Verify that `erigon.sh` enables parallel execution when Amsterdam is configured.
179+
BAL validation only runs in the parallel execution path. If the following block
180+
is missing from `erigon.sh`, add it after the `--sync.parallel-state-flushing` line:
181+
```bash
182+
# Enable parallel execution for Amsterdam (BAL) blocks.
183+
# BAL validation only runs in the parallel execution path.
184+
if [ "$HIVE_AMSTERDAM_TIMESTAMP" != "" ]; then
185+
export ERIGON_EXEC3_PARALLEL=true
186+
fi
187+
```
188+
Without this, Amsterdam blocks run through serial execution which has no BAL
189+
validation, causing `test_bal_invalid` tests to incorrectly return VALID.
190+
191+
7. **Create client config file:**
192+
```bash
193+
cat > erigon-local.yaml <<'EOF'
194+
- client: erigon
195+
dockerfile: local
196+
EOF
197+
```
198+
199+
8. **Build hive binary:**
200+
```bash
201+
go build .
202+
```
203+
204+
### Phase 2: Run Tests
205+
206+
Always use `--sim.parallelism 12` for all suites to maximize throughput.
207+
208+
When running multiple suites, launch **separate hive sessions in parallel** (as
209+
background shell commands) whenever the suites use different simulators. This gives
210+
`runs × parallelism` total concurrency. Suites using the same simulator can be combined
211+
with `--sim.limit "suite1|suite2|..."`.
212+
213+
**Engine suites** (sim: `ethereum/engine`) — combine all with `|`:
214+
```bash
215+
./hive --client-file erigon-local.yaml --sim ethereum/engine \
216+
--sim.limit "exchange-capabilities|withdrawals|cancun|api|auth" \
217+
--sim.parallelism 12 --sim.timelimit 30m
218+
```
219+
220+
**RPC compat** (sim: `ethereum/rpc`, limit: `compat`):
221+
```bash
222+
./hive --client-file erigon-local.yaml --sim ethereum/rpc \
223+
--sim.limit "compat" --sim.parallelism 12 --sim.timelimit 30m
224+
```
225+
226+
**EEST** (sim: `ethereum/eels/consume-engine`):
227+
```bash
228+
# $EEST_VERSION discovered in Phase 0 (e.g. v5.4.0), or user-provided via eest-version=
229+
./hive --client-file erigon-local.yaml \
230+
--sim ethereum/eels/consume-engine \
231+
--sim.parallelism=12 --docker.nocache=true \
232+
--sim.buildarg fixtures=https://github.com/ethereum/execution-spec-tests/releases/download/${EEST_VERSION}/fixtures_develop.tar.gz \
233+
--sim.timelimit 60m
234+
```
235+
236+
**EEST BAL** (sim: `ethereum/eels/consume-engine`, amsterdam filter):
237+
```bash
238+
# $BAL_BRANCH, $BAL_FIXTURES_URL, $DISABLE_STRICT discovered in Phase 0
239+
# (e.g. BAL_BRANCH=tests-bal@v5.2.0), or user-provided via bal-version=
240+
./hive --client-file erigon-local.yaml \
241+
--sim ethereum/eels/consume-engine \
242+
--sim.limit=".*amsterdam.*" \
243+
--sim.parallelism=12 --docker.nocache=true \
244+
--sim.buildarg branch=${BAL_BRANCH} \
245+
--sim.buildarg fixtures=${BAL_FIXTURES_URL} \
246+
${DISABLE_STRICT} \
247+
--sim.timelimit 60m
248+
```
249+
250+
Note: The `disable_strict_exception_matching` flag is only added when Phase 0 detects
251+
that the EEST `ErigonExceptionMapper` at the discovered tag is missing required entries
252+
(e.g. `BlockException.GAS_USED_OVERFLOW`, BAL exception types). Once upstream updates
253+
their tagged releases with the mapper fixes (already on `forks/amsterdam` HEAD), this
254+
flag will no longer be needed automatically.
255+
256+
### Phase 3: Parse Results
257+
258+
After each suite, parse the output to extract results:
259+
```bash
260+
status_line=$(tail -2 output.log | head -1 | sed -r "s/\x1B\[[0-9;]*[a-zA-Z]//g")
261+
suites=$(echo "$status_line" | sed -n 's/.*suites=\([0-9]*\).*/\1/p')
262+
tests=$(echo "$status_line" | sed -n 's/.*tests=\([0-9]*\).*/\1/p')
263+
failed=$(echo "$status_line" | sed -n 's/.*failed=\([0-9]*\).*/\1/p')
264+
```
265+
266+
Also check the JSON result files in `workspace/logs/*.json` for detailed per-test
267+
results. Report pass/fail counts and list any failing test names.
268+
269+
### Phase 4: Cleanup
270+
271+
**Always run cleanup**, even if tests fail:
272+
273+
```bash
274+
# Clean up hive containers
275+
./hive --cleanup
276+
277+
# Optionally remove the work directory
278+
rm -rf "$WORKDIR"
279+
280+
# Prune dangling docker images from the test run
281+
docker image prune -f
282+
```
283+
284+
## Troubleshooting
285+
286+
### Container crash: "libsilkworm_capi.so not found"
287+
The Dockerfile.local must use `make EXTRA_BUILD_TAGS=nosilkworm erigon`. Ensure the
288+
Dockerfile does NOT use Alpine (use Debian trixie).
289+
290+
### Fork ID test failures: "rlp: expected input list for devp2p.Disconnect"
291+
The erigon.sh is missing eth/69 support. Ensure `--p2p.protocol 68,69`.
292+
293+
### Timeout failures
294+
Run suites separately instead of combining them. Increase `--sim.timelimit` if needed.
295+
296+
### Leftover containers
297+
Run `./hive --cleanup` or `docker rm -f $(docker ps -aq)` to remove stale containers.
298+
The hive binary has built-in cleanup: `./hive --cleanup --cleanup.older-than 1h`.

0 commit comments

Comments
 (0)