-
-
Notifications
You must be signed in to change notification settings - Fork 290
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
Changes from 12 commits
dba5484
8565457
f5a134b
2da7112
d35dd1f
93be293
88d333d
8698363
560d066
5abed10
07ea887
bd6752c
e25b033
72e2c06
ddf1719
0ac4eba
712a039
caf7a63
aec549d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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; | ||
|
@@ -16,6 +18,10 @@ export interface P2pOptions { | |
bootnodes: string[]; | ||
} | ||
|
||
export interface ChainOptions { | ||
|
||
} | ||
|
||
/** | ||
* The P2PNetwork service manages p2p connection/subscription objects | ||
*/ | ||
|
@@ -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; | ||
|
@@ -89,18 +95,45 @@ export class P2PNetwork extends EventEmitter implements Service { | |
|
||
}); | ||
|
||
// 2-way handshake | ||
const protocol: string = "/eth/serenity/beacon/rpc/1"; | ||
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 { | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. white space, also not sure if this needs a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) { | ||
|
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; | ||
} |
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; | ||
} |
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 | ||
}; |
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>; | ||
|
||
} |
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 { | ||
|
||
} |
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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we could make a It would look like: export type Root = bytes32; and since we would be using it in ssz-ed types, we'd need a |
||
hash: Buffer; | ||
} |
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> { | ||
|
||
} | ||
|
||
} |
There was a problem hiding this comment.
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