Skip to content

Commit

Permalink
feat: Yellow status indicator for a pruned peer (#62)
Browse files Browse the repository at this point in the history
* feat: Yellow status indicator for a pruned peer

* fix: Changed node cmi/lmi variable names in PeerState.ts

* fix: Removed peer sync check for pruning warning message
  • Loading branch information
brancoder authored Dec 22, 2021
1 parent 0867752 commit 3fb5e59
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 14 deletions.
45 changes: 39 additions & 6 deletions src/app/components/tangle/PeersSummaryPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ReactComponent as HealthBadIcon } from "../../../assets/health-bad.svg"
import { ReactComponent as HealthGoodIcon } from "../../../assets/health-good.svg";
import { ReactComponent as HealthWarningIcon } from "../../../assets/health-warning.svg";
import { ServiceFactory } from "../../../factories/serviceFactory";
import { ISyncStatus } from "../../../models/websocket/ISyncStatus";
import { WebSocketTopic } from "../../../models/websocket/webSocketTopic";
import { MetricsService } from "../../../services/metricsService";
import { SettingsService } from "../../../services/settingsService";
Expand All @@ -33,6 +34,11 @@ class PeersSummaryPanel extends Component<unknown, PeersSummaryState> {
*/
private _peerSubscription?: string;

/**
* The sync status subscription id.
*/
private _syncStatusSubscription?: string;

/**
* Create a new instance of PeersSummaryPanel.
* @param props The props.
Expand All @@ -57,6 +63,23 @@ class PeersSummaryPanel extends Component<unknown, PeersSummaryState> {
data => {
this.handleData(data);
});

this._syncStatusSubscription = this._metricsService.subscribe<ISyncStatus>(
WebSocketTopic.SyncStatus,
data => {
if (data) {
const cmi = data.cmi;
const lmi = data.lmi;

if (cmi && cmi !== this.state.cmi) {
this.setState({ cmi });
}

if (lmi && lmi !== this.state.lmi) {
this.setState({ lmi });
}
}
});
}

/**
Expand All @@ -67,6 +90,11 @@ class PeersSummaryPanel extends Component<unknown, PeersSummaryState> {
this._metricsService.unsubscribe(this._peerSubscription);
this._peerSubscription = undefined;
}

if (this._syncStatusSubscription) {
this._metricsService.unsubscribe(this._syncStatusSubscription);
this._syncStatusSubscription = undefined;
}
}

/**
Expand Down Expand Up @@ -125,12 +153,17 @@ class PeersSummaryPanel extends Component<unknown, PeersSummaryState> {
let sortedPeers;

if (data) {
sortedPeers = DataHelper.sortPeers(data.map(p => ({
id: p.id,
alias: p.alias,
health: DataHelper.calculateHealth(p),
address: DataHelper.formatPeerAddress(p)
})));
sortedPeers = DataHelper.sortPeers(data.map(p => {
const cmi = this.state.cmi ? this.state.cmi : 0;
const lmi = this.state.lmi ? this.state.lmi : 0;

return {
id: p.id,
alias: p.alias,
health: DataHelper.calculateHealth(p, cmi, lmi),
address: DataHelper.formatPeerAddress(p)
};
}));
}

this.setState({
Expand Down
10 changes: 10 additions & 0 deletions src/app/components/tangle/PeersSummaryState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,14 @@ export interface PeersSummaryState {
* Hide any secure details.
*/
blindMode: boolean;

/**
* Confirmed milestone index.
*/
cmi?: number;

/**
* Latest milestone index.
*/
lmi?: number;
}
39 changes: 38 additions & 1 deletion src/app/routes/Peer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ReactComponent as EyeIcon } from "../../assets/eye.svg";
import { ReactComponent as MilestoneIcon } from "../../assets/milestone.svg";
import { ReactComponent as PruningIcon } from "../../assets/pruning.svg";
import { ServiceFactory } from "../../factories/serviceFactory";
import { ISyncStatus } from "../../models/websocket/ISyncStatus";
import { WebSocketTopic } from "../../models/websocket/webSocketTopic";
import { MetricsService } from "../../services/metricsService";
import { SettingsService } from "../../services/settingsService";
Expand Down Expand Up @@ -39,6 +40,11 @@ class Peer extends AsyncComponent<RouteComponentProps<PeerRouteProps>, PeerState
*/
private _peersSubscription?: string;

/**
* The sync status subscription id.
*/
private _syncStatusSubscription?: string;

/**
* Create a new instance of Peers.
* @param props The props.
Expand Down Expand Up @@ -97,12 +103,13 @@ class Peer extends AsyncComponent<RouteComponentProps<PeerRouteProps>, PeerState
for (const allDataPeers of allData) {
if (allDataPeers) {
const peer = allDataPeers.find(p => p.id === this.props.match.params.id);
const lmi = this.state.nodeLmi ? this.state.nodeLmi : 0;

if (peer) {
alias = peer.alias;
address = DataHelper.formatPeerAddress(peer) ?? "";
isConnected = peer.connected;
isSynced = isConnected && DataHelper.calculateIsSynced(peer);
isSynced = isConnected && DataHelper.calculateIsSynced(peer, lmi);
gossipMetrics = peer.gossip?.metrics;
relation = peer.relation;

Expand Down Expand Up @@ -157,6 +164,24 @@ class Peer extends AsyncComponent<RouteComponentProps<PeerRouteProps>, PeerState
});
}
);

this._syncStatusSubscription = this._metricsService.subscribe<ISyncStatus>(
WebSocketTopic.SyncStatus,
data => {
if (data) {
const cmi = data.cmi;
const lmi = data.lmi;

if (cmi && cmi !== this.state.nodeCmi) {
this.setState({ nodeCmi: cmi });
}

if (lmi && lmi !== this.state.nodeLmi) {
this.setState({ nodeLmi: lmi });
}
}
}
);
}

/**
Expand All @@ -169,6 +194,11 @@ class Peer extends AsyncComponent<RouteComponentProps<PeerRouteProps>, PeerState
this._metricsService.unsubscribe(this._peersSubscription);
this._peersSubscription = undefined;
}

if (this._syncStatusSubscription) {
this._metricsService.unsubscribe(this._syncStatusSubscription);
this._syncStatusSubscription = undefined;
}
}

/**
Expand Down Expand Up @@ -222,6 +252,13 @@ class Peer extends AsyncComponent<RouteComponentProps<PeerRouteProps>, PeerState
Relation:&nbsp;
{`${this.state.relation.slice(0, 1).toUpperCase()}${this.state.relation.slice(1)}`}
</p>
{this.state.nodeCmi &&
Number(this.state.pruningIndex) > this.state.nodeCmi && (
<p className="secondary warning margin-t-t">
Warning:&nbsp; History of peer not sufficient to sync from.
Consider using a newer snapshot if all peers have the same status.
</p>
)}
</div>
<div className="health-indicators col tablet-down-only-row phone-down-column">
<HealthIndicator
Expand Down
10 changes: 10 additions & 0 deletions src/app/routes/PeerState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,14 @@ export interface PeerState {
* Hide any secure details.
*/
blindMode: boolean;

/**
* Confirmed milestone index of the node.
*/
nodeCmi?: number;

/**
* Latest milestone index of the node.
*/
nodeLmi?: number;
}
32 changes: 31 additions & 1 deletion src/app/routes/Peers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ReactComponent as HealthBadIcon } from "../../assets/health-bad.svg";
import { ReactComponent as HealthGoodIcon } from "../../assets/health-good.svg";
import { ReactComponent as HealthWarningIcon } from "../../assets/health-warning.svg";
import { ServiceFactory } from "../../factories/serviceFactory";
import { ISyncStatus } from "../../models/websocket/ISyncStatus";
import { WebSocketTopic } from "../../models/websocket/webSocketTopic";
import { MetricsService } from "../../services/metricsService";
import { SettingsService } from "../../services/settingsService";
Expand Down Expand Up @@ -40,6 +41,11 @@ class Peers extends AsyncComponent<RouteComponentProps, PeersState> {
*/
private _peersSubscription?: string;

/**
* The sync status subscription id.
*/
private _syncStatusSubscription?: string;

/**
* Create a new instance of Peers.
* @param props The props.
Expand Down Expand Up @@ -93,7 +99,9 @@ class Peers extends AsyncComponent<RouteComponentProps, PeersState> {
for (const peer of allDataPeers) {
if (finalPeerIds.has(peer.id)) {
const address = DataHelper.formatPeerAddress(peer);
const health = DataHelper.calculateHealth(peer);
const cmi = this.state.cmi ? this.state.cmi : 0;
const lmi = this.state.lmi ? this.state.lmi : 0;
const health = DataHelper.calculateHealth(peer, cmi, lmi);

if (!peers[peer.id]) {
peers[peer.id] = {
Expand Down Expand Up @@ -152,6 +160,23 @@ class Peers extends AsyncComponent<RouteComponentProps, PeersState> {
});
}
);

this._syncStatusSubscription = this._metricsService.subscribe<ISyncStatus>(
WebSocketTopic.SyncStatus,
data => {
if (data) {
const cmi = data.cmi;
const lmi = data.lmi;

if (cmi && cmi !== this.state.cmi) {
this.setState({ cmi });
}

if (lmi && lmi !== this.state.lmi) {
this.setState({ lmi });
}
}
});
}

/**
Expand All @@ -164,6 +189,11 @@ class Peers extends AsyncComponent<RouteComponentProps, PeersState> {
this._metricsService.unsubscribe(this._peersSubscription);
this._peersSubscription = undefined;
}

if (this._syncStatusSubscription) {
this._metricsService.unsubscribe(this._syncStatusSubscription);
this._syncStatusSubscription = undefined;
}
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/app/routes/PeersState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,14 @@ export interface PeersState {
* Hide any secure details.
*/
blindMode: boolean;

/**
* Confirmed milestone index.
*/
cmi?: number;

/**
* Latest milestone index.
*/
lmi?: number;
}
21 changes: 15 additions & 6 deletions src/utils/dataHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,17 @@ export class DataHelper {
/**
* Calculate the health of the peer.
* @param peer The peer to calculate the health of.
* @param confirmedMilestoneIndex Confirmed milestone index of the node.
* @param latestMilestoneIndex Latest milestone index of the node.
* @returns The health.
*/
public static calculateHealth(peer: IPeer): number {
public static calculateHealth(peer: IPeer, confirmedMilestoneIndex: number, latestMilestoneIndex: number): number {
let health = 0;

if (peer.connected) {
health = DataHelper.calculateIsSynced(peer) ? 2 : 1;
health = (DataHelper.calculateIsSynced(peer, latestMilestoneIndex) &&
peer.gossip?.heartbeat &&
peer.gossip?.heartbeat?.prunedMilestoneIndex < confirmedMilestoneIndex) ? 2 : 1;
}

return health;
Expand All @@ -126,14 +130,19 @@ export class DataHelper {
/**
* Calculate the sync status of the peer.
* @param peer The peer to calculate the sync status of.
* @param latestMilestoneIndex Latest milestone index of the node.
* @returns The sync status.
*/
public static calculateIsSynced(peer: IPeer): boolean {
public static calculateIsSynced(peer: IPeer, latestMilestoneIndex: number): boolean {
let isSynced = false;

if (peer.gossip?.heartbeat &&
peer.gossip.heartbeat.solidMilestoneIndex >= (peer.gossip.heartbeat.latestMilestoneIndex - 2)) {
isSynced = true;
if (peer.gossip?.heartbeat) {
const latestKnownMilestoneIndex = (latestMilestoneIndex < peer.gossip.heartbeat.latestMilestoneIndex)
? peer.gossip.heartbeat.latestMilestoneIndex : latestMilestoneIndex;

if (peer.gossip.heartbeat.solidMilestoneIndex >= (latestKnownMilestoneIndex - 2)) {
isSynced = true;
}
}

return isSynced;
Expand Down

0 comments on commit 3fb5e59

Please sign in to comment.