Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion asic-rs-core/src/traits/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ use crate::{

#[async_trait]
pub trait MinerFirmware: ToString + DiscoveryCommands {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel, ModelSelectionError>;
async fn get_model(ip: IpAddr) -> Result<impl MinerModel + Send, ModelSelectionError>;
async fn get_version(ip: IpAddr) -> Option<semver::Version>;
}
59 changes: 58 additions & 1 deletion asic-rs-core/src/traits/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::{
miner::{MinerData, TuningTarget},
pool::PoolGroupData,
},
traits::firmware::MinerFirmware,
traits::model::MinerModel,
util::unix_timestamp_secs,
};
Expand All @@ -42,15 +43,29 @@ pub trait MinerConstructor {
fn new(ip: IpAddr, model: impl MinerModel, version: Option<semver::Version>) -> Box<dyn Miner>;
}

#[async_trait]
pub trait Miner:
GetMinerData + HasMinerControl + SupportsConfigs + UpgradeFirmware + HasAuth + HasDefaultAuth
{
async fn revalidate(&self) -> anyhow::Result<bool>;
}

#[async_trait]
impl<
T: GetMinerData + HasMinerControl + SupportsConfigs + UpgradeFirmware + HasAuth + HasDefaultAuth,
T: GetMinerData
+ HasMinerControl
+ SupportsConfigs
+ UpgradeFirmware
+ Validate
+ HasAuth
+ HasDefaultAuth,
> Miner for T
{
// Needs to be implemented here because otherwise Miner becomes
// dyn incompatible.
async fn revalidate(&self) -> anyhow::Result<bool> {
<Self as Validate>::revalidate(self).await
}
}

pub trait HasMinerControl:
Expand Down Expand Up @@ -384,6 +399,48 @@ pub trait GraphQLClient: APIClient {
) -> anyhow::Result<Value>;
}

#[async_trait]
pub trait Validate: GetIP + GetDeviceInfo + Send + Sync {
type Firmware: MinerFirmware + Default + Send + Sync + 'static;

fn validate(_version: Option<&semver::Version>) -> bool
where
Self: Sized,
{
true
}

/// Re-run this backend's firmware discovery checks against the miner IP.
///
/// Returns `true` when the device still identifies as the same make, model,
/// firmware family, and backend version range. Returns `false` for offline
/// devices, unsupported responses, or devices that would no longer be valid
/// for this backend.
async fn revalidate(&self) -> anyhow::Result<bool>
where
Self: Sized,
{
let expected = self.get_device_info();

let Ok(model) = <Self::Firmware as MinerFirmware>::get_model(self.get_ip()).await else {
return Ok(false);
};

if model.make_name() != expected.make {
return Ok(false);
}
if model.to_string() != expected.model {
return Ok(false);
}
if Self::Firmware::default().to_string() != expected.firmware {
return Ok(false);
}

let version = <Self::Firmware as MinerFirmware>::get_version(self.get_ip()).await;
Ok(Self::validate(version.as_ref()))
}
}

// Data traits
pub trait GetIP: Send + Sync {
/// Returns the IP address of the miner.
Expand Down
12 changes: 7 additions & 5 deletions asic-rs-firmwares/antminer/src/backends/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ pub mod v2023_07;
use std::net::IpAddr;

use asic_rs_core::traits::{
miner::{Miner, MinerConstructor},
miner::{Miner, MinerConstructor, Validate},
model::MinerModel,
};
use semver::Version;
use v2020::AntMinerV2020;
use v2023_07::AntMinerV202307;

Expand All @@ -16,9 +15,12 @@ pub struct AntMiner;
impl MinerConstructor for AntMiner {
#[allow(clippy::new_ret_no_self)]
fn new(ip: IpAddr, model: impl MinerModel, version: Option<semver::Version>) -> Box<dyn Miner> {
match version {
Some(ref v) if *v < Version::new(2023, 7, 0) => Box::new(AntMinerV2020::new(ip, model)),
_ => Box::new(AntMinerV202307::new(ip, model)),
if AntMinerV2020::validate(version.as_ref()) {
Box::new(AntMinerV2020::new(ip, model))
} else if AntMinerV202307::validate(version.as_ref()) {
Box::new(AntMinerV202307::new(ip, model))
} else {
Box::new(AntMinerV202307::new(ip, model))
}
}
}
9 changes: 9 additions & 0 deletions asic-rs-firmwares/antminer/src/backends/v2020/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use async_trait::async_trait;
use macaddr::MacAddr;
use measurements::{AngularVelocity, Frequency, Power, Temperature};
use rpc::AntMinerRPCAPI;
use semver::Version;
use serde_json::{Value, json};
use web::AntMinerWebAPI;

Expand Down Expand Up @@ -1157,6 +1158,14 @@ impl HasAuth for AntMinerV2020 {
}
}

impl Validate for AntMinerV2020 {
type Firmware = AntMinerStockFirmware;

fn validate(version: Option<&semver::Version>) -> bool {
version.is_some_and(|v| *v < Version::new(2023, 7, 0))
}
}

#[async_trait]
impl SupportsTuningConfig for AntMinerV2020 {
async fn set_tuning_config(
Expand Down
9 changes: 9 additions & 0 deletions asic-rs-firmwares/antminer/src/backends/v2023_07/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use async_trait::async_trait;
use macaddr::MacAddr;
use measurements::{AngularVelocity, Frequency, Power, Temperature};
use rpc::AntMinerRPCAPI;
use semver::Version;
use serde_json::{Value, json};
use web::AntMinerWebAPI;

Expand Down Expand Up @@ -1084,6 +1085,14 @@ impl HasAuth for AntMinerV202307 {
}
}

impl Validate for AntMinerV202307 {
type Firmware = AntMinerStockFirmware;

fn validate(version: Option<&semver::Version>) -> bool {
version.is_some_and(|v| *v >= Version::new(2023, 7, 0))
}
}

#[async_trait]
impl SupportsTuningConfig for AntMinerV202307 {
async fn set_tuning_config(
Expand Down
2 changes: 1 addition & 1 deletion asic-rs-firmwares/antminer/src/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ async fn get_version_with_auth(ip: IpAddr, auth: &MinerAuth) -> Option<semver::V
impl MinerFirmware for AntMinerStockFirmware {
/// Uses default credentials. For custom credentials, use `build_miner`
/// which passes auth through to the underlying digest-auth requests.
async fn get_model(ip: IpAddr) -> Result<impl MinerModel, ModelSelectionError> {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel + Send, ModelSelectionError> {
let default = crate::backends::v2020::AntMinerV2020::default_auth();
get_model_with_auth(ip, &default).await
}
Expand Down
4 changes: 4 additions & 0 deletions asic-rs-firmwares/auradine/src/backends/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1407,6 +1407,10 @@ impl HasAuth for AuradineV1 {
}
}

impl Validate for AuradineV1 {
type Firmware = AuradineFirmware;
}

#[async_trait]
impl SupportsTuningConfig for AuradineV1 {
fn supports_tuning_config(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion asic-rs-firmwares/auradine/src/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn parse_semver_like(version_str: &str) -> Option<semver::Version> {

#[async_trait]
impl MinerFirmware for AuradineFirmware {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel, ModelSelectionError> {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel + Send, ModelSelectionError> {
let data = util::send_rpc_command(&ip, "devdetails")
.await
.ok_or(ModelSelectionError::NoModelResponse)?;
Expand Down
4 changes: 4 additions & 0 deletions asic-rs-firmwares/avalonminer/src/backends/avalon_a/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,10 @@ impl UpgradeFirmware for AvalonAMiner {
impl HasAuth for AvalonAMiner {}
impl HasDefaultAuth for AvalonAMiner {}

impl Validate for AvalonAMiner {
type Firmware = AvalonStockFirmware;
}

#[async_trait]
impl SupportsTuningConfig for AvalonAMiner {
fn supports_tuning_config(&self) -> bool {
Expand Down
4 changes: 4 additions & 0 deletions asic-rs-firmwares/avalonminer/src/backends/avalon_q/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,10 @@ impl UpgradeFirmware for AvalonQMiner {
impl HasAuth for AvalonQMiner {}
impl HasDefaultAuth for AvalonQMiner {}

impl Validate for AvalonQMiner {
type Firmware = AvalonStockFirmware;
}

#[async_trait]
impl SupportsTuningConfig for AvalonQMiner {
fn supports_tuning_config(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion asic-rs-firmwares/avalonminer/src/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl DiscoveryCommands for AvalonStockFirmware {

#[async_trait]
impl MinerFirmware for AvalonStockFirmware {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel, ModelSelectionError> {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel + Send, ModelSelectionError> {
let response = util::send_rpc_command(&ip, "version").await;

match response {
Expand Down
7 changes: 4 additions & 3 deletions asic-rs-firmwares/bitaxe/src/backends/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::net::IpAddr;

use asic_rs_core::traits::{
miner::{Miner, MinerConstructor},
miner::{Miner, MinerConstructor, Validate},
model::MinerModel,
};
use semver::Version;
pub use v2_0_0::Bitaxe200;
pub use v2_9_0::Bitaxe290;

Expand All @@ -16,8 +15,10 @@ pub struct Bitaxe;
impl MinerConstructor for Bitaxe {
#[allow(clippy::new_ret_no_self)]
fn new(ip: IpAddr, model: impl MinerModel, version: Option<semver::Version>) -> Box<dyn Miner> {
if version.is_some_and(|v| v >= Version::new(2, 0, 0) && v < Version::new(2, 9, 0)) {
if Bitaxe200::validate(version.as_ref()) {
Box::new(Bitaxe200::new(ip, model))
} else if Bitaxe290::validate(version.as_ref()) {
Box::new(Bitaxe290::new(ip, model))
} else {
Box::new(Bitaxe290::new(ip, model))
}
Expand Down
9 changes: 9 additions & 0 deletions asic-rs-firmwares/bitaxe/src/backends/v2_0_0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use asic_rs_makes_bitaxe::hardware::BitaxeControlBoard;
use async_trait::async_trait;
use macaddr::MacAddr;
use measurements::{AngularVelocity, Frequency, Power, Temperature, Voltage};
use semver::Version;
use serde_json::Value;
use web::BitaxeWebAPI;

Expand Down Expand Up @@ -562,6 +563,14 @@ impl UpgradeFirmware for Bitaxe200 {
impl HasAuth for Bitaxe200 {}
impl HasDefaultAuth for Bitaxe200 {}

impl Validate for Bitaxe200 {
type Firmware = BitaxeFirmware;

fn validate(version: Option<&semver::Version>) -> bool {
version.is_some_and(|v| *v >= Version::new(2, 0, 0) && *v < Version::new(2, 9, 0))
}
}

#[async_trait]
impl SupportsTuningConfig for Bitaxe200 {
fn supports_tuning_config(&self) -> bool {
Expand Down
6 changes: 3 additions & 3 deletions asic-rs-firmwares/bitaxe/src/backends/v2_0_0/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,17 @@ impl WebAPIClient for BitaxeWebAPI {
Ok(json_data) => return Ok(json_data),
Err(e) => {
if attempt == self.retries {
return Err(BitaxeError::ParseError(e.to_string()))?;
Err(BitaxeError::ParseError(e.to_string()))?;
}
}
}
} else if attempt == self.retries {
return Err(BitaxeError::HttpError(response.status().as_u16()))?;
Err(BitaxeError::HttpError(response.status().as_u16()))?;
}
}
Err(e) => {
if attempt == self.retries {
return Err(e)?;
Err(e)?;
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions asic-rs-firmwares/bitaxe/src/backends/v2_9_0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use asic_rs_makes_bitaxe::hardware::BitaxeControlBoard;
use async_trait::async_trait;
use macaddr::MacAddr;
use measurements::{AngularVelocity, Frequency, Power, Temperature, Voltage};
use semver::Version;
use serde_json::Value;
use web::BitaxeWebAPI;

Expand Down Expand Up @@ -546,6 +547,14 @@ impl UpgradeFirmware for Bitaxe290 {
impl HasAuth for Bitaxe290 {}
impl HasDefaultAuth for Bitaxe290 {}

impl Validate for Bitaxe290 {
type Firmware = BitaxeFirmware;

fn validate(version: Option<&semver::Version>) -> bool {
version.is_some_and(|v| *v >= Version::new(2, 9, 0))
}
}

#[async_trait]
impl SupportsTuningConfig for Bitaxe290 {
fn supports_tuning_config(&self) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion asic-rs-firmwares/bitaxe/src/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl DiscoveryCommands for BitaxeFirmware {

#[async_trait]
impl MinerFirmware for BitaxeFirmware {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel, ModelSelectionError> {
async fn get_model(ip: IpAddr) -> Result<impl MinerModel + Send, ModelSelectionError> {
let response = util::send_web_command(&ip, "/api/system/info").await;

match response {
Expand Down
22 changes: 13 additions & 9 deletions asic-rs-firmwares/braiins/src/backends/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ pub mod v26_04;
use std::net::IpAddr;

use asic_rs_core::traits::{
miner::{Miner, MinerConstructor},
miner::{Miner, MinerConstructor, Validate},
model::MinerModel,
};

use semver::Version;
use v21_09::BraiinsV2109;
use v25_03::BraiinsV2503;
use v25_05::BraiinsV2505;
Expand All @@ -23,13 +22,18 @@ pub struct Braiins;

impl MinerConstructor for Braiins {
fn new(ip: IpAddr, model: impl MinerModel, version: Option<semver::Version>) -> Box<dyn Miner> {
match version {
Some(ref v) if *v >= Version::new(26, 4, 0) => Box::new(BraiinsV2604::new(ip, model)),
Some(ref v) if *v >= Version::new(25, 7, 0) => Box::new(BraiinsV2507::new(ip, model)),
Some(ref v) if *v >= Version::new(25, 5, 0) => Box::new(BraiinsV2505::new(ip, model)),
Some(ref v) if *v >= Version::new(25, 3, 0) => Box::new(BraiinsV2503::new(ip, model)),
Some(ref v) if *v >= Version::new(24, 9, 0) => Box::new(BraiinsV2109::new(ip, model)),
_ => Box::new(BraiinsV2109::new(ip, model)),
if BraiinsV2604::validate(version.as_ref()) {
Box::new(BraiinsV2604::new(ip, model))
} else if BraiinsV2507::validate(version.as_ref()) {
Box::new(BraiinsV2507::new(ip, model))
} else if BraiinsV2505::validate(version.as_ref()) {
Box::new(BraiinsV2505::new(ip, model))
} else if BraiinsV2503::validate(version.as_ref()) {
Box::new(BraiinsV2503::new(ip, model))
} else if BraiinsV2109::validate(version.as_ref()) {
Box::new(BraiinsV2109::new(ip, model))
} else {
Box::new(BraiinsV2109::new(ip, model))
}
}
}
9 changes: 9 additions & 0 deletions asic-rs-firmwares/braiins/src/backends/v21_09/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use asic_rs_core::{
use async_trait::async_trait;
use macaddr::MacAddr;
use measurements::{AngularVelocity, Frequency, Power, Temperature, Voltage};
use semver::Version;
use serde_json::{Value, json};
use web::BraiinsWebAPI;

Expand Down Expand Up @@ -982,6 +983,14 @@ impl HasAuth for BraiinsV2109 {
}
}

impl Validate for BraiinsV2109 {
type Firmware = BraiinsFirmware;

fn validate(version: Option<&semver::Version>) -> bool {
version.is_some_and(|v| *v < Version::new(25, 3, 0))
}
}

#[async_trait]
impl SupportsTuningConfig for BraiinsV2109 {
fn supports_tuning_config(&self) -> bool {
Expand Down
Loading