diff --git a/Dockerfile b/Dockerfile index a9e597c2fb9f..996a55f3cde3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ # --platform=$BUILDPLATFORM is used build javascript source with host arch # Otherwise TS builds on emulated archs and can be extremely slow (+1h) -FROM --platform=${BUILDPLATFORM:-amd64} node:20-alpine as build_src +FROM --platform=${BUILDPLATFORM:-amd64} node:20-slim AS build_src ARG COMMIT WORKDIR /usr/app -RUN apk update && apk add --no-cache g++ make python3 && rm -rf /var/cache/apk/* +RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* COPY . . @@ -21,21 +21,21 @@ RUN cd packages/cli && GIT_COMMIT=${COMMIT} yarn write-git-data # Copy built src + node_modules to build native packages for archs different than host. # Note: This step is redundant for the host arch -FROM node:20-alpine as build_deps +FROM node:20-slim AS build_deps WORKDIR /usr/app -RUN apk update && apk add --no-cache g++ make python3 && rm -rf /var/cache/apk/* +RUN apt-get update && apt-get install -y g++ make python3 python3-setuptools && apt-get clean && rm -rf /var/lib/apt/lists/* COPY --from=build_src /usr/app . # Do yarn --force to trigger a rebuild of the native packages -# Emmulates `yarn rebuild` which is not available in v1 https://yarnpkg.com/cli/rebuild +# Emmulates `yarn rebuild` which is not available in v1 https://yarnpkg.com/cli/rebuild RUN yarn install --non-interactive --frozen-lockfile --production --force # Rebuild leveldb bindings (required for arm64 build) RUN cd node_modules/classic-level && yarn rebuild # Copy built src + node_modules to a new layer to prune unnecessary fs # Previous layer weights 7.25GB, while this final 488MB (as of Oct 2020) -FROM node:20-alpine +FROM node:20-slim WORKDIR /usr/app COPY --from=build_deps /usr/app . @@ -44,4 +44,4 @@ COPY --from=build_deps /usr/app . # since memory may spike during certain network conditions. ENV NODE_OPTIONS=--max-old-space-size=8192 -ENTRYPOINT ["node", "./packages/cli/bin/lodestar"] \ No newline at end of file +ENTRYPOINT ["node", "./packages/cli/bin/lodestar"] diff --git a/packages/beacon-node/src/chain/blocks/utils/elephantWithWings.ts b/packages/beacon-node/src/chain/blocks/utils/elephantWithWings.ts new file mode 100644 index 000000000000..4879daf8f4a1 --- /dev/null +++ b/packages/beacon-node/src/chain/blocks/utils/elephantWithWings.ts @@ -0,0 +1,20 @@ +export const ELECTRA_ELEPHANTWITHWINGS_BANNER = String.raw` + :~~. + :!:^::^^!!^ + :!^^ !:J. + .!!:! .^7^ + .?7~: ^#! !!!^!~. + :!^ GP~..^^?^ ^!: + !^ Y5 #7: + .:^^~7~. ! ~~6800~~^ ^6800^ ~~6800 68 00 68~~ 00~ || + .~! 55J ~~6800~~ :! !^ .YP :JP 7B. ^7# + ^7 :: 5 #:::^::~~6800~~^^?!?.~:: :! !^ 6800 .^PJ JG ~!B + :G ^7 ^ !^68 00^ ~~6800~~ :! !: .&~ ^#! ^!55~~~6800~~7G~ !7B + 7G ~!5J ^? !.----. ~! ~~6800~~ .7#: 6800 ~ + ?G :^?G. ...... ^?^.!G. ?G :^?G. ...... ^?^.!G. ! + ~! ~~6800~~ .7#: 6800 G~ 7G ~!5J ^? !.----. :: + :! !: .&~ ^#! ^!55~~~6800~~7G~ !7B :G ^7 ^ !^68 00^ ~~6800~~ :: + :! !^ 6800 .^PJ JG ~!B ^7 :: 5 ^^ !!!! #:::^::~~6800~~^^?!?.~ + :! !^ .YP :JP 7B. ^7# .~!~ ~~6800 ^6800^ ~~6800~~ + 6800 68 00 68~~ 00~ 6800 +`; diff --git a/packages/beacon-node/src/chain/blocks/verifyBlock.ts b/packages/beacon-node/src/chain/blocks/verifyBlock.ts index 658ac05d3908..a57b1ffcdb73 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlock.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlock.ts @@ -18,6 +18,7 @@ import {BlockInput, ImportBlockOpts, BlockInputType} from "./types.js"; import {POS_PANDA_MERGE_TRANSITION_BANNER} from "./utils/pandaMergeTransitionBanner.js"; import {CAPELLA_OWL_BANNER} from "./utils/ownBanner.js"; import {DENEB_BLOWFISH_BANNER} from "./utils/blowfishBanner.js"; +import {ELECTRA_ELEPHANTWITHWINGS_BANNER} from "./utils/elephantWithWings.js"; import {verifyBlocksStateTransitionOnly} from "./verifyBlocksStateTransitionOnly.js"; import {verifyBlocksSignatures} from "./verifyBlocksSignatures.js"; import {verifyBlocksExecutionPayload, SegmentExecStatus} from "./verifyBlocksExecutionPayloads.js"; @@ -152,6 +153,11 @@ export async function verifyBlocksInEpoch( this.logger.info("Activating withdrawals", {epoch: this.config.CAPELLA_FORK_EPOCH}); break; + case ForkName.electra: + this.logger.info(ELECTRA_ELEPHANTWITHWINGS_BANNER); + this.logger.info("Activating verkle", {epoch: this.config.ELECTRA_FORK_EPOCH}); + break; + case ForkName.deneb: this.logger.info(DENEB_BLOWFISH_BANNER); this.logger.info("Activating blobs", {epoch: this.config.DENEB_FORK_EPOCH}); diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 72a0100f7a51..ca00183b1713 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -1,4 +1,5 @@ -import {allForks, capella, deneb, Wei, bellatrix, Root} from "@lodestar/types"; +import * as util from "node:util"; +import {allForks, capella, deneb, Wei, bellatrix, Root, electra, ssz} from "@lodestar/types"; import { BYTES_PER_LOGS_BLOOM, FIELD_ELEMENTS_PER_BLOB, @@ -134,6 +135,7 @@ export type ExecutionPayloadRpc = { blobGasUsed?: QUANTITY; // DENEB excessBlobGas?: QUANTITY; // DENEB parentBeaconBlockRoot?: QUANTITY; // DENEB + executionWitness?: Record; // DENEB }; export type WithdrawalRpc = { @@ -194,6 +196,20 @@ export function serializeExecutionPayload(fork: ForkName, data: allForks.Executi payload.excessBlobGas = numToQuantity(excessBlobGas); } + // ELECTRA adds executionWitness to the ExecutionPayload + if (ForkSeq[fork] >= ForkSeq.electra) { + const {executionWitness} = data as electra.ExecutionPayload; + // right now the caseMap of ssz ExecutionWitness is camel cased and can + // directly be used to serialize tojson + payload.executionWitness = ssz.electra.ExecutionWitness.toJson(executionWitness); + // serialization with ssz serialize suffix diff's suffix to a string while geth expects num + (payload.executionWitness as electra.ExecutionWitness).stateDiff.forEach((sDiff) => { + sDiff.suffixDiffs.forEach((sfDiff) => { + sfDiff.suffix = Number(sfDiff.suffix); + }); + }); + } + return payload; } @@ -279,6 +295,20 @@ export function parseExecutionPayload( (executionPayload as deneb.ExecutionPayload).excessBlobGas = quantityToBigint(excessBlobGas); } + // ELECTRA adds execution witness to the payload + if (ForkSeq[fork] >= ForkSeq.electra) { + // right now the casing of executionWitness is camel case in the ssz caseMap + // we can directly use fromJson to read the serialized data from payload + const {executionWitness} = data; + console.log( + "parse executionWitness from EL", + util.inspect(executionWitness, false, null, true /* enable colors */), + {blockNumber: data.blockNumber} + ); + (executionPayload as electra.ExecutionPayload).executionWitness = + ssz.electra.ExecutionWitness.fromJson(executionWitness); + } + return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; } diff --git a/packages/beacon-node/test/spec/presets/fork.test.ts b/packages/beacon-node/test/spec/presets/fork.test.ts index 228ab6a38935..c121e651fcea 100644 --- a/packages/beacon-node/test/spec/presets/fork.test.ts +++ b/packages/beacon-node/test/spec/presets/fork.test.ts @@ -5,6 +5,7 @@ import { CachedBeaconStateAltair, CachedBeaconStatePhase0, CachedBeaconStateCapella, + CachedBeaconStateDeneb, } from "@lodestar/state-transition"; import * as slotFns from "@lodestar/state-transition/slot"; import {phase0, ssz} from "@lodestar/types"; @@ -35,6 +36,8 @@ const fork: TestRunnerFn = (forkNext) => { return slotFns.upgradeStateToCapella(preState as CachedBeaconStateBellatrix); case ForkName.deneb: return slotFns.upgradeStateToDeneb(preState as CachedBeaconStateCapella); + case ForkName.electra: + return slotFns.upgradeStateToElectra(preState as CachedBeaconStateDeneb); } }, options: { diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index ba3351a2103c..c782c6bd432d 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -1,6 +1,6 @@ import path from "node:path"; import {expect} from "vitest"; -import {phase0, Root, ssz, TimeSeconds, allForks, deneb} from "@lodestar/types"; +import {phase0, Root, ssz, TimeSeconds, allForks} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; import { BeaconStateAllForks, @@ -47,7 +47,7 @@ const genesisInitialization: TestRunnerFn = { phase0: { @@ -57,6 +59,14 @@ function getForkConfig({ prevVersion: Buffer.from([0, 0, 0, 3]), prevForkName: ForkName.capella, }, + electra: { + name: ForkName.electra, + seq: ForkSeq.electra, + epoch: electra, + version: Buffer.from([0, 0, 0, 4]), + prevVersion: Buffer.from([0, 0, 0, 3]), + prevForkName: ForkName.capella, + }, }; const forksAscendingEpochOrder = Object.values(forks); const forksDescendingEpochOrder = Object.values(forks).reverse(); @@ -133,9 +143,10 @@ const testScenarios = [ for (const testScenario of testScenarios) { const {phase0, altair, bellatrix, capella, testCases} = testScenario; const deneb = Infinity; + const electra = Infinity; describe(`network / fork: phase0: ${phase0}, altair: ${altair}, bellatrix: ${bellatrix} capella: ${capella}`, () => { - const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb}); + const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb, electra}); const forks = forkConfig.forks; for (const testCase of testCases) { const {epoch, currentFork, nextFork, activeForks} = testCase; diff --git a/packages/beacon-node/test/utils/config.ts b/packages/beacon-node/test/utils/config.ts index 54c058d30722..2aad1c14c03e 100644 --- a/packages/beacon-node/test/utils/config.ts +++ b/packages/beacon-node/test/utils/config.ts @@ -31,5 +31,13 @@ export function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { CAPELLA_FORK_EPOCH: 0, DENEB_FORK_EPOCH: forkEpoch, }); + case ForkName.electra: + return createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: forkEpoch, + }); } } diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 9d060330d201..1bf51c4f3b4c 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -49,6 +49,10 @@ export const chainConfig: ChainConfig = { DENEB_FORK_VERSION: b("0x04000000"), DENEB_FORK_EPOCH: 269568, // March 13, 2024, 01:55:35pm UTC + // ELECTRA + ELECTRA_FORK_VERSION: b("0x05000000"), + ELECTRA_FORK_EPOCH: Infinity, + // Time parameters // --------------------------------------------------------------- // 12 seconds diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index 6c0a13d8abb2..143a64256724 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -45,6 +45,9 @@ export const chainConfig: ChainConfig = { // Deneb DENEB_FORK_VERSION: b("0x04000001"), DENEB_FORK_EPOCH: Infinity, + // Electra + ELECTRA_FORK_VERSION: b("0x05000001"), + ELECTRA_FORK_EPOCH: Infinity, // Time parameters // --------------------------------------------------------------- diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index 3e0844118290..384ef54ca994 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -40,6 +40,9 @@ export type ChainConfig = { // DENEB DENEB_FORK_VERSION: Uint8Array; DENEB_FORK_EPOCH: number; + // ELECTRA + ELECTRA_FORK_VERSION: Uint8Array; + ELECTRA_FORK_EPOCH: number; // Time parameters SECONDS_PER_SLOT: number; @@ -96,6 +99,9 @@ export const chainConfigTypes: SpecTypes = { // DENEB DENEB_FORK_VERSION: "bytes", DENEB_FORK_EPOCH: "number", + // ELECTRA + ELECTRA_FORK_VERSION: "bytes", + ELECTRA_FORK_EPOCH: "number", // Time parameters SECONDS_PER_SLOT: "number", diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index d630f1ddfc88..6615b4ce44e7 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -55,10 +55,18 @@ export function createForkConfig(config: ChainConfig): ForkConfig { prevVersion: config.CAPELLA_FORK_VERSION, prevForkName: ForkName.capella, }; + const electra: ForkInfo = { + name: ForkName.electra, + seq: ForkSeq.electra, + epoch: config.ELECTRA_FORK_EPOCH, + version: config.ELECTRA_FORK_VERSION, + prevVersion: config.CAPELLA_FORK_VERSION, + prevForkName: ForkName.capella, + }; /** Forks in order order of occurence, `phase0` first */ // Note: Downstream code relies on proper ordering. - const forks = {phase0, altair, bellatrix, capella, deneb}; + const forks = {phase0, altair, bellatrix, capella, electra, deneb}; // Prevents allocating an array on every getForkInfo() call const forksAscendingEpochOrder = Object.values(forks); diff --git a/packages/params/src/forkName.ts b/packages/params/src/forkName.ts index 142684c313f4..c779046292b6 100644 --- a/packages/params/src/forkName.ts +++ b/packages/params/src/forkName.ts @@ -7,6 +7,7 @@ export enum ForkName { bellatrix = "bellatrix", capella = "capella", deneb = "deneb", + electra = "electra", } /** @@ -17,7 +18,9 @@ export enum ForkSeq { altair = 1, bellatrix = 2, capella = 3, - deneb = 4, + // Electra is scheduled after capella for now + electra = 4, + deneb = 5, } export type ForkPreLightClient = ForkName.phase0; @@ -38,8 +41,14 @@ export function isForkWithdrawals(fork: ForkName): fork is ForkWithdrawals { return isForkExecution(fork) && fork !== ForkName.bellatrix; } -export type ForkPreBlobs = ForkPreWithdrawals | ForkName.capella; +export type ForkPreVerge = ForkPreWithdrawals | ForkName.capella; +export type ForkVerge = Exclude; +export function isForkVerge(fork: ForkName): fork is ForkVerge { + return isForkWithdrawals(fork) && fork !== ForkName.capella; +} + +export type ForkPreBlobs = ForkPreVerge | ForkName.electra; export type ForkBlobs = Exclude; export function isForkBlobs(fork: ForkName): fork is ForkBlobs { - return isForkWithdrawals(fork) && fork !== ForkName.capella; + return isForkVerge(fork) && fork !== ForkName.electra; } diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 6a95e3ca632e..05777b5d6d8a 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -244,3 +244,10 @@ export const KZG_COMMITMENT_SUBTREE_INDEX0 = KZG_COMMITMENT_GINDEX0 - 2 ** KZG_C // ssz.deneb.BlobSidecars.elementType.fixedSize export const BLOBSIDECAR_FIXED_SIZE = ACTIVE_PRESET === PresetName.minimal ? 131672 : 131928; + +// TODO: Electra spec notes these as preset but there's only one value +// https://github.com/ethereum/consensus-specs/blob/db74090c1e8dc1fb2c052bae268e22dc63061e32/specs/verge/beacon-chain.md#preset +export const MAX_STEMS = 2 ** 16; +export const MAX_COMMITMENTS_PER_STEM = 33; +export const VERKLE_WIDTH = 256; +export const IPA_PROOF_DEPTH = 8; diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 8b45152a3646..3015011da554 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -11,6 +11,7 @@ import { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateElectra, } from "./types.js"; import {RewardCache, createEmptyRewardCache} from "./rewardCache.js"; @@ -131,6 +132,7 @@ export type CachedBeaconStateAltair = CachedBeaconState; export type CachedBeaconStateBellatrix = CachedBeaconState; export type CachedBeaconStateCapella = CachedBeaconState; export type CachedBeaconStateDeneb = CachedBeaconState; +export type CachedBeaconStateElectra = CachedBeaconState; export type CachedBeaconStateAllForks = CachedBeaconState; export type CachedBeaconStateExecutions = CachedBeaconState; diff --git a/packages/state-transition/src/cache/types.ts b/packages/state-transition/src/cache/types.ts index 39b1dbb4b45b..a865aa4f4183 100644 --- a/packages/state-transition/src/cache/types.ts +++ b/packages/state-transition/src/cache/types.ts @@ -7,6 +7,7 @@ export type BeaconStateAltair = CompositeViewDU; export type BeaconStateBellatrix = CompositeViewDU; export type BeaconStateCapella = CompositeViewDU; export type BeaconStateDeneb = CompositeViewDU; +export type BeaconStateElectra = CompositeViewDU; // Union at the TreeViewDU level // - Works well as function argument and as generic type for allForks functions @@ -18,8 +19,9 @@ export type BeaconStateAllForks = | BeaconStateAltair | BeaconStateBellatrix | BeaconStateCapella - | BeaconStateDeneb; + | BeaconStateDeneb + | BeaconStateElectra; -export type BeaconStateExecutions = BeaconStateBellatrix | BeaconStateCapella | BeaconStateDeneb; +export type BeaconStateExecutions = BeaconStateBellatrix | BeaconStateCapella | BeaconStateDeneb | BeaconStateElectra; export type ShufflingGetter = (shufflingEpoch: Epoch, dependentRoot: RootHex) => EpochShuffling | null; diff --git a/packages/state-transition/src/slot/index.ts b/packages/state-transition/src/slot/index.ts index 6c4add1d1230..b05bd7ac93f2 100644 --- a/packages/state-transition/src/slot/index.ts +++ b/packages/state-transition/src/slot/index.ts @@ -7,6 +7,7 @@ export {upgradeStateToAltair} from "./upgradeStateToAltair.js"; export {upgradeStateToBellatrix} from "./upgradeStateToBellatrix.js"; export {upgradeStateToCapella} from "./upgradeStateToCapella.js"; export {upgradeStateToDeneb} from "./upgradeStateToDeneb.js"; +export {upgradeStateToElectra} from "./upgradeStateToElectra.js"; /** * Dial state to next slot. Common for all forks diff --git a/packages/state-transition/src/slot/upgradeStateToElectra.ts b/packages/state-transition/src/slot/upgradeStateToElectra.ts new file mode 100644 index 000000000000..d43d0d344486 --- /dev/null +++ b/packages/state-transition/src/slot/upgradeStateToElectra.ts @@ -0,0 +1,26 @@ +import {ssz} from "@lodestar/types"; +import {CachedBeaconStateCapella, CachedBeaconStateElectra} from "../types.js"; +import {getCachedBeaconState} from "../cache/stateCache.js"; + +/** + * Upgrade a state from Capella (Eventualy DENEB) to Electra. + */ +export function upgradeStateToElectra(stateCapella: CachedBeaconStateCapella): CachedBeaconStateElectra { + const {config} = stateCapella; + + const stateCapellaNode = ssz.capella.BeaconState.commitViewDU(stateCapella); + const stateElectraView = ssz.electra.BeaconState.getViewDU(stateCapellaNode); + + const stateElectra = getCachedBeaconState(stateElectraView, stateCapella); + + stateElectra.fork = ssz.phase0.Fork.toViewDU({ + previousVersion: stateCapella.fork.currentVersion, + currentVersion: config.ELECTRA_FORK_VERSION, + epoch: stateCapella.epochCtx.epoch, + }); + + // latestExecutionPayloadHeader's executionWitnessRoot will have default zero root + + stateElectra.commit(); + return stateElectra; +} diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index b3f3b41eb865..7a986b2b2e93 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -9,6 +9,7 @@ import { CachedBeaconStateAltair, CachedBeaconStateBellatrix, CachedBeaconStateCapella, + // CachedBeaconStateDeneb, } from "./types.js"; import {computeEpochAtSlot} from "./util/index.js"; import {verifyProposerSignature} from "./signatureSets/index.js"; @@ -23,6 +24,7 @@ import {processBlock} from "./block/index.js"; import {EpochTransitionStep, processEpoch} from "./epoch/index.js"; import {BlockExternalData, DataAvailableStatus, ExecutionPayloadStatus} from "./block/externalData.js"; import {ProcessBlockOpts} from "./block/types.js"; +import {upgradeStateToElectra} from "./slot/upgradeStateToElectra.js"; // Multifork capable state transition @@ -230,6 +232,9 @@ function processSlotsWithTransientCache( if (stateSlot === config.DENEB_FORK_EPOCH) { postState = upgradeStateToDeneb(postState as CachedBeaconStateCapella) as CachedBeaconStateAllForks; } + if (stateSlot === config.ELECTRA_FORK_EPOCH) { + postState = upgradeStateToElectra(postState as CachedBeaconStateCapella) as CachedBeaconStateAllForks; + } } else { postState.slot++; } diff --git a/packages/state-transition/src/types.ts b/packages/state-transition/src/types.ts index 6b6b1f6260b2..d3a1ed69a7a9 100644 --- a/packages/state-transition/src/types.ts +++ b/packages/state-transition/src/types.ts @@ -9,6 +9,7 @@ export type { CachedBeaconStateBellatrix, CachedBeaconStateCapella, CachedBeaconStateDeneb, + CachedBeaconStateElectra, } from "./cache/stateCache.js"; export type { @@ -19,4 +20,5 @@ export type { BeaconStateBellatrix, BeaconStateCapella, BeaconStateDeneb, + BeaconStateElectra, } from "./cache/types.js"; diff --git a/packages/state-transition/src/util/execution.ts b/packages/state-transition/src/util/execution.ts index 7ac4da4aeecb..ca9cd0f1dc5c 100644 --- a/packages/state-transition/src/util/execution.ts +++ b/packages/state-transition/src/util/execution.ts @@ -1,4 +1,4 @@ -import {allForks, bellatrix, capella, deneb, isBlindedBeaconBlockBody, ssz} from "@lodestar/types"; +import {allForks, bellatrix, capella, deneb, electra, isBlindedBeaconBlockBody, ssz} from "@lodestar/types"; import {ForkSeq} from "@lodestar/params"; import { @@ -170,5 +170,11 @@ export function executionPayloadToPayloadHeader( ).excessBlobGas; } + if (fork >= ForkSeq.electra) { + // https://github.com/ethereum/consensus-specs/blob/db74090c1e8dc1fb2c052bae268e22dc63061e32/specs/verge/beacon-chain.md#process_execution_payload + (bellatrixPayloadFields as electra.ExecutionPayloadHeader).executionWitnessRoot = + ssz.electra.ExecutionWitness.hashTreeRoot((payload as electra.ExecutionPayload).executionWitness); + } + return bellatrixPayloadFields; } diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 1041c33d0eb3..1edbab34ad57 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -214,6 +214,7 @@ export function initializeBeaconStateFromEth1( | typeof ssz.bellatrix.ExecutionPayloadHeader | typeof ssz.capella.ExecutionPayloadHeader | typeof ssz.deneb.ExecutionPayloadHeader + | typeof ssz.electra.ExecutionPayloadHeader > ): CachedBeaconStateAllForks { const stateView = getGenesisBeaconState( @@ -284,6 +285,15 @@ export function initializeBeaconStateFromEth1( ssz.deneb.ExecutionPayloadHeader.defaultViewDU(); } + if (GENESIS_SLOT >= config.ELECTRA_FORK_EPOCH) { + const stateElectra = state as CompositeViewDU; + stateElectra.fork.previousVersion = config.ELECTRA_FORK_VERSION; + stateElectra.fork.currentVersion = config.ELECTRA_FORK_VERSION; + stateElectra.latestExecutionPayloadHeader = + (executionPayloadHeader as CompositeViewDU) ?? + ssz.electra.ExecutionPayloadHeader.defaultViewDU(); + } + state.commit(); return state; diff --git a/packages/types/src/allForks/sszTypes.ts b/packages/types/src/allForks/sszTypes.ts index 7174bc52e89c..5d2f5f1558ce 100644 --- a/packages/types/src/allForks/sszTypes.ts +++ b/packages/types/src/allForks/sszTypes.ts @@ -3,6 +3,7 @@ import {ssz as altair} from "../altair/index.js"; import {ssz as bellatrix} from "../bellatrix/index.js"; import {ssz as capella} from "../capella/index.js"; import {ssz as deneb} from "../deneb/index.js"; +import {ssz as electra} from "../electra/index.js"; /** * Index the ssz types that differ by fork @@ -44,6 +45,13 @@ export const allForks = { BeaconState: deneb.BeaconState, Metadata: altair.Metadata, }, + electra: { + BeaconBlockBody: electra.BeaconBlockBody, + BeaconBlock: electra.BeaconBlock, + SignedBeaconBlock: electra.SignedBeaconBlock, + BeaconState: electra.BeaconState, + Metadata: altair.Metadata, + }, }; /** @@ -85,6 +93,17 @@ export const allForksExecution = { SignedBuilderBid: deneb.SignedBuilderBid, SSEPayloadAttributes: deneb.SSEPayloadAttributes, }, + electra: { + BeaconBlockBody: electra.BeaconBlockBody, + BeaconBlock: electra.BeaconBlock, + SignedBeaconBlock: electra.SignedBeaconBlock, + BeaconState: electra.BeaconState, + ExecutionPayload: electra.ExecutionPayload, + ExecutionPayloadHeader: electra.ExecutionPayloadHeader, + BuilderBid: deneb.BuilderBid, + SignedBuilderBid: deneb.SignedBuilderBid, + SSEPayloadAttributes: deneb.SSEPayloadAttributes, + }, }; /** @@ -107,6 +126,11 @@ export const allForksBlinded = { BeaconBlock: deneb.BlindedBeaconBlock, SignedBeaconBlock: deneb.SignedBlindedBeaconBlock, }, + electra: { + BeaconBlockBody: electra.BlindedBeaconBlockBody, + BeaconBlock: electra.BlindedBeaconBlock, + SignedBeaconBlock: electra.SignedBlindedBeaconBlock, + }, }; export const allForksLightClient = { @@ -150,6 +174,16 @@ export const allForksLightClient = { LightClientOptimisticUpdate: deneb.LightClientOptimisticUpdate, LightClientStore: deneb.LightClientStore, }, + electra: { + BeaconBlock: electra.BeaconBlock, + BeaconBlockBody: electra.BeaconBlockBody, + LightClientHeader: electra.LightClientHeader, + LightClientBootstrap: electra.LightClientBootstrap, + LightClientUpdate: electra.LightClientUpdate, + LightClientFinalityUpdate: electra.LightClientFinalityUpdate, + LightClientOptimisticUpdate: electra.LightClientOptimisticUpdate, + LightClientStore: electra.LightClientStore, + }, }; export const allForksBlobs = { @@ -157,4 +191,8 @@ export const allForksBlobs = { BlobSidecar: deneb.BlobSidecar, ExecutionPayloadAndBlobsBundle: deneb.ExecutionPayloadAndBlobsBundle, }, + // electra: { + // BlobSidecar: deneb.BlobSidecar, + // ExecutionPayloadAndBlobsBundle: electra.ExecutionPayloadAndBlobsBundle, + // }, }; diff --git a/packages/types/src/allForks/types.ts b/packages/types/src/allForks/types.ts index 59768a5a3308..ad9165d48fcb 100644 --- a/packages/types/src/allForks/types.ts +++ b/packages/types/src/allForks/types.ts @@ -4,12 +4,14 @@ import {ts as altair} from "../altair/index.js"; import {ts as bellatrix} from "../bellatrix/index.js"; import {ts as capella} from "../capella/index.js"; import {ts as deneb} from "../deneb/index.js"; +import {ts as electra} from "../electra/index.js"; import {ssz as phase0Ssz} from "../phase0/index.js"; import {ssz as altairSsz} from "../altair/index.js"; import {ssz as bellatrixSsz} from "../bellatrix/index.js"; import {ssz as capellaSsz} from "../capella/index.js"; import {ssz as denebSsz} from "../deneb/index.js"; +import {ssz as electraSsz} from "../electra/index.js"; // Re-export union types for types that are _known_ to differ @@ -18,47 +20,66 @@ export type BeaconBlockBody = | altair.BeaconBlockBody | bellatrix.BeaconBlockBody | capella.BeaconBlockBody - | deneb.BeaconBlockBody; + | deneb.BeaconBlockBody + | electra.BeaconBlockBody; export type BeaconBlock = | phase0.BeaconBlock | altair.BeaconBlock | bellatrix.BeaconBlock | capella.BeaconBlock - | deneb.BeaconBlock; + | deneb.BeaconBlock + | electra.BeaconBlock; export type SignedBeaconBlock = | phase0.SignedBeaconBlock | altair.SignedBeaconBlock | bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock - | deneb.SignedBeaconBlock; + | deneb.SignedBeaconBlock + | electra.SignedBeaconBlock; export type BeaconState = | phase0.BeaconState | altair.BeaconState | bellatrix.BeaconState | capella.BeaconState - | deneb.BeaconState; + | deneb.BeaconState + | electra.BeaconState; export type Metadata = phase0.Metadata | altair.Metadata; // For easy reference in the assemble block for building payloads -export type ExecutionBlockBody = bellatrix.BeaconBlockBody | capella.BeaconBlockBody | deneb.BeaconBlockBody; +export type ExecutionBlockBody = + | bellatrix.BeaconBlockBody + | capella.BeaconBlockBody + | deneb.BeaconBlockBody + | electra.BeaconBlockBody; // These two additional types will also change bellatrix forward -export type ExecutionPayload = bellatrix.ExecutionPayload | capella.ExecutionPayload | deneb.ExecutionPayload; +export type ExecutionPayload = + | bellatrix.ExecutionPayload + | capella.ExecutionPayload + | deneb.ExecutionPayload + | electra.ExecutionPayload; export type ExecutionPayloadHeader = | bellatrix.ExecutionPayloadHeader | capella.ExecutionPayloadHeader - | deneb.ExecutionPayloadHeader; + | deneb.ExecutionPayloadHeader + | electra.ExecutionPayloadHeader; // Blinded types that will change across forks export type BlindedBeaconBlockBody = | bellatrix.BlindedBeaconBlockBody | capella.BlindedBeaconBlockBody - | deneb.BlindedBeaconBlockBody; -export type BlindedBeaconBlock = bellatrix.BlindedBeaconBlock | capella.BlindedBeaconBlock | deneb.BlindedBeaconBlock; + | deneb.BlindedBeaconBlockBody + | electra.BlindedBeaconBlockBody; +export type BlindedBeaconBlock = + | bellatrix.BlindedBeaconBlock + | capella.BlindedBeaconBlock + | deneb.BlindedBeaconBlock + | electra.BlindedBeaconBlock; export type SignedBlindedBeaconBlock = | bellatrix.SignedBlindedBeaconBlock | capella.SignedBlindedBeaconBlock - | deneb.SignedBlindedBeaconBlock; + | deneb.SignedBlindedBeaconBlock + | electra.SignedBlindedBeaconBlock; // Full or blinded types export type FullOrBlindedExecutionPayload = @@ -178,6 +199,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + | typeof electraSsz.BeaconBlockBody >; BeaconBlock: AllForksTypeOf< | typeof phase0Ssz.BeaconBlock @@ -185,6 +207,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock + | typeof electraSsz.BeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof phase0Ssz.SignedBeaconBlock @@ -192,6 +215,7 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock + | typeof electraSsz.SignedBeaconBlock >; BeaconState: AllForksTypeOf< | typeof phase0Ssz.BeaconState @@ -199,30 +223,47 @@ export type AllForksSSZTypes = { | typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState + | typeof electraSsz.BeaconState >; Metadata: AllForksTypeOf; }; export type AllForksExecutionSSZTypes = { BeaconBlockBody: AllForksTypeOf< - typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + | typeof bellatrixSsz.BeaconBlockBody + | typeof capellaSsz.BeaconBlockBody + | typeof denebSsz.BeaconBlockBody + | typeof electraSsz.BeaconBlockBody >; BeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock + | typeof bellatrixSsz.BeaconBlock + | typeof capellaSsz.BeaconBlock + | typeof denebSsz.BeaconBlock + | typeof electraSsz.BeaconBlock >; SignedBeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.SignedBeaconBlock | typeof capellaSsz.SignedBeaconBlock | typeof denebSsz.SignedBeaconBlock + | typeof bellatrixSsz.SignedBeaconBlock + | typeof capellaSsz.SignedBeaconBlock + | typeof denebSsz.SignedBeaconBlock + | typeof electraSsz.SignedBeaconBlock >; BeaconState: AllForksTypeOf< - typeof bellatrixSsz.BeaconState | typeof capellaSsz.BeaconState | typeof denebSsz.BeaconState + | typeof bellatrixSsz.BeaconState + | typeof capellaSsz.BeaconState + | typeof denebSsz.BeaconState + | typeof electraSsz.BeaconState >; ExecutionPayload: AllForksTypeOf< - typeof bellatrixSsz.ExecutionPayload | typeof capellaSsz.ExecutionPayload | typeof denebSsz.ExecutionPayload + | typeof bellatrixSsz.ExecutionPayload + | typeof capellaSsz.ExecutionPayload + | typeof denebSsz.ExecutionPayload + | typeof electraSsz.ExecutionPayload >; ExecutionPayloadHeader: AllForksTypeOf< | typeof bellatrixSsz.ExecutionPayloadHeader | typeof capellaSsz.ExecutionPayloadHeader | typeof denebSsz.ExecutionPayloadHeader + | typeof electraSsz.ExecutionPayloadHeader >; BuilderBid: AllForksTypeOf< typeof bellatrixSsz.BuilderBid | typeof capellaSsz.BuilderBid | typeof denebSsz.BuilderBid @@ -242,14 +283,19 @@ export type AllForksBlindedSSZTypes = { | typeof bellatrixSsz.BlindedBeaconBlockBody | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock + | typeof electraSsz.BlindedBeaconBlock >; BeaconBlock: AllForksTypeOf< - typeof bellatrixSsz.BlindedBeaconBlock | typeof capellaSsz.BlindedBeaconBlock | typeof denebSsz.BlindedBeaconBlock + | typeof bellatrixSsz.BlindedBeaconBlock + | typeof capellaSsz.BlindedBeaconBlock + | typeof denebSsz.BlindedBeaconBlock + | typeof electraSsz.BlindedBeaconBlock >; SignedBeaconBlock: AllForksTypeOf< | typeof bellatrixSsz.SignedBlindedBeaconBlock | typeof capellaSsz.SignedBlindedBeaconBlock | typeof denebSsz.SignedBlindedBeaconBlock + | typeof electraSsz.SignedBlindedBeaconBlock >; }; @@ -259,36 +305,50 @@ export type AllForksLightClientSSZTypes = { | typeof bellatrixSsz.BeaconBlock | typeof capellaSsz.BeaconBlock | typeof denebSsz.BeaconBlock + | typeof electraSsz.BeaconBlock >; BeaconBlockBody: AllForksTypeOf< | typeof altairSsz.BeaconBlockBody | typeof bellatrixSsz.BeaconBlockBody | typeof capellaSsz.BeaconBlockBody | typeof denebSsz.BeaconBlockBody + | typeof electraSsz.BeaconBlockBody >; LightClientHeader: AllForksTypeOf< - typeof altairSsz.LightClientHeader | typeof capellaSsz.LightClientHeader | typeof denebSsz.LightClientHeader + | typeof altairSsz.LightClientHeader + | typeof capellaSsz.LightClientHeader + | typeof denebSsz.LightClientHeader + | typeof electraSsz.LightClientHeader >; LightClientBootstrap: AllForksTypeOf< | typeof altairSsz.LightClientBootstrap | typeof capellaSsz.LightClientBootstrap | typeof denebSsz.LightClientBootstrap + | typeof electraSsz.LightClientBootstrap >; LightClientUpdate: AllForksTypeOf< - typeof altairSsz.LightClientUpdate | typeof capellaSsz.LightClientUpdate | typeof denebSsz.LightClientUpdate + | typeof altairSsz.LightClientUpdate + | typeof capellaSsz.LightClientUpdate + | typeof denebSsz.LightClientUpdate + | typeof electraSsz.LightClientUpdate >; LightClientFinalityUpdate: AllForksTypeOf< | typeof altairSsz.LightClientFinalityUpdate | typeof capellaSsz.LightClientFinalityUpdate | typeof denebSsz.LightClientFinalityUpdate + | typeof electraSsz.LightClientFinalityUpdate >; LightClientOptimisticUpdate: AllForksTypeOf< | typeof altairSsz.LightClientOptimisticUpdate | typeof capellaSsz.LightClientOptimisticUpdate | typeof denebSsz.LightClientOptimisticUpdate + | typeof electraSsz.LightClientOptimisticUpdate >; LightClientStore: AllForksTypeOf< - typeof altairSsz.LightClientStore | typeof capellaSsz.LightClientStore | typeof denebSsz.LightClientStore + | typeof altairSsz.LightClientStore + | typeof capellaSsz.LightClientStore + | typeof denebSsz.LightClientStore + | typeof electraSsz.LightClientOptimisticUpdate >; }; diff --git a/packages/types/src/electra/index.ts b/packages/types/src/electra/index.ts new file mode 100644 index 000000000000..7856cd729620 --- /dev/null +++ b/packages/types/src/electra/index.ts @@ -0,0 +1,3 @@ +export * from "./types.js"; +export * as ts from "./types.js"; +export * as ssz from "./sszTypes.js"; diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts new file mode 100644 index 000000000000..acd9fcd7c22f --- /dev/null +++ b/packages/types/src/electra/sszTypes.ts @@ -0,0 +1,284 @@ +import { + ContainerType, + ListCompositeType, + ByteVectorType, + VectorCompositeType, + ByteListType, + OptionalType, +} from "@chainsafe/ssz"; +import { + HISTORICAL_ROOTS_LIMIT, + VERKLE_WIDTH, + MAX_STEMS, + IPA_PROOF_DEPTH, + MAX_COMMITMENTS_PER_STEM, + BLOCK_BODY_EXECUTION_PAYLOAD_DEPTH as EXECUTION_PAYLOAD_DEPTH, + EPOCHS_PER_SYNC_COMMITTEE_PERIOD, + SLOTS_PER_EPOCH, +} from "@lodestar/params"; +import {ssz as primitiveSsz} from "../primitive/index.js"; +import {ssz as phase0Ssz} from "../phase0/index.js"; +import {ssz as altairSsz} from "../altair/index.js"; +import {ssz as bellatrixSsz} from "../bellatrix/index.js"; +import {ssz as capellaSsz} from "../capella/index.js"; +// import {ssz as denebSsz} from "../deneb/index.js"; + +const {UintNum64, Root, BLSSignature, Slot, Bytes32} = primitiveSsz; + +// Spec: https://github.com/ethereum/consensus-specs/blob/db74090c1e8dc1fb2c052bae268e22dc63061e32/specs/verge/beacon-chain.md + +// Custom types + +export const Bytes31 = new ByteVectorType(31); +export const BanderwagonGroupElement = new ByteVectorType(32); +export const BanderwagonFieldElement = new ByteVectorType(32); +export const Stem = new ByteVectorType(31); + +// Beacon chain + +export const SuffixStateDiff = new ContainerType( + { + suffix: primitiveSsz.Byte, + // Null means not currently present + currentValue: new OptionalType(primitiveSsz.Bytes32), + // Null means value not updated + newValue: new OptionalType(primitiveSsz.Bytes32), + }, + { + typeName: "SuffixStateDiff", + casingMap: { + suffix: "suffix", + currentValue: "currentValue", + newValue: "newValue", + }, + } +); + +export const StemStateDiff = new ContainerType( + { + stem: Stem, + // Valid only if list is sorted by suffixes + suffixDiffs: new ListCompositeType(SuffixStateDiff, VERKLE_WIDTH), + }, + {typeName: "StemStateDiff", casingMap: {stem: "stem", suffixDiffs: "suffixDiffs"}} +); + +// Valid only if list is sorted by stems +export const StateDiff = new ListCompositeType(StemStateDiff, MAX_STEMS); + +export const IpaProof = new ContainerType( + { + cl: new VectorCompositeType(BanderwagonGroupElement, IPA_PROOF_DEPTH), + cr: new VectorCompositeType(BanderwagonGroupElement, IPA_PROOF_DEPTH), + finalEvaluation: BanderwagonFieldElement, + }, + {typeName: "IpaProof", casingMap: {cl: "cl", cr: "cr", finalEvaluation: "finalEvaluation"}} +); + +export const VerkleProof = new ContainerType( + { + otherStems: new ListCompositeType(Bytes31, MAX_STEMS), + depthExtensionPresent: new ByteListType(MAX_STEMS), + commitmentsByPath: new ListCompositeType(BanderwagonGroupElement, MAX_STEMS * MAX_COMMITMENTS_PER_STEM), + d: BanderwagonGroupElement, + ipaProof: IpaProof, + }, + { + typeName: "VerkleProof", + casingMap: { + otherStems: "otherStems", + depthExtensionPresent: "depthExtensionPresent", + commitmentsByPath: "commitmentsByPath", + d: "d", + ipaProof: "ipaProof", + }, + } +); + +export const ExecutionWitness = new ContainerType( + { + stateDiff: StateDiff, + verkleProof: VerkleProof, + parentStateRoot: Root, + }, + {typeName: "ExecutionWitness", casingMap: {stateDiff: "stateDiff", verkleProof: "verkleProof", parentStateRoot: "parentStateRoot"}} +); + +// Beacon Chain types +// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#containers + +export const ExecutionPayload = new ContainerType( + { + ...capellaSsz.ExecutionPayload.fields, + executionWitness: ExecutionWitness, // New in electra + }, + {typeName: "ExecutionPayload", jsonCase: "eth2"} +); + +export const ExecutionPayloadHeader = new ContainerType( + { + ...capellaSsz.ExecutionPayloadHeader.fields, + executionWitnessRoot: Root, // New in electra + }, + {typeName: "ExecutionPayloadHeader", jsonCase: "eth2"} +); + +// We have to preserve Fields ordering while changing the type of ExecutionPayload +export const BeaconBlockBody = new ContainerType( + { + ...altairSsz.BeaconBlockBody.fields, + executionPayload: ExecutionPayload, // Modified in electra + blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, + // blobKzgCommitments: denebSsz.BlobKzgCommitments, + }, + {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const BeaconBlock = new ContainerType( + { + ...capellaSsz.BeaconBlock.fields, + body: BeaconBlockBody, // Modified in electra + }, + {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedBeaconBlock = new ContainerType( + { + message: BeaconBlock, // Modified in electra + signature: BLSSignature, + }, + {typeName: "SignedBeaconBlock", jsonCase: "eth2"} +); + +export const BlindedBeaconBlockBody = new ContainerType( + { + ...altairSsz.BeaconBlockBody.fields, + executionPayloadHeader: ExecutionPayloadHeader, // Modified in electra + blsToExecutionChanges: capellaSsz.BeaconBlockBody.fields.blsToExecutionChanges, + // blobKzgCommitments: denebSsz.BlobKzgCommitments, + }, + {typeName: "BlindedBeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const BlindedBeaconBlock = new ContainerType( + { + ...bellatrixSsz.BlindedBeaconBlock.fields, + body: BlindedBeaconBlockBody, // Modified in DENEB + }, + {typeName: "BlindedBeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedBlindedBeaconBlock = new ContainerType( + { + message: BlindedBeaconBlock, // Modified in DENEB + signature: BLSSignature, + }, + {typeName: "SignedBlindedBeaconBlock", jsonCase: "eth2"} +); + +// We don't spread capella.BeaconState fields since we need to replace +// latestExecutionPayloadHeader and we cannot keep order doing that +export const BeaconState = new ContainerType( + { + genesisTime: UintNum64, + genesisValidatorsRoot: Root, + slot: primitiveSsz.Slot, + fork: phase0Ssz.Fork, + // History + latestBlockHeader: phase0Ssz.BeaconBlockHeader, + blockRoots: phase0Ssz.HistoricalBlockRoots, + stateRoots: phase0Ssz.HistoricalStateRoots, + // historical_roots Frozen in Capella, replaced by historical_summaries + historicalRoots: new ListCompositeType(Root, HISTORICAL_ROOTS_LIMIT), + // Eth1 + eth1Data: phase0Ssz.Eth1Data, + eth1DataVotes: phase0Ssz.Eth1DataVotes, + eth1DepositIndex: UintNum64, + // Registry + validators: phase0Ssz.Validators, + balances: phase0Ssz.Balances, + randaoMixes: phase0Ssz.RandaoMixes, + // Slashings + slashings: phase0Ssz.Slashings, + // Participation + previousEpochParticipation: altairSsz.EpochParticipation, + currentEpochParticipation: altairSsz.EpochParticipation, + // Finality + justificationBits: phase0Ssz.JustificationBits, + previousJustifiedCheckpoint: phase0Ssz.Checkpoint, + currentJustifiedCheckpoint: phase0Ssz.Checkpoint, + finalizedCheckpoint: phase0Ssz.Checkpoint, + // Inactivity + inactivityScores: altairSsz.InactivityScores, + // Sync + currentSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommittee: altairSsz.SyncCommittee, + // Execution + latestExecutionPayloadHeader: ExecutionPayloadHeader, // Modified in electra + // Withdrawals + nextWithdrawalIndex: capellaSsz.BeaconState.fields.nextWithdrawalIndex, + nextWithdrawalValidatorIndex: capellaSsz.BeaconState.fields.nextWithdrawalValidatorIndex, + // Deep history valid from Capella onwards + historicalSummaries: capellaSsz.BeaconState.fields.historicalSummaries, + }, + {typeName: "BeaconState", jsonCase: "eth2"} +); + +export const LightClientHeader = new ContainerType( + { + beacon: phase0Ssz.BeaconBlockHeader, + execution: ExecutionPayloadHeader, + executionBranch: new VectorCompositeType(Bytes32, EXECUTION_PAYLOAD_DEPTH), + }, + {typeName: "LightClientHeader", jsonCase: "eth2"} +); + +export const LightClientBootstrap = new ContainerType( + { + header: LightClientHeader, + currentSyncCommittee: altairSsz.SyncCommittee, + currentSyncCommitteeBranch: altairSsz.LightClientBootstrap.fields.currentSyncCommitteeBranch, + }, + {typeName: "LightClientBootstrap", jsonCase: "eth2"} +); + +export const LightClientUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + nextSyncCommittee: altairSsz.SyncCommittee, + nextSyncCommitteeBranch: altairSsz.LightClientUpdate.fields.nextSyncCommitteeBranch, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientUpdate", jsonCase: "eth2"} +); + +export const LightClientFinalityUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + finalizedHeader: LightClientHeader, + finalityBranch: altairSsz.LightClientFinalityUpdate.fields.finalityBranch, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientFinalityUpdate", jsonCase: "eth2"} +); + +export const LightClientOptimisticUpdate = new ContainerType( + { + attestedHeader: LightClientHeader, + syncAggregate: altairSsz.SyncAggregate, + signatureSlot: Slot, + }, + {typeName: "LightClientOptimisticUpdate", jsonCase: "eth2"} +); + +export const LightClientStore = new ContainerType( + { + snapshot: LightClientBootstrap, + validUpdates: new ListCompositeType(LightClientUpdate, EPOCHS_PER_SYNC_COMMITTEE_PERIOD * SLOTS_PER_EPOCH), + }, + {typeName: "LightClientStore", jsonCase: "eth2"} +); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts new file mode 100644 index 000000000000..6de7613eb47d --- /dev/null +++ b/packages/types/src/electra/types.ts @@ -0,0 +1,29 @@ +import {ValueOf} from "@chainsafe/ssz"; +import * as ssz from "./sszTypes.js"; + +export type Bytes31 = ValueOf; +export type BanderwagonGroupElement = ValueOf; +export type BanderwagonFieldElement = ValueOf; +export type Stem = ValueOf; + +export type SuffixStateDiff = ValueOf; +export type StemStateDiff = ValueOf; +export type StateDiff = ValueOf; +export type IpaProof = ValueOf; +export type VerkleProof = ValueOf; +export type ExecutionWitness = ValueOf; + +export type ExecutionPayload = ValueOf; +export type ExecutionPayloadHeader = ValueOf; + +export type BeaconBlockBody = ValueOf; +export type BeaconBlock = ValueOf; +export type SignedBeaconBlock = ValueOf; + +export type BeaconState = ValueOf; + +export type BlindedBeaconBlockBody = ValueOf; +export type BlindedBeaconBlock = ValueOf; +export type SignedBlindedBeaconBlock = ValueOf; + +export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadHeader; diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index 2a7df948a447..ff3e77ab6947 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -4,6 +4,7 @@ export {ssz as altair} from "./altair/index.js"; export {ssz as bellatrix} from "./bellatrix/index.js"; export {ssz as capella} from "./capella/index.js"; export {ssz as deneb} from "./deneb/index.js"; +export {ssz as electra} from "./electra/index.js"; import {ssz as allForksSsz} from "./allForks/index.js"; export const allForks = allForksSsz.allForks; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index e2e416fa3667..fbd7d5621da0 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -6,6 +6,7 @@ export {ts as altair} from "./altair/index.js"; export {ts as bellatrix} from "./bellatrix/index.js"; export {ts as capella} from "./capella/index.js"; export {ts as deneb} from "./deneb/index.js"; +export {ts as electra} from "./electra/index.js"; export {ts as allForks} from "./allForks/index.js"; diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 006ae3fadbbb..83ba7dbb326f 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -73,6 +73,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record