From e8f60b6a4cd28d475ef1b5acf0f2608a5865c992 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 5 May 2022 21:33:36 +0200 Subject: [PATCH] Optimize uint (#3977) --- .../block/isValidIndexedAttestation.ts | 43 ++++++++++--- .../allForks/block/processAttesterSlashing.ts | 12 ++-- .../allForks/block/processProposerSlashing.ts | 6 +- .../signatureSets/attesterSlashings.ts | 38 +++++++---- .../signatureSets/indexedAttestation.ts | 25 +------- .../signatureSets/proposerSlashings.ts | 5 +- .../src/util/attestation.ts | 4 +- .../test/perf/phase0/block/util.ts | 14 ++-- .../unit/signatureSets/signatureSets.test.ts | 36 ++++++----- .../test/unit/util/slashing.test.ts | 59 +++++++++-------- .../test/utils/attestation.ts | 32 +++++----- .../lodestar/src/network/gossip/gossipsub.ts | 4 +- .../unit/api/impl/beacon/pool/pool.test.ts | 11 ++-- .../chain/validation/attesterSlashing.test.ts | 4 +- .../chain/validation/proposerSlashing.test.ts | 8 +-- packages/lodestar/test/utils/block.ts | 13 ++++ packages/types/src/phase0/sszTypes.ts | 64 ++++++++++++++++--- packages/types/src/phase0/types.ts | 4 ++ packages/types/src/primitive/sszTypes.ts | 5 +- 19 files changed, 237 insertions(+), 150 deletions(-) diff --git a/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts b/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts index 9a6eeb7d8917..aa8c15b98d9d 100644 --- a/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts +++ b/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts @@ -1,7 +1,8 @@ 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. @@ -9,10 +10,39 @@ import {verifyIndexedAttestationSignature} from "../signatureSets"; 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; @@ -33,10 +63,5 @@ export function isValidIndexedAttestation( return false; } - // verify aggregate signature - if (!verifySignature) { - return true; - } - - return verifyIndexedAttestationSignature(state, indexedAttestation, indices); + return true; } diff --git a/packages/beacon-state-transition/src/allForks/block/processAttesterSlashing.ts b/packages/beacon-state-transition/src/allForks/block/processAttesterSlashing.ts index cf513a60ab47..c55dec67cc5b 100644 --- a/packages/beacon-state-transition/src/allForks/block/processAttesterSlashing.ts +++ b/packages/beacon-state-transition/src/allForks/block/processAttesterSlashing.ts @@ -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 @@ -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`); + } } } diff --git a/packages/beacon-state-transition/src/allForks/block/processProposerSlashing.ts b/packages/beacon-state-transition/src/allForks/block/processProposerSlashing.ts index 4698b1c3780d..24e1b6234865 100644 --- a/packages/beacon-state-transition/src/allForks/block/processProposerSlashing.ts +++ b/packages/beacon-state-transition/src/allForks/block/processProposerSlashing.ts @@ -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; @@ -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"); } diff --git a/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts b/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts index cd6952c683a0..e48b0f803cab 100644 --- a/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts +++ b/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts @@ -1,7 +1,17 @@ -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( @@ -9,16 +19,22 @@ export function getAttesterSlashingSignatureSets( 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, + }; } diff --git a/packages/beacon-state-transition/src/allForks/signatureSets/indexedAttestation.ts b/packages/beacon-state-transition/src/allForks/signatureSets/indexedAttestation.ts index eeaaf4fa5310..5bb2435f4678 100644 --- a/packages/beacon-state-transition/src/allForks/signatureSets/indexedAttestation.ts +++ b/packages/beacon-state-transition/src/allForks/signatureSets/indexedAttestation.ts @@ -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, @@ -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( diff --git a/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts b/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts index 8a939383ac50..bcf1fa9043a7 100644 --- a/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts +++ b/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts @@ -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, }; } diff --git a/packages/beacon-state-transition/src/util/attestation.ts b/packages/beacon-state-transition/src/util/attestation.ts index 44f2fe7e6c40..af0716dbbe6b 100644 --- a/packages/beacon-state-transition/src/util/attestation.ts +++ b/packages/beacon-state-transition/src/util/attestation.ts @@ -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) ); diff --git a/packages/beacon-state-transition/test/perf/phase0/block/util.ts b/packages/beacon-state-transition/test/perf/phase0/block/util.ts index 610ebda6a2c8..e67d26433b7b 100644 --- a/packages/beacon-state-transition/test/perf/phase0/block/util.ts +++ b/packages/beacon-state-transition/test/perf/phase0/block/util.ts @@ -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, }, }); @@ -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: { diff --git a/packages/beacon-state-transition/test/unit/signatureSets/signatureSets.test.ts b/packages/beacon-state-transition/test/unit/signatureSets/signatureSets.test.ts index de4f5e13624f..86b769f6747c 100644 --- a/packages/beacon-state-transition/test/unit/signatureSets/signatureSets.test.ts +++ b/packages/beacon-state-transition/test/unit/signatureSets/signatureSets.test.ts @@ -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, @@ -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, }; } @@ -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}, }; } diff --git a/packages/beacon-state-transition/test/unit/util/slashing.test.ts b/packages/beacon-state-transition/test/unit/util/slashing.test.ts index 19b33e9df2d5..02769cb7c28b 100644 --- a/packages/beacon-state-transition/test/unit/util/slashing.test.ts +++ b/packages/beacon-state-transition/test/unit/util/slashing.test.ts @@ -1,71 +1,70 @@ import {assert} from "chai"; import {SLOTS_PER_EPOCH} from "@chainsafe/lodestar-params"; -import {Epoch, Slot} from "@chainsafe/lodestar-types"; import {isSlashableAttestationData} from "../../../src/util"; import {randBetween} from "../../utils/misc"; -import {generateAttestationData} from "../../utils/attestation"; +import {generateAttestationDataBn} from "../../utils/attestation"; describe("isSlashableAttestationData", () => { it("Attestation data with the same target epoch should return true", () => { - const epoch1: Epoch = randBetween(1, 1000); - const epoch2: Epoch = epoch1 + 1; - const a1 = generateAttestationData(epoch1, epoch2); - const a2 = generateAttestationData(epoch1 - 1, epoch2); + const epoch1 = randBetween(1, 1000); + const epoch2 = epoch1 + 1; + const a1 = generateAttestationDataBn(epoch1, epoch2); + const a2 = generateAttestationDataBn(epoch1 - 1, epoch2); assert.isTrue(isSlashableAttestationData(a1, a2)); }); it("Attestation data with disjoint source/target epochs should return false", () => { - const epoch1: Epoch = randBetween(1, 1000); + const epoch1 = randBetween(1, 1000); const epoch2 = epoch1 + 1; - const epoch3 = epoch2 + 1; - const epoch4 = epoch3 + 1; - const a1 = generateAttestationData(epoch1, epoch2); - const a2 = generateAttestationData(epoch3, epoch4); + const epoch3 = epoch1 + 2; + const epoch4 = epoch1 + 3; + const a1 = generateAttestationDataBn(epoch1, epoch2); + const a2 = generateAttestationDataBn(epoch3, epoch4); assert.isFalse(isSlashableAttestationData(a1, a2)); }); it("Should return false if the second attestation does not have a greater source epoch", () => { // Both attestations have the same source epoch. - const sourceEpoch1: Epoch = randBetween(1, 1000); - let sourceEpoch2: Epoch = sourceEpoch1; + const sourceEpoch1 = randBetween(1, 1000); + const sourceEpoch2Hi = sourceEpoch1; - const targetEpoch1: Epoch = randBetween(1, 1000); - const targetEpoch2: Epoch = targetEpoch1 - 1; + const targetEpoch1 = randBetween(1, 1000); + const targetEpoch2 = targetEpoch1 - 1; - const a1 = generateAttestationData(sourceEpoch1, targetEpoch1); - let a2 = generateAttestationData(sourceEpoch2, targetEpoch2); + const a1 = generateAttestationDataBn(sourceEpoch1, targetEpoch1); + const a2Hi = generateAttestationDataBn(sourceEpoch2Hi, targetEpoch2); - assert.isFalse(isSlashableAttestationData(a1, a2)); + assert.isFalse(isSlashableAttestationData(a1, a2Hi)); // Second attestation has a smaller source epoch. - sourceEpoch2 = sourceEpoch1 - 1; - a2 = generateAttestationData(sourceEpoch2, targetEpoch2); - assert.isFalse(isSlashableAttestationData(a1, a2)); + const sourceEpoch2Lo = sourceEpoch1 - 1; + const a2Lo = generateAttestationDataBn(sourceEpoch2Lo, targetEpoch2); + assert.isFalse(isSlashableAttestationData(a1, a2Lo)); }); it("Should return false if the second attestation does not have a smaller target epoch", () => { // Both attestations have the same target epoch. - const sourceEpoch1: Epoch = randBetween(1, 1000); - const sourceEpoch2: Epoch = sourceEpoch1 + 1; + const sourceEpoch1 = randBetween(1, 1000); + const sourceEpoch2 = sourceEpoch1 + 1; - const targetEpoch: Epoch = randBetween(2, 1000); + const targetEpoch = randBetween(2, 1000); // Last slot in the epoch. - let targetSlot1: Slot = targetEpoch * SLOTS_PER_EPOCH - 1; + let targetSlot1 = targetEpoch * SLOTS_PER_EPOCH - 1; // First slot in the epoch - let targetSlot2: Slot = (targetEpoch - 1) * SLOTS_PER_EPOCH; + let targetSlot2 = (targetEpoch - 1) * SLOTS_PER_EPOCH; - let a1 = generateAttestationData(targetSlot1, sourceEpoch1); - let a2 = generateAttestationData(targetSlot2, sourceEpoch2); + let a1 = generateAttestationDataBn(targetSlot1, sourceEpoch1); + let a2 = generateAttestationDataBn(targetSlot2, sourceEpoch2); assert.isFalse(isSlashableAttestationData(a1, a2)); // Second attestation has a greater target epoch. targetSlot1 = targetEpoch * SLOTS_PER_EPOCH; targetSlot2 = (targetEpoch + 1) * SLOTS_PER_EPOCH; - a1 = generateAttestationData(targetSlot1, sourceEpoch1); - a2 = generateAttestationData(targetSlot2, sourceEpoch2); + a1 = generateAttestationDataBn(targetSlot1, sourceEpoch1); + a2 = generateAttestationDataBn(targetSlot2, sourceEpoch2); assert.isFalse(isSlashableAttestationData(a1, a2)); }); }); diff --git a/packages/beacon-state-transition/test/utils/attestation.ts b/packages/beacon-state-transition/test/utils/attestation.ts index b3dc827e0012..e4e2d75687f7 100644 --- a/packages/beacon-state-transition/test/utils/attestation.ts +++ b/packages/beacon-state-transition/test/utils/attestation.ts @@ -10,17 +10,21 @@ import {BitArray} from "@chainsafe/ssz"; export function generateAttestationData(sourceEpoch: Epoch, targetEpoch: Epoch): phase0.AttestationData { return { - slot: 0, + slot: 1, index: 0, beaconBlockRoot: Buffer.alloc(32), - source: { - epoch: sourceEpoch, - root: Buffer.alloc(32), - }, - target: { - epoch: targetEpoch, - root: Buffer.alloc(32), - }, + source: {epoch: sourceEpoch, root: Buffer.alloc(32)}, + target: {epoch: targetEpoch, root: Buffer.alloc(32)}, + }; +} + +export function generateAttestationDataBn(sourceEpoch: Epoch, targetEpoch: Epoch): phase0.AttestationDataBn { + return { + slot: BigInt(0), + index: BigInt(0), + beaconBlockRoot: Buffer.alloc(32), + source: {epoch: BigInt(sourceEpoch), root: Buffer.alloc(32)}, + target: {epoch: BigInt(targetEpoch), root: Buffer.alloc(32)}, }; } @@ -31,14 +35,8 @@ export function generateEmptyAttestation(): phase0.Attestation { slot: 1, index: 0, beaconBlockRoot: Buffer.alloc(32), - source: { - epoch: 0, - root: Buffer.alloc(32), - }, - target: { - epoch: 0, - root: Buffer.alloc(32), - }, + source: {epoch: 0, root: Buffer.alloc(32)}, + target: {epoch: 0, root: Buffer.alloc(32)}, }, signature: Buffer.alloc(96), }; diff --git a/packages/lodestar/src/network/gossip/gossipsub.ts b/packages/lodestar/src/network/gossip/gossipsub.ts index b26f743f3511..0305314038ad 100644 --- a/packages/lodestar/src/network/gossip/gossipsub.ts +++ b/packages/lodestar/src/network/gossip/gossipsub.ts @@ -205,7 +205,7 @@ export class Eth2Gossipsub extends Gossipsub { } async publishProposerSlashing(proposerSlashing: phase0.ProposerSlashing): Promise { - const fork = this.config.getForkName(proposerSlashing.signedHeader1.message.slot); + const fork = this.config.getForkName(Number(proposerSlashing.signedHeader1.message.slot as bigint)); await this.publishObject( {type: GossipType.proposer_slashing, fork}, proposerSlashing @@ -213,7 +213,7 @@ export class Eth2Gossipsub extends Gossipsub { } async publishAttesterSlashing(attesterSlashing: phase0.AttesterSlashing): Promise { - const fork = this.config.getForkName(attesterSlashing.attestation1.data.slot); + const fork = this.config.getForkName(Number(attesterSlashing.attestation1.data.slot as bigint)); await this.publishObject( {type: GossipType.attester_slashing, fork}, attesterSlashing diff --git a/packages/lodestar/test/unit/api/impl/beacon/pool/pool.test.ts b/packages/lodestar/test/unit/api/impl/beacon/pool/pool.test.ts index 252ebd5df42b..9e95d21d5b01 100644 --- a/packages/lodestar/test/unit/api/impl/beacon/pool/pool.test.ts +++ b/packages/lodestar/test/unit/api/impl/beacon/pool/pool.test.ts @@ -1,5 +1,6 @@ import {expect} from "chai"; import sinon from "sinon"; +import {generateAttestationDataBn} from "@chainsafe/lodestar-beacon-state-transition/test/utils/attestation"; import {getBeaconPoolApi} from "../../../../../../src/api/impl/beacon/pool"; import {Network} from "../../../../../../src/network/network"; import { @@ -15,7 +16,7 @@ import * as voluntaryExitValidation from "../../../../../../src/chain/validation import {phase0} from "@chainsafe/lodestar-types"; import {Eth2Gossipsub} from "../../../../../../src/network/gossip"; -import {generateEmptySignedBlockHeader} from "../../../../../utils/block"; +import {generateSignedBlockHeaderBn} from "../../../../../utils/block"; import {setupApiImplTestServer} from "../../index.test"; import {SinonStubFn} from "../../../../../utils/types"; import {testLogger} from "../../../../../utils/logger"; @@ -87,12 +88,12 @@ describe("beacon pool api impl", function () { const atterterSlashing: phase0.AttesterSlashing = { attestation1: { attestingIndices: [0], - data: generateAttestationData(0, 1, 0, 1), + data: generateAttestationDataBn(0, 1), signature: Buffer.alloc(96), }, attestation2: { attestingIndices: [0], - data: generateAttestationData(0, 1, 0, 1), + data: generateAttestationDataBn(0, 1), signature: Buffer.alloc(96), }, }; @@ -112,8 +113,8 @@ describe("beacon pool api impl", function () { describe("submitPoolProposerSlashing", function () { const proposerSlashing: phase0.ProposerSlashing = { - signedHeader1: generateEmptySignedBlockHeader(), - signedHeader2: generateEmptySignedBlockHeader(), + signedHeader1: generateSignedBlockHeaderBn(), + signedHeader2: generateSignedBlockHeaderBn(), }; it("should broadcast", async function () { diff --git a/packages/lodestar/test/unit/chain/validation/attesterSlashing.test.ts b/packages/lodestar/test/unit/chain/validation/attesterSlashing.test.ts index 33a0db461350..0e5f66922357 100644 --- a/packages/lodestar/test/unit/chain/validation/attesterSlashing.test.ts +++ b/packages/lodestar/test/unit/chain/validation/attesterSlashing.test.ts @@ -53,7 +53,7 @@ describe("GossipMessageValidator", () => { }); it("should return valid attester slashing", async () => { - const attestationData = ssz.phase0.AttestationData.defaultValue(); + const attestationData = ssz.phase0.AttestationDataBn.defaultValue(); const attesterSlashing: phase0.AttesterSlashing = { attestation1: { data: attestationData, @@ -61,7 +61,7 @@ describe("GossipMessageValidator", () => { attestingIndices: [0], }, attestation2: { - data: {...attestationData, slot: 1}, // Make it different so it's slashable + data: {...attestationData, slot: BigInt(1)}, // Make it different so it's slashable signature: Buffer.alloc(96, 0), attestingIndices: [0], }, diff --git a/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts b/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts index 50521a55d2f1..59ed90fb5011 100644 --- a/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts +++ b/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts @@ -45,8 +45,8 @@ describe("validate proposer slashing", () => { it("should return invalid proposer slashing - invalid", async () => { const proposerSlashing = ssz.phase0.ProposerSlashing.defaultValue(); // Make it invalid - proposerSlashing.signedHeader1.message.slot = 1; - proposerSlashing.signedHeader2.message.slot = 0; + proposerSlashing.signedHeader1.message.slot = BigInt(1); + proposerSlashing.signedHeader2.message.slot = BigInt(0); await expectRejectedWithLodestarError( validateGossipProposerSlashing(chainStub, proposerSlashing), @@ -55,8 +55,8 @@ describe("validate proposer slashing", () => { }); it("should return valid proposer slashing", async () => { - const signedHeader1 = ssz.phase0.SignedBeaconBlockHeader.defaultValue(); - const signedHeader2 = ssz.phase0.SignedBeaconBlockHeader.defaultValue(); + const signedHeader1 = ssz.phase0.SignedBeaconBlockHeaderBn.defaultValue(); + const signedHeader2 = ssz.phase0.SignedBeaconBlockHeaderBn.defaultValue(); // Make it different, so slashable signedHeader2.message.stateRoot = Buffer.alloc(32, 1); diff --git a/packages/lodestar/test/utils/block.ts b/packages/lodestar/test/utils/block.ts index 638d3241cf4a..3dd58a263489 100644 --- a/packages/lodestar/test/utils/block.ts +++ b/packages/lodestar/test/utils/block.ts @@ -75,6 +75,19 @@ export function generateEmptySignedBlockHeader(): phase0.SignedBeaconBlockHeader }; } +export function generateSignedBlockHeaderBn(): phase0.SignedBeaconBlockHeaderBn { + return { + message: { + slot: BigInt(0), + proposerIndex: 0, + parentRoot: Buffer.alloc(32), + stateRoot: Buffer.alloc(32), + bodyRoot: Buffer.alloc(32), + }, + signature: EMPTY_SIGNATURE, + }; +} + export function generateSignedBlock( override: RecursivePartial = {} ): phase0.SignedBeaconBlock { diff --git a/packages/types/src/phase0/sszTypes.ts b/packages/types/src/phase0/sszTypes.ts index 467c07156a31..bda287d7d674 100644 --- a/packages/types/src/phase0/sszTypes.ts +++ b/packages/types/src/phase0/sszTypes.ts @@ -36,6 +36,7 @@ const { UintBn64, Slot, Epoch, + EpochInf, CommitteeIndex, ValidatorIndex, Gwei, @@ -63,6 +64,17 @@ export const BeaconBlockHeader = new ContainerType( {typeName: "BeaconBlockHeader", jsonCase: "eth2", cachePermanentRootStruct: true} ); +export const BeaconBlockHeaderBn = new ContainerType( + { + slot: UintBn64, + proposerIndex: ValidatorIndex, + parentRoot: Root, + stateRoot: Root, + bodyRoot: Root, + }, + {typeName: "BeaconBlockHeader", jsonCase: "eth2", cachePermanentRootStruct: true} +); + export const SignedBeaconBlockHeader = new ContainerType( { message: BeaconBlockHeader, @@ -71,6 +83,14 @@ export const SignedBeaconBlockHeader = new ContainerType( {typeName: "SignedBeaconBlockHeader", jsonCase: "eth2"} ); +export const SignedBeaconBlockHeaderBn = new ContainerType( + { + message: BeaconBlockHeaderBn, + signature: BLSSignature, + }, + {typeName: "SignedBeaconBlockHeader", jsonCase: "eth2"} +); + export const Checkpoint = new ContainerType( { epoch: Epoch, @@ -79,6 +99,14 @@ export const Checkpoint = new ContainerType( {typeName: "Checkpoint", jsonCase: "eth2"} ); +export const CheckpointBn = new ContainerType( + { + epoch: UintBn64, + root: Root, + }, + {typeName: "Checkpoint", jsonCase: "eth2"} +); + export const CommitteeBits = new BitListType(MAX_VALIDATORS_PER_COMMITTEE); export const CommitteeIndices = new ListBasicType(ValidatorIndex, MAX_VALIDATORS_PER_COMMITTEE); @@ -199,10 +227,10 @@ export const ValidatorContainer = new ContainerType( withdrawalCredentials: Bytes32, effectiveBalance: UintNum64, slashed: Boolean, - activationEligibilityEpoch: Epoch, - activationEpoch: Epoch, - exitEpoch: Epoch, - withdrawableEpoch: Epoch, + activationEligibilityEpoch: EpochInf, + activationEpoch: EpochInf, + exitEpoch: EpochInf, + withdrawableEpoch: EpochInf, }, {typeName: "Validator", jsonCase: "eth2"} ); @@ -231,6 +259,17 @@ export const AttestationData = new ContainerType( {typeName: "AttestationData", jsonCase: "eth2", cachePermanentRootStruct: true} ); +export const AttestationDataBn = new ContainerType( + { + slot: UintBn64, + index: UintBn64, + beaconBlockRoot: Root, + source: CheckpointBn, + target: CheckpointBn, + }, + {typeName: "AttestationData", jsonCase: "eth2", cachePermanentRootStruct: true} +); + export const IndexedAttestation = new ContainerType( { attestingIndices: CommitteeIndices, @@ -240,6 +279,15 @@ export const IndexedAttestation = new ContainerType( {typeName: "IndexedAttestation", jsonCase: "eth2"} ); +export const IndexedAttestationBn = new ContainerType( + { + attestingIndices: CommitteeIndices, + data: AttestationDataBn, + signature: BLSSignature, + }, + {typeName: "IndexedAttestation", jsonCase: "eth2"} +); + export const PendingAttestation = new ContainerType( { aggregationBits: CommitteeBits, @@ -272,8 +320,8 @@ export const Attestation = new ContainerType( export const AttesterSlashing = new ContainerType( { - attestation1: IndexedAttestation, - attestation2: IndexedAttestation, + attestation1: IndexedAttestationBn, + attestation2: IndexedAttestationBn, }, {typeName: "AttesterSlashing", jsonCase: "eth2"} ); @@ -288,8 +336,8 @@ export const Deposit = new ContainerType( export const ProposerSlashing = new ContainerType( { - signedHeader1: SignedBeaconBlockHeader, - signedHeader2: SignedBeaconBlockHeader, + signedHeader1: SignedBeaconBlockHeaderBn, + signedHeader2: SignedBeaconBlockHeaderBn, }, {typeName: "ProposerSlashing", jsonCase: "eth2"} ); diff --git a/packages/types/src/phase0/types.ts b/packages/types/src/phase0/types.ts index 622996920679..738fc3a6ec22 100644 --- a/packages/types/src/phase0/types.ts +++ b/packages/types/src/phase0/types.ts @@ -3,7 +3,9 @@ import * as ssz from "./sszTypes"; export type AttestationSubnets = ValueOf; export type BeaconBlockHeader = ValueOf; +export type BeaconBlockHeaderBn = ValueOf; export type SignedBeaconBlockHeader = ValueOf; +export type SignedBeaconBlockHeaderBn = ValueOf; export type Checkpoint = ValueOf; export type DepositMessage = ValueOf; export type DepositData = ValueOf; @@ -17,7 +19,9 @@ export type ENRForkID = ValueOf; export type HistoricalBatch = ValueOf; export type Validator = ValueOf; export type AttestationData = ValueOf; +export type AttestationDataBn = ValueOf; export type IndexedAttestation = ValueOf; +export type IndexedAttestationBn = ValueOf; export type PendingAttestation = ValueOf; export type SigningData = ValueOf; export type Attestation = ValueOf; diff --git a/packages/types/src/primitive/sszTypes.ts b/packages/types/src/primitive/sszTypes.ts index 95e73c478496..268941554352 100644 --- a/packages/types/src/primitive/sszTypes.ts +++ b/packages/types/src/primitive/sszTypes.ts @@ -18,8 +18,9 @@ export const UintBn128 = new UintBigintType(16); export const UintBn256 = new UintBigintType(32); // Custom types, defined for type hinting and readability -export const Slot = UintNumInf64; -export const Epoch = UintNumInf64; +export const Slot = UintNum64; +export const Epoch = UintNum64; +export const EpochInf = UintNumInf64; export const SyncPeriod = UintNum64; export const CommitteeIndex = UintNum64; export const SubcommitteeIndex = UintNum64;