mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-04-30 10:48:01 +00:00
Add finalized block info (#104)
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
import { Types } from '@dotstats/common';
|
||||
|
||||
export default class Block {
|
||||
public static readonly ZERO = new Block(0 as Types.BlockNumber, '' as Types.BlockHash);
|
||||
|
||||
public readonly number: Types.BlockNumber;
|
||||
public readonly hash: Types.BlockHash;
|
||||
|
||||
constructor(number: Types.BlockNumber, hash: Types.BlockHash) {
|
||||
this.number = number;
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
gt(other: Block): boolean {
|
||||
return this.number > other.number;
|
||||
}
|
||||
|
||||
eq(other: Block): boolean {
|
||||
return this.number === other.number && this.hash === other.hash;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import * as EventEmitter from 'events';
|
||||
import Node from './Node';
|
||||
import Feed from './Feed';
|
||||
import FeedSet from './FeedSet';
|
||||
import Block from './Block';
|
||||
import { Maybe, Types, FeedMessage, NumStats } from '@dotstats/common';
|
||||
|
||||
const BLOCK_TIME_HISTORY = 10;
|
||||
@@ -14,6 +15,7 @@ export default class Chain {
|
||||
public readonly label: Types.ChainLabel;
|
||||
|
||||
public height = 0 as Types.BlockNumber;
|
||||
public finalized = Block.ZERO;
|
||||
public blockTimestamp = 0 as Types.Timestamp;
|
||||
|
||||
private blockTimes = new NumStats<Types.Milliseconds>(BLOCK_TIME_HISTORY);
|
||||
@@ -43,11 +45,13 @@ export default class Chain {
|
||||
});
|
||||
|
||||
node.events.on('block', () => this.updateBlock(node));
|
||||
node.events.on('finalized', () => this.updateFinalized(node));
|
||||
node.events.on('stats', () => this.feeds.broadcast(Feed.stats(node)));
|
||||
node.events.on('hardware', () => this.feeds.broadcast(Feed.hardware(node)));
|
||||
node.events.on('location', (location) => this.feeds.broadcast(Feed.locatedNode(node, location)));
|
||||
|
||||
this.updateBlock(node);
|
||||
this.updateFinalized(node);
|
||||
}
|
||||
|
||||
public addFeed(feed: Feed) {
|
||||
@@ -58,9 +62,11 @@ export default class Chain {
|
||||
|
||||
feed.sendMessage(Feed.timeSync());
|
||||
feed.sendMessage(Feed.bestBlock(this.height, this.blockTimestamp, this.averageBlockTime));
|
||||
feed.sendMessage(Feed.bestFinalizedBlock(this.finalized));
|
||||
|
||||
for (const node of this.nodes.values()) {
|
||||
feed.sendMessage(Feed.addedNode(node));
|
||||
feed.sendMessage(Feed.finalized(node));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,9 +87,11 @@ export default class Chain {
|
||||
}
|
||||
|
||||
private updateBlock(node: Node) {
|
||||
if (node.height > this.height) {
|
||||
const height = node.best.number;
|
||||
|
||||
if (height > this.height) {
|
||||
// New best block
|
||||
const { height, blockTimestamp } = node;
|
||||
const { blockTimestamp } = node;
|
||||
|
||||
if (this.blockTimestamp) {
|
||||
this.updateAverageBlockTime(height, blockTimestamp);
|
||||
@@ -100,14 +108,24 @@ export default class Chain {
|
||||
this.feeds.broadcast(Feed.bestBlock(this.height, this.blockTimestamp, this.averageBlockTime));
|
||||
|
||||
console.log(`[${this.label}] New block ${this.height}`);
|
||||
} else if (node.height === this.height) {
|
||||
} else if (height === this.height) {
|
||||
// Caught up to best block
|
||||
node.propagationTime = (node.blockTimestamp - this.blockTimestamp) as Types.PropagationTime;
|
||||
}
|
||||
|
||||
this.feeds.broadcast(Feed.imported(node));
|
||||
|
||||
console.log(`[${this.label}] ${node.name} imported ${node.height}, block time: ${node.blockTime / 1000}s, average: ${node.average / 1000}s | latency ${node.latency}`);
|
||||
console.log(`[${this.label}] ${node.name} imported ${height}, block time: ${node.blockTime / 1000}s, average: ${node.average / 1000}s | latency ${node.latency}`);
|
||||
}
|
||||
|
||||
private updateFinalized(node: Node) {
|
||||
if (node.finalized.gt(this.finalized)) {
|
||||
this.finalized = node.finalized;
|
||||
|
||||
this.feeds.broadcast(Feed.bestFinalizedBlock(this.finalized));
|
||||
}
|
||||
|
||||
this.feeds.broadcast(Feed.finalized(node));
|
||||
}
|
||||
|
||||
private updateAverageBlockTime(height: Types.BlockNumber, now: Types.Timestamp) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as WebSocket from 'ws';
|
||||
import * as EventEmitter from 'events';
|
||||
import Node from './Node';
|
||||
import Chain from './Chain';
|
||||
import Block from './Block';
|
||||
import { VERSION, timestamp, Maybe, FeedMessage, Types, idGenerator } from '@dotstats/common';
|
||||
import { Location } from './location';
|
||||
|
||||
@@ -42,6 +43,13 @@ export default class Feed {
|
||||
};
|
||||
}
|
||||
|
||||
public static bestFinalizedBlock(block: Block): FeedMessage.Message {
|
||||
return {
|
||||
action: Actions.BestFinalized,
|
||||
payload: [block.number, block.hash]
|
||||
};
|
||||
}
|
||||
|
||||
public static addedNode(node: Node): FeedMessage.Message {
|
||||
return {
|
||||
action: Actions.AddedNode,
|
||||
@@ -70,6 +78,13 @@ export default class Feed {
|
||||
};
|
||||
}
|
||||
|
||||
public static finalized(node: Node): FeedMessage.Message {
|
||||
return {
|
||||
action: Actions.FinalizedBlock,
|
||||
payload: [node.id, node.finalized.number, node.finalized.hash]
|
||||
};
|
||||
}
|
||||
|
||||
public static stats(node: Node): FeedMessage.Message {
|
||||
return {
|
||||
action: Actions.NodeStats,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Maybe, Types, timestamp } from '@dotstats/common';
|
||||
|
||||
export class MeanList<T extends number> {
|
||||
export default class MeanList<T extends number> {
|
||||
private periodCount = 0;
|
||||
private periodSum = 0;
|
||||
private meanIndex = 0;
|
||||
|
||||
@@ -4,7 +4,8 @@ import * as EventEmitter from 'events';
|
||||
import { noop, timestamp, idGenerator, Maybe, Types, NumStats } from '@dotstats/common';
|
||||
import { parseMessage, getBestBlock, Message, BestBlock, SystemInterval } from './message';
|
||||
import { locate, Location } from './location';
|
||||
import { MeanList } from './MeanList';
|
||||
import MeanList from './MeanList';
|
||||
import Block from './Block';
|
||||
|
||||
const BLOCK_TIME_HISTORY = 10;
|
||||
const MEMORY_RECORDS = 20;
|
||||
@@ -32,8 +33,8 @@ export default class Node {
|
||||
public location: Maybe<Location> = null;
|
||||
public lastMessage: Types.Timestamp;
|
||||
public config: string;
|
||||
public best = '' as Types.BlockHash;
|
||||
public height = 0 as Types.BlockNumber;
|
||||
public best = Block.ZERO;
|
||||
public finalized = Block.ZERO;
|
||||
public latency = 0 as Types.Milliseconds;
|
||||
public blockTime = 0 as Types.Milliseconds;
|
||||
public blockTimestamp = 0 as Types.Timestamp;
|
||||
@@ -190,7 +191,7 @@ export default class Node {
|
||||
}
|
||||
|
||||
public blockDetails(): Types.BlockDetails {
|
||||
return [this.height, this.best, this.blockTime, this.blockTimestamp, this.propagationTime];
|
||||
return [this.best.number, this.best.hash, this.blockTime, this.blockTimestamp, this.propagationTime];
|
||||
}
|
||||
|
||||
public nodeLocation(): Maybe<Types.NodeLocation> {
|
||||
@@ -234,7 +235,16 @@ export default class Node {
|
||||
}
|
||||
|
||||
private onSystemInterval(message: SystemInterval) {
|
||||
const { peers, txcount, cpu, memory, bandwidth_download: download, bandwidth_upload: upload } = message;
|
||||
const {
|
||||
peers,
|
||||
txcount,
|
||||
cpu,
|
||||
memory,
|
||||
bandwidth_download: download,
|
||||
bandwidth_upload: upload,
|
||||
finalized_height: finalized,
|
||||
finalized_hash: finalizedHash
|
||||
} = message;
|
||||
|
||||
if (this.peers !== peers || this.txcount !== txcount) {
|
||||
this.peers = peers;
|
||||
@@ -243,6 +253,12 @@ export default class Node {
|
||||
this.events.emit('stats');
|
||||
}
|
||||
|
||||
if (finalized != null && finalizedHash != null && finalized > this.finalized.number) {
|
||||
this.finalized = new Block(finalized, finalizedHash);
|
||||
|
||||
this.events.emit('finalized');
|
||||
}
|
||||
|
||||
if (cpu != null && memory != null) {
|
||||
const cpuChange = this.cpu.push(cpu);
|
||||
const memChange = this.memory.push(memory);
|
||||
@@ -279,11 +295,10 @@ export default class Node {
|
||||
private updateBestBlock(update: BestBlock) {
|
||||
const { height, ts: time, best } = update;
|
||||
|
||||
if (this.best !== best && this.height <= height) {
|
||||
if (this.best.hash !== best && this.best.number <= height) {
|
||||
const blockTime = this.getBlockTime(time);
|
||||
|
||||
this.best = best;
|
||||
this.height = height;
|
||||
this.best = new Block(height, best);
|
||||
this.blockTimestamp = timestamp();
|
||||
this.lastBlockAt = time;
|
||||
this.blockTimes.push(blockTime);
|
||||
|
||||
@@ -59,6 +59,8 @@ export interface SystemInterval extends BestBlock {
|
||||
status: 'Idle' | string; // TODO: 'Idle' | ...?
|
||||
bandwidth_upload: Maybe<Types.BytesPerSecond>;
|
||||
bandwidth_download: Maybe<Types.BytesPerSecond>;
|
||||
finalized_height: Maybe<Types.BlockNumber>;
|
||||
finalized_hash: Maybe<Types.BlockHash>;
|
||||
}
|
||||
|
||||
export interface NodeStart extends BestBlock {
|
||||
|
||||
Reference in New Issue
Block a user