Skip to content
This repository has been archived by the owner on Jun 7, 2019. It is now read-only.

Implement P2P.getNetworkStatus() functionality - Closes #985 and #897, addresses #896 and #953 #986

Merged
merged 17 commits into from
Jan 14, 2019

Conversation

jondubois
Copy link

What was the problem?

In order to implement the integration tests, there needs to be a way to get information about the network's state from the P2P library. This feature depends on the P2P.getNetworkStatus() method of the P2P library which itself depends on the peer request/send functionality (to allow peers to send us information about themselves).

How did I fix it?

  • Implemented outbound request/send functionality (at the Peer level only)
  • Implemented inbound request/message handling (at the Peer level only)
  • Implemented sending of P2PNodeInfo to remote peers.
  • Implemented receiving PeerInfo from remote peers.
  • Implemented getNetworkStatus() method on P2P class.

How to test it?

Will add integration tests for all these features as part of #953 then, once passing, the logic can be locked down with unit tests.

Review checklist

@shuse2 shuse2 added this to Open PRs in Version 2.1.0 via automation Jan 9, 2019
packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
packages/lisk-p2p/src/peer.ts Show resolved Hide resolved
packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
@@ -44,28 +44,45 @@ export interface P2PConfig {
readonly connectTimeout: number;
readonly ipAddress?: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why ipAddress is optional here?

Copy link
Author

Choose a reason for hiding this comment

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

This is the ipAddress of the node itself.
It's this property from the current config.json: https://github.com/LiskHQ/lisk/blob/development/config/default/config.json#L4 - Default is 0.0.0.0. We can rename this if it's confusing.

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe we can rename it to nodeIp to have a clear differentiation from the peer IP address. What do you think?

}

export interface NetworkStatus {}
// Network info exposed by the P2P library.
export interface P2PNetworkStatus {
Copy link
Contributor

Choose a reason for hiding this comment

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

since we have a concept of newPeers and triedPeers, maybe for clarity we should rename newPeers as availablePeers or unConnectedPeers at the network level.

Also, triedPeers can contain peers that are connected or disconnected. So it should also be checked as well for peers that are not connected

export interface P2PNetworkStatus {
    connectedPeers: ReadonlyArray<PeerInfo>; //  peers from peer pool
    unConnectedPeers: ReadonlyArray<PeerInfo>; // or availablePeers, peers from newPeers + triedPeers (check with peerPool)
}

Copy link
Author

@jondubois jondubois Jan 11, 2019

Choose a reason for hiding this comment

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

unConnectedPeers is slightly different because some peers in the _newPeers map could be connected inbound only; maybe it's OK but slightly more ambiguous.

I think newPeers is OK. Once we start moving peers into the _triedPeers table, it will make more sense. So there will be newPeers, triedPeers and connectedPeers activePeers. I think we should use the same name to refer to the same thing.

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually, according to the definition in LIPS, the moment you make a connection with any peer from newPeer we remove it from there and add it to triedPeer. So, newPeer should never have any peer for which we made connection already. Whereas triedPeers will have peers with whom we have a connection or had a connection in the past.

so, active peers should have, triedPeers peers which have a connection already and available peers will be the combination of (newPeers + triedPeers(with no socket))

Copy link
Author

Choose a reason for hiding this comment

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

We could have availablePeers be newPeers + triedPeers and connectedPeers be peers from the PeerPool?

Copy link
Contributor

Choose a reason for hiding this comment

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

availablePeers be newPeers + triedPeers and connectedPeers be peers from the PeerPool

I think this is good, im not sure if we need to expose newPeers or triedPeers

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't availablePeers and connectedPeers is enough? I thought we don't want to expose newPeers and triedPeers

readonly os: string;
readonly version: string;
readonly os?: string;
readonly version?: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought we were making version compulsory. If we don't passversion value then at sanitization it will always throw an error

Copy link
Author

@jondubois jondubois Jan 11, 2019

Choose a reason for hiding this comment

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

That's a tricky one.

The reason why version is optional is because the list of seedPeers which is fetched from the config file has this format:

readonly seedPeers: ReadonlyArray<PeerInfo>;

We cannot know what the version number of the seed peer is before we connect to it.
I think it's OK to expect the version in the sanitization logic when checking inbound PeerInfo from a remote peer, but it shouldn't be compulsory (based on our current types) at the type level because the PeerInfo object may be created directly in our own code or from a config file before we know anything about the peer (also would be tricky to know their OS before we connect to them).

Not sure if it's better to add yet another Peer... type? It's convenient that PeerInfo can be used for both getting information about peers and also for creating peers.

Copy link
Contributor

Choose a reason for hiding this comment

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

one idea to have BasePeerInfo which is extended to SeedPeerIndo and PeerInfo where the difference is version?

Copy link
Author

Choose a reason for hiding this comment

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

@shuse2 Sounds good but I think that SeedPeerInfo might end up having the same properties as BasePeerInfo so maybe just BasePeerInfo and PeerInfo?

Or it could be PeerInfo (for constructing) and DetailedPeerInfo (when getting information out of the node with getNetworkStatus())?

Copy link
Contributor

Choose a reason for hiding this comment

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

BasePeerInfo and PeerInfo

sounds good =)

return this._id;
private _handlePeerInfo(request: ProtocolInboundRPCRequest): void {
// Update peerInfo with the latest values from the remote peer.
Object.assign(this._peerInfo, request.data as PeerInfo);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we are missing sanitization of the peer object from the response. we can wrap request.data with instantiatePeerFromResponse()

Copy link
Contributor

Choose a reason for hiding this comment

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

validation needs to be added later here too

packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
return this._ipAddress;
}

public set outboundSocket(value: any) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this was not rebased properly, instead of any it should be SCServerSocket

return this._id;
}

public set inboundSocket(value: any) {
Copy link
Contributor

Choose a reason for hiding this comment

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

it should be SCServerSocket instead of any

public get nodeInfo(): P2PNodeInfo | undefined {
return this._nodeInfo;
}

public connect(): void {
if (!this.outboundSocket) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It should be this._outboundSocket

public connect(): void {
if (!this.outboundSocket) {
this.outboundSocket = this._createOutboundSocket();
}

this.outboundSocket.connect();
Copy link
Contributor

Choose a reason for hiding this comment

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

this._outboundSocket

this.inboundSocket.disconnect(code, reason);
if (this._inboundSocket) {
this._inboundSocket.disconnect(code, reason);
this._stopListeningForRPCs(this._inboundSocket);
}
if (this.outboundSocket) {
Copy link
Contributor

Choose a reason for hiding this comment

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

this._outboundSocket

Copy link
Contributor

@shuse2 shuse2 left a comment

Choose a reason for hiding this comment

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

minor thing and some question/comment

packages/lisk-p2p/src/p2p_types.ts Outdated Show resolved Hide resolved
readonly os: string;
readonly version: string;
readonly os?: string;
readonly version?: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

one idea to have BasePeerInfo which is extended to SeedPeerIndo and PeerInfo where the difference is version?

packages/lisk-p2p/src/peer.ts Outdated Show resolved Hide resolved
return this._id;
private _handlePeerInfo(request: ProtocolInboundRPCRequest): void {
// Update peerInfo with the latest values from the remote peer.
Object.assign(this._peerInfo, request.data as PeerInfo);
Copy link
Contributor

Choose a reason for hiding this comment

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

validation needs to be added later here too

packages/lisk-p2p/test/integration/p2p.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@ishantiw ishantiw left a comment

Choose a reason for hiding this comment

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

Some comments related to getNetworkStatus()

}

export interface NetworkStatus {}
// Network info exposed by the P2P library.
export interface P2PNetworkStatus {
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't availablePeers and connectedPeers is enough? I thought we don't want to expose newPeers and triedPeers

public getNetworkStatus(): P2PNetworkStatus {
const newPeers = [...this._newPeers.values()];
const triedPeers = [...this._triedPeers.values()];
const availablePeers = newPeers.concat(triedPeers);
Copy link
Contributor

Choose a reason for hiding this comment

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

is availablePeers are all the peers that are available but don't have any connection yet? or, does it include all the peers available or known including the connected peers? If its the former case then I think we need to filter newPeers and triedPeers to remove peers that we are already connected to and then concat.

Copy link
Author

@jondubois jondubois Jan 14, 2019

Choose a reason for hiding this comment

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

Since the getNetworkStatus call will be used by integration tests (not just API module), it's important that it shows the internal state of the node as closely as possible.

I think it's more important that this interface be detailed rather than user-friendly. Users of the method can do their own sanitisation of the raw data.

Integration test cases will want to check the state of the _newPeers and _triedPeers maps explicitly (since it's a core concept in the LIPs), so we need the name of the exposed properties to reflect the name of internal properties for which we want to allow introspection. We could call it newPeersList instead of newPeers maybe?

The less sanitisation/formatting we do on our end, the more performant this call will be.

Copy link
Author

Choose a reason for hiding this comment

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

@shuse2 What is your opinion about this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think without availablePeers is fine.
availablePeers seems ambiguous in this case because it will include all the peers regardless of connection since triedPeer will include the peer with outbound connection.
Also, not really useful if it's just combination of newPeers and triedPeers, user can just combine by themselves?

Copy link
Contributor

@ishantiw ishantiw Jan 14, 2019

Choose a reason for hiding this comment

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

In case we want to have a concatenated list of newPeers and triedPeers and if we are exposing them then we don't need availablePeers list as its redundant or the user can make it out by themselves. I was thinking that network status is just about knowing (connected and unconnected Peers) but since newPeers and triedPeers will be used in the network test then its a better to add it.

I guess in future we will need a separate class for handling peer bucket or peer directory (like I discussed once) that includes newPeer/triedPeer/bannedPeer and then it will be easier to test these lists.

@shuse2 shuse2 merged commit c9164dc into add_p2p_experiment Jan 14, 2019
Version 2.1.0 automation moved this from Open PRs to Closed PRs Jan 14, 2019
@shuse2 shuse2 deleted the p2p_jon branch January 14, 2019 16:46
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
Version 2.1.0
  
Closed PRs
Development

Successfully merging this pull request may close these issues.

None yet

3 participants