feat: perf & resilience (multi-pool failover, solo getblocktemplate, ctypes SHA-256)#7
Merged
devAsmodeus merged 5 commits intomainfrom May 3, 2026
Merged
Conversation
Adds src/hope_hash/sha_native.py: loads libcrypto-3.dll / libcrypto.so.3 / libcrypto.dylib via ctypes.CDLL, exposes sha256() / sha256d() / is_available() / BACKEND_NAME via the EVP API. Falls back to hashlib if libcrypto is not found. parallel.worker now dispatches to _worker_hashlib_midstate() (unchanged hot path) or _worker_ctypes() (sha256d per iteration, no mid-state — honest baseline for benchmark comparison). start_pool() takes sha_backend kwarg. bench.run_benchmark() takes sha_backend and print_header. New run_benchmark_all_backends() + available_backends() drive the --backends comparison; final line "[bench] result: ctypes X MH/s (Yx vs hashlib-midstate)" is grep-friendly. Verified hot path unchanged: 4-worker hashlib-midstate stays at ~3.18 MH/s (same order as v0.5.0). ctypes is ~0.3x because no mid-state — sognately so. 21 new tests; total 145 → 166. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New module src/hope_hash/pools.py: PoolList holds endpoints, tracks per-pool failure counts, rotates on threshold, knows when a full cycle has passed without a single success (full_cycle_failed). parse_pool_spec() handles host/host:port. Dedup is case-insensitive on host. stratum.StratumClient.set_endpoint(host, port) re-targets the client without recreating it: on_share_result, stop_event, suggest_diff, username and locks are preserved. This is what makes failover seamless inside mine(). miner.supervisor_loop now accepts pools: Optional[PoolList] and stats_provider: Optional[StatsProvider]. On a failed connect we mark_failed(); after rotation we set_endpoint() and continue. After full_cycle_failed we apply the existing exponential backoff once and reset_round(). When connect succeeds we mark_success(). tui.StatsProvider.update_pool(url) lets the supervisor push the active pool name through the canonical data bus so the TUI shows the live target. 24 new tests for PoolList: rotation at threshold, wrap-around, single-pool no-op, mark_success reset, full_cycle_failed, no-deadlock smoke. Total 166 → 190. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New module src/hope_hash/solo.py implementing solo mining against a local bitcoind: - BitcoinRPC: minimal stdlib urllib JSON-RPC client. Auth via cookie file (default for local) or username/password. Cookie wins if both are provided. - SoloClient: duck-types StratumClient's public surface (current_job, job_lock, extranonce1, extranonce2_size, difficulty, submit, on_share_result, connect, subscribe_and_authorize, reader_loop, close, host/port/sock) so mine() runs unchanged. reader_loop polls getblocktemplate every poll_interval_s and updates current_job on prevhash change. - build_coinbase: serializes a coinbase tx with BIP-34 height push, optional extranonce push, and optional BIP-141 witness commitment output (OP_RETURN OP_PUSH36 0xaa21a9ed <hash>). - compute_witness_commitment + parse_default_witness_commitment handle both directions: building from a witness root, or extracting the 32-byte hash from bitcoind's pre-built script. - serialize_block + compute_merkle_root_from_txids round out the surface needed for submitblock. scriptPubKey for the coinbase output is OP_RETURN — sognately unspendable. Real solo would need bech32/base58 decode to a P2WPKH/P2PKH script; that's noted in CLAUDE.md-style docstring as a known simplification (chance of finding a block ≈ 0). 35 tests using FakeRPC, including SoloClient.connect/submit success+reject paths, varint/push/height edge cases, witness commitment parity vs double_sha256. Total 190 → 225. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds CLI flags for the new perf/resilience features:
- --pool HOST:PORT (repeatable) drives PoolList, --rotate-after-failures
configures the threshold. When --pool is provided the legacy default
CKPool is replaced.
- --sha-backend {auto,hashlib,ctypes} (default auto). auto picks
ctypes when libcrypto loads, hashlib otherwise. The choice flows
through mine() → start_pool() → worker.
- --backends turns --benchmark into a comparative run across all
available backends.
- --solo + --rpc-url + (--rpc-cookie | --rpc-user/--rpc-pass) +
--solo-poll-sec switch the supervisor to SoloClient with the
same surface, so mine() works unchanged.
main() splits into three branches: bench, solo, and stratum-pool.
The supervisor thread is constructed with the right kwargs for each
case (pools=PoolList for stratum, plain for solo).
__init__.py bumps __version__ to 0.6.0 and re-exports the new
public symbols (PoolList, SoloClient, BitcoinRPC, build_coinbase,
sha_native module, run_benchmark_all_backends, etc.).
No behavior change for existing flags. All 225 tests still green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the v0.6.0 section to CHANGELOG and README, ticks off multi-pool failover, getblocktemplate solo mode, and the ctypes SHA-256 wrapper in ROADMAP. Records what shipped, the file map, new CLI flags, gotchas, and open questions for PR C in docs/handoff/pr-b-summary.md. README is intentionally only appended to (the v0.6.0 paragraph) — the full bilingual rewrite is PR C scope. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0b8b85a to
660ab26
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR B of the three-PR roadmap (
docs/superpowers/specs/2026-05-02-three-pr-roadmap.md),stacked on top of PR A (
feat/ops-and-ux). Pure stdlib (ctypes+urllib), no new pip dependencies. Previous handoff:docs/handoff/pr-a-summary.md.pools.py,--poolrepeatable). Round-robinrotation after N failures, exponential backoff once the full cycle
has passed without a single success.
StratumClient.set_endpoint()re-targets without recreating the client (preserves
on_share_result,locks).
solo.py,--solo --rpc-url ... --rpc-cookie ...).SoloClientducksStratumClient's surface somine()worksunchanged.
getblocktemplatepolling, BIP-34 height push, BIP-141witness commitment when
default_witness_commitmentis in thetemplate, full block serialization,
submitblockover JSON-RPC.Educational scope — coinbase scriptPubKey is
OP_RETURN, realpayout decode is left as a known TODO.
sha_native.py,--sha-backend). Loadslibcrypto-3.dll/libcrypto.so.3//opt/homebrew/lib/libcrypto.dylibvia
ctypes.CDLL, calls EVP API. No mid-state — sognately so, forhonest benchmark comparison. Falls back to
hashlibwhen libcryptois missing.
--benchmark --backendsruns all available backends back-to-backand prints
[bench] result: ctypes X MH/s (Yx vs hashlib-midstate).Hot path (
_worker_hashlib_midstate) is byte-identical with v0.5.0 —4-worker bench stays at ~3.18 MH/s.
block.pyendianness untouched.Tests: 145 → 225 (+80).
Test plan
py -3.11 -m unittest discover -s tests -v— 225 OKpy -3.11 -m hope_hash --help— all new flags presentpy -3.11 -m hope_hash --benchmark --bench-duration 1 --backends—runs hashlib + ctypes, prints comparison
py -3.11 -m hope_hash --benchmark --bench-duration 3 --workers 4— hashrate matches v0.5.0 baseline
py -3.11 -m hope_hash --solo <addr>— fails fast with clearmessage about missing
--rpc-urlpip installperformed; no third-party imports undersrc/hope_hash/Files
src/hope_hash/{pools,sha_native,solo}.py,tests/test_{pools,sha_native,solo,bench_backends}.py,docs/handoff/pr-b-summary.mdsrc/hope_hash/{cli,miner,parallel,stratum,bench,tui,__init__}.py,CHANGELOG.md,README.md,ROADMAP.mdSee
docs/handoff/pr-b-summary.mdfor full file map, gotchas,and open questions for PR C.