From a0e7e070b5aac2b32afc1d6627f2afce1bdcdd8e Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 9 Dec 2020 14:22:49 +0100 Subject: [PATCH 01/19] implement new eth2 client --- src/renderer/ducks/validator/sagas.ts | 23 +++-- .../eth2/client/eth2ApiClient/beacon/index.ts | 83 +++++++++++++++++++ .../eth2/client/eth2ApiClient/events.ts | 18 ++++ .../eth2/client/eth2ApiClient/index.ts | 43 ++++++++++ .../eth2/client/eth2ApiClient/nodeApi.ts | 23 +++++ .../eth2/client/eth2ApiClient/validator.tsx | 72 ++++++++++++++++ 6 files changed, 254 insertions(+), 8 deletions(-) create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/events.ts create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/index.ts create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/validator.tsx diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index fd6a8aa8..c2f3438c 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -40,6 +40,9 @@ import {getAuthAccount} from "../auth/selectors"; import {getBeaconNodes} from "../network/selectors"; import {getValidators} from "./selectors"; import {ValidatorBeaconNodes} from "../../models/validatorBeaconNodes"; +import {Eth2ApiClient} from "../../services/eth2/client/eth2ApiClient"; +import { HttpClient } from "../../services/api"; +import {WinstonLogger} from "@chainsafe/lodestar-utils"; interface IValidatorServices { [validatorAddress: string]: Validator; @@ -153,19 +156,23 @@ function* loadValidatorStatusSaga( function* startService( action: ReturnType, -): Generator, void, IValidatorBeaconNodes> { - const logger = new ValidatorLogger(); - const validatorBeaconNodes = yield select(getBeaconNodes); +): Generator, void> { const publicKey = action.payload.publicKey.toHex(); // TODO: Use beacon chain proxy instead of first node - const eth2API = validatorBeaconNodes[publicKey][0].client; + const eth2API = new Eth2ApiClient(config, "http://localhost:5052"); + const slashingProtection = new SlashingProtection({ + config, + controller: cgDbController, + }); + + // @ts-ignore + console.log(eth2API, slashingProtection); + + const logger = new WinstonLogger(); if (!validatorServices[publicKey]) { validatorServices[publicKey] = new Validator({ - slashingProtection: new SlashingProtection({ - config, - controller: cgDbController, - }), + slashingProtection, api: eth2API, config, secretKeys: [action.payload.privateKey], diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts new file mode 100644 index 00000000..7fbdb0dd --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts @@ -0,0 +1,83 @@ +import {ICGEth2BeaconApi} from "../../interface"; +import {IBeaconBlocksApi, IBeaconPoolApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import { + Attestation, + BeaconBlock, + BeaconState, + BLSPubkey, + Fork, + Genesis, + SignedBeaconBlock, + SignedBeaconHeaderResponse, + ValidatorIndex, + ValidatorResponse, +} from "@chainsafe/lodestar-types"; +import {HttpClient} from "../../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; + +export class Beacon implements ICGEth2BeaconApi { + public blocks: IBeaconBlocksApi = { + publishBlock: async (block: SignedBeaconBlock): Promise => { + console.log("publishBlock", block); + }, + }; + public pool: IBeaconPoolApi = { + submitAttestation: async (attestation: Attestation): Promise => { + console.log("submitAttestation", attestation); + }, + }; + public state: ICGEth2BeaconApi["state"] = { + getFork: async (stateId: "head"): Promise => { + console.log("getFork", stateId); + return null; + }, + getStateValidator: async ( + stateId: "head", + validatorId: ValidatorIndex | BLSPubkey, + ): Promise => { + console.log("getStateValidator", stateId, validatorId); + return null; + }, + getBlockHeader: async ( + stateId: "head", + blockId: "head" | number | string, + ): Promise => { + console.log("getBlockHeader", stateId, blockId); + return undefined as SignedBeaconHeaderResponse; + }, + getValidator: async ( + stateId: "head", + validatorId: string | BLSPubkey | ValidatorIndex, + ): Promise => { + console.log("getValidator", stateId, validatorId); + return undefined as ValidatorResponse; + }, + getValidators: async ( + stateId?: "head", + validatorIds?: (string | ValidatorIndex)[], + ): Promise => { + console.log("getValidators", stateId, validatorIds); + return undefined as ValidatorResponse[]; + }, + }; + + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + } + + public getGenesis = async (): Promise => { + console.log("getGenesis"); + return null; + }; + + public getChainHead = async (): Promise => { + throw new Error("Method 'getChainHead' not implemented."); + }; + + public getBeaconState = async (): Promise => { + throw new Error("Method 'getBeaconState' not implemented."); + }; +} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/events.ts b/src/renderer/services/eth2/client/eth2ApiClient/events.ts new file mode 100644 index 00000000..82fcee20 --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/events.ts @@ -0,0 +1,18 @@ +import {BeaconEvent, BeaconEventType, IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; +import {IStoppableEventIterable} from "@chainsafe/lodestar-utils"; +import {HttpClient} from "../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; + +export class Events implements IEventsApi { + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + } + + public getEventStream = (topics: BeaconEventType[]): IStoppableEventIterable => { + console.log("getEventStream", topics); + return undefined as IStoppableEventIterable; + }; +} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/index.ts new file mode 100644 index 00000000..09894a32 --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/index.ts @@ -0,0 +1,43 @@ +import {ICGEth2ValidatorApi, IValidatorBeaconClient, ICGEth2BeaconApi, ICGEth2NodeApi} from "../interface"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; +import {IEth2ChainHead} from "../../../../models/types/head"; +import {Beacon} from "./beacon"; +import {HttpClient} from "../../../api"; +import {AbstractApiClient} from "@chainsafe/lodestar-validator/lib/api/abstract"; +import {WinstonLogger} from "@chainsafe/lodestar-utils"; +import {Validator} from "./validator"; +import {NodeApi} from "./nodeApi"; +import {Events} from "./events"; + +export class Eth2ApiClient extends AbstractApiClient implements IValidatorBeaconClient { + public validator: ICGEth2ValidatorApi; + public beacon: ICGEth2BeaconApi; // + public node: ICGEth2NodeApi; + public events: IEventsApi; + + public url: string; + + private readonly httpClient: HttpClient; + public constructor(config: IBeaconConfig, url: string) { + // TODO: logger: create new or get it from outside? + super(config, new WinstonLogger()); + this.url = url; + this.httpClient = new HttpClient(url); + + this.validator = new Validator(config, this.httpClient); + this.beacon = new Beacon(config, this.httpClient); + this.events = new Events(config, this.httpClient); + this.node = new NodeApi(config, this.httpClient); + } + + public getVersion = async (): Promise => { + console.log("getVersion"); + return undefined as string; + }; + + public onNewChainHead = (callback: (head: IEth2ChainHead) => void): NodeJS.Timeout => { + console.log("onNewChainHead", callback); + return undefined as NodeJS.Timeout; + }; +} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts new file mode 100644 index 00000000..a5b3cd6c --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts @@ -0,0 +1,23 @@ +import {ICGEth2NodeApi} from "../interface"; +import {HttpClient} from "../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {SyncingStatus} from "@chainsafe/lodestar-types"; + +export class NodeApi implements ICGEth2NodeApi { + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + } + + public getSyncingStatus = async (): Promise => { + console.log("getSyncingStatus"); + return undefined as SyncingStatus; + }; + + public getVersion = async (): Promise => { + console.log("getVersion"); + return undefined as string; + }; +} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx b/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx new file mode 100644 index 00000000..8c52507c --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx @@ -0,0 +1,72 @@ +import {ICGEth2ValidatorApi} from "../interface"; +import { + Attestation, + AttestationData, + AttesterDuty, + BeaconBlock, + BLSPubkey, + CommitteeIndex, + Epoch, + ProposerDuty, + Root, + SignedAggregateAndProof, + Slot, + ValidatorIndex, +} from "@chainsafe/lodestar-types"; +import {HttpClient} from "../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; + +export class Validator implements ICGEth2ValidatorApi { + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + } + + public getAggregatedAttestation = async (attestationDataRoot: Root, slot: Slot): Promise => { + console.log("getAggregatedAttestation", attestationDataRoot, slot); + return undefined as Attestation; + }; + + public getAttesterDuties = async (epoch: Epoch, validatorPubKeys: ValidatorIndex[]): Promise => { + console.log("getAttesterDuties", epoch, validatorPubKeys); + return undefined as AttesterDuty[]; + }; + + public getProposerDuties = async (epoch: Epoch, validatorPubKeys: BLSPubkey[]): Promise => { + console.log("getProposerDuties", epoch, validatorPubKeys); + return undefined as ProposerDuty[]; + }; + + public prepareBeaconCommitteeSubnet = async ( + validatorIndex: ValidatorIndex, + committeeIndex: CommitteeIndex, + committeesAtSlot: number, + slot: Slot, + isAggregator: boolean, + ): Promise => { + console.log( + "prepareBeaconCommitteeSubnet", + validatorIndex, + committeeIndex, + committeesAtSlot, + slot, + isAggregator, + ); + }; + + public produceAttestationData = async (index: CommitteeIndex, slot: Slot): Promise => { + console.log("produceAttestationData", index, slot); + return undefined as AttestationData; + }; + + public produceBlock = async (slot: Slot, randaoReveal: Uint8Array, graffiti: string): Promise => { + console.log("produceBlock", slot, randaoReveal, graffiti); + return undefined as BeaconBlock; + }; + + public publishAggregateAndProofs = async (signedAggregateAndProofs: SignedAggregateAndProof[]): Promise => { + console.log("publishAggregateAndProofs", signedAggregateAndProofs); + }; +} From 5b545a23b326a43b6baf09f089106c8de98cfc82 Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 9 Dec 2020 15:57:26 +0100 Subject: [PATCH 02/19] implement validator rest methods --- .../eth2/client/eth2ApiClient/validator.tsx | 72 +++++++++++++------ 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx b/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx index 8c52507c..3a9f5550 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx +++ b/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx @@ -4,7 +4,6 @@ import { AttestationData, AttesterDuty, BeaconBlock, - BLSPubkey, CommitteeIndex, Epoch, ProposerDuty, @@ -15,6 +14,8 @@ import { } from "@chainsafe/lodestar-types"; import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {Json, toHexString} from "@chainsafe/ssz"; +import querystring from "querystring"; export class Validator implements ICGEth2ValidatorApi { private readonly httpClient: HttpClient; @@ -25,18 +26,29 @@ export class Validator implements ICGEth2ValidatorApi { } public getAggregatedAttestation = async (attestationDataRoot: Root, slot: Slot): Promise => { - console.log("getAggregatedAttestation", attestationDataRoot, slot); - return undefined as Attestation; + const query = querystring.stringify({ + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + attestation_data_root: this.config.types.Root.toJson(attestationDataRoot) as string, + slot, + }); + const url = `/eth/v1/validator/aggregate_attestation?${query}`; + const responseData = await this.httpClient.get<{data: Json[]}>(url); + return this.config.types.Attestation.fromJson(responseData.data, {case: "snake"}); }; public getAttesterDuties = async (epoch: Epoch, validatorPubKeys: ValidatorIndex[]): Promise => { - console.log("getAttesterDuties", epoch, validatorPubKeys); - return undefined as AttesterDuty[]; + const url = `/eth/v1/validator/duties/attester/${epoch.toString()}`; + const responseData = await this.httpClient.post( + url, + validatorPubKeys.map((index) => this.config.types.ValidatorIndex.toJson(index) as string), + ); + return responseData.data.map((value) => this.config.types.AttesterDuty.fromJson(value, {case: "snake"})); }; - public getProposerDuties = async (epoch: Epoch, validatorPubKeys: BLSPubkey[]): Promise => { - console.log("getProposerDuties", epoch, validatorPubKeys); - return undefined as ProposerDuty[]; + public getProposerDuties = async (epoch: Epoch): Promise => { + const url = `/eth/v1/validator/duties/proposer/${epoch.toString()}`; + const responseData = await this.httpClient.get<{data: Json[]}>(url); + return responseData.data.map((value) => this.config.types.ProposerDuty.fromJson(value, {case: "snake"})); }; public prepareBeaconCommitteeSubnet = async ( @@ -46,27 +58,45 @@ export class Validator implements ICGEth2ValidatorApi { slot: Slot, isAggregator: boolean, ): Promise => { - console.log( - "prepareBeaconCommitteeSubnet", - validatorIndex, - committeeIndex, - committeesAtSlot, - slot, - isAggregator, - ); + await this.httpClient.post("/beacon_committee_subscriptions", [ + { + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + validator_index: validatorIndex, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committee_index: committeeIndex, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committees_at_slot: committeesAtSlot, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + is_aggregator: isAggregator, + slot, + }, + ]); }; public produceAttestationData = async (index: CommitteeIndex, slot: Slot): Promise => { - console.log("produceAttestationData", index, slot); - return undefined as AttestationData; + const query = querystring.stringify({ + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committee_index: index, + slot, + }); + const responseData = await this.httpClient.get<{data: Json[]}>(`/eth/v1/validator/attestation_data?${query}`); + return this.config.types.AttestationData.fromJson(responseData.data, {case: "snake"}); }; public produceBlock = async (slot: Slot, randaoReveal: Uint8Array, graffiti: string): Promise => { - console.log("produceBlock", slot, randaoReveal, graffiti); - return undefined as BeaconBlock; + const query = querystring.stringify({ + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + randao_reveal: toHexString(randaoReveal), + graffiti: graffiti, + }); + const responseData = await this.httpClient.get<{data: Json}>(`/eth/v1/validator/blocks/${slot}?${query}`); + return this.config.types.BeaconBlock.fromJson(responseData.data, {case: "snake"}); }; public publishAggregateAndProofs = async (signedAggregateAndProofs: SignedAggregateAndProof[]): Promise => { - console.log("publishAggregateAndProofs", signedAggregateAndProofs); + await this.httpClient.post( + "/aggregate_and_proofs", + signedAggregateAndProofs.map((a) => this.config.types.SignedAggregateAndProof.toJson(a, {case: "snake"})), + ); }; } From d634cdf4a1d83b5ca50eebfc62a533ac04ca9320 Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 9 Dec 2020 16:42:23 +0100 Subject: [PATCH 03/19] implement beacon rest methods --- .../eth2/client/eth2ApiClient/beacon.ts | 46 ++++++++++ .../eth2/client/eth2ApiClient/beacon/index.ts | 83 ------------------- .../eth2/client/eth2ApiClient/beaconBlocks.ts | 20 +++++ .../eth2/client/eth2ApiClient/beaconPool.ts | 20 +++++ .../eth2/client/eth2ApiClient/beaconState.ts | 78 +++++++++++++++++ .../services/eth2/client/interface.ts | 12 +-- 6 files changed, 171 insertions(+), 88 deletions(-) create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/beacon.ts delete mode 100644 src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/beaconBlocks.ts create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/beaconPool.ts create mode 100644 src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beacon.ts b/src/renderer/services/eth2/client/eth2ApiClient/beacon.ts new file mode 100644 index 00000000..ed996dc2 --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/beacon.ts @@ -0,0 +1,46 @@ +import {ICGEth2BeaconApi, ICGEth2BeaconApiState} from "../interface"; +import {IBeaconBlocksApi, IBeaconPoolApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import {BeaconBlock, BeaconState, Genesis} from "@chainsafe/lodestar-types"; +import {HttpClient} from "../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {Json} from "@chainsafe/ssz"; +import {BeaconBlocks} from "./beaconBlocks"; +import {BeaconState as BeaconStateApi} from "./beaconState"; +import {BeaconPool} from "./beaconPool"; + +export class Beacon implements ICGEth2BeaconApi { + public blocks: IBeaconBlocksApi; + public state: ICGEth2BeaconApiState; + public pool: IBeaconPoolApi; + + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + // TODO: implement logger; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + + this.blocks = new BeaconBlocks(config, httpClient); + this.state = new BeaconStateApi(config, httpClient); + this.pool = new BeaconPool(config, httpClient); + } + + public getGenesis = async (): Promise => { + try { + const genesisResponse = await this.httpClient.get<{data: Json}>("/eth/v1/beacon/genesis"); + return this.config.types.Genesis.fromJson(genesisResponse.data, {case: "snake"}); + } catch (e) { + // TODO: implement logger; + console.error("Failed to obtain genesis time", {error: e.message}); + return null; + } + }; + + public getChainHead = async (): Promise => { + throw new Error("Method 'getChainHead' not implemented."); + }; + + public getBeaconState = async (): Promise => { + throw new Error("Method 'getBeaconState' not implemented."); + }; +} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts deleted file mode 100644 index 7fbdb0dd..00000000 --- a/src/renderer/services/eth2/client/eth2ApiClient/beacon/index.ts +++ /dev/null @@ -1,83 +0,0 @@ -import {ICGEth2BeaconApi} from "../../interface"; -import {IBeaconBlocksApi, IBeaconPoolApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; -import { - Attestation, - BeaconBlock, - BeaconState, - BLSPubkey, - Fork, - Genesis, - SignedBeaconBlock, - SignedBeaconHeaderResponse, - ValidatorIndex, - ValidatorResponse, -} from "@chainsafe/lodestar-types"; -import {HttpClient} from "../../../../api"; -import {IBeaconConfig} from "@chainsafe/lodestar-config"; - -export class Beacon implements ICGEth2BeaconApi { - public blocks: IBeaconBlocksApi = { - publishBlock: async (block: SignedBeaconBlock): Promise => { - console.log("publishBlock", block); - }, - }; - public pool: IBeaconPoolApi = { - submitAttestation: async (attestation: Attestation): Promise => { - console.log("submitAttestation", attestation); - }, - }; - public state: ICGEth2BeaconApi["state"] = { - getFork: async (stateId: "head"): Promise => { - console.log("getFork", stateId); - return null; - }, - getStateValidator: async ( - stateId: "head", - validatorId: ValidatorIndex | BLSPubkey, - ): Promise => { - console.log("getStateValidator", stateId, validatorId); - return null; - }, - getBlockHeader: async ( - stateId: "head", - blockId: "head" | number | string, - ): Promise => { - console.log("getBlockHeader", stateId, blockId); - return undefined as SignedBeaconHeaderResponse; - }, - getValidator: async ( - stateId: "head", - validatorId: string | BLSPubkey | ValidatorIndex, - ): Promise => { - console.log("getValidator", stateId, validatorId); - return undefined as ValidatorResponse; - }, - getValidators: async ( - stateId?: "head", - validatorIds?: (string | ValidatorIndex)[], - ): Promise => { - console.log("getValidators", stateId, validatorIds); - return undefined as ValidatorResponse[]; - }, - }; - - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; - public constructor(config: IBeaconConfig, httpClient: HttpClient) { - this.config = config; - this.httpClient = httpClient; - } - - public getGenesis = async (): Promise => { - console.log("getGenesis"); - return null; - }; - - public getChainHead = async (): Promise => { - throw new Error("Method 'getChainHead' not implemented."); - }; - - public getBeaconState = async (): Promise => { - throw new Error("Method 'getBeaconState' not implemented."); - }; -} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beaconBlocks.ts b/src/renderer/services/eth2/client/eth2ApiClient/beaconBlocks.ts new file mode 100644 index 00000000..9202bf77 --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/beaconBlocks.ts @@ -0,0 +1,20 @@ +import {IBeaconBlocksApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import {HttpClient} from "../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {SignedBeaconBlock} from "@chainsafe/lodestar-types"; + +export class BeaconBlocks implements IBeaconBlocksApi { + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + } + + public publishBlock = async (block: SignedBeaconBlock): Promise => { + await this.httpClient.post( + "/eth/v1/beacon/blocks", + this.config.types.SignedBeaconBlock.toJson(block, {case: "snake"}), + ); + }; +} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beaconPool.ts b/src/renderer/services/eth2/client/eth2ApiClient/beaconPool.ts new file mode 100644 index 00000000..83492614 --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/beaconPool.ts @@ -0,0 +1,20 @@ +import {IBeaconPoolApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import {HttpClient} from "../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {Attestation} from "@chainsafe/lodestar-types"; + +export class BeaconPool implements IBeaconPoolApi { + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + } + + public submitAttestation = async (attestation: Attestation): Promise => { + await this.httpClient.post( + "/eth/v1/beacon/pool/attestations", + this.config.types.Attestation.toJson(attestation, {case: "snake"}), + ); + }; +} diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts b/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts new file mode 100644 index 00000000..ca15aa78 --- /dev/null +++ b/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts @@ -0,0 +1,78 @@ +import { + BLSPubkey, + Fork, + SignedBeaconHeaderResponse, + ValidatorIndex, + ValidatorResponse, +} from "@chainsafe/lodestar-types"; +import {ICGEth2BeaconApiState} from "../interface"; +import {HttpClient} from "../../../api"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {Json} from "@chainsafe/ssz"; + +export class BeaconState implements ICGEth2BeaconApiState { + private readonly httpClient: HttpClient; + private readonly config: IBeaconConfig; + // TODO: implement logger; + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + this.config = config; + this.httpClient = httpClient; + } + + public getFork = async (stateId: "head"): Promise => { + try { + const forkResponse = await this.httpClient.get<{data: Json}>(`/eth/v1/beacon/states/${stateId}/fork`); + return this.config.types.Fork.fromJson(forkResponse.data, {case: "snake"}); + } catch (e) { + // TODO: implement logger; + console.error("Failed to fetch head fork version", {error: e.message}); + return null; + } + }; + + public getStateValidator = async ( + stateId: "head", + validatorId: ValidatorIndex | BLSPubkey, + ): Promise => { + const id = + typeof validatorId === "number" + ? validatorId.toString() + : this.config.types.BLSPubkey.toJson(validatorId)?.toString() ?? ""; + try { + const url = `/eth/v1/beacon/states/${stateId}/validators/${id}`; + const stateValidatorResponse = await this.httpClient.get<{data: Json}>(url); + return this.config.types.ValidatorResponse.fromJson(stateValidatorResponse.data, {case: "snake"}); + } catch (e) { + // TODO: implement logger; + console.error("Failed to fetch validator", {validatorId: id, error: e.message}); + return null; + } + }; + + public getBlockHeader = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + stateId: "head", + // eslint-disable-next-line @typescript-eslint/no-unused-vars + blockId: "head" | number | string, + ): Promise => { + throw new Error("Method 'getBlockHeader' not implemented."); + }; + + public getValidator = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + stateId: "head", + // eslint-disable-next-line @typescript-eslint/no-unused-vars + validatorId: string | BLSPubkey | ValidatorIndex, + ): Promise => { + throw new Error("Method 'getValidator' not implemented."); + }; + + public getValidators = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + stateId?: "head", + // eslint-disable-next-line @typescript-eslint/no-unused-vars + validatorIds?: (string | ValidatorIndex)[], + ): Promise => { + throw new Error("Method 'getValidators' not implemented."); + }; +} diff --git a/src/renderer/services/eth2/client/interface.ts b/src/renderer/services/eth2/client/interface.ts index 286c86d8..29b24450 100644 --- a/src/renderer/services/eth2/client/interface.ts +++ b/src/renderer/services/eth2/client/interface.ts @@ -7,12 +7,14 @@ import {IValidatorApi} from "@chainsafe/lodestar-validator/lib/api/interface/val import {IEth2ChainHead} from "../../../models/types/head"; import {BLSPubkey, SignedBeaconHeaderResponse, ValidatorIndex, ValidatorResponse} from "@chainsafe/lodestar-types"; +export interface ICGEth2BeaconApiState extends IBeaconStateApi { + getBlockHeader(stateId: "head", blockId: "head" | number | string): Promise; + getValidator(stateId: "head", validatorId: string | BLSPubkey | ValidatorIndex): Promise; + getValidators(stateId?: "head", validatorIds?: (string | ValidatorIndex)[]): Promise; +} + export interface ICGEth2BeaconApi extends IBeaconApi { - state: IBeaconStateApi & { - getBlockHeader(stateId: "head", blockId: "head" | number | string): Promise; - getValidator(stateId: "head", validatorId: string | BLSPubkey | ValidatorIndex): Promise; - getValidators(stateId?: "head", validatorIds?: (string | ValidatorIndex)[]): Promise; - }; + state: ICGEth2BeaconApiState; } export type ICGEth2NodeApi = INodeApi; export type ICGEth2ValidatorApi = IValidatorApi; From 3ecb97a885a8b86e7bb5811d661409aba408710b Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 9 Dec 2020 16:56:58 +0100 Subject: [PATCH 04/19] implement events methods --- .../eth2/client/eth2ApiClient/events.ts | 45 ++++++++++++++++--- .../eth2/client/eth2ApiClient/index.ts | 2 +- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/events.ts b/src/renderer/services/eth2/client/eth2ApiClient/events.ts index 82fcee20..b4de4145 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/events.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/events.ts @@ -1,18 +1,49 @@ import {BeaconEvent, BeaconEventType, IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; -import {IStoppableEventIterable} from "@chainsafe/lodestar-utils"; -import {HttpClient} from "../../../api"; +import {IStoppableEventIterable, LodestarEventIterator} from "@chainsafe/lodestar-utils"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {ContainerType} from "@chainsafe/ssz"; export class Events implements IEventsApi { - private readonly httpClient: HttpClient; + private readonly baseUrl: string; private readonly config: IBeaconConfig; - public constructor(config: IBeaconConfig, httpClient: HttpClient) { + public constructor(config: IBeaconConfig, baseUrl: string) { this.config = config; - this.httpClient = httpClient; + this.baseUrl = baseUrl; } public getEventStream = (topics: BeaconEventType[]): IStoppableEventIterable => { - console.log("getEventStream", topics); - return undefined as IStoppableEventIterable; + const url = `${this.baseUrl}/eth/v1/events?${topics.map((topic) => `topics=${topic}`).join("&")}`; + const eventSource = new EventSource(url); + return new LodestarEventIterator(({push}): (() => void) => { + eventSource.onmessage = (event): void => { + if (topics.includes(event.type as BeaconEventType)) { + push(this.deserializeBeaconEventMessage(event)); + } + }; + return (): void => { + eventSource.close(); + }; + }); + }; + + private deserializeBeaconEventMessage = (msg: MessageEvent): BeaconEvent => { + switch (msg.type) { + case BeaconEventType.BLOCK: + return { + type: BeaconEventType.BLOCK, + message: this.deserializeEventData(this.config.types.BlockEventPayload, msg.data), + }; + case BeaconEventType.CHAIN_REORG: + return { + type: BeaconEventType.CHAIN_REORG, + message: this.deserializeEventData(this.config.types.ChainReorg, msg.data), + }; + default: + throw new Error("Unsupported beacon event type " + msg.type); + } + }; + + private deserializeEventData = (type: ContainerType, data: string): T => { + return type.fromJson(JSON.parse(data)); }; } diff --git a/src/renderer/services/eth2/client/eth2ApiClient/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/index.ts index 09894a32..8e5c0c1b 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/index.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/index.ts @@ -27,7 +27,7 @@ export class Eth2ApiClient extends AbstractApiClient implements IValidatorBeacon this.validator = new Validator(config, this.httpClient); this.beacon = new Beacon(config, this.httpClient); - this.events = new Events(config, this.httpClient); + this.events = new Events(config, url); this.node = new NodeApi(config, this.httpClient); } From 4f6d1a1801809c94945113ec8e4db6a5fb02627f Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 9 Dec 2020 17:01:53 +0100 Subject: [PATCH 05/19] implement node methods --- .../services/eth2/client/eth2ApiClient/nodeApi.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts index a5b3cd6c..15d4084d 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts @@ -2,6 +2,7 @@ import {ICGEth2NodeApi} from "../interface"; import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {SyncingStatus} from "@chainsafe/lodestar-types"; +import {Json} from "@chainsafe/ssz"; export class NodeApi implements ICGEth2NodeApi { private readonly httpClient: HttpClient; @@ -12,12 +13,12 @@ export class NodeApi implements ICGEth2NodeApi { } public getSyncingStatus = async (): Promise => { - console.log("getSyncingStatus"); - return undefined as SyncingStatus; + const syncingResponse = await this.httpClient.get<{data: Json}>("/eth/v1/node/syncing"); + return this.config.types.SyncingStatus.fromJson(syncingResponse.data, {case: "snake"}); }; public getVersion = async (): Promise => { - console.log("getVersion"); - return undefined as string; + const versionResponse = await this.httpClient.get<{data: {version: string}}>("/eth/v1/node/version"); + return versionResponse.data.version; }; } From 209e069766d0a99a22963a53f90f44b8f1256e3d Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 9 Dec 2020 17:10:40 +0100 Subject: [PATCH 06/19] improve code --- src/renderer/ducks/validator/sagas.ts | 4 +--- src/renderer/services/eth2/client/eth2ApiClient/index.ts | 7 +++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index c2f3438c..2c25d740 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -41,7 +41,6 @@ import {getBeaconNodes} from "../network/selectors"; import {getValidators} from "./selectors"; import {ValidatorBeaconNodes} from "../../models/validatorBeaconNodes"; import {Eth2ApiClient} from "../../services/eth2/client/eth2ApiClient"; -import { HttpClient } from "../../services/api"; import {WinstonLogger} from "@chainsafe/lodestar-utils"; interface IValidatorServices { @@ -165,10 +164,9 @@ function* startService( controller: cgDbController, }); - // @ts-ignore console.log(eth2API, slashingProtection); - const logger = new WinstonLogger(); + const logger = new WinstonLogger() as ValidatorLogger; if (!validatorServices[publicKey]) { validatorServices[publicKey] = new Validator({ diff --git a/src/renderer/services/eth2/client/eth2ApiClient/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/index.ts index 8e5c0c1b..16d851c5 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/index.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/index.ts @@ -32,12 +32,11 @@ export class Eth2ApiClient extends AbstractApiClient implements IValidatorBeacon } public getVersion = async (): Promise => { - console.log("getVersion"); - return undefined as string; + throw new Error("Method 'getVersion' not implemented."); }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars public onNewChainHead = (callback: (head: IEth2ChainHead) => void): NodeJS.Timeout => { - console.log("onNewChainHead", callback); - return undefined as NodeJS.Timeout; + throw new Error("Method 'onNewChainHead' not implemented."); }; } From 03714c82d7215980756a649f5f99e3bb3d4e7edd Mon Sep 17 00:00:00 2001 From: Bernard Date: Mon, 14 Dec 2020 14:51:29 +0100 Subject: [PATCH 07/19] fix config preset (from minimal to mainnet) --- scripts/validator.ts | 2 +- src/renderer/ducks/validator/sagas.ts | 2 +- src/renderer/services/eth2/networks/local.ts | 6 +++--- src/renderer/services/eth2/networks/pyrmont.ts | 6 +++--- test/unit/validator/status/index.spec.ts | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/validator.ts b/scripts/validator.ts index 66628887..d1062fac 100644 --- a/scripts/validator.ts +++ b/scripts/validator.ts @@ -5,7 +5,7 @@ import {CGDatabase} from "../src/renderer/services/db/api"; import {LevelDbController} from "../src/main/db/controller"; import rimraf from "rimraf"; import {LighthouseEth2ApiClient} from "../src/renderer/services/eth2/client/lighthouse/lighthouse"; -import {config} from "@chainsafe/lodestar-config/lib/presets/minimal"; +import {config} from "@chainsafe/lodestar-config/lib/presets/mainnet"; import {LogLevel, WinstonLogger} from "@chainsafe/lodestar-utils"; import {getInteropKey} from "../src/renderer/services/validator/interop_keys"; diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index 2c25d740..53d225cb 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -7,7 +7,7 @@ import {EthersNotifier} from "../../services/deposit/ethers"; import {getValidatorStatus, ValidatorStatus} from "../../services/validator/status"; import {ValidatorLogger} from "../../services/eth2/client/logger"; import database, {cgDbController} from "../../services/db/api/database"; -import {config} from "@chainsafe/lodestar-config/lib/presets/minimal"; +import {config} from "@chainsafe/lodestar-config/lib/presets/mainnet"; import {IByPublicKey, IValidator} from "./slice"; import { loadValidators, diff --git a/src/renderer/services/eth2/networks/local.ts b/src/renderer/services/eth2/networks/local.ts index c9821ed9..649edbdf 100644 --- a/src/renderer/services/eth2/networks/local.ts +++ b/src/renderer/services/eth2/networks/local.ts @@ -1,4 +1,4 @@ -import {config as minimalBeaconConfig} from "@chainsafe/lodestar-config/lib/presets/minimal"; +import {config as mainnetBeaconConfig} from "@chainsafe/lodestar-config/lib/presets/mainnet"; import {INetworkConfig} from "../../interfaces"; import {ethers} from "ethers"; @@ -14,9 +14,9 @@ export const LocalhostConfig: INetworkConfig = Object.freeze({ deployedAtBlock: 0, }, eth2Config: { - ...minimalBeaconConfig, + ...mainnetBeaconConfig, params: { - ...minimalBeaconConfig.params, + ...mainnetBeaconConfig.params, GENESIS_FORK_VERSION: Buffer.from("0x00000001"), }, }, diff --git a/src/renderer/services/eth2/networks/pyrmont.ts b/src/renderer/services/eth2/networks/pyrmont.ts index ff5e5707..67d85f10 100644 --- a/src/renderer/services/eth2/networks/pyrmont.ts +++ b/src/renderer/services/eth2/networks/pyrmont.ts @@ -1,4 +1,4 @@ -import {config as minimalBeaconConfig} from "@chainsafe/lodestar-config/lib/presets/minimal"; +import {config as mainnetBeaconConfig} from "@chainsafe/lodestar-config/lib/presets/mainnet"; import {INetworkConfig} from "../../interfaces"; import {ethers} from "ethers"; @@ -14,9 +14,9 @@ export const PyrmontConfig: INetworkConfig = Object.freeze({ deployedAtBlock: 0, }, eth2Config: { - ...minimalBeaconConfig, + ...mainnetBeaconConfig, params: { - ...minimalBeaconConfig.params, + ...mainnetBeaconConfig.params, GENESIS_FORK_VERSION: Buffer.from("0x00002009"), }, }, diff --git a/test/unit/validator/status/index.spec.ts b/test/unit/validator/status/index.spec.ts index 318eb27f..55b12243 100644 --- a/test/unit/validator/status/index.spec.ts +++ b/test/unit/validator/status/index.spec.ts @@ -10,7 +10,7 @@ describe("validator status", function () { // import {initBLS} from "@chainsafe/bls"; // import {generateValidator} from "./util"; // import {IBeaconConfig} from "@chainsafe/lodestar-config"; -// import {config} from "@chainsafe/lodestar-config/lib/presets/minimal"; +// import {config} from "@chainsafe/lodestar-config/lib/presets/mainnet"; // import {IEth2BeaconApi, IGenericEth2Client} from "../../../../src/renderer/services/eth2/client/interface"; // import {IValidatorApi} from "@chainsafe/lodestar-validator/lib/api/interface/validators"; // import {StandardValidatorBeaconClient} from "../../../../src/renderer/services/eth2/client/standard"; From 47814954402d0450d25f90cc94d7a9bba17918c2 Mon Sep 17 00:00:00 2001 From: Bernard Date: Mon, 14 Dec 2020 15:13:57 +0100 Subject: [PATCH 08/19] remove chain_reorg from topics in getEventStream --- src/renderer/services/eth2/client/eth2ApiClient/events.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/events.ts b/src/renderer/services/eth2/client/eth2ApiClient/events.ts index b4de4145..b66b9ddf 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/events.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/events.ts @@ -12,7 +12,8 @@ export class Events implements IEventsApi { } public getEventStream = (topics: BeaconEventType[]): IStoppableEventIterable => { - const url = `${this.baseUrl}/eth/v1/events?${topics.map((topic) => `topics=${topic}`).join("&")}`; + const topicsQuery = topics.filter((topic) => topic !== "chain_reorg").join(","); + const url = `${this.baseUrl.replace(/\/+$/, "")}/eth/v1/events?topics=${topicsQuery}`; const eventSource = new EventSource(url); return new LodestarEventIterator(({push}): (() => void) => { eventSource.onmessage = (event): void => { From 9218dd3e2f52e936751fbf757993059a3a9bfd88 Mon Sep 17 00:00:00 2001 From: Bernard Date: Mon, 14 Dec 2020 16:29:56 +0100 Subject: [PATCH 09/19] fix --- .../eth2/client/eth2ApiClient/beaconState.ts | 3 +++ .../eth2/client/eth2ApiClient/validator.tsx | 21 ++++++------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts b/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts index ca15aa78..9d69a397 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts @@ -41,6 +41,9 @@ export class BeaconState implements ICGEth2BeaconApiState { try { const url = `/eth/v1/beacon/states/${stateId}/validators/${id}`; const stateValidatorResponse = await this.httpClient.get<{data: Json}>(url); + // TODO: remove hack after ssz is updated + // @ts-ignore + stateValidatorResponse.data.pubkey = stateValidatorResponse.data.validator.pubkey; return this.config.types.ValidatorResponse.fromJson(stateValidatorResponse.data, {case: "snake"}); } catch (e) { // TODO: implement logger; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx b/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx index 3a9f5550..390a27de 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx +++ b/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx @@ -52,26 +52,17 @@ export class Validator implements ICGEth2ValidatorApi { }; public prepareBeaconCommitteeSubnet = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars validatorIndex: ValidatorIndex, + // eslint-disable-next-line @typescript-eslint/no-unused-vars committeeIndex: CommitteeIndex, + // eslint-disable-next-line @typescript-eslint/no-unused-vars committeesAtSlot: number, + // eslint-disable-next-line @typescript-eslint/no-unused-vars slot: Slot, + // eslint-disable-next-line @typescript-eslint/no-unused-vars isAggregator: boolean, - ): Promise => { - await this.httpClient.post("/beacon_committee_subscriptions", [ - { - // eslint-disable-next-line camelcase,@typescript-eslint/camelcase - validator_index: validatorIndex, - // eslint-disable-next-line camelcase,@typescript-eslint/camelcase - committee_index: committeeIndex, - // eslint-disable-next-line camelcase,@typescript-eslint/camelcase - committees_at_slot: committeesAtSlot, - // eslint-disable-next-line camelcase,@typescript-eslint/camelcase - is_aggregator: isAggregator, - slot, - }, - ]); - }; + ): Promise => {}; public produceAttestationData = async (index: CommitteeIndex, slot: Slot): Promise => { const query = querystring.stringify({ From 6baeebe31e074c57319039c2c4417fc43d2711e0 Mon Sep 17 00:00:00 2001 From: Bernard Date: Tue, 15 Dec 2020 09:43:00 +0100 Subject: [PATCH 10/19] refactor class names --- src/renderer/ducks/validator/sagas.ts | 5 +++-- .../{beacon.ts => cgEth2BeaconApi.ts} | 14 +++++++------- ...eaconBlocks.ts => cgEth2BeaconBlocksApi.ts} | 2 +- .../{beaconPool.ts => cgEth2BeaconPoolApi.ts} | 2 +- ...{beaconState.ts => cgEth2BeaconStateApi.ts} | 2 +- .../{events.ts => cgEth2EventsApi.ts} | 2 +- .../{nodeApi.ts => cgEth2NodeApi.ts} | 2 +- .../{validator.tsx => cgEth2ValidatorApi.tsx} | 2 +- .../eth2/client/eth2ApiClient/index.ts | 18 +++++++++--------- 9 files changed, 25 insertions(+), 24 deletions(-) rename src/renderer/services/eth2/client/eth2ApiClient/{beacon.ts => cgEth2BeaconApi.ts} (77%) rename src/renderer/services/eth2/client/eth2ApiClient/{beaconBlocks.ts => cgEth2BeaconBlocksApi.ts} (91%) rename src/renderer/services/eth2/client/eth2ApiClient/{beaconPool.ts => cgEth2BeaconPoolApi.ts} (92%) rename src/renderer/services/eth2/client/eth2ApiClient/{beaconState.ts => cgEth2BeaconStateApi.ts} (97%) rename src/renderer/services/eth2/client/eth2ApiClient/{events.ts => cgEth2EventsApi.ts} (97%) rename src/renderer/services/eth2/client/eth2ApiClient/{nodeApi.ts => cgEth2NodeApi.ts} (94%) rename src/renderer/services/eth2/client/eth2ApiClient/{validator.tsx => cgEth2ValidatorApi.tsx} (98%) diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index 53d225cb..dcc81dbe 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -40,7 +40,7 @@ import {getAuthAccount} from "../auth/selectors"; import {getBeaconNodes} from "../network/selectors"; import {getValidators} from "./selectors"; import {ValidatorBeaconNodes} from "../../models/validatorBeaconNodes"; -import {Eth2ApiClient} from "../../services/eth2/client/eth2ApiClient"; +import {CgEth2ApiClient} from "../../services/eth2/client/eth2ApiClient"; import {WinstonLogger} from "@chainsafe/lodestar-utils"; interface IValidatorServices { @@ -158,7 +158,8 @@ function* startService( ): Generator, void> { const publicKey = action.payload.publicKey.toHex(); // TODO: Use beacon chain proxy instead of first node - const eth2API = new Eth2ApiClient(config, "http://localhost:5052"); + const eth2API = new CgEth2ApiClient(config, "http://localhost:5052"); + const slashingProtection = new SlashingProtection({ config, controller: cgDbController, diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beacon.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts similarity index 77% rename from src/renderer/services/eth2/client/eth2ApiClient/beacon.ts rename to src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts index ed996dc2..805dba70 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/beacon.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts @@ -4,11 +4,11 @@ import {BeaconBlock, BeaconState, Genesis} from "@chainsafe/lodestar-types"; import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {Json} from "@chainsafe/ssz"; -import {BeaconBlocks} from "./beaconBlocks"; -import {BeaconState as BeaconStateApi} from "./beaconState"; -import {BeaconPool} from "./beaconPool"; +import {CgEth2BeaconBlocksApi} from "./cgEth2BeaconBlocksApi"; +import {CgEth2BeaconStateApi} from "./cgEth2BeaconStateApi"; +import {CgEth2BeaconPoolApi} from "./cgEth2BeaconPoolApi"; -export class Beacon implements ICGEth2BeaconApi { +export class CgEth2BeaconApi implements ICGEth2BeaconApi { public blocks: IBeaconBlocksApi; public state: ICGEth2BeaconApiState; public pool: IBeaconPoolApi; @@ -20,9 +20,9 @@ export class Beacon implements ICGEth2BeaconApi { this.config = config; this.httpClient = httpClient; - this.blocks = new BeaconBlocks(config, httpClient); - this.state = new BeaconStateApi(config, httpClient); - this.pool = new BeaconPool(config, httpClient); + this.blocks = new CgEth2BeaconBlocksApi(config, httpClient); + this.state = new CgEth2BeaconStateApi(config, httpClient); + this.pool = new CgEth2BeaconPoolApi(config, httpClient); } public getGenesis = async (): Promise => { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beaconBlocks.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts similarity index 91% rename from src/renderer/services/eth2/client/eth2ApiClient/beaconBlocks.ts rename to src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts index 9202bf77..6267fd5c 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/beaconBlocks.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts @@ -3,7 +3,7 @@ import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {SignedBeaconBlock} from "@chainsafe/lodestar-types"; -export class BeaconBlocks implements IBeaconBlocksApi { +export class CgEth2BeaconBlocksApi implements IBeaconBlocksApi { private readonly httpClient: HttpClient; private readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beaconPool.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts similarity index 92% rename from src/renderer/services/eth2/client/eth2ApiClient/beaconPool.ts rename to src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts index 83492614..0f6dba47 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/beaconPool.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts @@ -3,7 +3,7 @@ import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {Attestation} from "@chainsafe/lodestar-types"; -export class BeaconPool implements IBeaconPoolApi { +export class CgEth2BeaconPoolApi implements IBeaconPoolApi { private readonly httpClient: HttpClient; private readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts similarity index 97% rename from src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts rename to src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts index 9d69a397..15496028 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/beaconState.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts @@ -10,7 +10,7 @@ import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {Json} from "@chainsafe/ssz"; -export class BeaconState implements ICGEth2BeaconApiState { +export class CgEth2BeaconStateApi implements ICGEth2BeaconApiState { private readonly httpClient: HttpClient; private readonly config: IBeaconConfig; // TODO: implement logger; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/events.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts similarity index 97% rename from src/renderer/services/eth2/client/eth2ApiClient/events.ts rename to src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts index b66b9ddf..c496c012 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/events.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts @@ -3,7 +3,7 @@ import {IStoppableEventIterable, LodestarEventIterator} from "@chainsafe/lodesta import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {ContainerType} from "@chainsafe/ssz"; -export class Events implements IEventsApi { +export class CgEth2EventsApi implements IEventsApi { private readonly baseUrl: string; private readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, baseUrl: string) { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2NodeApi.ts similarity index 94% rename from src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts rename to src/renderer/services/eth2/client/eth2ApiClient/cgEth2NodeApi.ts index 15d4084d..3ef613d0 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/nodeApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2NodeApi.ts @@ -4,7 +4,7 @@ import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {SyncingStatus} from "@chainsafe/lodestar-types"; import {Json} from "@chainsafe/ssz"; -export class NodeApi implements ICGEth2NodeApi { +export class CgEth2NodeApi implements ICGEth2NodeApi { private readonly httpClient: HttpClient; private readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx similarity index 98% rename from src/renderer/services/eth2/client/eth2ApiClient/validator.tsx rename to src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx index 390a27de..dc907775 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/validator.tsx +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx @@ -17,7 +17,7 @@ import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {Json, toHexString} from "@chainsafe/ssz"; import querystring from "querystring"; -export class Validator implements ICGEth2ValidatorApi { +export class CgEth2ValidatorApi implements ICGEth2ValidatorApi { private readonly httpClient: HttpClient; private readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/index.ts index 16d851c5..59bf6830 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/index.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/index.ts @@ -2,15 +2,15 @@ import {ICGEth2ValidatorApi, IValidatorBeaconClient, ICGEth2BeaconApi, ICGEth2No import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; import {IEth2ChainHead} from "../../../../models/types/head"; -import {Beacon} from "./beacon"; +import {CgEth2BeaconApi} from "./cgEth2BeaconApi"; import {HttpClient} from "../../../api"; import {AbstractApiClient} from "@chainsafe/lodestar-validator/lib/api/abstract"; import {WinstonLogger} from "@chainsafe/lodestar-utils"; -import {Validator} from "./validator"; -import {NodeApi} from "./nodeApi"; -import {Events} from "./events"; +import {CgEth2ValidatorApi} from "./cgEth2ValidatorApi"; +import {CgEth2NodeApi} from "./cgEth2NodeApi"; +import {CgEth2EventsApi} from "./cgEth2EventsApi"; -export class Eth2ApiClient extends AbstractApiClient implements IValidatorBeaconClient { +export class CgEth2ApiClient extends AbstractApiClient implements IValidatorBeaconClient { public validator: ICGEth2ValidatorApi; public beacon: ICGEth2BeaconApi; // public node: ICGEth2NodeApi; @@ -25,10 +25,10 @@ export class Eth2ApiClient extends AbstractApiClient implements IValidatorBeacon this.url = url; this.httpClient = new HttpClient(url); - this.validator = new Validator(config, this.httpClient); - this.beacon = new Beacon(config, this.httpClient); - this.events = new Events(config, url); - this.node = new NodeApi(config, this.httpClient); + this.validator = new CgEth2ValidatorApi(config, this.httpClient); + this.beacon = new CgEth2BeaconApi(config, this.httpClient); + this.events = new CgEth2EventsApi(config, url); + this.node = new CgEth2NodeApi(config, this.httpClient); } public getVersion = async (): Promise => { From e09ec36ea2de3f8817d5ab53aa3e6614f03bb776 Mon Sep 17 00:00:00 2001 From: Bernard Date: Tue, 15 Dec 2020 16:59:39 +0100 Subject: [PATCH 11/19] fix url --- .../eth2ApiClient/cgEth2ValidatorApi.tsx | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx index dc907775..61bbd0ea 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx @@ -52,17 +52,26 @@ export class CgEth2ValidatorApi implements ICGEth2ValidatorApi { }; public prepareBeaconCommitteeSubnet = async ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars validatorIndex: ValidatorIndex, - // eslint-disable-next-line @typescript-eslint/no-unused-vars committeeIndex: CommitteeIndex, - // eslint-disable-next-line @typescript-eslint/no-unused-vars committeesAtSlot: number, - // eslint-disable-next-line @typescript-eslint/no-unused-vars slot: Slot, - // eslint-disable-next-line @typescript-eslint/no-unused-vars isAggregator: boolean, - ): Promise => {}; + ): Promise => { + await this.httpClient.post("/eth/v1/validator/beacon_committee_subscriptions", [ + { + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + validator_index: validatorIndex, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committee_index: committeeIndex, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committees_at_slot: committeesAtSlot, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + is_aggregator: isAggregator, + slot, + }, + ]); + }; public produceAttestationData = async (index: CommitteeIndex, slot: Slot): Promise => { const query = querystring.stringify({ @@ -86,7 +95,7 @@ export class CgEth2ValidatorApi implements ICGEth2ValidatorApi { public publishAggregateAndProofs = async (signedAggregateAndProofs: SignedAggregateAndProof[]): Promise => { await this.httpClient.post( - "/aggregate_and_proofs", + "/eth/v1/validator/aggregate_and_proofs", signedAggregateAndProofs.map((a) => this.config.types.SignedAggregateAndProof.toJson(a, {case: "snake"})), ); }; From 9c4d01bd6bf693b7888e5871c85583f528290eb8 Mon Sep 17 00:00:00 2001 From: Bernard Date: Tue, 15 Dec 2020 17:10:26 +0100 Subject: [PATCH 12/19] fix payload of submitAttestation --- .../eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts index 0f6dba47..686026c7 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts @@ -12,9 +12,8 @@ export class CgEth2BeaconPoolApi implements IBeaconPoolApi { } public submitAttestation = async (attestation: Attestation): Promise => { - await this.httpClient.post( - "/eth/v1/beacon/pool/attestations", + await this.httpClient.post("/eth/v1/beacon/pool/attestations", [ this.config.types.Attestation.toJson(attestation, {case: "snake"}), - ); + ]); }; } From 3a3e3e4ca721dab2b6a19602ead45369638525d6 Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 16 Dec 2020 10:00:47 +0100 Subject: [PATCH 13/19] implement beacon node url from validator beacon list --- src/renderer/ducks/validator/sagas.ts | 54 +++++++++++++++------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index dcc81dbe..19e87fa8 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -38,10 +38,11 @@ import {ValidatorResponse} from "@chainsafe/lodestar-types"; import * as logger from "electron-log"; import {getAuthAccount} from "../auth/selectors"; import {getBeaconNodes} from "../network/selectors"; -import {getValidators} from "./selectors"; +import {getValidatorBeaconNodes, getValidators} from "./selectors"; import {ValidatorBeaconNodes} from "../../models/validatorBeaconNodes"; import {CgEth2ApiClient} from "../../services/eth2/client/eth2ApiClient"; import {WinstonLogger} from "@chainsafe/lodestar-utils"; +import {Beacon} from "../beacon/slice"; interface IValidatorServices { [validatorAddress: string]: Validator; @@ -155,33 +156,40 @@ function* loadValidatorStatusSaga( function* startService( action: ReturnType, -): Generator, void> { - const publicKey = action.payload.publicKey.toHex(); - // TODO: Use beacon chain proxy instead of first node - const eth2API = new CgEth2ApiClient(config, "http://localhost:5052"); - - const slashingProtection = new SlashingProtection({ - config, - controller: cgDbController, - }); - - console.log(eth2API, slashingProtection); +): Generator, void, Beacon[]> { + try { + const publicKey = action.payload.publicKey.toHex(); + const beaconNodes = yield select(getValidatorBeaconNodes, {publicKey}); + if (!beaconNodes.length) { + throw new Error("missing beacon node"); + } - const logger = new WinstonLogger() as ValidatorLogger; + // TODO: Use beacon chain proxy instead of first node + const eth2API = new CgEth2ApiClient(config, beaconNodes[0].url); - if (!validatorServices[publicKey]) { - validatorServices[publicKey] = new Validator({ - slashingProtection, - api: eth2API, + const slashingProtection = new SlashingProtection({ config, - secretKeys: [action.payload.privateKey], - logger, - graffiti: "ChainGuardian", + controller: cgDbController, }); - } - yield validatorServices[publicKey].start(); - yield put(startValidatorService(logger, publicKey)); + const logger = new WinstonLogger() as ValidatorLogger; + + if (!validatorServices[publicKey]) { + validatorServices[publicKey] = new Validator({ + slashingProtection, + api: eth2API, + config, + secretKeys: [action.payload.privateKey], + logger, + graffiti: "ChainGuardian", + }); + } + yield validatorServices[publicKey].start(); + + yield put(startValidatorService(logger, publicKey)); + } catch (e) { + console.error(e); + } } function* stopService(action: ReturnType): Generator> { From 78295131280d7bc718ee9e1475e715bac1e35db3 Mon Sep 17 00:00:00 2001 From: Bernard Date: Wed, 16 Dec 2020 10:21:13 +0100 Subject: [PATCH 14/19] implement config based on beacon network --- src/renderer/ducks/validator/sagas.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index 19e87fa8..aa193703 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -7,7 +7,7 @@ import {EthersNotifier} from "../../services/deposit/ethers"; import {getValidatorStatus, ValidatorStatus} from "../../services/validator/status"; import {ValidatorLogger} from "../../services/eth2/client/logger"; import database, {cgDbController} from "../../services/db/api/database"; -import {config} from "@chainsafe/lodestar-config/lib/presets/mainnet"; +import {config as mainnetConfig} from "@chainsafe/lodestar-config/lib/presets/mainnet"; import {IByPublicKey, IValidator} from "./slice"; import { loadValidators, @@ -43,6 +43,8 @@ import {ValidatorBeaconNodes} from "../../models/validatorBeaconNodes"; import {CgEth2ApiClient} from "../../services/eth2/client/eth2ApiClient"; import {WinstonLogger} from "@chainsafe/lodestar-utils"; import {Beacon} from "../beacon/slice"; +import {readBeaconChainNetwork} from "../../services/eth2/client"; +import {INetworkConfig} from "../../services/interfaces"; interface IValidatorServices { [validatorAddress: string]: Validator; @@ -156,7 +158,11 @@ function* loadValidatorStatusSaga( function* startService( action: ReturnType, -): Generator, void, Beacon[]> { +): Generator< + SelectEffect | PutEffect | Promise | Promise, + void, + Beacon[] & (INetworkConfig | null) +> { try { const publicKey = action.payload.publicKey.toHex(); const beaconNodes = yield select(getValidatorBeaconNodes, {publicKey}); @@ -164,6 +170,8 @@ function* startService( throw new Error("missing beacon node"); } + const config = (yield readBeaconChainNetwork(beaconNodes[0].url))?.eth2Config || mainnetConfig; + // TODO: Use beacon chain proxy instead of first node const eth2API = new CgEth2ApiClient(config, beaconNodes[0].url); @@ -188,7 +196,7 @@ function* startService( yield put(startValidatorService(logger, publicKey)); } catch (e) { - console.error(e); + logger.error("Failed to start validator", e.message); } } From 407cf84a364e154058d056c45478264bd68395e1 Mon Sep 17 00:00:00 2001 From: Bernard Date: Thu, 17 Dec 2020 14:23:09 +0100 Subject: [PATCH 15/19] fix comments --- .../client/eth2ApiClient/cgEth2BeaconApi.ts | 16 ++++---- .../eth2ApiClient/cgEth2BeaconStateApi.ts | 39 ++----------------- .../client/eth2ApiClient/cgEth2EventsApi.ts | 4 +- .../eth2/client/eth2ApiClient/index.ts | 10 ----- .../services/eth2/client/interface.ts | 17 +------- 5 files changed, 15 insertions(+), 71 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts index 805dba70..a98cd7fb 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts @@ -1,6 +1,10 @@ -import {ICGEth2BeaconApi, ICGEth2BeaconApiState} from "../interface"; -import {IBeaconBlocksApi, IBeaconPoolApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; -import {BeaconBlock, BeaconState, Genesis} from "@chainsafe/lodestar-types"; +import {ICGEth2BeaconApi} from "../interface"; +import { + IBeaconBlocksApi, + IBeaconPoolApi, + IBeaconStateApi +} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import {BeaconBlock, Genesis} from "@chainsafe/lodestar-types"; import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {Json} from "@chainsafe/ssz"; @@ -10,7 +14,7 @@ import {CgEth2BeaconPoolApi} from "./cgEth2BeaconPoolApi"; export class CgEth2BeaconApi implements ICGEth2BeaconApi { public blocks: IBeaconBlocksApi; - public state: ICGEth2BeaconApiState; + public state: IBeaconStateApi; public pool: IBeaconPoolApi; private readonly httpClient: HttpClient; @@ -39,8 +43,4 @@ export class CgEth2BeaconApi implements ICGEth2BeaconApi { public getChainHead = async (): Promise => { throw new Error("Method 'getChainHead' not implemented."); }; - - public getBeaconState = async (): Promise => { - throw new Error("Method 'getBeaconState' not implemented."); - }; } diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts index 15496028..1c434f84 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts @@ -1,16 +1,10 @@ -import { - BLSPubkey, - Fork, - SignedBeaconHeaderResponse, - ValidatorIndex, - ValidatorResponse, -} from "@chainsafe/lodestar-types"; -import {ICGEth2BeaconApiState} from "../interface"; +import {BLSPubkey, Fork, ValidatorIndex, ValidatorResponse} from "@chainsafe/lodestar-types"; import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {Json} from "@chainsafe/ssz"; +import {IBeaconStateApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; -export class CgEth2BeaconStateApi implements ICGEth2BeaconApiState { +export class CgEth2BeaconStateApi implements IBeaconStateApi { private readonly httpClient: HttpClient; private readonly config: IBeaconConfig; // TODO: implement logger; @@ -51,31 +45,4 @@ export class CgEth2BeaconStateApi implements ICGEth2BeaconApiState { return null; } }; - - public getBlockHeader = async ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - stateId: "head", - // eslint-disable-next-line @typescript-eslint/no-unused-vars - blockId: "head" | number | string, - ): Promise => { - throw new Error("Method 'getBlockHeader' not implemented."); - }; - - public getValidator = async ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - stateId: "head", - // eslint-disable-next-line @typescript-eslint/no-unused-vars - validatorId: string | BLSPubkey | ValidatorIndex, - ): Promise => { - throw new Error("Method 'getValidator' not implemented."); - }; - - public getValidators = async ( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - stateId?: "head", - // eslint-disable-next-line @typescript-eslint/no-unused-vars - validatorIds?: (string | ValidatorIndex)[], - ): Promise => { - throw new Error("Method 'getValidators' not implemented."); - }; } diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts index c496c012..83049124 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts @@ -13,8 +13,8 @@ export class CgEth2EventsApi implements IEventsApi { public getEventStream = (topics: BeaconEventType[]): IStoppableEventIterable => { const topicsQuery = topics.filter((topic) => topic !== "chain_reorg").join(","); - const url = `${this.baseUrl.replace(/\/+$/, "")}/eth/v1/events?topics=${topicsQuery}`; - const eventSource = new EventSource(url); + const url = new URL(`/eth/v1/events?topics=${topicsQuery}`, this.baseUrl); + const eventSource = new EventSource(url.href); return new LodestarEventIterator(({push}): (() => void) => { eventSource.onmessage = (event): void => { if (topics.includes(event.type as BeaconEventType)) { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/index.ts index 59bf6830..31e181cd 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/index.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/index.ts @@ -1,7 +1,6 @@ import {ICGEth2ValidatorApi, IValidatorBeaconClient, ICGEth2BeaconApi, ICGEth2NodeApi} from "../interface"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; -import {IEth2ChainHead} from "../../../../models/types/head"; import {CgEth2BeaconApi} from "./cgEth2BeaconApi"; import {HttpClient} from "../../../api"; import {AbstractApiClient} from "@chainsafe/lodestar-validator/lib/api/abstract"; @@ -30,13 +29,4 @@ export class CgEth2ApiClient extends AbstractApiClient implements IValidatorBeac this.events = new CgEth2EventsApi(config, url); this.node = new CgEth2NodeApi(config, this.httpClient); } - - public getVersion = async (): Promise => { - throw new Error("Method 'getVersion' not implemented."); - }; - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - public onNewChainHead = (callback: (head: IEth2ChainHead) => void): NodeJS.Timeout => { - throw new Error("Method 'onNewChainHead' not implemented."); - }; } diff --git a/src/renderer/services/eth2/client/interface.ts b/src/renderer/services/eth2/client/interface.ts index 29b24450..079dcd11 100644 --- a/src/renderer/services/eth2/client/interface.ts +++ b/src/renderer/services/eth2/client/interface.ts @@ -1,21 +1,11 @@ import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {ILogger} from "@chainsafe/lodestar-utils"; import {IApiClient} from "@chainsafe/lodestar-validator/lib"; -import {IBeaconApi, IBeaconStateApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import {IBeaconApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; import {INodeApi} from "@chainsafe/lodestar-validator/lib/api/interface/node"; import {IValidatorApi} from "@chainsafe/lodestar-validator/lib/api/interface/validators"; -import {IEth2ChainHead} from "../../../models/types/head"; -import {BLSPubkey, SignedBeaconHeaderResponse, ValidatorIndex, ValidatorResponse} from "@chainsafe/lodestar-types"; -export interface ICGEth2BeaconApiState extends IBeaconStateApi { - getBlockHeader(stateId: "head", blockId: "head" | number | string): Promise; - getValidator(stateId: "head", validatorId: string | BLSPubkey | ValidatorIndex): Promise; - getValidators(stateId?: "head", validatorIds?: (string | ValidatorIndex)[]): Promise; -} - -export interface ICGEth2BeaconApi extends IBeaconApi { - state: ICGEth2BeaconApiState; -} +export type ICGEth2BeaconApi = IBeaconApi; export type ICGEth2NodeApi = INodeApi; export type ICGEth2ValidatorApi = IValidatorApi; @@ -27,9 +17,6 @@ export interface ICgEth2ApiClient extends IApiClient { beacon: ICGEth2BeaconApi; validator: ICGEth2ValidatorApi; node: ICGEth2NodeApi; - - getVersion(): Promise; - onNewChainHead(callback: (head: IEth2ChainHead) => void): NodeJS.Timeout; } export type IValidatorBeaconClient = IApiClient; From baef9a26fbfe5afba2bd4dabc6dd909ba69b16ef Mon Sep 17 00:00:00 2001 From: Bernard Date: Thu, 17 Dec 2020 14:42:10 +0100 Subject: [PATCH 16/19] fix lint and types --- src/renderer/ducks/network/sagas.ts | 63 +------------------ src/renderer/ducks/validator/sagas.ts | 10 +-- .../client/eth2ApiClient/cgEth2BeaconApi.ts | 2 +- .../services/validator/status/index.ts | 6 +- 4 files changed, 6 insertions(+), 75 deletions(-) diff --git a/src/renderer/ducks/network/sagas.ts b/src/renderer/ducks/network/sagas.ts index 3cae5dfa..d4838e0a 100644 --- a/src/renderer/ducks/network/sagas.ts +++ b/src/renderer/ducks/network/sagas.ts @@ -6,16 +6,9 @@ import {BeaconNode, BeaconNodes} from "../../models/beaconNode"; import database from "../../services/db/api/database"; import * as logger from "electron-log"; import {IEth2ChainHead} from "../../models/types/head"; -import { - saveBeaconNode, - loadedValidatorBeaconNodes, - removeBeaconNode, - loadValidatorBeaconNodes, - subscribeToBlockListening, -} from "./actions"; +import {saveBeaconNode, loadedValidatorBeaconNodes, removeBeaconNode, loadValidatorBeaconNodes} from "./actions"; import {CGAccount} from "../../models/account"; import {getRegisterSigningKey} from "../register/selectors"; -import {getValidatorBeaconNodes, getValidatorBlockSubscription} from "./selectors"; import {getAuthAccount} from "../auth/selectors"; function* saveBeaconNodeSaga({ @@ -50,7 +43,7 @@ function* removeBeaconNodeSaga({ } export function* loadValidatorBeaconNodesSaga({ - payload: {subscribe, validator}, + payload: {validator}, }: ReturnType): Generator< | SelectEffect | CallEffect @@ -67,58 +60,6 @@ export function* loadValidatorBeaconNodesSaga({ } const validatorBeaconNodes: BeaconNode[] = yield call(account.getValidatorBeaconNodes, validator); logger.info(`Found ${validatorBeaconNodes.length} beacon nodes for validator ${validator}.`); - yield all( - validatorBeaconNodes.map(function* (validatorBN) { - if (validatorBN.client) { - try { - const chainHead: IEth2ChainHead = yield validatorBN.client.beacon.state.getBlockHeader( - "head", - "head", - ); - const refreshFnWithContext = refreshBeaconNodeStatus.bind(null, validator); - yield call(refreshFnWithContext, chainHead); - - if (subscribe) { - const existingTimeout = yield select((state) => - getValidatorBlockSubscription(state, {validator}), - ); - if (!existingTimeout) { - const timeoutId = validatorBN.client.onNewChainHead(refreshFnWithContext); - yield put(subscribeToBlockListening(timeoutId, validator)); - } - } - } catch (e) { - yield put(loadedValidatorBeaconNodes(validatorBeaconNodes, validator)); - logger.warn("Error while fetching chainhead from beacon node... ", e.message); - } - } - }), - ); -} - -function* refreshBeaconNodeStatus( - validator: string, - chainHead: IEth2ChainHead, -): Generator>, void, BeaconNode[]> { - const validatorBeaconNodes = yield select((state) => getValidatorBeaconNodes(state, {validator})); - const beaconNodes: BeaconNode[] = yield all( - validatorBeaconNodes.map(async (validatorBN: BeaconNode) => { - try { - if (!validatorBN.client) { - throw new Error("No ETH2 API client"); - } - return { - ...validatorBN, - isSyncing: (await validatorBN.client.node.getSyncingStatus()).syncDistance === BigInt(0), - currentSlot: String(chainHead.slot), - }; - } catch (e) { - logger.warn(`Error while trying to fetch beacon node status... ${e.message}`); - return validatorBN; - } - }), - ); - yield put(loadedValidatorBeaconNodes(beaconNodes, validator)); } export function* networkSagaWatcher(): Generator { diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index aa193703..d3752f37 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -16,7 +16,6 @@ import { startValidatorService, stopValidatorService, loadValidatorStatus, - loadedValidatorsBalance, stopActiveValidatorService, startNewValidatorService, updateValidatorsFromChain, @@ -127,14 +126,7 @@ function* loadValidatorsFromChain( const validatorBeaconNodes: IValidatorBeaconNodes = yield select(getBeaconNodes); const beaconNodes = validatorBeaconNodes[action.payload[0]]; if (beaconNodes && beaconNodes.length > 0) { - // TODO: Use any working beacon node instead of first one - const client = beaconNodes[0].client; - try { - const response = yield client.beacon.state.getValidators("head", action.payload); - yield put(loadedValidatorsBalance(response)); - } catch (e) { - logger.warn("Error while fetching validator balance...", e.message); - } + logger.warn("Error while fetching validator balance..."); } } diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts index a98cd7fb..333410dc 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts @@ -2,7 +2,7 @@ import {ICGEth2BeaconApi} from "../interface"; import { IBeaconBlocksApi, IBeaconPoolApi, - IBeaconStateApi + IBeaconStateApi, } from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; import {BeaconBlock, Genesis} from "@chainsafe/lodestar-types"; import {HttpClient} from "../../../api"; diff --git a/src/renderer/services/validator/status/index.ts b/src/renderer/services/validator/status/index.ts index 72dd3117..32acb155 100644 --- a/src/renderer/services/validator/status/index.ts +++ b/src/renderer/services/validator/status/index.ts @@ -22,16 +22,14 @@ export async function getValidatorStatus( if (await isBeaconNodeSyncing(eth2Api)) { return ValidatorStatus.SYNCING; } - const validator = await eth2Api.beacon.state.getValidator("head", validatorPubKey); - //TODO: convert to our validator - return (validator.status as unknown) as ValidatorStatus; + return (undefined as unknown) as ValidatorStatus; } async function isBeaconNodeWorking(eth2Api: ICgEth2ApiClient | null): Promise { if (!eth2Api) return false; try { - await eth2Api.getVersion(); return true; + // eslint-disable-next-line no-unreachable } catch (e) { return false; } From c6c4162f7f9496dd0f27520bf0cab6cde808fe27 Mon Sep 17 00:00:00 2001 From: Bernard Date: Thu, 17 Dec 2020 16:28:22 +0100 Subject: [PATCH 17/19] fix grafiti --- src/renderer/ducks/validator/sagas.ts | 2 +- .../eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx | 6 ++++-- src/renderer/services/eth2/networks/local.ts | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index d3752f37..88675eff 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -181,7 +181,7 @@ function* startService( config, secretKeys: [action.payload.privateKey], logger, - graffiti: "ChainGuardian", + // TODO: graffiti: "ChainGuardian", }); } yield validatorServices[publicKey].start(); diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx index 61bbd0ea..42d44fca 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx @@ -84,11 +84,13 @@ export class CgEth2ValidatorApi implements ICGEth2ValidatorApi { }; public produceBlock = async (slot: Slot, randaoReveal: Uint8Array, graffiti: string): Promise => { - const query = querystring.stringify({ + const values = { // eslint-disable-next-line camelcase,@typescript-eslint/camelcase randao_reveal: toHexString(randaoReveal), graffiti: graffiti, - }); + }; + if (!graffiti) delete values.graffiti; + const query = querystring.stringify(values); const responseData = await this.httpClient.get<{data: Json}>(`/eth/v1/validator/blocks/${slot}?${query}`); return this.config.types.BeaconBlock.fromJson(responseData.data, {case: "snake"}); }; diff --git a/src/renderer/services/eth2/networks/local.ts b/src/renderer/services/eth2/networks/local.ts index 649edbdf..ba2708da 100644 --- a/src/renderer/services/eth2/networks/local.ts +++ b/src/renderer/services/eth2/networks/local.ts @@ -17,7 +17,7 @@ export const LocalhostConfig: INetworkConfig = Object.freeze({ ...mainnetBeaconConfig, params: { ...mainnetBeaconConfig.params, - GENESIS_FORK_VERSION: Buffer.from("0x00000001"), + GENESIS_FORK_VERSION: Buffer.from("0x00000000"), }, }, eth1Provider: new ethers.providers.JsonRpcProvider("http://localhost:8545"), From 002312b11df1ccb44f6659c88dfbfeb2caeddbd6 Mon Sep 17 00:00:00 2001 From: Bernard Date: Fri, 18 Dec 2020 10:43:32 +0100 Subject: [PATCH 18/19] implement graffiti --- src/renderer/ducks/validator/sagas.ts | 2 +- .../services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/renderer/ducks/validator/sagas.ts b/src/renderer/ducks/validator/sagas.ts index 88675eff..d3752f37 100644 --- a/src/renderer/ducks/validator/sagas.ts +++ b/src/renderer/ducks/validator/sagas.ts @@ -181,7 +181,7 @@ function* startService( config, secretKeys: [action.payload.privateKey], logger, - // TODO: graffiti: "ChainGuardian", + graffiti: "ChainGuardian", }); } yield validatorServices[publicKey].start(); diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx index 42d44fca..30be6dde 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx @@ -87,7 +87,9 @@ export class CgEth2ValidatorApi implements ICGEth2ValidatorApi { const values = { // eslint-disable-next-line camelcase,@typescript-eslint/camelcase randao_reveal: toHexString(randaoReveal), - graffiti: graffiti, + graffiti: graffiti.startsWith("0x") + ? graffiti + : "0x" + Buffer.from(graffiti, "utf-8").toString("hex").padEnd(64, "0"), }; if (!graffiti) delete values.graffiti; const query = querystring.stringify(values); From 6956e527ea575b83f9b7ed345d1dd778bc528c54 Mon Sep 17 00:00:00 2001 From: Bernard Date: Fri, 18 Dec 2020 13:27:11 +0100 Subject: [PATCH 19/19] implement get block --- .../eth2/client/eth2ApiClient/cgEth2BeaconApi.ts | 16 ++++------------ .../eth2ApiClient/cgEth2BeaconBlocksApi.ts | 10 ++++++++-- .../services/eth2/client/eth2ApiClient/index.ts | 4 ++-- src/renderer/services/eth2/client/interface.ts | 15 +++++++++++---- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts index 333410dc..89b9e0dc 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts @@ -1,10 +1,6 @@ -import {ICGEth2BeaconApi} from "../interface"; -import { - IBeaconBlocksApi, - IBeaconPoolApi, - IBeaconStateApi, -} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; -import {BeaconBlock, Genesis} from "@chainsafe/lodestar-types"; +import {ICGEth2BeaconApi, ICGETH2BeaconBlocksApi} from "../interface"; +import {IBeaconPoolApi, IBeaconStateApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import {Genesis} from "@chainsafe/lodestar-types"; import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {Json} from "@chainsafe/ssz"; @@ -13,7 +9,7 @@ import {CgEth2BeaconStateApi} from "./cgEth2BeaconStateApi"; import {CgEth2BeaconPoolApi} from "./cgEth2BeaconPoolApi"; export class CgEth2BeaconApi implements ICGEth2BeaconApi { - public blocks: IBeaconBlocksApi; + public blocks: ICGETH2BeaconBlocksApi; public state: IBeaconStateApi; public pool: IBeaconPoolApi; @@ -39,8 +35,4 @@ export class CgEth2BeaconApi implements ICGEth2BeaconApi { return null; } }; - - public getChainHead = async (): Promise => { - throw new Error("Method 'getChainHead' not implemented."); - }; } diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts index 6267fd5c..814128f1 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts @@ -1,9 +1,10 @@ -import {IBeaconBlocksApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; import {HttpClient} from "../../../api"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {SignedBeaconBlock} from "@chainsafe/lodestar-types"; +import {Json} from "@chainsafe/ssz"; +import {ICGETH2BeaconBlocksApi} from "../interface"; -export class CgEth2BeaconBlocksApi implements IBeaconBlocksApi { +export class CgEth2BeaconBlocksApi implements ICGETH2BeaconBlocksApi { private readonly httpClient: HttpClient; private readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { @@ -17,4 +18,9 @@ export class CgEth2BeaconBlocksApi implements IBeaconBlocksApi { this.config.types.SignedBeaconBlock.toJson(block, {case: "snake"}), ); }; + + public getBlock = async (blockId: "head" | "genesis" | "finalized" | number): Promise => { + const blocksResponse = await this.httpClient.get<{data: Json}>(`/eth/v1/beacon/blocks/${blockId}`); + return this.config.types.SignedBeaconBlock.fromJson(blocksResponse.data, {case: "snake"}); + }; } diff --git a/src/renderer/services/eth2/client/eth2ApiClient/index.ts b/src/renderer/services/eth2/client/eth2ApiClient/index.ts index 31e181cd..affca159 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/index.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/index.ts @@ -1,4 +1,4 @@ -import {ICGEth2ValidatorApi, IValidatorBeaconClient, ICGEth2BeaconApi, ICGEth2NodeApi} from "../interface"; +import {ICGEth2ValidatorApi, ICGEth2BeaconApi, ICGEth2NodeApi, ICgEth2ApiClient} from "../interface"; import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; import {CgEth2BeaconApi} from "./cgEth2BeaconApi"; @@ -9,7 +9,7 @@ import {CgEth2ValidatorApi} from "./cgEth2ValidatorApi"; import {CgEth2NodeApi} from "./cgEth2NodeApi"; import {CgEth2EventsApi} from "./cgEth2EventsApi"; -export class CgEth2ApiClient extends AbstractApiClient implements IValidatorBeaconClient { +export class CgEth2ApiClient extends AbstractApiClient implements ICgEth2ApiClient { public validator: ICGEth2ValidatorApi; public beacon: ICGEth2BeaconApi; // public node: ICGEth2NodeApi; diff --git a/src/renderer/services/eth2/client/interface.ts b/src/renderer/services/eth2/client/interface.ts index 079dcd11..e9455cef 100644 --- a/src/renderer/services/eth2/client/interface.ts +++ b/src/renderer/services/eth2/client/interface.ts @@ -1,19 +1,26 @@ import {IBeaconConfig} from "@chainsafe/lodestar-config"; import {ILogger} from "@chainsafe/lodestar-utils"; import {IApiClient} from "@chainsafe/lodestar-validator/lib"; -import {IBeaconApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; +import {IBeaconApi, IBeaconBlocksApi} from "@chainsafe/lodestar-validator/lib/api/interface/beacon"; import {INodeApi} from "@chainsafe/lodestar-validator/lib/api/interface/node"; import {IValidatorApi} from "@chainsafe/lodestar-validator/lib/api/interface/validators"; +import {SignedBeaconBlock} from "@chainsafe/lodestar-types"; + +export interface ICGETH2BeaconBlocksApi extends IBeaconBlocksApi { + getBlock(blockId: "head" | "genesis" | "finalized" | number): Promise; +} + +export interface ICGEth2BeaconApi extends Omit { + blocks: ICGETH2BeaconBlocksApi; +} -export type ICGEth2BeaconApi = IBeaconApi; export type ICGEth2NodeApi = INodeApi; export type ICGEth2ValidatorApi = IValidatorApi; /** * Extends minimal interface(IApiClient) required by lodestar validator */ -export interface ICgEth2ApiClient extends IApiClient { - config: IBeaconConfig; +export interface ICgEth2ApiClient extends Omit { beacon: ICGEth2BeaconApi; validator: ICGEth2ValidatorApi; node: ICGEth2NodeApi;