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; }