diff --git a/chain/jsonrpc-primitives/src/types/status.rs b/chain/jsonrpc-primitives/src/types/status.rs index d0a29e7db29..fe116a24aa5 100644 --- a/chain/jsonrpc-primitives/src/types/status.rs +++ b/chain/jsonrpc-primitives/src/types/status.rs @@ -5,7 +5,7 @@ use near_client_primitives::debug::{ #[cfg(feature = "debug_types")] use near_primitives::views::{ CatchupStatusView, ChainProcessingInfo, NetworkGraphView, NetworkRoutesView, PeerStoreView, - RecentOutboundConnectionsView, RequestedStatePartsView, SyncStatusView, + RecentOutboundConnectionsView, RequestedStatePartsView, SnapshotHostsView, SyncStatusView, }; #[derive(Debug, serde::Serialize, serde::Deserialize)] @@ -33,6 +33,7 @@ pub enum DebugStatusResponse { NetworkGraph(NetworkGraphView), RecentOutboundConnections(RecentOutboundConnectionsView), Routes(NetworkRoutesView), + SnapshotHosts(SnapshotHostsView), } #[cfg(feature = "debug_types")] diff --git a/chain/jsonrpc/src/api/status.rs b/chain/jsonrpc/src/api/status.rs index 6ea655df977..d856bbdd693 100644 --- a/chain/jsonrpc/src/api/status.rs +++ b/chain/jsonrpc/src/api/status.rs @@ -70,6 +70,9 @@ impl RpcFrom near_network::debug::DebugStatus::Routes(x) => { near_jsonrpc_primitives::types::status::DebugStatusResponse::Routes(x) } + near_network::debug::DebugStatus::SnapshotHosts(x) => { + near_jsonrpc_primitives::types::status::DebugStatusResponse::SnapshotHosts(x) + } } } } diff --git a/chain/jsonrpc/src/lib.rs b/chain/jsonrpc/src/lib.rs index ee3a1166219..c2a2f68604d 100644 --- a/chain/jsonrpc/src/lib.rs +++ b/chain/jsonrpc/src/lib.rs @@ -761,6 +761,10 @@ impl JsonRpcHandler { .peer_manager_send(near_network::debug::GetDebugStatus::Routes) .await? .rpc_into(), + "/debug/api/snapshot_hosts" => self + .peer_manager_send(near_network::debug::GetDebugStatus::SnapshotHosts) + .await? + .rpc_into(), _ => return Ok(None), }; Ok(Some(near_jsonrpc_primitives::types::status::RpcDebugStatusResponse { diff --git a/chain/network/src/debug.rs b/chain/network/src/debug.rs index fdf89b2e84a..f30115ba606 100644 --- a/chain/network/src/debug.rs +++ b/chain/network/src/debug.rs @@ -1,6 +1,7 @@ use ::actix::Message; use near_primitives::views::{ NetworkGraphView, NetworkRoutesView, PeerStoreView, RecentOutboundConnectionsView, + SnapshotHostsView, }; // Different debug requests that can be sent by HTML pages, via GET. @@ -9,6 +10,7 @@ pub enum GetDebugStatus { Graph, RecentOutboundConnections, Routes, + SnapshotHosts, } #[derive(actix::MessageResponse, Debug)] @@ -17,6 +19,7 @@ pub enum DebugStatus { Graph(NetworkGraphView), RecentOutboundConnections(RecentOutboundConnectionsView), Routes(NetworkRoutesView), + SnapshotHosts(SnapshotHostsView), } impl Message for GetDebugStatus { diff --git a/chain/network/src/peer_manager/peer_manager_actor.rs b/chain/network/src/peer_manager/peer_manager_actor.rs index b3811049db5..03850e59283 100644 --- a/chain/network/src/peer_manager/peer_manager_actor.rs +++ b/chain/network/src/peer_manager/peer_manager_actor.rs @@ -31,7 +31,7 @@ use near_primitives::network::{AnnounceAccount, PeerId}; use near_primitives::types::EpochHeight; use near_primitives::views::{ ConnectionInfoView, EdgeView, KnownPeerStateView, NetworkGraphView, PeerStoreView, - RecentOutboundConnectionsView, + RecentOutboundConnectionsView, SnapshotHostInfoView, SnapshotHostsView, }; use rand::seq::IteratorRandom; use rand::thread_rng; @@ -1111,6 +1111,20 @@ impl actix::Handler for PeerManagerActor { }) } GetDebugStatus::Routes => DebugStatus::Routes(self.state.graph_v2.get_debug_view()), + GetDebugStatus::SnapshotHosts => DebugStatus::SnapshotHosts(SnapshotHostsView { + hosts: self + .state + .snapshot_hosts + .get_hosts() + .iter() + .map(|h| SnapshotHostInfoView { + peer_id: h.peer_id.clone(), + sync_hash: h.sync_hash, + epoch_height: h.epoch_height, + shards: h.shards.clone(), + }) + .collect::>(), + }), } } } diff --git a/core/primitives/src/views.rs b/core/primitives/src/views.rs index 6c6becdd162..61b5559b9ee 100644 --- a/core/primitives/src/views.rs +++ b/core/primitives/src/views.rs @@ -284,6 +284,15 @@ pub struct ConnectionInfoView { pub time_connected_until: i64, } +#[cfg_attr(feature = "deepsize_feature", derive(deepsize::DeepSizeOf))] +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone)] +pub struct SnapshotHostInfoView { + pub peer_id: PeerId, + pub sync_hash: CryptoHash, + pub epoch_height: u64, + pub shards: Vec, +} + #[cfg_attr(feature = "deepsize_feature", derive(deepsize::DeepSizeOf))] #[derive(Debug, PartialEq, Eq, Clone)] pub enum QueryResponseKind { @@ -446,6 +455,11 @@ pub struct RecentOutboundConnectionsView { pub recent_outbound_connections: Vec, } +#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)] +pub struct SnapshotHostsView { + pub hosts: Vec, +} + #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq)] pub struct EdgeView { pub peer0: PeerId, diff --git a/tools/debug-ui/src/NetworkInfoView.tsx b/tools/debug-ui/src/NetworkInfoView.tsx index 63ab02267d8..c95134e4cc2 100644 --- a/tools/debug-ui/src/NetworkInfoView.tsx +++ b/tools/debug-ui/src/NetworkInfoView.tsx @@ -5,6 +5,7 @@ import { PeerStorageView } from './PeerStorageView'; import { ConnectionStorageView } from './ConnectionStorageView'; import { Tier1View } from './Tier1View'; import { RoutingTableView } from './RoutingTableView'; +import { SnapshotHostsView } from './SnapshotHostsView'; type NetworkInfoViewProps = { addr: string; @@ -29,6 +30,9 @@ export const NetworkInfoView = ({ addr }: NetworkInfoViewProps) => { Routing Table + + Snapshot Hosts + } /> @@ -37,6 +41,7 @@ export const NetworkInfoView = ({ addr }: NetworkInfoViewProps) => { } /> } /> } /> + } /> ); diff --git a/tools/debug-ui/src/SnapshotHostsView.scss b/tools/debug-ui/src/SnapshotHostsView.scss new file mode 100644 index 00000000000..9448bd3898c --- /dev/null +++ b/tools/debug-ui/src/SnapshotHostsView.scss @@ -0,0 +1,3 @@ +.snapshot-hosts-view { + margin: 10px; +} diff --git a/tools/debug-ui/src/SnapshotHostsView.tsx b/tools/debug-ui/src/SnapshotHostsView.tsx new file mode 100644 index 00000000000..c647c75bda6 --- /dev/null +++ b/tools/debug-ui/src/SnapshotHostsView.tsx @@ -0,0 +1,51 @@ +import { useQuery } from 'react-query'; +import { toHumanTime } from './utils'; +import { fetchSnapshotHosts } from './api'; +import './SnapshotHostsView.scss'; + +type SnapshotHostsViewProps = { + addr: string; +}; + +export const SnapshotHostsView = ({ addr }: SnapshotHostsViewProps) => { + const { + data: snapshotHosts, + error, + isLoading, + } = useQuery(['snapshotHosts', addr], () => fetchSnapshotHosts(addr)); + + if (isLoading) { + return
Loading...
; + } else if (error) { + return
{(error as Error).stack}
; + } + + const snapshot_hosts = snapshotHosts!.status_response.SnapshotHosts; + + return ( +
+ + + + + + + + + {snapshot_hosts.hosts.map( + (host) => { + return ( + + + + + + + ); + } + )} + +
Peer IDShardsEpoch HeightSync Hash
{host.peer_id}{JSON.stringify(host.shards)}{host.epoch_height}{host.sync_hash}
+
+ ); +}; diff --git a/tools/debug-ui/src/api.tsx b/tools/debug-ui/src/api.tsx index 145982d6d43..3c8c2404ed7 100644 --- a/tools/debug-ui/src/api.tsx +++ b/tools/debug-ui/src/api.tsx @@ -330,6 +330,23 @@ export interface RoutingTableResponse { }; } +export interface SnapshotHostInfoView { + peer_id: string, + sync_hash: string, + epoch_height: number, + shards: number[], +} + +export interface SnapshotHostsView { + hosts: SnapshotHostInfoView[], +} + +export interface SnapshotHostsResponse { + status_response: { + SnapshotHosts: SnapshotHostsView; + }; +} + export type DroppedReason = 'HeightProcessed' | 'TooManyProcessingBlocks'; export type BlockProcessingStatus = @@ -441,6 +458,13 @@ export async function fetchRoutingTable( return await response.json(); } +export async function fetchSnapshotHosts( + addr: string +): Promise { + const response = await fetch(`http://${addr}/debug/api/snapshot_hosts`); + return await response.json(); +} + export async function fetchChainProcessingStatus( addr: string ): Promise {