matroskin 0.1.0

whatsminer api client lib
Documentation

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.

Highlights

  • 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.

Quickstart

Add matroskin and tokio to your Cargo.toml (requires Rust 1.85+ / Edition 2024):

[dependencies]
matroskin = "0.1.0"
tokio = { version = "1", features = ["full"] }

Basic Usage

Note: Initializing an Actor via Actor::new requires an active Tokio runtime context. Actor::clone() creates an independent actor instance; wrap in Arc<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(())
}

Flat Commands & Typed Parameters

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(())
}

Direct Streaming Operations

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(())
}

Command Inventory

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

Development & Testing

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

License

Dual-licensed under either of:

at your option.