Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Keeps the release build context small and reproducible. Notably drops .git
# (~23 MB) and any tarballs produced by a previous run.
.git
.gitignore
dist
*.tar.gz
*.tar.gz.sha256
53 changes: 53 additions & 0 deletions .github/docker/Dockerfile.release
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Release build for cgminer-htr.
#
# Built on Debian bullseye (glibc 2.31) on purpose: glibc is forward- but not
# backward-compatible, so a binary linked here runs on Raspberry Pi OS Bullseye
# and every newer release. Building on the GitHub runner's own Ubuntu 24.04
# (glibc 2.39) would produce a binary that fails to start on Bookworm.
#
# libjansson-dev is deliberately NOT installed: configure then falls back to the
# bundled compat/jansson-2.9 and links it statically, which is one less runtime
# dependency on the miner host.

FROM debian:bullseye AS build

RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
autoconf \
automake \
libtool \
pkg-config \
libcurl4-openssl-dev \
libusb-1.0-0-dev \
libncurses-dev \
zlib1g-dev \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /src
COPY . /src

# -fcommon is required on GCC 10+ (Bullseye ships GCC 10, Bookworm GCC 12).
# This tree predates -fno-common becoming the default and otherwise fails to
# link with "multiple definition of 'bab_drv'" and friends. Pre-existing
# upstream issue, not specific to this fork's changes.
RUN ./autogen.sh > /tmp/autogen.log 2>&1 || (tail -40 /tmp/autogen.log; exit 1)
RUN ./configure --enable-gekko CFLAGS="-O2 -fcommon" > /tmp/configure.log 2>&1 \
|| (tail -40 /tmp/configure.log; exit 1)
RUN make -j"$(nproc)" > /tmp/make.log 2>&1 || (tail -60 /tmp/make.log; exit 1)
RUN strip cgminer

COPY .github/docker/smoke-test.sh /usr/local/bin/smoke-test.sh
RUN /usr/local/bin/smoke-test.sh /src/cgminer

# Stage the payload so the export stage is a flat, predictable layout.
RUN set -eux; \
mkdir -p /out; \
cp /src/cgminer /out/cgminer; \
cp /src/README /out/README; \
cp /src/ASIC-README /out/ASIC-README 2>/dev/null || true; \
objdump -p /out/cgminer | awk '/NEEDED/ {print $2}' > /out/RUNTIME-DEPS.txt; \
cat /out/RUNTIME-DEPS.txt

FROM scratch AS artifact
COPY --from=build /out/ /
108 changes: 108 additions & 0 deletions .github/docker/INSTALL.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
cgminer-htr - prebuilt binary
=============================

This is a build of HathorNetwork/cgminer with --gekko-ticket-diff, the option
that lets a GekkoScience device answer Hathor transaction jobs instead of only
block jobs. See the README section "GEKKO TICKET DIFFICULTY" for what it does.


1. PICK THE RIGHT TARBALL
-------------------------

Run this on the machine that has the miner plugged in:

uname -m

aarch64 -> use the linux-arm64 tarball (Raspberry Pi OS 64-bit)
armv7l -> use the linux-armhf tarball (Raspberry Pi OS 32-bit)
x86_64 -> use the linux-amd64 tarball (normal PC or server)

If you download the wrong one, it will not start and will say
"cannot execute binary file" or "Exec format error". No harm done - just get
the other one.


2. CHECK YOU HAVE THE LIBRARIES
-------------------------------

The binary is dynamically linked. RUNTIME-DEPS.txt lists exactly what it needs.
On Raspberry Pi OS / Debian / Ubuntu these are almost always already installed;
if not:

sudo apt-get install libcurl4 libusb-1.0-0 libncurses6

You do NOT need any -dev packages, and you do not need a compiler.

The JSON library (jansson) is compiled into the binary, so it is not a
dependency you have to install.

This binary is built on Debian Bullseye. glibc is forward-compatible but not
backward-compatible, so it runs on Bullseye and anything newer (Bookworm,
Trixie), but NOT on anything older.


3. INSTALL IT
-------------

Stop the miner first, so the USB device is free:

sudo systemctl stop cgminer # or whatever your service is called

Keep the old binary so you can go back:

sudo cp /usr/local/bin/cgminer /usr/local/bin/cgminer.bak

Put the new one in place (adjust the path if yours lives somewhere else -
`which cgminer` will tell you):

sudo install -m 755 ./cgminer /usr/local/bin/cgminer

Start it again:

sudo systemctl start cgminer

Your udev rules, USB group membership, and service file are untouched.


4. CONFIRM IT WORKED
--------------------

The option defaults to 1, so you do not have to change your command line or
your .conf file. In the log you should now see:

set ticket to 0x00/1

instead of the old value (0xf0/16 on a BM1397 board such as the Compac F).

Two things to watch in the first hour:

- Transaction shares. This is the whole point: the device should start
getting accepted transaction jobs, not only block jobs.
- The string "PT_NONONCE" in the log. A lower ticket means the driver
expects nonces more often, so its stall watchdog window gets shorter. If
you see PT_NONONCE and the frequency resetting, please report it - that is
the one known risk of this change and we want to know.

To go back at any time:

sudo systemctl stop cgminer
sudo cp /usr/local/bin/cgminer.bak /usr/local/bin/cgminer
sudo systemctl start cgminer

Or keep this binary and turn the change off with --gekko-ticket-diff 0, which
restores the original upstream behaviour.


5. IF YOU PREFER TO BUILD IT YOURSELF
-------------------------------------

sudo apt-get install build-essential autoconf automake libtool pkg-config \
libcurl4-openssl-dev libusb-1.0-0-dev libncurses-dev zlib1g-dev
./autogen.sh
./configure --enable-gekko CFLAGS="-O2 -fcommon"
make

-fcommon is required on GCC 10 and newer, which includes every current
Raspberry Pi OS. Without it the link fails with "multiple definition of
'bab_drv'". This is a pre-existing upstream issue, not something this fork
introduced.
75 changes: 75 additions & 0 deletions .github/docker/smoke-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash
# Smoke tests run inside the release build, against the freshly built binary.
# These are cheap and they guard against shipping a binary that is broken in a
# way `make` cannot see. The config-save test in particular is a regression test
# for a SIGSEGV that got all the way to review: write_config() dispatches on the
# option's callback pointer, so a new setter that is not registered there is
# type-punned and passed to strlen(). It crashed on default settings, on every
# gekko build, whether or not the new flag was used.
set -euo pipefail

CGMINER="${1:?usage: smoke-test.sh /path/to/cgminer}"
API_PORT=4028
CONF=/tmp/smoke-out.conf

fail() { echo "SMOKE FAIL: $*" >&2; exit 1; }
pass() { echo " ok $*"; }

echo "== 1. binary runs and reports a version"
"$CGMINER" --version || fail "--version exited non-zero"
pass "--version"

echo "== 2. --gekko-ticket-diff is registered with the documented default"
HELP="$("$CGMINER" --help 2>&1 || true)"
grep -q -- '--gekko-ticket-diff' <<<"$HELP" || fail "--gekko-ticket-diff missing from --help"
grep -A2 -- '--gekko-ticket-diff' <<<"$HELP" | grep -qi 'default: 1' \
|| fail "--gekko-ticket-diff default is not 1"
pass "--gekko-ticket-diff present, default 1"

echo "== 3. argument validation"
for good in 0 1 16 64; do
"$CGMINER" --gekko-ticket-diff "$good" --version >/dev/null 2>&1 \
|| fail "valid ticket-diff $good was rejected"
done
pass "accepts 0 1 16 64"
for bad in 0.5 100 -1 nan; do
if "$CGMINER" --gekko-ticket-diff "$bad" --version >/dev/null 2>&1; then
fail "invalid ticket-diff $bad was accepted"
fi
done
pass "rejects 0.5 100 -1 nan"

echo "== 4. config save does not crash (regression: write_config type-pun SIGSEGV)"
rm -f "$CONF"
"$CGMINER" --benchmark -T \
--api-listen --api-allow "W:127.0.0.1" --api-port "$API_PORT" \
> /tmp/smoke-cgminer.log 2>&1 &
CGPID=$!
trap 'kill -9 "$CGPID" 2>/dev/null || true' EXIT

# QEMU-emulated startup is slow; poll rather than sleeping a fixed amount.
for _ in $(seq 1 60); do
if (exec 3<>/dev/tcp/127.0.0.1/"$API_PORT") 2>/dev/null; then
exec 3<&- 3>&-
break
fi
sleep 1
done

kill -0 "$CGPID" 2>/dev/null || fail "cgminer died before the API came up"

exec 3<>/dev/tcp/127.0.0.1/"$API_PORT" || fail "could not reach the API"
printf 'save|%s' "$CONF" >&3
API_REPLY="$(timeout 30 cat <&3 || true)"
exec 3<&- 3>&- || true

sleep 2
kill -0 "$CGPID" 2>/dev/null || fail "cgminer CRASHED on config save -- reply was: ${API_REPLY:-<none>}"
grep -q 'STATUS=S' <<<"$API_REPLY" || fail "config save reported failure: ${API_REPLY:-<none>}"
[ -s "$CONF" ] || fail "config save wrote no bytes"
grep -q 'gekko-ticket-diff' "$CONF" || fail "gekko-ticket-diff missing from the saved config"
pass "config save: $(wc -c < "$CONF") bytes, $(grep -o '"gekko-ticket-diff" : "[^"]*"' "$CONF")"

kill "$CGPID" 2>/dev/null || true
trap - EXIT
echo "SMOKE OK"
128 changes: 128 additions & 0 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
name: Build release binaries

# Produces ready-to-run cgminer binaries for the Hathor mining fleet, so an
# operator can drop in a new build instead of installing a toolchain and
# compiling on a Raspberry Pi.
#
# Push a tag (v1.2.3) to cut a release, or run it manually from the Actions tab
# to get throwaway artifacts without publishing anything. Pull requests build
# and smoke-test but publish nothing.

on:
push:
tags:
- 'v*'
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
build:
name: ${{ matrix.arch }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
# Raspberry Pi OS 64-bit -> `uname -m` reports aarch64.
# Built natively on GitHub's ARM runners (free for public repos), so
# the smoke tests execute on real ARM hardware rather than under QEMU.
- arch: arm64
platform: linux/arm64
runner: ubuntu-24.04-arm
qemu: false
# Raspberry Pi OS 32-bit -> `uname -m` reports armv7l.
# Needs QEMU: GitHub's ARM runners are Cobalt/Ampere cores, which do
# not support 32-bit execution, so this cannot be built natively here.
- arch: armhf
platform: linux/arm/v7
runner: ubuntu-24.04
qemu: true
# Not for the fleet - lets a maintainer reproduce a shipped binary on
# a normal dev machine.
- arch: amd64
platform: linux/amd64
runner: ubuntu-24.04
qemu: false

steps:
- uses: actions/checkout@v4

- name: Set up QEMU
if: matrix.qemu
uses: docker/setup-qemu-action@v3

- uses: docker/setup-buildx-action@v3

- name: Build and smoke-test
run: |
docker buildx build \
--platform "${{ matrix.platform }}" \
--file .github/docker/Dockerfile.release \
--target artifact \
--progress plain \
--output "type=local,dest=dist/${{ matrix.arch }}" \
.

- name: Package
id: package
run: |
set -euo pipefail
if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
VERSION="${GITHUB_REF_NAME}"
else
VERSION="$(git describe --tags --always --dirty 2>/dev/null || git rev-parse --short HEAD)"
fi
NAME="cgminer-htr-${VERSION}-linux-${{ matrix.arch }}"
mv "dist/${{ matrix.arch }}" "dist/${NAME}"
cp .github/docker/INSTALL.txt "dist/${NAME}/INSTALL.txt"
tar -C dist -czf "${NAME}.tar.gz" "${NAME}"
sha256sum "${NAME}.tar.gz" > "${NAME}.tar.gz.sha256"
echo "name=${NAME}" >> "$GITHUB_OUTPUT"
echo "--- shipped ---"
ls -l "dist/${NAME}"
echo "--- runtime deps ---"
cat "dist/${NAME}/RUNTIME-DEPS.txt"

- uses: actions/upload-artifact@v4
with:
name: ${{ steps.package.outputs.name }}
path: |
*.tar.gz
*.tar.gz.sha256
if-no-files-found: error

release:
name: Publish release
needs: build
if: github.ref_type == 'tag'
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true

- name: Publish
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
ls -l artifacts
if gh release view "${GITHUB_REF_NAME}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
gh release upload "${GITHUB_REF_NAME}" \
--repo "${GITHUB_REPOSITORY}" \
--clobber \
artifacts/*
else
gh release create "${GITHUB_REF_NAME}" \
--repo "${GITHUB_REPOSITORY}" \
--title "${GITHUB_REF_NAME}" \
--generate-notes \
--verify-tag \
artifacts/*
fi
Loading
Loading