Skip to content

Commit 1c49435

Browse files
authored
Improved reproducible builds (#806)
1 parent 6784328 commit 1c49435

File tree

6 files changed

+144
-33
lines changed

6 files changed

+144
-33
lines changed

.github/workflows/release.yaml

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ on:
3333
jobs:
3434
extract-version:
3535
name: Extract version
36-
runs-on: warp-ubuntu-2404-x64-16x
36+
runs-on: warp-ubuntu-2404-x64-2x
3737
outputs:
3838
VERSION: ${{ steps.extract_version.outputs.VERSION }}
3939
steps:
@@ -82,62 +82,60 @@ jobs:
8282
- ${{ github.event.inputs.features || '' }}
8383

8484
steps:
85-
- name: Install dependencies
85+
- uses: actions/checkout@v4
86+
87+
- name: Set up Docker Buildx
88+
uses: docker/setup-buildx-action@v3
89+
90+
- name: Install rust
8691
run: |
87-
sudo apt-get update
88-
sudo apt-get install -y \
89-
build-essential \
90-
cmake \
91-
curl \
92-
git \
93-
libclang-dev \
94-
libssl-dev \
95-
pkg-config \
96-
protobuf-compiler
9792
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
9893
99-
- uses: actions/checkout@v4
100-
101-
- name: Build
94+
- name: Build reproducible binary with Docker
10295
run: |
103-
FEATURES=${{ matrix.features }} make build
104-
VERSION=${{ needs.extract-version.outputs.VERSION }} make build-deb
96+
RUST_TOOLCHAIN=$(rustc --version | cut -d' ' -f2)
97+
docker build \
98+
--build-arg "RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" \
99+
--build-arg "FEATURES=${{ matrix.features }}" \
100+
--build-arg "VERSION=${{ needs.extract-version.outputs.VERSION }}" \
101+
-f docker/Dockerfile.reproducible -t rbuilder:release \
102+
--output type=local,dest=./target .
105103
106104
- name: Upload rbuilder artifact
107105
uses: actions/upload-artifact@v4
108106
with:
109107
name: rbuilder-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }}
110-
path: target/${{ matrix.configs.target }}/${{ matrix.configs.profile }}/rbuilder
108+
path: target/${{ matrix.configs.profile }}/rbuilder
111109

112110
- name: Upload rbuilder-operator artifact
113111
uses: actions/upload-artifact@v4
114112
with:
115113
name: rbuilder-operator-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }}
116-
path: target/${{ matrix.configs.target }}/${{ matrix.configs.profile }}/rbuilder-operator
114+
path: target/${{ matrix.configs.profile }}/rbuilder-operator
117115

118116
- name: Upload reth-rbuilder artifact
119117
uses: actions/upload-artifact@v4
120118
with:
121119
name: reth-rbuilder-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }}
122-
path: target/${{ matrix.configs.target }}/${{ matrix.configs.profile }}/reth-rbuilder
120+
path: target/${{ matrix.configs.profile }}/reth-rbuilder
123121

124122
- name: Upload bid-scraper artifact
125123
uses: actions/upload-artifact@v4
126124
with:
127125
name: bid-scraper-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }}
128-
path: target/${{ matrix.configs.target }}/${{ matrix.configs.profile }}/bid-scraper
126+
path: target/${{ matrix.configs.profile }}/bid-scraper
129127

130128
- name: Upload rbuilder-rebalancer artifact
131129
uses: actions/upload-artifact@v4
132130
with:
133131
name: rbuilder-rebalancer-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }}
134-
path: target/${{ matrix.configs.target }}/${{ matrix.configs.profile }}/rbuilder-rebalancer
132+
path: target/${{ matrix.configs.profile }}/rbuilder-rebalancer
135133

136134
- name: Upload *.deb packages
137135
uses: actions/upload-artifact@v4
138136
with:
139137
name: deb-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }}
140-
path: target/${{ matrix.configs.target }}/debian/*.deb
138+
path: target/debian/*.deb
141139

142140

143141
draft-release:

.github/workflows/reprotest.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: reproducible-build-test
2+
3+
on:
4+
workflow_dispatch: {}
5+
schedule:
6+
- cron: "0 1 */2 * *"
7+
8+
jobs:
9+
build:
10+
name: build reproducible binaries
11+
runs-on: ${{ matrix.runner }}
12+
strategy:
13+
matrix:
14+
include:
15+
- runner: warp-ubuntu-2404-x64-32x
16+
machine: machine-1
17+
- runner: warp-ubuntu-2204-x64-32x
18+
machine: machine-2
19+
steps:
20+
- uses: actions/checkout@v5
21+
22+
- name: Set up Docker Buildx
23+
uses: docker/setup-buildx-action@v3
24+
25+
- name: Install rust
26+
run: |
27+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
28+
29+
- name: Build reproducible binary with Docker
30+
run: |
31+
RUST_TOOLCHAIN=$(rustc --version | cut -d' ' -f2)
32+
docker build \
33+
--build-arg "RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" \
34+
-f docker/Dockerfile.reproducible -t rbuilder:release \
35+
--output type=local,dest=./target .
36+
37+
- name: Calculate SHA256
38+
id: sha256
39+
run: |
40+
sha256sum target/reproducible/{rbuilder-operator,rbuilder-rebalancer} > checksums.sha256
41+
echo "Binaries SHA256 on ${{ matrix.machine }}: $(cat checksums.sha256)"
42+
- name: Upload the hash
43+
uses: actions/upload-artifact@v4
44+
with:
45+
name: checksums-${{ matrix.machine }}
46+
path: |
47+
checksums.sha256
48+
retention-days: 1
49+
50+
compare:
51+
name: compare reproducible binaries
52+
needs: build
53+
runs-on: ubuntu-latest
54+
steps:
55+
- name: Download artifacts from machine-1
56+
uses: actions/download-artifact@v4
57+
with:
58+
name: checksums-machine-1
59+
path: machine-1/
60+
- name: Download artifacts from machine-2
61+
uses: actions/download-artifact@v4
62+
with:
63+
name: checksums-machine-2
64+
path: machine-2/
65+
- name: Compare SHA256 hashes
66+
run: |
67+
echo "=== SHA256 Comparison ==="
68+
echo "Machine 1 hashes:"
69+
cat machine-1/checksums.sha256
70+
echo "Machine 2 hashes:"
71+
cat machine-2/checksums.sha256
72+
73+
if cmp -s machine-1/checksums.sha256 machine-2/checksums.sha256; then
74+
echo "✅ SUCCESS: Binaries are identical (reproducible build verified)"
75+
else
76+
echo "❌ FAILURE: Binaries differ (reproducible build failed)"
77+
exit 1
78+
fi

Makefile

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ ifeq ($(IS_X86_64),1)
6161
BUILD_ENV = SOURCE_DATE_EPOCH=$(SOURCE_DATE) \
6262
RUSTFLAGS="${RUST_BUILD_FLAGS}" \
6363
LC_ALL=${LOCALE_VAL} \
64-
TZ=${TZ_VAL}
64+
TZ=${TZ_VAL} \
65+
JEMALLOC_OVERRIDE=/usr/lib/x86_64-linux-gnu/libjemalloc.a
6566
else
6667
# Non-x86_64: Use release profile without reproducible build flags
6768
BUILD_PROFILE = release
@@ -72,19 +73,19 @@ endif
7273

7374
.PHONY: build
7475
build: ## Build (release version)
75-
$(BUILD_ENV) cargo build --features "$(FEATURES)" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --profile $(BUILD_PROFILE) --workspace
76+
$(BUILD_ENV) cargo build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --profile $(BUILD_PROFILE) --workspace
7677

7778
.PHONY: build-bid-scraper
7879
build-bid-scraper: ## Build the bid-scraper binary (release version)
7980
$(BUILD_ENV) cargo build --features "$(FEATURES)" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin bid-scraper --profile $(BUILD_PROFILE)
8081

8182
.PHONY: build-rbuilder-operator
8283
build-rbuilder-operator: ## Build the rbuilder-operator binary (release version)
83-
$(BUILD_ENV) cargo build --features "$(FEATURES)" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-operator --profile $(BUILD_PROFILE)
84+
$(BUILD_ENV) cargo build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-operator --profile $(BUILD_PROFILE)
8485

8586
.PHONY: build-rbuilder-rebalancer
8687
build-rbuilder-rebalancer: ## Build the rbuilder-rebalancer binary (release version)
87-
$(BUILD_ENV) cargo build --features "$(FEATURES)" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-rebalancer --profile $(BUILD_PROFILE)
88+
$(BUILD_ENV) cargo build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-rebalancer --profile $(BUILD_PROFILE)
8889

8990
.PHONY: build-dev
9091
build-dev: ## Build (debug version)
@@ -94,35 +95,51 @@ build-dev: ## Build (debug version)
9495
docker-image-rbuilder: ## Build a rbuilder Docker image
9596
docker build --platform linux/amd64 --target rbuilder-runtime --build-arg FEATURES="$(FEATURES)" -t rbuilder -f docker/Dockerfile.rbuilder .
9697

97-
.PHONE: docker-image-rbuilder-operator
98-
docker build --platform linux/amd64 --target rbuilder-runtime --build-arg FEATURES="$(FEATURES)" -t rbuilder -f docker/Dockerfile.rbuilder-operator .
98+
.PHONY: docker-image-rbuilder-operator
99+
docker-image-rbuilder-operator: ## Build a rbuilder-operator Docker image
100+
docker build --platform linux/amd64 --target rbuilder-runtime --build-arg FEATURES="$(FEATURES) jemalloc-unprefixed" -t rbuilder-operator -f docker/Dockerfile.rbuilder-operator .
99101

100102
.PHONY: docker-image-test-relay
101103
docker-image-test-relay: ## Build a test relay Docker image
102104
docker build --platform linux/amd64 --target test-relay-runtime --build-arg FEATURES="$(FEATURES)" . -t test-relay
103105

104106
##@ Debian Packages
105107

108+
# Define binary paths for smart dependencies
109+
BID_SCRAPER_BIN := target/$(if $(BUILD_TARGET),$(BUILD_TARGET)/)$(BUILD_PROFILE)/bid-scraper
110+
RBUILDER_OPERATOR_BIN := target/$(if $(BUILD_TARGET),$(BUILD_TARGET)/)$(BUILD_PROFILE)/rbuilder-operator
111+
RBUILDER_REBALANCER_BIN := target/$(if $(BUILD_TARGET),$(BUILD_TARGET)/)$(BUILD_PROFILE)/rbuilder-rebalancer
112+
106113
.PHONY: install-cargo-deb
107114
install-cargo-deb:
108115
@command -v cargo-deb >/dev/null 2>&1 || cargo install [email protected] --locked
109116

117+
# Build individual binaries only if they don't exist - delegate to existing build targets
118+
$(BID_SCRAPER_BIN): build-bid-scraper
119+
@# Binary built by build-bid-scraper target
120+
121+
$(RBUILDER_OPERATOR_BIN): build-rbuilder-operator
122+
@# Binary built by build-rbuilder-operator target
123+
124+
$(RBUILDER_REBALANCER_BIN): build-rbuilder-rebalancer
125+
@# Binary built by build-rbuilder-rebalancer target
126+
110127
.PHONY: build-deb-bid-scraper
111-
build-deb-bid-scraper: install-cargo-deb build-bid-scraper ## Build bid-scraper Debian package
128+
build-deb-bid-scraper: install-cargo-deb $(BID_SCRAPER_BIN) ## Build bid-scraper Debian package
112129
cargo deb --profile $(BUILD_PROFILE) --no-build --no-dbgsym --no-strip \
113130
-p bid-scraper \
114131
$(if $(BUILD_TARGET),--target $(BUILD_TARGET)) \
115132
$(if $(VERSION),--deb-version "1~$(VERSION)")
116133

117134
.PHONY: build-deb-rbuilder-operator
118-
build-deb-rbuilder-operator: install-cargo-deb build-rbuilder-operator ## Build rbuilder-operator Debian package
135+
build-deb-rbuilder-operator: install-cargo-deb $(RBUILDER_OPERATOR_BIN) ## Build rbuilder-operator Debian package
119136
cargo deb --profile $(BUILD_PROFILE) --no-build --no-dbgsym --no-strip \
120137
-p rbuilder-operator \
121138
$(if $(BUILD_TARGET),--target $(BUILD_TARGET)) \
122139
$(if $(VERSION),--deb-version "1~$(VERSION)")
123140

124141
.PHONY: build-deb-rbuilder-rebalancer
125-
build-deb-rbuilder-rebalancer: install-cargo-deb build-rbuilder-rebalancer ## Build rbuilder-rebalancer Debian package
142+
build-deb-rbuilder-rebalancer: install-cargo-deb $(RBUILDER_REBALANCER_BIN) ## Build rbuilder-rebalancer Debian package
126143
cargo deb --profile $(BUILD_PROFILE) --no-build --no-dbgsym --no-strip \
127144
-p rbuilder-rebalancer \
128145
$(if $(BUILD_TARGET),--target $(BUILD_TARGET)) \

crates/rbuilder/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ criterion = { workspace = true, features = ["html_reports", "async_tokio"] }
154154
# TODO: remove?
155155
optimism = []
156156
redact-sensitive = []
157+
jemalloc-unprefixed = ["tikv-jemallocator/unprefixed_malloc_on_supported_platforms"]
157158

158159
[[bench]]
159160
name = "bench_main"

docker/Dockerfile.reproducible

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
ARG RUST_TOOLCHAIN=1.89.0
2+
FROM docker.io/rust:$RUST_TOOLCHAIN-trixie AS builder
3+
4+
ARG FEATURES VERSION
5+
# Switch to snapshot repository
6+
RUN sed -i '/^# http/{N;s|^# \(http[^ ]*\)\nURIs: .*|# \1\nURIs: \1|}' /etc/apt/sources.list.d/debian.sources
7+
RUN apt-get -o Acquire::Check-Valid-Until=false update && \
8+
apt-get install -y \
9+
libjemalloc-dev \
10+
libclang-dev \
11+
protobuf-compiler \
12+
cmake
13+
WORKDIR /build
14+
COPY . .
15+
RUN SOURCE_DATE=1730000000 make build && make build-deb
16+
17+
FROM scratch AS artifacts
18+
COPY --from=builder /build/target/x86_64-unknown-linux-gnu/ /

rust-toolchain.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
[toolchain]
22
channel = "stable"
3-
version = "1.88.0"
43
components = ["rustfmt", "clippy"]

0 commit comments

Comments
 (0)