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

[WIP] ETH2.0 Wire protocol #195

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
dba5484
Added messages in ETH2.0 wire protocol
Mikerah Apr 29, 2019
8565457
Added messages in ETH2.0 wire protocol
Mikerah Apr 29, 2019
f5a134b
Merge branch 'mikerah/eth2-wire-protocol' of github.com:ChainSafe/lod…
Mikerah Apr 29, 2019
2da7112
Added messages in ETH2.0 wire protocol
Mikerah Apr 29, 2019
d35dd1f
Merge branch 'mikerah/eth2-wire-protocol' of github.com:ChainSafe/lod…
Mikerah May 2, 2019
93be293
Merge branch 'master' of github.com:ChainSafe/lodestar into mikerah/e…
Mikerah May 2, 2019
88d333d
Merge branch 'master' of github.com:ChainSafe/lodestar into mikerah/e…
Mikerah May 5, 2019
8698363
Completed 2-way handshake
Mikerah May 6, 2019
560d066
Refactored wire protocol api into rpc module
Mikerah May 7, 2019
5abed10
Completed RPC methods interface for wire protocol
Mikerah May 7, 2019
07ea887
Stubbed out wire.ts
Mikerah May 7, 2019
bd6752c
Forgot to change import statement to reflect refactor in p2p/index.ts
Mikerah May 7, 2019
e25b033
Added some of Marin's and Greg's suggestions
Mikerah May 8, 2019
72e2c06
Fixed lint errors in p2p/index.ts and made changes to the constructor…
Mikerah May 8, 2019
ddf1719
Changed message properties to camelcase and added aliased types. Stil…
Mikerah May 8, 2019
0ac4eba
Added protobuf file for wire protocol
Mikerah May 8, 2019
712a039
Started refactoring to enable RPC over Libp2p
Mikerah May 10, 2019
caf7a63
Added packet protobuf
Mikerah May 20, 2019
aec549d
Refactoring p2p code to make it easier to do RPC over libp2p
Mikerah May 21, 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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"pouchdb-adapter-memory": "^7.0.0",
"pouchdb-core": "^7.0.0",
"promisify-es6": "^1.0.3",
"pull-stream": "^3.6.10",
"winston": "^3.2.1",
"ws": "^6.2.1"
},
Expand Down
2 changes: 1 addition & 1 deletion src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class BeaconNode {
);

this.db = new LevelDB(this.conf.db);
this.network = new P2PNetwork(this.conf.network);
this.network = new P2PNetwork(this.conf.network, {chain, db});
this.eth1 = new EthersEth1Notifier(
this.conf.eth1,
{
Expand Down
85 changes: 43 additions & 42 deletions src/p2p/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import {LodestarNode} from "./node";
import logger, {AbstractLogger} from "../logger";
import {PeerInfo} from "peer-info";
import LibP2p from "libp2p";
import {pull} from "pull-stream";
import {PeerBook} from "peer-book";
import {PeerId} from "peer-id";
import {promisify} from "promisify-es6";
import {Hello, Goodbye} from "../rpc/api/wire/messages";
import {DB} from "../db";
import {BeaconChain} from "../chain";

export interface P2pOptions {
maxPeers: number;
Expand Down Expand Up @@ -41,15 +45,21 @@ export class P2PNetwork extends EventEmitter implements Service {

private log: AbstractLogger;

public constructor(opts: P2pOptions) {
private chain: BeaconChain;

private db: DB;

public constructor(opts: P2pOptions, {chain, db}) {
super();
this.options = opts;
this.maxPeers = this.options.maxPeers;
this.refreshInterval = this.options.refreshInterval;
this.peerBook = this.options.peerBook;
this.privateKey = this.options.privateKey;
this.bootnodes = this.options.bootnodes;
this.bootnodes = this.options.bootnodes || [];

this.chain = chain;
this.db = db;

this.started = false;
this.node = null;
Expand All @@ -71,43 +81,6 @@ export class P2PNetwork extends EventEmitter implements Service {
peerInfo: await this.createPeerInfo(),
bootnodes: this.options.bootnodes
});

this.node.on('peer:discovery', (peerInfo) => {
try {
const peerId = peerInfo.id.toB58String();
// Check if peer has already been discovered
if (this.options.peerBook.has(peerId) || this.discoveredPeers.has(peerId)) {
return;
}
this.peerBook.put(peerInfo);
this.node.dial(peerInfo, () => {});
this.log.info(`Peer discovered: ${peerInfo}`);
this.emit('connected', peerInfo);
} catch (err) {
this.log.error(err);
}

});

this.node.on('peer:connect', (peerInfo) => {
try {
this.log.info(`Peer connected: ${peerInfo}`);
this.peerBook.put(peerInfo);
this.discoveredPeers.add(peerInfo);
} catch (err) {
this.log.error(err);
}
});

this.node.on('peer:disconnect', (peerInfo) => {
try {
this.peerBook.remove(peerInfo);
this.discoveredPeers.delete(peerInfo);
} catch (err) {
this.log.error(err);
}
});
}
await promisify(this.node.start.bind(this.node))();

this.started = true;
Expand All @@ -125,8 +98,36 @@ export class P2PNetwork extends EventEmitter implements Service {
return new Promise((resolve, reject) => {
const handler = (err, peerInfo) => {
if (err) {
return reject(err);
}
return reject(err);
}

protobuf.load('./messages/wire.proto').then((root) => {
this.node.on('peer:connection', (conn, peer) => {
this.log.info('peer:connection');

// Temporary parameters until the rest is ready.
peer.rpc.Hello({
networkId: 0,
chainId: 0,
latestFinalizedRoot: 0x00,
latestFinalizedEpoch: 0,
bestRoot: 0x00,
bestSlot: 0,
},

(response, peer) => {
// Process response
});
});

// Simplify this.
this.node.handle('Hello', (networkId, chainId, latestFinalizedRoot, latestFinalizedEpoch, bestRoot, BestSlot, peer, response) => {
response({
// Respond with hello message
});
});
});

this.peerBook.getAll().forEach((peer) => {
peer.multiaddrs.forEach((multiaddr) => {
peerInfo.multiaddrs.add(multiaddr);
Expand All @@ -146,4 +147,4 @@ export class P2PNetwork extends EventEmitter implements Service {
}
});
}
}
}i
8 changes: 8 additions & 0 deletions src/p2p/messages/packet.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
syntax = "proto3";

message Packet {
string key = 1;
string method = 2;
string type = 3;
string dataType = 4;
}
87 changes: 87 additions & 0 deletions src/p2p/messages/wire.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
syntax = "proto3";

service Eth2WireProtocol {
rpc Hello (HelloRequest) returns (HelloResponse) {}
rpc Goodbye (GoodbyeRequest) returns (GoodbyeResponse) {}
rpc GetStatus (GetStatusRequest) returns (GetStatusResponse) {}
rpc BeaconBlockRoots (BeaconBlockRootsRequest) returns (BeaconBlockRootsResponse) {}
rpc BeaconBlockHeaders (BeaconBlockHeadersRequest) returns (BeaconBlockResponse) {}
rpc BeaconBlockBodies (BeaconBlockBodiesRequest) returns (BeaconBlockBodiesResponse) {}
rpc BeaconChainState (BeaconChainStateRequest) returns (BeaconChainStateResponse) {}
}

message HelloRequest {
uint32 networkId = 1;
uint64 chainId = 2;
bytes latestFinalizedRoot = 3;
uint64 latestFinalizedEpoch = 4;
bytes bestRoot = 5;
uint64 bestSlot = 6;
}

message HelloResponse {
uint32 networkId = 1;
uint64 chainId = 2;
bytes latestFinalizedRoot = 3;
uint64 latestFinalizedEpoch = 4;
bytes bestRoot = 5;
uint64 bestSlot = 6;
}

message GoodbyeRequest {
uint64 reason = 1;
}

message GoodbyeResponse {
uint64 reason = 1;
}

message GetStatusRequest {
bytes sha = 1;
bytes userAgent = 2;
uint64 timestamp = 3;
}

message GetStatusResponse {
bytes sha = 1;
bytes userAgent = 2;
uint64 timestamp = 3;
}

message BeaconBlockRootsRequest {
uint64 startSlot = 1;
uint64 count = 2;
}

message BeaconBlockRootsResponse {
bytes blockRoot = 1;
uint64 slot = 2;
repeated bytes roots = 3;
}

message BeaconBlockHeadersRequest {
bytes startRoot = 1;
uint64 startSlot = 2;
uint64 maxHeaders = 3;
uint64 skipSlots = 4;
}

message BeaconBlockHeadersResponse {
repeated bytes headers = 1;
}

message BeaconBlockBodiesRequest {
repeated bytes blockRoots = 1;
}

message BeaconBlockBodiesResponse {
repeated bytes blockBodies = 1;
}

message BeaconChainStateRequest {
repeated bytes hashes = 1;
}

message BeaconChainStateResponse {

}
64 changes: 63 additions & 1 deletion src/p2p/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import {PeerInfo} from "peer-info";
import {PeerId} from "peer-id";
import {defaultsDeep} from "@nodeutils/defaults-deep";
import * as FloodSub from "libp2p-floodsub";
import {protobuf} from "protobufjs";
import logger, {AbstractLogger} from "../logger";
import {PeerBook} from "peer-book";

export interface LodestarNodeOpts {
bootstrap?: string[];
Expand All @@ -18,6 +21,10 @@ export class LodestarNode extends LibP2p {

private pubsub: FloodSub;

private log: AbstractLogger;

private peerBook: PeerBook;

private constructor(_options: LodestarNodeOpts) {
const defaults = {
modules: {
Expand All @@ -36,6 +43,10 @@ export class LodestarNode extends LibP2p {
}
};

this.handlers = {};
this.requests = {};
this.peerBook = new PeerBook();
this.log = logger;
super(defaultsDeep(_options, defaults));
}

Expand All @@ -53,8 +64,59 @@ export class LodestarNode extends LibP2p {
}

public async start(): Promise<void> {
await promisify(super.start.bind(this))();
const startFn = promisify(super.start.bind(this));
await startFn((err) => {
if (err) {
this.log.info(err);
return;
}

this.on('peer:discovery', (peerInfo) => {
this.log.info(`Discovered Peer: ${peerInfo}`);
const peerId = peerInfo.id.toB58String();
if (peerBook.has(peerId)) {
return;
}

this.peerBook.put(peerInfo);

this.dialProtocol(peerInfo, 'eth/serenity/beacon/rpc/1', (err, conn) => {
if (err) {
this.log.info(`Error during dialing: ${err} `);
return;
}

return this._connection(conn, peerInfo);
})
});
super.handle('eth/serenity/beacon/rpc/1', (protocol, conn) => {
return this._connection(conn, null);
});

this.on('peer:connect', (peerInfo) => {
this.log.info(`Peer connected: ${peerInfo}`);
this.peerBook.put(peerInfo);
});

this.on('peer:disconnect', (peerInfo) => {
this.log.info(`Peer disconnected: ${peerInfo}`);
this.peerBook.remote(peerInfo);
});

});
await promisify(this.pubsub.start.bind(this.pubsub))();
}

public async handle() {

}

private async _connection(conn: Connection, peer:): Promise<void> {

}

private async _rpc(send: ): Promise<void> {

}
}

7 changes: 7 additions & 0 deletions src/rpc/api/wire/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {WireProtocolApi} from "./wire";
import {IWireProtocolApi} from "./interface";

export {
WireProtocolApi,
IWireProtocolApi
};
46 changes: 46 additions & 0 deletions src/rpc/api/wire/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {IApi} from "../interface";

import {
Request,
Response,
Hello,
Goodbye,
GetStatus,
BeaconBlockRootsRequest,
BeaconBlockRootsResponse,
BeaconBlockHeaderRequest,
BeaconBlockHeaderResponse,
BeaconBlockBodiesRequest,
BeaconBlockBodiesResponse,
BeaconChainStateRequest,
BeaconChainStateResponse
} from "./messages";

export interface IWireProtocolApi extends IApi {

/**
* Returns metadata about the remote node.
*/
GetStatus(): Promise<GetStatus>;

/**
* Returns list of block roots and slots from the peer
*/
RequestBeaconBlockRoots(request: BeaconBlockRootsRequest): Promise<BeaconBlockRootsResponse>;

/**
* Returns beacon block headers from peer
*/
RequestBeaconBlockHeaders(request: BeaconBlockHeadersRequest): Promise<BeaconBlockHeaderResponse>;

/**
* Returns block bodies associated with block roots from a peer
*/
RequestBeaconBlockBodies(request: BeaconBlockBodiesRequest): Promise<BeaconBlockBodiesResponse>;

/**
* Returns the hashes of merkle tree nodes from merkelizing the block's state root.
*/
RequestBeaconChainState(request: BeaconChainStateRequest): Promise<BeaconChainStateResponse>;

}
Loading