Skip to content

Commit

Permalink
Merge 92f5e3c into c357ef9
Browse files Browse the repository at this point in the history
  • Loading branch information
dapplion authored Sep 10, 2021
2 parents c357ef9 + 92f5e3c commit 77ad181
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 113 deletions.
48 changes: 44 additions & 4 deletions packages/lodestar/src/api/impl/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
computeStartSlotAtEpoch,
proposerShufflingDecisionRoot,
attesterShufflingDecisionRoot,
getBlockRootAtSlot,
computeEpochAtSlot,
} from "@chainsafe/lodestar-beacon-state-transition";
import {
GENESIS_SLOT,
Expand All @@ -13,7 +15,6 @@ import {
SYNC_COMMITTEE_SUBNET_COUNT,
} from "@chainsafe/lodestar-params";
import {allForks, Root, Slot, ValidatorIndex, ssz} from "@chainsafe/lodestar-types";
import {assembleAttestationData} from "../../../chain/factory/attestation";
import {assembleBlock} from "../../../chain/factory/block";
import {AttestationError, AttestationErrorCode, GossipAction, SyncCommitteeError} from "../../../chain/errors";
import {validateGossipAggregateAndProof} from "../../../chain/validation";
Expand Down Expand Up @@ -165,9 +166,46 @@ export function getValidatorApi({

await waitForSlot(slot); // Must never request for a future slot > currentSlot

const headRoot = chain.forkChoice.getHeadRoot();
const state = await chain.regen.getBlockSlotState(headRoot, slot, RegenCaller.produceAttestationData);
return {data: assembleAttestationData(state, headRoot, slot, committeeIndex)};
// This needs a state in the same epoch as `slot` such that state.currentJustifiedCheckpoint is correct.
// Note: This may trigger an epoch transition if there skipped slots at the begining of the epoch.
const headState = chain.getHeadState();
const headSlot = headState.slot;
const attEpoch = computeEpochAtSlot(slot);
const headEpoch = computeEpochAtSlot(headSlot);
const headBlockRoot = chain.forkChoice.getHeadRoot();

const beaconBlockRoot =
slot >= headSlot
? // When attesting to the head slot or later, always use the head of the chain.
headBlockRoot
: // Permit attesting to slots *prior* to the current head. This is desirable when
// the VC and BN are out-of-sync due to time issues or overloading.
getBlockRootAtSlot(headState, slot);

const targetSlot = computeStartSlotAtEpoch(attEpoch);
const targetRoot =
targetSlot >= headSlot
? // If the state is earlier than the target slot then the target *must* be the head block root.
headBlockRoot
: getBlockRootAtSlot(headState, targetSlot);

// To get the correct source we must get a state in the same epoch as the attestation's epoch.
// An epoch transition may change state.currentJustifiedCheckpoint
const attEpochState =
attEpoch <= headEpoch
? headState
: // Will advance the state to the correct next epoch if necessary
await chain.regen.getBlockSlotState(headBlockRoot, slot, RegenCaller.produceAttestationData);

return {
data: {
slot,
index: committeeIndex,
beaconBlockRoot,
source: attEpochState.currentJustifiedCheckpoint,
target: {epoch: attEpoch, root: targetRoot},
},
};
},

/**
Expand Down Expand Up @@ -295,6 +333,8 @@ export function getValidatorApi({
// May request for an epoch that's in the future
await waitForNextClosestEpoch();

// sync committee duties have a lookahead of 1 day. Assuming the validator only requests duties for upcomming
// epochs, the head state will very likely have the duties available for the requested epoch.
// Note: does not support requesting past duties
const state = chain.getHeadState();

Expand Down
22 changes: 1 addition & 21 deletions packages/lodestar/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,7 @@ export class BeaconChain implements IBeaconChain {
const currentEpochStartSlot = computeStartSlotAtEpoch(this.clock.currentEpoch);
const head = this.forkChoice.getHead();
const bestSlot = currentEpochStartSlot > head.slot ? currentEpochStartSlot : head.slot;
return await this.regen.getBlockSlotState(head.blockRoot, bestSlot, RegenCaller.getProposerAttesterDuties);
}

async getHeadStateAtCurrentSlot(): Promise<CachedBeaconState<allForks.BeaconState>> {
return await this.regen.getBlockSlotState(
this.forkChoice.getHeadRoot(),
this.clock.currentSlot,
RegenCaller.getProposerAttesterDuties
);
return await this.regen.getBlockSlotState(head.blockRoot, bestSlot, RegenCaller.getDuties);
}

async getHeadBlock(): Promise<allForks.SignedBeaconBlock | null> {
Expand All @@ -211,18 +203,6 @@ export class BeaconChain implements IBeaconChain {
return await this.db.block.get(summary.blockRoot);
}

async getStateByBlockRoot(blockRoot: Root): Promise<CachedBeaconState<allForks.BeaconState> | null> {
const blockSummary = this.forkChoice.getBlock(blockRoot);
if (!blockSummary) {
return null;
}
try {
return await this.regen.getState(blockSummary.stateRoot, RegenCaller.getStateByBlockRoot);
} catch (e) {
return null;
}
}

/** Returned blocks have the same ordering as `slots` */
async getUnfinalizedBlocksAtSlots(slots: Slot[]): Promise<allForks.SignedBeaconBlock[]> {
if (slots.length === 0) {
Expand Down
38 changes: 0 additions & 38 deletions packages/lodestar/src/chain/factory/attestation/data.ts

This file was deleted.

7 changes: 0 additions & 7 deletions packages/lodestar/src/chain/factory/attestation/index.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/lodestar/src/chain/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ export interface IBeaconChain {

getHeadState(): CachedBeaconState<allForks.BeaconState>;
getHeadStateAtCurrentEpoch(): Promise<CachedBeaconState<allForks.BeaconState>>;
getHeadStateAtCurrentSlot(): Promise<CachedBeaconState<allForks.BeaconState>>;
getHeadBlock(): Promise<allForks.SignedBeaconBlock | null>;

/**
Expand All @@ -93,7 +92,6 @@ export interface IBeaconChain {
* @param slot
*/
getCanonicalBlockAtSlot(slot: Slot): Promise<allForks.SignedBeaconBlock | null>;
getStateByBlockRoot(blockRoot: Root): Promise<CachedBeaconState<allForks.BeaconState> | null>;
getUnfinalizedBlocksAtSlots(slots: Slot[]): Promise<allForks.SignedBeaconBlock[]>;
getFinalizedCheckpoint(): phase0.Checkpoint;

Expand Down
13 changes: 6 additions & 7 deletions packages/lodestar/src/chain/regen/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import {allForks, phase0, Root, Slot} from "@chainsafe/lodestar-types";
import {CachedBeaconState} from "@chainsafe/lodestar-beacon-state-transition";

export enum RegenCaller {
getProposerAttesterDuties = "getProposerAttesterDuties",
getDuties = "getDuties",
produceBlock = "produceBlock",
validateGossipBlock = "validateGossipBlock",
produceAttestationData = "produceAttestationData",
getStateByBlockRoot = "getStateByBlockRoot",
processBlocksInEpoch = "processBlocksInEpoch",
validateGossipAggregateAndProof = "validateGossipAggregateAndProof",
validateGossipAttestation = "validateGossipAttestation",
Expand All @@ -28,25 +27,25 @@ export interface IStateRegenerator {
* Return a valid pre-state for a beacon block
* This will always return a state in the latest viable epoch
*/
getPreState: (block: allForks.BeaconBlock, rCaller: RegenCaller) => Promise<CachedBeaconState<allForks.BeaconState>>;
getPreState(block: allForks.BeaconBlock, rCaller: RegenCaller): Promise<CachedBeaconState<allForks.BeaconState>>;

/**
* Return a valid checkpoint state
* This will always return a state with `state.slot % SLOTS_PER_EPOCH === 0`
*/
getCheckpointState: (cp: phase0.Checkpoint, rCaller: RegenCaller) => Promise<CachedBeaconState<allForks.BeaconState>>;
getCheckpointState(cp: phase0.Checkpoint, rCaller: RegenCaller): Promise<CachedBeaconState<allForks.BeaconState>>;

/**
* Return the state of `blockRoot` processed to slot `slot`
*/
getBlockSlotState: (
getBlockSlotState(
blockRoot: Root,
slot: Slot,
rCaller: RegenCaller
) => Promise<CachedBeaconState<allForks.BeaconState>>;
): Promise<CachedBeaconState<allForks.BeaconState>>;

/**
* Return the exact state with `stateRoot`
*/
getState: (stateRoot: Root, rCaller: RegenCaller) => Promise<CachedBeaconState<allForks.BeaconState>>;
getState(stateRoot: Root, rCaller: RegenCaller): Promise<CachedBeaconState<allForks.BeaconState>>;
}
26 changes: 0 additions & 26 deletions packages/lodestar/test/unit/chain/factory/attestation/data.test.ts

This file was deleted.

8 changes: 0 additions & 8 deletions packages/lodestar/test/utils/mocks/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,6 @@ export class MockBeaconChain implements IBeaconChain {
return createCachedBeaconState(this.config, this.state);
}

async getHeadStateAtCurrentSlot(): Promise<CachedBeaconState<allForks.BeaconState>> {
return createCachedBeaconState(this.config, this.state);
}

async getCanonicalBlockAtSlot(slot: Slot): Promise<allForks.SignedBeaconBlock> {
const block = generateEmptySignedBlock();
block.message.slot = slot;
Expand Down Expand Up @@ -180,10 +176,6 @@ export class MockBeaconChain implements IBeaconChain {

async persistToDisk(): Promise<void> {}

async getStateByBlockRoot(): Promise<CachedBeaconState<allForks.BeaconState> | null> {
return null;
}

getStatus(): phase0.Status {
return {
forkDigest: this.getHeadForkDigest(),
Expand Down

0 comments on commit 77ad181

Please sign in to comment.