Compare commits

..

No commits in common. "5e90456fdff46c1d6c14a0f6af4ee3035672088b" and "2afc38068a7b773bbf002d642901a27cc4af0f6a" have entirely different histories.

20 changed files with 156 additions and 94 deletions

View File

@ -2,7 +2,7 @@
name = "ghost-eye"
authors = ["str3tch <stretch@ghostchain.io>"]
description = "Application for interacting with Casper/Ghost nodes that are exposing RPC only to the localhost"
version = "0.3.34"
version = "0.3.27"
edition = "2021"
[dependencies]

View File

@ -115,7 +115,7 @@ pub enum Action {
SetStashSecret([u8; 32]),
SetChoosenValidator([u8; 32], u32, u32),
SetSlashingSpansLength(usize, [u8; 32]),
SetUnlockingIsEmpty(bool, [u8; 32]),
SetUnlockingIsEmpty(bool),
BestBlockInformation(H256, u32),
FinalizedBlockInformation(H256, u32),
@ -132,7 +132,7 @@ pub enum Action {
SetValidatorEraReward(u32, u128),
SetValidatorEraClaimed(u32, bool),
SetValidatorEraSlash(u32, u128),
SetValidatorEraUnlocking(u32, u128, [u8; 32]),
SetValidatorEraUnlocking(u32, u128),
SetIsBonded(bool),
SetStakedAmountRatio(u128, u128, [u8; 32]),
SetStakedRatio(u128, u128, [u8; 32]),

View File

@ -81,7 +81,7 @@ impl CurrentValidatorDetails {
self.is_nomination_disabled = is_disabled;
match maybe_commission {
Some(commission) => {
self.commission = commission as f64 / 10_000_000.0;
self.commission = commission as f64 / 1_000_000_000.0;
self.is_active_validator = true;
},
None => {

View File

@ -34,7 +34,6 @@ pub struct CurrentValidators {
table_state: TableState,
individual: Vec<EraRewardPoints>,
known_validators: std::collections::HashMap<[u8; 32], String>,
active_validators: std::collections::HashSet<String>,
total_points: u32,
era_index: u32,
my_stash_id: Option<[u8; 32]>,
@ -58,7 +57,6 @@ impl CurrentValidators {
table_state: TableState::new(),
individual: Default::default(),
known_validators: Default::default(),
active_validators: Default::default(),
total_points: 0,
era_index: 0,
my_stash_id: None,
@ -270,14 +268,7 @@ impl Component for CurrentValidators {
}
let mut current_validator_is_my_stash = false;
if index == 0 {
if let Some(account_id) = self.my_stash_id {
current_validator_is_my_stash = account_id == info.account_id;
}
};
if current_validator_is_my_stash {
if self.my_stash_id.is_some() && index == 0 {
let name = self.known_validators
.get(&info.account_id)
.cloned()

View File

@ -60,13 +60,7 @@ impl BondPopup {
fn submit_message(&mut self) {
if let Some(network_tx) = &self.network_tx {
let str_amount = self.amount.value();
let str_amount = if str_amount.starts_with('.') {
&format!("0{}", str_amount)[..]
} else {
str_amount
};
match str_amount.parse::<f64>() {
match self.amount.value().parse::<f64>() {
Ok(value) => {
let amount = (value * 1_000_000_000_000_000_000.0) as u128;
let _ = if self.is_bonded {

View File

@ -64,19 +64,17 @@ impl History {
fn payout_by_era_index(&mut self) {
if let Some(index) = self.table_state.selected() {
let length = self.rewards.len() as u32;
let era_index = self.rewards
.keys()
.nth(index)
.map(|i| length - i - 1)
.expect("BTreeMap of rewards is indexed; qed");
let is_claimed = self.rewards
.get(&era_index)
.get(era_index)
.map(|x| x.is_claimed)
.expect("BTreeMap of rewards is indexed; qed");
if let Some(action_tx) = &self.action_tx {
let _ = action_tx.send(
Action::PayoutValidatorPopup(era_index, is_claimed));
Action::PayoutValidatorPopup(*era_index, is_claimed));
}
}
}
@ -244,7 +242,6 @@ impl Component for History {
let table = Table::new(
self.rewards
.iter()
.rev()
.map(|(key, value)| {
let mut era_index_text = Text::from(key.to_string()).alignment(Alignment::Left);
let mut slash_text = Text::from(self.prepare_u128(value.slash)).alignment(Alignment::Center);

View File

@ -52,6 +52,7 @@ use withdraw_popup::WithdrawPopup;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum CurrentTab {
Nothing,
StashInfo,
ListenAddresses,
NominatorsByValidator,
History,
@ -117,13 +118,15 @@ impl Validator {
CurrentTab::Withdrawals => self.current_tab = CurrentTab::History,
CurrentTab::History => self.current_tab = CurrentTab::NominatorsByValidator,
CurrentTab::NominatorsByValidator => self.current_tab = CurrentTab::ListenAddresses,
CurrentTab::ListenAddresses => self.current_tab = CurrentTab::StashInfo,
_ => {}
}
}
fn move_right(&mut self) {
match self.current_tab {
CurrentTab::Nothing => self.current_tab = CurrentTab::ListenAddresses,
CurrentTab::Nothing => self.current_tab = CurrentTab::StashInfo,
CurrentTab::StashInfo => self.current_tab = CurrentTab::ListenAddresses,
CurrentTab::ListenAddresses => self.current_tab = CurrentTab::NominatorsByValidator,
CurrentTab::NominatorsByValidator => self.current_tab = CurrentTab::History,
CurrentTab::History => self.current_tab = CurrentTab::Withdrawals,
@ -264,7 +267,7 @@ impl Component for Validator {
match action {
Action::SetActiveScreen(Mode::Validator) => {
self.is_active = true;
self.current_tab = CurrentTab::ListenAddresses;
self.current_tab = CurrentTab::StashInfo;
}
Action::PayoutValidatorPopup(_, _) => {
self.previous_tab = self.current_tab;

View File

@ -56,13 +56,7 @@ impl RebondPopup {
fn submit_message(&mut self) {
if let Some(network_tx) = &self.network_tx {
let str_amount = self.amount.value();
let str_amount = if str_amount.starts_with('.') {
&format!("0{}", str_amount)[..]
} else {
str_amount
};
match str_amount.parse::<f64>() {
match self.amount.value().parse::<f64>() {
Ok(value) => {
let amount = (value * 1_000_000_000_000_000_000.0) as u128;
let _ = network_tx.send(Action::RebondFrom(self.secret_seed, amount));

View File

@ -46,7 +46,7 @@ impl RewardDetails {
match self.commission {
Some(commission) => {
if self.nominators_blocked { "blocked".to_string() }
else { format!("{:.2}%", commission as f64 / 10_000_000.0) }
else { format!("{:.2}%", commission as f64 / 1_000_000_000.0) }
},
None => DotSpinner::default().to_string(),
}

View File

@ -70,10 +70,10 @@ impl RotatePopup {
(gran_key, babe_key, audi_key, slow_key)
} else {
(
String::from("0x0000000000000000000000000000000000000000000000000000000000000000"),
String::from("0x0000000000000000000000000000000000000000000000000000000000000000"),
String::from("0x0000000000000000000000000000000000000000000000000000000000000000"),
String::from("0x0000000000000000000000000000000000000000000000000000000000000000"),
String::from("not prepared"),
String::from("not prepared"),
String::from("not prepared"),
String::from("not prepared"),
)
}
}
@ -94,11 +94,6 @@ impl Component for RotatePopup {
Ok(())
}
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
self.action_tx = Some(tx);
Ok(())
}
fn register_config_handler(&mut self, config: Config) -> Result<()> {
if let Some(style) = config.styles.get(&crate::app::Mode::Wallet) {
self.palette.with_normal_style(style.get("normal_style").copied());
@ -155,7 +150,7 @@ impl Component for RotatePopup {
]),
],
[
Constraint::Length(4),
Constraint::Min(4),
Constraint::Min(0),
],
)

View File

@ -3,12 +3,16 @@ use std::fs::File;
use std::io::{Write, BufRead, BufReader};
use color_eyre::Result;
use ratatui::layout::Constraint;
use crossterm::event::{KeyCode, KeyEvent};
use ratatui::layout::{Constraint, Margin};
use ratatui::style::{Modifier, Stylize};
use ratatui::{
text::Text,
layout::{Alignment, Rect},
widgets::{Block, Cell, Row, Table},
widgets::{
Block, Cell, Row, Table, TableState, Scrollbar,
ScrollbarOrientation, ScrollbarState,
},
Frame
};
@ -38,6 +42,8 @@ pub struct StashInfo {
action_tx: Option<UnboundedSender<Action>>,
network_tx: Option<Sender<Action>>,
palette: StylePalette,
scroll_state: ScrollbarState,
table_state: TableState,
stash_pair: Option<PairSigner<CasperConfig, Pair>>,
stash_address: String,
session_keys: std::collections::HashMap<String, SessionKeyInfo>,
@ -57,6 +63,8 @@ impl StashInfo {
is_active: false,
action_tx: None,
network_tx: None,
scroll_state: ScrollbarState::new(0),
table_state: TableState::new(),
palette: StylePalette::default(),
stash_address: String::new(),
stash_pair: None,
@ -73,6 +81,51 @@ impl StashInfo {
}
}
fn first_row(&mut self) {
if self.session_keys.len() > 0 {
self.table_state.select(Some(0));
self.scroll_state = self.scroll_state.position(0);
}
}
fn next_row(&mut self) {
let i = match self.table_state.selected() {
Some(i) => {
if i >= self.session_keys.len() - 1 {
i
} else {
i + 1
}
},
None => 0,
};
self.table_state.select(Some(i));
self.scroll_state = self.scroll_state.position(i);
}
fn last_row(&mut self) {
if self.session_keys.len() > 0 {
let last = self.session_keys.len() - 1;
self.table_state.select(Some(last));
self.scroll_state = self.scroll_state.position(last);
}
}
fn previous_row(&mut self) {
let i = match self.table_state.selected() {
Some(i) => {
if i == 0 {
0
} else {
i - 1
}
},
None => 0
};
self.table_state.select(Some(i));
self.scroll_state = self.scroll_state.position(i);
}
fn read_or_create_stash(&mut self) -> Result<()> {
match File::open(&self.stash_filepath) {
Ok(file) => {
@ -177,7 +230,16 @@ impl StashInfo {
}
impl PartialComponent for StashInfo {
fn set_active(&mut self, _current_tab: CurrentTab) { }
fn set_active(&mut self, current_tab: CurrentTab) {
match current_tab {
CurrentTab::StashInfo => self.is_active = true,
_ => {
self.is_active = false;
self.table_state.select(None);
self.scroll_state = self.scroll_state.position(0);
}
}
}
}
impl Component for StashInfo {
@ -214,6 +276,19 @@ impl Component for StashInfo {
Ok(None)
}
fn handle_key_event(&mut self, key: KeyEvent) -> Result<Option<Action>> {
if self.is_active {
match key.code {
KeyCode::Up | KeyCode::Char('k') => self.previous_row(),
KeyCode::Down | KeyCode::Char('j') => self.next_row(),
KeyCode::Char('g') => self.first_row(),
KeyCode::Char('G') => self.last_row(),
_ => {},
};
}
Ok(None)
}
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
let [place, _] = super::validator_session_and_listen_layout(area);
let (border_style, border_type) = self.palette.create_border_style(self.is_active);
@ -265,7 +340,19 @@ impl Component for StashInfo {
.title_style(self.palette.create_title_style(false))
.title(self.stash_address.clone()));
frame.render_widget(table, place);
let scrollbar = Scrollbar::default()
.orientation(ScrollbarOrientation::VerticalRight)
.begin_symbol(None)
.end_symbol(None)
.style(self.palette.create_scrollbar_style());
frame.render_stateful_widget(table, place, &mut self.table_state);
frame.render_stateful_widget(
scrollbar,
place.inner(Margin { vertical: 1, horizontal: 1 }),
&mut self.scroll_state,
);
Ok(())
}
}

View File

@ -56,13 +56,7 @@ impl UnbondPopup {
fn submit_message(&mut self) {
if let Some(network_tx) = &self.network_tx {
let str_amount = self.amount.value();
let str_amount = if str_amount.starts_with('.') {
&format!("0{}", str_amount)[..]
} else {
str_amount
};
match str_amount.parse::<f64>() {
match self.amount.value().parse::<f64>() {
Ok(value) => {
if self.is_bonded {
let amount = (value * 1_000_000_000_000_000_000.0) as u128;

View File

@ -56,15 +56,9 @@ impl ValidatePopup {
fn submit_message(&mut self) {
if let Some(network_tx) = &self.network_tx {
let str_amount = self.amount.value();
let str_amount = if str_amount.starts_with('.') {
&format!("0{}", str_amount)[..]
} else {
str_amount
};
match str_amount.parse::<f64>() {
match self.amount.value().parse::<f64>() {
Ok(value) => {
let amount = (value * 10_000_000.0).round() as u32;
let amount = (value * 1_000_000_000.0).round() as u32;
let _ = network_tx.send(Action::ValidateFrom(self.secret_seed, amount));
if let Some(action_tx) = &self.action_tx {
let _ = action_tx.send(Action::ClosePopup);

View File

@ -120,15 +120,14 @@ impl Component for WithdrawPopup {
fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action {
Action::SetExistentialDeposit(existential_deposit) => self.existential_deposit = existential_deposit,
Action::SetStashAccount(account_id) => self.stash_account = account_id,
Action::SetStashSecret(secret_seed) => self.secret_seed = secret_seed,
Action::SetSlashingSpansLength(length, account_id) if self.stash_account == account_id =>
self.slashing_spans_length = length as u32,
Action::SetStakedAmountRatio(_, active_balance, account_id) if self.stash_account == account_id =>
self.active_balance = active_balance,
Action::SetUnlockingIsEmpty(is_empty, account_id) if self.stash_account == account_id =>
self.unlocking_is_empty = is_empty,
Action::SetUnlockingIsEmpty(is_empty) => self.unlocking_is_empty = is_empty,
Action::SetExistentialDeposit(existential_deposit) => self.existential_deposit = existential_deposit,
_ => {}
};
Ok(None)

View File

@ -27,7 +27,6 @@ pub struct Withdrawals {
scroll_state: ScrollbarState,
table_state: TableState,
unlockings: BTreeMap<u32, u128>,
stash_account: [u8; 32],
current_era: u32,
}
@ -48,7 +47,6 @@ impl Withdrawals {
table_state: TableState::new(),
palette: StylePalette::default(),
unlockings: BTreeMap::new(),
stash_account: [0u8; 32],
current_era: 0,
}
}
@ -153,9 +151,8 @@ impl Component for Withdrawals {
fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action {
Action::SetStashAccount(account_id) => self.stash_account = account_id,
Action::SetCurrentEra(current_era) => self.current_era = current_era,
Action::SetValidatorEraUnlocking(era_index, unlocking, account_id) if self.stash_account == account_id =>
Action::SetValidatorEraUnlocking(era_index, unlocking) =>
self.add_new_unlocking(era_index, unlocking),
_ => {}
};

View File

@ -82,13 +82,7 @@ impl Transfer {
let mut account_id = [0u8; 32];
account_id.copy_from_slice(&seed_vec);
let str_amount = self.amount.value();
let str_amount = if str_amount.starts_with('.') {
&format!("0{}", str_amount)[..]
} else {
str_amount
};
match str_amount.parse::<f64>() {
match self.amount.value().parse::<f64>() {
Ok(value) => {
let amount = (value * 1_000_000_000_000_000_000.0) as u128;
let _ = network_tx.send(Action::TransferBalance(

View File

@ -281,9 +281,20 @@ pub async fn get_validator_staking_results(
api: &OnlineClient<CasperConfig>,
account_id: &[u8; 32],
) -> Result<()> {
let current_era = super::raw_calls::staking::current_era(api, None).await?.unwrap_or(0);
let era_depth = super::raw_calls::staking::history_depth(api).unwrap_or(0);
for era_index in current_era.saturating_sub(era_depth)..current_era {
let (start, end) = super::raw_calls::historical::stored_range(api, None)
.await?
.map(|range| {
(
range.0
.saturating_div(6)
.saturating_sub(1),
range.1
.saturating_div(6)
.saturating_sub(1),
)
})
.unwrap_or((0, 0));
for era_index in start..end {
get_validator_staking_result(action_tx, api, account_id, era_index).await?;
}
Ok(())
@ -424,9 +435,9 @@ pub async fn get_validators_ledger(
if let Some(ledger) = maybe_ledger {
action_tx.send(Action::SetStakedAmountRatio(ledger.total, ledger.active, *account_id))?;
action_tx.send(Action::SetUnlockingIsEmpty(ledger.unlocking.0.is_empty(), *account_id))?;
action_tx.send(Action::SetUnlockingIsEmpty(ledger.unlocking.0.is_empty()))?;
for chunk in ledger.unlocking.0.iter() {
action_tx.send(Action::SetValidatorEraUnlocking(chunk.era, chunk.value, *account_id))?;
action_tx.send(Action::SetValidatorEraUnlocking(chunk.era, chunk.value))?;
}
}
@ -503,11 +514,11 @@ pub async fn get_validator_prefs(
) -> Result<()> {
let maybe_validator_prefs = super::raw_calls::staking::validators(api, None, account_id)
.await?;
let (commission, blocked) = match maybe_validator_prefs {
let (comission, blocked) = match maybe_validator_prefs {
Some(prefs) => (Some(prefs.commission.0), prefs.blocked),
None => (None, false),
};
action_tx.send(Action::SetValidatorPrefs(commission, blocked, *account_id))?;
action_tx.send(Action::SetValidatorPrefs(comission, blocked, *account_id))?;
Ok(())
}

View File

@ -0,0 +1,19 @@
use color_eyre::Result;
use subxt::{
utils::H256,
client::OnlineClient,
};
use crate::{
casper_network,
CasperConfig,
};
pub async fn stored_range(
online_client: &OnlineClient<CasperConfig>,
at_hash: Option<&H256>,
) -> Result<Option<(u32, u32)>> {
let storage_key = casper_network::storage().historical().stored_range();
let maybe_stored_range = super::do_storage_call(online_client, &storage_key, at_hash).await?;
Ok(maybe_stored_range)
}

View File

@ -12,6 +12,7 @@ pub mod staking;
pub mod system;
pub mod babe;
pub mod balances;
pub mod historical;
pub async fn do_storage_call<'address, Addr>(
online_client: &OnlineClient<CasperConfig>,

View File

@ -194,11 +194,3 @@ pub async fn slashing_spans(
let maybe_slashing_spans = super::do_storage_call(online_client, &storage_key, at_hash).await?;
Ok(maybe_slashing_spans)
}
pub fn history_depth(
online_client: &OnlineClient<CasperConfig>,
) -> Result<u32> {
let constant_query = casper_network::constants().staking().history_depth();
let history_depth = super::do_constant_call(online_client, &constant_query)?;
Ok(history_depth)
}