Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
1bb41eb
Make it clear that settings apply only to list view
cmichi Mar 19, 2019
138b4af
Add Jdenticon
cmichi Mar 21, 2019
8c26dc8
Add Grandpa consensus visualisation
cmichi Apr 3, 2019
3c830af
Remove fade-in animation
cmichi Apr 4, 2019
c570cbc
Update packages and yarn.lock
cmichi Apr 4, 2019
e4de35c
Broadcast only delta of what changed
cmichi Apr 6, 2019
1e824c7
Minor code improvements
cmichi Apr 7, 2019
a7ba531
Use NodeId instead of Address in first dimension
cmichi Apr 8, 2019
672a33f
Refactoring and improving naming
cmichi Apr 8, 2019
e4b4916
Display boxes only after size has been detected
cmichi Apr 8, 2019
b2253e0
Fix cache
cmichi Apr 8, 2019
a3e9f06
Send consensus info on first subscribe
cmichi Apr 8, 2019
4b5505b
Increase cache size
cmichi Apr 8, 2019
5c48daa
Send deltas only if block in cache
cmichi Apr 8, 2019
0623e5b
Adjust cache size
cmichi Apr 8, 2019
064506a
Make cache sizes dependent
cmichi Apr 8, 2019
bde604a
Ensure authority caches are aligned
cmichi Apr 8, 2019
5b590ba
Extract function
cmichi Apr 10, 2019
062866a
Handle restarts on authority set changes properly
cmichi Apr 10, 2019
a569f54
Fix backfill mechanism
cmichi Apr 10, 2019
003aace
Display only blocks since last authority set change
cmichi Apr 10, 2019
b3d3507
Handle authority set sent on connect
cmichi Apr 12, 2019
03b3ae4
Introduce Authority type
cmichi Apr 12, 2019
fdc86c5
Handle corner case
cmichi Apr 15, 2019
b8d689b
Display placeholder if name not yet available
cmichi Apr 15, 2019
0a0acce
Replace with camelCase
cmichi Apr 23, 2019
23c254e
Replace with correct types
cmichi May 6, 2019
44bf2a5
Replace grandpa icon
cmichi May 6, 2019
3a4ea63
Merge branch 'master' into cmichi-display-state-of-consensus
maciejhirsz May 6, 2019
3a6427a
Change consensus icon to cube (finalized block icon)
cmichi May 13, 2019
bf4d9ea
Upgrade dependencies
cmichi May 15, 2019
7040545
Implement thin backend instead of thick
cmichi May 15, 2019
ca5d29b
Cleanup and minor improvements
cmichi May 16, 2019
0bc61dc
Minor refactoring
cmichi May 16, 2019
019d1f5
Extract common code into function
cmichi May 16, 2019
ed429c6
Switch module to class
cmichi May 16, 2019
6fe140a
Remove unused code
cmichi May 16, 2019
4e73e8f
Clean markup
cmichi May 16, 2019
5e0dbdf
Remove unused code
cmichi May 16, 2019
174eba4
Revert "Upgrade dependencies"
cmichi May 19, 2019
0da0c44
Update polkadot-identicon in frontend
cmichi May 19, 2019
64d08c3
Run yarn install
cmichi May 19, 2019
acd1218
Update react-measure to 2.3.0
cmichi May 19, 2019
f198278
Improve typing by introducing partial type
cmichi May 19, 2019
5da7937
Reduce indexing operations
cmichi May 19, 2019
b02f72d
Shorten function
cmichi May 19, 2019
12fd5c9
Shorten function
cmichi May 19, 2019
770b10f
Introduce initialiseConsensusViewByRef
cmichi May 19, 2019
0bafe84
Remove dead conditional branch
cmichi May 19, 2019
bce0576
Return consensusView ref from initialiseConsensusView
cmichi May 19, 2019
44863a5
Handle consensusView ref returned from initialiseConsensusView
cmichi May 20, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/backend/src/Aggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ export default class Aggregator {
feed.sendMessage(Feed.unsubscribedFrom(label));
}
});

feed.events.on('subscribe-consensus-info', (label: Types.ChainLabel) => {
const chain = this.chains.get(label);

if (chain) {
feed.sendMessage(Feed.subscribedTo(label));
chain.addFeed(feed);
}
});

feed.events.on('unsubscribe-consensus-info', (label: Types.ChainLabel) => {
const chain = this.chains.get(label);

if (chain) {
chain.removeFeed(feed);
feed.sendMessage(Feed.unsubscribedFrom(label));
}
});
}

public getExistingChain(label: Types.ChainLabel) : Maybe<Chain> {
Expand Down
35 changes: 34 additions & 1 deletion packages/backend/src/Chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Node from './Node';
import Feed from './Feed';
import FeedSet from './FeedSet';
import Block from './Block';
import { Maybe, Types, FeedMessage, NumStats } from '@dotstats/common';
import { Maybe, Types, NumStats } from '@dotstats/common';

const BLOCK_TIME_HISTORY = 10;

Expand All @@ -21,6 +21,8 @@ export default class Chain {
private blockTimes = new NumStats<Types.Milliseconds>(BLOCK_TIME_HISTORY);
private averageBlockTime: Maybe<Types.Milliseconds> = null;

public lastBroadcastedAuthoritySetInfo: Maybe<Types.AuthoritySetInfo> = null;

constructor(label: Types.ChainLabel) {
this.label = label;
}
Expand All @@ -39,6 +41,33 @@ export default class Chain {

node.events.on('block', () => this.updateBlock(node));
node.events.on('finalized', () => this.updateFinalized(node));

node.events.on('afg-finalized', (finalizedNumber, finalizedHash) => this.feeds.each(
f => f.sendConsensusMessage(Feed.afgFinalized(node, finalizedNumber, finalizedHash))
));
node.events.on('afg-received-prevote', (finalizedNumber, finalizedHash, voter) => this.feeds.each(
f => f.sendConsensusMessage(Feed.afgReceivedPrevote(node, finalizedNumber, finalizedHash, voter))
));
node.events.on('afg-received-precommit', (finalizedNumber, finalizedHash, voter) => this.feeds.each(
f => f.sendConsensusMessage(Feed.afgReceivedPrecommit(node, finalizedNumber, finalizedHash, voter))
));
node.events.on('authority-set-changed', (authorities, authoritySetId, blockNumber, blockHash) => {
let newSet;
if (this.lastBroadcastedAuthoritySetInfo == null) {
newSet = true;
} else {
const [lastBroadcastedAuthoritySetId] = this.lastBroadcastedAuthoritySetInfo;
newSet = authoritySetId !== lastBroadcastedAuthoritySetId;
}

if (node.isAuthority() && newSet) {
const addr = node.address != null ? node.address : "" as Types.Address;
const set = [authoritySetId, authorities, addr, blockNumber, blockHash] as Types.AuthoritySetInfo;
this.feeds.broadcast(Feed.afgAuthoritySet(set));
this.lastBroadcastedAuthoritySetInfo = set;
}
});

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)));
Expand Down Expand Up @@ -70,6 +99,10 @@ export default class Chain {
feed.sendMessage(Feed.bestBlock(this.height, this.blockTimestamp, this.averageBlockTime));
feed.sendMessage(Feed.bestFinalizedBlock(this.finalized));

if (this.lastBroadcastedAuthoritySetInfo != null) {
feed.sendMessage(Feed.afgAuthoritySet(this.lastBroadcastedAuthoritySetInfo));
}

for (const node of this.nodes.values()) {
feed.sendMessage(Feed.addedNode(node));
feed.sendMessage(Feed.finalized(node));
Expand Down
60 changes: 60 additions & 0 deletions packages/backend/src/Feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default class Feed {
private socket: WebSocket;
private messages: Array<FeedMessage.Message> = [];
private waitingForPong = false;
private sendFinality = false;

constructor(socket: WebSocket) {
this.id = nextId();
Expand Down Expand Up @@ -92,6 +93,49 @@ export default class Feed {
};
}

public static afgFinalized(node: Node, finalizedNumber: Types.BlockNumber, finalizedHash: Types.BlockHash): FeedMessage.Message {
const addr = node.address != null ? node.address : "" as Types.Address;
return {
action: Actions.AfgFinalized,
payload: [addr, finalizedNumber, finalizedHash]
};
}

public static afgReceivedPrevote(
node: Node,
targetNumber: Types.BlockNumber,
targetHash: Types.BlockHash,
voter: Types.Address
): FeedMessage.Message {
const addr = node.address != null ? node.address : "" as Types.Address;
return {
action: Actions.AfgReceivedPrevote,
payload: [addr, targetNumber, targetHash, voter]
};
}

public static afgReceivedPrecommit(
node: Node,
targetNumber: Types.BlockNumber,
targetHash: Types.BlockHash,
voter: Types.Address
): FeedMessage.Message {
const addr = node.address != null ? node.address : "" as Types.Address;
return {
action: Actions.AfgReceivedPrecommit,
payload: [addr, targetNumber, targetHash, voter]
};
}

public static afgAuthoritySet(
authoritySetInfo: Types.AuthoritySetInfo,
): FeedMessage.Message {
return {
action: Actions.AfgAuthoritySet,
payload: authoritySetInfo,
};
}

public static hardware(node: Node): FeedMessage.Message {
return {
action: Actions.NodeHardware,
Expand Down Expand Up @@ -155,6 +199,14 @@ export default class Feed {
}
}

public sendConsensusMessage(message: FeedMessage.Message) {
if (!this.sendFinality) {
return;
}

this.sendMessage(message);
}

public ping() {
if (this.waitingForPong) {
this.disconnect();
Expand Down Expand Up @@ -188,6 +240,14 @@ export default class Feed {
this.events.emit('subscribe', payload as Types.ChainLabel);
break;

case 'send-finality':
this.sendFinality = true;
break;

case 'no-more-finality':
this.sendFinality = false;
break;

case 'ping':
this.sendMessage(Feed.pong(payload));
break;
Expand Down
83 changes: 81 additions & 2 deletions packages/backend/src/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ import * as WebSocket from 'ws';
import * as EventEmitter from 'events';

import { noop, timestamp, idGenerator, Maybe, Types, NumStats } from '@dotstats/common';
import { parseMessage, getBestBlock, Message, BestBlock, SystemInterval } from './message';
import { BlockHash, BlockNumber, ConsensusView } from "@dotstats/common/build/types";
import {
parseMessage,
getBestBlock,
Message,
BestBlock,
SystemInterval,
AfgFinalized,
AfgReceivedPrecommit,
AfgReceivedPrevote,
AfgAuthoritySet,
} from './message';
import { locate, Location } from './location';
import MeanList from './MeanList';
import Block from './Block';
Expand Down Expand Up @@ -57,6 +68,9 @@ export default class Node {
private pingStart = 0 as Types.Timestamp;
private throttle = false;

private authorities: Types.Authorities = [] as Types.Authorities;
private authoritySetId: Types.AuthoritySetId = 0 as Types.AuthoritySetId;

constructor(
ip: string,
socket: WebSocket,
Expand Down Expand Up @@ -182,8 +196,9 @@ export default class Node {

public nodeDetails(): Types.NodeDetails {
const authority = this.authority ? this.address : null;
const addr = this.address ? this.address : '' as Types.Address;

return [this.name, this.implementation, this.version, authority, this.networkId];
return [this.name, addr, this.implementation, this.version, authority, this.networkId];
}

public nodeStats(): Types.NodeStats {
Expand Down Expand Up @@ -236,6 +251,19 @@ export default class Node {
if (message.msg === 'system.interval') {
this.onSystemInterval(message);
}

if (message.msg === 'afg.finalized') {
this.onAfgFinalized(message);
}
if (message.msg === 'afg.received_precommit') {
this.onAfgReceivedPrecommit(message);
}
if (message.msg === 'afg.received_prevote') {
this.onAfgReceivedPrevote(message);
}
if (message.msg === 'afg.authority_set') {
this.onAfgAuthoritySet(message);
}
}

private onSystemInterval(message: SystemInterval) {
Expand Down Expand Up @@ -283,6 +311,57 @@ export default class Node {
}
}

public isAuthority(): boolean {
return this.authority;
}

private onAfgReceivedPrecommit(message: AfgReceivedPrecommit) {
const {
target_number: targetNumber,
target_hash: targetHash,
} = message;
const voter = this.extractVoter(message.voter);
this.events.emit('afg-received-precommit', targetNumber, targetHash, voter);
}

private onAfgReceivedPrevote(message: AfgReceivedPrevote) {
const {
target_number: targetNumber,
target_hash: targetHash,
} = message;
const voter = this.extractVoter(message.voter);
this.events.emit('afg-received-prevote', targetNumber, targetHash, voter);
}

private onAfgAuthoritySet(message: AfgAuthoritySet) {
const {
authority_set_id: authoritySetId,
hash,
number,
} = message;

// we manually parse the authorities message, because the array was formatted as a
// string by substrate before sending it.
const authorities = JSON.parse(String(message.authorities)) as Types.Authorities;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more FYI, but I think the telemetry allows nested JSON now without having to serialize things as strings.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand you right that we should be able to remove the serde serialization happening here?

(I had tried it naively without looking any further into it and ran into the trait 'slog::Value' is not implemented for 'std::vec::Vec<std::string::String>'.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think that was fixed recently.


if (JSON.stringify(this.authorities) !== String(message.authorities) ||
this.authoritySetId !== authoritySetId) {
this.events.emit('authority-set-changed', authorities, authoritySetId, number, hash);
}
}

private onAfgFinalized(message: AfgFinalized) {
const {
finalized_number: finalizedNumber,
finalized_hash: finalizedHash,
} = message;
this.events.emit('afg-finalized', finalizedNumber, finalizedHash);
}

private extractVoter(message_voter: String): Types.Address {
return String(message_voter.replace(/"/g, '')) as Types.Address;
}

private updateLatency(now: Types.Timestamp) {
// if (this.pingStart) {
// console.error(`${this.name} timed out on ping message.`);
Expand Down
40 changes: 40 additions & 0 deletions packages/backend/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,41 @@ export interface BestBlock {
ts: Date;
}

export interface AfgFinalized {
ts: Date;
finalized_number: Types.BlockNumber;
finalized_hash: Types.BlockHash;
msg: 'afg.finalized';
}

export interface AfgReceived {
ts: Date;
target_number: Maybe<Types.BlockNumber>;
target_hash: Maybe<Types.BlockHash>;
voter: Types.Address;
}

export interface AfgReceivedPrecommit extends AfgReceived {
msg: 'afg.received_precommit';
}

export interface AfgReceivedPrevote extends AfgReceived {
msg: 'afg.received_prevote';
}

export interface AfgReceivedCommit extends AfgReceived {
msg: 'afg.received_commit';
}

export interface AfgAuthoritySet {
msg: 'afg.authority_set';
ts: Date;
authorities: Types.Authorities;
authority_set_id: Types.AuthoritySetId;
number: Types.BlockNumber;
hash: Types.BlockHash;
}

export interface SystemConnected {
msg: 'system.connected';
name: Types.NodeName;
Expand Down Expand Up @@ -79,6 +114,11 @@ export type Message = MessageBase & (
| SystemInterval
| NodeStart
| BlockImport
| AfgFinalized
| AfgReceivedPrecommit
| AfgReceivedPrevote
| AfgReceivedCommit
| AfgAuthoritySet
);


Expand Down
Loading