Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
4 changes: 2 additions & 2 deletions .github/DISCUSSION_TEMPLATE/issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ body:
placeholder: |
Environment variables:
RUST_LOG=debug
MUJINA_POOL_URL=stratum+tcp://pool.example.com:3333
MUJINA_POOL_USER=your_wallet.worker_name
MUJINA__POOL__URL=stratum+tcp://pool.example.com:3333
MUJINA__POOL__USER=your_wallet.worker_name
render: bash
validations:
required: false
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Cargo.lock
/target/
/.cache/
mujina.yaml
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ repository = "https://github.com/256-Foundation/Mujina-Mining-Firmware"

[workspace.dependencies]
anyhow = "1.0"
clap = { version = "4", features = ["derive"] }
config = { version = "0.14", features = ["yaml"] }
async-trait = "0.1"
axum = "0.8"
bitcoin = "0.32"
Expand Down
81 changes: 71 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ On Debian or Ubuntu:
git clone https://github.com/256foundation/mujina.git
cd mujina
sudo apt-get install libudev-dev libssl-dev
MUJINA_CPUMINER_THREADS=1 MUJINA_CPUMINER_DUTY=50 MUJINA_USB_DISABLE=1 \
MUJINA__BOARDS__CPU_MINER__ENABLED=true \
MUJINA__BOARDS__CPU_MINER__THREADS=1 \
MUJINA__BACKPLANE__USB_ENABLED=false \
cargo run --bin mujina-minerd
```

Expand Down Expand Up @@ -120,22 +122,81 @@ without `just` installed.

## Running

Mujina is currently configured through environment variables.
Persistent configuration via the REST API and CLI will follow as those
interfaces mature.
Configuration is managed through a YAML config file, environment variables, or
CLI flags. See [Configuration](docs/configuration.md) for the full reference.

### Connecting to a job source

Point Mujina at a Stratum v1 mining pool:

```bash
MUJINA_POOL_URL="stratum+tcp://pool.example.com:3333" \
MUJINA_POOL_USER="your-address.worker" \
MUJINA__POOL__URL="stratum+tcp://localhost:3333" \
MUJINA__POOL__USER="bc1qce93hy5rhg02s6aeu7mfdvxg76x66pqqtrvzs3.mujina" \
MUJINA__POOL__PASSWORD="custom-password" \
cargo run
```

The password defaults to "x" if not specified.

Without `pool.url` set, the miner runs with a dummy job source that generates
synthetic mining work, useful for testing hardware without a pool connection.

### API Server

The REST API listens on `127.0.0.1:7785` by default. To listen
on all interfaces:

```bash
MUJINA__API__LISTEN="0.0.0.0" cargo run
```

See [REST API](docs/api.md) for endpoints and details.

### Running Without Hardware

For development and testing without physical mining hardware, the miner
includes a CPU mining backend. See [CPU Mining](docs/cpu-mining.md) for
details.

A container image is available for deploying to cloud infrastructure or
Kubernetes for pool and miner testing. See [Container Image](docs/container.md).

### Log Levels

Control output verbosity with `RUST_LOG`:

```bash
# Info level (default) -- shows pool connection, shares, errors
cargo run

# Debug level -- adds job distribution, hardware state changes
RUST_LOG=mujina_miner=debug cargo run

# Trace level -- shows all protocol traffic (serial, network, I2C)
RUST_LOG=mujina_miner=trace cargo run
```

Target specific modules for focused debugging:

```bash
# Trace just the Stratum v1 client
RUST_LOG=mujina_miner::stratum_v1=trace cargo run

# Debug Stratum v1, trace BM13xx protocol
RUST_LOG=mujina_miner::stratum_v1=debug,mujina_miner::asic::bm13xx=trace cargo run
```

Combine pool configuration with logging as needed:

```bash
RUST_LOG=mujina_miner=debug \
MUJINA__POOL__URL="stratum+tcp://pool.example.com:3333" \
MUJINA__POOL__USER="your-address.worker" \
cargo run --bin mujina-minerd
```

`MUJINA_POOL_USER` defaults to `mujina-testing` and `MUJINA_POOL_PASS`
defaults to `x`, so only `MUJINA_POOL_URL` is strictly required.
`MUJINA__POOL__USER` defaults to `mujina-testing` and `MUJINA__POOL__PASSWORD`
defaults to `x`, so only `MUJINA__POOL__URL` is strictly required.

### Testing without a pool

Expand Down Expand Up @@ -178,10 +239,10 @@ Mujina logs the API bind address at startup. By default it's

```bash
# All interfaces, default port
MUJINA_API_LISTEN="0.0.0.0" cargo run --bin mujina-minerd
MUJINA__API__LISTEN="0.0.0.0" cargo run --bin mujina-minerd

# All interfaces, custom port
MUJINA_API_LISTEN="0.0.0.0:9000" cargo run --bin mujina-minerd
MUJINA__API__LISTEN="0.0.0.0:9000" cargo run --bin mujina-minerd
```

See [REST API](docs/api.md) for endpoints and conventions. The
Expand Down
121 changes: 121 additions & 0 deletions configs/mujina.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Mujina Miner — example configuration
#
# Copy this file to /etc/mujina/mujina.yaml and edit as needed.
# All keys are optional; values shown here are the hard-coded defaults.
#
# Full documentation: docs/configuration.md

# ------------------------------------------------------------
# daemon — process and logging
# ------------------------------------------------------------
daemon:
# Minimum log level emitted to stdout or journald.
# Values: error | warn | info | debug | trace
log_level: "info"

# PID file written on startup, removed on clean exit.
# Null disables PID file creation.
pid_file: ~

# Emit systemd sd_notify readiness notifications.
# Enable when running under a systemd Type=notify service unit.
systemd: false


# ------------------------------------------------------------
# api — HTTP REST API server
# ------------------------------------------------------------
api:
# TCP address and port for the API server.
# Use 127.0.0.1 (loopback) to restrict access to localhost.
# Use 0.0.0.0 to expose on all interfaces (see security note below).
listen: "127.0.0.1:7785"

# WARNING: The API has no authentication. Binding to a non-loopback
# address exposes full miner control to the network. Only do this
# behind a firewall or reverse proxy that provides authentication.


# ------------------------------------------------------------
# pool — primary mining pool
# ------------------------------------------------------------
pool:
# Stratum v1 pool URL.
# Format: stratum+tcp://<host>:<port>
# Required for actual mining. When absent, the daemon starts with
# a dummy job source (useful for hardware testing).
url: ~

# Worker name, typically wallet_address.worker_name
user: "mujina-testing"

# Worker password. Most pools accept "x".
password: "x"

# Target share rate in shares per minute for the forced-rate wrapper.
# When set, overrides the pool's share target so a CPU miner finds shares
# at this rate regardless of pool difficulty. Useful for testing share
# submission flow without waiting days for a real share.
# Null disables the wrapper (normal pool difficulty applies).
forced_rate: ~


# ------------------------------------------------------------
# backplane — board discovery and lifecycle management
# ------------------------------------------------------------
backplane:
# Enable USB device discovery and hotplug monitoring.
# Disable for environments without USB mining hardware
# (e.g., CPU-only testing).
usb_enabled: true


# ------------------------------------------------------------
# boards — per-board-type hardware configuration
# ------------------------------------------------------------
boards:

# -- Bitaxe family (BM1370-based boards) --
# NOTE: These fields are parsed but not yet wired to board behavior.
# They are reserved for near-term implementation.
bitaxe:
# Emergency shutdown temperature in Celsius.
# The board halts hashing if any sensor reads above this value.
temp_limit_c: 85.0

# Fan speed bounds as a percentage of full speed.
# The thermal controller adjusts within this range.
fan_min_pct: 20
fan_max_pct: 100

# Maximum board power consumption in watts.
# Null disables the power cap (hardware default applies).
power_limit_w: ~

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather just skip this and then each author will implement support for their upcoming features.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept thinking about this and wanted to clarify, I'm coming from a place of implementing the thermal control for the bitaxes and not knowing for sure what should be exposed, if you check this config file it has many properties and each of them are arguably important for this implementation.

I believe the properties there might change a lot and so it's introduced already "out of sync" while both this and #33 are open at the same time. If anything I'd be more inclined exposing them all and giving our users the power of customizing everything, but having safe defaults.


# -- CPU miner (software SHA256d, for testing and development) --
cpu_miner:
# Enable the software CPU miner.
# When false, no CPU mining threads are started.
enabled: false

# Number of OS threads to dedicate to hashing.
threads: 1

# Target CPU utilisation per thread as a percentage (1–100).
# At 80%, each thread hashes for 800 ms then sleeps for 200 ms.
# Useful on cloud instances that alert on sustained 100% CPU usage.
duty_percent: 50


# ------------------------------------------------------------
# hash_thread — ASIC hash thread tuning
# NOTE: These fields are parsed but not yet wired to board behavior.
# They are reserved for near-term implementation.
# ------------------------------------------------------------
hash_thread:
# Difficulty target configured on-chip for share reporting.
# Lower values produce more frequent shares (useful for health
# monitoring); higher values reduce message volume on large
# installations. The scheduler still applies pool difficulty
# filtering before forwarding shares to the pool.
chip_target_difficulty: 256

@jayrmotta jayrmotta Apr 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: May be worth pointing out which PR, branch, discussion, etc, led you to this near-term implementation.

6 changes: 3 additions & 3 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

Mujina exposes an HTTP API on port 7785 (ASCII "MU") for
monitoring and control. It binds to localhost by default. Set
`MUJINA_API_LISTEN` to override the listen address:
`api.listen` in the config file, or use the env var:

```bash
MUJINA_API_LISTEN="0.0.0.0" cargo run
MUJINA__API__LISTEN="0.0.0.0" cargo run
```

The port defaults to 7785 if not specified, or you can
override it with `MUJINA_API_LISTEN="0.0.0.0:9000"`.
override it with `MUJINA__API__LISTEN="0.0.0.0:9000"`.

The API currently has no authentication or encryption, so
binding to a non-localhost address exposes it to the network
Expand Down
Loading
Loading