From 7eeeaaf3c35eccff8b1fdea7b72dc81655d67b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Papie=C5=BC?= Date: Thu, 8 Aug 2024 14:58:07 +0200 Subject: [PATCH 1/2] feat(mining): implement eco and ludicrous mode (#31) Description --- Motivation and Context --- How Has This Been Tested? --- What process can a PR reviewer use to test or verify this change? --- Breaking Changes --- - [x] None - [ ] Requires data directory on base node to be deleted - [ ] Requires hard fork - [ ] Other - Please specify --- src-tauri/Cargo.toml | 1 - src-tauri/src/app_config.rs | 103 ++++++++++++++++++ src-tauri/src/cpu_miner.rs | 18 ++- src-tauri/src/main.rs | 36 +++++- src-tauri/src/xmrig_adapter.rs | 3 +- .../SideBar/Miner/components/ModeSelect.tsx | 8 +- src/hooks/useGetStatus.ts | 2 + src/store/types.ts | 2 +- src/store/useAppStatusStore.ts | 13 ++- src/types/app-status.ts | 3 + 10 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 src-tauri/src/app_config.rs diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index fb49589c3..5bf24251f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -65,7 +65,6 @@ libsqlite3-sys = { version = "0.25.1", features = ["bundled"] } log = "0.4.22" rand = "0.8.5" - [features] # This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!! custom-protocol = ["tauri/custom-protocol"] diff --git a/src-tauri/src/app_config.rs b/src-tauri/src/app_config.rs new file mode 100644 index 000000000..36498ecd9 --- /dev/null +++ b/src-tauri/src/app_config.rs @@ -0,0 +1,103 @@ +use anyhow::anyhow; +use log::{info, warn}; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use tokio::fs; + +const LOG_TARGET: &str = "tari::universe::app_config"; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct AppConfigFromFile { + pub mode: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum MiningMode { + Eco, + Ludicrous, +} + +impl MiningMode { + pub fn from_str(s: &str) -> Option { + match s { + "Eco" => Some(MiningMode::Eco), + "Ludicrous" => Some(MiningMode::Ludicrous), + _ => None, + } + } + + pub fn to_str(m: MiningMode) -> String { + match m { + MiningMode::Eco => String::from("Eco"), + MiningMode::Ludicrous => String::from("Ludicrous"), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AppConfig { + config_file: Option, + pub mode: MiningMode, + // auto-mining in future etc. +} + +impl AppConfig { + pub fn new() -> Self { + Self { + config_file: None, + mode: MiningMode::Eco, + } + } + + pub async fn load_or_create(&mut self, config_path: PathBuf) -> Result<(), anyhow::Error> { + let file: PathBuf = config_path.join("app_config.json"); + self.config_file = Some(file.clone()); + + if file.exists() { + info!(target: LOG_TARGET, "Loading app config from file: {:?}", file); + let config = fs::read_to_string(&file).await?; + match serde_json::from_str::(&config) { + Ok(config) => { + self.mode = MiningMode::from_str(&config.mode).unwrap_or(MiningMode::Eco); + } + Err(e) => { + warn!(target: LOG_TARGET, "Failed to parse app config: {}", e.to_string()); + } + } + } + info!(target: LOG_TARGET, "App config does not exist or is corrupt. Creating new one"); + let config = &AppConfigFromFile { + mode: MiningMode::to_str(self.mode.clone()), + }; + let config = serde_json::to_string(&config)?; + fs::write(file, config).await?; + Ok(()) + } + + pub async fn set_mode(&mut self, mode: String) -> Result<(), anyhow::Error> { + let new_mode = match mode.as_str() { + "Eco" => MiningMode::Eco, + "Ludicrous" => MiningMode::Ludicrous, + _ => return Err(anyhow!("Invalid mode")), + }; + self.mode = new_mode; + self.update_config_file().await?; + Ok(()) + } + + pub fn get_mode(&self) -> MiningMode { + self.mode.clone() + } + + pub async fn update_config_file(&mut self) -> Result<(), anyhow::Error> { + let file = self.config_file.clone().unwrap(); + let config = &AppConfigFromFile { + mode: MiningMode::to_str(self.mode.clone()), + }; + let config = serde_json::to_string(config)?; + info!(target: LOG_TARGET, "Updating config file: {:?} {:?}", file, self.clone()); + fs::write(file, config).await?; + + Ok(()) + } +} diff --git a/src-tauri/src/cpu_miner.rs b/src-tauri/src/cpu_miner.rs index 40f3d781a..540c8c313 100644 --- a/src-tauri/src/cpu_miner.rs +++ b/src-tauri/src/cpu_miner.rs @@ -1,7 +1,9 @@ use crate::mm_proxy_manager::MmProxyManager; use crate::xmrig::http_api::XmrigHttpApiClient; use crate::xmrig_adapter::{XmrigAdapter, XmrigNodeConnection}; -use crate::{CpuMinerConfig, CpuMinerConnection, CpuMinerConnectionStatus, CpuMinerStatus}; +use crate::{ + CpuMinerConfig, CpuMinerConnection, CpuMinerConnectionStatus, CpuMinerStatus, MiningMode, +}; use log::warn; use std::path::PathBuf; use sysinfo::{CpuRefreshKind, RefreshKind, System}; @@ -43,6 +45,7 @@ impl CpuMiner { cache_dir: PathBuf, log_dir: PathBuf, window: tauri::Window, + mode: MiningMode, ) -> Result<(), anyhow::Error> { if self.watcher_task.is_some() { warn!(target: LOG_TARGET, "Tried to start mining twice"); @@ -70,9 +73,18 @@ impl CpuMiner { } } }; + let cpu_max_percentage = match mode { + MiningMode::Eco => 30, + MiningMode::Ludicrous => 100, + }; let xmrig = XmrigAdapter::new(xmrig_node_connection, "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A".to_string() ); - let (mut _rx, mut xmrig_child, client) = - xmrig.spawn(cache_dir, log_dir, base_path, window.clone())?; + let (mut _rx, mut xmrig_child, client) = xmrig.spawn( + cache_dir, + log_dir, + base_path, + window.clone(), + cpu_max_percentage, + )?; self.api_client = Some(client); self.watcher_task = Some(tauri::async_runtime::spawn(async move { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index a0570628c..64f1f376d 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -7,6 +7,7 @@ mod process_watcher; mod xmrig; mod xmrig_adapter; +mod app_config; mod binary_resolver; mod download_utils; mod github; @@ -26,6 +27,7 @@ use crate::mm_proxy_manager::MmProxyManager; use crate::node_manager::NodeManager; use crate::wallet_adapter::WalletBalance; use crate::wallet_manager::WalletManager; +use app_config::{AppConfig, MiningMode}; use futures_util::TryFutureExt; use log::{debug, error, info, warn}; use serde::{Deserialize, Serialize}; @@ -51,6 +53,18 @@ struct SetupStatusEvent { progress: f64, } +#[tauri::command] +async fn set_mode<'r>( + mode: String, + _window: tauri::Window, + state: tauri::State<'r, UniverseAppState>, + _app: tauri::AppHandle, +) -> Result<(), String> { + let _ = state.config.write().await.set_mode(mode).await; + + Ok(()) +} + #[tauri::command] async fn setup_application<'r>( window: tauri::Window, @@ -137,6 +151,7 @@ async fn start_mining<'r>( app.path_resolver().app_cache_dir().unwrap(), app.path_resolver().app_log_dir().unwrap(), window.clone(), + state.config.read().await.get_mode(), ) .await .map_err(|e| { @@ -207,6 +222,8 @@ async fn status(state: tauri::State<'_, UniverseAppState>) -> Result) -> Result>, shutdown: Shutdown, cpu_miner: RwLock, cpu_miner_config: Arc>, @@ -286,7 +306,9 @@ fn main() { node_connection: CpuMinerConnection::BuiltInProxy, tari_address: TariAddress::default(), })); + let app_config = Arc::new(RwLock::new(AppConfig::new())); let app_state = UniverseAppState { + config: app_config.clone(), shutdown: shutdown.clone(), cpu_miner: CpuMiner::new().into(), cpu_miner_config: cpu_config.clone(), @@ -308,6 +330,17 @@ fn main() { ) .expect("Could not set up logging"); + let config_path = app.path_resolver().app_config_dir().unwrap(); + let thread_config = tauri::async_runtime::spawn(async move { + app_config.write().await.load_or_create(config_path).await + }); + match tauri::async_runtime::block_on(thread_config).unwrap() { + Ok(_) => {} + Err(e) => { + error!(target: LOG_TARGET, "Error setting up app state: {:?}", e); + } + }; + let config_path = app.path_resolver().app_config_dir().unwrap(); let thread = tauri::async_runtime::spawn(async move { match InternalWallet::load_or_create(config_path).await { @@ -342,7 +375,8 @@ fn main() { setup_application, status, start_mining, - stop_mining + stop_mining, + set_mode ]) .build(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/xmrig_adapter.rs b/src-tauri/src/xmrig_adapter.rs index af2065a25..bea72e008 100644 --- a/src-tauri/src/xmrig_adapter.rs +++ b/src-tauri/src/xmrig_adapter.rs @@ -66,6 +66,7 @@ impl XmrigAdapter { logs_dir: PathBuf, data_dir: PathBuf, window: tauri::Window, + cpu_max_percentage: u16, ) -> Result<(Receiver, XmrigInstance, XmrigHttpApiClient), anyhow::Error> { self.kill_previous_instances(data_dir.clone())?; @@ -81,7 +82,7 @@ impl XmrigAdapter { args.push(format!("--http-access-token={}", self.http_api_token)); args.push(format!("--donate-level=1")); args.push(format!("--user={}", self.monero_address)); - args.push("--threads=6".to_string()); + args.push(format!("--cpu-max-threads-hint={}", cpu_max_percentage)); let client = XmrigHttpApiClient::new( format!("http://127.0.0.1:{}", self.http_api_port), diff --git a/src/containers/SideBar/Miner/components/ModeSelect.tsx b/src/containers/SideBar/Miner/components/ModeSelect.tsx index 46bad081f..b6f597674 100644 --- a/src/containers/SideBar/Miner/components/ModeSelect.tsx +++ b/src/containers/SideBar/Miner/components/ModeSelect.tsx @@ -24,10 +24,10 @@ const CustomSelect = styled(Select)(({ theme }: { theme: any }) => ({ function ModeSelect() { const mode = useAppStatusStore((s) => s.mode); - const setMode = useAppStatusStore((s) => s.setMode); + const setConfigMode = useAppStatusStore((s) => s.setConfigMode); const handleChange = (event: SelectChangeEvent) => { - setMode(event.target.value as modeType); + setConfigMode(event.target.value as modeType); }; const theme = useTheme(); return ( @@ -47,8 +47,8 @@ function ModeSelect() { }, }} > - Eco - Ludicrous + Eco + Ludicrous diff --git a/src/hooks/useGetStatus.ts b/src/hooks/useGetStatus.ts index b65e16002..83e018282 100644 --- a/src/hooks/useGetStatus.ts +++ b/src/hooks/useGetStatus.ts @@ -11,6 +11,7 @@ export function useGetStatus() { const setBalance = useWalletStore((state) => state.setBalance); const setAppStatus = useAppStatusStore((s) => s.setAppStatus); const setError = useAppStateStore((s) => s.setError); + const setMode = useAppStatusStore(s => s.setMode); useEffect(() => { const intervalId = setInterval(() => { @@ -31,6 +32,7 @@ export function useGetStatus() { timelocked_balance + pending_incoming_balance ); + setMode(status.mode) } else { console.error('Could not get status'); } diff --git a/src/store/types.ts b/src/store/types.ts index d70519a88..2d262ccd3 100644 --- a/src/store/types.ts +++ b/src/store/types.ts @@ -7,4 +7,4 @@ export type backgroundType = | 'mining' | 'loser' | 'winner'; -export type modeType = 'eco' | 'ludicrous'; +export type modeType = 'Eco' | 'Ludicrous'; diff --git a/src/store/useAppStatusStore.ts b/src/store/useAppStatusStore.ts index 6811f3e7f..71c07671d 100644 --- a/src/store/useAppStatusStore.ts +++ b/src/store/useAppStatusStore.ts @@ -2,6 +2,7 @@ import { create } from 'zustand'; import { AppStatus } from '../types/app-status.ts'; import { modeType } from './types.ts'; import { persist } from 'zustand/middleware'; +import { invoke } from '@tauri-apps/api/tauri'; interface State extends AppStatus { mode: modeType; @@ -9,6 +10,7 @@ interface State extends AppStatus { interface Actions { setAppStatus: (appStatus: AppStatus) => void; setMode: (mode: modeType) => void; + setConfigMode: (mode: modeType) => void; } type AppStatusStoreState = State & Actions; @@ -16,7 +18,7 @@ const initialState: State = { cpu: undefined, base_node: undefined, wallet_balance: undefined, - mode: 'eco', + mode: 'Eco', }; export const useAppStatusStore = create()( persist( @@ -24,6 +26,15 @@ export const useAppStatusStore = create()( ...initialState, setAppStatus: (appStatus) => set({ ...appStatus }), setMode: (mode) => set({ mode }), + setConfigMode: async (mode: modeType) => { + try { + await invoke('set_mode', { mode }); + set({ mode }) + console.log(`Mode changed to ${mode}`); + } catch (e) { + console.error('Could not change the mode', e); + } + }, }), { name: 'status-store' } ) diff --git a/src/types/app-status.ts b/src/types/app-status.ts index 5fd8998ec..57f08af2c 100644 --- a/src/types/app-status.ts +++ b/src/types/app-status.ts @@ -1,7 +1,10 @@ +import { modeType } from "../store/types"; + export interface AppStatus { cpu?: CpuMinerStatus; base_node?: BaseNodeStatus; wallet_balance?: WalletBalance; + mode: modeType; } export interface CpuMinerStatus { From 4e21dca445121c30cb5b388eb678df26f8c247df Mon Sep 17 00:00:00 2001 From: stringhandler Date: Thu, 8 Aug 2024 17:01:26 +0200 Subject: [PATCH 2/2] chore(release): v0.1.25 --- src-tauri/tauri.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 0ee08fcf7..9316d4808 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ }, "package": { "productName": "Tari Universe", - "version": "0.1.24" + "version": "0.1.25" }, "tauri": { "updater": {