Skip to content

Commit

Permalink
Merge pull request #93 from nazar-pc/node-free-space-monitoring
Browse files Browse the repository at this point in the history
Free disk space monitoring of the node path
  • Loading branch information
nazar-pc authored Jan 26, 2024
2 parents 31f0247 + 61e51a7 commit 8e3fb5f
Show file tree
Hide file tree
Showing 6 changed files with 388 additions and 161 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "space-acres"
description = "Space Acres is an opinionated unofficial GUI application for farming on Subspace Network"
license = "0BSD"
version = "0.0.19"
version = "0.0.20"
authors = ["Nazar Mokrynskyi <[email protected]>"]
repository = "https://github.com/nazar-pc/space-acres"
edition = "2021"
Expand Down Expand Up @@ -41,6 +41,7 @@ duct = "0.13.6"
event-listener-primitives = "2.0.1"
file-rotate = "0.7.5"
frame-system = { git = "https://github.com/subspace/polkadot-sdk", rev = "c63a8b28a9fd26d42116b0dcef1f2a5cefb9cd1c", default-features = false }
fs4 = "0.7.0"
futures = "0.3.29"
gtk = { version = "0.7.3", package = "gtk4" }
hex = "0.4.3"
Expand Down
8 changes: 8 additions & 0 deletions res/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ progressbar progress {
color: #ff3800;
}

.free-disk-space > trough > block.low {
background-color: #ff3800;
}

.free-disk-space > trough > block.high {
background-color: #ffA400;
}

farm-sectors > child {
padding: 0;
}
Expand Down
6 changes: 6 additions & 0 deletions src/backend/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ pub enum SyncState {
Idle,
}

impl SyncState {
pub fn is_synced(&self) -> bool {
matches!(self, SyncState::Idle)
}
}

#[derive(Debug, Copy, Clone)]
pub struct BlockImported {
pub number: BlockNumber,
Expand Down
220 changes: 61 additions & 159 deletions src/frontend/running.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
mod farm;
mod node;

use crate::backend::config::RawConfig;
use crate::backend::farmer::{FarmerNotification, InitialFarmState};
use crate::backend::node::{ChainInfo, SyncKind, SyncState};
use crate::backend::node::ChainInfo;
use crate::backend::NodeNotification;
use crate::frontend::running::farm::{FarmWidget, FarmWidgetInit, FarmWidgetInput};
use crate::frontend::running::node::{NodeInput, NodeView};
use gtk::prelude::*;
use relm4::factory::FactoryHashMap;
use relm4::prelude::*;
use subspace_core_primitives::BlockNumber;
use subspace_runtime_primitives::{Balance, SSC};

/// Maximum blocks to store in the import queue.
// HACK: This constant comes from Substrate's sync, but it is not public in there
const MAX_IMPORTING_BLOCKS: BlockNumber = 2048;

#[derive(Debug)]
pub enum RunningInput {
Initialize {
Expand All @@ -29,26 +27,21 @@ pub enum RunningInput {
FarmerNotification(FarmerNotification),
}

#[derive(Debug, Default)]
struct NodeState {
best_block_number: BlockNumber,
sync_state: SyncState,
}

#[derive(Debug, Default)]
struct FarmerState {
initial_reward_address_balance: Balance,
reward_address_balance: Balance,
piece_cache_sync_progress: f32,
reward_address: String,
reward_address_url: String,
token_symbol: String,
}

#[derive(Debug)]
pub struct RunningView {
node_state: NodeState,
node_view: Controller<NodeView>,
node_synced: bool,
farmer_state: FarmerState,
farms: FactoryHashMap<u8, FarmWidget>,
chain_info: ChainInfo,
}

#[relm4::component(pub)]
Expand All @@ -63,79 +56,7 @@ impl Component for RunningView {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,

gtk::Box {
set_height_request: 100,
set_orientation: gtk::Orientation::Vertical,
set_spacing: 10,

gtk::Label {
add_css_class: "heading",
set_halign: gtk::Align::Start,
#[watch]
set_label: &format!(
"{} consensus node",
model.chain_info.chain_name.strip_prefix("Subspace ").unwrap_or(&model.chain_info.chain_name)
),
},

#[transition = "SlideUpDown"]
match model.node_state.sync_state {
SyncState::Unknown => gtk::Box {
gtk::Label {
#[watch]
set_label: &format!(
"Connecting to the network, best block #{}",
model.node_state.best_block_number
),
}
},
SyncState::Syncing { kind, target, speed } => gtk::Box {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 10,

gtk::Box {
set_spacing: 5,

gtk::Label {
set_halign: gtk::Align::Start,

#[watch]
set_label: &{
let kind = match kind {
SyncKind::Dsn => "Syncing from DSN",
SyncKind::Regular => "Regular sync",
};

format!(
"{} #{}/{}{}",
kind,
model.node_state.best_block_number,
target,
speed
.map(|speed| format!(", {:.2} blocks/s", speed))
.unwrap_or_default(),
)
},
},

gtk::Spinner {
start: (),
},
},

gtk::ProgressBar {
#[watch]
set_fraction: model.node_state.best_block_number as f64 / target as f64,
},
},
SyncState::Idle => gtk::Box {
gtk::Label {
#[watch]
set_label: &format!("Synced, best block #{}", model.node_state.best_block_number),
}
},
},
},
model.node_view.widget().clone(),

gtk::Separator {
set_margin_all: 10,
Expand All @@ -159,13 +80,7 @@ impl Component for RunningView {
remove_css_class: "link",
set_tooltip: "Total account balance and coins farmed since application started, click to see details in Astral",
#[watch]
// 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_uri: &model.farmer_state.reward_address_url,
set_use_underline: false,

gtk::Label {
Expand All @@ -175,7 +90,7 @@ impl Component for RunningView {
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;
let token_symbol = &model.farmer_state.token_symbol;

format!(
"{current_balance:.2}<span color=\"#3bbf2c\"><sup>+{balance_increase:.2}</sup></span> {token_symbol}"
Expand Down Expand Up @@ -243,15 +158,16 @@ impl Component for RunningView {
_root: Self::Root,
_sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let node_view = NodeView::builder().launch(()).detach();
let farms = FactoryHashMap::builder()
.launch(gtk::Box::default())
.detach();

let model = Self {
node_state: NodeState::default(),
node_view,
node_synced: false,
farmer_state: FarmerState::default(),
farms,
chain_info: ChainInfo::default(),
};

let farms_box = model.farms.widget();
Expand Down Expand Up @@ -296,78 +212,64 @@ impl RunningView {
);
}

self.node_state = NodeState {
best_block_number,
sync_state: SyncState::default(),
};
self.farmer_state = FarmerState {
initial_reward_address_balance: reward_address_balance,
reward_address_balance,
reward_address: raw_config.reward_address().to_string(),
piece_cache_sync_progress: 0.0,
// TODO: Would be great to have `gemini-3g` in chain spec, but it is
// not available in there in clean form
reward_address_url: format!(
"https://explorer.subspace.network/#/{}/consensus/accounts/{}",
chain_info
.protocol_id
.strip_prefix("subspace-")
.unwrap_or(&chain_info.protocol_id),
raw_config.reward_address()
),
token_symbol: chain_info.token_symbol.clone(),
};
self.chain_info = chain_info;
self.node_view.emit(NodeInput::Initialize {
best_block_number,
chain_info,
node_path: raw_config.node_path().clone(),
});
}
RunningInput::NodeNotification(node_notification) => match node_notification {
NodeNotification::SyncStateUpdate(mut sync_state) => {
if let SyncState::Syncing {
target: new_target, ..
} = &mut sync_state
{
*new_target = (*new_target).max(self.node_state.best_block_number);

// Ensure target is never below current block
if let SyncState::Syncing {
target: old_target, ..
} = &self.node_state.sync_state
{
// If old target was within `MAX_IMPORTING_BLOCKS` from new target, keep old target
if old_target
.checked_sub(*new_target)
.map(|diff| diff <= MAX_IMPORTING_BLOCKS)
.unwrap_or_default()
{
*new_target = *old_target;
}
RunningInput::NodeNotification(node_notification) => {
self.node_view
.emit(NodeInput::NodeNotification(node_notification.clone()));

match node_notification {
NodeNotification::SyncStateUpdate(sync_state) => {
let new_synced = sync_state.is_synced();
if self.node_synced != new_synced {
self.farms
.broadcast(FarmWidgetInput::NodeSynced(new_synced));
}
self.node_synced = new_synced;
}

let old_synced = matches!(self.node_state.sync_state, SyncState::Idle);
let new_synced = matches!(sync_state, SyncState::Idle);
if old_synced != new_synced {
self.farms
.broadcast(FarmWidgetInput::NodeSynced(new_synced));
}
self.node_state.sync_state = sync_state;
}
NodeNotification::BlockImported(imported_block) => {
self.node_state.best_block_number = imported_block.number;
if !matches!(self.node_state.sync_state, SyncState::Idle) {
// Do not count balance increase during sync as increase related to farming,
// but preserve accumulated diff
let previous_diff = self.farmer_state.reward_address_balance
- self.farmer_state.initial_reward_address_balance;
self.farmer_state.initial_reward_address_balance =
imported_block.reward_address_balance - previous_diff;
}
// In case balance decreased, subtract it from initial balance to ignore, this
// typically happens due to chain reorg when reward is "disappears"
if let Some(decreased_by) = self
.farmer_state
.reward_address_balance
.checked_sub(imported_block.reward_address_balance)
{
self.farmer_state.initial_reward_address_balance -= decreased_by;
}
self.farmer_state.reward_address_balance =
imported_block.reward_address_balance;

// Ensure target is never below current block
if let SyncState::Syncing { target, .. } = &mut self.node_state.sync_state {
*target = (*target).max(self.node_state.best_block_number);
NodeNotification::BlockImported(imported_block) => {
if !self.node_synced {
// Do not count balance increase during sync as increase related to
// farming, but preserve accumulated diff
let previous_diff = self.farmer_state.reward_address_balance
- self.farmer_state.initial_reward_address_balance;
self.farmer_state.initial_reward_address_balance =
imported_block.reward_address_balance - previous_diff;
}
// In case balance decreased, subtract it from initial balance to ignore,
// this typically happens due to chain reorg when reward is "disappears"
if let Some(decreased_by) = self
.farmer_state
.reward_address_balance
.checked_sub(imported_block.reward_address_balance)
{
self.farmer_state.initial_reward_address_balance -= decreased_by;
}
self.farmer_state.reward_address_balance =
imported_block.reward_address_balance;
}
}
},
}
RunningInput::FarmerNotification(farmer_notification) => match farmer_notification {
FarmerNotification::SectorUpdate {
farm_index,
Expand Down
Loading

0 comments on commit 8e3fb5f

Please sign in to comment.