I finaly got the Obelisk SC1 Slim Gen 2 miner to mine on blake2b POW today. Here’s a writeup my AI Agent created
Obelisk SC1 Gen2 → Bitcoin BLAKE2b-POW: findings and fixes
Shareable write-up for other miners running Obelisk SC1 “Slim” (Gen 2) units on the
Bitcoin Knots BLAKE2b hard-fork. Author: Klaus E. Frederiksen. Date: 2026-09-05.
The Obelisk SC1 Gen2 (ob2 firmware, cgminer 4.10.0) can mine the BLAKE2b fork.
The ASIC hardware, the software Blake2b, and the verify target are all standard —
the only thing standing between the miner and accepted shares was a
4-byte-vs-8-byte extranonce2 mismatch between the miner firmware and the DATUM
gateway. Two small changes make shares accepted:
-
A 3-instruction binary patch to the miner’s cgminer-sia (zero-pad the
extranonce2 in the merkle-root leaf).
-
A gateway-side zero-extension in datum_stratum.c (zero the high 4 bytes of
the submitted extranonce2).
-
The fork switched SHA-256d → BLAKE2b at block 961,640 (2026-08-30). Miners attach
through a DATUM Gateway (a “Siacoin dialect” of Stratum v1).
-
The SC1 Gen2 control card is a TI AM335x (ARMv7), Linux 4.9.118, running a
closed-source ob2 cgminer-sia binary. (The Gen1 “ob1” source is open but has
a different ASIC layer, so it can’t be rebuilt for Gen2 hardware.)
-
The fork’s merkle leaf (datum_pow.c datum_blake2b_work_root) is:
Blake2b(0x00 || coinb1(39) || sid_inv(4) || extranonce2(8)) — a 52-byte input.
-
The firmware builds its leaf as 0x00 || coinb1 || en1(4) || en2 || coinb2, which
is byte-identical to the fork’s when coinb2 is empty and en2 is 8 bytes.
Shares were submitted but every one was rejected by the gateway with error 23
H-not-zero. The miner’s own log reported the shares as found, but the gateway
reconstructed a different header hash.
-
The leaf uses a 4-byte extranonce2. The ob2 merkle-root builder hashes a
48-byte leaf with a 32-bit nonce2, while the gateway (and fork consensus) hash a
52-byte leaf with a 64-bit extranonce2. Different root → different header hash →
h[0] != 0 → H-not-zero.
-
The submission path reads 8 bytes out of a 4-byte nonce2. The stratum submit
(__bin2hex(nonce2hex, &extranonce2, nonce2_len=8)) reads 8 bytes from a 4-byte
uint32_t, so the high 4 bytes are stack garbage. Even after fixing the leaf, the
submitted extranonce2 still carried garbage in the high 4 bytes.
All in the 32-bit ARM (armv7, ARM-state) binary /usr/local/ob2/bin/cgminer-sia:
| Patch |
File offset |
Change |
| nonce2_len gate |
0xc6bc |
cmp r3,#4 → cmp r3,#8 (allow nonce2_len 8) |
| ExtraNonce2Size |
0x32610 (VMA 0x42610) |
mov r0,#4 → mov r0,#8 |
| leaf zero-pad |
0x32694 |
bl memcpy → str r8,[r0] (zero the en2 high 4 bytes) |
| leaf zero-pad |
0x32698 |
add r2,r8,r7 → add r2,r7,#4 (hash 52 bytes, not 48) |
The leaf patch makes the miner hash a 52-byte leaf with the high 4 bytes of the
extranonce2 explicitly zeroed, matching the gateway.
The pristine gateway reads all 8 bytes of the submitted extranonce2. The SC1 only has
4 real bytes (the high 4 are garbage), so zero them:
Plain Text
Show linesCopy
// Obelisk SC1 miners have a 32-bit nonce2 and submit it in the low 4 bytes of the
// 8-byte extranonce2, leaving stack garbage in the high 4 bytes. Zero-extend to
// 64-bit so the gateway's work-root leaf matches the miner's (which zero-pads the
// same 32-bit nonce2 in its leaf builder). SC1-specific: a true 64-bit-nonce2 miner
// would need the full 8 bytes preserved.
for(i=0;i<4;i++) {
extranonce_bin[i+4] = hex2bin_uchar(&extranonce2_s[i<<1]);
}
memset(&extranonce_bin[8], 0, 4);
(the pristine version read for(i=0;i<8;i++) with no memset.)
-
Software Blake2b (ob2 0x41e80) matches hashlib.blake2b(digest_size=32) on
empty / "abc" / 80-byte vectors (4/4).
-
Hardware ASIC is standard: 4/4 chip-valid nonces hash to h[0]==0.
-
Verify target is the correct pool target (not a looser chip target).
-
Header layout (prevhash32 || nonce8 || ntime8 || root32) is byte-identical on
both sides.
So the rejection was never a hashing or hardware problem — it was purely the
extranonce2 width.
Miner log:
CRITICAL:Accepted 00000028 Diff 18.4E/16384 BLOCK! Obelisk OB2 0
(previously CRITICAL:Rejected ... BLOCK! Obelisk OB2 0 (H-not-zero)).
-
Fingerprint the live binary: md5 4c0b44bc41226205347abd3e4a65311a (pristine ob2).
If it differs, re-apply the three patches to that unit’s own binary offline.
-
Deploy the pre-patched binary (md5 a59d7e04cb01e03cc52617320fd11614):
kill cgminer-sia → mount -o remount,rw / → replace
/usr/local/ob2/bin/cgminer-sia → mount -o remount,ro / → restart.
-
Write the pool config (/var/etc/ob2/cgminer.conf) — a factory-fresh unit has
pools: []; set {"url":"stratum+tcp://<gateway>:23334","user":"sc1-N","pass":"x"}.
-
Confirm Accepted ... BLOCK! Obelisk OB2 0 in /var/log/ob2/cgminer-sia.
On-device backup at /var/backup/cgminer-sia.preleaf; restore by copying it back,
remounting ro, and restarting.