Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added peer store information to network page #7761

Merged
merged 13 commits into from
Oct 20, 2022
20 changes: 19 additions & 1 deletion chain/jsonrpc-primitives/src/types/status.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use near_client_primitives::debug::{
DebugBlockStatus, EpochInfoView, TrackedShardsView, ValidatorStatus,
};
use near_primitives::views::{CatchupStatusView, PeerStoreView, SyncStatusView};
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
Expand All @@ -6,10 +10,24 @@ pub struct RpcStatusResponse {
pub status_response: near_primitives::views::StatusResponse,
}

#[derive(Serialize, Debug)]
pub enum DebugStatusResponse {
SyncStatus(SyncStatusView),
CatchupStatus(Vec<CatchupStatusView>),
TrackedShards(TrackedShardsView),
// List of epochs - in descending order (next epoch is first).
EpochInfo(Vec<EpochInfoView>),
// Detailed information about blocks.
BlockStatus(Vec<DebugBlockStatus>),
// Detailed information about the validator (approvals, block & chunk production etc.)
ValidatorStatus(ValidatorStatus),
PeerStore(PeerStoreView),
}

#[cfg(feature = "debug_types")]
#[derive(Debug, Serialize)]
pub struct RpcDebugStatusResponse {
pub status_response: near_client_primitives::debug::DebugStatusResponse,
pub status_response: DebugStatusResponse,
}

#[derive(Debug, Serialize, Deserialize)]
Expand Down
1 change: 1 addition & 0 deletions chain/jsonrpc/jsonrpc-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub fn start_all_with_validity_period_and_no_epoch_sync(
TEST_GENESIS_CONFIG.clone(),
client_addr,
view_client_addr.clone(),
None,
);
(view_client_addr, addr)
}
Expand Down
72 changes: 72 additions & 0 deletions chain/jsonrpc/res/network_info.html
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@
}

$(document).ready(() => {
$('.detailed-peer-storage-div').hide();
$('span').text("Loading...");
$.ajax({
type: "GET",
Expand Down Expand Up @@ -274,6 +275,57 @@
})

});

function to_human_time(seconds) {
let result = "";
if (seconds >= 60) {
let minutes = Math.floor(seconds / 60);
seconds = seconds % 60;
if (minutes > 60) {
let hours = Math.floor(minutes / 60);
minutes = minutes % 60;
if (hours > 24) {
let days = Math.floor(hours / 24);
hours = hours % 24;
result += days + " days ";
}
result += hours + " h ";
}
result += minutes + " m ";
}
result += seconds + " s"
return result;
}

function show_peer_storage() {
$(".detailed-peer-storage-button").text("Loading...");
$(".tbody-detailed-peer-storage").html("");
$.ajax({
type: "GET",
url: "/debug/api/peer_store",
success: data => {
$(".detailed-peer-storage-size").text(data.status_response.PeerStore.peer_states.length);
data.status_response.PeerStore.peer_states.forEach(element => {
let row = $("<tr>");
row.append($("<td>").append(element['peer_id']));
row.append($("<td>").append(element['addr']));

let first_seen =
row.append($("<td>").append(to_human_time(Math.floor(Date.now() / 1000) - element['first_seen'])));
row.append($("<td>").append(to_human_time(Math.floor(Date.now() / 1000) - element['last_seen'])));
if (element['last_attempt'] != null) {
row.append($("<td>").append(to_human_time(Math.floor(Date.now() / 1000) - element['last_attempt'])));
} else {
row.append($("<td>"));
}
row.append($("<td>").append(element['status']));
$(".tbody-detailed-peer-storage").append(row);
});
$(".detailed-peer-storage-div").show();
$(".detailed-peer-storage-button").text("Refresh");
}
});
}
</script>
</head>

Expand Down Expand Up @@ -349,6 +401,26 @@ <h2>
<tbody class="js-tbody-peers">
</tbody>
</table>
<br>
<button onclick="show_peer_storage()" class="detailed-peer-storage-button">
Show detailed peer storage
</button>
<div class="detailed-peer-storage-div">
<h2>Peers in storage: <span class="detailed-peer-storage-size"></span></h2>
<table class="detailed-peer-storage">
<thead>
<th>Peer id</th>
<th>Peer address</th>
<th>First seen</th>
<th>Last seen</th>
<th>Last connection attempt</th>
<th>Status</th>
</thead>
<tbody class="tbody-detailed-peer-storage">

</tbody>
</table>
</div>
</body>

</html>
37 changes: 34 additions & 3 deletions chain/jsonrpc/src/api/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,41 @@ impl RpcFrom<StatusResponse> for RpcStatusResponse {
}

impl RpcFrom<near_client_primitives::debug::DebugStatusResponse>
for near_jsonrpc_primitives::types::status::RpcDebugStatusResponse
for near_jsonrpc_primitives::types::status::DebugStatusResponse
{
fn rpc_from(status_response: near_client_primitives::debug::DebugStatusResponse) -> Self {
Self { status_response }
fn rpc_from(response: near_client_primitives::debug::DebugStatusResponse) -> Self {
match response {
near_client_primitives::debug::DebugStatusResponse::SyncStatus(x) => {
near_jsonrpc_primitives::types::status::DebugStatusResponse::SyncStatus(x)
}
near_client_primitives::debug::DebugStatusResponse::CatchupStatus(x) => {
near_jsonrpc_primitives::types::status::DebugStatusResponse::CatchupStatus(x)
}
near_client_primitives::debug::DebugStatusResponse::TrackedShards(x) => {
near_jsonrpc_primitives::types::status::DebugStatusResponse::TrackedShards(x)
}
near_client_primitives::debug::DebugStatusResponse::EpochInfo(x) => {
near_jsonrpc_primitives::types::status::DebugStatusResponse::EpochInfo(x)
}
near_client_primitives::debug::DebugStatusResponse::BlockStatus(x) => {
near_jsonrpc_primitives::types::status::DebugStatusResponse::BlockStatus(x)
}
near_client_primitives::debug::DebugStatusResponse::ValidatorStatus(x) => {
near_jsonrpc_primitives::types::status::DebugStatusResponse::ValidatorStatus(x)
}
}
}
}

impl RpcFrom<near_network::debug::DebugStatus>
for near_jsonrpc_primitives::types::status::DebugStatusResponse
{
fn rpc_from(response: near_network::debug::DebugStatus) -> Self {
match response {
near_network::debug::DebugStatus::PeerStore(x) => {
near_jsonrpc_primitives::types::status::DebugStatusResponse::PeerStore(x)
}
}
}
}

Expand Down
60 changes: 47 additions & 13 deletions chain/jsonrpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
use std::path::PathBuf;
use std::time::{Duration, Instant};

use actix::Addr;
use actix::{Addr, MailboxError};
use actix_cors::Cors;
use actix_web::http::header;
use actix_web::HttpRequest;
use actix_web::{get, http, middleware, web, App, Error as HttpError, HttpResponse, HttpServer};
use futures::Future;
use futures::FutureExt;
use near_network::PeerManagerActor;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use tokio::time::{sleep, timeout};
Expand Down Expand Up @@ -220,6 +221,7 @@ fn process_query_response(
struct JsonRpcHandler {
client_addr: Addr<ClientActor>,
view_client_addr: Addr<ViewClientActor>,
peer_manager_addr: Option<Addr<PeerManagerActor>>,
polling_config: RpcPollingConfig,
genesis_config: GenesisConfig,
enable_debug_rpc: bool,
Expand Down Expand Up @@ -419,6 +421,19 @@ impl JsonRpcHandler {
.map_err(RpcFrom::rpc_from)
}

async fn peer_manager_send<M, T, E>(&self, msg: M) -> Result<T, E>
where
PeerManagerActor: actix::Handler<M>,
M: actix::Message<Result = T> + Send + 'static,
M::Result: Send,
E: RpcFrom<actix::MailboxError>,
{
match &self.peer_manager_addr {
Some(peer_manager_addr) => peer_manager_addr.send(msg).await.map_err(RpcFrom::rpc_from),
None => Err(RpcFrom::rpc_from(MailboxError::Closed)),
}
}

async fn send_tx_async(
&self,
request_data: near_jsonrpc_primitives::types::transactions::RpcBroadcastTransactionRequest,
Expand Down Expand Up @@ -758,18 +773,35 @@ impl JsonRpcHandler {
near_jsonrpc_primitives::types::status::RpcStatusError,
> {
if self.enable_debug_rpc {
let debug_status = match path {
"/debug/api/tracked_shards" => self.client_send(DebugStatus::TrackedShards).await?,
"/debug/api/sync_status" => self.client_send(DebugStatus::SyncStatus).await?,
"/debug/api/catchup_status" => self.client_send(DebugStatus::CatchupStatus).await?,
"/debug/api/epoch_info" => self.client_send(DebugStatus::EpochInfo).await?,
"/debug/api/block_status" => self.client_send(DebugStatus::BlockStatus).await?,
"/debug/api/validator_status" => {
self.client_send(DebugStatus::ValidatorStatus).await?
}
_ => return Ok(None),
};
return Ok(Some(debug_status.rpc_into()));
let debug_status: near_jsonrpc_primitives::types::status::DebugStatusResponse =
match path {
"/debug/api/tracked_shards" => {
self.client_send(DebugStatus::TrackedShards).await?.rpc_into()
}
"/debug/api/sync_status" => {
self.client_send(DebugStatus::SyncStatus).await?.rpc_into()
}
"/debug/api/catchup_status" => {
self.client_send(DebugStatus::CatchupStatus).await?.rpc_into()
}
"/debug/api/epoch_info" => {
self.client_send(DebugStatus::EpochInfo).await?.rpc_into()
}
"/debug/api/block_status" => {
self.client_send(DebugStatus::BlockStatus).await?.rpc_into()
}
"/debug/api/validator_status" => {
self.client_send(DebugStatus::ValidatorStatus).await?.rpc_into()
}
"/debug/api/peer_store" => self
.peer_manager_send(near_network::debug::GetDebugStatus::PeerStore)
.await?
.rpc_into(),
_ => return Ok(None),
};
return Ok(Some(near_jsonrpc_primitives::types::status::RpcDebugStatusResponse {
status_response: debug_status,
}));
} else {
return Ok(None);
}
Expand Down Expand Up @@ -1404,6 +1436,7 @@ pub fn start_http(
genesis_config: GenesisConfig,
client_addr: Addr<ClientActor>,
view_client_addr: Addr<ViewClientActor>,
peer_manager_addr: Option<Addr<PeerManagerActor>>,
) -> Vec<(&'static str, actix_web::dev::ServerHandle)> {
let RpcConfig {
addr,
Expand All @@ -1424,6 +1457,7 @@ pub fn start_http(
.app_data(web::Data::new(JsonRpcHandler {
client_addr: client_addr.clone(),
view_client_addr: view_client_addr.clone(),
peer_manager_addr: peer_manager_addr.clone(),
polling_config,
genesis_config: genesis_config.clone(),
enable_debug_rpc,
Expand Down
16 changes: 16 additions & 0 deletions chain/network/src/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use ::actix::Message;
use near_primitives::views::PeerStoreView;

// Different debug requests that can be sent by HTML pages, via GET.
pub enum GetDebugStatus {
PeerStore,
}

#[derive(actix::MessageResponse, Debug)]
pub enum DebugStatus {
PeerStore(PeerStoreView),
}

impl Message for GetDebugStatus {
type Result = DebugStatus;
}
1 change: 1 addition & 0 deletions chain/network/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod blacklist;
pub mod client;
pub mod config;
pub mod config_json;
pub mod debug;
pub mod routing;
pub mod tcp;
pub mod test_utils;
Expand Down
37 changes: 35 additions & 2 deletions chain/network/src/peer_manager/peer_manager_actor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::client;
use crate::config;
use crate::debug::{DebugStatus, GetDebugStatus};
use crate::network_protocol::{
AccountData, AccountOrPeerIdOrHash, Edge, EdgeState, PartialEdgeInfo, PeerInfo, PeerMessage,
Ping, Pong, RawRoutedMessage, RoutedMessageBody, RoutingTableUpdate, StateResponseInfo,
Expand Down Expand Up @@ -36,6 +37,7 @@ use near_performance_metrics_macros::perf;
use near_primitives::block::GenesisId;
use near_primitives::network::{AnnounceAccount, PeerId};
use near_primitives::types::AccountId;
use near_primitives::views::{KnownPeerStateView, PeerStoreView};
use parking_lot::RwLock;
use rand::seq::IteratorRandom;
use rand::thread_rng;
Expand Down Expand Up @@ -143,6 +145,9 @@ pub struct PeerManagerActor {
whitelist_nodes: Vec<WhitelistNode>,

pub(crate) state: Arc<NetworkState>,

/// Last time when we tried to establish connection to this peer.
last_peer_outbound_attempt: HashMap<PeerId, time::Utc>,
}

/// TEST-ONLY
Expand Down Expand Up @@ -299,6 +304,7 @@ impl PeerManagerActor {
started_connect_attempts: false,
local_peer_pending_update_nonce_request: HashMap::new(),
whitelist_nodes,
last_peer_outbound_attempt: Default::default(),
state: Arc::new(NetworkState::new(
config.clone(),
genesis_id,
Expand Down Expand Up @@ -878,7 +884,7 @@ impl PeerManagerActor {
self.started_connect_attempts = true;
interval = default_interval;
}

self.last_peer_outbound_attempt.insert(peer_info.id.clone(), self.clock.now_utc());
ctx.spawn(wrap_future({
let state = self.state.clone();
let clock = self.clock.clone();
Expand Down Expand Up @@ -1324,7 +1330,6 @@ impl PeerManagerActor {
self.handle_msg_network_requests(msg, ctx),
)
}
// TEST-ONLY
PeerManagerMessageRequest::OutboundTcpConnect(stream) => {
let peer_addr = stream.peer_addr;
if let Err(err) =
Expand Down Expand Up @@ -1581,3 +1586,31 @@ impl Handler<WithSpanContext<PeerManagerMessageRequest>> for PeerManagerActor {
self.handle_peer_manager_message(msg, ctx)
}
}

impl Handler<GetDebugStatus> for PeerManagerActor {
type Result = DebugStatus;
fn handle(&mut self, msg: GetDebugStatus, _ctx: &mut Context<Self>) -> Self::Result {
match msg {
GetDebugStatus::PeerStore => {
let mut peer_states_view = self
.peer_store
.iter()
.map(|(peer_id, known_peer_state)| KnownPeerStateView {
peer_id: peer_id.clone(),
status: format!("{:?}", known_peer_state.status),
addr: format!("{:?}", known_peer_state.peer_info.addr),
first_seen: known_peer_state.first_seen.unix_timestamp(),
last_seen: known_peer_state.last_seen.unix_timestamp(),
last_attempt: self
.last_peer_outbound_attempt
.get(peer_id)
.map(|it| it.unix_timestamp()),
})
.collect::<Vec<_>>();

peer_states_view.sort_by_key(|a| (-a.last_attempt.unwrap_or(0), -a.last_seen));
DebugStatus::PeerStore(PeerStoreView { peer_states: peer_states_view })
}
}
}
}
Loading