upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/Makefile
blob: 9f97b730acf19de7b9336fe6da3d1408321aff57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# Bitflash — top-level build
#
#   make linux    build Bitflash-*-x86_64.AppImage
#   make windows  build Bitflash-*-windows.zip (from MSYS2 UCRT64)
#   make windows-tor build Bitflash-*-windows-with-tor.zip
#   make tests    build and run standalone unit tests
#   make checksums create SHA256SUMS for release assets
#   make verify-release TAG=v1.2.13
#   make clean    remove build artifacts

ROOT    := $(shell pwd)
NPROC   := $(shell nproc 2>/dev/null || echo 2)
SUDO    := $(shell [ "$$(id -u)" = "0" ] && echo "" || echo "sudo")
# Not "1.2.19". This tree is upstream v1.2.19 plus our own hardening commits and
# a hand-merged payout ledger, so a binary built here must not be mistakable for
# the upstream release of that number -- it names every release artifact.
VERSION := 1.2.19+sec

# ---- Pinned third-party sources -------------------------------------------
#
# These were `git clone --depth 1 <url>` with no revision, which resolves to
# whatever the default branch happens to point at the moment the build runs.
# For a dependency that only had to link, that is untidy. For these two it is
# not:
#
#   RandomX is the proof of work. Its master is not frozen -- v2.0 (Mar 2026)
#   changed the algorithm -- so two builds of the same Bitflash commit, made a
#   few weeks apart, can compute different hashes for the same header. That is
#   not a supply-chain worry, it is a chain split arriving as a build artifact,
#   with no version recorded anywhere to explain it afterwards.
#
#   libsecp256k1 is signature verification, i.e. the rule deciding who may
#   spend. Whatever is on master on the day of the build is what enforces it.
#
# Pinned to full commit ids, not tags: a tag is a mutable pointer, and `git
# checkout <sha>` is the only form here that verifies what it fetched (git
# resolves the object by its own hash). Bump deliberately, and rebuild and
# resync before shipping the result.
#
# RandomX pin is the commit this tree has been building and syncing against
# (post-v2.0.1 master, 2026-05-24) -- identical to upstream's pin.
#
# libsecp256k1 is pinned to upstream v1.2.18's commit rather than the one this
# fork carried, so signature validation matches the binaries the rest of the
# network runs. Consensus code must not differ from the network by accident.
# There must be exactly ONE assignment of each of these variables in this file:
# upstream defines them near the top too, and GNU Make takes the last `:=`, so
# a second block silently decides the build.
SECP256K1_REPO   := https://github.com/bitcoin-core/secp256k1
SECP256K1_COMMIT := 7fecac74aed8e1fd9078380d67dd04663705c989
RANDOMX_REPO     := https://github.com/tevador/RandomX
RANDOMX_COMMIT   := 1e9d4b2df63fa6edf46b06789486e23c0fcaa55a

# appimagetool came from the "continuous" release, a tag that is moved in place
# on every upstream push, fetched over the network and executed. Pinned to a
# numbered release and checked by digest before it is allowed to run.
APPIMAGETOOL_URL    := https://github.com/AppImage/appimagetool/releases/download/1.9.1/appimagetool-x86_64.AppImage
APPIMAGETOOL_SHA256 := ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0

# ---- Linux ----------------------------------------------------------------

linux: deps-linux
	$(MAKE) -C src -f Makefile -j$(NPROC)
	strip src/bitflash
	$(MAKE) -f Makefile appimage
	$(MAKE) -f Makefile linux-node

# Headless node, no ImGui/GLFW/OpenGL. The GUI build needs libGL present at load
# time even when started with -nogui -- the dynamic loader resolves everything
# before main() runs, so the flag comes far too late. On a clean server, which is
# where a node most naturally lives, that is a hard failure. This binary has no
# such dependency and needs no FUSE either, so it drops onto a VPS and runs.
linux-node: deps-linux
	$(MAKE) -C src -f Makefile bitflash-node -j$(NPROC)
	strip src/bitflash-node
	cp src/bitflash-node bitflash-node-$(VERSION)-x86_64
	@echo "Built: bitflash-node-$(VERSION)-x86_64"

deps-linux: deps-apt deps-secp256k1 deps-randomx

deps-apt:
	@if command -v apt-get >/dev/null 2>&1; then \
	  $(SUDO) apt-get install -y build-essential cmake git pkg-config autoconf \
	    libtool libssl-dev libdb5.3++-dev libsodium-dev nlohmann-json3-dev \
	    libboost-system-dev libglfw3-dev libgl-dev python3-pil clang; \
	else \
	  echo "Not an apt system — install: g++ cmake git autoconf libtool"; \
	  echo "  libssl libdb++ libsodium nlohmann-json boost glfw3 opengl python3-pil"; \
	fi

deps-secp256k1:
	@if [ ! -f /usr/local/lib/libsecp256k1.a ]; then \
	  echo "==> building libsecp256k1"; \
	  rm -rf $(ROOT)/secp256k1-build; \
	  git init -q $(ROOT)/secp256k1-build; \
	  cd $(ROOT)/secp256k1-build && \
	  git remote add origin $(SECP256K1_REPO) && \
	  git fetch -q --depth 1 origin $(SECP256K1_COMMIT) && \
	  git checkout -q --detach FETCH_HEAD && \
	  test "$$(git rev-parse HEAD)" = "$(SECP256K1_COMMIT)" && \
	  echo "==> libsecp256k1 pinned at $(SECP256K1_COMMIT)" && \
	  cd $(ROOT)/secp256k1-build && ./autogen.sh && \
	  ./configure --enable-module-schnorrsig --enable-module-extrakeys \
	    --disable-shared --with-pic --disable-benchmark --disable-tests && \
	  make -j$(NPROC) && $(SUDO) make install && $(SUDO) ldconfig; \
	  echo "==> libsecp256k1 done"; \
	else \
	  echo "==> libsecp256k1 already installed"; \
	fi

deps-randomx:
	@if [ ! -f $(HOME)/RandomX/build/librandomx.a ]; then \
	  echo "==> building RandomX"; \
	  rm -rf $(HOME)/RandomX; \
	  git init -q $(HOME)/RandomX; \
	  cd $(HOME)/RandomX && \
	  git remote add origin $(RANDOMX_REPO) && \
	  git fetch -q --depth 1 origin $(RANDOMX_COMMIT) && \
	  git checkout -q --detach FETCH_HEAD && \
	  test "$$(git rev-parse HEAD)" = "$(RANDOMX_COMMIT)" && \
	  echo "==> RandomX pinned at $(RANDOMX_COMMIT)" && \
	  mkdir -p $(HOME)/RandomX/build; \
	  cd $(HOME)/RandomX/build && cmake .. -DCMAKE_BUILD_TYPE=Release && \
	  make -j$(NPROC) randomx; \
	  echo "==> RandomX done"; \
	else \
	  echo "==> RandomX already built"; \
	fi

# APPDIR and the tool both used fixed paths under /tmp, on a directory every
# local account can write. `[ ! -x /tmp/appimagetool ]` means an executable
# already sitting at that name is taken as the tool and run, so anyone with a
# shell on the build machine could have put one there first and had it execute
# as whoever ran make; `rm -rf /tmp/bitflash.AppDir` then mkdir is the same
# problem one step later, through symlinks. Both now live under the build tree,
# which the build already owns.
APPDIR       := $(ROOT)/build/bitflash.AppDir
APPIMAGETOOL := $(ROOT)/build/appimagetool

appimage: src/bitflash
	@echo "==> building AppImage"
	@mkdir -p $(ROOT)/build
	@if [ ! -x "$(APPIMAGETOOL)" ]; then \
	  echo "  fetching appimagetool"; \
	  wget -q "$(APPIMAGETOOL_URL)" -O "$(APPIMAGETOOL).tmp" || \
	    { echo "  ERROR: appimagetool download failed"; rm -f "$(APPIMAGETOOL).tmp"; exit 1; }; \
	  echo "$(APPIMAGETOOL_SHA256)  $(APPIMAGETOOL).tmp" | sha256sum -c - >/dev/null 2>&1 || \
	    { echo "  ERROR: appimagetool digest mismatch, refusing to run it"; \
	      echo "         expected $(APPIMAGETOOL_SHA256)"; \
	      echo "         got      $$(sha256sum "$(APPIMAGETOOL).tmp" | cut -d" " -f1)"; \
	      rm -f "$(APPIMAGETOOL).tmp"; exit 1; }; \
	  chmod +x "$(APPIMAGETOOL).tmp" && mv "$(APPIMAGETOOL).tmp" "$(APPIMAGETOOL)"; \
	fi
	@rm -rf $(APPDIR)
	@mkdir -p $(APPDIR)/usr/bin \
	          $(APPDIR)/usr/lib \
	          $(APPDIR)/usr/share/applications \
	          $(APPDIR)/usr/share/icons/hicolor/256x256/apps
	@cp src/bitflash $(APPDIR)/usr/bin/bitflash
	@printf '#!/bin/sh\nHERE="$$(dirname "$$(readlink -f "$$0")")"\nexport LD_LIBRARY_PATH="$$HERE/usr/lib:$$LD_LIBRARY_PATH"\nexec "$$HERE/usr/bin/bitflash" "$$@"\n' \
	  > $(APPDIR)/AppRun && chmod +x $(APPDIR)/AppRun
	@printf '[Desktop Entry]\nName=Bitflash\nExec=bitflash\nIcon=bitflash\nType=Application\nCategories=Finance;\n' \
	  > $(APPDIR)/bitflash.desktop
	@cp $(APPDIR)/bitflash.desktop \
	    $(APPDIR)/usr/share/applications/
	@APPDIR=$(APPDIR) python3 -c "\
import os; \
from PIL import Image; \
d = os.environ['APPDIR']; \
ico = Image.open('src/rc/bitcoin.ico'); \
img = ico.convert('RGBA'); \
img.save(d + '/bitflash.png'); \
import shutil; shutil.copy(d + '/bitflash.png', \
d + '/usr/share/icons/hicolor/256x256/apps/bitflash.png')"
	@for lib in libsodium.so.23 libdb_cxx-5.3.so libglfw.so.3; do \
	  path=$$(ldconfig -p | grep " $$lib " | awk '{print $$NF}' | head -1); \
	  [ -z "$$path" ] && path=$$(find /usr/lib /lib -name "$$lib" 2>/dev/null | head -1); \
	  [ -n "$$path" ] && cp -L "$$path" $(APPDIR)/usr/lib/ && echo "  bundled $$lib" || echo "  missing $$lib"; \
	done
	@ARCH=x86_64 $(APPIMAGETOOL) --no-appstream $(APPDIR) \
	  $(ROOT)/Bitflash-$(VERSION)-x86_64.AppImage 2>&1 | grep -E "^Built|^Error" || true
	@echo "Built: Bitflash-$(VERSION)-x86_64.AppImage"

# ---- Windows (MSYS2 UCRT64) -----------------------------------------------

deps-windows:
	pacman -S --noconfirm --needed \
	  mingw-w64-ucrt-x86_64-gcc \
	  mingw-w64-ucrt-x86_64-make \
	  mingw-w64-ucrt-x86_64-glfw \
	  mingw-w64-ucrt-x86_64-openssl \
	  mingw-w64-ucrt-x86_64-db \
	  mingw-w64-ucrt-x86_64-libsodium \
	  mingw-w64-ucrt-x86_64-nlohmann-json \
	  mingw-w64-ucrt-x86_64-boost \
	  mingw-w64-ucrt-x86_64-cmake \
	  autoconf automake libtool
	@if [ ! -f deps/lib/libsecp256k1.a ]; then \
	  rm -rf secp256k1-build; \
	  git init -q secp256k1-build; \
	  cd secp256k1-build && \
	  git remote add origin $(SECP256K1_REPO) && \
	  git fetch -q --depth 1 origin $(SECP256K1_COMMIT) && \
	  git checkout -q --detach FETCH_HEAD && \
	  test "$$(git rev-parse HEAD)" = "$(SECP256K1_COMMIT)" && \
	  echo "==> secp256k1 pinned at $(SECP256K1_COMMIT)" && \
	  cd $(ROOT)/secp256k1-build && ./autogen.sh && \
	  ./configure --prefix=$(ROOT)/deps \
	    --enable-module-schnorrsig --enable-module-extrakeys \
	    --disable-shared --with-pic --disable-benchmark --disable-tests && \
	  make install; \
	  echo "==> secp256k1 done"; \
	else \
	  echo "==> secp256k1 already built"; \
	fi
	@if [ ! -f RandomX/build/librandomx.a ]; then \
	  rm -rf RandomX; \
	  git init -q RandomX; \
	  cd RandomX && \
	  git remote add origin $(RANDOMX_REPO) && \
	  git fetch -q --depth 1 origin $(RANDOMX_COMMIT) && \
	  git checkout -q --detach FETCH_HEAD && \
	  test "$$(git rev-parse HEAD)" = "$(RANDOMX_COMMIT)" && \
	  echo "==> RandomX pinned at $(RANDOMX_COMMIT)" && \
	  mkdir -p $(ROOT)/RandomX/build; \
	  cd $(ROOT)/RandomX/build && cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release && \
	  make randomx; \
	  echo "==> RandomX done"; \
	else \
	  echo "==> RandomX already built"; \
	fi

windows: deps-windows
	cd src && make -f makefile.mingw
	@rm -rf Bitflash-$(VERSION)-windows
	@mkdir -p Bitflash-$(VERSION)-windows
	@cp src/bitflash.exe Bitflash-$(VERSION)-windows/Bitflash.exe
	@ldd src/bitflash.exe | grep ucrt64 | awk '{print $$3}' | \
	  xargs -I{} cp {} Bitflash-$(VERSION)-windows/ 2>/dev/null || true
	@zip -r Bitflash-$(VERSION)-windows.zip Bitflash-$(VERSION)-windows/
	@echo "Built: Bitflash-$(VERSION)-windows.zip"

windows-tor: windows
	./scripts/package-windows-tor.sh

# ---- Clean ----------------------------------------------------------------

clean:
	$(MAKE) -C src -f Makefile clean 2>/dev/null || true
	cd src && make -f makefile.mingw clean 2>/dev/null || true
	rm -f Bitflash-*.AppImage Bitflash-*.zip
	rm -rf Bitflash-*-windows build

tests:
	$(MAKE) -C src -f Makefile tests

fuzz-net-message-smoke: deps-linux
	$(MAKE) -C src -f Makefile fuzz-net-message-smoke

fuzz-script-smoke: deps-linux
	$(MAKE) -C src -f Makefile fuzz-script-smoke

checksums:
	./scripts/make-release-checksums.sh

sign-checksums:
	./scripts/make-release-checksums.sh --sign $(if $(KEY),--local-user $(KEY),)

verify-release:
	./scripts/verify-release.sh $(if $(TAG),$(TAG),latest)

.PHONY: linux windows windows-tor clean appimage \
        tests fuzz-net-message-smoke fuzz-script-smoke checksums sign-checksums verify-release \
        deps-linux deps-windows deps-apt deps-secp256k1 deps-randomx