ability to see basic gatekeeped network information
Signed-off-by: Uncle Stretch <uncle.stretch@ghostchain.io>
This commit is contained in:
parent
29622e6ec3
commit
9afda5a701
@ -2,7 +2,7 @@
|
|||||||
name = "ghost-eye"
|
name = "ghost-eye"
|
||||||
authors = ["str3tch <stretch@ghostchain.io>"]
|
authors = ["str3tch <stretch@ghostchain.io>"]
|
||||||
description = "Application for interacting with Casper/Ghost nodes that are exposing RPC only to the localhost"
|
description = "Application for interacting with Casper/Ghost nodes that are exposing RPC only to the localhost"
|
||||||
version = "0.3.63"
|
version = "0.3.64"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
homepage = "https://git.ghostchain.io/ghostchain"
|
homepage = "https://git.ghostchain.io/ghostchain"
|
||||||
repository = "https://git.ghostchain.io/ghostchain/ghost-eye"
|
repository = "https://git.ghostchain.io/ghostchain/ghost-eye"
|
||||||
|
@ -7,7 +7,7 @@ use subxt::config::substrate::DigestItem;
|
|||||||
use crate::types::{
|
use crate::types::{
|
||||||
ActionLevel, ActionTarget, CasperExtrinsicDetails, EraInfo, EraRewardPoints,
|
ActionLevel, ActionTarget, CasperExtrinsicDetails, EraInfo, EraRewardPoints,
|
||||||
Nominator, Nominations, PeerInformation, SessionKeyInfo, UnlockChunk, SystemAccount,
|
Nominator, Nominations, PeerInformation, SessionKeyInfo, UnlockChunk, SystemAccount,
|
||||||
RewardDestination,
|
RewardDestination, Gatekeeper, BlockRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
|
||||||
@ -120,9 +120,11 @@ pub enum Action {
|
|||||||
SetGenesisHash(Option<H256>),
|
SetGenesisHash(Option<H256>),
|
||||||
SetChainName(Option<String>),
|
SetChainName(Option<String>),
|
||||||
SetChainVersion(Option<String>),
|
SetChainVersion(Option<String>),
|
||||||
|
SetBlockRange(u64, BlockRange),
|
||||||
SetStashAccount([u8; 32]),
|
SetStashAccount([u8; 32]),
|
||||||
SetStashSecret([u8; 32]),
|
SetStashSecret([u8; 32]),
|
||||||
SetChoosenValidator([u8; 32], u32, u32),
|
SetChoosenValidator([u8; 32], u32, u32),
|
||||||
|
SetChoosenGatekeeper(u64),
|
||||||
SetSlashingSpansLength(usize, [u8; 32]),
|
SetSlashingSpansLength(usize, [u8; 32]),
|
||||||
|
|
||||||
BestBlockInformation(H256, u32),
|
BestBlockInformation(H256, u32),
|
||||||
@ -153,8 +155,11 @@ pub enum Action {
|
|||||||
GetTotalIssuance,
|
GetTotalIssuance,
|
||||||
GetExistentialDeposit,
|
GetExistentialDeposit,
|
||||||
GetMinValidatorBond,
|
GetMinValidatorBond,
|
||||||
|
GetGatekeepedNetwork(u64),
|
||||||
|
GetBlockRange,
|
||||||
|
|
||||||
SetExistentialDeposit(u128),
|
SetExistentialDeposit(u128),
|
||||||
SetMinValidatorBond(u128),
|
SetMinValidatorBond(u128),
|
||||||
|
SetGatekeepedNetwork(Gatekeeper),
|
||||||
SetTotalIssuance(Option<u128>),
|
SetTotalIssuance(Option<u128>),
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,7 @@ impl App {
|
|||||||
self.network_tx.send(Action::GetPendingExtrinsics)?;
|
self.network_tx.send(Action::GetPendingExtrinsics)?;
|
||||||
self.network_tx.send(Action::GetConnectedPeers)?;
|
self.network_tx.send(Action::GetConnectedPeers)?;
|
||||||
self.network_tx.send(Action::CheckPendingTransactions)?;
|
self.network_tx.send(Action::CheckPendingTransactions)?;
|
||||||
|
self.network_tx.send(Action::GetBlockRange)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
126
src/components/validator/gatekeeper_details.rs
Normal file
126
src/components/validator/gatekeeper_details.rs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use color_eyre::Result;
|
||||||
|
use ratatui::layout::Constraint;
|
||||||
|
use ratatui::{
|
||||||
|
text::Text,
|
||||||
|
layout::{Alignment, Rect},
|
||||||
|
widgets::{Block, Cell, Row, Table},
|
||||||
|
Frame
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{PartialComponent, Component, CurrentTab};
|
||||||
|
use crate::types::BlockRange;
|
||||||
|
use crate::{
|
||||||
|
action::Action,
|
||||||
|
config::Config,
|
||||||
|
palette::StylePalette,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
struct Details {
|
||||||
|
incoming_fee: String,
|
||||||
|
outgoing_fee: String,
|
||||||
|
gatekeeper: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct GatekeeperDetails {
|
||||||
|
palette: StylePalette,
|
||||||
|
gatekeeper_details: HashMap<u64, Details>,
|
||||||
|
block_ranges: HashMap<u64, BlockRange>,
|
||||||
|
selected_chain_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialComponent for GatekeeperDetails {
|
||||||
|
fn set_active(&mut self, _current_tab: CurrentTab) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for GatekeeperDetails {
|
||||||
|
fn register_config_handler(&mut self, config: Config) -> Result<()> {
|
||||||
|
if let Some(style) = config.styles.get(&crate::app::Mode::Validator) {
|
||||||
|
self.palette.with_normal_style(style.get("normal_style").copied());
|
||||||
|
self.palette.with_hover_style(style.get("hover_style").copied());
|
||||||
|
self.palette.with_normal_border_style(style.get("normal_border_style").copied());
|
||||||
|
self.palette.with_hover_border_style(style.get("hover_border_style").copied());
|
||||||
|
self.palette.with_normal_title_style(style.get("normal_title_style").copied());
|
||||||
|
self.palette.with_hover_title_style(style.get("hover_title_style").copied());
|
||||||
|
self.palette.with_highlight_style(style.get("highlight_style").copied());
|
||||||
|
self.palette.with_scrollbar_style(style.get("scrollbar_style").copied());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
||||||
|
match action {
|
||||||
|
Action::SetChoosenGatekeeper(chain_id) => self.selected_chain_id = chain_id,
|
||||||
|
Action::SetBlockRange(chain_id, block_range) => {
|
||||||
|
let _ = self.block_ranges.insert(chain_id, block_range);
|
||||||
|
},
|
||||||
|
Action::SetGatekeepedNetwork(network) => {
|
||||||
|
self.gatekeeper_details.insert(network.chain_id, Details {
|
||||||
|
incoming_fee: format!("{:.5}%", network.incoming_fee as f64 / 1_000_000_000.0),
|
||||||
|
outgoing_fee: format!("{:.5}%", network.outgoing_fee as f64 / 1_000_000_000.0),
|
||||||
|
gatekeeper: network.gatekeeper,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
|
||||||
|
let [_, place] = super::validator_gatekeeped_networks_layout(area);
|
||||||
|
let (border_style, border_type) = self.palette.create_border_style(false);
|
||||||
|
|
||||||
|
let current_gatekeeper_details = self.gatekeeper_details
|
||||||
|
.get(&self.selected_chain_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let current_block_range = self.block_ranges
|
||||||
|
.get(&self.selected_chain_id)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let table = Table::new(
|
||||||
|
vec![
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(Text::from("From block".to_string()).alignment(Alignment::Left)),
|
||||||
|
Cell::from(Text::from(current_block_range.from_block.to_string()).alignment(Alignment::Right)),
|
||||||
|
]),
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(Text::from("To block".to_string()).alignment(Alignment::Left)),
|
||||||
|
Cell::from(Text::from(current_block_range.to_block.to_string()).alignment(Alignment::Right)),
|
||||||
|
]),
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(Text::from("Incoming fee".to_string()).alignment(Alignment::Left)),
|
||||||
|
Cell::from(Text::from(current_gatekeeper_details.incoming_fee).alignment(Alignment::Right)),
|
||||||
|
]),
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(Text::from("Outgoing fee".to_string()).alignment(Alignment::Left)),
|
||||||
|
Cell::from(Text::from(current_gatekeeper_details.outgoing_fee).alignment(Alignment::Right)),
|
||||||
|
]),
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(Text::from("Gatekeeper".to_string()).alignment(Alignment::Left)),
|
||||||
|
Cell::from(Text::from(current_gatekeeper_details.gatekeeper).alignment(Alignment::Right)),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Constraint::Length(12),
|
||||||
|
Constraint::Fill(1),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.highlight_style(self.palette.create_highlight_style())
|
||||||
|
.column_spacing(1)
|
||||||
|
.block(Block::bordered()
|
||||||
|
.border_style(border_style)
|
||||||
|
.border_type(border_type)
|
||||||
|
.title_alignment(Alignment::Right)
|
||||||
|
.title_style(self.palette.create_title_style(false))
|
||||||
|
.title(format!("Chain ID: {}", self.selected_chain_id)));
|
||||||
|
|
||||||
|
frame.render_widget(table, place);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
235
src/components/validator/gatekeepers.rs
Normal file
235
src/components/validator/gatekeepers.rs
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use color_eyre::Result;
|
||||||
|
use crossterm::event::{KeyCode, KeyEvent};
|
||||||
|
use ratatui::layout::Margin;
|
||||||
|
use ratatui::{
|
||||||
|
layout::{Alignment, Rect},
|
||||||
|
widgets::{
|
||||||
|
Block, List, ListState, ListItem, Scrollbar,
|
||||||
|
ScrollbarOrientation, ScrollbarState,
|
||||||
|
},
|
||||||
|
Frame
|
||||||
|
};
|
||||||
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
use super::{PartialComponent, Component, CurrentTab};
|
||||||
|
use crate::types::Gatekeeper;
|
||||||
|
use crate::{
|
||||||
|
action::Action,
|
||||||
|
config::Config,
|
||||||
|
palette::StylePalette,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NetworkDetails {
|
||||||
|
chain_id: u64,
|
||||||
|
chain_name: String,
|
||||||
|
chain_type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Gatekeepers {
|
||||||
|
is_active: bool,
|
||||||
|
action_tx: Option<UnboundedSender<Action>>,
|
||||||
|
palette: StylePalette,
|
||||||
|
scroll_state: ScrollbarState,
|
||||||
|
list_state: ListState,
|
||||||
|
gatekeepers: Vec<NetworkDetails>,
|
||||||
|
chain_ids: HashMap<u64, usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Gatekeepers {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Gatekeepers {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
is_active: false,
|
||||||
|
action_tx: None,
|
||||||
|
scroll_state: ScrollbarState::new(0),
|
||||||
|
list_state: ListState::default(),
|
||||||
|
gatekeepers: Vec::new(),
|
||||||
|
palette: StylePalette::default(),
|
||||||
|
chain_ids: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_choosen_gatekeeper(&mut self) {
|
||||||
|
if let Some(action_tx) = &self.action_tx {
|
||||||
|
if let Some(chain_id) = self.list_state
|
||||||
|
.selected()
|
||||||
|
.map(|index| self.gatekeepers
|
||||||
|
.get(index)
|
||||||
|
.map(|data| data.chain_id)
|
||||||
|
)
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
|
let _ = action_tx.send(Action::SetChoosenGatekeeper(chain_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_gatekeeped_network(&mut self, network: Gatekeeper) {
|
||||||
|
if let Some(index) = self.chain_ids.get(&network.chain_id) {
|
||||||
|
self.gatekeepers[*index] = NetworkDetails {
|
||||||
|
chain_id: network.chain_id,
|
||||||
|
chain_name: network.chain_name,
|
||||||
|
chain_type: network.chain_type,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let position = self.gatekeepers.len();
|
||||||
|
self.chain_ids.insert(network.chain_id, position);
|
||||||
|
self.gatekeepers.push(NetworkDetails {
|
||||||
|
chain_id: network.chain_id,
|
||||||
|
chain_name: network.chain_name,
|
||||||
|
chain_type: network.chain_type,
|
||||||
|
});
|
||||||
|
|
||||||
|
if position == 0 {
|
||||||
|
self.first_row();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_row(&mut self) {
|
||||||
|
if self.gatekeepers.len() > 0 {
|
||||||
|
self.list_state.select(Some(0));
|
||||||
|
self.scroll_state = self.scroll_state.position(0);
|
||||||
|
}
|
||||||
|
self.change_choosen_gatekeeper();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_row(&mut self) {
|
||||||
|
let i = match self.list_state.selected() {
|
||||||
|
Some(i) => {
|
||||||
|
if i >= self.gatekeepers.len() - 1 {
|
||||||
|
i
|
||||||
|
} else {
|
||||||
|
i + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
self.list_state.select(Some(i));
|
||||||
|
self.scroll_state = self.scroll_state.position(i);
|
||||||
|
self.change_choosen_gatekeeper();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last_row(&mut self) {
|
||||||
|
if self.gatekeepers.len() > 0 {
|
||||||
|
let last = self.gatekeepers.len() - 1;
|
||||||
|
self.list_state.select(Some(last));
|
||||||
|
self.scroll_state = self.scroll_state.position(last);
|
||||||
|
}
|
||||||
|
self.change_choosen_gatekeeper();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn previous_row(&mut self) {
|
||||||
|
let i = match self.list_state.selected() {
|
||||||
|
Some(i) => {
|
||||||
|
if i == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
i - 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => 0
|
||||||
|
};
|
||||||
|
self.list_state.select(Some(i));
|
||||||
|
self.scroll_state = self.scroll_state.position(i);
|
||||||
|
self.change_choosen_gatekeeper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialComponent for Gatekeepers {
|
||||||
|
fn set_active(&mut self, current_tab: CurrentTab) {
|
||||||
|
match current_tab {
|
||||||
|
CurrentTab::Gatekeepers => self.is_active = true,
|
||||||
|
_ => {
|
||||||
|
self.is_active = false;
|
||||||
|
self.list_state.select(None);
|
||||||
|
self.scroll_state = self.scroll_state.position(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Component for Gatekeepers {
|
||||||
|
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::Validator) {
|
||||||
|
self.palette.with_normal_style(style.get("normal_style").copied());
|
||||||
|
self.palette.with_hover_style(style.get("hover_style").copied());
|
||||||
|
self.palette.with_normal_border_style(style.get("normal_border_style").copied());
|
||||||
|
self.palette.with_hover_border_style(style.get("hover_border_style").copied());
|
||||||
|
self.palette.with_normal_title_style(style.get("normal_title_style").copied());
|
||||||
|
self.palette.with_hover_title_style(style.get("hover_title_style").copied());
|
||||||
|
self.palette.with_highlight_style(style.get("highlight_style").copied());
|
||||||
|
self.palette.with_scrollbar_style(style.get("scrollbar_style").copied());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, action: Action) -> Result<Option<Action>> {
|
||||||
|
match action {
|
||||||
|
Action::SetGatekeepedNetwork(network) =>
|
||||||
|
self.update_gatekeeped_network(network),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
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_gatekeeped_networks_layout(area);
|
||||||
|
let (border_style, border_type) = self.palette.create_border_style(self.is_active);
|
||||||
|
let list = List::new(
|
||||||
|
self.gatekeepers
|
||||||
|
.iter()
|
||||||
|
.map(|network| ListItem::new(format!("{} ({}) | {}",
|
||||||
|
network.chain_name,
|
||||||
|
network.chain_id,
|
||||||
|
network.chain_type))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.highlight_style(self.palette.create_highlight_style())
|
||||||
|
.block(Block::bordered()
|
||||||
|
.border_style(border_style)
|
||||||
|
.border_type(border_type)
|
||||||
|
.title_alignment(Alignment::Right)
|
||||||
|
.title_style(self.palette.create_title_style(false))
|
||||||
|
.title("Gatekeeped Networks"));
|
||||||
|
|
||||||
|
let scrollbar = Scrollbar::default()
|
||||||
|
.orientation(ScrollbarOrientation::VerticalRight)
|
||||||
|
.begin_symbol(None)
|
||||||
|
.end_symbol(None)
|
||||||
|
.style(self.palette.create_scrollbar_style());
|
||||||
|
|
||||||
|
frame.render_stateful_widget(list, place, &mut self.list_state);
|
||||||
|
frame.render_stateful_widget(
|
||||||
|
scrollbar,
|
||||||
|
place.inner(Margin { vertical: 1, horizontal: 1 }),
|
||||||
|
&mut self.scroll_state,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -150,7 +150,7 @@ impl Component for ListenAddresses {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
|
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
|
||||||
let [_, place] = super::validator_session_and_listen_layout(area);
|
let [_, place, _] = super::validator_session_and_listen_layout(area);
|
||||||
let (border_style, border_type) = self.palette.create_border_style(self.is_active);
|
let (border_style, border_type) = self.palette.create_border_style(self.is_active);
|
||||||
let list = List::new(
|
let list = List::new(
|
||||||
self.listen_addresses
|
self.listen_addresses
|
||||||
|
@ -16,6 +16,8 @@ mod peers;
|
|||||||
mod stash_info;
|
mod stash_info;
|
||||||
mod nominators;
|
mod nominators;
|
||||||
mod listen_addresses;
|
mod listen_addresses;
|
||||||
|
mod gatekeepers;
|
||||||
|
mod gatekeeper_details;
|
||||||
mod history;
|
mod history;
|
||||||
mod withdrawals;
|
mod withdrawals;
|
||||||
mod stash_details;
|
mod stash_details;
|
||||||
@ -39,6 +41,8 @@ use event_log::EventLogs;
|
|||||||
use peers::Peers;
|
use peers::Peers;
|
||||||
use stash_info::StashInfo;
|
use stash_info::StashInfo;
|
||||||
use listen_addresses::ListenAddresses;
|
use listen_addresses::ListenAddresses;
|
||||||
|
use gatekeepers::Gatekeepers;
|
||||||
|
use gatekeeper_details::GatekeeperDetails;
|
||||||
use nominators::NominatorsByValidator;
|
use nominators::NominatorsByValidator;
|
||||||
use history::History;
|
use history::History;
|
||||||
use withdrawals::Withdrawals;
|
use withdrawals::Withdrawals;
|
||||||
@ -57,6 +61,7 @@ use payee_popup::PayeePopup;
|
|||||||
pub enum CurrentTab {
|
pub enum CurrentTab {
|
||||||
Nothing,
|
Nothing,
|
||||||
ListenAddresses,
|
ListenAddresses,
|
||||||
|
Gatekeepers,
|
||||||
NominatorsByValidator,
|
NominatorsByValidator,
|
||||||
History,
|
History,
|
||||||
Withdrawals,
|
Withdrawals,
|
||||||
@ -97,10 +102,12 @@ impl Default for Validator {
|
|||||||
Box::new(StashDetails::default()),
|
Box::new(StashDetails::default()),
|
||||||
Box::new(StakingDetails::default()),
|
Box::new(StakingDetails::default()),
|
||||||
Box::new(RewardDetails::default()),
|
Box::new(RewardDetails::default()),
|
||||||
|
Box::new(GatekeeperDetails::default()),
|
||||||
Box::new(History::default()),
|
Box::new(History::default()),
|
||||||
Box::new(Withdrawals::default()),
|
Box::new(Withdrawals::default()),
|
||||||
Box::new(Peers::default()),
|
Box::new(Peers::default()),
|
||||||
Box::new(ListenAddresses::default()),
|
Box::new(ListenAddresses::default()),
|
||||||
|
Box::new(Gatekeepers::default()),
|
||||||
Box::new(EventLogs::default()),
|
Box::new(EventLogs::default()),
|
||||||
Box::new(BondPopup::default()),
|
Box::new(BondPopup::default()),
|
||||||
Box::new(PayoutPopup::default()),
|
Box::new(PayoutPopup::default()),
|
||||||
@ -124,14 +131,16 @@ impl Validator {
|
|||||||
CurrentTab::Peers => self.current_tab = CurrentTab::Withdrawals,
|
CurrentTab::Peers => self.current_tab = CurrentTab::Withdrawals,
|
||||||
CurrentTab::Withdrawals => self.current_tab = CurrentTab::History,
|
CurrentTab::Withdrawals => self.current_tab = CurrentTab::History,
|
||||||
CurrentTab::History => self.current_tab = CurrentTab::NominatorsByValidator,
|
CurrentTab::History => self.current_tab = CurrentTab::NominatorsByValidator,
|
||||||
CurrentTab::ListenAddresses => self.current_tab = CurrentTab::NominatorsByValidator,
|
CurrentTab::NominatorsByValidator => self.current_tab = CurrentTab::Gatekeepers,
|
||||||
|
CurrentTab::ListenAddresses => self.current_tab = CurrentTab::Gatekeepers,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_right(&mut self) {
|
fn move_right(&mut self) {
|
||||||
match self.current_tab {
|
match self.current_tab {
|
||||||
CurrentTab::ListenAddresses => self.current_tab = CurrentTab::NominatorsByValidator,
|
CurrentTab::ListenAddresses => self.current_tab = CurrentTab::Gatekeepers,
|
||||||
|
CurrentTab::Gatekeepers => self.current_tab = CurrentTab::NominatorsByValidator,
|
||||||
CurrentTab::Nothing => self.current_tab = CurrentTab::NominatorsByValidator,
|
CurrentTab::Nothing => self.current_tab = CurrentTab::NominatorsByValidator,
|
||||||
CurrentTab::NominatorsByValidator => self.current_tab = CurrentTab::History,
|
CurrentTab::NominatorsByValidator => self.current_tab = CurrentTab::History,
|
||||||
CurrentTab::History => self.current_tab = CurrentTab::Withdrawals,
|
CurrentTab::History => self.current_tab = CurrentTab::Withdrawals,
|
||||||
@ -278,7 +287,7 @@ impl Component for Validator {
|
|||||||
|
|
||||||
pub fn validator_layout(area: Rect) -> [Rect; 4] {
|
pub fn validator_layout(area: Rect) -> [Rect; 4] {
|
||||||
Layout::vertical([
|
Layout::vertical([
|
||||||
Constraint::Length(16),
|
Constraint::Length(19),
|
||||||
Constraint::Fill(1),
|
Constraint::Fill(1),
|
||||||
Constraint::Fill(1),
|
Constraint::Fill(1),
|
||||||
Constraint::Percentage(25),
|
Constraint::Percentage(25),
|
||||||
@ -293,14 +302,23 @@ pub fn validator_details_layout(area: Rect) -> [Rect; 2] {
|
|||||||
]).areas(place)
|
]).areas(place)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validator_session_and_listen_layout(area: Rect) -> [Rect; 2] {
|
pub fn validator_session_and_listen_layout(area: Rect) -> [Rect; 3] {
|
||||||
let [_, place] = validator_details_layout(area);
|
let [_, place] = validator_details_layout(area);
|
||||||
Layout::vertical([
|
Layout::vertical([
|
||||||
|
Constraint::Length(6),
|
||||||
Constraint::Length(6),
|
Constraint::Length(6),
|
||||||
Constraint::Fill(1),
|
Constraint::Fill(1),
|
||||||
]).areas(place)
|
]).areas(place)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn validator_gatekeeped_networks_layout(area: Rect) -> [Rect; 2] {
|
||||||
|
let [_, _, place] = validator_session_and_listen_layout(area);
|
||||||
|
Layout::horizontal([
|
||||||
|
Constraint::Fill(1),
|
||||||
|
Constraint::Length(57),
|
||||||
|
]).areas(place)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn validator_statistics_layout(area: Rect) -> [Rect; 3] {
|
pub fn validator_statistics_layout(area: Rect) -> [Rect; 3] {
|
||||||
let [_, place, _, _] = validator_layout(area);
|
let [_, place, _, _] = validator_layout(area);
|
||||||
Layout::horizontal([
|
Layout::horizontal([
|
||||||
@ -314,7 +332,7 @@ pub fn validator_balance_layout(area: Rect) -> [Rect; 3] {
|
|||||||
let [place, _] = validator_details_layout(area);
|
let [place, _] = validator_details_layout(area);
|
||||||
Layout::vertical([
|
Layout::vertical([
|
||||||
Constraint::Length(6),
|
Constraint::Length(6),
|
||||||
Constraint::Length(5),
|
Constraint::Length(6),
|
||||||
Constraint::Length(5),
|
Constraint::Length(9),
|
||||||
]).areas(place)
|
]).areas(place)
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ impl Component for StashInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
|
fn draw(&mut self, frame: &mut Frame, area: Rect) -> Result<()> {
|
||||||
let [place, _] = super::validator_session_and_listen_layout(area);
|
let [place, _, _] = super::validator_session_and_listen_layout(area);
|
||||||
let (border_style, border_type) = self.palette.create_border_style(self.is_active);
|
let (border_style, border_type) = self.palette.create_border_style(self.is_active);
|
||||||
let table = Table::new(
|
let table = Table::new(
|
||||||
self.key_names
|
self.key_names
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use tokio::sync::mpsc::UnboundedSender;
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use subxt::{backend::{legacy::rpc_methods::SystemHealth, rpc::RpcClient}, rpc_params};
|
use subxt::{backend::{legacy::rpc_methods::SystemHealth, rpc::RpcClient}, rpc_params};
|
||||||
|
use codec::{Encode, Decode};
|
||||||
|
|
||||||
use crate::{action::Action, types::PeerInformation};
|
use crate::{action::Action, network::miscellaneous::get_slow_clap_storage_key, types::{BlockRange, PeerInformation}};
|
||||||
|
|
||||||
pub async fn get_node_name(
|
pub async fn get_node_name(
|
||||||
action_tx: &UnboundedSender<Action>,
|
action_tx: &UnboundedSender<Action>,
|
||||||
@ -132,3 +133,31 @@ pub async fn rotate_keys(
|
|||||||
action_tx.send(Action::StoreRotatedKeys(rotated_keys))?;
|
action_tx.send(Action::StoreRotatedKeys(rotated_keys))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_block_range(
|
||||||
|
action_tx: &UnboundedSender<Action>,
|
||||||
|
rpc_client: &RpcClient,
|
||||||
|
chain_id: u64
|
||||||
|
) -> Result<()> {
|
||||||
|
let chain_id_encoded = chain_id.encode();
|
||||||
|
let block_range_key_raw = get_slow_clap_storage_key(b"block-", &chain_id_encoded);
|
||||||
|
let mut block_range_key = String::from("0x");
|
||||||
|
for byte in block_range_key_raw {
|
||||||
|
block_range_key.push_str(&format!("{:02x}", byte));
|
||||||
|
}
|
||||||
|
let block_range: BlockRange = rpc_client
|
||||||
|
.request("offchain_localStorageGet", rpc_params!["PERSISTENT", block_range_key])
|
||||||
|
.await
|
||||||
|
.ok()
|
||||||
|
.map(|hex_string: String| {
|
||||||
|
let bytes = hex::decode(&hex_string[2..]).expect("Invalid hex string");
|
||||||
|
let mut cursor = &bytes[..];
|
||||||
|
let from_block: u64 = u64::decode(&mut cursor).expect("first valid");
|
||||||
|
let to_block: u64 = u64::decode(&mut cursor).expect("second valid");
|
||||||
|
BlockRange { from_block, to_block }
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
action_tx.send(Action::SetBlockRange(chain_id, block_range))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use subxt::ext::sp_runtime::Perbill;
|
use subxt::ext::sp_runtime::Perbill;
|
||||||
|
|
||||||
|
const SLOW_CLAP_DB_PREFIX: &[u8] = b"slow_clap::";
|
||||||
|
|
||||||
// generated outside, based on params
|
// generated outside, based on params
|
||||||
// MIN_INFLATION: u32 = 0_006_900;
|
// MIN_INFLATION: u32 = 0_006_900;
|
||||||
// MAX_INFLATION: u32 = 0_690_000;
|
// MAX_INFLATION: u32 = 0_690_000;
|
||||||
@ -112,3 +114,10 @@ pub fn prepare_perbill_fraction_string(value: Perbill) -> String {
|
|||||||
|
|
||||||
format!("{}.{:02}%", units, rest / m)
|
format!("{}.{:02}%", units, rest / m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_slow_clap_storage_key(first: &[u8], second: &[u8]) -> Vec<u8> {
|
||||||
|
let mut key = SLOW_CLAP_DB_PREFIX.to_vec();
|
||||||
|
key.extend(first);
|
||||||
|
key.extend(second);
|
||||||
|
key
|
||||||
|
}
|
||||||
|
@ -21,6 +21,10 @@ use crate::{
|
|||||||
|
|
||||||
pub use subscriptions::{FinalizedSubscription, BestSubscription};
|
pub use subscriptions::{FinalizedSubscription, BestSubscription};
|
||||||
|
|
||||||
|
const GATEKEEPED_CHAIN_IDS: [u64; 1] = [
|
||||||
|
11155111, //Sepolia
|
||||||
|
];
|
||||||
|
|
||||||
struct TxToWatch {
|
struct TxToWatch {
|
||||||
tx_progress: TxProgress<CasperConfig, OnlineClient<CasperConfig>>,
|
tx_progress: TxProgress<CasperConfig, OnlineClient<CasperConfig>>,
|
||||||
sender: String,
|
sender: String,
|
||||||
@ -186,12 +190,20 @@ impl Network {
|
|||||||
Action::GetListenAddresses => legacy_rpc_calls::get_listen_addresses(&self.action_tx, &self.rpc_client).await,
|
Action::GetListenAddresses => legacy_rpc_calls::get_listen_addresses(&self.action_tx, &self.rpc_client).await,
|
||||||
Action::GetLocalIdentity => legacy_rpc_calls::get_local_identity(&self.action_tx, &self.rpc_client).await,
|
Action::GetLocalIdentity => legacy_rpc_calls::get_local_identity(&self.action_tx, &self.rpc_client).await,
|
||||||
Action::RotateSessionKeys => legacy_rpc_calls::rotate_keys(&self.action_tx, &self.rpc_client).await,
|
Action::RotateSessionKeys => legacy_rpc_calls::rotate_keys(&self.action_tx, &self.rpc_client).await,
|
||||||
|
Action::GetBlockRange => {
|
||||||
|
for chain_id in GATEKEEPED_CHAIN_IDS {
|
||||||
|
legacy_rpc_calls::get_block_range(&self.action_tx, &self.rpc_client, chain_id).await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
Action::GetBlockAuthor(hash, logs) => predefined_calls::get_block_author(&self.action_tx, &self.online_client_api, &logs, &hash).await,
|
Action::GetBlockAuthor(hash, logs) => predefined_calls::get_block_author(&self.action_tx, &self.online_client_api, &logs, &hash).await,
|
||||||
Action::GetActiveEra => predefined_calls::get_active_era(&self.action_tx, &self.online_client_api).await,
|
Action::GetActiveEra => predefined_calls::get_active_era(&self.action_tx, &self.online_client_api).await,
|
||||||
Action::GetCurrentEra => predefined_calls::get_current_era(&self.action_tx, &self.online_client_api).await,
|
Action::GetCurrentEra => predefined_calls::get_current_era(&self.action_tx, &self.online_client_api).await,
|
||||||
Action::GetEpochProgress => predefined_calls::get_epoch_progress(&self.action_tx, &self.online_client_api).await,
|
Action::GetEpochProgress => predefined_calls::get_epoch_progress(&self.action_tx, &self.online_client_api).await,
|
||||||
Action::GetMinValidatorBond => predefined_calls::get_minimal_validator_bond(&self.action_tx, &self.online_client_api).await,
|
Action::GetMinValidatorBond => predefined_calls::get_minimal_validator_bond(&self.action_tx, &self.online_client_api).await,
|
||||||
|
Action::GetGatekeepedNetwork(chain_id) => predefined_calls::get_gatekeeped_network(&self.action_tx, &self.online_client_api, chain_id).await,
|
||||||
|
|
||||||
|
|
||||||
Action::GetExistentialDeposit => predefined_calls::get_existential_deposit(&self.action_tx, &self.online_client_api).await,
|
Action::GetExistentialDeposit => predefined_calls::get_existential_deposit(&self.action_tx, &self.online_client_api).await,
|
||||||
Action::GetTotalIssuance => predefined_calls::get_total_issuance(&self.action_tx, &self.online_client_api).await,
|
Action::GetTotalIssuance => predefined_calls::get_total_issuance(&self.action_tx, &self.online_client_api).await,
|
||||||
|
@ -13,8 +13,8 @@ use subxt::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
action::Action,
|
action::Action,
|
||||||
casper_network::runtime_types::{pallet_staking::RewardDestination, sp_consensus_slots},
|
casper_network::runtime_types::{ghost_networks::NetworkType, pallet_staking::RewardDestination, sp_consensus_slots},
|
||||||
types::{EraInfo, EraRewardPoints, Nominator, Nominations, SessionKeyInfo, SystemAccount, UnlockChunk},
|
types::{EraInfo, EraRewardPoints, Gatekeeper, Nominations, Nominator, SessionKeyInfo, SystemAccount, UnlockChunk},
|
||||||
CasperAccountId, CasperConfig
|
CasperAccountId, CasperConfig
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -644,3 +644,29 @@ pub async fn get_account_payee(
|
|||||||
action_tx.send(Action::SetStakingPayee(payee, *account_id))?;
|
action_tx.send(Action::SetStakingPayee(payee, *account_id))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_gatekeeped_network(
|
||||||
|
action_tx: &UnboundedSender<Action>,
|
||||||
|
api: &OnlineClient<CasperConfig>,
|
||||||
|
chain_id: u64,
|
||||||
|
) -> Result<()> {
|
||||||
|
let gatekeeped_network = super::raw_calls::networks::networks(api, None, chain_id)
|
||||||
|
.await?
|
||||||
|
.map(|network| Gatekeeper {
|
||||||
|
chain_id,
|
||||||
|
chain_name: String::from_utf8_lossy(&network.chain_name)
|
||||||
|
.to_string(),
|
||||||
|
chain_type: match network.network_type {
|
||||||
|
NetworkType::Evm => String::from("EVM"),
|
||||||
|
NetworkType::Utxo => String::from("UTXO"),
|
||||||
|
NetworkType::Undefined => String::from("???"),
|
||||||
|
},
|
||||||
|
gatekeeper: String::from_utf8_lossy(&network.gatekeeper)
|
||||||
|
.to_string(),
|
||||||
|
incoming_fee: network.incoming_fee,
|
||||||
|
outgoing_fee: network.outgoing_fee,
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
action_tx.send(Action::SetGatekeepedNetwork(gatekeeped_network))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
@ -7,7 +7,7 @@ use subxt::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
casper_network::{
|
casper_network::{
|
||||||
self,
|
self,
|
||||||
runtime_types::ghost_networks::BridgeAdjustment,
|
runtime_types::ghost_networks::{BridgeAdjustment, NetworkData},
|
||||||
},
|
},
|
||||||
CasperConfig,
|
CasperConfig,
|
||||||
};
|
};
|
||||||
@ -29,3 +29,13 @@ pub async fn accumulated_commission(
|
|||||||
let maybe_accumulated_commission = super::do_storage_call(online_client, &storage_key, at_hash).await?;
|
let maybe_accumulated_commission = super::do_storage_call(online_client, &storage_key, at_hash).await?;
|
||||||
Ok(maybe_accumulated_commission)
|
Ok(maybe_accumulated_commission)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn networks(
|
||||||
|
online_client: &OnlineClient<CasperConfig>,
|
||||||
|
at_hash: Option<&H256>,
|
||||||
|
chain_id: u64,
|
||||||
|
) -> Result<Option<NetworkData>> {
|
||||||
|
let storage_key = casper_network::storage().ghost_networks().networks(chain_id);
|
||||||
|
let maybe_network = super::do_storage_call(online_client, &storage_key, at_hash).await?;
|
||||||
|
Ok(maybe_network)
|
||||||
|
}
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
use crate::{types::CasperExtrinsicDetails, action::Action, casper::CasperBlock};
|
use crate::{
|
||||||
|
types::CasperExtrinsicDetails,
|
||||||
|
action::Action,
|
||||||
|
casper::CasperBlock,
|
||||||
|
};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
|
|
||||||
|
use super::GATEKEEPED_CHAIN_IDS;
|
||||||
|
|
||||||
pub struct FinalizedSubscription {
|
pub struct FinalizedSubscription {
|
||||||
action_tx: tokio::sync::mpsc::UnboundedSender<Action>,
|
action_tx: tokio::sync::mpsc::UnboundedSender<Action>,
|
||||||
network_tx: std::sync::mpsc::Sender<Action>,
|
network_tx: std::sync::mpsc::Sender<Action>,
|
||||||
@ -120,6 +126,10 @@ impl BestSubscription {
|
|||||||
self.network_tx.send(Action::GetInflation)?;
|
self.network_tx.send(Action::GetInflation)?;
|
||||||
self.network_tx.send(Action::GetCurrentValidatorEraRewards)?;
|
self.network_tx.send(Action::GetCurrentValidatorEraRewards)?;
|
||||||
self.network_tx.send(Action::GetMinValidatorBond)?;
|
self.network_tx.send(Action::GetMinValidatorBond)?;
|
||||||
|
|
||||||
|
for chain_id in GATEKEEPED_CHAIN_IDS {
|
||||||
|
self.network_tx.send(Action::GetGatekeepedNetwork(chain_id))?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ mod peer;
|
|||||||
mod session;
|
mod session;
|
||||||
mod nominator;
|
mod nominator;
|
||||||
mod staking;
|
mod staking;
|
||||||
|
mod networks;
|
||||||
|
|
||||||
pub use extrinsics::CasperExtrinsicDetails;
|
pub use extrinsics::CasperExtrinsicDetails;
|
||||||
pub use era::{EraRewardPoints, EraInfo};
|
pub use era::{EraRewardPoints, EraInfo};
|
||||||
@ -18,3 +19,5 @@ pub use nominator::Nominator;
|
|||||||
pub use nominator::Nominations;
|
pub use nominator::Nominations;
|
||||||
pub use staking::UnlockChunk;
|
pub use staking::UnlockChunk;
|
||||||
pub use staking::RewardDestination;
|
pub use staking::RewardDestination;
|
||||||
|
pub use networks::Gatekeeper;
|
||||||
|
pub use networks::BlockRange;
|
||||||
|
18
src/types/networks.rs
Normal file
18
src/types/networks.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use codec::Decode;
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, Decode)]
|
||||||
|
pub struct Gatekeeper {
|
||||||
|
pub chain_id: u64,
|
||||||
|
pub chain_name: String,
|
||||||
|
pub chain_type: String,
|
||||||
|
pub gatekeeper: String,
|
||||||
|
pub incoming_fee: u32,
|
||||||
|
pub outgoing_fee: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Decode)]
|
||||||
|
pub struct BlockRange {
|
||||||
|
pub from_block: u64,
|
||||||
|
pub to_block: u64,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user