Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {EpochContext} from "../util";
import {BeaconBlock, BeaconState} from "@chainsafe/lodestar-types";
import {EpochContext, CachedValidatorsBeaconState} from "../util";
import {BeaconBlock} from "@chainsafe/lodestar-types";

import {processBlockHeader} from "./processBlockHeader";
import {processRandao} from "./processRandao";
Expand All @@ -25,7 +25,7 @@ export {

export function processBlock(
epochCtx: EpochContext,
state: BeaconState,
state: CachedValidatorsBeaconState,
block: BeaconBlock,
verifySignatures = true
): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import {readOnlyMap} from "@chainsafe/ssz";
import {BeaconState, ValidatorIndex} from "@chainsafe/lodestar-types";
import {ValidatorIndex} from "@chainsafe/lodestar-types";

import {FAR_FUTURE_EPOCH} from "../../constants";
import {computeActivationExitEpoch, getChurnLimit} from "../../util";
import {EpochContext} from "../util";
import {EpochContext, CachedValidatorsBeaconState} from "../util";

/**
* Initiate the exit of the validator with index ``index``.
*/
export function initiateValidatorExit(epochCtx: EpochContext, state: BeaconState, index: ValidatorIndex): void {
export function initiateValidatorExit(
epochCtx: EpochContext,
state: CachedValidatorsBeaconState,
index: ValidatorIndex
): void {
const config = epochCtx.config;
// return if validator already initiated exit
const validator = state.validators[index];
if (validator.exitEpoch !== FAR_FUTURE_EPOCH) {
if (state.validators[index].exitEpoch !== FAR_FUTURE_EPOCH) {
return;
}

const currentEpoch = epochCtx.currentShuffling.epoch;

// compute exit queue epoch
const validatorExitEpochs = readOnlyMap(state.validators, (v) => v.exitEpoch);
const validatorExitEpochs = state.flatValidators().map((v) => v.exitEpoch);
const exitEpochs = validatorExitEpochs.filter((exitEpoch) => exitEpoch !== FAR_FUTURE_EPOCH);
exitEpochs.push(computeActivationExitEpoch(config, currentEpoch));
let exitQueueEpoch = Math.max(...exitEpochs);
Expand All @@ -29,6 +31,8 @@ export function initiateValidatorExit(epochCtx: EpochContext, state: BeaconState
}

// set validator exit epoch and withdrawable epoch
validator.exitEpoch = exitQueueEpoch;
validator.withdrawableEpoch = validator.exitEpoch + config.params.MIN_VALIDATOR_WITHDRAWABILITY_DELAY;
state.setValidator(index, {
exitEpoch: exitQueueEpoch,
withdrawableEpoch: exitQueueEpoch + config.params.MIN_VALIDATOR_WITHDRAWABILITY_DELAY,
});
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {AttesterSlashing, BeaconState} from "@chainsafe/lodestar-types";
import {AttesterSlashing, ValidatorIndex} from "@chainsafe/lodestar-types";

import {isSlashableValidator, isSlashableAttestationData} from "../../util";
import {EpochContext} from "../util";
import {EpochContext, CachedValidatorsBeaconState} from "../util";
import {slashValidator} from "./slashValidator";
import {isValidIndexedAttestation} from "./isValidIndexedAttestation";

export function processAttesterSlashing(
epochCtx: EpochContext,
state: BeaconState,
state: CachedValidatorsBeaconState,
attesterSlashing: AttesterSlashing,
verifySignatures = true
): void {
Expand All @@ -27,7 +27,7 @@ export function processAttesterSlashing(
let slashedAny = false;
const attSet1 = new Set(attestation1.attestingIndices);
const attSet2 = new Set(attestation2.attestingIndices);
const indices = [];
const indices: ValidatorIndex[] = [];
for (const i of attSet1.values()) {
if (attSet2.has(i)) {
indices.push(i);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import bls from "@chainsafe/bls";
import {BeaconState, Deposit} from "@chainsafe/lodestar-types";
import {Deposit} from "@chainsafe/lodestar-types";
import {verifyMerkleBranch, bigIntMin} from "@chainsafe/lodestar-utils";

import {DEPOSIT_CONTRACT_TREE_DEPTH, DomainType, FAR_FUTURE_EPOCH} from "../../constants";
import {computeDomain, computeSigningRoot, increaseBalance} from "../../util";
import {EpochContext} from "../util";
import {EpochContext, CachedValidatorsBeaconState} from "../util";

export function processDeposit(epochCtx: EpochContext, state: BeaconState, deposit: Deposit): void {
export function processDeposit(epochCtx: EpochContext, state: CachedValidatorsBeaconState, deposit: Deposit): void {
const config = epochCtx.config;
const {EFFECTIVE_BALANCE_INCREMENT, MAX_EFFECTIVE_BALANCE} = config.params;
// verify the merkle branch
Expand Down Expand Up @@ -43,7 +43,7 @@ export function processDeposit(epochCtx: EpochContext, state: BeaconState, depos
}

// add validator and balance entries
state.validators.push({
state.addValidator({
pubkey: pubkey,
withdrawalCredentials: deposit.data.withdrawalCredentials,
activationEligibilityEpoch: FAR_FUTURE_EPOCH,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,29 @@ import {
Attestation,
AttesterSlashing,
BeaconBlockBody,
BeaconState,
Deposit,
ProposerSlashing,
VoluntaryExit,
} from "@chainsafe/lodestar-types";

import {EpochContext} from "../util";
import {EpochContext, CachedValidatorsBeaconState} from "../util";
import {processProposerSlashing} from "./processProposerSlashing";
import {processAttesterSlashing} from "./processAttesterSlashing";
import {processAttestation} from "./processAttestation";
import {processDeposit} from "./processDeposit";
import {processVoluntaryExit} from "./processVoluntaryExit";

type Operation = ProposerSlashing | AttesterSlashing | Attestation | Deposit | VoluntaryExit;
type OperationFunction = (epochCtx: EpochContext, state: BeaconState, op: Operation, verify: boolean) => void;
type OperationFunction = (
epochCtx: EpochContext,
state: CachedValidatorsBeaconState,
op: Operation,
verify: boolean
) => void;

export function processOperations(
epochCtx: EpochContext,
state: BeaconState,
state: CachedValidatorsBeaconState,
body: BeaconBlockBody,
verifySignatures = true
): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {BeaconState, ProposerSlashing} from "@chainsafe/lodestar-types";
import {DomainType} from "../../constants";
import {computeEpochAtSlot, computeSigningRoot, getDomain, isSlashableValidator} from "../../util";
import {EpochContext} from "../util";
import {EpochContext, CachedValidatorsBeaconState} from "../util";
import {slashValidator} from "./slashValidator";
import {ISignatureSet, SignatureSetType, verifySignatureSet} from "../signatureSets";

export function processProposerSlashing(
epochCtx: EpochContext,
state: BeaconState,
state: CachedValidatorsBeaconState,
proposerSlashing: ProposerSlashing,
verifySignatures = true
): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import {BeaconState, SignedVoluntaryExit} from "@chainsafe/lodestar-types";
import {DomainType, FAR_FUTURE_EPOCH} from "../../constants";
import {computeSigningRoot, getDomain, isActiveValidator} from "../../util";
import {ISignatureSet, SignatureSetType, verifySignatureSet} from "../signatureSets";
import {EpochContext} from "../util";
import {EpochContext, CachedValidatorsBeaconState} from "../util";
import {initiateValidatorExit} from "./initiateValidatorExit";

export function processVoluntaryExit(
epochCtx: EpochContext,
state: BeaconState,
state: CachedValidatorsBeaconState,
signedVoluntaryExit: SignedVoluntaryExit,
verifySignature = true
): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {BeaconState, ValidatorIndex} from "@chainsafe/lodestar-types";
import {ValidatorIndex} from "@chainsafe/lodestar-types";

import {decreaseBalance, increaseBalance} from "../../util";
import {EpochContext} from "../util";
import {EpochContext, CachedValidatorsBeaconState} from "../util";
import {initiateValidatorExit} from "./initiateValidatorExit";

export function slashValidator(
epochCtx: EpochContext,
state: BeaconState,
state: CachedValidatorsBeaconState,
slashedIndex: ValidatorIndex,
whistleblowerIndex?: ValidatorIndex
): void {
Expand All @@ -19,8 +19,10 @@ export function slashValidator(
const epoch = epochCtx.currentShuffling.epoch;
initiateValidatorExit(epochCtx, state, slashedIndex);
const validator = state.validators[slashedIndex];
validator.slashed = true;
validator.withdrawableEpoch = Math.max(validator.withdrawableEpoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR);
state.setValidator(slashedIndex, {
slashed: true,
withdrawableEpoch: Math.max(validator.withdrawableEpoch, epoch + EPOCHS_PER_SLASHINGS_VECTOR),
});
state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effectiveBalance;
decreaseBalance(state, slashedIndex, validator.effectiveBalance / BigInt(MIN_SLASHING_PENALTY_QUOTIENT));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import {BeaconState} from "@chainsafe/lodestar-types";

import {prepareEpochProcessState} from "../util";
import {CachedValidatorsBeaconState, prepareEpochProcessState} from "../util";
import {StateTransitionEpochContext} from "../util/epochContext";
import {processJustificationAndFinalization} from "./processJustificationAndFinalization";
import {processRewardsAndPenalties} from "./processRewardsAndPenalties";
Expand All @@ -20,7 +18,7 @@ export {
getAttestationDeltas,
};

export function processEpoch(epochCtx: StateTransitionEpochContext, state: BeaconState): void {
export function processEpoch(epochCtx: StateTransitionEpochContext, state: CachedValidatorsBeaconState): void {
const process = prepareEpochProcessState(epochCtx, state);
epochCtx.epochProcess = process;
processJustificationAndFinalization(epochCtx, process, state);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import {readOnlyMap, List} from "@chainsafe/ssz";
import {BeaconState, Eth1Data, PendingAttestation} from "@chainsafe/lodestar-types";
import {Eth1Data, PendingAttestation} from "@chainsafe/lodestar-types";
import {bigIntMin, intDiv} from "@chainsafe/lodestar-utils";

import {getRandaoMix} from "../../util";
import {EpochContext, IEpochProcess} from "../util";
import {EpochContext, IEpochProcess, CachedValidatorsBeaconState} from "../util";

export function processFinalUpdates(epochCtx: EpochContext, process: IEpochProcess, state: BeaconState): void {
export function processFinalUpdates(
epochCtx: EpochContext,
process: IEpochProcess,
state: CachedValidatorsBeaconState
): void {
const config = epochCtx.config;
const currentEpoch = process.currentEpoch;
const nextEpoch = currentEpoch + 1;
Expand Down Expand Up @@ -37,10 +41,9 @@ export function processFinalUpdates(epochCtx: EpochContext, process: IEpochProce
const balance = balances[i];
const effectiveBalance = status.validator.effectiveBalance;
if (balance + DOWNWARD_THRESHOLD < effectiveBalance || effectiveBalance + UPWARD_THRESHOLD < balance) {
state.validators[i].effectiveBalance = bigIntMin(
balance - (balance % EFFECTIVE_BALANCE_INCREMENT),
MAX_EFFECTIVE_BALANCE
);
state.setValidator(i, {
effectiveBalance: bigIntMin(balance - (balance % EFFECTIVE_BALANCE_INCREMENT), MAX_EFFECTIVE_BALANCE),
});
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import {BeaconState} from "@chainsafe/lodestar-types";

import {computeActivationExitEpoch} from "../../util";
import {EpochContext, IEpochProcess} from "../util";
import {EpochContext, IEpochProcess, CachedValidatorsBeaconState} from "../util";

export function processRegistryUpdates(epochCtx: EpochContext, process: IEpochProcess, state: BeaconState): void {
export function processRegistryUpdates(
epochCtx: EpochContext,
process: IEpochProcess,
state: CachedValidatorsBeaconState
): void {
const config = epochCtx.config;
let exitEnd = process.exitQueueEnd;
let endChurn = process.exitQueueEndChurn;
const {MIN_VALIDATOR_WITHDRAWABILITY_DELAY} = epochCtx.config.params;
// process ejections
process.indicesToEject.forEach((index) => {
const validator = state.validators[index];

// set validator exit epoch and withdrawable epoch
validator.exitEpoch = exitEnd;
validator.withdrawableEpoch = exitEnd + MIN_VALIDATOR_WITHDRAWABILITY_DELAY;
state.setValidator(index, {
exitEpoch: exitEnd,
withdrawableEpoch: exitEnd + MIN_VALIDATOR_WITHDRAWABILITY_DELAY,
});

endChurn += 1;
if (endChurn >= process.churnLimit) {
Expand All @@ -25,7 +27,9 @@ export function processRegistryUpdates(epochCtx: EpochContext, process: IEpochPr

// set new activation eligibilities
process.indicesToSetActivationEligibility.forEach((index) => {
state.validators[index].activationEligibilityEpoch = epochCtx.currentShuffling.epoch + 1;
state.setValidator(index, {
activationEligibilityEpoch: epochCtx.currentShuffling.epoch + 1,
});
});

const finalityEpoch = state.finalizedCheckpoint.epoch;
Expand All @@ -35,6 +39,8 @@ export function processRegistryUpdates(epochCtx: EpochContext, process: IEpochPr
if (process.statuses[index].validator.activationEligibilityEpoch > finalityEpoch) {
break; // remaining validators all have an activationEligibilityEpoch that is higher anyway, break early
}
state.validators[index].activationEpoch = computeActivationExitEpoch(config, process.currentEpoch);
state.setValidator(index, {
activationEpoch: computeActivationExitEpoch(config, process.currentEpoch),
});
}
}
11 changes: 7 additions & 4 deletions packages/lodestar-beacon-state-transition/src/fast/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {BeaconState, SignedBeaconBlock} from "@chainsafe/lodestar-types";
import {SignedBeaconBlock} from "@chainsafe/lodestar-types";

import {verifyBlockSignature} from "./util";
import {CachedValidatorsBeaconState, verifyBlockSignature} from "./util";
import {IStateContext} from "./util";
import {StateTransitionEpochContext} from "./util/epochContext";
import {EpochContext} from "./util/epochContext";
Expand All @@ -22,7 +22,7 @@ export function fastStateTransition(
const types = epochCtx.config.types;

const block = signedBlock.message;
const postState = types.BeaconState.clone(state);
const postState = state.clone();
// process slots (including those with no blocks) since block
processSlots(epochCtx, postState, block.slot);

Expand All @@ -46,7 +46,10 @@ export function fastStateTransition(
/**
* Trim epochProcess in epochCtx, and insert the standard/exchange interface epochProcess to the final IStateContext
*/
export function toIStateContext(epochCtx: StateTransitionEpochContext, state: BeaconState): IStateContext {
export function toIStateContext(
epochCtx: StateTransitionEpochContext,
state: CachedValidatorsBeaconState
): IStateContext {
const epochProcess = epochCtx.epochProcess;
epochCtx.epochProcess = undefined;
return {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import {BeaconState, Slot} from "@chainsafe/lodestar-types";
import {Slot} from "@chainsafe/lodestar-types";

import {StateTransitionEpochContext} from "../util/epochContext";
import {processEpoch} from "../epoch";
import {processSlot} from "./processSlot";
import {CachedValidatorsBeaconState} from "../util/interface";

export {processSlot};

export function processSlots(epochCtx: StateTransitionEpochContext, state: BeaconState, slot: Slot): void {
export function processSlots(
epochCtx: StateTransitionEpochContext,
state: CachedValidatorsBeaconState,
slot: Slot
): void {
if (!(state.slot < slot)) {
throw new Error("State slot must transition to a future slot: " + `stateSlot=${state.slot} slot=${slot}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
} from "../../util";
import {computeEpochShuffling, IEpochShuffling} from "./epochShuffling";
import {IEpochProcess} from "./epochProcess";
import {CachedValidatorsBeaconState} from "./interface";

export class PubkeyIndexMap extends Map<ByteVector, ValidatorIndex> {
get(key: ByteVector): ValidatorIndex | undefined {
Expand Down Expand Up @@ -138,15 +139,13 @@ export class EpochContext {
* Called to re-use information, such as the shuffling of the next epoch, after transitioning into a
* new epoch.
*/
public rotateEpochs(state: BeaconState): void {
public rotateEpochs(state: CachedValidatorsBeaconState): void {
this.previousShuffling = this.currentShuffling;
this.currentShuffling = this.nextShuffling;
const nextEpoch = this.currentShuffling.epoch + 1;
const indicesBounded: [ValidatorIndex, Epoch, Epoch][] = readOnlyMap(state.validators, (v, i) => [
i,
v.activationEpoch,
v.exitEpoch,
]);
const indicesBounded: [ValidatorIndex, Epoch, Epoch][] = state
.flatValidators()
.map((v, i) => [i, v.activationEpoch, v.exitEpoch]);
this.nextShuffling = computeEpochShuffling(this.config, state, indicesBounded, nextEpoch);
this._resetProposers(state);
}
Expand Down
Loading