@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
78 lines (70 loc) • 2.81 kB
text/typescript
import {
assertValidAttesterSlashing,
getAttesterSlashableIndices,
getAttesterSlashingSignatureSets,
isSlashableValidator,
} from "@lodestar/state-transition";
import {AttesterSlashing} from "@lodestar/types";
import {AttesterSlashingError, AttesterSlashingErrorCode, GossipAction} from "../errors/index.js";
import {IBeaconChain} from "../index.js";
export async function validateApiAttesterSlashing(
chain: IBeaconChain,
attesterSlashing: AttesterSlashing
): Promise<void> {
const prioritizeBls = true;
return validateAttesterSlashing(chain, attesterSlashing, prioritizeBls);
}
export async function validateGossipAttesterSlashing(
chain: IBeaconChain,
attesterSlashing: AttesterSlashing
): Promise<void> {
return validateAttesterSlashing(chain, attesterSlashing);
}
export async function validateAttesterSlashing(
chain: IBeaconChain,
attesterSlashing: AttesterSlashing,
prioritizeBls = false
): Promise<void> {
// [IGNORE] At least one index in the intersection of the attesting indices of each attestation has not yet been seen
// in any prior attester_slashing (i.e.
// attester_slashed_indices = set(attestation_1.attesting_indices).intersection(attestation_2.attesting_indices
// ), verify if any(attester_slashed_indices.difference(prior_seen_attester_slashed_indices))).
const intersectingIndices = getAttesterSlashableIndices(attesterSlashing);
if (chain.opPool.hasSeenAttesterSlashing(intersectingIndices)) {
throw new AttesterSlashingError(GossipAction.IGNORE, {
code: AttesterSlashingErrorCode.ALREADY_EXISTS,
});
}
const state = chain.getHeadState();
// [REJECT] All of the conditions within process_attester_slashing pass validation.
try {
// verifySignature = false, verified in batch below
assertValidAttesterSlashing(
chain.config,
chain.pubkeyCache,
state.slot,
state.validatorCount,
attesterSlashing,
false
);
} catch (e) {
throw new AttesterSlashingError(GossipAction.REJECT, {
code: AttesterSlashingErrorCode.INVALID,
error: e as Error,
});
}
const currentEpoch = state.epoch;
if (!intersectingIndices.some((index) => isSlashableValidator(state.getValidator(index), currentEpoch))) {
throw new AttesterSlashingError(GossipAction.REJECT, {
code: AttesterSlashingErrorCode.INVALID,
error: Error("AttesterSlashing has no slashable validators"),
});
}
const signatureSets = getAttesterSlashingSignatureSets(chain.config, state.slot, attesterSlashing);
if (!(await chain.bls.verifySignatureSets(signatureSets, {batchable: true, priority: prioritizeBls}))) {
throw new AttesterSlashingError(GossipAction.REJECT, {
code: AttesterSlashingErrorCode.INVALID,
error: Error("Invalid signature"),
});
}
}