diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts index af63e01f844..19783c89577 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksSignatures.ts @@ -28,6 +28,7 @@ export async function verifyBlocksSignatures( ): Promise<{verifySignaturesTime: number}> { const isValidPromises: Promise[] = []; const recvToValLatency = Date.now() / 1000 - (opts.seenTimestampSec ?? Date.now() / 1000); + const currentSyncCommitteeIndexed = preState0.epochCtx.currentSyncCommitteeIndexed; // Verifies signatures after running state transition, so all SyncCommittee signed roots are known at this point. // We must ensure block.slot <= state.slot before running getAllBlockSignatureSets(). @@ -41,9 +42,16 @@ export async function verifyBlocksSignatures( : // // Verify signatures per block to track which block is invalid bls.verifySignatureSets( - getBlockSignatureSets(config, index2pubkey, preState0, block, indexedAttestationsByBlock[i], { - skipProposerSignature: opts.validProposerSignature, - }) + getBlockSignatureSets( + config, + index2pubkey, + currentSyncCommitteeIndexed, + block, + indexedAttestationsByBlock[i], + { + skipProposerSignature: opts.validProposerSignature, + } + ) ); // getBlockSignatureSets() takes 45ms in benchmarks for 2022Q2 mainnet blocks (100 sigs). When syncing a 32 blocks diff --git a/packages/beacon-node/src/chain/validation/attesterSlashing.ts b/packages/beacon-node/src/chain/validation/attesterSlashing.ts index abdca9a4204..99b5ce474a3 100644 --- a/packages/beacon-node/src/chain/validation/attesterSlashing.ts +++ b/packages/beacon-node/src/chain/validation/attesterSlashing.ts @@ -51,7 +51,12 @@ export async function validateAttesterSlashing( }); } - const signatureSets = getAttesterSlashingSignatureSets(chain.config, chain.index2pubkey, state, attesterSlashing); + const signatureSets = getAttesterSlashingSignatureSets( + chain.config, + chain.index2pubkey, + state.slot, + attesterSlashing + ); if (!(await chain.bls.verifySignatureSets(signatureSets, {batchable: true, priority: prioritizeBls}))) { throw new AttesterSlashingError(GossipAction.REJECT, { code: AttesterSlashingErrorCode.INVALID, diff --git a/packages/beacon-node/src/chain/validation/block.ts b/packages/beacon-node/src/chain/validation/block.ts index 905096e79c1..24b23aa43f6 100644 --- a/packages/beacon-node/src/chain/validation/block.ts +++ b/packages/beacon-node/src/chain/validation/block.ts @@ -154,7 +154,7 @@ export async function validateGossipBlock( // [REJECT] The proposer signature, signed_beacon_block.signature, is valid with respect to the proposer_index pubkey. if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockSlot, blockRoot, signedBlock.signature)) { - const signatureSet = getBlockProposerSignatureSet(chain.config, chain.index2pubkey, blockState, signedBlock); + const signatureSet = getBlockProposerSignatureSet(chain.config, chain.index2pubkey, signedBlock); // Don't batch so verification is not delayed if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) { throw new BlockGossipError(GossipAction.REJECT, { diff --git a/packages/beacon-node/src/chain/validation/proposerSlashing.ts b/packages/beacon-node/src/chain/validation/proposerSlashing.ts index 4d36295b752..231c5d5bf18 100644 --- a/packages/beacon-node/src/chain/validation/proposerSlashing.ts +++ b/packages/beacon-node/src/chain/validation/proposerSlashing.ts @@ -44,7 +44,12 @@ async function validateProposerSlashing( }); } - const signatureSets = getProposerSlashingSignatureSets(chain.config, chain.index2pubkey, state, proposerSlashing); + const signatureSets = getProposerSlashingSignatureSets( + chain.config, + chain.index2pubkey, + state.slot, + proposerSlashing + ); if (!(await chain.bls.verifySignatureSets(signatureSets, {batchable: true, priority: prioritizeBls}))) { throw new ProposerSlashingError(GossipAction.REJECT, { code: ProposerSlashingErrorCode.INVALID, diff --git a/packages/beacon-node/src/chain/validation/voluntaryExit.ts b/packages/beacon-node/src/chain/validation/voluntaryExit.ts index b72d9d62605..537738053a3 100644 --- a/packages/beacon-node/src/chain/validation/voluntaryExit.ts +++ b/packages/beacon-node/src/chain/validation/voluntaryExit.ts @@ -59,7 +59,7 @@ async function validateVoluntaryExit( }); } - const signatureSet = getVoluntaryExitSignatureSet(chain.config, chain.index2pubkey, state, voluntaryExit); + const signatureSet = getVoluntaryExitSignatureSet(chain.config, chain.index2pubkey, state.slot, voluntaryExit); if (!(await chain.bls.verifySignatureSets([signatureSet], {batchable: true, priority: prioritizeBls}))) { throw new VoluntaryExitError(GossipAction.REJECT, { code: VoluntaryExitErrorCode.INVALID_SIGNATURE, diff --git a/packages/beacon-node/src/sync/backfill/verify.ts b/packages/beacon-node/src/sync/backfill/verify.ts index 262f6941258..b678bc54def 100644 --- a/packages/beacon-node/src/sync/backfill/verify.ts +++ b/packages/beacon-node/src/sync/backfill/verify.ts @@ -55,8 +55,7 @@ export async function verifyBlockProposerSignature( if (blocks.length === 1 && blocks[0].message.slot === GENESIS_SLOT) return; const signatures = blocks.reduce((sigs: ISignatureSet[], block) => { // genesis block doesn't have valid signature - if (block.message.slot !== GENESIS_SLOT) - sigs.push(getBlockProposerSignatureSet(config, index2pubkey, state, block)); + if (block.message.slot !== GENESIS_SLOT) sigs.push(getBlockProposerSignatureSet(config, index2pubkey, block)); return sigs; }, []); diff --git a/packages/state-transition/src/block/isValidIndexedAttestation.ts b/packages/state-transition/src/block/isValidIndexedAttestation.ts index 26b9db9192d..4cb09b0e46f 100644 --- a/packages/state-transition/src/block/isValidIndexedAttestation.ts +++ b/packages/state-transition/src/block/isValidIndexedAttestation.ts @@ -21,7 +21,7 @@ export function isValidIndexedAttestation( } if (verifySignature) { - return verifySignatureSet(getIndexedAttestationSignatureSet(config, index2pubkey, state, indexedAttestation)); + return verifySignatureSet(getIndexedAttestationSignatureSet(config, index2pubkey, state.slot, indexedAttestation)); } return true; } @@ -38,7 +38,9 @@ export function isValidIndexedAttestationBigint( } if (verifySignature) { - return verifySignatureSet(getIndexedAttestationBigintSignatureSet(config, index2pubkey, state, indexedAttestation)); + return verifySignatureSet( + getIndexedAttestationBigintSignatureSet(config, index2pubkey, state.slot, indexedAttestation) + ); } return true; } diff --git a/packages/state-transition/src/block/processAttestationsAltair.ts b/packages/state-transition/src/block/processAttestationsAltair.ts index 9218d221142..3cf366bb833 100644 --- a/packages/state-transition/src/block/processAttestationsAltair.ts +++ b/packages/state-transition/src/block/processAttestationsAltair.ts @@ -67,7 +67,7 @@ export function processAttestationsAltair( const sigSet = getAttestationWithIndicesSignatureSet( state.config, epochCtx.index2pubkey, - state, + state.slot, attestation, attestingIndices ); diff --git a/packages/state-transition/src/block/processProposerSlashing.ts b/packages/state-transition/src/block/processProposerSlashing.ts index b51fcb08b53..aec8047c753 100644 --- a/packages/state-transition/src/block/processProposerSlashing.ts +++ b/packages/state-transition/src/block/processProposerSlashing.ts @@ -80,7 +80,7 @@ export function assertValidProposerSlashing( const signatureSets = getProposerSlashingSignatureSets( state.config, state.epochCtx.index2pubkey, - state, + state.slot, proposerSlashing ); for (let i = 0; i < signatureSets.length; i++) { diff --git a/packages/state-transition/src/block/processRandao.ts b/packages/state-transition/src/block/processRandao.ts index 1f0ef252354..b43d12bdaac 100644 --- a/packages/state-transition/src/block/processRandao.ts +++ b/packages/state-transition/src/block/processRandao.ts @@ -12,12 +12,12 @@ import {getRandaoMix} from "../util/index.js"; * PERF: Fixed work independent of block contents. */ export function processRandao(state: CachedBeaconStateAllForks, block: BeaconBlock, verifySignature = true): void { - const {epochCtx} = state; + const {epochCtx, config} = state; const epoch = epochCtx.epoch; const randaoReveal = block.body.randaoReveal; // verify RANDAO reveal - if (verifySignature && !verifyRandaoSignature(state.config, epochCtx.index2pubkey, state, block)) { + if (verifySignature && !verifyRandaoSignature(config, epochCtx.index2pubkey, block)) { throw new Error("RANDAO reveal is an invalid signature"); } diff --git a/packages/state-transition/src/block/processSyncCommittee.ts b/packages/state-transition/src/block/processSyncCommittee.ts index b2dbe165a00..ec7cae676b9 100644 --- a/packages/state-transition/src/block/processSyncCommittee.ts +++ b/packages/state-transition/src/block/processSyncCommittee.ts @@ -3,6 +3,7 @@ import {BeaconConfig} from "@lodestar/config"; import {DOMAIN_SYNC_COMMITTEE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; import {altair, ssz} from "@lodestar/types"; import {Index2PubkeyCache} from "../cache/pubkeyCache.js"; +import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js"; import {G2_POINT_AT_INFINITY} from "../constants/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; import { @@ -28,7 +29,7 @@ export function processSyncAggregate( const signatureSet = getSyncCommitteeSignatureSet( state.config, state.epochCtx.index2pubkey, - state, + state.epochCtx.currentSyncCommitteeIndexed, block, participantIndices ); @@ -73,7 +74,7 @@ export function processSyncAggregate( export function getSyncCommitteeSignatureSet( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + currentSyncCommitteeIndexed: SyncCommitteeCache, block: altair.BeaconBlock, /** Optional parameter to prevent computing it twice */ participantIndices?: number[] @@ -101,7 +102,7 @@ export function getSyncCommitteeSignatureSet( const rootSigned = block.parentRoot; if (!participantIndices) { - const committeeIndices = state.epochCtx.currentSyncCommitteeIndexed.validatorIndices; + const committeeIndices = currentSyncCommitteeIndexed.validatorIndices; participantIndices = syncAggregate.syncCommitteeBits.intersectValues(committeeIndices); } @@ -115,7 +116,9 @@ export function getSyncCommitteeSignatureSet( throw Error("Empty sync committee signature is not infinity"); } - const domain = config.getDomain(state.slot, DOMAIN_SYNC_COMMITTEE, previousSlot); + // the getDomain() api requires the state slot as 1st param, however it's the same to block.slot in state-transition + // and the same epoch when we verify blocks in batch in beacon-node. So we can safely use block.slot here. + const domain = config.getDomain(block.slot, DOMAIN_SYNC_COMMITTEE, previousSlot); return { type: SignatureSetType.aggregate, diff --git a/packages/state-transition/src/block/processVoluntaryExit.ts b/packages/state-transition/src/block/processVoluntaryExit.ts index c3d1ce860be..2a5f103c29b 100644 --- a/packages/state-transition/src/block/processVoluntaryExit.ts +++ b/packages/state-transition/src/block/processVoluntaryExit.ts @@ -76,7 +76,7 @@ export function getVoluntaryExitValidity( if ( verifySignature && - !verifyVoluntaryExitSignature(state.config, epochCtx.index2pubkey, state, signedVoluntaryExit) + !verifyVoluntaryExitSignature(state.config, epochCtx.index2pubkey, state.slot, signedVoluntaryExit) ) { return VoluntaryExitValidity.invalidSignature; } diff --git a/packages/state-transition/src/signatureSets/attesterSlashings.ts b/packages/state-transition/src/signatureSets/attesterSlashings.ts index 335b5717ade..57256fda5f0 100644 --- a/packages/state-transition/src/signatureSets/attesterSlashings.ts +++ b/packages/state-transition/src/signatureSets/attesterSlashings.ts @@ -1,19 +1,20 @@ import {BeaconConfig} from "@lodestar/config"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; -import {AttesterSlashing, IndexedAttestationBigint, SignedBeaconBlock, ssz} from "@lodestar/types"; +import {AttesterSlashing, IndexedAttestationBigint, SignedBeaconBlock, Slot, ssz} from "@lodestar/types"; import {Index2PubkeyCache} from "../cache/pubkeyCache.js"; -import {CachedBeaconStateAllForks} from "../types.js"; import {ISignatureSet, SignatureSetType, computeSigningRoot, computeStartSlotAtEpoch} from "../util/index.js"; /** Get signature sets from all AttesterSlashing objects in a block */ export function getAttesterSlashingsSignatureSets( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock ): ISignatureSet[] { + // the getDomain() api requires the state slot as 1st param, however it's the same to block.slot in state-transition + // and the same epoch when we verify blocks in batch in beacon-node. So we can safely use block.slot here. + const blockSlot = signedBlock.message.slot; return signedBlock.message.body.attesterSlashings.flatMap((attesterSlashing) => - getAttesterSlashingSignatureSets(config, index2pubkey, state, attesterSlashing) + getAttesterSlashingSignatureSets(config, index2pubkey, blockSlot, attesterSlashing) ); } @@ -21,22 +22,22 @@ export function getAttesterSlashingsSignatureSets( export function getAttesterSlashingSignatureSets( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + stateSlot: Slot, attesterSlashing: AttesterSlashing ): ISignatureSet[] { return [attesterSlashing.attestation1, attesterSlashing.attestation2].map((attestation) => - getIndexedAttestationBigintSignatureSet(config, index2pubkey, state, attestation) + getIndexedAttestationBigintSignatureSet(config, index2pubkey, stateSlot, attestation) ); } export function getIndexedAttestationBigintSignatureSet( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + stateSlot: Slot, indexedAttestation: IndexedAttestationBigint ): ISignatureSet { - const slot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); - const domain = config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); + const messageSlot = computeStartSlotAtEpoch(Number(indexedAttestation.data.target.epoch as bigint)); + const domain = config.getDomain(stateSlot, DOMAIN_BEACON_ATTESTER, messageSlot); return { type: SignatureSetType.aggregate, diff --git a/packages/state-transition/src/signatureSets/index.ts b/packages/state-transition/src/signatureSets/index.ts index 3d3ad0254d4..7397074d074 100644 --- a/packages/state-transition/src/signatureSets/index.ts +++ b/packages/state-transition/src/signatureSets/index.ts @@ -3,7 +3,7 @@ import {ForkSeq} from "@lodestar/params"; import {IndexedAttestation, SignedBeaconBlock, altair, capella} from "@lodestar/types"; import {getSyncCommitteeSignatureSet} from "../block/processSyncCommittee.js"; import {Index2PubkeyCache} from "../cache/pubkeyCache.js"; -import {CachedBeaconStateAllForks, CachedBeaconStateAltair} from "../types.js"; +import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js"; import {ISignatureSet} from "../util/index.js"; import {getAttesterSlashingsSignatureSets} from "./attesterSlashings.js"; import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js"; @@ -29,7 +29,7 @@ export * from "./voluntaryExits.js"; export function getBlockSignatureSets( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + currentSyncCommitteeIndexed: SyncCommitteeCache, signedBlock: SignedBeaconBlock, indexedAttestations: IndexedAttestation[], opts?: { @@ -38,18 +38,18 @@ export function getBlockSignatureSets( } ): ISignatureSet[] { // fork based validations - const fork = state.config.getForkSeq(signedBlock.message.slot); + const fork = config.getForkSeq(signedBlock.message.slot); const signatureSets = [ - getRandaoRevealSignatureSet(config, index2pubkey, state, signedBlock.message), - ...getProposerSlashingsSignatureSets(config, index2pubkey, state, signedBlock), - ...getAttesterSlashingsSignatureSets(config, index2pubkey, state, signedBlock), - ...getAttestationsSignatureSets(config, index2pubkey, state, signedBlock, indexedAttestations), - ...getVoluntaryExitsSignatureSets(config, index2pubkey, state, signedBlock), + getRandaoRevealSignatureSet(config, index2pubkey, signedBlock.message), + ...getProposerSlashingsSignatureSets(config, index2pubkey, signedBlock), + ...getAttesterSlashingsSignatureSets(config, index2pubkey, signedBlock), + ...getAttestationsSignatureSets(config, index2pubkey, signedBlock, indexedAttestations), + ...getVoluntaryExitsSignatureSets(config, index2pubkey, signedBlock), ]; if (!opts?.skipProposerSignature) { - signatureSets.push(getBlockProposerSignatureSet(config, index2pubkey, state, signedBlock)); + signatureSets.push(getBlockProposerSignatureSet(config, index2pubkey, signedBlock)); } // Only after altair fork, validate tSyncCommitteeSignature @@ -57,7 +57,7 @@ export function getBlockSignatureSets( const syncCommitteeSignatureSet = getSyncCommitteeSignatureSet( config, index2pubkey, - state as CachedBeaconStateAltair, + currentSyncCommitteeIndexed, (signedBlock as altair.SignedBeaconBlock).message ); // There may be no participants in this syncCommitteeSignature, so it must not be validated @@ -69,7 +69,7 @@ export function getBlockSignatureSets( // only after capella fork if (fork >= ForkSeq.capella) { const blsToExecutionChangeSignatureSets = getBlsToExecutionChangeSignatureSets( - state.config, + config, signedBlock as capella.SignedBeaconBlock ); if (blsToExecutionChangeSignatureSets.length > 0) { diff --git a/packages/state-transition/src/signatureSets/indexedAttestation.ts b/packages/state-transition/src/signatureSets/indexedAttestation.ts index f3a9724736d..bb8d00e6b7d 100644 --- a/packages/state-transition/src/signatureSets/indexedAttestation.ts +++ b/packages/state-transition/src/signatureSets/indexedAttestation.ts @@ -1,8 +1,7 @@ import {BeaconConfig} from "@lodestar/config"; import {DOMAIN_BEACON_ATTESTER} from "@lodestar/params"; -import {IndexedAttestation, SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {IndexedAttestation, SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types"; import {Index2PubkeyCache} from "../cache/pubkeyCache.js"; -import {CachedBeaconStateAllForks} from "../types.js"; import { ISignatureSet, computeSigningRoot, @@ -12,11 +11,11 @@ import { export function getAttestationDataSigningRoot( config: BeaconConfig, - state: CachedBeaconStateAllForks, + stateSlot: Slot, data: phase0.AttestationData ): Uint8Array { - const slot = computeStartSlotAtEpoch(data.target.epoch); - const domain = config.getDomain(state.slot, DOMAIN_BEACON_ATTESTER, slot); + const messageSlot = computeStartSlotAtEpoch(data.target.epoch); + const domain = config.getDomain(stateSlot, DOMAIN_BEACON_ATTESTER, messageSlot); return computeSigningRoot(ssz.phase0.AttestationData, data, domain); } @@ -24,13 +23,13 @@ export function getAttestationDataSigningRoot( export function getAttestationWithIndicesSignatureSet( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + stateSlot: Slot, attestation: Pick, attestingIndices: number[] ): ISignatureSet { return createAggregateSignatureSetFromComponents( attestingIndices.map((i) => index2pubkey[i]), - getAttestationDataSigningRoot(config, state, attestation.data), + getAttestationDataSigningRoot(config, stateSlot, attestation.data), attestation.signature ); } @@ -38,13 +37,13 @@ export function getAttestationWithIndicesSignatureSet( export function getIndexedAttestationSignatureSet( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + stateSlot: Slot, indexedAttestation: IndexedAttestation ): ISignatureSet { return getAttestationWithIndicesSignatureSet( config, index2pubkey, - state, + stateSlot, indexedAttestation, indexedAttestation.attestingIndices ); @@ -53,7 +52,6 @@ export function getIndexedAttestationSignatureSet( export function getAttestationsSignatureSets( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock, indexedAttestations: IndexedAttestation[] ): ISignatureSet[] { @@ -62,7 +60,10 @@ export function getAttestationsSignatureSets( `Indexed attestations length mismatch: got ${indexedAttestations.length}, expected ${signedBlock.message.body.attestations.length}` ); } + // the getDomain() api requires the state slot as 1st param, however it's the same to block.slot in state-transition + // and the same epoch when we verify blocks in batch in beacon-node. So we can safely use block.slot here. + const blockSlot = signedBlock.message.slot; return indexedAttestations.map((indexedAttestation) => - getIndexedAttestationSignatureSet(config, index2pubkey, state, indexedAttestation) + getIndexedAttestationSignatureSet(config, index2pubkey, blockSlot, indexedAttestation) ); } diff --git a/packages/state-transition/src/signatureSets/proposer.ts b/packages/state-transition/src/signatureSets/proposer.ts index 3ffd346d31f..cf692fcac9a 100644 --- a/packages/state-transition/src/signatureSets/proposer.ts +++ b/packages/state-transition/src/signatureSets/proposer.ts @@ -9,20 +9,21 @@ import {ISignatureSet, SignatureSetType, verifySignatureSet} from "../util/signa export function verifyProposerSignature( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock ): boolean { - const signatureSet = getBlockProposerSignatureSet(config, index2pubkey, state, signedBlock); + const signatureSet = getBlockProposerSignatureSet(config, index2pubkey, signedBlock); return verifySignatureSet(signatureSet); } export function getBlockProposerSignatureSet( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock | SignedBlindedBeaconBlock ): ISignatureSet { - const domain = config.getDomain(state.slot, DOMAIN_BEACON_PROPOSER, signedBlock.message.slot); + // the getDomain() api requires the state slot as 1st param, however it's the same to block.slot in state-transition + // and the same epoch when we verify blocks in batch in beacon-node. So we can safely use block.slot here. + const blockSlot = signedBlock.message.slot; + const domain = config.getDomain(blockSlot, DOMAIN_BEACON_PROPOSER, blockSlot); const blockType = isBlindedBeaconBlock(signedBlock.message) ? config.getPostBellatrixForkTypes(signedBlock.message.slot).BlindedBeaconBlock diff --git a/packages/state-transition/src/signatureSets/proposerSlashings.ts b/packages/state-transition/src/signatureSets/proposerSlashings.ts index 218eef8d2d7..058d87cf490 100644 --- a/packages/state-transition/src/signatureSets/proposerSlashings.ts +++ b/packages/state-transition/src/signatureSets/proposerSlashings.ts @@ -1,8 +1,7 @@ import {BeaconConfig} from "@lodestar/config"; import {DOMAIN_BEACON_PROPOSER} from "@lodestar/params"; -import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types"; import {Index2PubkeyCache} from "../cache/pubkeyCache.js"; -import {CachedBeaconStateAllForks} from "../types.js"; import {ISignatureSet, SignatureSetType, computeSigningRoot} from "../util/index.js"; /** @@ -11,7 +10,7 @@ import {ISignatureSet, SignatureSetType, computeSigningRoot} from "../util/index export function getProposerSlashingSignatureSets( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + stateSlot: Slot, proposerSlashing: phase0.ProposerSlashing ): ISignatureSet[] { const pubkey = index2pubkey[proposerSlashing.signedHeader1.message.proposerIndex]; @@ -19,7 +18,7 @@ export function getProposerSlashingSignatureSets( // 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 = config.getDomain(state.slot, DOMAIN_BEACON_PROPOSER, Number(signedHeader.message.slot as bigint)); + const domain = config.getDomain(stateSlot, DOMAIN_BEACON_PROPOSER, Number(signedHeader.message.slot as bigint)); return { type: SignatureSetType.single, @@ -33,10 +32,12 @@ export function getProposerSlashingSignatureSets( export function getProposerSlashingsSignatureSets( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock ): ISignatureSet[] { + // the getDomain() api requires the state slot as 1st param, however it's the same to block.slot in state-transition + // and the same epoch when we verify blocks in batch in beacon-node. So we can safely use block.slot here. + const blockSlot = signedBlock.message.slot; return signedBlock.message.body.proposerSlashings.flatMap((proposerSlashing) => - getProposerSlashingSignatureSets(config, index2pubkey, state, proposerSlashing) + getProposerSlashingSignatureSets(config, index2pubkey, blockSlot, proposerSlashing) ); } diff --git a/packages/state-transition/src/signatureSets/randao.ts b/packages/state-transition/src/signatureSets/randao.ts index 3b6dc463763..6cb99cee301 100644 --- a/packages/state-transition/src/signatureSets/randao.ts +++ b/packages/state-transition/src/signatureSets/randao.ts @@ -2,7 +2,6 @@ import {BeaconConfig} from "@lodestar/config"; import {DOMAIN_RANDAO} from "@lodestar/params"; import {BeaconBlock, ssz} from "@lodestar/types"; import {Index2PubkeyCache} from "../cache/pubkeyCache.js"; -import {CachedBeaconStateAllForks} from "../types.js"; import { ISignatureSet, SignatureSetType, @@ -14,10 +13,9 @@ import { export function verifyRandaoSignature( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, block: BeaconBlock ): boolean { - return verifySignatureSet(getRandaoRevealSignatureSet(config, index2pubkey, state, block)); + return verifySignatureSet(getRandaoRevealSignatureSet(config, index2pubkey, block)); } /** @@ -26,12 +24,13 @@ export function verifyRandaoSignature( export function getRandaoRevealSignatureSet( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, block: BeaconBlock ): ISignatureSet { // should not get epoch from epochCtx const epoch = computeEpochAtSlot(block.slot); - const domain = config.getDomain(state.slot, DOMAIN_RANDAO, block.slot); + // the getDomain() api requires the state slot as 1st param, however it's the same to block.slot in state-transition + // and the same epoch when we verify blocks in batch in beacon-node. So we can safely use block.slot here. + const domain = config.getDomain(block.slot, DOMAIN_RANDAO, block.slot); return { type: SignatureSetType.single, diff --git a/packages/state-transition/src/signatureSets/voluntaryExits.ts b/packages/state-transition/src/signatureSets/voluntaryExits.ts index b7d6e82b012..7c2086aa586 100644 --- a/packages/state-transition/src/signatureSets/voluntaryExits.ts +++ b/packages/state-transition/src/signatureSets/voluntaryExits.ts @@ -1,7 +1,6 @@ import {BeaconConfig} from "@lodestar/config"; -import {SignedBeaconBlock, phase0, ssz} from "@lodestar/types"; +import {SignedBeaconBlock, Slot, phase0, ssz} from "@lodestar/types"; import {Index2PubkeyCache} from "../cache/pubkeyCache.js"; -import {CachedBeaconStateAllForks} from "../types.js"; import { ISignatureSet, SignatureSetType, @@ -13,10 +12,10 @@ import { export function verifyVoluntaryExitSignature( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + stateSlot: Slot, signedVoluntaryExit: phase0.SignedVoluntaryExit ): boolean { - return verifySignatureSet(getVoluntaryExitSignatureSet(config, index2pubkey, state, signedVoluntaryExit)); + return verifySignatureSet(getVoluntaryExitSignatureSet(config, index2pubkey, stateSlot, signedVoluntaryExit)); } /** @@ -25,11 +24,11 @@ export function verifyVoluntaryExitSignature( export function getVoluntaryExitSignatureSet( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, + stateSlot: Slot, signedVoluntaryExit: phase0.SignedVoluntaryExit ): ISignatureSet { - const slot = computeStartSlotAtEpoch(signedVoluntaryExit.message.epoch); - const domain = config.getDomainForVoluntaryExit(state.slot, slot); + const messageSlot = computeStartSlotAtEpoch(signedVoluntaryExit.message.epoch); + const domain = config.getDomainForVoluntaryExit(stateSlot, messageSlot); return { type: SignatureSetType.single, @@ -42,10 +41,12 @@ export function getVoluntaryExitSignatureSet( export function getVoluntaryExitsSignatureSets( config: BeaconConfig, index2pubkey: Index2PubkeyCache, - state: CachedBeaconStateAllForks, signedBlock: SignedBeaconBlock ): ISignatureSet[] { + // the getDomain() api requires the state slot as 1st param, however it's the same to block.slot in state-transition + // and the same epoch when we verify blocks in batch in beacon-node. So we can safely use block.slot here. + const blockSlot = signedBlock.message.slot; return signedBlock.message.body.voluntaryExits.map((voluntaryExit) => - getVoluntaryExitSignatureSet(config, index2pubkey, state, voluntaryExit) + getVoluntaryExitSignatureSet(config, index2pubkey, blockSlot, voluntaryExit) ); } diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index 3f2bc6147d5..9e1f006cf83 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -111,10 +111,7 @@ export function stateTransition( postState = processSlotsWithTransientCache(postState, blockSlot, options, {metrics, validatorMonitor}); // Verify proposer signature only - if ( - verifyProposer && - !verifyProposerSignature(postState.config, postState.epochCtx.index2pubkey, postState, signedBlock) - ) { + if (verifyProposer && !verifyProposerSignature(postState.config, postState.epochCtx.index2pubkey, signedBlock)) { throw new Error("Invalid block signature"); } diff --git a/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts b/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts index 6fb825bb41d..eead18b1e81 100644 --- a/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts +++ b/packages/state-transition/test/unit/signatureSets/signatureSets.test.ts @@ -73,7 +73,7 @@ describe("signatureSets", () => { const signatureSets = getBlockSignatureSets( state.config, state.epochCtx.index2pubkey, - state, + state.epochCtx.currentSyncCommitteeIndexed, signedBlock, indexedAttestations );