# HASHBATTLE — automatic signed CPU/GPU mining

Choose CPU or GPU. The miner fetches live work, solves it, verifies the proof,
revalidates chain state and price, **signs and sends with your own wallet**, waits
for the receipt, then repeats automatically. No manual calldata or separate
signer is needed for each warrior.

## Start

Requires **Python 3.10+**, its `venv` support, **GCC** and Bash on Linux/macOS.
For GPU mining, also install your GPU vendor's drivers and a working native
WebGPU backend. A software GPU is rejected; use CPU mode instead if no supported
hardware adapter is available. GPU compatibility and speed depend on your system;
this guide makes no hardware benchmark or universal-support claim.

Extract the **entire ZIP** into one directory. Before the first launch, copy
`chain.json.example` to `chain.json` and edit it **once**:

```bash
cp chain.json.example chain.json
# Edit chain.json: replace rpc, contract and chainId nulls with trusted values.
chmod +x start.sh
```

No default RPC, contract or chain ID ships. The example deliberately contains:

```json
{
  "rpc": null,
  "contract": null,
  "chainId": null
}
```

Use the intended deployment's trusted public configuration. `chainId` is the
expected numeric network ID, not a value to blindly copy from an unknown RPC.
The signed loop requires it and checks the RPC's network against it.

From the downloaded directory, run **one** of:

```bash
./start.sh --engine cpu
```

```bash
./start.sh --engine gpu
```

Enter your **dedicated mining wallet's private key** at the hidden prompt **once
per process**. It is not echoed or saved; the running process holds it in memory
so it can sign subsequent mints without another prompt. Do not use your main
wallet or treasury wallet. Fund the dedicated wallet only with what you can lose.
Never send your key to the site, a support message, or an RPC provider.

The launcher creates `.venv` if needed, installs `eth-account==0.14.0` and
`wgpu==0.31.0` using **that environment's Python and pip**, then runs `hb_mine.py`.
Both dependencies are installed for either mode so switching CPU/GPU needs no
extra setup; CPU mode does not need GPU drivers. Installed pinned packages are
reused on later launches. The engine compiles the bundled C kernel on first use
with GCC; both CPU and GPU proofs are verified with that C implementation.

## Automatic means real spending

The default loop is unlimited (`--max-mints 0`). It pays the current enlist price
**plus gas** for every submitted transaction and continues until **Ctrl+C**, a
configured limit, insufficient balance, or an error. A failed/reverted transaction
can still consume gas. Mining is not free and does not guarantee profit or a mint.

A bounded first run:

```bash
./start.sh --engine cpu --max-mints 1
```

Optional guards (choose values you are willing to spend; these are examples, not
recommended budgets):

```bash
./start.sh --engine gpu --max-mints 3 \
  --max-price-eth 0.001 \
  --max-gas-price-gwei 2 \
  --max-total-cost-eth 0.005
```

- `--max-mints N`: stop after N confirmed mints; `0` means unlimited.
- `--max-price-eth`: maximum enlist price per transaction, excluding gas.
- `--max-gas-price-gwei`: maximum gas price the miner may sign with.
- `--max-total-cost-eth`: **per-transaction** cap on enlist price plus the full
  signed gas allowance. It is **not a session budget**: repeated mints can spend
  more in total. Combine it with `--max-mints` and a limited wallet balance.
  This is a guard, not a refund or protection from bad RPC data.
- `--state-dir PATH`: persist transaction progress. Pending **signed raw
  transactions**, not your private key, are saved for reconciliation on restart.
  Signed transactions can be rebroadcast: keep state private. Do not delete it
  while a transaction is unresolved, or run two miners with the same wallet/state.

**Ctrl+C cannot cancel an already signed or broadcast transaction.** It may still
be mined. Restart with the same wallet, network and state directory so the miner
reconciles pending work before signing new work. The hidden key prompt occurs
again in a new process.

The state directory retains the **latest completed outcome** as a private
`.completed` record, including signed transaction bytes, so interrupted cleanup
cannot lose a validated result. A recovered success counts toward `--max-mints`
on the next launch; it is not a cumulative lifetime/session budget. For example,
restarting with `--max-mints 1` after a recorded success stops without a new mint.
A local disk error stops the miner: keep the state, repair the storage problem,
then restart to reconcile. Do not share or delete recovery records blindly.

## Other key/config options

The hidden prompt is the simplest default. For unattended use, the miner also
accepts `--key-file PATH` (a player-created file with permissions **0600**) or the
`HB_PRIVATE_KEY` environment variable. Treat both as sensitive: environment
variables may be exposed to other processes, shell history or logs. Do not put a
private key in command-line arguments, `chain.json`, this kit, or a screenshot.
The launcher neither downloads keys nor reads shell key files, prints keys,
stores them, or sends telemetry.

`--config PATH` selects another public chain configuration. Without it, the miner
looks for `chain.json` next to `hb_mine.py`. You can instead set all three target
fields using `--rpc RPC_URL --contract CONTRACT_ADDRESS --chain CHAIN_ID`.
CLI-only setup requires no existing null configuration: do not copy the empty
example to `chain.json` for this route, or select an absent file with
`--config PATH`. Any existing selected configuration must be fully populated,
even when CLI target options are supplied.
Use `./start.sh --help` for the complete CLI. Relative paths are resolved from the
kit directory; use absolute paths for keys/config/state kept elsewhere.

**An RPC can lie.** Checking chain ID, contract code, live work and price against
one endpoint does not authenticate that endpoint or prove the contract is the
intended deployment. Use trusted configuration and an RPC you trust. Review the
code before giving it a funded key; local signing and proof checks are not a
security guarantee against malicious configuration, dependencies or RPC data.

## Included files

- `start.sh`, `requirements.txt`: one-command isolated setup and launch.
- `hb_mine.py`: automatic local signing, submission, receipt wait and repeat.
- `hb_engines.py`: CPU/GPU engines and C proof verification.
- `gpu_miner.wgsl`: GPU hashing shader.
- `keccak256_miner.c`: bundled C solver/verifier, compiled locally.
- `chain.json.example`: public, empty network template; **no secrets**.
- `hb_work.py`: optional advanced **keyless/read-only helper** for work inspection,
  calldata construction and local proof checks. It does not sign or run the
  automatic loop; normal mining uses `start.sh` instead.

Browser mining is separate: the site runs its **own mining** and asks its
connected wallet to sign. It is not a submission/import screen for a proof found
by this command-line miner.

## PoW reference (advanced)

The core Solidity source is not included. This is the public mining interface.

**Preimage — 116 bytes exactly:**

| Bytes | Field | Encoding |
|-------|-------|----------|
| 0:20 | miner | your signer address, raw 20 bytes |
| 20:52 | nonce | uint256 big-endian |
| 52:84 | prevWork | uint256 big-endian, from `prevWork()` |
| 84:116 | anchor | raw 32 bytes, from `challengeAnchor()` |

**Accept rule:** `uint256(keccak256(preimage)) < targetFor(yourAddress)`.
This is Ethereum Keccak-256 (`0x01 … 0x80` padding), **not SHA3-256**.
The nonce is the full uint256, not a 32-bit counter. Your personal target must
be read with your signer address, not the zero address.

**Submission:** `mine(uint256 nonce, uint256 anchorBlock)` — selector
`0x071e9503`, payable with the live `enlistPrice()` as `msg.value`.
Calldata is that selector followed by the two uint256 big-endian words.

`prevWork` changes on each accepted mint, invalidating old work. Anchors must be
no older than **250 blocks** (`ANCHOR_WINDOW`) and `anchorBlock` must be strictly
less than the current L2 block. A stale anchor reverts and can burn gas. Read the
anchor from `challengeBlock()` / `challengeAnchor()`: on an Arbitrum-style L2 the
contract uses its L2 block hash, not the header hash from `eth_getBlockByNumber`.
Revalidation reduces stale submissions but cannot eliminate races before inclusion.

| Selector | Function | Purpose |
|----------|----------|---------|
| `0xa4da5da2` | `prevWork()` | current preimage word |
| `0xcefc2977` | `challengeBlock()` | anchor block number |
| `0xb5da0777` | `challengeAnchor()` | anchor hash |
| `0x16ccc8c0` | `targetFor(address)` | personal accept threshold |
| `0x5ce65b1d` | `currentBoost(address)` | personal burst penalty |
| `0x9eb5ee97` | `enlistPrice()` | live price to attach |
| `0xe1b0385f` | `currentAge()` | contract epoch |
| `0xe71f3134` | `totalEnlisted()` | total warriors minted |
| `0x0d768f34` | `livingMercenaries()` | warriors alive |
| `0x071e9503` | `mine(uint256,uint256)` | submit proof and pay |

Only the public `mine()` path is used: no privileged mint, relay, gas sponsorship,
or founder signer. One proof per transaction; the live target and enlist price
can change. Everyone mines and pays with their own wallet.
