Skip to content

Commit

Permalink
Optimize uint (#3977)
Browse files Browse the repository at this point in the history
  • Loading branch information
dapplion authored May 5, 2022
1 parent 7d78388 commit e8f60b6
Show file tree
Hide file tree
Showing 19 changed files with 237 additions and 150 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,48 @@
import {MAX_VALIDATORS_PER_COMMITTEE} from "@chainsafe/lodestar-params";
import {phase0} from "@chainsafe/lodestar-types";
import {CachedBeaconStateAllForks} from "../../types";
import {verifyIndexedAttestationSignature} from "../signatureSets";
import {verifySignatureSet} from "../../util";
import {getIndexedAttestationBnSignatureSet, getIndexedAttestationSignatureSet} from "../signatureSets";

/**
* Check if `indexedAttestation` has sorted and unique indices and a valid aggregate signature.
*/
export function isValidIndexedAttestation(
state: CachedBeaconStateAllForks,
indexedAttestation: phase0.IndexedAttestation,
verifySignature = true
verifySignature: boolean
): boolean {
const indices = indexedAttestation.attestingIndices;
if (!isValidIndexedAttestationIndices(state, indexedAttestation.attestingIndices)) {
return false;
}

if (verifySignature) {
return verifySignatureSet(getIndexedAttestationSignatureSet(state, indexedAttestation));
} else {
return true;
}
}

export function isValidIndexedAttestationBn(
state: CachedBeaconStateAllForks,
indexedAttestation: phase0.IndexedAttestationBn,
verifySignature: boolean
): boolean {
if (!isValidIndexedAttestationIndices(state, indexedAttestation.attestingIndices)) {
return false;
}

if (verifySignature) {
return verifySignatureSet(getIndexedAttestationBnSignatureSet(state, indexedAttestation));
} else {
return true;
}
}

/**
* Check if `indexedAttestation` has sorted and unique indices and a valid aggregate signature.
*/
export function isValidIndexedAttestationIndices(state: CachedBeaconStateAllForks, indices: number[]): boolean {
// verify max number of indices
if (!(indices.length > 0 && indices.length <= MAX_VALIDATORS_PER_COMMITTEE)) {
return false;
Expand All @@ -33,10 +63,5 @@ export function isValidIndexedAttestation(
return false;
}

// verify aggregate signature
if (!verifySignature) {
return true;
}

return verifyIndexedAttestationSignature(state, indexedAttestation, indices);
return true;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {ForkName} from "@chainsafe/lodestar-params";

import {isSlashableValidator, isSlashableAttestationData, getAttesterSlashableIndices} from "../../util";
import {CachedBeaconStateAllForks} from "../../types";
import {isValidIndexedAttestation} from "./isValidIndexedAttestation";
import {slashValidatorAllForks} from "./slashValidator";
import {isValidIndexedAttestationBn} from "./isValidIndexedAttestation";

/**
* Process an AttesterSlashing operation. Initiates the exit of a validator, decreases the balance of the slashed
Expand Down Expand Up @@ -48,10 +48,10 @@ export function assertValidAttesterSlashing(
if (!isSlashableAttestationData(attestation1.data, attestation2.data)) {
throw new Error("AttesterSlashing is not slashable");
}
if (!isValidIndexedAttestation(state, attestation1, verifySignatures)) {
throw new Error("AttesterSlashing attestation1 is not a valid IndexedAttestation");
}
if (!isValidIndexedAttestation(state, attestation2, verifySignatures)) {
throw new Error("AttesterSlashing attestation2 is not a valid IndexedAttestation");

for (const [i, attestation] of [attestation1, attestation2].entries()) {
if (!isValidIndexedAttestationBn(state, attestation, verifySignatures)) {
throw new Error(`AttesterSlashing attestation${i} is invalid`);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ export function assertValidProposerSlashing(
proposerSlashing: phase0.ProposerSlashing,
verifySignatures = true
): void {
const {epochCtx} = state;
const {BeaconBlockHeader} = ssz.phase0;
const header1 = proposerSlashing.signedHeader1.message;
const header2 = proposerSlashing.signedHeader2.message;

Expand All @@ -46,13 +44,13 @@ export function assertValidProposerSlashing(
}

// verify headers are different
if (BeaconBlockHeader.equals(header1, header2)) {
if (ssz.phase0.BeaconBlockHeaderBn.equals(header1, header2)) {
throw new Error("ProposerSlashing headers are equal");
}

// verify the proposer is slashable
const proposer = state.validators.get(header1.proposerIndex);
if (!isSlashableValidator(proposer, epochCtx.currentShuffling.epoch)) {
if (!isSlashableValidator(proposer, state.epochCtx.epoch)) {
throw new Error("ProposerSlashing proposer is not slashable");
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
import {allForks, phase0} from "@chainsafe/lodestar-types";
import {ISignatureSet} from "../../util";
import {allForks, phase0, ssz} from "@chainsafe/lodestar-types";
import {computeSigningRoot, computeStartSlotAtEpoch, ISignatureSet, SignatureSetType} from "../../util";
import {CachedBeaconStateAllForks} from "../../types";
import {getIndexedAttestationSignatureSet} from "./indexedAttestation";
import {DOMAIN_BEACON_ATTESTER} from "@chainsafe/lodestar-params";

/** Get signature sets from all AttesterSlashing objects in a block */
export function getAttesterSlashingsSignatureSets(
state: CachedBeaconStateAllForks,
signedBlock: allForks.SignedBeaconBlock
): ISignatureSet[] {
return signedBlock.message.body.attesterSlashings
.map((attesterSlashing) => getAttesterSlashingSignatureSets(state, attesterSlashing))
.flat(1);
}

/** Get signature sets from a single AttesterSlashing object */
export function getAttesterSlashingSignatureSets(
state: CachedBeaconStateAllForks,
attesterSlashing: phase0.AttesterSlashing
): ISignatureSet[] {
return [attesterSlashing.attestation1, attesterSlashing.attestation2].map((attestation) =>
getIndexedAttestationSignatureSet(state, attestation)
getIndexedAttestationBnSignatureSet(state, attestation)
);
}

/** Get signature sets from all AttesterSlashing objects in a block */
export function getAttesterSlashingsSignatureSets(
export function getIndexedAttestationBnSignatureSet(
state: CachedBeaconStateAllForks,
signedBlock: allForks.SignedBeaconBlock
): ISignatureSet[] {
return signedBlock.message.body.attesterSlashings
.map((attesterSlashing) => getAttesterSlashingSignatureSets(state, attesterSlashing))
.flat(1);
indexedAttestation: phase0.IndexedAttestationBn
): ISignatureSet {
const {index2pubkey} = state.epochCtx;
const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint));
const domain = state.config.getDomain(DOMAIN_BEACON_ATTESTER, slot);

return {
type: SignatureSetType.aggregate,
pubkeys: indexedAttestation.attestingIndices.map((i) => index2pubkey[i]),
signingRoot: computeSigningRoot(ssz.phase0.AttestationDataBn, indexedAttestation.data, domain),
signature: indexedAttestation.signature,
};
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
import {DOMAIN_BEACON_ATTESTER} from "@chainsafe/lodestar-params";
import {allForks, phase0, ssz} from "@chainsafe/lodestar-types";
import {
computeSigningRoot,
computeStartSlotAtEpoch,
ISignatureSet,
SignatureSetType,
verifySignatureSet,
} from "../../util";
import {computeSigningRoot, computeStartSlotAtEpoch, ISignatureSet, SignatureSetType} from "../../util";
import {CachedBeaconStateAllForks} from "../../types";

export function verifyIndexedAttestationSignature(
state: CachedBeaconStateAllForks,
indexedAttestation: phase0.IndexedAttestation,
indices?: number[]
): boolean {
return verifySignatureSet(getIndexedAttestationSignatureSet(state, indexedAttestation, indices));
}

export function getAttestationWithIndicesSignatureSet(
state: CachedBeaconStateAllForks,
attestation: Pick<phase0.Attestation, "data" | "signature">,
Expand All @@ -36,14 +22,9 @@ export function getAttestationWithIndicesSignatureSet(

export function getIndexedAttestationSignatureSet(
state: CachedBeaconStateAllForks,
indexedAttestation: phase0.IndexedAttestation,
indices?: number[]
indexedAttestation: phase0.IndexedAttestation
): ISignatureSet {
return getAttestationWithIndicesSignatureSet(
state,
indexedAttestation,
indices ?? indexedAttestation.attestingIndices
);
return getAttestationWithIndicesSignatureSet(state, indexedAttestation, indexedAttestation.attestingIndices);
}

export function getAttestationsSignatureSets(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ export function getProposerSlashingSignatureSets(

return [proposerSlashing.signedHeader1, proposerSlashing.signedHeader2].map(
(signedHeader): ISignatureSet => {
const domain = state.config.getDomain(DOMAIN_BEACON_PROPOSER, signedHeader.message.slot);
const beaconBlockHeaderType = ssz.phase0.BeaconBlockHeader;
const domain = state.config.getDomain(DOMAIN_BEACON_PROPOSER, Number(signedHeader.message.slot as bigint));

return {
type: SignatureSetType.single,
pubkey,
signingRoot: computeSigningRoot(beaconBlockHeaderType, signedHeader.message, domain),
signingRoot: computeSigningRoot(ssz.phase0.BeaconBlockHeaderBn, signedHeader.message, domain),
signature: signedHeader.signature,
};
}
Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-state-transition/src/util/attestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import {phase0, Slot, ssz, ValidatorIndex} from "@chainsafe/lodestar-types";
/**
* Check if [[data1]] and [[data2]] are slashable according to Casper FFG rules.
*/
export function isSlashableAttestationData(data1: phase0.AttestationData, data2: phase0.AttestationData): boolean {
export function isSlashableAttestationData(data1: phase0.AttestationDataBn, data2: phase0.AttestationDataBn): boolean {
return (
// Double vote
(!ssz.phase0.AttestationData.equals(data1, data2) && data1.target.epoch === data2.target.epoch) ||
(!ssz.phase0.AttestationDataBn.equals(data1, data2) && data1.target.epoch === data2.target.epoch) ||
// Surround vote
(data1.source.epoch < data2.source.epoch && data2.target.epoch < data1.target.epoch)
);
Expand Down
14 changes: 7 additions & 7 deletions packages/beacon-state-transition/test/perf/phase0/block/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ export function getBlockPhase0(
const proposerIndex = proposerSlashingStartIndex + i * exitedIndexStep;
proposerSlashings.push({
signedHeader1: {
message: {slot: 1_800_000, proposerIndex, parentRoot: rootA, stateRoot: rootB, bodyRoot: rootC},
message: {slot: BigInt(1_800_000), proposerIndex, parentRoot: rootA, stateRoot: rootB, bodyRoot: rootC},
signature: emptySig,
},
signedHeader2: {
message: {slot: 1_800_000, proposerIndex, parentRoot: rootC, stateRoot: rootA, bodyRoot: rootB},
message: {slot: BigInt(1_800_000), proposerIndex, parentRoot: rootC, stateRoot: rootA, bodyRoot: rootB},
signature: emptySig,
},
});
Expand All @@ -71,12 +71,12 @@ export function getBlockPhase0(
const startIndex = attesterSlashingStartIndex + i * bitsLen * exitedIndexStep;
const attestingIndices = linspace(startIndex, bitsLen, exitedIndexStep);

const attData: phase0.AttestationData = {
slot: attSlot,
index: 0,
const attData: phase0.AttestationDataBn = {
slot: BigInt(attSlot),
index: BigInt(0),
beaconBlockRoot: rootA,
source: {epoch: stateEpoch - 3, root: rootC},
target: {epoch: attEpoch, root: rootA},
source: {epoch: BigInt(stateEpoch - 3), root: rootC},
target: {epoch: BigInt(attEpoch), root: rootA},
};
attesterSlashings.push({
attestation1: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ interface IBlockProposerData {

function getMockProposerSlashings(data1: IBlockProposerData, data2: IBlockProposerData): phase0.ProposerSlashing {
return {
signedHeader1: getMockSignedBeaconBlockHeader(data1),
signedHeader2: getMockSignedBeaconBlockHeader(data2),
signedHeader1: getMockSignedBeaconBlockHeaderBn(data1),
signedHeader2: getMockSignedBeaconBlockHeaderBn(data2),
};
}

function getMockSignedBeaconBlockHeader(data: IBlockProposerData): phase0.SignedBeaconBlockHeader {
function getMockSignedBeaconBlockHeaderBn(data: IBlockProposerData): phase0.SignedBeaconBlockHeaderBn {
return {
message: {
slot: 0,
slot: BigInt(0),
proposerIndex: data.proposerIndex,
parentRoot: ZERO_HASH,
stateRoot: ZERO_HASH,
Expand All @@ -113,15 +113,15 @@ interface IIndexAttestationData {

function getMockAttesterSlashings(data1: IIndexAttestationData, data2: IIndexAttestationData): phase0.AttesterSlashing {
return {
attestation1: getMockIndexAttestation(data1),
attestation2: getMockIndexAttestation(data2),
attestation1: getMockIndexAttestationBn(data1),
attestation2: getMockIndexAttestationBn(data2),
};
}

function getMockIndexAttestation(data: IIndexAttestationData): phase0.IndexedAttestation {
function getMockIndexAttestationBn(data: IIndexAttestationData): phase0.IndexedAttestationBn {
return {
attestingIndices: data.attestingIndices,
data: getAttestationData(),
data: getAttestationDataBn(),
signature: data.signature,
};
}
Expand All @@ -131,14 +131,18 @@ function getAttestationData(): phase0.AttestationData {
slot: 0,
index: 0,
beaconBlockRoot: ZERO_HASH,
source: {
epoch: 0,
root: ZERO_HASH,
},
target: {
epoch: 0,
root: ZERO_HASH,
},
source: {epoch: 0, root: ZERO_HASH},
target: {epoch: 0, root: ZERO_HASH},
};
}

function getAttestationDataBn(): phase0.AttestationDataBn {
return {
slot: BigInt(0),
index: BigInt(0),
beaconBlockRoot: ZERO_HASH,
source: {epoch: BigInt(0), root: ZERO_HASH},
target: {epoch: BigInt(0), root: ZERO_HASH},
};
}

Expand Down
Loading

0 comments on commit e8f60b6

Please sign in to comment.