diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-08-19 18:17:16 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-08-23 04:37:36 +0000 |
| commit | 8f8a02e8ea3358ddec043bb9b1f615d0d1fc9fc7 (patch) | |
| tree | 00f4c8247b2c90825529d03e1272f05251d8d23c | |
| parent | a7744058c49b1ba2c605f9e8380d9c3e8665bbc0 (diff) | |
build: pin the dependencies that decide consensus, and check what we run
The two dependency clones were `git clone --depth 1 <url>` with no
revision, which resolves to whatever the default branch points at the
moment the build happens to run.
For RandomX that is the proof of work. Its master is not frozen -- v2.0
changed the algorithm in March -- so two builds of the same Bitflash
commit, made weeks apart, can hash the same header differently. That is
not a supply-chain worry, it is a chain split delivered as a build
artifact, with no version recorded anywhere to explain it afterwards. For
libsecp256k1 it is signature verification, the rule deciding who may
spend.
Both now fetch a full commit id, which is the only form here that
verifies what it got, since git resolves the object by its own hash. The
RandomX pin is the commit this tree has been building and syncing
against, so today's behaviour is unchanged; secp256k1 is pinned to the
v0.8.0 release commit.
appimagetool came from the "continuous" tag, which upstream moves in
place on every push, fetched over the network and executed unverified.
Pinned to a numbered release and checked by digest before it is allowed
to run.
It also ran from /tmp on a fixed name, guarded by `[ ! -x
/tmp/appimagetool ]` -- an executable already sitting there is taken as
the tool, so any local account could leave one and have it run as
whoever built. The AppDir had the same shape one step later, through
symlinks on the rm -rf. Both moved under the build tree, which the build
already owns, and cleaned by `make clean`.
(cherry picked from commit 664aebca08d17a9dbae12c25f21cd8ef2abe7aa6)
| -rw-r--r-- | Makefile | 108 |
1 files changed, 85 insertions, 23 deletions
| @@ -12,6 +12,40 @@ NPROC := $(shell nproc 2>/dev/null || echo 2) | |||
| 12 | SUDO := $(shell [ "$$(id -u)" = "0" ] && echo "" || echo "sudo") | 12 | SUDO := $(shell [ "$$(id -u)" = "0" ] && echo "" || echo "sudo") |
| 13 | VERSION := 1.2.15 | 13 | VERSION := 1.2.15 |
| 14 | 14 | ||
| 15 | # ---- Pinned third-party sources ------------------------------------------- | ||
| 16 | # | ||
| 17 | # These were `git clone --depth 1 <url>` with no revision, which resolves to | ||
| 18 | # whatever the default branch happens to point at the moment the build runs. | ||
| 19 | # For a dependency that only had to link, that is untidy. For these two it is | ||
| 20 | # not: | ||
| 21 | # | ||
| 22 | # RandomX is the proof of work. Its master is not frozen -- v2.0 (Mar 2026) | ||
| 23 | # changed the algorithm -- so two builds of the same Bitflash commit, made a | ||
| 24 | # few weeks apart, can compute different hashes for the same header. That is | ||
| 25 | # not a supply-chain worry, it is a chain split arriving as a build artifact, | ||
| 26 | # with no version recorded anywhere to explain it afterwards. | ||
| 27 | # | ||
| 28 | # libsecp256k1 is signature verification, i.e. the rule deciding who may | ||
| 29 | # spend. Whatever is on master on the day of the build is what enforces it. | ||
| 30 | # | ||
| 31 | # Pinned to full commit ids, not tags: a tag is a mutable pointer, and `git | ||
| 32 | # checkout <sha>` is the only form here that verifies what it fetched (git | ||
| 33 | # resolves the object by its own hash). Bump deliberately, and rebuild and | ||
| 34 | # resync before shipping the result. | ||
| 35 | # | ||
| 36 | # RandomX pin is the commit this tree has been building and syncing against | ||
| 37 | # (post-v2.0.1 master, 2026-05-24) -- chosen to change nothing today. | ||
| 38 | SECP256K1_REPO := https://github.com/bitcoin-core/secp256k1 | ||
| 39 | SECP256K1_COMMIT := 6e2c8bc4ecdc6e71dbe7a368f360d8d453ce435d | ||
| 40 | RANDOMX_REPO := https://github.com/tevador/RandomX | ||
| 41 | RANDOMX_COMMIT := 1e9d4b2df63fa6edf46b06789486e23c0fcaa55a | ||
| 42 | |||
| 43 | # appimagetool came from the "continuous" release, a tag that is moved in place | ||
| 44 | # on every upstream push, fetched over the network and executed. Pinned to a | ||
| 45 | # numbered release and checked by digest before it is allowed to run. | ||
| 46 | APPIMAGETOOL_URL := https://github.com/AppImage/appimagetool/releases/download/1.9.1/appimagetool-x86_64.AppImage | ||
| 47 | APPIMAGETOOL_SHA256 := ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0 | ||
| 48 | |||
| 15 | # ---- Linux ---------------------------------------------------------------- | 49 | # ---- Linux ---------------------------------------------------------------- |
| 16 | 50 | ||
| 17 | linux: deps-linux | 51 | linux: deps-linux |
| @@ -47,8 +81,12 @@ deps-secp256k1: | |||
| 47 | @if [ ! -f /usr/local/lib/libsecp256k1.a ]; then \ | 81 | @if [ ! -f /usr/local/lib/libsecp256k1.a ]; then \ |
| 48 | echo "==> building libsecp256k1"; \ | 82 | echo "==> building libsecp256k1"; \ |
| 49 | rm -rf $(ROOT)/secp256k1-build; \ | 83 | rm -rf $(ROOT)/secp256k1-build; \ |
| 50 | git clone --depth 1 https://github.com/bitcoin-core/secp256k1 $(ROOT)/secp256k1-build; \ | 84 | git init -q $(ROOT)/secp256k1-build; \ |
| 51 | cd $(ROOT)/secp256k1-build && ./autogen.sh && \ | 85 | cd $(ROOT)/secp256k1-build && \ |
| 86 | git remote add origin $(SECP256K1_REPO) && \ | ||
| 87 | git fetch -q --depth 1 origin $(SECP256K1_COMMIT) && \ | ||
| 88 | git checkout -q $(SECP256K1_COMMIT) && \ | ||
| 89 | ./autogen.sh && \ | ||
| 52 | ./configure --enable-module-schnorrsig --enable-module-extrakeys \ | 90 | ./configure --enable-module-schnorrsig --enable-module-extrakeys \ |
| 53 | --disable-shared --with-pic --disable-benchmark --disable-tests && \ | 91 | --disable-shared --with-pic --disable-benchmark --disable-tests && \ |
| 54 | make -j$(NPROC) && $(SUDO) make install && $(SUDO) ldconfig; \ | 92 | make -j$(NPROC) && $(SUDO) make install && $(SUDO) ldconfig; \ |
| @@ -61,7 +99,11 @@ deps-randomx: | |||
| 61 | @if [ ! -f $(HOME)/RandomX/build/librandomx.a ]; then \ | 99 | @if [ ! -f $(HOME)/RandomX/build/librandomx.a ]; then \ |
| 62 | echo "==> building RandomX"; \ | 100 | echo "==> building RandomX"; \ |
| 63 | rm -rf $(HOME)/RandomX; \ | 101 | rm -rf $(HOME)/RandomX; \ |
| 64 | git clone --depth 1 https://github.com/tevador/RandomX $(HOME)/RandomX; \ | 102 | git init -q $(HOME)/RandomX; \ |
| 103 | cd $(HOME)/RandomX && \ | ||
| 104 | git remote add origin $(RANDOMX_REPO) && \ | ||
| 105 | git fetch -q --depth 1 origin $(RANDOMX_COMMIT) && \ | ||
| 106 | git checkout -q $(RANDOMX_COMMIT); \ | ||
| 65 | mkdir -p $(HOME)/RandomX/build; \ | 107 | mkdir -p $(HOME)/RandomX/build; \ |
| 66 | cd $(HOME)/RandomX/build && cmake .. -DCMAKE_BUILD_TYPE=Release && \ | 108 | cd $(HOME)/RandomX/build && cmake .. -DCMAKE_BUILD_TYPE=Release && \ |
| 67 | make -j$(NPROC) randomx; \ | 109 | make -j$(NPROC) randomx; \ |
| @@ -70,37 +112,57 @@ deps-randomx: | |||
| 70 | echo "==> RandomX already built"; \ | 112 | echo "==> RandomX already built"; \ |
| 71 | fi | 113 | fi |
| 72 | 114 | ||
| 115 | # APPDIR and the tool both used fixed paths under /tmp, on a directory every | ||
| 116 | # local account can write. `[ ! -x /tmp/appimagetool ]` means an executable | ||
| 117 | # already sitting at that name is taken as the tool and run, so anyone with a | ||
| 118 | # shell on the build machine could have put one there first and had it execute | ||
| 119 | # as whoever ran make; `rm -rf /tmp/bitflash.AppDir` then mkdir is the same | ||
| 120 | # problem one step later, through symlinks. Both now live under the build tree, | ||
| 121 | # which the build already owns. | ||
| 122 | APPDIR := $(ROOT)/build/bitflash.AppDir | ||
| 123 | APPIMAGETOOL := $(ROOT)/build/appimagetool | ||
| 124 | |||
| 73 | appimage: src/bitflash | 125 | appimage: src/bitflash |
| 74 | @echo "==> building AppImage" | 126 | @echo "==> building AppImage" |
| 75 | @if [ ! -x /tmp/appimagetool ]; then \ | 127 | @mkdir -p $(ROOT)/build |
| 76 | wget -q "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage" \ | 128 | @if [ ! -x "$(APPIMAGETOOL)" ]; then \ |
| 77 | -O /tmp/appimagetool && chmod +x /tmp/appimagetool; \ | 129 | echo " fetching appimagetool"; \ |
| 130 | wget -q "$(APPIMAGETOOL_URL)" -O "$(APPIMAGETOOL).tmp" || \ | ||
| 131 | { echo " ERROR: appimagetool download failed"; rm -f "$(APPIMAGETOOL).tmp"; exit 1; }; \ | ||
| 132 | echo "$(APPIMAGETOOL_SHA256) $(APPIMAGETOOL).tmp" | sha256sum -c - >/dev/null 2>&1 || \ | ||
| 133 | { echo " ERROR: appimagetool digest mismatch, refusing to run it"; \ | ||
| 134 | echo " expected $(APPIMAGETOOL_SHA256)"; \ | ||
| 135 | echo " got $$(sha256sum "$(APPIMAGETOOL).tmp" | cut -d" " -f1)"; \ | ||
| 136 | rm -f "$(APPIMAGETOOL).tmp"; exit 1; }; \ | ||
| 137 | chmod +x "$(APPIMAGETOOL).tmp" && mv "$(APPIMAGETOOL).tmp" "$(APPIMAGETOOL)"; \ | ||
| 78 | fi | 138 | fi |
| 79 | @rm -rf /tmp/bitflash.AppDir | 139 | @rm -rf $(APPDIR) |
| 80 | @mkdir -p /tmp/bitflash.AppDir/usr/bin \ | 140 | @mkdir -p $(APPDIR)/usr/bin \ |
| 81 | /tmp/bitflash.AppDir/usr/lib \ | 141 | $(APPDIR)/usr/lib \ |
| 82 | /tmp/bitflash.AppDir/usr/share/applications \ | 142 | $(APPDIR)/usr/share/applications \ |
| 83 | /tmp/bitflash.AppDir/usr/share/icons/hicolor/256x256/apps | 143 | $(APPDIR)/usr/share/icons/hicolor/256x256/apps |
| 84 | @cp src/bitflash /tmp/bitflash.AppDir/usr/bin/bitflash | 144 | @cp src/bitflash $(APPDIR)/usr/bin/bitflash |
| 85 | @printf '#!/bin/sh\nHERE="$$(dirname "$$(readlink -f "$$0")")"\nexport LD_LIBRARY_PATH="$$HERE/usr/lib:$$LD_LIBRARY_PATH"\nexec "$$HERE/usr/bin/bitflash" "$$@"\n' \ | 145 | @printf '#!/bin/sh\nHERE="$$(dirname "$$(readlink -f "$$0")")"\nexport LD_LIBRARY_PATH="$$HERE/usr/lib:$$LD_LIBRARY_PATH"\nexec "$$HERE/usr/bin/bitflash" "$$@"\n' \ |
| 86 | > /tmp/bitflash.AppDir/AppRun && chmod +x /tmp/bitflash.AppDir/AppRun | 146 | > $(APPDIR)/AppRun && chmod +x $(APPDIR)/AppRun |
| 87 | @printf '[Desktop Entry]\nName=Bitflash\nExec=bitflash\nIcon=bitflash\nType=Application\nCategories=Finance;\n' \ | 147 | @printf '[Desktop Entry]\nName=Bitflash\nExec=bitflash\nIcon=bitflash\nType=Application\nCategories=Finance;\n' \ |
| 88 | > /tmp/bitflash.AppDir/bitflash.desktop | 148 | > $(APPDIR)/bitflash.desktop |
| 89 | @cp /tmp/bitflash.AppDir/bitflash.desktop \ | 149 | @cp $(APPDIR)/bitflash.desktop \ |
| 90 | /tmp/bitflash.AppDir/usr/share/applications/ | 150 | $(APPDIR)/usr/share/applications/ |
| 91 | @python3 -c "\ | 151 | @APPDIR=$(APPDIR) python3 -c "\ |
| 152 | import os; \ | ||
| 92 | from PIL import Image; \ | 153 | from PIL import Image; \ |
| 154 | d = os.environ['APPDIR']; \ | ||
| 93 | ico = Image.open('src/rc/bitcoin.ico'); \ | 155 | ico = Image.open('src/rc/bitcoin.ico'); \ |
| 94 | img = ico.convert('RGBA'); \ | 156 | img = ico.convert('RGBA'); \ |
| 95 | img.save('/tmp/bitflash.AppDir/bitflash.png'); \ | 157 | img.save(d + '/bitflash.png'); \ |
| 96 | import shutil; shutil.copy('/tmp/bitflash.AppDir/bitflash.png', \ | 158 | import shutil; shutil.copy(d + '/bitflash.png', \ |
| 97 | '/tmp/bitflash.AppDir/usr/share/icons/hicolor/256x256/apps/bitflash.png')" | 159 | d + '/usr/share/icons/hicolor/256x256/apps/bitflash.png')" |
| 98 | @for lib in libsodium.so.23 libdb_cxx-5.3.so libglfw.so.3; do \ | 160 | @for lib in libsodium.so.23 libdb_cxx-5.3.so libglfw.so.3; do \ |
| 99 | path=$$(ldconfig -p | grep " $$lib " | awk '{print $$NF}' | head -1); \ | 161 | path=$$(ldconfig -p | grep " $$lib " | awk '{print $$NF}' | head -1); \ |
| 100 | [ -z "$$path" ] && path=$$(find /usr/lib /lib -name "$$lib" 2>/dev/null | head -1); \ | 162 | [ -z "$$path" ] && path=$$(find /usr/lib /lib -name "$$lib" 2>/dev/null | head -1); \ |
| 101 | [ -n "$$path" ] && cp -L "$$path" /tmp/bitflash.AppDir/usr/lib/ && echo " bundled $$lib" || echo " missing $$lib"; \ | 163 | [ -n "$$path" ] && cp -L "$$path" $(APPDIR)/usr/lib/ && echo " bundled $$lib" || echo " missing $$lib"; \ |
| 102 | done | 164 | done |
| 103 | @ARCH=x86_64 /tmp/appimagetool --no-appstream /tmp/bitflash.AppDir \ | 165 | @ARCH=x86_64 $(APPIMAGETOOL) --no-appstream $(APPDIR) \ |
| 104 | $(ROOT)/Bitflash-$(VERSION)-x86_64.AppImage 2>&1 | grep -E "^Built|^Error" || true | 166 | $(ROOT)/Bitflash-$(VERSION)-x86_64.AppImage 2>&1 | grep -E "^Built|^Error" || true |
| 105 | @echo "Built: Bitflash-$(VERSION)-x86_64.AppImage" | 167 | @echo "Built: Bitflash-$(VERSION)-x86_64.AppImage" |
| 106 | 168 | ||
| @@ -157,7 +219,7 @@ clean: | |||
| 157 | $(MAKE) -C src -f Makefile clean 2>/dev/null || true | 219 | $(MAKE) -C src -f Makefile clean 2>/dev/null || true |
| 158 | cd src && make -f makefile.mingw clean 2>/dev/null || true | 220 | cd src && make -f makefile.mingw clean 2>/dev/null || true |
| 159 | rm -f Bitflash-*.AppImage Bitflash-*.zip | 221 | rm -f Bitflash-*.AppImage Bitflash-*.zip |
| 160 | rm -rf Bitflash-*-windows | 222 | rm -rf Bitflash-*-windows build |
| 161 | 223 | ||
| 162 | tests: | 224 | tests: |
| 163 | $(MAKE) -C src -f Makefile tests | 225 | $(MAKE) -C src -f Makefile tests |