dg_fast_farmer 2.0.2

A lite farmer for the Chia Blockchain.
Documentation
use crate::farmer::config::Config;
use crate::farmer::{CA_PRIVATE_CRT, PRIVATE_CRT, PRIVATE_KEY};
use dg_logger::{DruidGardenLogger, TimestampFormat};
use dg_xch_clients::ClientSSLConfig;
use dg_xch_clients::rpc::full_node::FullnodeClient as RpcClient;
use dg_xch_core::blockchain::sized_bytes::Bytes32;
use dg_xch_core::ssl::load_certs_from_bytes;
use dg_xch_core::traits::SizedBytes;
use dg_xch_core::utils::hash_256;
use home::home_dir;
use log::Level;
use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::path::{Path, PathBuf};
use std::sync::Arc;
use tokio::sync::RwLock;

pub(crate) fn get_root_path() -> PathBuf {
    let prefix = home_dir().unwrap_or(Path::new("/").to_path_buf());
    prefix.as_path().join(Path::new(".config/fast_farmer/"))
}

pub fn get_config_path() -> PathBuf {
    get_root_path()
        .as_path()
        .join(Path::new("fast_farmer.yaml"))
}

pub(crate) fn get_device_id_path() -> PathBuf {
    get_root_path().as_path().join(Path::new("device_id.bin"))
}

pub fn get_ssl_root_path<C: Clone>(config: &Config<C>) -> PathBuf {
    if let Some(ssl_root_path) = &config.ssl_root_path {
        PathBuf::from(ssl_root_path)
    } else {
        get_root_path().as_path().join(Path::new("ssl/"))
    }
}

pub(crate) fn rpc_client_from_config<C: Clone>(
    config: &Config<C>,
    headers: &Option<HashMap<String, String>>,
) -> Result<Arc<RpcClient>, Error> {
    Ok(Arc::new(RpcClient::new(
        &config.fullnode_rpc_host,
        config.fullnode_rpc_port,
        600,
        if is_community_node(config) {
            None
        } else {
            config.ssl_root_path.clone().map(|s| ClientSSLConfig {
                ssl_crt_path: Path::new(&s)
                    .join(PRIVATE_CRT)
                    .to_string_lossy()
                    .to_string(),
                ssl_key_path: Path::new(&s)
                    .join(PRIVATE_KEY)
                    .to_string_lossy()
                    .to_string(),
                ssl_ca_crt_path: Path::new(&s)
                    .join(CA_PRIVATE_CRT)
                    .to_string_lossy()
                    .to_string(),
            })
        },
        headers,
    )?))
}

pub async fn load_client_id<C: Clone>(config: Arc<RwLock<Config<C>>>) -> Result<Bytes32, Error> {
    let ssl_path = {
        let config = config.read().await;
        get_ssl_root_path(&*config).join(Path::new(crate::farmer::HARVESTER_CRT))
    };
    let cert_bytes = tokio::fs::read(&ssl_path).await?;
    let cert_chain = load_certs_from_bytes(&cert_bytes)?;
    let cert = cert_chain.first().ok_or(Error::new(
        ErrorKind::NotFound,
        format!("No Valid Cert found at {:?}", ssl_path),
    ))?;
    Ok(Bytes32::new(hash_256(cert)))
}

pub fn is_community_node<C: Clone>(config: &Config<C>) -> bool {
    ["druid.garden", "dev.druid.garden"]
        .contains(&config.fullnode_rpc_host.to_ascii_lowercase().trim())
}

pub fn init_logger() -> Result<Arc<DruidGardenLogger>, Error> {
    DruidGardenLogger::build()
        .use_colors(true)
        .current_level(Level::Info)
        .timestamp_format(TimestampFormat::Local)
        .init()
        .map_err(|e| Error::other(format!("{e:?}")))
}

pub fn check_config(config_path: &Path) -> Result<(), Error> {
    if !config_path.exists() {
        let error_msg = format!(
            "Failed to find config at {:?}, please run init",
            config_path
        );
        eprintln!("{error_msg}");
        Err(Error::new(ErrorKind::NotFound, error_msg))
    } else {
        Ok(())
    }
}