matroskin is an asynchronous Rust client for WhatsMiner ASIC hardware. An internal actor state machine encapsulates the WhatsMiner v3 TCP protocol—handling framing, encrypted authentication, and automatic reconnects behind a lock-free, strongly-typed actor.send(cmd) interface.
Warning
Operational & API Version Status:
- API Version: The library implements WhatsMiner API v3.0.3. The upstream API has since released v3.0.5; features introduced in 3.0.4/3.0.5 are not yet supported.
- Hardware Validation: Read-only queries (
get.*) and verified control commands (set.miner.fastboot,set.system.reboot,set.user.permission) have been tested on physical hardware (marked●). All other state-modifying operations (marked○) are verified against the mock harness and must be evaluated with caution prior to production use.
- Actor-based FSM: Single-owner Tokio task manages the connection lifecycle without mutexes or runtime locks.
- Complete API Coverage: All 39 WhatsMiner v3 commands implemented as typed, owned structures.
- Simple Command Dispatch: Uniform
actor.send(cmd).await?interface with strongly-typed request and response payloads. - Resilient Reconnection: Transparent backoff and reconnect queuing that preserves pending commands during connection drops.
- Secure by Default: Zeroizing credentials and session salts on drop, AES-256-ECB parameter encryption, and automatic secret redaction in debug logs.
Add matroskin and tokio to your Cargo.toml (requires Rust 1.85+ / Edition 2024):
[dependencies]
matroskin = "0.1.0"
tokio = { version = "1", features = ["full"] }Note: Initializing an
ActorviaActor::newrequires an active Tokio runtime context.Actor::clone()creates an independent actor instance; wrap inArc<Actor>to share one connected actor across tasks.
use matroskin::{
account::Account,
actor::Actor,
command::get_device_info::GetDeviceInfo,
password::Password,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. Initialize actor in `Created` state (synchronous in memory, no network I/O yet).
let actor = Actor::new("10.10.10.10:4433", Account::Super, Password::Super);
// 2. Queue non-blocking connect intent.
actor.connect()?;
// 3. Send an owned command by value.
// The command mailbox waits until the actor establishes a Connected session.
let response = actor.send(GetDeviceInfo::all()).await?;
println!("Device info: {:#?}", response.msg);
// 4. Graceful non-blocking shutdown intent.
actor.shutdown()?;
Ok(())
}All commands use flat structures with named fields and .new(...) constructors. Executing actor.send(cmd) returns Response<C::Response>, where C::Response is the typed payload in .msg:
use matroskin::{
account::{Account, Users},
actor::Actor,
command::{
get_device_info::GetDeviceInfo,
set_miner_pools::{PoolConfig, SetMinerPools},
set_user_permission::SetUserPermission,
},
password::Password,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let actor = Actor::new("10.10.10.10:4433", Account::Super, Password::Super);
actor.connect()?;
// Query device info: response payload is DeviceInfo (optional salt is redacted)
let info = actor.send(GetDeviceInfo::all()).await?;
println!("Salt present: {}", info.msg.salt.is_some());
// Set user permissions: requires All permission level
let perm = SetUserPermission::new(Users::User1, "set.system.led,set.miner.pools");
actor.send(perm).await?;
// Configure pools: 3 fixed entries with protected credentials (AES-256-ECB encrypted)
let pools = [
PoolConfig::new("stratum+tcp://pool1.com:3333", "worker1", "pass1"),
PoolConfig::new("stratum+tcp://pool2.com:3333", "worker2", "pass2"),
PoolConfig::new("stratum+tcp://pool3.com:3333", "worker3", "pass3"),
];
actor.send(SetMinerPools::new(pools)).await?;
actor.shutdown()?;
Ok(())
}Streaming operations take exclusive ownership of the network transport while active:
use matroskin::{account::Account, actor::Actor, password::Password};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let actor = Actor::new("10.10.10.10:4433", Account::Super, Password::Super);
actor.connect()?;
// Download system logs directly into an owned AsyncWrite destination
let log_file = tokio::fs::File::create("miner.log").await?;
actor.download_log(log_file).await?;
// Firmware upload accepts an owned AsyncRead source and exact byte length
// (Use with caution on production devices)
// let fw_file = tokio::fs::File::open("firmware.bin").await?;
// let len = fw_file.metadata().await?.len();
// actor.upload_firmware(fw_file, len).await?;
actor.shutdown()?;
Ok(())
}Status of implemented commands against the WhatsMiner API v3 (target specification: v3.0.3, current upstream: v3.0.5):
●Hardware verified: Tested and confirmed on physical WhatsMiner hardware.○Mock verified: Verified against the in-process mock test suite; use on physical hardware at your own risk.
| Command | Status | Level | Access | Description |
|---|---|---|---|---|
get.device.custom_data |
● | Public | Read-only | Retrieve device custom metadata fields |
get.device.info |
● | Public | Read-only | Retrieve system, network, miner, power, and error status |
get.fan.setting |
● | Public | Read-only | Get fan speed and temperature offset summary |
get.log.download |
● | Public | Read-only | Stream packaged .tgz log archive (download_log) |
get.miner.history |
● | Public | Read-only | Get miner history within a time window (≤ 24h) |
get.miner.setting |
● | Public | Read-only | Get power mode, limit, and fastboot settings |
get.miner.status |
● | Public | Read-only | Get detailed status: summary, pools, and edevs |
get.system.setting |
● | Public | Read-only | Get system settings (hostname, NTP, timezone) |
set.device.custom_data |
○ | Secured | Read-Write | Set custom metadata key-value pair |
set.fan.poweroff_cool |
○ | Secured | Read-Write | Toggle power-off cooling |
set.fan.temp_offset |
○ | Secured | Read-Write | Set fan temperature target offset (-10..10°C) |
set.fan.zero_speed |
○ | Secured | Read-Write | Toggle zero fan speed mode |
set.log.upload |
○ | Secured | Read-Write | Configure remote syslog upload server |
set.miner.cointype |
○ | Secured | Read-Write | Set coin mining algorithm (e.g. BTC) |
set.miner.fast_hash |
○ | Secured | Read-Write | Toggle fast hash mode |
set.miner.fastboot |
● | Secured | Read-Write | Toggle fastboot mode |
set.miner.heat_mode |
○ | Secured | Read-Write | Configure heat mode (e.g. normal, heating) |
set.miner.pools |
○ | Encrypted | Read-Write | Set 3 stratum mining pools (AES-256-ECB) |
set.miner.power |
○ | Secured | Read-Write | Set target power consumption in Watts |
set.miner.power_limit |
○ | Secured | Read-Write | Set maximum power limit threshold in Watts |
set.miner.power_mode |
○ | Secured | Read-Write | Set power mode (low, normal, high) |
set.miner.power_percent |
○ | Secured | Read-Write | Set target power percentage and mode |
set.miner.report |
○ | Secured | Read-Write | Configure periodic status report interval |
set.miner.restore_setting |
○ | Secured | Read-Write | Restore miner settings to factory defaults |
set.miner.service |
○ | Secured | Read-Write | Restart or stop miner hashing service |
set.miner.target_freq |
○ | Secured | Read-Write | Adjust target frequency percentage |
set.miner.upfreq_speed |
○ | Secured | Read-Write | Configure frequency ramp-up speed |
set.system.factory_reset |
○ | Secured | All (Super) | Factory reset control board settings |
set.system.hostname |
○ | Secured | Read-Write | Set device network hostname |
set.system.led |
○ | Secured | Read-Write | Set LED status mode (auto, manual, off) |
set.system.net_config |
○ | Secured | All (Super) | Configure network interface (DHCP or static) |
set.system.ntp_server |
○ | Secured | Read-Write | Configure NTP time synchronization servers |
set.system.reboot |
● | Secured | Read-Write | Immediately restart the ASIC controller |
set.system.time_randomized |
○ | Encrypted | Read-Write | Configure randomized start/stop time jitter |
set.system.timezone |
○ | Encrypted | Read-Write | Configure system timezone name and offset |
set.system.update_firmware |
○ | Secured | All (Super) | Stream binary firmware update (upload_firmware) |
set.system.webpools |
○ | Secured | Read-Write | Toggle web pool modification lock |
set.user.change_passwd |
○ | Encrypted | Super/User | Change account password (AES-256-ECB) |
set.user.permission |
● | Secured | All (Super) | Set comma-separated allowed commands for user |
The repository provides built-in Cargo aliases in .cargo/config.toml:
# Run all unit tests, mock device tests, and doc tests
cargo test
# Run in-process mock device tests (thread-isolated)
cargo test-mock
# Strict linter check across all targets and features
cargo lint
# Check code formatting
cargo fmt-check
# Verify documentation builds without warnings
cargo doc-check
# List hardware integration tests without connecting to an ASIC
cargo test-real-list
# Run physical hardware tests (requires ASIC reachable at MINER_ADDR)
MINER_ADDR=10.20.1.2:4433 cargo test --test real_device --features real-device- See mock device testing for in-process mock device testing.
- See physical hardware testing for real-device testing guidelines.
- See architecture reference for the actor, session, and protocol model.
- See AGENTS.md for repository terminology and contribution constraints.
Dual-licensed under either of:
at your option.
