From 7a78e3cc5c31d4a2c182f58df4a41a789636a705 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Tue, 30 Apr 2019 21:04:01 -0400 Subject: [PATCH 01/12] add validator rpc types --- src/types/index.ts | 1 + src/types/misc.ts | 4 ++-- src/types/validator.ts | 43 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 src/types/validator.ts diff --git a/src/types/index.ts b/src/types/index.ts index 60e0f619812c..ccc3f40e58cd 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -25,3 +25,4 @@ export * from "./misc"; export * from "./operations"; export * from "./block"; export * from "./state"; +export * from "./validator"; diff --git a/src/types/misc.ts b/src/types/misc.ts index b962b0befc44..94956c247280 100644 --- a/src/types/misc.ts +++ b/src/types/misc.ts @@ -230,8 +230,8 @@ export interface HistoricalBatch { export const HistoricalBatch: SimpleContainerType = { name: "HistoricalBatch", fields: [ - ["blockRoots", [bytes32, SLOTS_PER_HISTORICAL_ROOT]], - ["stateRoots", [bytes32, SLOTS_PER_HISTORICAL_ROOT]], + ["blockRoots", [bytes32]], + ["stateRoots", [bytes32]], ], }; diff --git a/src/types/validator.ts b/src/types/validator.ts new file mode 100644 index 000000000000..c740d7e8293d --- /dev/null +++ b/src/types/validator.ts @@ -0,0 +1,43 @@ +import {bytes48, uint64} from "./primitive"; +import {Shard, Slot} from "./custom"; +import {SimpleContainerType} from "@chainsafe/ssz"; + +export interface ValidatorDuty { + // The validator's public key, uniquely identifying them + validatorPubkey: bytes48; + // The index of the validator in the committee + committeeIndex: uint64; + // The slot at which the validator must attest + attestationSlot: Slot; + // The shard in which the validator must attest + attestationShard: Shard; + // The slot in which a validator must propose a block, this field can be Null + blockProductionSlot: Slot; +} +export const ValidatorDuty: SimpleContainerType = { + name: "ValidatorDuty", + fields: [ + ["validatorPubkey", bytes48], + ["committeeIndex", uint64], + ["attestationSlot", Slot], + ["attestationShard", Shard], + ["blockProductionSlot", Slot], + ], +}; + +export interface SyncingStatus { + // The block at which syncing started (will only be reset, after the sync reached his head) + startingBlock: uint64; + // Current Block + currentBlock: uint64; + // The estimated highest block, or current target block number + highestBlock: uint64; +} +export const SyncingStatus: SimpleContainerType = { + name: "SyncingStatus", + fields: [ + ["startingBlock", uint64], + ["currentBlock", uint64], + ["highestBlock", uint64], + ], +}; From f03a15b7def2059df68ef9eef11bbc3a795ec3bb Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Wed, 1 May 2019 17:56:26 -0400 Subject: [PATCH 02/12] add validator rpc --- src/rpc/validator/api.ts | 62 ++++++++++++++++++++++++++++++ src/rpc/validator/index.ts | 2 + src/rpc/validator/interface.ts | 70 ++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 src/rpc/validator/api.ts create mode 100644 src/rpc/validator/index.ts create mode 100644 src/rpc/validator/interface.ts diff --git a/src/rpc/validator/api.ts b/src/rpc/validator/api.ts new file mode 100644 index 000000000000..7930a44e7b28 --- /dev/null +++ b/src/rpc/validator/api.ts @@ -0,0 +1,62 @@ +import { + Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data, uint64, + Fork, SyncingStatus, ValidatorDuty, bytes48, bytes +} from "../../types"; +import { DB } from "../../db"; +import { BeaconChain } from "../../chain"; +import { OpPool } from "../../opPool"; + +import {API} from "./interface"; + +export class ValidatorAPI implements API { + private chain: BeaconChain; + private db: DB; + private opPool: OpPool; + + public constructor(opts, {chain, db, opPool}) { + this.chain = chain; + this.db = db; + this.opPool = opPool; + } + + public async getClientVersion(): Promise { + return Buffer.alloc(32); + } + + public async getFork(): Promise<{fork: Fork, chain_id: uint64}> { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as {fork: Fork, chain_id: uint64}; + } + + public async getGenesisTime(): Promise { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as uint64; + } + + public async getSyncingStatus(): Promise { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as boolean | SyncingStatus; + } + + public async getDuties(validator_pubkeys: bytes48[]): Promise<{current_version: Fork, validator_duties: ValidatorDuty[]}> { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as {current_version: Fork, validator_duties: ValidatorDuty[]}; + } + + public async produceBlock(slot: Slot, randao_reveal: bytes): Promise { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as BeaconBlock; + } + + public async produceAttestation(slot: Slot, shard: Shard): Promise { + // await this.opPool.receiveAttestation(attestation); + } + + public async publishBlock(beacon_block: BeaconBlock): Promise { + // await this.chain.receiveBlock(block); + } + + public async publishAttestation(indexed_attestation: IndexedAttestation): Promise { + // await this.chain.receiveBlock(block); + } +} diff --git a/src/rpc/validator/index.ts b/src/rpc/validator/index.ts new file mode 100644 index 000000000000..310430e8139a --- /dev/null +++ b/src/rpc/validator/index.ts @@ -0,0 +1,2 @@ +export * from "./interface"; +export * from "./api"; diff --git a/src/rpc/validator/interface.ts b/src/rpc/validator/interface.ts new file mode 100644 index 000000000000..20769de2ed28 --- /dev/null +++ b/src/rpc/validator/interface.ts @@ -0,0 +1,70 @@ +/** + * The API interface defines the calls that can be made from a Validator + */ +import { + BeaconBlock, bytes, bytes32, bytes48, Fork, Shard, Slot, SyncingStatus, uint64, + ValidatorDuty +} from "../../types"; + +export interface API { + /** + * Requests that the BeaconNode identify information about its implementation in a format similar to a HTTP User-Agent field. + * @returns {Promise} An ASCII-encoded hex string which uniquely defines the implementation of the BeaconNode and its current software version. + */ + getClientVersion(): Promise; + + /** + * Requests the BeaconNode to provide which fork version it is currently on. + * @returns {Promise<{fork: Fork; chain_id: uint64}>} + */ + getFork(): Promise<{fork: Fork, chain_id: uint64}>; + + /** + * Requests the genesis_time parameter from the BeaconNode, which should be consistent across all BeaconNodes that follow the same beacon chain. + * @returns {Promise} The genesis_time, which is a fairly static configuration option for the BeaconNode. + */ + getGenesisTime(): Promise; + + /** + * Requests the BeaconNode to describe if it's currently syncing or not, and if it is, what block it is up to. This is modelled after the Eth1.0 JSON-RPC eth_syncing call. + * @returns {Promise} Either false if the node is not syncing, or a SyncingStatus object if it is. + */ + getSyncingStatus(): Promise; + + /** + * Requests the BeaconNode to provide a set of “duties”, which are actions that should be performed by ValidatorClients. This API call should be polled at every slot, to ensure that any chain reorganisations are catered for, and to ensure that the currently connected BeaconNode is properly synchronised. + * @param {bytes48[]} validator_pubkeys + * @returns {Promise<{current_version: bytes4; validator_duties: ValidatorDuty[]}>} A list of unique validator public keys, where each item is a 0x encoded hex string. + */ + getDuties(validator_pubkeys: bytes48[]): Promise<{current_version: Fork, validator_duties: ValidatorDuty[]}>; + + /** + * Requests a BeaconNode to produce a valid block, which can then be signed by a ValidatorClient. + * @param {Slot} slot + * @param {bytes} randao_reveal + * @returns {Promise} A proposed BeaconBlock object, but with the signature field left blank. + */ + produceBlock(slot: Slot, randao_reveal: bytes): Promise; + + /** + * Requests that the BeaconNode produce an IndexedAttestation, with a blank signature field, which the ValidatorClient will then sign. + * @param {Slot} slot + * @param {Shard} shard + * @returns {Promise} + */ + produceAttestation(slot: Slot, shard: Shard): Promise; + + /** + * Instructs the BeaconNode to publish a newly signed beacon block to the beacon network, to be included in the beacon chain. + * @param {BeaconBlock} beacon_block + * @returns {Promise} + */ + publishBlock(beacon_block: BeaconBlock): Promise; + + /** + * Instructs the BeaconNode to publish a newly signed IndexedAttestation object, to be incorporated into the beacon chain. + * @param {IndexedAttestation} indexed_attestation + * @returns {Promise} + */ + publishAttestation(indexed_attestation: IndexedAttestation): Promise; +} From 202bf913bfb5afb46e3f5294e3c41909b0282483 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Wed, 1 May 2019 18:20:12 -0400 Subject: [PATCH 03/12] fix linter errors --- src/rpc/validator/api.ts | 29 +++++++++++++---------------- src/rpc/validator/interface.ts | 24 ++++++++++++------------ 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/rpc/validator/api.ts b/src/rpc/validator/api.ts index 7930a44e7b28..aa1a98c5d1a4 100644 --- a/src/rpc/validator/api.ts +++ b/src/rpc/validator/api.ts @@ -1,10 +1,10 @@ import { Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data, uint64, - Fork, SyncingStatus, ValidatorDuty, bytes48, bytes + Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation } from "../../types"; -import { DB } from "../../db"; -import { BeaconChain } from "../../chain"; -import { OpPool } from "../../opPool"; +import {DB} from "../../db"; +import {BeaconChain} from "../../chain"; +import {OpPool} from "../../opPool"; import {API} from "./interface"; @@ -23,9 +23,9 @@ export class ValidatorAPI implements API { return Buffer.alloc(32); } - public async getFork(): Promise<{fork: Fork, chain_id: uint64}> { + public async getFork(): Promise<{fork: Fork; chainId: uint64}> { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as {fork: Fork, chain_id: uint64}; + return {} as {fork: Fork; chainId: uint64}; } public async getGenesisTime(): Promise { @@ -38,25 +38,22 @@ export class ValidatorAPI implements API { return {} as boolean | SyncingStatus; } - public async getDuties(validator_pubkeys: bytes48[]): Promise<{current_version: Fork, validator_duties: ValidatorDuty[]}> { + public async getDuties(validatorPubkeys: bytes48[]): Promise<{currentVersion: Fork; validatorDuties: ValidatorDuty[]}> { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as {current_version: Fork, validator_duties: ValidatorDuty[]}; + return {} as {currentVersion: Fork; validatorDuties: ValidatorDuty[]}; } - public async produceBlock(slot: Slot, randao_reveal: bytes): Promise { + public async produceBlock(slot: Slot, randaoReveal: bytes): Promise { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion return {} as BeaconBlock; } public async produceAttestation(slot: Slot, shard: Shard): Promise { - // await this.opPool.receiveAttestation(attestation); + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as IndexedAttestation; } - public async publishBlock(beacon_block: BeaconBlock): Promise { - // await this.chain.receiveBlock(block); - } + public async publishBlock(beaconBlock: BeaconBlock): Promise {} - public async publishAttestation(indexed_attestation: IndexedAttestation): Promise { - // await this.chain.receiveBlock(block); - } + public async publishAttestation(indexedAttestation: IndexedAttestation): Promise {} } diff --git a/src/rpc/validator/interface.ts b/src/rpc/validator/interface.ts index 20769de2ed28..9414a063eb7c 100644 --- a/src/rpc/validator/interface.ts +++ b/src/rpc/validator/interface.ts @@ -2,7 +2,7 @@ * The API interface defines the calls that can be made from a Validator */ import { - BeaconBlock, bytes, bytes32, bytes48, Fork, Shard, Slot, SyncingStatus, uint64, + BeaconBlock, bytes, bytes32, bytes48, Fork, IndexedAttestation, Shard, Slot, SyncingStatus, uint64, ValidatorDuty } from "../../types"; @@ -15,9 +15,9 @@ export interface API { /** * Requests the BeaconNode to provide which fork version it is currently on. - * @returns {Promise<{fork: Fork; chain_id: uint64}>} + * @returns {Promise<{fork: Fork; chainId: uint64}>} */ - getFork(): Promise<{fork: Fork, chain_id: uint64}>; + getFork(): Promise<{fork: Fork; chainId: uint64}>; /** * Requests the genesis_time parameter from the BeaconNode, which should be consistent across all BeaconNodes that follow the same beacon chain. @@ -33,18 +33,18 @@ export interface API { /** * Requests the BeaconNode to provide a set of “duties”, which are actions that should be performed by ValidatorClients. This API call should be polled at every slot, to ensure that any chain reorganisations are catered for, and to ensure that the currently connected BeaconNode is properly synchronised. - * @param {bytes48[]} validator_pubkeys - * @returns {Promise<{current_version: bytes4; validator_duties: ValidatorDuty[]}>} A list of unique validator public keys, where each item is a 0x encoded hex string. + * @param {bytes48[]} validatorPubkeys + * @returns {Promise<{currentVersion: bytes4; validatorDuties: ValidatorDuty[]}>} A list of unique validator public keys, where each item is a 0x encoded hex string. */ - getDuties(validator_pubkeys: bytes48[]): Promise<{current_version: Fork, validator_duties: ValidatorDuty[]}>; + getDuties(validatorPubkeys: bytes48[]): Promise<{currentVersion: Fork; validatorDuties: ValidatorDuty[]}>; /** * Requests a BeaconNode to produce a valid block, which can then be signed by a ValidatorClient. * @param {Slot} slot - * @param {bytes} randao_reveal + * @param {bytes} randaoReveal * @returns {Promise} A proposed BeaconBlock object, but with the signature field left blank. */ - produceBlock(slot: Slot, randao_reveal: bytes): Promise; + produceBlock(slot: Slot, randaoReveal: bytes): Promise; /** * Requests that the BeaconNode produce an IndexedAttestation, with a blank signature field, which the ValidatorClient will then sign. @@ -56,15 +56,15 @@ export interface API { /** * Instructs the BeaconNode to publish a newly signed beacon block to the beacon network, to be included in the beacon chain. - * @param {BeaconBlock} beacon_block + * @param {BeaconBlock} beaconBlock * @returns {Promise} */ - publishBlock(beacon_block: BeaconBlock): Promise; + publishBlock(beaconBlock: BeaconBlock): Promise; /** * Instructs the BeaconNode to publish a newly signed IndexedAttestation object, to be incorporated into the beacon chain. - * @param {IndexedAttestation} indexed_attestation + * @param {IndexedAttestation} indexedAttestation * @returns {Promise} */ - publishAttestation(indexed_attestation: IndexedAttestation): Promise; + publishAttestation(indexedAttestation: IndexedAttestation): Promise; } From f89a0713797942710178663d5781dd87829ccb2d Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Thu, 2 May 2019 11:33:50 -0400 Subject: [PATCH 04/12] seperate rpc into modules --- src/node/index.ts | 4 ++-- src/rpc/api/index.ts | 4 ++-- src/rpc/api/{interface.ts => interfaces/beacon.ts} | 4 ++-- src/rpc/api/interfaces/index.ts | 7 +++++++ .../interface.ts => api/interfaces/validator.ts} | 4 ++-- src/rpc/api/mock.ts | 4 ++-- src/rpc/api/{api.ts => modules/beacon.ts} | 12 ++++++------ src/rpc/api/modules/index.ts | 7 +++++++ .../{validator/api.ts => api/modules/validator.ts} | 12 ++++++------ src/rpc/protocol/jsonRpc.ts | 7 +++++-- src/rpc/validator/index.ts | 2 -- src/types/validator.ts | 3 +-- test/unit/rpc/api.test.ts | 2 +- test/unit/rpc/jsonRpcOverHttp.test.ts | 8 ++++---- test/unit/rpc/jsonRpcOverWs.test.ts | 4 ++-- 15 files changed, 49 insertions(+), 35 deletions(-) rename src/rpc/api/{interface.ts => interfaces/beacon.ts} (93%) create mode 100644 src/rpc/api/interfaces/index.ts rename src/rpc/{validator/interface.ts => api/interfaces/validator.ts} (98%) rename src/rpc/api/{api.ts => modules/beacon.ts} (83%) create mode 100644 src/rpc/api/modules/index.ts rename src/rpc/{validator/api.ts => api/modules/validator.ts} (88%) delete mode 100644 src/rpc/validator/index.ts diff --git a/src/node/index.ts b/src/node/index.ts index de14196028e9..da33c0b37b71 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -11,7 +11,7 @@ import {BeaconChain} from "../chain"; import {OpPool} from "../opPool"; import {JSONRPC} from "../rpc/protocol"; import {WSServer} from "../rpc/transport"; -import {BeaconAPI} from "../rpc/api"; +import {BeaconApi} from "../rpc/api"; interface Service { start(): Promise; @@ -65,7 +65,7 @@ class BeaconNode { }); this.rpc = new JSONRPC(this.conf.rpc, { transport: new WSServer(this.conf.rpc), - api: new BeaconAPI(this.conf.rpc, { + api: new BeaconApi(this.conf.rpc, { chain: this.chain, db: this.db, opPool: this.opPool, diff --git a/src/rpc/api/index.ts b/src/rpc/api/index.ts index b069ca92315d..db278183ad8b 100644 --- a/src/rpc/api/index.ts +++ b/src/rpc/api/index.ts @@ -1,3 +1,3 @@ -export * from "./interface"; +export * from "./interfaces"; export * from "./mock"; -export * from "./api"; +export * from "./modules"; diff --git a/src/rpc/api/interface.ts b/src/rpc/api/interfaces/beacon.ts similarity index 93% rename from src/rpc/api/interface.ts rename to src/rpc/api/interfaces/beacon.ts index da453b1a9cee..c2eb6d78ce03 100644 --- a/src/rpc/api/interface.ts +++ b/src/rpc/api/interfaces/beacon.ts @@ -1,9 +1,9 @@ -import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../types"; +import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../types"; /** * The API interface defines the calls that can be made externally */ -export interface API { +export interface IBeaconApi { /** * Return the current chain head */ diff --git a/src/rpc/api/interfaces/index.ts b/src/rpc/api/interfaces/index.ts new file mode 100644 index 000000000000..f77f53fca810 --- /dev/null +++ b/src/rpc/api/interfaces/index.ts @@ -0,0 +1,7 @@ +import {IBeaconApi} from "./beacon"; +import {IValidatorApi} from "./validator"; + +export { + IBeaconApi, + IValidatorApi +} diff --git a/src/rpc/validator/interface.ts b/src/rpc/api/interfaces/validator.ts similarity index 98% rename from src/rpc/validator/interface.ts rename to src/rpc/api/interfaces/validator.ts index 9414a063eb7c..d4366559d7a5 100644 --- a/src/rpc/validator/interface.ts +++ b/src/rpc/api/interfaces/validator.ts @@ -4,9 +4,9 @@ import { BeaconBlock, bytes, bytes32, bytes48, Fork, IndexedAttestation, Shard, Slot, SyncingStatus, uint64, ValidatorDuty -} from "../../types"; +} from "../../../types"; -export interface API { +export interface IValidatorApi { /** * Requests that the BeaconNode identify information about its implementation in a format similar to a HTTP User-Agent field. * @returns {Promise} An ASCII-encoded hex string which uniquely defines the implementation of the BeaconNode and its current software version. diff --git a/src/rpc/api/mock.ts b/src/rpc/api/mock.ts index 6a8b20c50dcb..058d0b9ff1e0 100644 --- a/src/rpc/api/mock.ts +++ b/src/rpc/api/mock.ts @@ -2,7 +2,7 @@ import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot import {getEmptyBlock} from "../../chain/genesis"; -import {API} from "./interface"; +import {IBeaconApi} from "./interfaces"; export interface MockAPIOpts { head?: BeaconBlock; @@ -12,7 +12,7 @@ export interface MockAPIOpts { attestationData?: AttestationData; } -export class MockAPI implements API { +export class MockAPI implements IBeaconApi { private head; private attestations; public constructor(opts?: MockAPIOpts) { diff --git a/src/rpc/api/api.ts b/src/rpc/api/modules/beacon.ts similarity index 83% rename from src/rpc/api/api.ts rename to src/rpc/api/modules/beacon.ts index 59347f264120..0108dab81622 100644 --- a/src/rpc/api/api.ts +++ b/src/rpc/api/modules/beacon.ts @@ -1,11 +1,11 @@ -import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../types"; -import {DB} from "../../db"; -import {BeaconChain} from "../../chain"; -import {OpPool} from "../../opPool"; +import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../types"; +import {DB} from "../../../db"; +import {BeaconChain} from "../../../chain"; +import {OpPool} from "../../../opPool"; -import {API} from "./interface"; +import {IBeaconApi} from "../interfaces"; -export class BeaconAPI implements API { +export class BeaconApi implements IBeaconApi { private chain: BeaconChain; private db: DB; private opPool: OpPool; diff --git a/src/rpc/api/modules/index.ts b/src/rpc/api/modules/index.ts new file mode 100644 index 000000000000..1ca7c3481295 --- /dev/null +++ b/src/rpc/api/modules/index.ts @@ -0,0 +1,7 @@ +import {ValidatorApi} from "./validator"; +import {BeaconApi} from "./beacon"; + +export { + ValidatorApi, + BeaconApi +} diff --git a/src/rpc/validator/api.ts b/src/rpc/api/modules/validator.ts similarity index 88% rename from src/rpc/validator/api.ts rename to src/rpc/api/modules/validator.ts index aa1a98c5d1a4..289c90cf3bc1 100644 --- a/src/rpc/validator/api.ts +++ b/src/rpc/api/modules/validator.ts @@ -1,14 +1,14 @@ import { Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data, uint64, Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation -} from "../../types"; -import {DB} from "../../db"; -import {BeaconChain} from "../../chain"; -import {OpPool} from "../../opPool"; +} from "../../../types"; +import {DB} from "../../../db"; +import {BeaconChain} from "../../../chain"; +import {OpPool} from "../../../opPool"; -import {API} from "./interface"; +import {IValidatorApi} from "../interfaces"; -export class ValidatorAPI implements API { +export class ValidatorApi implements IValidatorApi { private chain: BeaconChain; private db: DB; private opPool: OpPool; diff --git a/src/rpc/protocol/jsonRpc.ts b/src/rpc/protocol/jsonRpc.ts index ca0c8a508938..165e0407a615 100644 --- a/src/rpc/protocol/jsonRpc.ts +++ b/src/rpc/protocol/jsonRpc.ts @@ -1,7 +1,7 @@ import * as jsonRpc from "noice-json-rpc"; -import {API} from "../api"; +import {IValidatorApi, IBeaconApi} from "../api"; export interface LikeSocketServer extends jsonRpc.LikeSocketServer { start(): Promise; @@ -18,7 +18,7 @@ export class JSONRPC { private transport: LikeSocketServer; private jsonRpcApi; - public constructor(opts, {transport, api}: {transport: LikeSocketServer; api: API}) { + public constructor(opts, {transport, api}: {transport: LikeSocketServer; api: IBeaconApi | IValidatorApi}) { this.transport = transport; // attach the json-rpc server to underlying transport this.rpcServer = new jsonRpc.Server(this.transport); @@ -26,15 +26,18 @@ export class JSONRPC { // collect the api methods into an enumerable object for rpc exposure const methods = {}; for (let name of Object.getOwnPropertyNames(Object.getPrototypeOf(api))) { + console.log(api[name]); if (name !== 'constructor' && typeof api[name] === 'function') { methods[name] = api[name].bind(api); } } this.jsonRpcApi.BeaconChain.expose(methods); } + public async start(): Promise { await this.transport.start(); } + public async stop(): Promise { await this.transport.stop(); } diff --git a/src/rpc/validator/index.ts b/src/rpc/validator/index.ts deleted file mode 100644 index 310430e8139a..000000000000 --- a/src/rpc/validator/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./interface"; -export * from "./api"; diff --git a/src/types/validator.ts b/src/types/validator.ts index c740d7e8293d..b8d71df268d6 100644 --- a/src/types/validator.ts +++ b/src/types/validator.ts @@ -1,5 +1,4 @@ -import {bytes48, uint64} from "./primitive"; -import {Shard, Slot} from "./custom"; +import {bytes48, Shard, Slot, uint64} from "./primitive"; import {SimpleContainerType} from "@chainsafe/ssz"; export interface ValidatorDuty { diff --git a/test/unit/rpc/api.test.ts b/test/unit/rpc/api.test.ts index 2b405533fe9f..0718c0b5a9ad 100644 --- a/test/unit/rpc/api.test.ts +++ b/test/unit/rpc/api.test.ts @@ -9,7 +9,7 @@ import { import {BeaconChain} from "../../../src/chain"; import {OpPool} from "../../../src/opPool"; import {LevelDB} from "../../../src/db"; -import {BeaconAPI} from "../../../src/rpc"; +// import {BeaconAPI} from "../../../src/rpc"; import { generateEmptyBlock } from "../../utils/block"; import { generateEmptyAttestation } from "../../utils/attestation"; diff --git a/test/unit/rpc/jsonRpcOverHttp.test.ts b/test/unit/rpc/jsonRpcOverHttp.test.ts index 1aa4750083e7..0f04eced4734 100644 --- a/test/unit/rpc/jsonRpcOverHttp.test.ts +++ b/test/unit/rpc/jsonRpcOverHttp.test.ts @@ -12,7 +12,7 @@ describe("Json RPC over http", () => { logger.silent(true); const rpcServer = new HttpServer({port: 32421}); server = rpcServer.server; - rpc = new JSONRPC({}, {transport: rpcServer, api: new MockAPI()}) + rpc = new JSONRPC({}, {transport: rpcServer, api: new MockAPI()}); await rpc.start(); }); after(async () => { @@ -33,7 +33,7 @@ describe("Json RPC over http", () => { } done(); }); - }) + }); it("should fail for unknown methods", (done) => { request.default(server) .post('/') @@ -49,7 +49,7 @@ describe("Json RPC over http", () => { assert.fail('Should not be successfull'); done(); }); - }) + }); it("should fail for methods other than POST", (done) => { request.default(server) .get('/') @@ -58,7 +58,7 @@ describe("Json RPC over http", () => { .end((err) => { done(err); }); - }) + }); it("should fail to start on existing port", (done) => { const rpc = new JSONRPC({}, {transport: new HttpServer({port: 32421}), api: new MockAPI()}); rpc.start() diff --git a/test/unit/rpc/jsonRpcOverWs.test.ts b/test/unit/rpc/jsonRpcOverWs.test.ts index b83f081c5c7f..b6f44c1236d9 100644 --- a/test/unit/rpc/jsonRpcOverWs.test.ts +++ b/test/unit/rpc/jsonRpcOverWs.test.ts @@ -1,7 +1,7 @@ import { assert } from "chai"; import * as jsonRpc from "noice-json-rpc"; import Websocket from "ws"; -import {MockAPI, JSONRPC, API, WSServer} from "../../../src/rpc"; +import {MockAPI, JSONRPC, BeaconApi, WSServer} from "../../../src/rpc"; import { generateEmptyBlock } from "../../utils/block"; import { generateEmptyAttestation } from "../../utils/attestation"; @@ -9,7 +9,7 @@ describe("Json RPC over WS", () => { const rpc = new JSONRPC({}, {transport: new WSServer({port: 32420}), api: new MockAPI()}); let client; let ws; - let clientApi: {BeaconChain: API}; + let clientApi: {BeaconChain: BeaconApi}; before(async () => { await rpc.start(); ws = new Websocket("ws://localhost:32420"); From e3663ecb9f8fdb5a324a2561c425e7de687f4e64 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Thu, 2 May 2019 11:35:55 -0400 Subject: [PATCH 05/12] fix lint issues --- .eslintrc | 1 + src/rpc/api/interfaces/index.ts | 2 +- src/rpc/api/modules/index.ts | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.eslintrc b/.eslintrc index 26faacf9046e..ce75e43d6df5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,6 +8,7 @@ "rules": { "@typescript-eslint/indent": ["error", 2], "@typescript-eslint/no-require-imports": "error", + "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/no-unused-vars": ["warn", { "varsIgnorePattern": "^_" diff --git a/src/rpc/api/interfaces/index.ts b/src/rpc/api/interfaces/index.ts index f77f53fca810..fe6594d0d706 100644 --- a/src/rpc/api/interfaces/index.ts +++ b/src/rpc/api/interfaces/index.ts @@ -4,4 +4,4 @@ import {IValidatorApi} from "./validator"; export { IBeaconApi, IValidatorApi -} +}; diff --git a/src/rpc/api/modules/index.ts b/src/rpc/api/modules/index.ts index 1ca7c3481295..c0bde283c951 100644 --- a/src/rpc/api/modules/index.ts +++ b/src/rpc/api/modules/index.ts @@ -4,4 +4,4 @@ import {BeaconApi} from "./beacon"; export { ValidatorApi, BeaconApi -} +}; From 2b042f9e94d78ab52dbc4743dcc0d11506a6be01 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Thu, 2 May 2019 12:36:52 -0400 Subject: [PATCH 06/12] remove beacon api and fix pr comments --- src/rpc/api/interfaces/beacon.ts | 46 ------------------- src/rpc/api/{mock.ts => mock/validator.ts} | 0 src/rpc/api/modules/beacon.ts | 52 ---------------------- src/rpc/protocol/jsonRpc.ts | 1 - src/types/misc.ts | 4 +- 5 files changed, 2 insertions(+), 101 deletions(-) delete mode 100644 src/rpc/api/interfaces/beacon.ts rename src/rpc/api/{mock.ts => mock/validator.ts} (100%) delete mode 100644 src/rpc/api/modules/beacon.ts diff --git a/src/rpc/api/interfaces/beacon.ts b/src/rpc/api/interfaces/beacon.ts deleted file mode 100644 index c2eb6d78ce03..000000000000 --- a/src/rpc/api/interfaces/beacon.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../types"; - -/** - * The API interface defines the calls that can be made externally - */ -export interface IBeaconApi { - /** - * Return the current chain head - */ - getChainHead(): Promise; - - /** - * Return a list of attestations ready for inclusion in the next block - */ - getPendingAttestations(): Promise; - - /** - * Return a list of deposits ready for inclusion in the next block - */ - getPendingDeposits(): Promise; - - /** - * Return the Eth1Data to be included in the next block - */ - getEth1Data(): Promise; - - /** - * Return the state root after the block has been run through the state transition - */ - computeStateRoot(block: BeaconBlock): Promise; - - /** - * Return the attestation data for a slot and shard based on the current head - */ - getAttestationData(slot: Slot, shard: Shard): Promise; - - /** - * Submit an attestation for processing - */ - putAttestation(attestation: Attestation): Promise; - - /** - * Submit a block for processing - */ - putBlock(block: BeaconBlock): Promise; -} diff --git a/src/rpc/api/mock.ts b/src/rpc/api/mock/validator.ts similarity index 100% rename from src/rpc/api/mock.ts rename to src/rpc/api/mock/validator.ts diff --git a/src/rpc/api/modules/beacon.ts b/src/rpc/api/modules/beacon.ts deleted file mode 100644 index 0108dab81622..000000000000 --- a/src/rpc/api/modules/beacon.ts +++ /dev/null @@ -1,52 +0,0 @@ -import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../types"; -import {DB} from "../../../db"; -import {BeaconChain} from "../../../chain"; -import {OpPool} from "../../../opPool"; - -import {IBeaconApi} from "../interfaces"; - -export class BeaconApi implements IBeaconApi { - private chain: BeaconChain; - private db: DB; - private opPool: OpPool; - - public constructor(opts, {chain, db, opPool}) { - this.chain = chain; - this.db = db; - this.opPool = opPool; - } - - public async getChainHead(): Promise { - return await this.db.getChainHead(); - } - - public async getPendingAttestations(): Promise { - return this.opPool.getAttestations(); - } - - public async getPendingDeposits(): Promise { - return []; - } - - public async getEth1Data(): Promise { - // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as Eth1Data; - } - - public async computeStateRoot(block: BeaconBlock): Promise { - return Buffer.alloc(32); - } - - public async getAttestationData(slot: Slot, shard: Shard): Promise { - // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as AttestationData; - } - - public async putAttestation(attestation: Attestation): Promise { - await this.opPool.receiveAttestation(attestation); - } - - public async putBlock(block: BeaconBlock): Promise { - await this.chain.receiveBlock(block); - } -} diff --git a/src/rpc/protocol/jsonRpc.ts b/src/rpc/protocol/jsonRpc.ts index 165e0407a615..3b13bd941364 100644 --- a/src/rpc/protocol/jsonRpc.ts +++ b/src/rpc/protocol/jsonRpc.ts @@ -26,7 +26,6 @@ export class JSONRPC { // collect the api methods into an enumerable object for rpc exposure const methods = {}; for (let name of Object.getOwnPropertyNames(Object.getPrototypeOf(api))) { - console.log(api[name]); if (name !== 'constructor' && typeof api[name] === 'function') { methods[name] = api[name].bind(api); } diff --git a/src/types/misc.ts b/src/types/misc.ts index 94956c247280..b962b0befc44 100644 --- a/src/types/misc.ts +++ b/src/types/misc.ts @@ -230,8 +230,8 @@ export interface HistoricalBatch { export const HistoricalBatch: SimpleContainerType = { name: "HistoricalBatch", fields: [ - ["blockRoots", [bytes32]], - ["stateRoots", [bytes32]], + ["blockRoots", [bytes32, SLOTS_PER_HISTORICAL_ROOT]], + ["stateRoots", [bytes32, SLOTS_PER_HISTORICAL_ROOT]], ], }; From 3b557bca2fbaf07f21bba6b147237c537c092117 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Thu, 2 May 2019 17:14:02 -0400 Subject: [PATCH 07/12] fix test and linter --- src/chain/index.ts | 2 + src/node/index.ts | 4 +- src/rpc/api/index.ts | 2 +- src/rpc/api/interfaces/index.ts | 2 - src/rpc/api/interfaces/validator.ts | 15 +++---- src/rpc/api/mock/validator.ts | 52 ++++++++++++++---------- src/rpc/api/modules/index.ts | 2 - src/rpc/api/modules/validator.ts | 25 ++++++------ src/rpc/protocol/jsonRpc.ts | 6 +-- test/unit/rpc/jsonRpcOverHttp.test.ts | 2 +- test/unit/rpc/jsonRpcOverWs.test.ts | 57 ++++++++++++++------------- 11 files changed, 91 insertions(+), 78 deletions(-) diff --git a/src/chain/index.ts b/src/chain/index.ts index f6e23c1e920e..125869af78a8 100644 --- a/src/chain/index.ts +++ b/src/chain/index.ts @@ -20,6 +20,7 @@ import {getBlockRoot, getEpochStartSlot} from "./stateTransition/util"; */ export class BeaconChain extends EventEmitter { public chain: string; + public genesisTime: number64; private db: DB; private eth1: Eth1Notifier; private _latestBlock: BeaconBlock; @@ -57,6 +58,7 @@ export class BeaconChain extends EventEmitter { const genesisState = getGenesisBeaconState(genesisDeposits, genesisTime, genesisEth1Data); const genesisBlock = getEmptyBlock(); genesisBlock.stateRoot = hashTreeRoot(genesisState, BeaconState); + this.genesisTime = genesisTime; await this.db.setBlock(genesisBlock); await this.db.setChainHead(genesisState, genesisBlock); await this.db.setJustifiedBlock(genesisBlock); diff --git a/src/node/index.ts b/src/node/index.ts index da33c0b37b71..d51202d50bbc 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -11,7 +11,7 @@ import {BeaconChain} from "../chain"; import {OpPool} from "../opPool"; import {JSONRPC} from "../rpc/protocol"; import {WSServer} from "../rpc/transport"; -import {BeaconApi} from "../rpc/api"; +import {ValidatorApi} from "../rpc/api"; interface Service { start(): Promise; @@ -65,7 +65,7 @@ class BeaconNode { }); this.rpc = new JSONRPC(this.conf.rpc, { transport: new WSServer(this.conf.rpc), - api: new BeaconApi(this.conf.rpc, { + api: new ValidatorApi(this.conf.rpc, { chain: this.chain, db: this.db, opPool: this.opPool, diff --git a/src/rpc/api/index.ts b/src/rpc/api/index.ts index db278183ad8b..f757ab1c5d80 100644 --- a/src/rpc/api/index.ts +++ b/src/rpc/api/index.ts @@ -1,3 +1,3 @@ export * from "./interfaces"; -export * from "./mock"; +export * from "./mock/validator"; export * from "./modules"; diff --git a/src/rpc/api/interfaces/index.ts b/src/rpc/api/interfaces/index.ts index fe6594d0d706..5677a4ad1fab 100644 --- a/src/rpc/api/interfaces/index.ts +++ b/src/rpc/api/interfaces/index.ts @@ -1,7 +1,5 @@ -import {IBeaconApi} from "./beacon"; import {IValidatorApi} from "./validator"; export { - IBeaconApi, IValidatorApi }; diff --git a/src/rpc/api/interfaces/validator.ts b/src/rpc/api/interfaces/validator.ts index d4366559d7a5..6b0107449b89 100644 --- a/src/rpc/api/interfaces/validator.ts +++ b/src/rpc/api/interfaces/validator.ts @@ -2,7 +2,8 @@ * The API interface defines the calls that can be made from a Validator */ import { - BeaconBlock, bytes, bytes32, bytes48, Fork, IndexedAttestation, Shard, Slot, SyncingStatus, uint64, + Attestation, AttestationData, + BeaconBlock, bytes, bytes32, bytes48, Fork, IndexedAttestation, number64, Shard, Slot, SyncingStatus, uint64, ValidatorDuty } from "../../../types"; @@ -17,13 +18,13 @@ export interface IValidatorApi { * Requests the BeaconNode to provide which fork version it is currently on. * @returns {Promise<{fork: Fork; chainId: uint64}>} */ - getFork(): Promise<{fork: Fork; chainId: uint64}>; + getFork(): Promise<{fork: Fork; chainId: number64}>; /** * Requests the genesis_time parameter from the BeaconNode, which should be consistent across all BeaconNodes that follow the same beacon chain. * @returns {Promise} The genesis_time, which is a fairly static configuration option for the BeaconNode. */ - getGenesisTime(): Promise; + getGenesisTime(): Promise; /** * Requests the BeaconNode to describe if it's currently syncing or not, and if it is, what block it is up to. This is modelled after the Eth1.0 JSON-RPC eth_syncing call. @@ -50,9 +51,9 @@ export interface IValidatorApi { * Requests that the BeaconNode produce an IndexedAttestation, with a blank signature field, which the ValidatorClient will then sign. * @param {Slot} slot * @param {Shard} shard - * @returns {Promise} + * @returns {Promise} */ - produceAttestation(slot: Slot, shard: Shard): Promise; + produceAttestation(slot: Slot, shard: Shard): Promise; /** * Instructs the BeaconNode to publish a newly signed beacon block to the beacon network, to be included in the beacon chain. @@ -63,8 +64,8 @@ export interface IValidatorApi { /** * Instructs the BeaconNode to publish a newly signed IndexedAttestation object, to be incorporated into the beacon chain. - * @param {IndexedAttestation} indexedAttestation + * @param {Attestation} attestation * @returns {Promise} */ - publishAttestation(indexedAttestation: IndexedAttestation): Promise; + publishAttestation(attestation: Attestation): Promise; } diff --git a/src/rpc/api/mock/validator.ts b/src/rpc/api/mock/validator.ts index 058d0b9ff1e0..efe89e56f54f 100644 --- a/src/rpc/api/mock/validator.ts +++ b/src/rpc/api/mock/validator.ts @@ -1,8 +1,9 @@ -import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../types"; +import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../types/index"; -import {getEmptyBlock} from "../../chain/genesis"; +import {getEmptyBlock} from "../../../chain/genesis"; -import {IBeaconApi} from "./interfaces"; +import {IValidatorApi} from "../interfaces/index"; +import {bytes, bytes48, Fork, number64, SyncingStatus, uint64, ValidatorDuty} from "../../../types"; export interface MockAPIOpts { head?: BeaconBlock; @@ -12,44 +13,53 @@ export interface MockAPIOpts { attestationData?: AttestationData; } -export class MockAPI implements IBeaconApi { - private head; +export class MockAPI implements IValidatorApi { + private version: bytes32; + private fork: Fork; + private chainId: number64; private attestations; + private head: BeaconBlock; public constructor(opts?: MockAPIOpts) { this.attestations = opts && opts.pendingAttestations || []; this.head = opts && opts.head || getEmptyBlock(); } - public async getChainHead(): Promise { - return this.head; + public async getClientVersion(): Promise { + return this.version; } - public async getPendingAttestations(): Promise { - return this.attestations; + public async getFork(): Promise<{fork: Fork; chainId: number64}> { + return {fork: this.fork, chainId: this.chainId}; } - public async getPendingDeposits(): Promise { - return []; + public async getGenesisTime(): Promise { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as number64; } - public async getEth1Data(): Promise { - // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as Eth1Data; + public async getSyncingStatus(): Promise { + return false; } - public async computeStateRoot(block: BeaconBlock): Promise { - return Buffer.alloc(32); + public async getDuties(validatorPubkeys: bytes48[]): Promise<{currentVersion: Fork; validatorDuties: ValidatorDuty[]}> { + return {} as {currentVersion: Fork; validatorDuties: ValidatorDuty[]}; } - public async getAttestationData(slot: Slot, shard: Shard): Promise { + public async produceBlock(slot: Slot, randaoReveal: bytes): Promise { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as AttestationData; + return {} as BeaconBlock; } - public async putAttestation(attestation: Attestation): Promise { - this.attestations.push(attestation); + public async produceAttestation(slot: Slot, shard: Shard): Promise { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as AttestationData; } - public async putBlock(block: BeaconBlock): Promise { + public async publishBlock(block: BeaconBlock): Promise { this.head = block; } + + public async publishAttestation(attestation: Attestation): Promise { + this.attestations.push(Attestation); + } + } diff --git a/src/rpc/api/modules/index.ts b/src/rpc/api/modules/index.ts index c0bde283c951..c621d33a07cc 100644 --- a/src/rpc/api/modules/index.ts +++ b/src/rpc/api/modules/index.ts @@ -1,7 +1,5 @@ import {ValidatorApi} from "./validator"; -import {BeaconApi} from "./beacon"; export { ValidatorApi, - BeaconApi }; diff --git a/src/rpc/api/modules/validator.ts b/src/rpc/api/modules/validator.ts index 289c90cf3bc1..efc71259b650 100644 --- a/src/rpc/api/modules/validator.ts +++ b/src/rpc/api/modules/validator.ts @@ -1,6 +1,6 @@ import { Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data, uint64, - Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation + Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation, number64 } from "../../../types"; import {DB} from "../../../db"; import {BeaconChain} from "../../../chain"; @@ -23,15 +23,14 @@ export class ValidatorApi implements IValidatorApi { return Buffer.alloc(32); } - public async getFork(): Promise<{fork: Fork; chainId: uint64}> { + public async getFork(): Promise<{fork: Fork; chainId: number64}> { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as {fork: Fork; chainId: uint64}; + return {} as {fork: Fork; chainId: number64}; } - public async getGenesisTime(): Promise { - // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as uint64; - } + public async getGenesisTime(): Promise { + return await this.chain.genesisTime; + }s public async getSyncingStatus(): Promise { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion @@ -48,12 +47,16 @@ export class ValidatorApi implements IValidatorApi { return {} as BeaconBlock; } - public async produceAttestation(slot: Slot, shard: Shard): Promise { + public async produceAttestation(slot: Slot, shard: Shard): Promise { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as IndexedAttestation; + return {} as AttestationData; } - public async publishBlock(beaconBlock: BeaconBlock): Promise {} + public async publishBlock(block: BeaconBlock): Promise { + await this.chain.receiveBlock(block); + } - public async publishAttestation(indexedAttestation: IndexedAttestation): Promise {} + public async publishAttestation(attestation: Attestation): Promise { + await this.opPool.receiveAttestation(attestation); + } } diff --git a/src/rpc/protocol/jsonRpc.ts b/src/rpc/protocol/jsonRpc.ts index 3b13bd941364..9abe171f8157 100644 --- a/src/rpc/protocol/jsonRpc.ts +++ b/src/rpc/protocol/jsonRpc.ts @@ -1,7 +1,7 @@ import * as jsonRpc from "noice-json-rpc"; -import {IValidatorApi, IBeaconApi} from "../api"; +import {IValidatorApi} from "../api"; export interface LikeSocketServer extends jsonRpc.LikeSocketServer { start(): Promise; @@ -10,15 +10,13 @@ export interface LikeSocketServer extends jsonRpc.LikeSocketServer { /** * JSON-RPC over some transport - * - * */ export class JSONRPC { private rpcServer: jsonRpc.Server; private transport: LikeSocketServer; private jsonRpcApi; - public constructor(opts, {transport, api}: {transport: LikeSocketServer; api: IBeaconApi | IValidatorApi}) { + public constructor(opts, {transport, api}: {transport: LikeSocketServer; api: IValidatorApi}) { this.transport = transport; // attach the json-rpc server to underlying transport this.rpcServer = new jsonRpc.Server(this.transport); diff --git a/test/unit/rpc/jsonRpcOverHttp.test.ts b/test/unit/rpc/jsonRpcOverHttp.test.ts index 0f04eced4734..3cd76e063dd8 100644 --- a/test/unit/rpc/jsonRpcOverHttp.test.ts +++ b/test/unit/rpc/jsonRpcOverHttp.test.ts @@ -22,7 +22,7 @@ describe("Json RPC over http", () => { it("should get the chain head", (done) => { request.default(server) .post('/') - .send(generateRPCCall('BeaconChain.getChainHead', [])) + .send(generateRPCCall('BeaconChain.getFork', [])) .set('Accept', 'application/json') .expect('Content-Type', /json/) .expect(200) diff --git a/test/unit/rpc/jsonRpcOverWs.test.ts b/test/unit/rpc/jsonRpcOverWs.test.ts index b6f44c1236d9..8d1f22055331 100644 --- a/test/unit/rpc/jsonRpcOverWs.test.ts +++ b/test/unit/rpc/jsonRpcOverWs.test.ts @@ -1,7 +1,7 @@ import { assert } from "chai"; import * as jsonRpc from "noice-json-rpc"; import Websocket from "ws"; -import {MockAPI, JSONRPC, BeaconApi, WSServer} from "../../../src/rpc"; +import {MockAPI, JSONRPC, IValidatorApi, WSServer} from "../../../src/rpc"; import { generateEmptyBlock } from "../../utils/block"; import { generateEmptyAttestation } from "../../utils/attestation"; @@ -9,53 +9,56 @@ describe("Json RPC over WS", () => { const rpc = new JSONRPC({}, {transport: new WSServer({port: 32420}), api: new MockAPI()}); let client; let ws; - let clientApi: {BeaconChain: BeaconApi}; + let clientApi: {BeaconChain: IValidatorApi}; before(async () => { await rpc.start(); ws = new Websocket("ws://localhost:32420"); client = new jsonRpc.Client(ws); clientApi = client.api(); - }) + }); after(async () => { await rpc.stop(); - }) - it("should get the chain head", async () => { - const head = await clientApi.BeaconChain.getChainHead(); + }); + it("should get the chain version", async () => { + const head = await clientApi.BeaconChain.getClientVersion(); assert.ok(head); - }) - it("should get pending attestations", async () => { - const attestations = await clientApi.BeaconChain.getPendingAttestations(); + }); + it("should get the fork version", async () => { + const attestations = await clientApi.BeaconChain.getFork(); assert.ok(attestations); - }) - it("should get pending deposits", async () => { - const deposits = await clientApi.BeaconChain.getPendingDeposits(); + }); + it("should get the genesis time", async () => { + const deposits = await clientApi.BeaconChain.getGenesisTime(); assert.ok(deposits); - }) - it("should get eth1 data", async () => { - const eth1Data = await clientApi.BeaconChain.getEth1Data(); + }); + it("should get the sync status", async () => { + const eth1Data = await clientApi.BeaconChain.getSyncingStatus(); assert.ok(eth1Data); - }) - it("should compute the state root", async () => { - const root = await clientApi.BeaconChain.computeStateRoot(generateEmptyBlock()); + }); + it("should get validator duties", async () => { + const root = await clientApi.BeaconChain.getDuties([Buffer.alloc(48)]); assert.ok(root); - }) - it("should get attestation data", async () => { - const data = await clientApi.BeaconChain.getAttestationData(0, 0); + }); + it("should produce a block for the validator", async () => { + const data = await clientApi.BeaconChain.produceBlock(0, Buffer.alloc(0)); assert.ok(data); - }) + }); + it("should produce an attestation", async () => { + await clientApi.BeaconChain.produceAttestation(0,1); + assert.ok(true); + }); it("should accept an attestation submission", async () => { - await clientApi.BeaconChain.putAttestation(generateEmptyAttestation()); + await clientApi.BeaconChain.publishAttestation(generateEmptyAttestation()); assert.ok(true); - }) + }); it("should accept a block submission", async () => { - await clientApi.BeaconChain.putBlock(generateEmptyBlock()); + await clientApi.BeaconChain.publishBlock(generateEmptyBlock()); assert.ok(true); - }) + }); it("should fail for unknown methods", async () => { try { await (clientApi.BeaconChain as any).foo(); assert.fail('Unknown/undefined method should fail'); } catch (e) {} }) - }); From e0d1f4d7ea68a7162d237ab91b009e2616659b0e Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Thu, 2 May 2019 20:44:48 -0400 Subject: [PATCH 08/12] fix linter --- src/rpc/api/mock/validator.ts | 3 ++- src/rpc/api/modules/validator.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/rpc/api/mock/validator.ts b/src/rpc/api/mock/validator.ts index efe89e56f54f..ebc9041595f0 100644 --- a/src/rpc/api/mock/validator.ts +++ b/src/rpc/api/mock/validator.ts @@ -41,7 +41,8 @@ export class MockAPI implements IValidatorApi { } public async getDuties(validatorPubkeys: bytes48[]): Promise<{currentVersion: Fork; validatorDuties: ValidatorDuty[]}> { - return {} as {currentVersion: Fork; validatorDuties: ValidatorDuty[]}; + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as {currentVersion: Fork; validatorDuties: ValidatorDuty[]}; } public async produceBlock(slot: Slot, randaoReveal: bytes): Promise { diff --git a/src/rpc/api/modules/validator.ts b/src/rpc/api/modules/validator.ts index efc71259b650..f101551c81f4 100644 --- a/src/rpc/api/modules/validator.ts +++ b/src/rpc/api/modules/validator.ts @@ -30,7 +30,7 @@ export class ValidatorApi implements IValidatorApi { public async getGenesisTime(): Promise { return await this.chain.genesisTime; - }s + } public async getSyncingStatus(): Promise { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion From 488e06d8dc12d842fc3eb2270a3568b2b8d2288d Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Fri, 3 May 2019 19:41:35 -0400 Subject: [PATCH 09/12] update based on pr comments --- src/rpc/api/index.ts | 4 +-- src/rpc/api/interfaces/index.ts | 5 ---- src/rpc/api/{modules => validator}/index.ts | 2 ++ .../validator.ts => validator/interface.ts} | 10 ++++---- .../api/{modules => validator}/validator.ts | 14 +++++------ test/unit/rpc/jsonRpcOverHttp.test.ts | 7 +++--- test/unit/rpc/jsonRpcOverWs.test.ts | 7 +++--- .../utils/mocks/rpc}/validator.ts | 25 ++++++++++++------- 8 files changed, 39 insertions(+), 35 deletions(-) delete mode 100644 src/rpc/api/interfaces/index.ts rename src/rpc/api/{modules => validator}/index.ts (54%) rename src/rpc/api/{interfaces/validator.ts => validator/interface.ts} (88%) rename src/rpc/api/{modules => validator}/validator.ts (78%) rename {src/rpc/api/mock => test/utils/mocks/rpc}/validator.ts (67%) diff --git a/src/rpc/api/index.ts b/src/rpc/api/index.ts index f757ab1c5d80..c23d239883a8 100644 --- a/src/rpc/api/index.ts +++ b/src/rpc/api/index.ts @@ -1,3 +1 @@ -export * from "./interfaces"; -export * from "./mock/validator"; -export * from "./modules"; +export * from "./validator"; diff --git a/src/rpc/api/interfaces/index.ts b/src/rpc/api/interfaces/index.ts deleted file mode 100644 index 5677a4ad1fab..000000000000 --- a/src/rpc/api/interfaces/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {IValidatorApi} from "./validator"; - -export { - IValidatorApi -}; diff --git a/src/rpc/api/modules/index.ts b/src/rpc/api/validator/index.ts similarity index 54% rename from src/rpc/api/modules/index.ts rename to src/rpc/api/validator/index.ts index c621d33a07cc..3e45c3457afc 100644 --- a/src/rpc/api/modules/index.ts +++ b/src/rpc/api/validator/index.ts @@ -1,5 +1,7 @@ import {ValidatorApi} from "./validator"; +import {IValidatorApi} from "./interface"; export { ValidatorApi, + IValidatorApi }; diff --git a/src/rpc/api/interfaces/validator.ts b/src/rpc/api/validator/interface.ts similarity index 88% rename from src/rpc/api/interfaces/validator.ts rename to src/rpc/api/validator/interface.ts index 6b0107449b89..e8d232b60b7d 100644 --- a/src/rpc/api/interfaces/validator.ts +++ b/src/rpc/api/validator/interface.ts @@ -5,7 +5,7 @@ import { Attestation, AttestationData, BeaconBlock, bytes, bytes32, bytes48, Fork, IndexedAttestation, number64, Shard, Slot, SyncingStatus, uint64, ValidatorDuty -} from "../../../types"; +} from "../../../types/index"; export interface IValidatorApi { /** @@ -18,7 +18,7 @@ export interface IValidatorApi { * Requests the BeaconNode to provide which fork version it is currently on. * @returns {Promise<{fork: Fork; chainId: uint64}>} */ - getFork(): Promise<{fork: Fork; chainId: number64}>; + getFork(): Promise; /** * Requests the genesis_time parameter from the BeaconNode, which should be consistent across all BeaconNodes that follow the same beacon chain. @@ -34,10 +34,10 @@ export interface IValidatorApi { /** * Requests the BeaconNode to provide a set of “duties”, which are actions that should be performed by ValidatorClients. This API call should be polled at every slot, to ensure that any chain reorganisations are catered for, and to ensure that the currently connected BeaconNode is properly synchronised. - * @param {bytes48[]} validatorPubkeys - * @returns {Promise<{currentVersion: bytes4; validatorDuties: ValidatorDuty[]}>} A list of unique validator public keys, where each item is a 0x encoded hex string. + * @param {bytes48[]} validatorPubkey + * @returns {Promise<{currentVersion: bytes4; validatorDuty: ValidatorDuty}>} A list of unique validator public keys, where each item is a 0x encoded hex string. */ - getDuties(validatorPubkeys: bytes48[]): Promise<{currentVersion: Fork; validatorDuties: ValidatorDuty[]}>; + getDuties(validatorPubkey: bytes48): Promise<{currentVersion: Fork; validatorDuty: ValidatorDuty}>; /** * Requests a BeaconNode to produce a valid block, which can then be signed by a ValidatorClient. diff --git a/src/rpc/api/modules/validator.ts b/src/rpc/api/validator/validator.ts similarity index 78% rename from src/rpc/api/modules/validator.ts rename to src/rpc/api/validator/validator.ts index f101551c81f4..65dd22ffec77 100644 --- a/src/rpc/api/modules/validator.ts +++ b/src/rpc/api/validator/validator.ts @@ -1,12 +1,12 @@ import { Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data, uint64, - Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation, number64 + Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation, number64, BeaconState } from "../../../types"; import {DB} from "../../../db"; import {BeaconChain} from "../../../chain"; import {OpPool} from "../../../opPool"; -import {IValidatorApi} from "../interfaces"; +import {IValidatorApi} from "./interface"; export class ValidatorApi implements IValidatorApi { private chain: BeaconChain; @@ -23,9 +23,9 @@ export class ValidatorApi implements IValidatorApi { return Buffer.alloc(32); } - public async getFork(): Promise<{fork: Fork; chainId: number64}> { - // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as {fork: Fork; chainId: number64}; + public async getFork(): Promise { + const state: BeaconState = await this.db.getState(); + return state.fork; } public async getGenesisTime(): Promise { @@ -37,9 +37,9 @@ export class ValidatorApi implements IValidatorApi { return {} as boolean | SyncingStatus; } - public async getDuties(validatorPubkeys: bytes48[]): Promise<{currentVersion: Fork; validatorDuties: ValidatorDuty[]}> { + public async getDuties(validatorPubkey: bytes48): Promise<{currentVersion: Fork; validatorDuty: ValidatorDuty}> { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as {currentVersion: Fork; validatorDuties: ValidatorDuty[]}; + return {} as {currentVersion: Fork; validatorDuty: ValidatorDuty}; } public async produceBlock(slot: Slot, randaoReveal: bytes): Promise { diff --git a/test/unit/rpc/jsonRpcOverHttp.test.ts b/test/unit/rpc/jsonRpcOverHttp.test.ts index 3cd76e063dd8..2e17dfbab3ee 100644 --- a/test/unit/rpc/jsonRpcOverHttp.test.ts +++ b/test/unit/rpc/jsonRpcOverHttp.test.ts @@ -1,6 +1,7 @@ import {assert} from "chai"; import * as request from "supertest"; -import {JSONRPC, MockAPI} from "../../../src/rpc"; +import {JSONRPC} from "../../../src/rpc"; +import {MockValidatorApi} from "../../utils/mocks/rpc/validator"; import HttpServer from "../../../src/rpc/transport/http"; import {generateRPCCall} from "../../utils/rpcCall"; import logger from "../../../src/logger/winston"; @@ -12,7 +13,7 @@ describe("Json RPC over http", () => { logger.silent(true); const rpcServer = new HttpServer({port: 32421}); server = rpcServer.server; - rpc = new JSONRPC({}, {transport: rpcServer, api: new MockAPI()}); + rpc = new JSONRPC({}, {transport: rpcServer, api: new MockValidatorApi()}); await rpc.start(); }); after(async () => { @@ -60,7 +61,7 @@ describe("Json RPC over http", () => { }); }); it("should fail to start on existing port", (done) => { - const rpc = new JSONRPC({}, {transport: new HttpServer({port: 32421}), api: new MockAPI()}); + const rpc = new JSONRPC({}, {transport: new HttpServer({port: 32421}), api: new MockValidatorApi()}); rpc.start() .then(async () => { await rpc.stop(); diff --git a/test/unit/rpc/jsonRpcOverWs.test.ts b/test/unit/rpc/jsonRpcOverWs.test.ts index 8d1f22055331..85f20df971f1 100644 --- a/test/unit/rpc/jsonRpcOverWs.test.ts +++ b/test/unit/rpc/jsonRpcOverWs.test.ts @@ -1,12 +1,13 @@ import { assert } from "chai"; import * as jsonRpc from "noice-json-rpc"; import Websocket from "ws"; -import {MockAPI, JSONRPC, IValidatorApi, WSServer} from "../../../src/rpc"; +import {JSONRPC, IValidatorApi, WSServer} from "../../../src/rpc"; import { generateEmptyBlock } from "../../utils/block"; +import {MockValidatorApi} from "../../utils/mocks/rpc/validator"; import { generateEmptyAttestation } from "../../utils/attestation"; describe("Json RPC over WS", () => { - const rpc = new JSONRPC({}, {transport: new WSServer({port: 32420}), api: new MockAPI()}); + const rpc = new JSONRPC({}, {transport: new WSServer({port: 32420}), api: new MockValidatorApi()}); let client; let ws; let clientApi: {BeaconChain: IValidatorApi}; @@ -36,7 +37,7 @@ describe("Json RPC over WS", () => { assert.ok(eth1Data); }); it("should get validator duties", async () => { - const root = await clientApi.BeaconChain.getDuties([Buffer.alloc(48)]); + const root = await clientApi.BeaconChain.getDuties(Buffer.alloc(48)); assert.ok(root); }); it("should produce a block for the validator", async () => { diff --git a/src/rpc/api/mock/validator.ts b/test/utils/mocks/rpc/validator.ts similarity index 67% rename from src/rpc/api/mock/validator.ts rename to test/utils/mocks/rpc/validator.ts index ebc9041595f0..58e52bbd8453 100644 --- a/src/rpc/api/mock/validator.ts +++ b/test/utils/mocks/rpc/validator.ts @@ -1,19 +1,22 @@ -import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../types/index"; +import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../../src/types"; -import {getEmptyBlock} from "../../../chain/genesis"; +import {getEmptyBlock} from "../../../../src/chain/genesis"; -import {IValidatorApi} from "../interfaces/index"; -import {bytes, bytes48, Fork, number64, SyncingStatus, uint64, ValidatorDuty} from "../../../types"; +import {IValidatorApi} from "../../../../src/rpc/api/validator"; +import {bytes, bytes48, Fork, number64, SyncingStatus, uint64, ValidatorDuty} from "../../../../src/types"; export interface MockAPIOpts { head?: BeaconBlock; + version?: bytes32; + fork?: Fork; + chainId?: number64; pendingAttestations?: Attestation[]; getPendingDeposits?: Deposit[]; Eth1Data?: Eth1Data; attestationData?: AttestationData; } -export class MockAPI implements IValidatorApi { +export class MockValidatorApi implements IValidatorApi { private version: bytes32; private fork: Fork; private chainId: number64; @@ -22,13 +25,17 @@ export class MockAPI implements IValidatorApi { public constructor(opts?: MockAPIOpts) { this.attestations = opts && opts.pendingAttestations || []; this.head = opts && opts.head || getEmptyBlock(); + this.version = opts && opts.version || Buffer.alloc(0); + this.fork = opts && opts.fork || {previousVersion: Buffer.alloc(0), currentVersion: Buffer.alloc(0), epoch: 0} + this.chainId = opts && opts.chainId || 0; } + public async getClientVersion(): Promise { return this.version; } - public async getFork(): Promise<{fork: Fork; chainId: number64}> { - return {fork: this.fork, chainId: this.chainId}; + public async getFork(): Promise { + return this.fork; } public async getGenesisTime(): Promise { @@ -40,9 +47,9 @@ export class MockAPI implements IValidatorApi { return false; } - public async getDuties(validatorPubkeys: bytes48[]): Promise<{currentVersion: Fork; validatorDuties: ValidatorDuty[]}> { + public async getDuties(validatorPubkey: bytes48): Promise<{currentVersion: Fork; validatorDuty: ValidatorDuty}> { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion - return {} as {currentVersion: Fork; validatorDuties: ValidatorDuty[]}; + return {} as {currentVersion: Fork; validatorDuty: ValidatorDuty}; } public async produceBlock(slot: Slot, randaoReveal: bytes): Promise { From 5cd174b367af79191bbf276cede6090426c3b1b6 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Sat, 4 May 2019 12:46:01 -0400 Subject: [PATCH 10/12] add single api namespacing --- src/rpc/api/interface.ts | 7 +++ src/rpc/api/validator/interface.ts | 3 +- src/rpc/api/validator/validator.ts | 2 + src/rpc/protocol/jsonRpc.ts | 2 +- .../{ => validator}/jsonRpcOverHttp.test.ts | 16 +++---- .../rpc/{ => validator}/jsonRpcOverWs.test.ts | 44 +++++++++---------- test/utils/mocks/rpc/validator.ts | 2 + 7 files changed, 44 insertions(+), 32 deletions(-) create mode 100644 src/rpc/api/interface.ts rename test/unit/rpc/{ => validator}/jsonRpcOverHttp.test.ts (81%) rename test/unit/rpc/{ => validator}/jsonRpcOverWs.test.ts (50%) diff --git a/src/rpc/api/interface.ts b/src/rpc/api/interface.ts new file mode 100644 index 000000000000..4df21dc7ec2f --- /dev/null +++ b/src/rpc/api/interface.ts @@ -0,0 +1,7 @@ +export interface IApi { + /** + * Name space for API commands + */ + namespace: string; +} + diff --git a/src/rpc/api/validator/interface.ts b/src/rpc/api/validator/interface.ts index e8d232b60b7d..919c95fd7839 100644 --- a/src/rpc/api/validator/interface.ts +++ b/src/rpc/api/validator/interface.ts @@ -6,8 +6,9 @@ import { BeaconBlock, bytes, bytes32, bytes48, Fork, IndexedAttestation, number64, Shard, Slot, SyncingStatus, uint64, ValidatorDuty } from "../../../types/index"; +import {IApi} from "../interface"; -export interface IValidatorApi { +export interface IValidatorApi extends IApi { /** * Requests that the BeaconNode identify information about its implementation in a format similar to a HTTP User-Agent field. * @returns {Promise} An ASCII-encoded hex string which uniquely defines the implementation of the BeaconNode and its current software version. diff --git a/src/rpc/api/validator/validator.ts b/src/rpc/api/validator/validator.ts index 65dd22ffec77..3a60d705f18c 100644 --- a/src/rpc/api/validator/validator.ts +++ b/src/rpc/api/validator/validator.ts @@ -9,11 +9,13 @@ import {OpPool} from "../../../opPool"; import {IValidatorApi} from "./interface"; export class ValidatorApi implements IValidatorApi { + public namespace: string; private chain: BeaconChain; private db: DB; private opPool: OpPool; public constructor(opts, {chain, db, opPool}) { + this.namespace = "validator"; this.chain = chain; this.db = db; this.opPool = opPool; diff --git a/src/rpc/protocol/jsonRpc.ts b/src/rpc/protocol/jsonRpc.ts index 9abe171f8157..3b18918b5e07 100644 --- a/src/rpc/protocol/jsonRpc.ts +++ b/src/rpc/protocol/jsonRpc.ts @@ -28,7 +28,7 @@ export class JSONRPC { methods[name] = api[name].bind(api); } } - this.jsonRpcApi.BeaconChain.expose(methods); + this.jsonRpcApi[api.namespace].expose(methods); } public async start(): Promise { diff --git a/test/unit/rpc/jsonRpcOverHttp.test.ts b/test/unit/rpc/validator/jsonRpcOverHttp.test.ts similarity index 81% rename from test/unit/rpc/jsonRpcOverHttp.test.ts rename to test/unit/rpc/validator/jsonRpcOverHttp.test.ts index 2e17dfbab3ee..28bb95f93e1a 100644 --- a/test/unit/rpc/jsonRpcOverHttp.test.ts +++ b/test/unit/rpc/validator/jsonRpcOverHttp.test.ts @@ -1,10 +1,10 @@ import {assert} from "chai"; import * as request from "supertest"; -import {JSONRPC} from "../../../src/rpc"; -import {MockValidatorApi} from "../../utils/mocks/rpc/validator"; -import HttpServer from "../../../src/rpc/transport/http"; -import {generateRPCCall} from "../../utils/rpcCall"; -import logger from "../../../src/logger/winston"; +import {JSONRPC} from "../../../../src/rpc/index"; +import {MockValidatorApi} from "../../../utils/mocks/rpc/validator"; +import HttpServer from "../../../../src/rpc/transport/http"; +import {generateRPCCall} from "../../../utils/rpcCall"; +import logger from "../../../../src/logger/winston"; describe("Json RPC over http", () => { let rpc; @@ -20,10 +20,10 @@ describe("Json RPC over http", () => { await rpc.stop(); logger.silent(false); }); - it("should get the chain head", (done) => { + it("should get the version", (done) => { request.default(server) .post('/') - .send(generateRPCCall('BeaconChain.getFork', [])) + .send(generateRPCCall('validator.getFork', [])) .set('Accept', 'application/json') .expect('Content-Type', /json/) .expect(200) @@ -38,7 +38,7 @@ describe("Json RPC over http", () => { it("should fail for unknown methods", (done) => { request.default(server) .post('/') - .send(generateRPCCall('BeaconChain.notExistingMethod', [])) + .send(generateRPCCall('validator.notExistingMethod', [])) .set('Accept', 'application/json') .expect('Content-Type', /json/) .expect(200) diff --git a/test/unit/rpc/jsonRpcOverWs.test.ts b/test/unit/rpc/validator/jsonRpcOverWs.test.ts similarity index 50% rename from test/unit/rpc/jsonRpcOverWs.test.ts rename to test/unit/rpc/validator/jsonRpcOverWs.test.ts index 85f20df971f1..152bdc1a6e68 100644 --- a/test/unit/rpc/jsonRpcOverWs.test.ts +++ b/test/unit/rpc/validator/jsonRpcOverWs.test.ts @@ -1,16 +1,16 @@ import { assert } from "chai"; import * as jsonRpc from "noice-json-rpc"; import Websocket from "ws"; -import {JSONRPC, IValidatorApi, WSServer} from "../../../src/rpc"; -import { generateEmptyBlock } from "../../utils/block"; -import {MockValidatorApi} from "../../utils/mocks/rpc/validator"; -import { generateEmptyAttestation } from "../../utils/attestation"; +import {JSONRPC, IValidatorApi, WSServer} from "../../../../src/rpc/index"; +import { generateEmptyBlock } from "../../../utils/block"; +import {MockValidatorApi} from "../../../utils/mocks/rpc/validator"; +import { generateEmptyAttestation } from "../../../utils/attestation"; describe("Json RPC over WS", () => { const rpc = new JSONRPC({}, {transport: new WSServer({port: 32420}), api: new MockValidatorApi()}); let client; let ws; - let clientApi: {BeaconChain: IValidatorApi}; + let clientApi: {validator: IValidatorApi}; before(async () => { await rpc.start(); ws = new Websocket("ws://localhost:32420"); @@ -20,45 +20,45 @@ describe("Json RPC over WS", () => { after(async () => { await rpc.stop(); }); - it("should get the chain version", async () => { - const head = await clientApi.BeaconChain.getClientVersion(); - assert.ok(head); + it("should get the client version", async () => { + const version = await clientApi.validator.getClientVersion(); + assert.ok(version); }); it("should get the fork version", async () => { - const attestations = await clientApi.BeaconChain.getFork(); - assert.ok(attestations); + const fork = await clientApi.validator.getFork(); + assert.ok(fork); }); it("should get the genesis time", async () => { - const deposits = await clientApi.BeaconChain.getGenesisTime(); - assert.ok(deposits); + const time = await clientApi.validator.getGenesisTime(); + assert.ok(time); }); it("should get the sync status", async () => { - const eth1Data = await clientApi.BeaconChain.getSyncingStatus(); - assert.ok(eth1Data); + const status = await clientApi.validator.getSyncingStatus(); + assert.ok(status); }); it("should get validator duties", async () => { - const root = await clientApi.BeaconChain.getDuties(Buffer.alloc(48)); - assert.ok(root); + const duties = await clientApi.validator.getDuties(Buffer.alloc(48)); + assert.ok(duties); }); it("should produce a block for the validator", async () => { - const data = await clientApi.BeaconChain.produceBlock(0, Buffer.alloc(0)); - assert.ok(data); + const block = await clientApi.validator.produceBlock(0, Buffer.alloc(0)); + assert.ok(block); }); it("should produce an attestation", async () => { - await clientApi.BeaconChain.produceAttestation(0,1); + await clientApi.validator.produceAttestation(0,1); assert.ok(true); }); it("should accept an attestation submission", async () => { - await clientApi.BeaconChain.publishAttestation(generateEmptyAttestation()); + await clientApi.validator.publishAttestation(generateEmptyAttestation()); assert.ok(true); }); it("should accept a block submission", async () => { - await clientApi.BeaconChain.publishBlock(generateEmptyBlock()); + await clientApi.validator.publishBlock(generateEmptyBlock()); assert.ok(true); }); it("should fail for unknown methods", async () => { try { - await (clientApi.BeaconChain as any).foo(); + await (clientApi.validator as any).foo(); assert.fail('Unknown/undefined method should fail'); } catch (e) {} }) diff --git a/test/utils/mocks/rpc/validator.ts b/test/utils/mocks/rpc/validator.ts index 58e52bbd8453..0ee4bf1f2996 100644 --- a/test/utils/mocks/rpc/validator.ts +++ b/test/utils/mocks/rpc/validator.ts @@ -17,12 +17,14 @@ export interface MockAPIOpts { } export class MockValidatorApi implements IValidatorApi { + public namespace: string; private version: bytes32; private fork: Fork; private chainId: number64; private attestations; private head: BeaconBlock; public constructor(opts?: MockAPIOpts) { + this.namespace = "validator"; this.attestations = opts && opts.pendingAttestations || []; this.head = opts && opts.head || getEmptyBlock(); this.version = opts && opts.version || Buffer.alloc(0); From b551fc4c10273b807a78576ed730a43d3210479d Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Sat, 4 May 2019 18:22:59 -0400 Subject: [PATCH 11/12] move vlaidator assingments into chain module --- src/chain/stateTransition/util/validator.ts | 62 ++++++++++++++++- src/validator/utils/assignments.ts | 76 --------------------- 2 files changed, 61 insertions(+), 77 deletions(-) delete mode 100644 src/validator/utils/assignments.ts diff --git a/src/chain/stateTransition/util/validator.ts b/src/chain/stateTransition/util/validator.ts index 52b542ed46de..b0e025db9931 100644 --- a/src/chain/stateTransition/util/validator.ts +++ b/src/chain/stateTransition/util/validator.ts @@ -1,9 +1,14 @@ +import assert from "assert"; import { BeaconState, - Epoch, + Epoch, Slot, Validator, ValidatorIndex, } from "../../../types"; +import {getBeaconProposerIndex, getCrosslinkCommitteesAtSlot, getPreviousEpoch, slotToEpoch} from "./index"; +import {CommitteeAssignment} from "../../../validator/types"; +import {getCurrentEpoch, getEpochStartSlot} from "./epoch"; +import {SLOTS_PER_EPOCH} from "../../../constants"; /** @@ -44,3 +49,58 @@ export function getActiveValidatorIndices(state: BeaconState, epoch: Epoch): Val return indices; }, []); } + +/** + * Return the committee assignment in the ``epoch`` for ``validator_index`` and ``registry_change``. + * ``assignment`` returned is a tuple of the following form: + * ``assignment[0]`` is the list of validators in the committee + * ``assignment[1]`` is the shard to which the committee is assigned + * ``assignment[2]`` is the slot at which the committee is assigned + * a beacon block at the assigned slot. + * @param {BeaconState} state + * @param {Epoch} epoch + * @param {ValidatorIndex} validatorIndex + * @param {boolean} registryChange + * @returns {{validators: ValidatorIndex[]; shard: Shard; slot: number; isProposer: boolean}} + */ +export function getCommitteeAssignment( + state: BeaconState, + epoch: Epoch, + validatorIndex: ValidatorIndex): CommitteeAssignment { + + const previousEpoch = getPreviousEpoch(state); + const nextEpoch = getCurrentEpoch(state) + 1; + assert(previousEpoch <= epoch && epoch <= nextEpoch); + + const epochStartSlot = getEpochStartSlot(epoch); + const loopEnd = epochStartSlot + SLOTS_PER_EPOCH; + + for (let slot = epochStartSlot; slot < loopEnd; slot++) { + const crosslinkCommittees = getCrosslinkCommitteesAtSlot(state, slot); + const selectedCommittees = crosslinkCommittees.map((committee) => committee[0].includes(validatorIndex)); + + if (selectedCommittees.length > 0) { + const validators = selectedCommittees[0][0]; + const shard = selectedCommittees[0][1]; + return {validators, shard, slot}; + } + } +} + +/** + * Checks if a validator is supposed to propose a block + * @param {BeaconState} state + * @param {Slot} slot + * @param {ValidatorIndex} validatorIndex + * @returns {Boolean} + */ +export function isProposerAtSlot( + state: BeaconState, + slot: Slot, + validatorIndex: ValidatorIndex): boolean { + + const currentEpoch = getCurrentEpoch(state); + assert(slotToEpoch(slot) === currentEpoch); + + return getBeaconProposerIndex(state) === validatorIndex; +} diff --git a/src/validator/utils/assignments.ts b/src/validator/utils/assignments.ts deleted file mode 100644 index 2bca2e1b80c2..000000000000 --- a/src/validator/utils/assignments.ts +++ /dev/null @@ -1,76 +0,0 @@ -import assert from "assert"; - -import { - BeaconState, Epoch, Slot, - ValidatorIndex, -} from "../../types"; - -import { - SLOTS_PER_EPOCH, -} from "../../constants"; - -import { - getBeaconProposerIndex, getCrosslinkCommitteesAtSlot, - getCurrentEpoch, - getPreviousEpoch, - getEpochStartSlot, - slotToEpoch, -} from "../../chain/stateTransition/util"; - -import {CommitteeAssignment} from "../types"; - - -/** - * Return the committee assignment in the ``epoch`` for ``validator_index`` and ``registry_change``. - * ``assignment`` returned is a tuple of the following form: - * ``assignment[0]`` is the list of validators in the committee - * ``assignment[1]`` is the shard to which the committee is assigned - * ``assignment[2]`` is the slot at which the committee is assigned - * a beacon block at the assigned slot. - * @param {BeaconState} state - * @param {Epoch} epoch - * @param {ValidatorIndex} validatorIndex - * @param {boolean} registryChange - * @returns {{validators: ValidatorIndex[]; shard: Shard; slot: number; isProposer: boolean}} - */ -export function getCommitteeAssignment( - state: BeaconState, - epoch: Epoch, - validatorIndex: ValidatorIndex): CommitteeAssignment { - - const previousEpoch = getPreviousEpoch(state); - const nextEpoch = getCurrentEpoch(state) + 1; - assert(previousEpoch <= epoch && epoch <= nextEpoch); - - const epochStartSlot = getEpochStartSlot(epoch); - const loopEnd = epochStartSlot + SLOTS_PER_EPOCH; - - for (let slot = epochStartSlot; slot < loopEnd; slot++) { - const crosslinkCommittees = getCrosslinkCommitteesAtSlot(state, slot); - const selectedCommittees = crosslinkCommittees.map((committee) => committee[0].includes(validatorIndex)); - - if (selectedCommittees.length > 0) { - const validators = selectedCommittees[0][0]; - const shard = selectedCommittees[0][1]; - return {validators, shard, slot}; - } - } -} - -/** - * Checks if a validator is supposed to propose a block - * @param {BeaconState} state - * @param {Slot} slot - * @param {ValidatorIndex} validatorIndex - * @returns {Boolean} - */ -export function isProposerAtSlot( - state: BeaconState, - slot: Slot, - validatorIndex: ValidatorIndex): boolean { - - const currentEpoch = getCurrentEpoch(state); - assert(slotToEpoch(slot) === currentEpoch); - - return getBeaconProposerIndex(state) === validatorIndex; -} From 15ee2f3d52adad591d3fd81b4520a15a5f1111f0 Mon Sep 17 00:00:00 2001 From: Gregory Markou Date: Sat, 4 May 2019 19:25:27 -0400 Subject: [PATCH 12/12] seperated validator duties --- src/chain/index.ts | 2 +- src/rpc/api/validator/interface.ts | 20 ++++++++++++++++++-- src/rpc/api/validator/validator.ts | 14 +++++++++++++- test/utils/mocks/rpc/validator.ts | 16 +++++++++++++++- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/chain/index.ts b/src/chain/index.ts index 125869af78a8..0eee2e5cbd71 100644 --- a/src/chain/index.ts +++ b/src/chain/index.ts @@ -2,7 +2,7 @@ import assert from "assert"; import {EventEmitter} from "events"; import {hashTreeRoot} from "@chainsafe/ssz"; -import {BeaconBlock, BeaconState, Deposit, Eth1Data, number64} from "../types"; +import {BeaconBlock, BeaconState, bytes48, Deposit, Epoch, Eth1Data, number64, Slot, ValidatorIndex} from "../types"; import {GENESIS_SLOT, SECONDS_PER_SLOT} from "../constants"; import {DB} from "../db"; diff --git a/src/rpc/api/validator/interface.ts b/src/rpc/api/validator/interface.ts index 919c95fd7839..eb59abe8aed8 100644 --- a/src/rpc/api/validator/interface.ts +++ b/src/rpc/api/validator/interface.ts @@ -3,10 +3,11 @@ */ import { Attestation, AttestationData, - BeaconBlock, bytes, bytes32, bytes48, Fork, IndexedAttestation, number64, Shard, Slot, SyncingStatus, uint64, - ValidatorDuty + BeaconBlock, bytes, bytes32, bytes48, Epoch, Fork, IndexedAttestation, number64, Shard, Slot, SyncingStatus, uint64, + ValidatorDuty, ValidatorIndex } from "../../../types/index"; import {IApi} from "../interface"; +import {CommitteeAssignment} from "../../../validator/types"; export interface IValidatorApi extends IApi { /** @@ -40,6 +41,21 @@ export interface IValidatorApi extends IApi { */ getDuties(validatorPubkey: bytes48): Promise<{currentVersion: Fork; validatorDuty: ValidatorDuty}>; + /** + * Requests to check if a validator should propose for a given slot. + * @param {bytes48} validatorPubkey + * @param {Slot} slot + * @returns {Promise<{slot: Slot, proposer: boolean}} + */ + isProposer(index: ValidatorIndex, slot: Slot): Promise; + + /** + * Requests a validators committeeAssignment, can be used for past, current and one epoch in the future + * @param {ValidatorIndex} index + * @param {Epoch} epoch + */ + getCommitteeAssignment(index: ValidatorIndex, epoch: Epoch): Promise; + /** * Requests a BeaconNode to produce a valid block, which can then be signed by a ValidatorClient. * @param {Slot} slot diff --git a/src/rpc/api/validator/validator.ts b/src/rpc/api/validator/validator.ts index 3a60d705f18c..1bc94c8d573d 100644 --- a/src/rpc/api/validator/validator.ts +++ b/src/rpc/api/validator/validator.ts @@ -1,12 +1,14 @@ import { Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data, uint64, - Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation, number64, BeaconState + Fork, SyncingStatus, ValidatorDuty, bytes48, bytes, IndexedAttestation, number64, BeaconState, ValidatorIndex, Epoch } from "../../../types"; import {DB} from "../../../db"; import {BeaconChain} from "../../../chain"; import {OpPool} from "../../../opPool"; import {IValidatorApi} from "./interface"; +import {getCommitteeAssignment, isProposerAtSlot} from "../../../chain/stateTransition/util"; +import {CommitteeAssignment} from "../../../validator/types"; export class ValidatorApi implements IValidatorApi { public namespace: string; @@ -49,6 +51,16 @@ export class ValidatorApi implements IValidatorApi { return {} as BeaconBlock; } + public async isProposer(index: ValidatorIndex, slot: Slot): Promise { + const state: BeaconState = await this.db.getState(); + return isProposerAtSlot(state, slot, index); + } + + public async getCommitteeAssignment(index: ValidatorIndex, epoch: Epoch): Promise { + const state: BeaconState = await this.db.getState(); + return getCommitteeAssignment(state, epoch, index); + } + public async produceAttestation(slot: Slot, shard: Shard): Promise { // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion return {} as AttestationData; diff --git a/test/utils/mocks/rpc/validator.ts b/test/utils/mocks/rpc/validator.ts index 0ee4bf1f2996..4b0bd1b65943 100644 --- a/test/utils/mocks/rpc/validator.ts +++ b/test/utils/mocks/rpc/validator.ts @@ -1,9 +1,14 @@ -import {Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data} from "../../../../src/types"; +import { + Attestation, AttestationData, BeaconBlock, bytes32, Deposit, Shard, Slot, Eth1Data, + BeaconState, ValidatorIndex, Epoch +} from "../../../../src/types"; import {getEmptyBlock} from "../../../../src/chain/genesis"; import {IValidatorApi} from "../../../../src/rpc/api/validator"; import {bytes, bytes48, Fork, number64, SyncingStatus, uint64, ValidatorDuty} from "../../../../src/types"; +import {getCommitteeAssignment, isProposerAtSlot} from "../../../../src/chain/stateTransition/util"; +import {CommitteeAssignment} from "../../../../src/validator/types"; export interface MockAPIOpts { head?: BeaconBlock; @@ -64,6 +69,15 @@ export class MockValidatorApi implements IValidatorApi { return {} as AttestationData; } + public async isProposer(index: ValidatorIndex, slot: Slot): Promise { + return true; + } + + public async getCommitteeAssignment(index: ValidatorIndex, epoch: Epoch): Promise { + // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion + return {} as CommitteeAssignment; + } + public async publishBlock(block: BeaconBlock): Promise { this.head = block; }