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 12 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
39 changes: 36 additions & 3 deletions src/p2p/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ 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";

export interface P2pOptions {
maxPeers: number;
Expand All @@ -16,6 +18,10 @@ export interface P2pOptions {
bootnodes: string[];
}

export interface ChainOptions {

}

/**
* The P2PNetwork service manages p2p connection/subscription objects
*/
Expand Down Expand Up @@ -48,7 +54,7 @@ export class P2PNetwork extends EventEmitter implements Service {
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.started = false;
Expand Down Expand Up @@ -89,18 +95,45 @@ export class P2PNetwork extends EventEmitter implements Service {

});

// 2-way handshake
const protocol: string = "/eth/serenity/beacon/rpc/1";
Copy link
Member

Choose a reason for hiding this comment

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

probably put this into constants file

const helloMsg: Hello = {

mpetrunic marked this conversation as resolved.
Show resolved Hide resolved
};
this.node.handle(protocol, (proto, conn) => {
pull(
pull.values([Buffer.from(JSON.stringify(helloMsg))]),
conn,
pull.collect((values) => {
// Peers' responses

})
);
});
this.node.on('peer:connect', (peerInfo) => {
try {
GregTheGreek marked this conversation as resolved.
Show resolved Hide resolved
this.log.info(`Peer connected: ${peerInfo}`);
this.peerBook.put(peerInfo);
this.discoveredPeers.add(peerInfo);
this.discoveredPeers.add(peerInfo);
this.node.dialProtocol(peerInfo, protocol, (err, conn) => {
pull(
pull.values([Buffer.from(JSON.stringify(helloMsg))]),
conn,
pull.collect((values) => {
// Peers responses

})
);
})

} catch (err) {
this.log.error(err);
}
});

this.node.on('peer:disconnect', (peerInfo) => {
try {
try {

Copy link
Member

Choose a reason for hiding this comment

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

white space, also not sure if this needs a try/catch theres no async functionality happening

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The pull-stream is there because that's what used in the example I was given. I will be changing this to an async iterator. Also, you can still use try/catch whether or not there's async functionality. Is there a preferred way for catching errors that would be better in this case?

Copy link
Member

Choose a reason for hiding this comment

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

The way I look at It, those functions should return a promise or callback if they have an error.

I'm on mobile but I'll check the api later

this.peerBook.remove(peerInfo);
this.discoveredPeers.delete(peerInfo);
} catch (err) {
Expand Down
Empty file added src/p2p/wire/interface.ts
Empty file.
79 changes: 79 additions & 0 deletions src/p2p/wire/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

Mikerah marked this conversation as resolved.
Show resolved Hide resolved
export interface Request {
id: number;
method_id: number;
body: string;
Mikerah marked this conversation as resolved.
Show resolved Hide resolved
}

export interface Response {
id: number;
response_code: number;
result: Buffer;
}

// Method ID: 0

export interface Hello {
network_id: number;
chain_id: number;
latest_finalized_root: Buffer;
latest_finalized_epoch: number;
best_root: Buffer;
best_slot: number;
}

// Method ID: 1

export interface Goodbye {
reason: number;
}

// Method ID: 2

export interface GetStatus {
sha: Buffer;
user_agent: Buffer;
timestamp: number;
}

// Method ID: 10

export interface RequestBeaconBlockRoots {
start_slot: number;
count: number;
}

export interface BeaconBlockRoots {
block_root: Buffer;
slot: number;
// Doesn't currently exist as a standalone type
roots: []BlockRootSlot;
}

// Method ID: 11
export interface RequestBeaconBlockHeader {
// Doesn't currently exist as a standalone type
start_root: HashTreeRoot;
start_slot: number;
max_headers: number;
skip_slots: number;
}

export interface BeaconBlockHeaders {
// Doesn't currently exist as a standalone type
headers: []BeaconBlockHeader
}

// Method ID: 12
export interface RequestBeaconBlockBodies {
block_roots: []HashTreeRoot;
}

export interface BeaconBlockBodies {
block_bodies: []BeaconBlockBody;
}

// Method ID: 13
export interface RequestBeaconChainState {
hashes: []HashTreeRoot;
}
10 changes: 10 additions & 0 deletions src/p2p/wire/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {Slot} from "../../types/primitive"

export interface BlockRootSlot {
block_root: Buffer;
slot: Slot;
}

export interface HashTreeRoot {
hash: Buffer;
}
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>;

}
89 changes: 89 additions & 0 deletions src/rpc/api/wire/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {Slot} from "../../types/primitive";
import {BlockRootSlot, HashTreeRoot} from "./types";

type RPCMethod = Hello | Goodbye | GetStatus;

export interface Request {
Mikerah marked this conversation as resolved.
Show resolved Hide resolved
id: number;
method_id: number;
body: string;
}

export interface Response {
id: number;
response_code: number;
result: Buffer;
}

// Method ID: 0

export interface Hello {
network_id: number;
chain_id: number;
latest_finalized_root: Buffer;
latest_finalized_epoch: number;
best_root: Buffer;
best_slot: Slot;
}

// Method ID: 1

export interface Goodbye {
reason: number;
}

// Method ID: 2

export interface GetStatusRequest {
sha: Buffer;
user_agent: Buffer;
timestamp: number;
}

// Method ID: 10

export interface BeaconBlockRootsRequest {
start_slot: Slot;
count: number;
}

export interface BeaconBlockRootsResponse {
block_root: Buffer;
slot: Slot;
// Doesn't currently exist as a standalone type
roots: []BlockRootSlot;
}

// Method ID: 11
export interface BeaconBlockHeadersRequest {
// Doesn't currently exist as a standalone type
start_root: HashTreeRoot;
start_slot: Slot;
max_headers: number;
skip_slots: number;
}

export interface BeaconBlockHeadersResponse {
// Doesn't currently exist as a standalone type
headers: []BeaconBlockHeader
}

// Method ID: 12
export interface BeaconBlockBodiesRequest {
block_roots: []HashTreeRoot;
}

export interface BeaconBlockBodiesResponse {
block_bodies: []BeaconBlockBody;
}

// Method ID: 13
export interface BeaconChainStateRequest {
hashes: []HashTreeRoot;
}

// Method ID: 14
// Not yet defined in the ETH2.0 Wire spec.
export interface BeaconChainStateResponse {

}
10 changes: 10 additions & 0 deletions src/rpc/api/wire/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {Slot} from "../../types/primitive"

export interface BlockRootSlot {
block_root: Buffer;
slot: Slot;
}

export interface HashTreeRoot {
Copy link
Member

Choose a reason for hiding this comment

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

I think we could make a Root type in src/types/primitive.ts that would be useful across the codebase, used in the wire messages.

It would look like:

export type Root = bytes32;

and since we would be using it in ssz-ed types, we'd need a export const Root = bytes32; too.

hash: Buffer;
}
58 changes: 58 additions & 0 deletions src/rpc/api/wire/wire.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {IWireProtocolApi} from "./interface";
import {BeaconChain} from "../../../chain";
import {DB} from "../../../db";

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

import {
BlockRootSlot,
HashTreeRoot
} from "./types";

export class WireProtocolApi implements IWireProtocolApi {

public namespace: string;

private chain: BeaconChain;
private db: DB;

public constructor(opts, {chain, db}) {
this.namespace = 'eth2-wire';
Mikerah marked this conversation as resolved.
Show resolved Hide resolved
this.db;
this.chain;
}

public async GetStatus(): Promise<GetStatus> {

}

public async RequestBeaconBlockRoots(request: BeaconBlockRootsRequest): Promise<BeaconBlockRootsResponse> {

}

public async RequestBeaconBlockHeaders(request: BeaconBlockHeadersRequest): Promise<BeaconBlockHeadersResponse> {

}

public async RequestBeaconBlockBodies(request: BeaconBlockBodiesRequest): Promise<BeaconBlockBodiesResponse> {

}

public async RequestBeaconChainState(request: BeaconChainStateRequest): Promise<BeaconChainStateResponse> {

}

}