Skip to content

Fix miner/TLS hardware SHA collision (root cause of direct-HTTPS instability)#43

Open
BurtonJeff wants to merge 1 commit into
SneezeGUI:mainfrom
BurtonJeff:fix/https-sha-collision
Open

Fix miner/TLS hardware SHA collision (root cause of direct-HTTPS instability)#43
BurtonJeff wants to merge 1 commit into
SneezeGUI:mainfrom
BurtonJeff:fix/https-sha-collision

Conversation

@BurtonJeff

@BurtonJeff BurtonJeff commented Jul 9, 2026

Copy link
Copy Markdown

Symptoms

With enableHttpsStats = true on a classic ESP32 (CYD), the first direct-HTTPS stats fetch reliably destabilizes the device within a minute or two:

  • both mining cores freeze (hash counters stop dead, hashrate falls to 0) with the stratum connection still "up"
  • heap drops ~40KB and stays down (a wedged WiFiClientSecure session)
  • or the task watchdog fires and reboots the device - I believe this is the "direct HTTPS may cause WDT crashes" that led to it being disabled by default

Some HTTPS servers also abort handshakes with a fatal alert even when the device seems fine (observed with pool.nerdminers.org, which negotiates a SHA-384 cipher suite - that turned out to be a clue, see below).

Root cause

The ESP32 has one SHA peripheral whose parallel engines (SHA-1/256/384/512) share the SHA_TEXT input registers. The core-1 pipelined mining assembly drives those registers directly and never takes ESP-IDF's engine locks; mbedtls (TLS) hashes through the locked API and, finding the locks free, uses the same hardware. When the two interleave:

  • the miner's in-flight block gets corrupted and the assembly wedges in the SHA_BUSY wait
  • the TLS side's transcript hash is corrupted mid-handshake, so it hangs, or the server rejects the handshake with a fatal alert (any suite hashing with SHA-256 or SHA-384 - different engine lock, same shared registers)

Fix

  1. miner_init() permanently claims all four SHA engine locks on behalf of the mining assembly. mbedtls acquires engines with a try-lock and falls back to software SHA when they're held, so TLS can never touch the hardware mid-mine. Try-lock rather than lock, because SHA-384/512 share one lock and a blocking second acquisition deadlocks boot (found the hard way). This must run after the boot self-tests, which use mbedtls hardware SHA.
  2. Core 0's opportunistic hardware-midstate grab is removed - its result was never used (the hybrid loop verifies/mines in software), and with the locks held permanently it would deadlock that task.
  3. fetchHttpsDirect() unsubscribes core 0's idle task from the task WDT for the duration of the fetch: with TLS hashing in software on a chip that's also mining, a handshake can occupy core 0 long enough to starve IDLE0. Mining on core 1 stays watchdog-protected throughout.

Verification

On an ESP32-2432S028R (CYD, the default env): repeated multi-minute soaks with direct HTTPS enabled - CoinGecko price + pool stats fetched every cycle, ~680 kH/s sustained with no dips, stable heap, zero WDT events, previously-failing SHA-384 handshakes now complete. Before the fix, the same configuration froze both mining cores within a minute of the first fetch.

With this in, enableHttpsStats could plausibly become safe to enable by default - happy to test further configurations if useful.

Companion PR: the block-height/fee fetches have a separate long-standing failure (HTTP to HTTPS redirect) fixed in #44.

🤖 Generated with Claude Code

The ESP32 has one SHA peripheral whose parallel engines (SHA-1/256/384/
512) share the SHA_TEXT input registers. The core-1 mining assembly
drives those registers directly without holding ESP-IDF's engine locks,
while mbedtls (any direct-HTTPS stats fetch) hashes through the locked
API. When the two interleave, both sides corrupt each other: the mining
cores wedge in busy-waits (hashrate silently drops to zero) and the TLS
session hangs holding ~40KB of heap - or the starved idle task trips
the task watchdog. This is the "direct HTTPS causes WDT crashes" that
led to enableHttpsStats being disabled by default.

Fix, in two parts:

1. miner_init() permanently claims ALL four SHA engine locks on behalf
   of the mining assembly. mbedtls acquires engines with a try-lock and
   falls back to software SHA when they are held, so TLS can never touch
   the hardware mid-mine. All four engines matter (a TLS suite hashing
   its transcript with SHA-384 through a free engine corrupts the shared
   registers just the same - observed as servers aborting handshakes
   with fatal alerts). try-lock rather than lock because SHA-384/512
   share a lock and a blocking second acquisition deadlocks boot.

   Core 0's opportunistic hardware-midstate grab is removed: its result
   was never used (the hybrid loop is pure software), and with the locks
   held permanently it would deadlock.

2. fetchHttpsDirect() unsubscribes core 0's idle task from the task WDT
   for the duration of the fetch: with TLS hashing in software on a chip
   that is also mining, a handshake can occupy core 0 long enough to
   starve IDLE0. Mining on core 1 stays watchdog-protected.

Verified on an ESP32-2432S028R (CYD): repeated soaks with direct HTTPS
enabled - price + pool fetches every cycle, ~680 kH/s sustained
throughout, stable heap, zero WDT events. Before the fix the same
config froze both mining cores within a minute of the first fetch.
jmarquez84 pushed a commit to jmarquez84/SparkMiner that referenced this pull request Jul 22, 2026
jmarquez84 added a commit to jmarquez84/SparkMiner that referenced this pull request Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant