@@ -14,6 +14,14 @@ VERSION 0.8
1414# the builtin resolves to the literal string `HEAD` across every PR.
1515ARG --global CACHE_KEY= local
1616
17+ # Content-addressed cache of cooked Rust dependencies (cargo-chef). The deps image
18+ # is named by hash(recipe.json · arch · rust-version · flavor); a cache miss cooks
19+ # locally (+cook-<flavor>), a hit is pulled. Pushing to the shared registry is OFF
20+ # by default so untrusted (PR) builds can't poison the cache — only trusted CI runs
21+ # on `main` flip ALLOW_CACHE_PUSH=true. See +cook-build / +build-prepare.
22+ ARG --global DEPS_CACHE_REPO= ghcr.io/midnight-ntwrk/midnight-node-deps
23+ ARG --global ALLOW_CACHE_PUSH= false
24+
1725# ================ Local Targets START ================
1826# If you add a new one here, prefix it with "local-"
1927# Add the target name to the doc string so it shows up
@@ -140,15 +148,16 @@ subxt:
140148# build-node-only builds only the midnight-node binary
141149build-node-only :
142150 FROM +build-prepare
143- COPY --keep-ts -- dir Cargo.lock Cargo.toml docs .sqlx \
151+ COPY --dir Cargo.lock Cargo.toml docs .sqlx \
144152 ledger node pallets primitives metadata res runtime util tests relay partner-chains .
145153
146154 ARG NATIVEARCH
147155
148156 RUN cargo auditable build -p midnight-node --locked --release
149157
150158 RUN mkdir -p /artifacts-$NATIVEARCH \
151- && mv /target/release/midnight-node /artifacts-$NATIVEARCH
159+ && mv /target/release/midnight-node /artifacts-$NATIVEARCH \
160+ && objcopy --compress-debug-sections = zlib "/artifacts-$NATIVEARCH/midnight-node"
152161
153162 SAVE ARTIFACT /artifacts-$NATIVEARCH
154163
@@ -715,6 +724,24 @@ prep-no-copy:
715724 # FROM --platform=$NATIVEPLATFORM +node-ci-image-single-platform
716725 FROM midnightntwrk/midnight-node-ci:${RUST_VERSION}-${COMPACTC_VERSION}-$NATIVEARCH
717726
727+ # Inherited by every target built FROM +prep-no-copy (prep, build-prepare,
728+ # check-rust-prepare, test, …) so all cargo invocations share these settings:
729+ # - verbose output (equivalent to -v, and propagates into nested cargo builds
730+ # driven by nextest/auditable/chef that a per-line -v would miss)
731+ # - RUSTC_BOOTSTRAP=1 unlocks unstable cargo features on the stable toolchain
732+ # - checksum-freshness: decide out-of-date by file hash, not mtime (unstable;
733+ # requires the bootstrap above). Earthly's COPY (without --keep-ts) pins every
734+ # file to a fixed constant mtime (2020-04-16T12:00:00Z) for reproducible layers,
735+ # which defeats cargo's default mtime freshness check: re-copied content with the
736+ # same constant mtime would be seen as unchanged. Hashing the bytes avoids that.
737+ ENV CARGO_TERM_VERBOSE= true
738+ ENV RUSTC_BOOTSTRAP= 1
739+ ENV CARGO_UNSTABLE_CHECKSUM_FRESHNESS= true
740+ # Off everywhere: incremental artifacts are large and embed host-specific
741+ # absolute paths, which bloat and poison the cross-machine cooked-deps cache.
742+ # (Release is already non-incremental; this also covers the dev/check flavor.)
743+ ENV CARGO_INCREMENTAL= 0
744+
718745 # ca-certificates and curl-minimal already present in the CI base image
719746
720747 RUN cargo --version
@@ -724,7 +751,7 @@ prep-no-copy:
724751
725752prep :
726753 FROM +prep-no-copy
727- COPY --keep-ts -- dir \
754+ COPY --dir \
728755 Cargo.lock Cargo.toml .cargo .config .sqlx deny.toml docs \
729756 ledger LICENSE node pallets primitives README.md res runtime \
730757 metadata rustfmt.toml util tests relay partner-chains COMPACTC_VERSION .
@@ -800,21 +827,41 @@ planner:
800827 RUN cargo chef prepare --recipe-path recipe.json
801828 SAVE ARTIFACT recipe.json /recipe.json
802829
803- check-rust-prepare :
804- # NOTE: This just uses recipe.json - no src files!
830+ # cook-check pre-compiles deps for the check (clippy) flavor. Cooks the superset —
831+ # clippy, all-targets (dev-deps), and the rb+try-runtime features check-rust lints —
832+ # so check-rust fully reuses it and check-feature-unification rides on top, recompiling
833+ # only its --no-dev-deps/default-features delta.
834+ cook-check :
805835 FROM +prep-no-copy
806- # COPY +planner/recipe.json /recipe.json
807- CACHE --sharing shared --id cargo-git /usr/local/cargo/git
808- CACHE --sharing shared --id cargo-reg /usr/local/cargo/registry
836+ COPY +planner/recipe.json /recipe.json
837+ RUN cargo chef cook --clippy --workspace --all-targets --features runtime-benchmarks,try-runtime --recipe-path /recipe.json
838+ ARG DEPS_TAG
839+ IF [ "$ALLOW_CACHE_PUSH" = "true" ]
840+ SAVE IMAGE --push $DEPS_CACHE_REPO :$DEPS_TAG
841+ END
809842
810- # Build dependencies - this is the caching Docker layer!
811- # RUN SKIP_WASM_BUILD=1 cargo chef cook --clippy --workspace --all-targets --features runtime-benchmarks --recipe-path /recipe.json
843+ check-rust-prepare :
844+ # Resolve the check dependency cache (pull or cook), mirroring +build-prepare.
845+ FROM +prep-no-copy
846+ COPY +planner/recipe.json /recipe.json
847+ COPY rust-toolchain.toml /rust-toolchain.toml
848+ ARG NATIVEARCH
849+ ARG RUST_VERSION= $(grep '^channel' /rust-toolchain.toml | sed 's/.*"\( .*\) ".*/\1 /' )
850+ ARG RECIPE_HASH= $(sha256sum /recipe.json | cut -c1-16 )
851+ ARG DEPS_TAG= ${RUST_VERSION }-${NATIVEARCH }-check- ${RECIPE_HASH }
852+ COPY (+cache-probe/hit.txt --DEPS_TAG = $DEPS_TAG ) /deps-hit.txt
853+ ARG DEPS_HIT= $(cat /deps-hit.txt)
854+ IF [ "$DEPS_HIT" = "true" ]
855+ FROM $DEPS_CACHE_REPO:$DEPS_TAG
856+ ELSE
857+ FROM +cook-check --DEPS_TAG = $DEPS_TAG
858+ END
812859
813860check-rust :
814861 FROM +check-rust-prepare
815862 CACHE --sharing shared --id cargo-git /usr/local/cargo/git
816863 CACHE --sharing shared --id cargo-reg /usr/local/cargo/registry
817- COPY --keep-ts -- dir \
864+ COPY --dir \
818865 Cargo.lock Cargo.toml .config .sqlx deny.toml docs \
819866 ledger LICENSE node pallets primitives README.md res runtime \
820867 metadata rustfmt.toml util tests relay partner-chains COMPACTC_VERSION .
@@ -835,7 +882,7 @@ check-feature-unification:
835882 FROM +check-rust-prepare
836883 CACHE --sharing shared --id cargo-git /usr/local/cargo/git
837884 CACHE --sharing shared --id cargo-reg /usr/local/cargo/registry
838- COPY --keep-ts -- dir \
885+ COPY --dir \
839886 Cargo.lock Cargo.toml .config .sqlx deny.toml docs \
840887 ledger LICENSE node pallets primitives README.md res runtime \
841888 metadata rustfmt.toml util tests relay partner-chains COMPACTC_VERSION .
@@ -870,16 +917,21 @@ check:
870917# Core tests - excludes Midnight Node Toolkit (requires Node Toolkit (JS) npm packages from midnight-js)
871918test :
872919 ARG NATIVEARCH
873- FROM +prep
920+ # Consume the release deps cache (cooked once, shared with +build). No CACHE /target
921+ # mount here: it would shadow the cooked /target baked into the build image.
922+ FROM +build-prepare
874923 CACHE --sharing shared --id cargo-git /usr/local/cargo/git
875924 CACHE --sharing shared --id cargo-reg /usr/local/cargo/registry
876- # See top-of-file CACHE_KEY ARG for why this is scoped.
877- CACHE --id target-${CACHE_KEY } /target
925+ COPY --dir Cargo.lock Cargo.toml .cargo .config .sqlx deny.toml docs \
926+ ledger LICENSE node pallets primitives README.md res runtime \
927+ metadata rustfmt.toml util tests relay partner-chains COMPACTC_VERSION .
878928
879929 # Test
880930 RUN mkdir /test-artifacts
881- # Note: debug and opt-level=1 OOM the linker (>24GB) due to large test binaries
882- ENV RUSTFLAGS= "-C target-cpu=native -C opt-level=2 -C debuginfo=1"
931+ # No RUSTFLAGS override: release profile (opt-3) inherited — keeps test binaries
932+ # small enough to link (debug/opt-1 OOM'd the linker at >24GB), and debuginfo is
933+ # line-tables via [profile.release] in Cargo.toml. target-cpu=native is gone (it
934+ # made artifacts non-portable across the machines now sharing this image).
883935 COPY .envrc ./bin/.envrc
884936 COPY static/contracts/simple-merkle-tree /test-static/simple-merkle-tree
885937 ENV MIDNIGHT_LEDGER_TEST_STATIC_DIR= /test-static
@@ -914,23 +966,24 @@ test:
914966# These tests do NOT require toolkit-js
915967test-pallet-fixtures :
916968 ARG NATIVEARCH
917- FROM +prep
969+ # Unified with +test onto the release deps cache. Previously a separate debug build
970+ # (for speed); now it rides the shared image, so release costs nothing extra here.
971+ FROM +build-prepare
918972 CACHE --sharing shared --id cargo-git /usr/local/cargo/git
919973 CACHE --sharing shared --id cargo-reg /usr/local/cargo/registry
920- # See top-of-file CACHE_KEY ARG for why this is scoped.
921- CACHE --id target-${CACHE_KEY } /target
974+ COPY --dir Cargo.lock Cargo.toml .cargo .config .sqlx deny.toml docs \
975+ ledger LICENSE node pallets primitives README.md res runtime \
976+ metadata rustfmt.toml util tests relay partner-chains COMPACTC_VERSION .
922977
923978 # These tests use a mock runtime (MockBlock<Test>), not the real WASM runtime.
924- # Debug mode skips LLVM optimization passes, compiling faster than release on free CI runners.
925979 ENV SKIP_WASM_BUILD= 1
926- ENV RUSTFLAGS= "-C debuginfo=1"
927980 COPY .envrc ./bin/.envrc
928981 COPY static/contracts/simple-merkle-tree /test-static/simple-merkle-tree
929982 ENV MIDNIGHT_LEDGER_TEST_STATIC_DIR= /test-static
930983
931- # Run pallet-midnight fixture tests in debug mode (compiles much faster)
984+ # --release so the fingerprints match +test/+build and reuse the shared deps.
932985 WITH DOCKER
933- RUN MIDNIGHT_LEDGER_EXPERIMENTAL= 1 cargo nextest r --profile ci --locked \
986+ RUN MIDNIGHT_LEDGER_EXPERIMENTAL= 1 cargo nextest r --profile ci --release -- locked \
934987 -E 'test(/^tests::test_get_contract_state$/) | test(/^tests::test_send_mn_transaction$/) | test(/^tests::test_validation_works$/)'
935988 END
936989 # RUN cargo llvm-cov report --html --release --output-dir /test-artifacts-pallet-fixtures-$NATIVEARCH/html
@@ -968,7 +1021,9 @@ build-test-toolkit:
9681021 # Test
9691022 RUN mkdir /test-artifacts-toolkit
9701023 # Compile the tests to go as fast as possible on this machine:
971- ENV RUSTFLAGS= "-C target-cpu=native -C debuginfo=1"
1024+ # target-cpu=native removed: non-portable codegen under a fixed fingerprint is
1025+ # unsound once build artifacts are shared across machines.
1026+ ENV RUSTFLAGS= "-C debuginfo=1"
9721027 COPY .envrc ./bin/.envrc
9731028 COPY static/contracts/simple-merkle-tree /test-static/simple-merkle-tree
9741029 ENV MIDNIGHT_LEDGER_TEST_STATIC_DIR= /test-static
@@ -1023,31 +1078,69 @@ test-toolkit:
10231078 END
10241079 SAVE ARTIFACT /artifacts AS LOCAL ./test-artifacts-toolkit
10251080
1081+ # cache-probe (LOCALLY): does the named deps image already exist in the registry?
1082+ # Runs on the host so it uses host docker + registry creds. Emits hit.txt
1083+ # ("true"/"false"). Generic over flavor — the caller passes the full DEPS_TAG.
1084+ # Not logged in / no creds → inspect fails → "false" → the caller cooks locally.
1085+ cache-probe :
1086+ LOCALLY
1087+ ARG DEPS_TAG
1088+ RUN docker manifest inspect "$DEPS_CACHE_REPO:$DEPS_TAG" > /dev/null 2> &1 \
1089+ && echo true > "/tmp/deps-hit-$DEPS_TAG" \
1090+ || echo false > "/tmp/deps-hit-$DEPS_TAG"
1091+ SAVE ARTIFACT "/tmp/deps-hit-$DEPS_TAG" hit.txt
1092+
1093+ # cook-build pre-compiles every third-party dependency for the release (build)
1094+ # flavor into a content-addressed image. The codegen env here is baked into the
1095+ # image, so both the pull and the cook path expose identical CC/CXX to the
1096+ # downstream workspace build. Consumed by +build-prepare on a cache miss.
1097+ cook-build :
1098+ FROM +prep-no-copy
1099+ ENV CC= clang
1100+ ENV CXX= clang++
1101+ ENV CARGO_PROFILE_RELEASE_BUILD_OVERRIDE_DEBUG= true
1102+ COPY +planner/recipe.json /recipe.json
1103+ # Deps inherit [profile.release] (opt-3, line-tables) from chef's reconstructed
1104+ # skeleton — matching what +build compiles the workspace crates with, so cargo
1105+ # reuses them instead of rebuilding.
1106+ RUN cargo chef cook --release --recipe-path /recipe.json
1107+ ARG DEPS_TAG
1108+ IF [ "$ALLOW_CACHE_PUSH" = "true" ]
1109+ SAVE IMAGE --push $DEPS_CACHE_REPO :$DEPS_TAG
1110+ END
1111+
10261112build-prepare :
1027- # NOTE: This just uses recipe.json - no src files!
1113+ # Resolve the release dependency cache: pull the pre-cooked image if it exists,
1114+ # else cook it locally (+cook-build). The cook is the expensive layer; this
1115+ # shares it across machines/CI runs. recipe.json + rust-toolchain.toml are used
1116+ # only to compute the tag — discarded when we re-FROM the chosen base below.
10281117 FROM +prep-no-copy
1029- # TODO: re-enable when chef is improved.
1030- # COPY +planner/recipe.json /recipe.json
1031- # CACHE --sharing shared --id cargo-git /usr/local/cargo/git
1032- # CACHE --sharing shared --id cargo-reg /usr/local/cargo/registry
1118+ COPY +planner/recipe.json /recipe.json
1119+ COPY rust-toolchain.toml /rust-toolchain.toml
1120+ ARG NATIVEARCH
1121+ ARG RUST_VERSION= $(grep '^channel' /rust-toolchain.toml | sed 's/.*"\( .*\) ".*/\1 /' )
1122+ ARG RECIPE_HASH= $(sha256sum /recipe.json | cut -c1-16 )
1123+ ARG DEPS_TAG= ${RUST_VERSION }-${NATIVEARCH }-build- ${RECIPE_HASH }
1124+ COPY (+cache-probe/hit.txt --DEPS_TAG = $DEPS_TAG ) /deps-hit.txt
1125+ ARG DEPS_HIT= $(cat /deps-hit.txt)
1126+ IF [ "$DEPS_HIT" = "true" ]
1127+ FROM $DEPS_CACHE_REPO:$DEPS_TAG
1128+ ELSE
1129+ FROM +cook-build --DEPS_TAG = $DEPS_TAG
1130+ END
10331131
1132+ # Per-commit, affects only the node crate's build script — kept out of the cook
1133+ # so it doesn't bust the deps cache every commit.
10341134 ARG EARTHLY_GIT_SHORT_HASH
10351135 ENV SUBSTRATE_CLI_GIT_COMMIT_HASH= $EARTHLY_GIT_SHORT_HASH
1036- ENV CARGO_PROFILE_RELEASE_BUILD_OVERRIDE_DEBUG= true
1037- ENV CC= clang
1038- ENV CXX= clang++
1039-
1040- # Build dependencies - this is the caching Docker layer!
1041- # TODO: re-enable when chef is improved.
1042- # RUN SKIP_WASM_BUILD=1 cargo chef cook --release --workspace --all-targets --recipe-path /recipe.json
10431136
10441137# build creates production ready binaries
10451138build :
10461139 FROM +build-prepare
10471140 # CACHE --sharing shared --id cargo-git /usr/local/cargo/git
10481141 # CACHE --sharing shared --id cargo-reg /usr/local/cargo/registry
10491142 # CACHE /target
1050- COPY --keep-ts -- dir Cargo.lock Cargo.toml docs .sqlx \
1143+ COPY --dir Cargo.lock Cargo.toml docs .sqlx \
10511144 ledger node pallets primitives metadata res runtime util tests relay partner-chains COMPACTC_VERSION .
10521145
10531146 ARG NATIVEARCH
@@ -1071,11 +1164,18 @@ build:
10711164 && mv /target/release/aiken-deployer /artifacts-$NATIVEARCH \
10721165 && cp /target/release/wbuild/midnight-node-runtime/*.wasm /artifacts-$NATIVEARCH /midnight-node-runtime/
10731166
1167+ # zlib-compress the (our-code-only) line-tables debug in the shipped ELF binaries:
1168+ # ~1/3 the size, file:line backtraces preserved (verified — runtime panic traces
1169+ # resolve from SHF_COMPRESSED sections). Post-link file op, no build-cache impact.
1170+ RUN for b in midnight-node midnight-node-toolkit aiken-deployer; do \
1171+ objcopy --compress-debug-sections = zlib "/artifacts-$NATIVEARCH/$b" ; \
1172+ done
1173+
10741174 SAVE ARTIFACT /artifacts-$NATIVEARCH AS LOCAL artifacts
10751175
10761176build-benchmarks :
10771177 FROM +build-prepare
1078- COPY --keep-ts -- dir Cargo.lock Cargo.toml docs .sqlx \
1178+ COPY --dir Cargo.lock Cargo.toml docs .sqlx \
10791179 ledger node pallets primitives metadata relay res runtime util tests partner-chains .
10801180
10811181 ARG NATIVEARCH
@@ -1085,7 +1185,8 @@ build-benchmarks:
10851185 cargo auditable build --workspace --locked --release --features runtime-benchmarks
10861186
10871187 RUN mkdir -p /artifacts-$NATIVEARCH \
1088- && mv /target/release/midnight-node /artifacts-$NATIVEARCH /midnight-node-benchmarks
1188+ && mv /target/release/midnight-node /artifacts-$NATIVEARCH /midnight-node-benchmarks \
1189+ && objcopy --compress-debug-sections = zlib "/artifacts-$NATIVEARCH/midnight-node-benchmarks"
10891190
10901191 SAVE ARTIFACT /artifacts-$NATIVEARCH AS LOCAL artifacts-benchmarks
10911192
@@ -1494,7 +1595,7 @@ local-env-e2e:
14941595 # Defaults reproduce the legacy single-tenant ports.
14951596 ARG E2E_NODE_RPC_PORT= 9933
14961597 ARG E2E_OGMIOS_PORT= 1337
1497- COPY --keep-ts -- dir Cargo.lock Cargo.toml docs .sqlx \
1598+ COPY --dir Cargo.lock Cargo.toml docs .sqlx \
14981599 ledger node pallets primitives metadata res runtime util tests relay partner-chains local-environment scripts .
14991600 COPY static/contracts/simple-merkle-tree /test-static/simple-merkle-tree
15001601 ENV MIDNIGHT_LEDGER_TEST_STATIC_DIR= /test-static
0 commit comments