diff --git a/packages/lodestar/src/api/impl/validator/produceAttestation.ts b/packages/lodestar/src/api/impl/validator/produceAttestation.ts index c9cb3c36e59a..e8c4a5cc2387 100644 --- a/packages/lodestar/src/api/impl/validator/produceAttestation.ts +++ b/packages/lodestar/src/api/impl/validator/produceAttestation.ts @@ -1,9 +1,9 @@ import {assembleAttestation} from "../../../chain/factory/attestation"; -import {Attestation, BeaconState, BLSPubkey, CommitteeIndex, Slot} from "@chainsafe/eth2.0-types"; +import {Attestation, BLSPubkey, CommitteeIndex, Slot} from "@chainsafe/eth2.0-types"; import {IBeaconDb} from "../../../db/api"; import {IBeaconChain} from "../../../chain"; import {IBeaconConfig} from "@chainsafe/eth2.0-config"; -import {clone} from "@chainsafe/ssz"; +import { processSlots } from "@chainsafe/eth2.0-state-transition"; export async function produceAttestation( {config, db, chain}: {config: IBeaconConfig; db: IBeaconDb; chain: IBeaconChain}, @@ -12,11 +12,12 @@ export async function produceAttestation( slot: Slot ): Promise { try { - const [headState, headBlock, validatorIndex] = await Promise.all([ - clone(chain.latestState, config.types.BeaconState) as BeaconState, + const [headBlock, validatorIndex] = await Promise.all([ db.block.get(chain.forkChoice.head()), db.getValidatorIndex(validatorPubKey) ]); + const headState = await db.state.get(headBlock.stateRoot); + await processSlots(config, headState, slot); return await assembleAttestation({config, db}, headState, headBlock, validatorIndex, index, slot); } catch (e) { throw e; diff --git a/packages/lodestar/src/chain/chain.ts b/packages/lodestar/src/chain/chain.ts index ead058617991..89c4a39d985c 100644 --- a/packages/lodestar/src/chain/chain.ts +++ b/packages/lodestar/src/chain/chain.ts @@ -117,10 +117,9 @@ export class BeaconChain extends (EventEmitter as { new(): ChainEventEmitter }) public async receiveAttestation(attestation: Attestation): Promise { const attestationHash = hashTreeRoot(attestation, this.config.types.Attestation); this.logger.info(`Received attestation ${attestationHash.toString("hex")}`); - const latestState = this.latestState; try { const attestationSlot: Slot = attestation.data.slot; - if(attestationSlot + this.config.params.SLOTS_PER_EPOCH < latestState.slot) { + if(attestationSlot + this.config.params.SLOTS_PER_EPOCH < this.latestState.slot) { this.logger.verbose(`Attestation ${attestationHash.toString("hex")} is too old. Ignored.`); return; } @@ -128,7 +127,7 @@ export class BeaconChain extends (EventEmitter as { new(): ChainEventEmitter }) return; } this.attestationProcessingQueue.push(async () => { - return this.processAttestation(latestState, attestation, attestationHash); + return this.processAttestation(attestation, attestationHash); }); } @@ -141,6 +140,8 @@ export class BeaconChain extends (EventEmitter as { new(): ChainEventEmitter }) if(!await this.db.block.has(block.parentRoot)) { this.emit("unknownBlockRoot", block.parentRoot); + this.blockProcessingQueue.add(block); + return; } if(block.slot <= this.latestState.slot) { @@ -151,25 +152,11 @@ export class BeaconChain extends (EventEmitter as { new(): ChainEventEmitter }) return; } - if(block.slot > this.latestState.slot) { - //either block came too early or we are suppose to skip some slots - const latestBlock = await this.db.block.getChainHead(); - if(!block.parentRoot.equals(signingRoot(latestBlock, this.config.types.BeaconBlock))){ - //block processed too early - this.logger.warn(`Block ${blockHash.toString("hex")} tried to be processed too early. Requeue...`); - //wait a bit to give new block a chance - await sleep(500); - // add to priority queue - this.blockProcessingQueue.add(block); - return; - } - } await this.processBlock(block, blockHash); const nextBlockInQueue = this.blockProcessingQueue.peek(); while (nextBlockInQueue) { - const latestBlock = await this.db.block.getChainHead(); - if (nextBlockInQueue.parentRoot.equals(signingRoot(latestBlock, this.config.types.BeaconBlock))) { + if (await this.db.block.has(nextBlockInQueue.parentRoot)) { await this.processBlock(nextBlockInQueue, signingRoot(nextBlockInQueue, this.config.types.BeaconBlock)); this.blockProcessingQueue.poll(); } else{ @@ -242,16 +229,19 @@ export class BeaconChain extends (EventEmitter as { new(): ChainEventEmitter }) return Math.floor(Date.now() / 1000) >= stateSlotTime; } - private processAttestation = async (latestState: BeaconState, attestation: Attestation, attestationHash: Hash) => { - const currentSlot = getCurrentSlot(this.config, latestState.genesisTime); + private processAttestation = async (attestation: Attestation, attestationHash: Hash) => { + const justifiedCheckpoint = this.forkChoice.getJustified(); + const justifiedBlock = await this.db.block.get(justifiedCheckpoint.root); + const checkpointState = await this.db.state.get(justifiedBlock.stateRoot); + const currentSlot = getCurrentSlot(this.config, checkpointState.genesisTime); const currentEpoch = computeEpochAtSlot(this.config, currentSlot); const previousEpoch = currentEpoch > GENESIS_EPOCH ? currentEpoch - 1 : GENESIS_EPOCH; const epoch = attestation.data.target.epoch; assert([currentEpoch, previousEpoch].includes(epoch)); const validators = getAttestingIndices( - this.config, latestState, attestation.data, attestation.aggregationBits); - const balances = validators.map((index) => latestState.balances[index]); + this.config, checkpointState, attestation.data, attestation.aggregationBits); + const balances = validators.map((index) => checkpointState.balances[index]); for (let i = 0; i < validators.length; i++) { this.forkChoice.addAttestation(attestation.data.beaconBlockRoot, validators[i], balances[i]); } @@ -260,12 +250,12 @@ export class BeaconChain extends (EventEmitter as { new(): ChainEventEmitter }) }; private processBlock = async (block: BeaconBlock, blockHash: Hash) => { - - const isValidBlock = await this.isValidBlock(this.latestState, block); + const parentBlock = await this.db.block.get(block.parentRoot); + const pre = await this.db.state.get(parentBlock.stateRoot); + const isValidBlock = await this.isValidBlock(pre, block); assert(isValidBlock); this.logger.info(`0x${blockHash.toString("hex")} is valid, running state transition...`); - const pre = this.latestState; // process current slot const post = await this.runStateTransition(block, pre); @@ -337,7 +327,7 @@ export class BeaconChain extends (EventEmitter as { new(): ChainEventEmitter }) await this.db.setChainHeadRoots(blockRoot, block.stateRoot); this.forkChoice.addBlock(block.slot, blockRoot, block.parentRoot, newState.currentJustifiedCheckpoint, newState.finalizedCheckpoint); - // await this.applyForkChoiceRule(); + await this.applyForkChoiceRule(); await this.updateDepositMerkleTree(newState); // update metrics this.metrics.currentSlot.set(block.slot); diff --git a/packages/lodestar/src/chain/forkChoice/interface.ts b/packages/lodestar/src/chain/forkChoice/interface.ts index 0686727b67bc..a727905e4347 100644 --- a/packages/lodestar/src/chain/forkChoice/interface.ts +++ b/packages/lodestar/src/chain/forkChoice/interface.ts @@ -11,4 +11,5 @@ export interface ILMDGHOST { finalizedCheckpoint: Checkpoint): void; addAttestation(blockRootBuf: Hash, attester: ValidatorIndex, weight: Gwei): void; head(): Hash; + getJustified(): Checkpoint; } diff --git a/packages/lodestar/src/chain/forkChoice/statefulDag/lmdGhost.ts b/packages/lodestar/src/chain/forkChoice/statefulDag/lmdGhost.ts index 505e8d8f54bb..2d98939dd73c 100644 --- a/packages/lodestar/src/chain/forkChoice/statefulDag/lmdGhost.ts +++ b/packages/lodestar/src/chain/forkChoice/statefulDag/lmdGhost.ts @@ -290,6 +290,13 @@ export class StatefulDagLMDGHOST implements ILMDGHOST { return true; } + public getJustified(): Checkpoint { + if (!this.justified) { + return null; + } + return {root: Buffer.from(this.justified.node.blockRoot, "hex"), epoch: this.justified.epoch}; + } + private setFinalized(checkpoint: Checkpoint): void { this.synced = false; const rootHex = checkpoint.root.toString("hex"); diff --git a/packages/lodestar/src/chain/interface.ts b/packages/lodestar/src/chain/interface.ts index 5bc31365ad2e..587a41f9f602 100644 --- a/packages/lodestar/src/chain/interface.ts +++ b/packages/lodestar/src/chain/interface.ts @@ -38,7 +38,7 @@ export interface IBeaconChain extends ChainEventEmitter { /** * Add attestation to the fork-choice rule */ - receiveAttestation(attestation: Attestation): Promise; + receiveAttestation(attestation: Attestation, beaconState?: BeaconState): Promise; /** * Pre-process and run the per slot state transition function