From 7a676c12d98b1825740d3928c5cad2c55f988fb5 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Thu, 12 May 2022 23:04:51 +0700 Subject: [PATCH] Clarify #3977 with unbounded uint issue --- .../block/isValidIndexedAttestation.ts | 8 ++-- .../allForks/block/processAttesterSlashing.ts | 7 +++- .../allForks/block/processProposerSlashing.ts | 2 +- .../signatureSets/attesterSlashings.ts | 8 ++-- .../signatureSets/proposerSlashings.ts | 4 +- .../src/util/attestation.ts | 7 +++- .../test/perf/phase0/block/util.ts | 2 +- .../unit/signatureSets/signatureSets.test.ts | 12 +++--- .../test/unit/util/slashing.test.ts | 24 ++++++------ .../test/utils/attestation.ts | 2 +- .../unit/api/impl/beacon/pool/pool.test.ts | 6 +-- .../chain/validation/attesterSlashing.test.ts | 2 +- .../chain/validation/proposerSlashing.test.ts | 4 +- packages/lodestar/test/utils/block.ts | 2 +- packages/types/src/phase0/sszTypes.ts | 38 ++++++++++++------- packages/types/src/phase0/types.ts | 8 ++-- packages/types/src/primitive/sszTypes.ts | 23 +++++++++++ 17 files changed, 101 insertions(+), 58 deletions(-) diff --git a/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts b/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts index aa8c15b98d9d..a7193ad27a2d 100644 --- a/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts +++ b/packages/beacon-state-transition/src/allForks/block/isValidIndexedAttestation.ts @@ -2,7 +2,7 @@ import {MAX_VALIDATORS_PER_COMMITTEE} from "@chainsafe/lodestar-params"; import {phase0} from "@chainsafe/lodestar-types"; import {CachedBeaconStateAllForks} from "../../types"; import {verifySignatureSet} from "../../util"; -import {getIndexedAttestationBnSignatureSet, getIndexedAttestationSignatureSet} from "../signatureSets"; +import {getIndexedAttestationBigintSignatureSet, getIndexedAttestationSignatureSet} from "../signatureSets"; /** * Check if `indexedAttestation` has sorted and unique indices and a valid aggregate signature. @@ -23,9 +23,9 @@ export function isValidIndexedAttestation( } } -export function isValidIndexedAttestationBn( +export function isValidIndexedAttestationBigint( state: CachedBeaconStateAllForks, - indexedAttestation: phase0.IndexedAttestationBn, + indexedAttestation: phase0.IndexedAttestationBigint, verifySignature: boolean ): boolean { if (!isValidIndexedAttestationIndices(state, indexedAttestation.attestingIndices)) { @@ -33,7 +33,7 @@ export function isValidIndexedAttestationBn( } if (verifySignature) { - return verifySignatureSet(getIndexedAttestationBnSignatureSet(state, indexedAttestation)); + return verifySignatureSet(getIndexedAttestationBigintSignatureSet(state, indexedAttestation)); } else { 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 c55dec67cc5b..703ecdcbbfc5 100644 --- a/packages/beacon-state-transition/src/allForks/block/processAttesterSlashing.ts +++ b/packages/beacon-state-transition/src/allForks/block/processAttesterSlashing.ts @@ -4,7 +4,7 @@ import {ForkName} from "@chainsafe/lodestar-params"; import {isSlashableValidator, isSlashableAttestationData, getAttesterSlashableIndices} from "../../util"; import {CachedBeaconStateAllForks} from "../../types"; import {slashValidatorAllForks} from "./slashValidator"; -import {isValidIndexedAttestationBn} from "./isValidIndexedAttestation"; +import {isValidIndexedAttestationBigint} from "./isValidIndexedAttestation"; /** * Process an AttesterSlashing operation. Initiates the exit of a validator, decreases the balance of the slashed @@ -49,8 +49,11 @@ export function assertValidAttesterSlashing( throw new Error("AttesterSlashing is not slashable"); } + // In state transition, AttesterSlashing attestations are only partially validated. Their slot and epoch could + // be higher than the clock and the slashing would still be valid. Same applies to attestation data index, which + // can be any arbitrary value. Must use bigint variants to hash correctly to all possible values for (const [i, attestation] of [attestation1, attestation2].entries()) { - if (!isValidIndexedAttestationBn(state, attestation, verifySignatures)) { + if (!isValidIndexedAttestationBigint(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 24e1b6234865..f19da7425d09 100644 --- a/packages/beacon-state-transition/src/allForks/block/processProposerSlashing.ts +++ b/packages/beacon-state-transition/src/allForks/block/processProposerSlashing.ts @@ -44,7 +44,7 @@ export function assertValidProposerSlashing( } // verify headers are different - if (ssz.phase0.BeaconBlockHeaderBn.equals(header1, header2)) { + if (ssz.phase0.BeaconBlockHeaderBigint.equals(header1, header2)) { throw new Error("ProposerSlashing headers are equal"); } diff --git a/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts b/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts index e48b0f803cab..f6b3f478ebf2 100644 --- a/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts +++ b/packages/beacon-state-transition/src/allForks/signatureSets/attesterSlashings.ts @@ -19,13 +19,13 @@ export function getAttesterSlashingSignatureSets( attesterSlashing: phase0.AttesterSlashing ): ISignatureSet[] { return [attesterSlashing.attestation1, attesterSlashing.attestation2].map((attestation) => - getIndexedAttestationBnSignatureSet(state, attestation) + getIndexedAttestationBigintSignatureSet(state, attestation) ); } -export function getIndexedAttestationBnSignatureSet( +export function getIndexedAttestationBigintSignatureSet( state: CachedBeaconStateAllForks, - indexedAttestation: phase0.IndexedAttestationBn + indexedAttestation: phase0.IndexedAttestationBigint ): ISignatureSet { const {index2pubkey} = state.epochCtx; const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); @@ -34,7 +34,7 @@ export function getIndexedAttestationBnSignatureSet( return { type: SignatureSetType.aggregate, pubkeys: indexedAttestation.attestingIndices.map((i) => index2pubkey[i]), - signingRoot: computeSigningRoot(ssz.phase0.AttestationDataBn, indexedAttestation.data, domain), + signingRoot: computeSigningRoot(ssz.phase0.AttestationDataBigint, indexedAttestation.data, domain), signature: indexedAttestation.signature, }; } diff --git a/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts b/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts index bcf1fa9043a7..3aabb3520494 100644 --- a/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts +++ b/packages/beacon-state-transition/src/allForks/signatureSets/proposerSlashings.ts @@ -13,6 +13,8 @@ export function getProposerSlashingSignatureSets( const {epochCtx} = state; const pubkey = epochCtx.index2pubkey[proposerSlashing.signedHeader1.message.proposerIndex]; + // In state transition, ProposerSlashing headers are only partially validated. Their slot could be higher than the + // clock and the slashing would still be valid. Must use bigint variants to hash correctly to all possible values return [proposerSlashing.signedHeader1, proposerSlashing.signedHeader2].map( (signedHeader): ISignatureSet => { const domain = state.config.getDomain(DOMAIN_BEACON_PROPOSER, Number(signedHeader.message.slot as bigint)); @@ -20,7 +22,7 @@ export function getProposerSlashingSignatureSets( return { type: SignatureSetType.single, pubkey, - signingRoot: computeSigningRoot(ssz.phase0.BeaconBlockHeaderBn, signedHeader.message, domain), + signingRoot: computeSigningRoot(ssz.phase0.BeaconBlockHeaderBigint, 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 af0716dbbe6b..e25dd629a9de 100644 --- a/packages/beacon-state-transition/src/util/attestation.ts +++ b/packages/beacon-state-transition/src/util/attestation.ts @@ -8,10 +8,13 @@ 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.AttestationDataBn, data2: phase0.AttestationDataBn): boolean { +export function isSlashableAttestationData( + data1: phase0.AttestationDataBigint, + data2: phase0.AttestationDataBigint +): boolean { return ( // Double vote - (!ssz.phase0.AttestationDataBn.equals(data1, data2) && data1.target.epoch === data2.target.epoch) || + (!ssz.phase0.AttestationDataBigint.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 e67d26433b7b..af385947e5ab 100644 --- a/packages/beacon-state-transition/test/perf/phase0/block/util.ts +++ b/packages/beacon-state-transition/test/perf/phase0/block/util.ts @@ -71,7 +71,7 @@ export function getBlockPhase0( const startIndex = attesterSlashingStartIndex + i * bitsLen * exitedIndexStep; const attestingIndices = linspace(startIndex, bitsLen, exitedIndexStep); - const attData: phase0.AttestationDataBn = { + const attData: phase0.AttestationDataBigint = { slot: BigInt(attSlot), index: BigInt(0), beaconBlockRoot: rootA, 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 86b769f6747c..5d51933ffc00 100644 --- a/packages/beacon-state-transition/test/unit/signatureSets/signatureSets.test.ts +++ b/packages/beacon-state-transition/test/unit/signatureSets/signatureSets.test.ts @@ -88,12 +88,12 @@ interface IBlockProposerData { function getMockProposerSlashings(data1: IBlockProposerData, data2: IBlockProposerData): phase0.ProposerSlashing { return { - signedHeader1: getMockSignedBeaconBlockHeaderBn(data1), - signedHeader2: getMockSignedBeaconBlockHeaderBn(data2), + signedHeader1: getMockSignedBeaconBlockHeaderBigint(data1), + signedHeader2: getMockSignedBeaconBlockHeaderBigint(data2), }; } -function getMockSignedBeaconBlockHeaderBn(data: IBlockProposerData): phase0.SignedBeaconBlockHeaderBn { +function getMockSignedBeaconBlockHeaderBigint(data: IBlockProposerData): phase0.SignedBeaconBlockHeaderBigint { return { message: { slot: BigInt(0), @@ -118,10 +118,10 @@ function getMockAttesterSlashings(data1: IIndexAttestationData, data2: IIndexAtt }; } -function getMockIndexAttestationBn(data: IIndexAttestationData): phase0.IndexedAttestationBn { +function getMockIndexAttestationBn(data: IIndexAttestationData): phase0.IndexedAttestationBigint { return { attestingIndices: data.attestingIndices, - data: getAttestationDataBn(), + data: getAttestationDataBigint(), signature: data.signature, }; } @@ -136,7 +136,7 @@ function getAttestationData(): phase0.AttestationData { }; } -function getAttestationDataBn(): phase0.AttestationDataBn { +function getAttestationDataBigint(): phase0.AttestationDataBigint { return { slot: BigInt(0), index: BigInt(0), 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 02769cb7c28b..fb1a1d9b12a9 100644 --- a/packages/beacon-state-transition/test/unit/util/slashing.test.ts +++ b/packages/beacon-state-transition/test/unit/util/slashing.test.ts @@ -3,14 +3,14 @@ import {assert} from "chai"; import {SLOTS_PER_EPOCH} from "@chainsafe/lodestar-params"; import {isSlashableAttestationData} from "../../../src/util"; import {randBetween} from "../../utils/misc"; -import {generateAttestationDataBn} from "../../utils/attestation"; +import {generateAttestationDataBigint} from "../../utils/attestation"; describe("isSlashableAttestationData", () => { it("Attestation data with the same target epoch should return true", () => { const epoch1 = randBetween(1, 1000); const epoch2 = epoch1 + 1; - const a1 = generateAttestationDataBn(epoch1, epoch2); - const a2 = generateAttestationDataBn(epoch1 - 1, epoch2); + const a1 = generateAttestationDataBigint(epoch1, epoch2); + const a2 = generateAttestationDataBigint(epoch1 - 1, epoch2); assert.isTrue(isSlashableAttestationData(a1, a2)); }); @@ -19,8 +19,8 @@ describe("isSlashableAttestationData", () => { const epoch2 = epoch1 + 1; const epoch3 = epoch1 + 2; const epoch4 = epoch1 + 3; - const a1 = generateAttestationDataBn(epoch1, epoch2); - const a2 = generateAttestationDataBn(epoch3, epoch4); + const a1 = generateAttestationDataBigint(epoch1, epoch2); + const a2 = generateAttestationDataBigint(epoch3, epoch4); assert.isFalse(isSlashableAttestationData(a1, a2)); }); @@ -32,14 +32,14 @@ describe("isSlashableAttestationData", () => { const targetEpoch1 = randBetween(1, 1000); const targetEpoch2 = targetEpoch1 - 1; - const a1 = generateAttestationDataBn(sourceEpoch1, targetEpoch1); - const a2Hi = generateAttestationDataBn(sourceEpoch2Hi, targetEpoch2); + const a1 = generateAttestationDataBigint(sourceEpoch1, targetEpoch1); + const a2Hi = generateAttestationDataBigint(sourceEpoch2Hi, targetEpoch2); assert.isFalse(isSlashableAttestationData(a1, a2Hi)); // Second attestation has a smaller source epoch. const sourceEpoch2Lo = sourceEpoch1 - 1; - const a2Lo = generateAttestationDataBn(sourceEpoch2Lo, targetEpoch2); + const a2Lo = generateAttestationDataBigint(sourceEpoch2Lo, targetEpoch2); assert.isFalse(isSlashableAttestationData(a1, a2Lo)); }); @@ -55,16 +55,16 @@ describe("isSlashableAttestationData", () => { // First slot in the epoch let targetSlot2 = (targetEpoch - 1) * SLOTS_PER_EPOCH; - let a1 = generateAttestationDataBn(targetSlot1, sourceEpoch1); - let a2 = generateAttestationDataBn(targetSlot2, sourceEpoch2); + let a1 = generateAttestationDataBigint(targetSlot1, sourceEpoch1); + let a2 = generateAttestationDataBigint(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 = generateAttestationDataBn(targetSlot1, sourceEpoch1); - a2 = generateAttestationDataBn(targetSlot2, sourceEpoch2); + a1 = generateAttestationDataBigint(targetSlot1, sourceEpoch1); + a2 = generateAttestationDataBigint(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 e4e2d75687f7..21d3ba1433a9 100644 --- a/packages/beacon-state-transition/test/utils/attestation.ts +++ b/packages/beacon-state-transition/test/utils/attestation.ts @@ -18,7 +18,7 @@ export function generateAttestationData(sourceEpoch: Epoch, targetEpoch: Epoch): }; } -export function generateAttestationDataBn(sourceEpoch: Epoch, targetEpoch: Epoch): phase0.AttestationDataBn { +export function generateAttestationDataBigint(sourceEpoch: Epoch, targetEpoch: Epoch): phase0.AttestationDataBigint { return { slot: BigInt(0), index: BigInt(0), 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 9e95d21d5b01..06613303081b 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,6 +1,6 @@ import {expect} from "chai"; import sinon from "sinon"; -import {generateAttestationDataBn} from "@chainsafe/lodestar-beacon-state-transition/test/utils/attestation"; +import {generateAttestationDataBigint} from "@chainsafe/lodestar-beacon-state-transition/test/utils/attestation"; import {getBeaconPoolApi} from "../../../../../../src/api/impl/beacon/pool"; import {Network} from "../../../../../../src/network/network"; import { @@ -88,12 +88,12 @@ describe("beacon pool api impl", function () { const atterterSlashing: phase0.AttesterSlashing = { attestation1: { attestingIndices: [0], - data: generateAttestationDataBn(0, 1), + data: generateAttestationDataBigint(0, 1), signature: Buffer.alloc(96), }, attestation2: { attestingIndices: [0], - data: generateAttestationDataBn(0, 1), + data: generateAttestationDataBigint(0, 1), signature: Buffer.alloc(96), }, }; diff --git a/packages/lodestar/test/unit/chain/validation/attesterSlashing.test.ts b/packages/lodestar/test/unit/chain/validation/attesterSlashing.test.ts index 0e5f66922357..f6eb7154fcbd 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.AttestationDataBn.defaultValue(); + const attestationData = ssz.phase0.AttestationDataBigint.defaultValue(); const attesterSlashing: phase0.AttesterSlashing = { attestation1: { data: attestationData, diff --git a/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts b/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts index 59ed90fb5011..5ca1251e3179 100644 --- a/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts +++ b/packages/lodestar/test/unit/chain/validation/proposerSlashing.test.ts @@ -55,8 +55,8 @@ describe("validate proposer slashing", () => { }); it("should return valid proposer slashing", async () => { - const signedHeader1 = ssz.phase0.SignedBeaconBlockHeaderBn.defaultValue(); - const signedHeader2 = ssz.phase0.SignedBeaconBlockHeaderBn.defaultValue(); + const signedHeader1 = ssz.phase0.SignedBeaconBlockHeaderBigint.defaultValue(); + const signedHeader2 = ssz.phase0.SignedBeaconBlockHeaderBigint.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 3dd58a263489..dfd9655ff7bb 100644 --- a/packages/lodestar/test/utils/block.ts +++ b/packages/lodestar/test/utils/block.ts @@ -75,7 +75,7 @@ export function generateEmptySignedBlockHeader(): phase0.SignedBeaconBlockHeader }; } -export function generateSignedBlockHeaderBn(): phase0.SignedBeaconBlockHeaderBn { +export function generateSignedBlockHeaderBn(): phase0.SignedBeaconBlockHeaderBigint { return { message: { slot: BigInt(0), diff --git a/packages/types/src/phase0/sszTypes.ts b/packages/types/src/phase0/sszTypes.ts index bda287d7d674..6ea60cd05716 100644 --- a/packages/types/src/phase0/sszTypes.ts +++ b/packages/types/src/phase0/sszTypes.ts @@ -53,6 +53,7 @@ const { export const AttestationSubnets = new BitVectorType(ATTESTATION_SUBNET_COUNT); +/** BeaconBlockHeader where slot is bounded by the clock, and values above it are invalid */ export const BeaconBlockHeader = new ContainerType( { slot: Slot, @@ -64,7 +65,8 @@ export const BeaconBlockHeader = new ContainerType( {typeName: "BeaconBlockHeader", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const BeaconBlockHeaderBn = new ContainerType( +/** BeaconBlockHeader where slot is NOT bounded by the clock, i.e. slashings. So slot is a bigint. */ +export const BeaconBlockHeaderBigint = new ContainerType( { slot: UintBn64, proposerIndex: ValidatorIndex, @@ -83,14 +85,16 @@ export const SignedBeaconBlockHeader = new ContainerType( {typeName: "SignedBeaconBlockHeader", jsonCase: "eth2"} ); -export const SignedBeaconBlockHeaderBn = new ContainerType( +/** Same as `SignedBeaconBlockHeader` but slot is not bounded by the clock and must be a bigint */ +export const SignedBeaconBlockHeaderBigint = new ContainerType( { - message: BeaconBlockHeaderBn, + message: BeaconBlockHeaderBigint, signature: BLSSignature, }, {typeName: "SignedBeaconBlockHeader", jsonCase: "eth2"} ); +/** Checkpoint where epoch is bounded by the clock, and values above it are invalid */ export const Checkpoint = new ContainerType( { epoch: Epoch, @@ -99,7 +103,8 @@ export const Checkpoint = new ContainerType( {typeName: "Checkpoint", jsonCase: "eth2"} ); -export const CheckpointBn = new ContainerType( +/** Checkpoint where epoch is NOT bounded by the clock, so must be a bigint */ +export const CheckpointBigint = new ContainerType( { epoch: UintBn64, root: Root, @@ -259,13 +264,14 @@ export const AttestationData = new ContainerType( {typeName: "AttestationData", jsonCase: "eth2", cachePermanentRootStruct: true} ); -export const AttestationDataBn = new ContainerType( +/** Same as `AttestationData` but epoch, slot and index are not bounded and must be a bigint */ +export const AttestationDataBigint = new ContainerType( { slot: UintBn64, index: UintBn64, beaconBlockRoot: Root, - source: CheckpointBn, - target: CheckpointBn, + source: CheckpointBigint, + target: CheckpointBigint, }, {typeName: "AttestationData", jsonCase: "eth2", cachePermanentRootStruct: true} ); @@ -279,10 +285,11 @@ export const IndexedAttestation = new ContainerType( {typeName: "IndexedAttestation", jsonCase: "eth2"} ); -export const IndexedAttestationBn = new ContainerType( +/** Same as `IndexedAttestation` but epoch, slot and index are not bounded and must be a bigint */ +export const IndexedAttestationBigint = new ContainerType( { attestingIndices: CommitteeIndices, - data: AttestationDataBn, + data: AttestationDataBigint, signature: BLSSignature, }, {typeName: "IndexedAttestation", jsonCase: "eth2"} @@ -320,8 +327,11 @@ export const Attestation = new ContainerType( export const AttesterSlashing = new ContainerType( { - attestation1: IndexedAttestationBn, - attestation2: IndexedAttestationBn, + // In state transition, AttesterSlashing attestations are only partially validated. Their slot and epoch could + // be higher than the clock and the slashing would still be valid. Same applies to attestation data index, which + // can be any arbitrary value. Must use bigint variants to hash correctly to all possible values + attestation1: IndexedAttestationBigint, + attestation2: IndexedAttestationBigint, }, {typeName: "AttesterSlashing", jsonCase: "eth2"} ); @@ -336,8 +346,10 @@ export const Deposit = new ContainerType( export const ProposerSlashing = new ContainerType( { - signedHeader1: SignedBeaconBlockHeaderBn, - signedHeader2: SignedBeaconBlockHeaderBn, + // In state transition, ProposerSlashing headers are only partially validated. Their slot could be higher than the + // clock and the slashing would still be valid. Must use bigint variants to hash correctly to all possible values + signedHeader1: SignedBeaconBlockHeaderBigint, + signedHeader2: SignedBeaconBlockHeaderBigint, }, {typeName: "ProposerSlashing", jsonCase: "eth2"} ); diff --git a/packages/types/src/phase0/types.ts b/packages/types/src/phase0/types.ts index 738fc3a6ec22..0dd2c6c28181 100644 --- a/packages/types/src/phase0/types.ts +++ b/packages/types/src/phase0/types.ts @@ -3,9 +3,9 @@ import * as ssz from "./sszTypes"; export type AttestationSubnets = ValueOf; export type BeaconBlockHeader = ValueOf; -export type BeaconBlockHeaderBn = ValueOf; +export type BeaconBlockHeaderBigint = ValueOf; export type SignedBeaconBlockHeader = ValueOf; -export type SignedBeaconBlockHeaderBn = ValueOf; +export type SignedBeaconBlockHeaderBigint = ValueOf; export type Checkpoint = ValueOf; export type DepositMessage = ValueOf; export type DepositData = ValueOf; @@ -19,9 +19,9 @@ export type ENRForkID = ValueOf; export type HistoricalBatch = ValueOf; export type Validator = ValueOf; export type AttestationData = ValueOf; -export type AttestationDataBn = ValueOf; +export type AttestationDataBigint = ValueOf; export type IndexedAttestation = ValueOf; -export type IndexedAttestationBn = ValueOf; +export type IndexedAttestationBigint = 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 268941554352..d3cd812c3bc1 100644 --- a/packages/types/src/primitive/sszTypes.ts +++ b/packages/types/src/primitive/sszTypes.ts @@ -18,12 +18,35 @@ export const UintBn128 = new UintBigintType(16); export const UintBn256 = new UintBigintType(32); // Custom types, defined for type hinting and readability + +/** + * Use JS Number for performance, values must be limited to 2**52-1. + * Slot is a time unit, so in all usages it's bounded by the clock, ensuring < 2**53-1 + */ export const Slot = UintNum64; +/** + * Use JS Number for performance, values must be limited to 2**52-1. + * Epoch is a time unit, so in all usages it's bounded by the clock, ensuring < 2**53-1 + */ export const Epoch = UintNum64; +/** Same as @see Epoch + some validator properties must represent 2**52-1 also, which we map to `Infinity` */ export const EpochInf = UintNumInf64; +/** + * Use JS Number for performance, values must be limited to 2**52-1. + * SyncPeriod is a time unit, so in all usages it's bounded by the clock, ensuring < 2**53-1 + */ export const SyncPeriod = UintNum64; +/** + * Use JS Number for performance, values must be limited to 2**52-1. + * CommitteeIndex is bounded by the max possible number of committees which is bounded by `VALIDATOR_REGISTRY_LIMIT` + */ export const CommitteeIndex = UintNum64; +/** @see CommitteeIndex */ export const SubcommitteeIndex = UintNum64; +/** + * Use JS Number for performance, values must be limited to 2**52-1. + * ValidatorIndex is bounded by `VALIDATOR_REGISTRY_LIMIT` + */ export const ValidatorIndex = UintNum64; export const Gwei = UintBn64; export const Root = new ByteVectorType(32);