diff --git a/src/backend.rs b/src/backend.rs index 3aaa5a73..3853a8a9 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -10,7 +10,8 @@ use crate::backend::farmer::maybe_node_client::MaybeNodeRpcClient; use crate::backend::farmer::{DiskFarm, Farmer, FarmerOptions, PlottingState}; use crate::backend::networking::{create_network, NetworkOptions}; use crate::backend::node::{ - dsn_bootstrap_nodes, BlockImported, ChainSpec, ConsensusNode, SyncState, GENESIS_HASH, RPC_PORT, + dsn_bootstrap_nodes, BlockImported, ChainInfo, ChainSpec, ConsensusNode, SyncState, + GENESIS_HASH, RPC_PORT, }; use future::FutureExt; use futures::channel::mpsc; @@ -105,6 +106,7 @@ pub enum BackendNotification { reward_address_balance: Balance, initial_plotting_states: Vec, farm_during_initial_plotting: bool, + chain_info: ChainInfo, }, Node(NodeNotification), Farmer(FarmerNotification), @@ -315,6 +317,7 @@ async fn run( reward_address_balance: consensus_node.account_balance(&config.reward_address), initial_plotting_states: farmer.initial_plotting_states().to_vec(), farm_during_initial_plotting: farmer.farm_during_initial_plotting(), + chain_info: consensus_node.chain_info().clone(), }) .await?; diff --git a/src/backend/node.rs b/src/backend/node.rs index 8cbf9404..33e56c37 100644 --- a/src/backend/node.rs +++ b/src/backend/node.rs @@ -56,6 +56,13 @@ impl fmt::Debug for ChainSpec { } } +#[derive(Debug, Default, Clone)] +pub struct ChainInfo { + pub chain_name: String, + pub protocol_id: String, + pub token_symbol: String, +} + #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum SyncKind { Dsn, @@ -90,6 +97,7 @@ struct Handlers { pub(super) struct ConsensusNode { full_node: NewFull>, sync_mode: Arc>, + chain_info: ChainInfo, handlers: Handlers, } @@ -103,10 +111,12 @@ impl ConsensusNode { fn new( full_node: NewFull>, sync_mode: Arc>, + chain_info: ChainInfo, ) -> Self { Self { full_node, sync_mode, + chain_info, handlers: Handlers::default(), } } @@ -213,6 +223,10 @@ impl ConsensusNode { .unwrap_or_default() } + pub(super) fn chain_info(&self) -> &ChainInfo { + &self.chain_info + } + pub(super) fn on_sync_state_change(&self, callback: HandlerFn) -> HandlerId { self.handlers.sync_state_change.add(callback) } @@ -421,6 +435,18 @@ pub(super) async fn create_consensus_node( let pot_external_entropy = pot_external_entropy(&chain_spec)?; let dsn_bootstrap_nodes = dsn_bootstrap_nodes(&chain_spec)?; + let chain_info = ChainInfo { + chain_name: chain_spec.0.name().to_string(), + protocol_id: chain_spec.0.protocol_id().unwrap_or_default().to_string(), + token_symbol: chain_spec + .0 + .properties() + .get("tokenSymbol") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + }; + let consensus_chain_config = create_consensus_chain_config(keypair, base_path, chain_spec); let sync_mode = Arc::clone(&consensus_chain_config.network.sync_mode); @@ -480,5 +506,5 @@ pub(super) async fn create_consensus_node( sc_service::Error::Other(format!("Failed to start storage monitor: {error:?}")) })?; - Ok(ConsensusNode::new(consensus_node, sync_mode)) + Ok(ConsensusNode::new(consensus_node, sync_mode, chain_info)) } diff --git a/src/frontend/running.rs b/src/frontend/running.rs index 0fba0b40..9e62955c 100644 --- a/src/frontend/running.rs +++ b/src/frontend/running.rs @@ -2,7 +2,7 @@ mod farm; use crate::backend::config::RawConfig; use crate::backend::farmer::{PlottingKind, PlottingState}; -use crate::backend::node::{SyncKind, SyncState}; +use crate::backend::node::{ChainInfo, SyncKind, SyncState}; use crate::backend::{FarmerNotification, NodeNotification}; use crate::frontend::running::farm::{FarmWidget, FarmWidgetInit, FarmWidgetInput}; use gtk::prelude::*; @@ -24,6 +24,7 @@ pub enum RunningInput { initial_plotting_states: Vec, farm_during_initial_plotting: bool, raw_config: RawConfig, + chain_info: ChainInfo, }, NodeNotification(NodeNotification), FarmerNotification(FarmerNotification), @@ -43,6 +44,7 @@ struct FarmerState { plotting_state: Vec, farm_during_initial_plotting: bool, piece_cache_sync_progress: f32, + reward_address: String, } #[derive(Debug)] @@ -50,6 +52,7 @@ pub struct RunningView { node_state: NodeState, farmer_state: FarmerState, farms: FactoryHashMap, + chain_info: ChainInfo, } #[relm4::component(pub)] @@ -72,7 +75,11 @@ impl Component for RunningView { gtk::Label { add_css_class: "heading", set_halign: gtk::Align::Start, - set_label: "Consensus node", + #[watch] + set_label: &format!( + "{} consensus node", + model.chain_info.chain_name.strip_prefix("Subspace ").unwrap_or(&model.chain_info.chain_name) + ), }, #[transition = "SlideUpDown"] @@ -231,17 +238,36 @@ impl Component for RunningView { set_halign: gtk::Align::End, set_hexpand: true, - gtk::Label { - set_tooltip: "Total account balance and coins farmed since application started", + gtk::LinkButton { + remove_css_class: "link", + set_tooltip: "Total account balance and coins farmed since application started, click to see details in Astral", #[watch] - set_label: &format!( - "{:.2}+{:.2} tSSC", - (model.farmer_state.reward_address_balance / (SSC / 100)) as f32 / 100.0, - ((model.farmer_state.reward_address_balance - model.farmer_state.initial_reward_address_balance) / (SSC / 100)) as f32 / 100.0 + // TODO: Would be great to have `gemini-3g` in chain spec, but it is + // not available in there in clean form + set_uri: &format!( + "https://explorer.subspace.network/#/{}/consensus/accounts/{}", + model.chain_info.protocol_id.strip_prefix("subspace-").unwrap_or(&model.chain_info.protocol_id), + model.farmer_state.reward_address ), - set_use_markup: true, + set_use_underline: false, + + gtk::Label { + #[watch] + set_label: &{ + let current_balance = model.farmer_state.reward_address_balance; + let balance_increase = model.farmer_state.reward_address_balance - model.farmer_state.initial_reward_address_balance; + let current_balance = (current_balance / (SSC / 100)) as f32 / 100.0; + let balance_increase = (balance_increase / (SSC / 100)) as f32 / 100.0; + let token_symbol = &model.chain_info.token_symbol; + + format!( + "{current_balance:.2}+{balance_increase:.2} {token_symbol}" + ) + }, + set_use_markup: true, + }, } - } + }, } }, @@ -270,6 +296,7 @@ impl Component for RunningView { node_state: NodeState::default(), farmer_state: FarmerState::default(), farms, + chain_info: ChainInfo::default(), }; let widgets = view_output!(); @@ -291,6 +318,7 @@ impl RunningView { initial_plotting_states, farm_during_initial_plotting, raw_config, + chain_info, } => { for (farm_index, (initial_plotting_state, farm)) in initial_plotting_states .iter() @@ -315,10 +343,12 @@ impl RunningView { self.farmer_state = FarmerState { initial_reward_address_balance: reward_address_balance, reward_address_balance, + reward_address: raw_config.reward_address().to_string(), plotting_state: initial_plotting_states, farm_during_initial_plotting, piece_cache_sync_progress: 0.0, }; + self.chain_info = chain_info; } RunningInput::NodeNotification(node_notification) => match node_notification { NodeNotification::SyncStateUpdate(mut sync_state) => { diff --git a/src/main.rs b/src/main.rs index 1354b2b9..c82822ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -479,6 +479,7 @@ impl App { reward_address_balance, initial_plotting_states, farm_during_initial_plotting, + chain_info, } => { self.current_raw_config.replace(raw_config.clone()); self.current_view = View::Running; @@ -488,6 +489,7 @@ impl App { initial_plotting_states, farm_during_initial_plotting, raw_config, + chain_info, }); } BackendNotification::Node(node_notification) => {