From 19b82eaa1d9ebc0ddc4454ef1c496654e661348d Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Fri, 24 Jan 2025 19:06:53 -0800 Subject: [PATCH 01/10] initial commit --- .../src/api/impl/beacon/pool/index.ts | 7 +-- .../beacon-node/src/chain/opPools/opPool.ts | 15 ++++-- .../src/chain/validation/attesterSlashing.ts | 8 +-- packages/beacon-node/src/db/buckets.ts | 2 +- .../src/db/repositories/attesterSlashing.ts | 49 +++++++++++++++++-- .../src/network/gossip/interface.ts | 5 +- packages/beacon-node/src/network/interface.ts | 3 +- packages/beacon-node/src/network/network.ts | 3 +- .../src/network/processor/gossipHandlers.ts | 3 +- .../test/spec/presets/operations.test.ts | 4 +- .../fork-choice/src/forkChoice/forkChoice.ts | 15 +++++- .../fork-choice/src/forkChoice/interface.ts | 14 +++++- .../src/block/isValidIndexedAttestation.ts | 4 +- .../src/block/processAttesterSlashing.ts | 6 +-- .../state-transition/src/util/attestation.ts | 4 +- 15 files changed, 107 insertions(+), 35 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index d0c35b1c0cd8..39556171670d 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -163,13 +163,14 @@ export function getBeaconPoolApi({ async submitPoolAttesterSlashings({attesterSlashing}) { await validateApiAttesterSlashing(chain, attesterSlashing); - chain.opPool.insertAttesterSlashing(attesterSlashing); + chain.opPool.insertAttesterSlashing(ForkName.phase0, attesterSlashing); await network.publishAttesterSlashing(attesterSlashing); }, async submitPoolAttesterSlashingsV2({attesterSlashing}) { - // TODO Electra: Refactor submitPoolAttesterSlashings and submitPoolAttesterSlashingsV2 - await this.submitPoolAttesterSlashings({attesterSlashing}); + await validateApiAttesterSlashing(chain, attesterSlashing); + chain.opPool.insertAttesterSlashing(ForkName.electra, attesterSlashing); + await network.publishAttesterSlashing(attesterSlashing); }, async submitPoolProposerSlashings({proposerSlashing}) { diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index 819873d2e835..4017aa72d142 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -1,12 +1,14 @@ import {Id, Repository} from "@lodestar/db"; import { BLS_WITHDRAWAL_PREFIX, + ForkName, ForkSeq, MAX_ATTESTER_SLASHINGS, MAX_ATTESTER_SLASHINGS_ELECTRA, MAX_BLS_TO_EXECUTION_CHANGES, MAX_PROPOSER_SLASHINGS, MAX_VOLUNTARY_EXITS, + isForkPostElectra, } from "@lodestar/params"; import { CachedBeaconStateAllForks, @@ -26,7 +28,7 @@ import {isValidBlsToExecutionChangeForBlockInclusion} from "./utils.js"; type HexRoot = string; type AttesterSlashingCached = { - attesterSlashing: phase0.AttesterSlashing; + attesterSlashing: AttesterSlashing; intersectingIndices: number[]; }; @@ -132,8 +134,12 @@ export class OpPool { } /** Must be validated beforehand */ - insertAttesterSlashing(attesterSlashing: phase0.AttesterSlashing, rootHash?: Uint8Array): void { - if (!rootHash) rootHash = ssz.phase0.AttesterSlashing.hashTreeRoot(attesterSlashing); + insertAttesterSlashing(fork: ForkName, attesterSlashing: AttesterSlashing, rootHash?: Uint8Array): void { + if (!rootHash) { + const type = isForkPostElectra(fork) ? ssz.electra.AttesterSlashing : ssz.phase0.AttesterSlashing; + rootHash = type.hashTreeRoot(attesterSlashing); + } + // TODO: Do once and cache attached to the AttesterSlashing object const intersectingIndices = getAttesterSlashableIndices(attesterSlashing); this.attesterSlashings.set(toRootHex(rootHash), { @@ -284,8 +290,7 @@ export class OpPool { } /** For beacon pool API */ - // TODO Electra: Update to adapt electra.AttesterSlashing - getAllAttesterSlashings(): phase0.AttesterSlashing[] { + getAllAttesterSlashings(): AttesterSlashing[] { return Array.from(this.attesterSlashings.values()).map((attesterSlashings) => attesterSlashings.attesterSlashing); } diff --git a/packages/beacon-node/src/chain/validation/attesterSlashing.ts b/packages/beacon-node/src/chain/validation/attesterSlashing.ts index c097774ecb02..2aaca763b0c5 100644 --- a/packages/beacon-node/src/chain/validation/attesterSlashing.ts +++ b/packages/beacon-node/src/chain/validation/attesterSlashing.ts @@ -3,13 +3,13 @@ import { getAttesterSlashableIndices, getAttesterSlashingSignatureSets, } from "@lodestar/state-transition"; -import {phase0} from "@lodestar/types"; +import {AttesterSlashing} from "@lodestar/types"; import {AttesterSlashingError, AttesterSlashingErrorCode, GossipAction} from "../errors/index.js"; import {IBeaconChain} from "../index.js"; export async function validateApiAttesterSlashing( chain: IBeaconChain, - attesterSlashing: phase0.AttesterSlashing // TODO Electra: Handle electra.AttesterSlashing + attesterSlashing: AttesterSlashing ): Promise { const prioritizeBls = true; return validateAttesterSlashing(chain, attesterSlashing, prioritizeBls); @@ -17,14 +17,14 @@ export async function validateApiAttesterSlashing( export async function validateGossipAttesterSlashing( chain: IBeaconChain, - attesterSlashing: phase0.AttesterSlashing + attesterSlashing: AttesterSlashing ): Promise { return validateAttesterSlashing(chain, attesterSlashing); } export async function validateAttesterSlashing( chain: IBeaconChain, - attesterSlashing: phase0.AttesterSlashing, + attesterSlashing: AttesterSlashing, prioritizeBls = false ): Promise { // [IGNORE] At least one index in the intersection of the attesting indices of each attestation has not yet been seen diff --git a/packages/beacon-node/src/db/buckets.ts b/packages/beacon-node/src/db/buckets.ts index c35a5a18edf5..7b729b201f5c 100644 --- a/packages/beacon-node/src/db/buckets.ts +++ b/packages/beacon-node/src/db/buckets.ts @@ -26,7 +26,7 @@ export enum Bucket { phase0_depositData = 12, // [DEPRECATED] index -> DepositData phase0_exit = 13, // ValidatorIndex -> VoluntaryExit phase0_proposerSlashing = 14, // ValidatorIndex -> ProposerSlashing - phase0_attesterSlashing = 15, // Root -> AttesterSlashing + allForks_attesterSlashing = 15, // Root -> AttesterSlashing capella_blsToExecutionChange = 16, // ValidatorIndex -> SignedBLSToExecutionChange // checkpoint states allForks_checkpointState = 17, // Root -> BeaconState diff --git a/packages/beacon-node/src/db/repositories/attesterSlashing.ts b/packages/beacon-node/src/db/repositories/attesterSlashing.ts index dd83c25998b6..43e5c1ba24a5 100644 --- a/packages/beacon-node/src/db/repositories/attesterSlashing.ts +++ b/packages/beacon-node/src/db/repositories/attesterSlashing.ts @@ -1,18 +1,26 @@ import {ChainForkConfig} from "@lodestar/config"; import {Db, Repository} from "@lodestar/db"; -import {ValidatorIndex, phase0, ssz} from "@lodestar/types"; +import {ForkName, isForkPostElectra} from "@lodestar/params"; +import {AttesterSlashing, ValidatorIndex, phase0, ssz, sszTypesFor} from "@lodestar/types"; import {Bucket, getBucketNameByValue} from "../buckets.js"; +// We add a 1-byte prefix where 0 means pre-electra and 1 means post-electra +enum PrefixByte { + PRE_ELECTRA = 0, + POST_ELECTRA = 1, +} + /** * AttesterSlashing indexed by root * * Added via gossip or api * Removed when included on chain or old */ -export class AttesterSlashingRepository extends Repository { +export class AttesterSlashingRepository extends Repository { constructor(config: ChainForkConfig, db: Db) { - const bucket = Bucket.phase0_attesterSlashing; - super(config, db, bucket, ssz.phase0.AttesterSlashing, getBucketNameByValue(bucket)); + const bucket = Bucket.allForks_attesterSlashing; + const type = ssz.phase0.AttesterSlashing; // Pick some type. Will be overriden + super(config, db, bucket, type, getBucketNameByValue(bucket)); } async hasAll(attesterIndices: ValidatorIndex[] = []): Promise { @@ -29,4 +37,37 @@ export class AttesterSlashingRepository extends Repository Promise | void; [GossipType.voluntary_exit]: (voluntaryExit: phase0.SignedVoluntaryExit) => Promise | void; [GossipType.proposer_slashing]: (proposerSlashing: phase0.ProposerSlashing) => Promise | void; - [GossipType.attester_slashing]: (attesterSlashing: phase0.AttesterSlashing) => Promise | void; + [GossipType.attester_slashing]: (attesterSlashing: AttesterSlashing) => Promise | void; [GossipType.sync_committee_contribution_and_proof]: ( signedContributionAndProof: altair.SignedContributionAndProof ) => Promise | void; diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index aab3c06991d3..22801cbda42d 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -15,6 +15,7 @@ import { } from "@libp2p/interface"; import type {AddressManager, ConnectionManager, Registrar, TransportManager} from "@libp2p/interface-internal"; import { + AttesterSlashing, LightClientFinalityUpdate, LightClientOptimisticUpdate, SignedAggregateAndProof, @@ -79,7 +80,7 @@ export interface INetwork extends INetworkCorePublic { publishVoluntaryExit(voluntaryExit: phase0.SignedVoluntaryExit): Promise; publishBlsToExecutionChange(blsToExecutionChange: capella.SignedBLSToExecutionChange): Promise; publishProposerSlashing(proposerSlashing: phase0.ProposerSlashing): Promise; - publishAttesterSlashing(attesterSlashing: phase0.AttesterSlashing): Promise; + publishAttesterSlashing(attesterSlashing: AttesterSlashing): Promise; publishSyncCommitteeSignature(signature: altair.SyncCommitteeMessage, subnet: SubnetID): Promise; publishContributionAndProof(contributionAndProof: altair.SignedContributionAndProof): Promise; publishLightClientFinalityUpdate(update: LightClientFinalityUpdate): Promise; diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 505da6718c33..b27a0cd23b6b 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -8,6 +8,7 @@ import {ForkSeq} from "@lodestar/params"; import {ResponseIncoming} from "@lodestar/reqresp"; import {computeStartSlotAtEpoch, computeTimeAtSlot} from "@lodestar/state-transition"; import { + AttesterSlashing, LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate, @@ -373,7 +374,7 @@ export class Network implements INetwork { ); } - async publishAttesterSlashing(attesterSlashing: phase0.AttesterSlashing): Promise { + async publishAttesterSlashing(attesterSlashing: AttesterSlashing): Promise { const fork = this.config.getForkName(Number(attesterSlashing.attestation1.data.slot as bigint)); return this.publishGossip( {type: GossipType.attester_slashing, fork}, diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index ec61aa277d03..53a1183aaf53 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -470,13 +470,14 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand topic, }: GossipHandlerParamGeneric) => { const {serializedData} = gossipData; + const {fork} = topic; const attesterSlashing = sszDeserialize(topic, serializedData); await validateGossipAttesterSlashing(chain, attesterSlashing); // Handler try { - chain.opPool.insertAttesterSlashing(attesterSlashing); + chain.opPool.insertAttesterSlashing(fork, attesterSlashing); chain.forkChoice.onAttesterSlashing(attesterSlashing); } catch (e) { logger.error("Error adding attesterSlashing to pool", {}, e as Error); diff --git a/packages/beacon-node/test/spec/presets/operations.test.ts b/packages/beacon-node/test/spec/presets/operations.test.ts index 0a9996c0a2b1..6c7a2278b748 100644 --- a/packages/beacon-node/test/spec/presets/operations.test.ts +++ b/packages/beacon-node/test/spec/presets/operations.test.ts @@ -11,7 +11,7 @@ import { getBlockRootAtSlot, } from "@lodestar/state-transition"; import * as blockFns from "@lodestar/state-transition/block"; -import {altair, bellatrix, capella, electra, phase0, ssz, sszTypesFor} from "@lodestar/types"; +import {AttesterSlashing, altair, bellatrix, capella, electra, phase0, ssz, sszTypesFor} from "@lodestar/types"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; import {getConfig} from "../../utils/config.js"; @@ -41,7 +41,7 @@ const operationFns: Record> = blockFns.processAttestations(fork, state, [testCase.attestation]); }, - attester_slashing: (state, testCase: BaseSpecTest & {attester_slashing: phase0.AttesterSlashing}) => { + attester_slashing: (state, testCase: BaseSpecTest & {attester_slashing: AttesterSlashing}) => { const fork = state.config.getForkSeq(state.slot); blockFns.processAttesterSlashing(fork, state, testCase.attester_slashing, shouldVerify(testCase)); }, diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 2b803c3553a4..66347590e1c2 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -13,7 +13,18 @@ import { isExecutionStateType, } from "@lodestar/state-transition"; import {computeUnrealizedCheckpoints} from "@lodestar/state-transition/epoch"; -import {BeaconBlock, Epoch, Root, RootHex, Slot, ValidatorIndex, bellatrix, phase0, ssz} from "@lodestar/types"; +import { + AttesterSlashing, + BeaconBlock, + Epoch, + Root, + RootHex, + Slot, + ValidatorIndex, + bellatrix, + phase0, + ssz, +} from "@lodestar/types"; import {Logger, MapDef, fromHex, toRootHex} from "@lodestar/utils"; import {computeDeltas} from "../protoArray/computeDeltas.js"; @@ -738,7 +749,7 @@ export class ForkChoice implements IForkChoice { * We already call is_slashable_attestation_data() and is_valid_indexed_attestation * in state transition so no need to do it again */ - onAttesterSlashing(attesterSlashing: phase0.AttesterSlashing): void { + onAttesterSlashing(attesterSlashing: AttesterSlashing): void { // TODO: we already call in in state-transition, find a way not to recompute it again const intersectingIndices = getAttesterSlashableIndices(attesterSlashing); for (const validatorIndex of intersectingIndices) { diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index 05c803b50dc8..f3f5c0c83145 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -1,6 +1,16 @@ import {EffectiveBalanceIncrements} from "@lodestar/state-transition"; import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; -import {BeaconBlock, Epoch, IndexedAttestation, Root, RootHex, Slot, ValidatorIndex, phase0} from "@lodestar/types"; +import { + AttesterSlashing, + BeaconBlock, + Epoch, + IndexedAttestation, + Root, + RootHex, + Slot, + ValidatorIndex, + phase0, +} from "@lodestar/types"; import { DataAvailabilityStatus, LVHExecResponse, @@ -164,7 +174,7 @@ export interface IForkChoice { * * https://github.com/ethereum/consensus-specs/blob/v1.2.0-rc.3/specs/phase0/fork-choice.md#on_attester_slashing */ - onAttesterSlashing(slashing: phase0.AttesterSlashing): void; + onAttesterSlashing(slashing: AttesterSlashing): void; getLatestMessage(validatorIndex: ValidatorIndex): LatestMessage | undefined; /** * Call `onTick` for all slots between `fcStore.getCurrentSlot()` and the provided `currentSlot`. diff --git a/packages/state-transition/src/block/isValidIndexedAttestation.ts b/packages/state-transition/src/block/isValidIndexedAttestation.ts index fdb005484733..290da795cc04 100644 --- a/packages/state-transition/src/block/isValidIndexedAttestation.ts +++ b/packages/state-transition/src/block/isValidIndexedAttestation.ts @@ -1,5 +1,5 @@ import {ForkSeq, MAX_COMMITTEES_PER_SLOT, MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; -import {phase0} from "@lodestar/types"; +import {IndexedAttestationBigint, phase0} from "@lodestar/types"; import {getIndexedAttestationBigintSignatureSet, getIndexedAttestationSignatureSet} from "../signatureSets/index.js"; import {CachedBeaconStateAllForks} from "../types.js"; import {verifySignatureSet} from "../util/index.js"; @@ -24,7 +24,7 @@ export function isValidIndexedAttestation( export function isValidIndexedAttestationBigint( state: CachedBeaconStateAllForks, - indexedAttestation: phase0.IndexedAttestationBigint, + indexedAttestation: IndexedAttestationBigint, verifySignature: boolean ): boolean { if (!isValidIndexedAttestationIndices(state, indexedAttestation.attestingIndices)) { diff --git a/packages/state-transition/src/block/processAttesterSlashing.ts b/packages/state-transition/src/block/processAttesterSlashing.ts index 5470082a7c2b..f04c6c958580 100644 --- a/packages/state-transition/src/block/processAttesterSlashing.ts +++ b/packages/state-transition/src/block/processAttesterSlashing.ts @@ -1,5 +1,5 @@ import {ForkSeq} from "@lodestar/params"; -import {phase0} from "@lodestar/types"; +import {AttesterSlashing} from "@lodestar/types"; import {CachedBeaconStateAllForks} from "../types.js"; import {getAttesterSlashableIndices, isSlashableAttestationData, isSlashableValidator} from "../util/index.js"; @@ -15,7 +15,7 @@ import {slashValidator} from "./slashValidator.js"; export function processAttesterSlashing( fork: ForkSeq, state: CachedBeaconStateAllForks, - attesterSlashing: phase0.AttesterSlashing, + attesterSlashing: AttesterSlashing, verifySignatures = true ): void { assertValidAttesterSlashing(state, attesterSlashing, verifySignatures); @@ -39,7 +39,7 @@ export function processAttesterSlashing( export function assertValidAttesterSlashing( state: CachedBeaconStateAllForks, - attesterSlashing: phase0.AttesterSlashing, + attesterSlashing: AttesterSlashing, verifySignatures = true ): void { const attestation1 = attesterSlashing.attestation1; diff --git a/packages/state-transition/src/util/attestation.ts b/packages/state-transition/src/util/attestation.ts index f45011b1e838..a55646ad5366 100644 --- a/packages/state-transition/src/util/attestation.ts +++ b/packages/state-transition/src/util/attestation.ts @@ -1,5 +1,5 @@ import {MIN_ATTESTATION_INCLUSION_DELAY, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {Slot, ValidatorIndex, phase0, ssz} from "@lodestar/types"; +import {AttesterSlashing, Slot, ValidatorIndex, phase0, ssz} from "@lodestar/types"; /** * Check if [[data1]] and [[data2]] are slashable according to Casper FFG rules. @@ -22,7 +22,7 @@ export function isValidAttestationSlot(attestationSlot: Slot, currentSlot: Slot) ); } -export function getAttesterSlashableIndices(attesterSlashing: phase0.AttesterSlashing): ValidatorIndex[] { +export function getAttesterSlashableIndices(attesterSlashing: AttesterSlashing): ValidatorIndex[] { const indices: ValidatorIndex[] = []; const attSet1 = new Set(attesterSlashing.attestation1.attestingIndices); const attArr2 = attesterSlashing.attestation2.attestingIndices; From 1fb71a37ab097d7f78966ee9c612bf9be53e307b Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 25 Jan 2025 11:53:30 +0000 Subject: [PATCH 02/10] Throw error if v1 api is used post-elecra, might not be able to serialize data --- packages/beacon-node/src/api/impl/beacon/pool/index.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 39556171670d..5f7463fe0e90 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -68,6 +68,15 @@ export function getBeaconPoolApi({ }, async getPoolAttesterSlashings() { + const fork = chain.config.getForkName(chain.clock.currentSlot); + + if (isForkPostElectra(fork)) { + throw new ApiError( + 400, + `Use getPoolAttesterSlashingsV2 to retrieve pool attester slashings for post-electra fork=${fork}` + ); + } + return {data: chain.opPool.getAllAttesterSlashings()}; }, From f78b61afa0a2d8ed1f6f6197191a7767488521bf Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 25 Jan 2025 11:54:03 +0000 Subject: [PATCH 03/10] Return fork based on clock slot in v2 api --- packages/beacon-node/src/api/impl/beacon/pool/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 5f7463fe0e90..18682e8fdcbe 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -81,8 +81,8 @@ export function getBeaconPoolApi({ }, async getPoolAttesterSlashingsV2() { - // TODO Electra: Determine fork based on data returned by api - return {data: chain.opPool.getAllAttesterSlashings(), meta: {version: ForkName.phase0}}; + const fork = chain.config.getForkName(chain.clock.currentSlot); + return {data: chain.opPool.getAllAttesterSlashings(), meta: {version: fork}}; }, async getPoolProposerSlashings() { From 8a40d0e4e0f98e776b010514131fdb1ae1196bf4 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 25 Jan 2025 11:58:24 +0000 Subject: [PATCH 04/10] Use electra type when inserting to op pool from db --- packages/beacon-node/src/chain/opPools/opPool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index 4017aa72d142..f4a6a62a24f6 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -68,7 +68,7 @@ export class OpPool { ]); for (const attesterSlashing of attesterSlashings) { - this.insertAttesterSlashing(attesterSlashing.value, attesterSlashing.key); + this.insertAttesterSlashing(ForkName.electra, attesterSlashing.value, attesterSlashing.key); } for (const proposerSlashing of proposerSlashings) { this.insertProposerSlashing(proposerSlashing); From 43297cdccb33f2648eb8f25c5e9ddad7a8abc91f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 25 Jan 2025 11:59:06 +0000 Subject: [PATCH 05/10] Simplify picking type --- packages/beacon-node/src/chain/opPools/opPool.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index f4a6a62a24f6..726fde5fb816 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -8,7 +8,6 @@ import { MAX_BLS_TO_EXECUTION_CHANGES, MAX_PROPOSER_SLASHINGS, MAX_VOLUNTARY_EXITS, - isForkPostElectra, } from "@lodestar/params"; import { CachedBeaconStateAllForks, @@ -17,7 +16,15 @@ import { getAttesterSlashableIndices, isValidVoluntaryExit, } from "@lodestar/state-transition"; -import {AttesterSlashing, Epoch, SignedBeaconBlock, ValidatorIndex, capella, phase0, ssz} from "@lodestar/types"; +import { + AttesterSlashing, + Epoch, + SignedBeaconBlock, + ValidatorIndex, + capella, + phase0, + sszTypesFor, +} from "@lodestar/types"; import {fromHex, toHex, toRootHex} from "@lodestar/utils"; import {IBeaconDb} from "../../db/index.js"; import {Metrics} from "../../metrics/metrics.js"; @@ -136,7 +143,7 @@ export class OpPool { /** Must be validated beforehand */ insertAttesterSlashing(fork: ForkName, attesterSlashing: AttesterSlashing, rootHash?: Uint8Array): void { if (!rootHash) { - const type = isForkPostElectra(fork) ? ssz.electra.AttesterSlashing : ssz.phase0.AttesterSlashing; + const type = sszTypesFor(fork).AttesterSlashing; rootHash = type.hashTreeRoot(attesterSlashing); } From 16e8e8ce90284a8421e2a8471372205d7c45f09d Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 25 Jan 2025 12:30:58 +0000 Subject: [PATCH 06/10] Use correct fork type when submitting through api --- packages/beacon-node/src/api/impl/beacon/pool/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 18682e8fdcbe..5715ac0cd14b 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -171,14 +171,13 @@ export function getBeaconPoolApi({ }, async submitPoolAttesterSlashings({attesterSlashing}) { - await validateApiAttesterSlashing(chain, attesterSlashing); - chain.opPool.insertAttesterSlashing(ForkName.phase0, attesterSlashing); - await network.publishAttesterSlashing(attesterSlashing); + await this.submitPoolAttesterSlashingsV2({attesterSlashing}); }, async submitPoolAttesterSlashingsV2({attesterSlashing}) { await validateApiAttesterSlashing(chain, attesterSlashing); - chain.opPool.insertAttesterSlashing(ForkName.electra, attesterSlashing); + const fork = chain.config.getForkName(Number(attesterSlashing.attestation1.data.slot)); + chain.opPool.insertAttesterSlashing(fork, attesterSlashing); await network.publishAttesterSlashing(attesterSlashing); }, From 27cb3a1ad887da106a7c5baca56015f8bd139d50 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 25 Jan 2025 12:39:55 +0000 Subject: [PATCH 07/10] Fix op pool perf tests --- packages/beacon-node/test/perf/chain/opPools/opPool.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts index d685ec36c6b7..2aae1419e56f 100644 --- a/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/opPool.test.ts @@ -1,5 +1,6 @@ import {itBench} from "@dapplion/benchmark"; import { + ForkName, MAX_ATTESTER_SLASHINGS, MAX_BLS_TO_EXECUTION_CHANGES, MAX_PROPOSER_SLASHINGS, @@ -63,7 +64,7 @@ describe("opPool", () => { function fillAttesterSlashing(pool: OpPool, state: CachedBeaconStateAltair, count: number): OpPool { for (const attestation of generateIndexedAttestations(state, count)) { - pool.insertAttesterSlashing({ + pool.insertAttesterSlashing(ForkName.phase0, { attestation1: ssz.phase0.IndexedAttestationBigint.fromJson(ssz.phase0.IndexedAttestation.toJson(attestation)), attestation2: ssz.phase0.IndexedAttestationBigint.fromJson(ssz.phase0.IndexedAttestation.toJson(attestation)), }); From 375f5dcfdf7a6ddfe16cceed52fef0f271161bcb Mon Sep 17 00:00:00 2001 From: NC <17676176+ensi321@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:02:11 -0800 Subject: [PATCH 08/10] Address comment --- .../src/db/repositories/attesterSlashing.ts | 49 +++---------------- 1 file changed, 7 insertions(+), 42 deletions(-) diff --git a/packages/beacon-node/src/db/repositories/attesterSlashing.ts b/packages/beacon-node/src/db/repositories/attesterSlashing.ts index 43e5c1ba24a5..2ee50853efa9 100644 --- a/packages/beacon-node/src/db/repositories/attesterSlashing.ts +++ b/packages/beacon-node/src/db/repositories/attesterSlashing.ts @@ -1,15 +1,8 @@ import {ChainForkConfig} from "@lodestar/config"; import {Db, Repository} from "@lodestar/db"; -import {ForkName, isForkPostElectra} from "@lodestar/params"; -import {AttesterSlashing, ValidatorIndex, phase0, ssz, sszTypesFor} from "@lodestar/types"; +import {AttesterSlashing, ValidatorIndex, ssz} from "@lodestar/types"; import {Bucket, getBucketNameByValue} from "../buckets.js"; -// We add a 1-byte prefix where 0 means pre-electra and 1 means post-electra -enum PrefixByte { - PRE_ELECTRA = 0, - POST_ELECTRA = 1, -} - /** * AttesterSlashing indexed by root * @@ -19,7 +12,12 @@ enum PrefixByte { export class AttesterSlashingRepository extends Repository { constructor(config: ChainForkConfig, db: Db) { const bucket = Bucket.allForks_attesterSlashing; - const type = ssz.phase0.AttesterSlashing; // Pick some type. Will be overriden + /** + * We are using ssz.electra.AttesterSlashing type since it is backward compatible with ssz.phase0.AttesterSlashing + * But this also means the length of attestingIndices is not checked/enfoced here. Need to make sure length + * is correct when put/get + */ + const type = ssz.electra.AttesterSlashing; super(config, db, bucket, type, getBucketNameByValue(bucket)); } @@ -37,37 +35,4 @@ export class AttesterSlashingRepository extends Repository Date: Thu, 30 Jan 2025 12:43:14 +0000 Subject: [PATCH 09/10] Cleanup --- packages/beacon-node/src/chain/opPools/opPool.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index 726fde5fb816..7bec42bdb0db 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -143,8 +143,7 @@ export class OpPool { /** Must be validated beforehand */ insertAttesterSlashing(fork: ForkName, attesterSlashing: AttesterSlashing, rootHash?: Uint8Array): void { if (!rootHash) { - const type = sszTypesFor(fork).AttesterSlashing; - rootHash = type.hashTreeRoot(attesterSlashing); + rootHash = sszTypesFor(fork).AttesterSlashing.hashTreeRoot(attesterSlashing); } // TODO: Do once and cache attached to the AttesterSlashing object From 628424fb07b4d098a2bb0051149c77f51e15a557 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Thu, 30 Jan 2025 12:43:47 +0000 Subject: [PATCH 10/10] Revise comment --- .../beacon-node/src/db/repositories/attesterSlashing.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/beacon-node/src/db/repositories/attesterSlashing.ts b/packages/beacon-node/src/db/repositories/attesterSlashing.ts index 2ee50853efa9..120267c67204 100644 --- a/packages/beacon-node/src/db/repositories/attesterSlashing.ts +++ b/packages/beacon-node/src/db/repositories/attesterSlashing.ts @@ -13,9 +13,9 @@ export class AttesterSlashingRepository extends Repository