Skip to content

Commit 16514ee

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix-any-chain-treestate
2 parents d298ec4 + 05d129b commit 16514ee

40 files changed

Lines changed: 2035 additions & 1452 deletions

File tree

.github/workflows/README.md

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ graph TB
3131
%% Reusable build
3232
subgraph Build
3333
BuildDocker[zfnd-build-docker-image.yml]
34+
PrepareBinaries[zfnd-release-binaries.yml]
35+
AttachBinaries[zfnd-attach-release-binaries.yml]
3436
end
3537
3638
%% Release automation
@@ -69,14 +71,16 @@ graph TB
6971
Manual --> IT & DeployNodes & Cleanup
7072
7173
%% Build dependency
74+
ReleaseBinaries --> BuildDocker & PrepareBinaries
75+
PrepareBinaries --> AttachBinaries
7276
BuildDocker --> IT
7377
IT --> FindDisks --> Deploy
7478
7579
%% Styling
7680
classDef primary fill:#2374ab,stroke:#2374ab,color:white
7781
classDef secondary fill:#48a9a6,stroke:#48a9a6,color:white
7882
classDef trigger fill:#95a5a6,stroke:#95a5a6,color:white
79-
class BuildDocker primary
83+
class BuildDocker,PrepareBinaries,AttachBinaries primary
8084
class ReleaseWorkflow,ReleaseBinaries primary
8185
class Unit,Lint,Coverage,DockerCfg,CrateBuild,PRGate,Docs,Security secondary
8286
class IT,FindDisks,Deploy,DeployNodes,Cleanup secondary
@@ -138,7 +142,40 @@ _The diagram above illustrates the parallel execution patterns in our CI/CD syst
138142

139143
**Note**: Self-hosted Runners are just used to keep the logs running in the GitHub Actions UI for over 6 hours, the Integration Tests are not run in the Self-hosted Runner itself, but in the deployed VMs in GCP through GitHub Actions.
140144

141-
### 5. Queue Management
145+
### 5. Rust build caching
146+
147+
Rust jobs cache `~/.cargo` and dependency artifacts in `target/` through
148+
[`actions-rust-lang/setup-rust-toolchain`](https://github.com/actions-rust-lang/setup-rust-toolchain),
149+
which wraps [`Swatinem/rust-cache`](https://github.com/Swatinem/rust-cache). Caching is on by
150+
default, so a job opts _out_ with `cache: false` rather than opting in.
151+
152+
GitHub gives each repository 10 GB of cache storage by default; administrators can configure a
153+
higher paid limit. Least-recently-used entries are evicted when the configured limit is exceeded.
154+
Caches are also branch-scoped: a branch can read its own caches and the default branch's,
155+
caches written by PRs can never be read by anyone else, but they still evict main's caches, which
156+
are the only ones every PR does restore from.
157+
158+
Three rules keep the quota usable:
159+
160+
1. **Only main writes.** The main building jobs set
161+
`cache-save-if: ${{ github.ref == 'refs/heads/main' }}`. PRs restore from main and write nothing. (There are some minor exceptions to this rule.)
162+
2. **Wide matrices share one key.** The `test-crates.yml` matrices use
163+
`cache-shared-key` and seed the shared cache from a single build (`zebrad`
164+
which has the widest dependency closure; `zebra-rpc` for the MSRV build since
165+
it does not build `zebrad` and `zebra-rpc` is second widest option).
166+
3. **Jobs that don't build don't cache.** `fmt`, `no-test-deps`, `deny` (12 jobs wide), and the
167+
crate-matrix generator in `test-crates.yml` set `cache: false`.
168+
169+
To inspect the current state:
170+
171+
```bash
172+
gh api repos/ZcashFoundation/zebra/actions/cache/usage
173+
gh api 'repos/ZcashFoundation/zebra/actions/caches?per_page=100' \
174+
--jq '[.actions_caches[] | {ref, mb: (.size_in_bytes/1048576|round)}]
175+
| group_by(.ref)[] | "\(.[0].ref) n=\(length) \(map(.mb)|add)MB"'
176+
```
177+
178+
### 6. Queue Management
142179

143180
[Mergify](https://mergify.com)
144181

@@ -160,12 +197,14 @@ _The diagram above illustrates the parallel execution patterns in our CI/CD syst
160197
- **Docs (Book + internal)** (`book.yml`): Builds mdBook and internal rustdoc, publishes to Pages
161198
- **Security Analysis** (`zizmor.yml`): GitHub Actions security lint (SARIF)
162199
- **Release** (`release.yml`): Creates or updates Release PRs with release-plz, then uses `ZcashFoundation/cargo-release` and native Cargo to reconcile crates, tags, and one `zebrad` GitHub Release. See the [release process](../../book/src/dev/release-process.md#release-candidate--release-process) for operational instructions.
163-
- **Release Binaries** (`release-binaries.yml`): Build and publish release artifacts
200+
- **Release Binaries** (`release-binaries.yml`): Orchestrates release images, prepares and attaches downloadable binaries, and supports manual preparation validation without release attachment
164201
- **Integration Tests on GCP** (`zfnd-ci-integration-tests-gcp.yml`): Stateful tests, E2E tests, cached disks, lwd flows
165202

166203
### Supporting/Re-usable Workflows
167204

168205
- **Build docker image** (`zfnd-build-docker-image.yml`): Reusable image build with caching and tagging
206+
- **Prepare release binaries** (`zfnd-release-binaries.yml`): Builds, attests, checksums, signs, and uploads the immutable binary bundle
207+
- **Attach release binaries** (`zfnd-attach-release-binaries.yml`): Attaches the prepared binary bundle to an existing GitHub Release
169208
- **Find cached disks** (`zfnd-find-cached-disks.yml`): Discovers GCP disks for stateful tests
170209
- **Deploy integration tests** (`zfnd-deploy-integration-tests-gcp.yml`): Orchestrates GCP VMs and test runs
171210
- **Deploy nodes** (`zfnd-deploy-nodes-gcp.yml`): Provision long-lived nodes

.github/workflows/lint.yml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,16 @@ jobs:
7070
with:
7171
components: clippy
7272
toolchain: 1.97.0
73+
# Both matrix legs build the same workspace, so they share one cache.
74+
cache-shared-key: clippy
7375
cache-on-failure: true
76+
# Restore on every ref, but only write from main. Actions caches are
77+
# branch-scoped, so a cache written by a PR can never be read by any
78+
# other branch, yet it still consumes the repo-wide cache allowance
79+
# and can evict main's caches - the only ones PRs can restore from.
80+
# The `tests` leg seeds it, because its feature set is a superset.
81+
# See "Rust build caching" in .github/workflows/README.md.
82+
cache-save-if: ${{ github.ref == 'refs/heads/main' && matrix.type == 'tests' }}
7483
- uses: ./.github/actions/setup-zebra-build
7584
- name: Run clippy
7685
run: cargo clippy ${{ matrix.args }} --features "${{ matrix.features }}"
@@ -90,6 +99,8 @@ jobs:
9099
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 #v1.16.1
91100
with:
92101
cache-on-failure: true
102+
# Only main writes caches, see the clippy job above.
103+
cache-save-if: ${{ github.ref == 'refs/heads/main' }}
93104
- uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 #v2.79.3
94105
with:
95106
tool: cargo-hack
@@ -118,6 +129,8 @@ jobs:
118129
with:
119130
toolchain: 1.91.0 # MSRV
120131
cache-on-failure: true
132+
# Only main writes caches, see the clippy job above.
133+
cache-save-if: ${{ github.ref == 'refs/heads/main' }}
121134
- uses: ./.github/actions/setup-zebra-build
122135
- run: cargo build --bin "${{ matrix.binary }}" --workspace
123136

@@ -138,6 +151,8 @@ jobs:
138151
with:
139152
toolchain: 1.91.0
140153
components: rustfmt
154+
# `cargo fmt` builds nothing, so a cache here only consumes quota.
155+
cache: false
141156
- name: Run fmt
142157
run: cargo fmt --all -- --check
143158

@@ -154,7 +169,8 @@ jobs:
154169
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 #v1.16.1
155170
with:
156171
toolchain: 1.97.0
157-
cache-on-failure: true
172+
# `cargo tree` builds nothing, so a cache here only consumes quota.
173+
cache: false
158174
- name: Ensure no arbitrary or proptest dependency on default build
159175
run: cargo tree --package zebrad -e=features,no-dev | grep -Eq "arbitrary|proptest" && exit 1 || exit 0
160176

@@ -175,6 +191,8 @@ jobs:
175191
with:
176192
toolchain: 1.97.0
177193
cache-on-failure: true
194+
# Only main writes caches, see the clippy job above.
195+
cache-save-if: ${{ github.ref == 'refs/heads/main' }}
178196
- uses: ./.github/actions/setup-zebra-build
179197
- run: cargo check --locked --all-features --all-targets
180198

@@ -211,7 +229,9 @@ jobs:
211229
persist-credentials: false
212230
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 #v1.16.1
213231
with:
214-
cache-on-failure: true
232+
# cargo-deny reads the dependency graph without building it, and this
233+
# matrix is 12 jobs wide, so caching here is pure quota consumption.
234+
cache: false
215235
- name: Check ${{ matrix.checks }} with features ${{ matrix.features }}
216236
uses: EmbarkStudios/cargo-deny-action@6c8f9facfa5047ec02d8485b6bf52b587b7777d1 #v2.0.18
217237
with:

.github/workflows/pr-gate.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ jobs:
137137
feature-group: default-features
138138
baseline-rev: ${{ steps.baseline.outputs.rev }}
139139

140+
# This checks for changelog entries depending on the type of the PR (per title).
141+
# An entry is required for a crate if any file in the crate changed.
142+
# If the title indicates a breaking change, the changelog must also have a `### Breaking Changes` section.
140143
changelog-gate:
141144
needs: changes
142145
if: >-
@@ -192,6 +195,8 @@ jobs:
192195
exit 1
193196
fi
194197
echo "base_sha=${base_sha}" >> "${GITHUB_OUTPUT}"
198+
# Checks if the changelogs have entries for the versions being released
199+
# (used in the in the release PR).
195200
- name: Validate release changelogs
196201
id: changelogs
197202
continue-on-error: true
@@ -219,7 +224,7 @@ jobs:
219224
- name: Check desired release state
220225
id: cargo-release
221226
continue-on-error: true
222-
uses: ZcashFoundation/cargo-release@34a37595755444456ce0e2d2b1258d9a29c14fac
227+
uses: ZcashFoundation/cargo-release@0083006dfd267ed560b4cf1aed347ef2f326162e # v0.1.0
223228
with:
224229
phase: check
225230
base-sha: ${{ steps.release-target.outputs.base_sha }}
@@ -284,4 +289,7 @@ jobs:
284289
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
285290
with:
286291
jobs: ${{ toJSON(needs) }}
292+
# Leave it for the PR author and reviewer to decide if the changelog
293+
# entries are good enough.
294+
allowed-failures: changelog-gate
287295
allowed-skips: semver-checks, changelog-gate, release-readiness

.github/workflows/release-binaries.yml

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
# This workflow is triggered if:
88
# - A release is published
99
# - A pre-release is changed to a release
10+
# - A maintainer manually validates binary preparation before a release
1011
name: Release binaries
1112

1213
on:
1314
release:
1415
types:
1516
- released
17+
workflow_dispatch:
1618

1719
permissions:
1820
contents: read
@@ -51,15 +53,52 @@ jobs:
5153
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
5254
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
5355

54-
# Build and attach downloadable zebrad binaries to the GitHub release.
55-
binaries:
56-
name: Attach release binaries
56+
# Resolve the release tag into the version used in binary asset names.
57+
binary-version:
58+
name: Resolve release binary version
5759
if: github.repository_owner == 'ZcashFoundation' && startsWith(github.event.release.tag_name, 'v')
60+
runs-on: ubuntu-latest
61+
timeout-minutes: 1
62+
outputs:
63+
version: ${{ steps.release.outputs.version }}
64+
steps:
65+
- name: Resolve release inputs
66+
id: release
67+
env:
68+
RELEASE_TAG: ${{ github.event.release.tag_name }}
69+
run: |
70+
printf 'version=%s\n' "${RELEASE_TAG#v}" >> "${GITHUB_OUTPUT}"
71+
72+
prepare-binaries:
73+
name: Prepare release binaries
74+
needs: binary-version
5875
permissions:
59-
contents: write
60-
id-token: write
61-
attestations: write
76+
contents: read
77+
id-token: write # authenticate binary provenance and signatures
78+
attestations: write # store binary provenance
6279
uses: ./.github/workflows/zfnd-release-binaries.yml
80+
with:
81+
version: ${{ needs.binary-version.outputs.version }}
82+
features: default-release-binaries
83+
84+
validate-binaries:
85+
name: Validate release binary preparation
86+
if: github.event_name == 'workflow_dispatch' && github.repository_owner == 'ZcashFoundation'
87+
permissions:
88+
contents: read
89+
id-token: write # authenticate test provenance and signatures
90+
attestations: write # store test provenance
91+
uses: ./.github/workflows/zfnd-release-binaries.yml
92+
with:
93+
version: 0.0.0-test
94+
features: default-release-binaries
95+
96+
attach-binaries:
97+
name: Attach release binaries
98+
needs: prepare-binaries
99+
permissions:
100+
contents: write # attach assets to the existing release
101+
uses: ./.github/workflows/zfnd-attach-release-binaries.yml
63102
with:
64103
release_tag: ${{ github.event.release.tag_name }}
65104

@@ -95,7 +134,9 @@ jobs:
95134
}}
96135
needs:
97136
- build
98-
- binaries
137+
- binary-version
138+
- prepare-binaries
139+
- attach-binaries
99140
timeout-minutes: 1
100141
steps:
101142
- name: Decide whether the needed jobs succeeded or failed
@@ -106,7 +147,7 @@ jobs:
106147
failure-issue:
107148
name: Open or update issues for release binaries failures
108149
# When a new job is added to this workflow, add it to this list.
109-
needs: [ build, binaries ]
150+
needs: [ build, binary-version, prepare-binaries, attach-binaries ]
110151
# Open tickets for any failed build in this workflow.
111152
if: failure() || cancelled()
112153
runs-on: ubuntu-latest

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ jobs:
254254
- name: Check desired release state
255255
id: cargo-release
256256
continue-on-error: true
257-
uses: ZcashFoundation/cargo-release@34a37595755444456ce0e2d2b1258d9a29c14fac
257+
uses: ZcashFoundation/cargo-release@0083006dfd267ed560b4cf1aed347ef2f326162e #v0.1.0
258258
with:
259259
phase: check
260260
source-directory: release-source
@@ -363,7 +363,7 @@ jobs:
363363
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 #v1.0.5
364364
- name: Publish and verify missing crates
365365
id: cargo-release-publish
366-
uses: ZcashFoundation/cargo-release@34a37595755444456ce0e2d2b1258d9a29c14fac
366+
uses: ZcashFoundation/cargo-release@0083006dfd267ed560b4cf1aed347ef2f326162e #v0.1.0
367367
with:
368368
phase: publish
369369
source-directory: release-source
@@ -409,7 +409,7 @@ jobs:
409409
exit 1
410410
- name: Create missing tags and GitHub Release
411411
id: cargo-release-finalize
412-
uses: ZcashFoundation/cargo-release@34a37595755444456ce0e2d2b1258d9a29c14fac
412+
uses: ZcashFoundation/cargo-release@0083006dfd267ed560b4cf1aed347ef2f326162e #v0.1.0
413413
with:
414414
phase: finalize
415415
source-directory: release-source

.github/workflows/test-crates.yml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ jobs:
6363
with:
6464
toolchain: 1.97.0
6565
components: clippy
66-
cache-on-failure: true
66+
# This job only runs `cargo tree` to build the matrix, so a cache here
67+
# only consumes quota.
68+
cache: false
6769
- uses: ./.github/actions/setup-zebra-build
6870

6971
# This step dynamically creates a JSON containing the values of each crate
@@ -117,8 +119,16 @@ jobs:
117119
with:
118120
toolchain: 1.97.0
119121
components: clippy
120-
cache-key: crate-build-${{ matrix.crate }}
122+
# One cache for the whole matrix instead of one per crate. These jobs
123+
# compile overlapping subsets of the same dependency graph, so 12
124+
# per-crate caches stored ~12 GB of near-duplicate artifacts and blew
125+
# through the repo's default 10 GB quota on their own.
126+
cache-shared-key: crate-build
121127
cache-on-failure: true
128+
# Only main writes the shared cache, and only from the crate with the
129+
# widest dependency closure, so the other legs restore a superset
130+
# rather than whichever leg happened to finish first.
131+
cache-save-if: ${{ github.ref == 'refs/heads/main' && matrix.crate == 'zebrad' }}
122132

123133
- uses: ./.github/actions/setup-zebra-build
124134

@@ -179,8 +189,13 @@ jobs:
179189
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 #v1.16.1
180190
with:
181191
toolchain: ${{ steps.msrv.outputs.version }}
182-
cache-key: crate-build-msrv-${{ matrix.crate }}
192+
# One cache for the whole matrix, see the `build` job above.
193+
cache-shared-key: crate-build-msrv
183194
cache-on-failure: true
195+
# `zebrad` can't seed this matrix: the build step below skips it, so
196+
# that leg compiles nothing. `zebra-rpc` has the widest closure of
197+
# the crates that do build here.
198+
cache-save-if: ${{ github.ref == 'refs/heads/main' && matrix.crate == 'zebra-rpc' }}
184199

185200
- uses: ./.github/actions/setup-zebra-build
186201

.github/workflows/tests-unit.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ jobs:
6969
toolchain: 1.97.0
7070
cache-key: unit-tests-1.97.0-default-release-binaries
7171
cache-on-failure: true
72+
# Restore on every ref, but only write from main. This is the longest
73+
# job in CI, so it is the one that suffers most when PR-scoped caches
74+
# evict main's copy. See "Rust build caching" in README.md.
75+
cache-save-if: ${{ github.ref == 'refs/heads/main' }}
7276
- uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 #v2.79.3
7377
with:
7478
tool: cargo-nextest

0 commit comments

Comments
 (0)