diff --git a/packages/beacon-node/src/api/impl/config/constants.ts b/packages/beacon-node/src/api/impl/config/constants.ts index e0cd383b4163..6ea436749384 100644 --- a/packages/beacon-node/src/api/impl/config/constants.ts +++ b/packages/beacon-node/src/api/impl/config/constants.ts @@ -26,6 +26,7 @@ import { DOMAIN_BUILDER_DEPOSIT, DOMAIN_CONTRIBUTION_AND_PROOF, DOMAIN_DEPOSIT, + DOMAIN_INCLUSION_LIST_COMMITTEE, DOMAIN_PROPOSER_PREFERENCES, DOMAIN_PTC_ATTESTER, DOMAIN_RANDAO, @@ -148,6 +149,9 @@ export const specConstants = { DOMAIN_BUILDER_DEPOSIT, BUILDER_DEPOSIT_REQUEST_TYPE: toHexByte(BUILDER_DEPOSIT_REQUEST_TYPE), BUILDER_EXIT_REQUEST_TYPE: toHexByte(BUILDER_EXIT_REQUEST_TYPE), + + // heze + DOMAIN_INCLUSION_LIST_COMMITTEE, }; /** Convert single-byte numbers to hex strings for API spec compliance */ diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 25cea68f1d3b..eebc71b8ec8f 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -49,6 +49,7 @@ import { electra, fulu, gloas, + heze, ssz, } from "@lodestar/types"; import {GWEI_TO_WEI, Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; @@ -927,6 +928,11 @@ function preparePayloadAttributes( ); } + if (ForkSeq[fork] >= ForkSeq.heze) { + // TODO HEZE: populate from inclusion list pool once IL aggregation is wired up. + (payloadAttributes as heze.SSEPayloadAttributes["payloadAttributes"]).inclusionListTransactions = []; + } + return payloadAttributes; } diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index 2ad9b5173a65..bd252f331a8e 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -7,6 +7,7 @@ import { isForkPostAltair, isForkPostElectra, isForkPostFulu, + isForkPostGloas, } from "@lodestar/params"; import {Attestation, SingleAttestation, ssz, sszTypesFor} from "@lodestar/types"; import {GossipAction, GossipActionError, GossipErrorCode} from "../../chain/errors/gossipValidation.js"; @@ -124,7 +125,7 @@ export function getGossipSSZType(topic: GossipTopic) { case GossipType.payload_attestation_message: return ssz.gloas.PayloadAttestationMessage; case GossipType.execution_payload_bid: - return ssz.gloas.SignedExecutionPayloadBid; + return isForkPostGloas(fork) ? sszTypesFor(fork).SignedExecutionPayloadBid : ssz.gloas.SignedExecutionPayloadBid; case GossipType.proposer_preferences: return ssz.gloas.SignedProposerPreferences; } diff --git a/packages/beacon-node/test/spec/presets/fork.test.ts b/packages/beacon-node/test/spec/presets/fork.test.ts index fcb9a6efad42..bf9b4c258c49 100644 --- a/packages/beacon-node/test/spec/presets/fork.test.ts +++ b/packages/beacon-node/test/spec/presets/fork.test.ts @@ -9,6 +9,7 @@ import { CachedBeaconStateDeneb, CachedBeaconStateElectra, CachedBeaconStateFulu, + CachedBeaconStateGloas, CachedBeaconStatePhase0, } from "@lodestar/state-transition"; import * as slotFns from "@lodestar/state-transition/slot"; @@ -44,6 +45,8 @@ const fork: TestRunnerFn = (forkNext) => { return slotFns.upgradeStateToFulu(preState as CachedBeaconStateElectra); case ForkName.gloas: return slotFns.upgradeStateToGloas(preState as CachedBeaconStateFulu); + case ForkName.heze: + return slotFns.upgradeStateToHeze(preState as CachedBeaconStateGloas); } }, options: { diff --git a/packages/beacon-node/test/spec/presets/fork_choice.test.ts b/packages/beacon-node/test/spec/presets/fork_choice.test.ts index bdc72a6b4e61..4e6e5689742b 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -735,7 +735,7 @@ const forkChoiceTest = shouldSkip: (_testcase, name, _index) => name.includes("invalid_incorrect_proof") || // TODO GLOAS: These tests will be unskipped by https://github.com/ChainSafe/lodestar/pull/9233 - (name.includes("gloas") && + ((name.includes("gloas") || name.includes("heze")) && (name.includes("simple_attempted_reorg_without_enough_ffg_votes") || name.includes("include_votes_another_empty_chain_with_enough_ffg_votes_current_epoch") || name.includes("include_votes_another_empty_chain_with_enough_ffg_votes_previous_epoch") || diff --git a/packages/beacon-node/test/spec/presets/transition.test.ts b/packages/beacon-node/test/spec/presets/transition.test.ts index ea411ede2b0a..220f07929e8a 100644 --- a/packages/beacon-node/test/spec/presets/transition.test.ts +++ b/packages/beacon-node/test/spec/presets/transition.test.ts @@ -127,6 +127,17 @@ function getTransitionConfig(fork: ForkName, forkEpoch: number): Partial = { @@ -33,6 +35,7 @@ const slots: Record = { electra: computeStartSlotAtEpoch(ELECTRA_FORK_EPOCH), fulu: computeStartSlotAtEpoch(FULU_FORK_EPOCH), gloas: computeStartSlotAtEpoch(GLOAS_FORK_EPOCH), + heze: computeStartSlotAtEpoch(HEZE_FORK_EPOCH), }; type BlockTestSet = { diff --git a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts index a455f97c50ef..850ea882433f 100644 --- a/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts +++ b/packages/beacon-node/test/unit/chain/lightclient/upgradeLightClientHeader.test.ts @@ -17,6 +17,7 @@ describe("UpgradeLightClientHeader", () => { ELECTRA_FORK_EPOCH: 5, FULU_FORK_EPOCH: 6, GLOAS_FORK_EPOCH: 7, + HEZE_FORK_EPOCH: 8, }); const genesisValidatorsRoot = Buffer.alloc(32, 0xaa); @@ -32,6 +33,7 @@ describe("UpgradeLightClientHeader", () => { electra: ssz.deneb.LightClientHeader.defaultValue(), fulu: ssz.deneb.LightClientHeader.defaultValue(), gloas: ssz.deneb.LightClientHeader.defaultValue(), + heze: ssz.deneb.LightClientHeader.defaultValue(), }; testSlots = { @@ -43,6 +45,7 @@ describe("UpgradeLightClientHeader", () => { electra: 164, fulu: 216, gloas: 235, + heze: 260, }; }); diff --git a/packages/beacon-node/test/unit/network/fork.test.ts b/packages/beacon-node/test/unit/network/fork.test.ts index 3c995e0f38c5..471046c62ca9 100644 --- a/packages/beacon-node/test/unit/network/fork.test.ts +++ b/packages/beacon-node/test/unit/network/fork.test.ts @@ -12,6 +12,7 @@ function getForkConfig({ electra, fulu, gloas, + heze, }: { phase0: number; altair: number; @@ -21,6 +22,7 @@ function getForkConfig({ electra: number; fulu: number; gloas: number; + heze: number; }): BeaconConfig { const forks: Record = { phase0: { @@ -87,6 +89,14 @@ function getForkConfig({ prevVersion: Buffer.from([0, 0, 0, 6]), prevForkName: ForkName.fulu, }, + heze: { + name: ForkName.heze, + seq: ForkSeq.heze, + epoch: heze, + version: Buffer.from([0, 0, 0, 8]), + prevVersion: Buffer.from([0, 0, 0, 7]), + prevForkName: ForkName.gloas, + }, }; const forksAscendingEpochOrder = Object.values(forks); const forksDescendingEpochOrder = Object.values(forks).reverse(); @@ -171,9 +181,10 @@ for (const testScenario of testScenarios) { const electra = Infinity; const fulu = Infinity; const gloas = Infinity; + const heze = Infinity; describe(`network / fork: phase0: ${phase0}, altair: ${altair}, bellatrix: ${bellatrix} capella: ${capella}`, () => { - const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb, electra, fulu, gloas}); + const forkConfig = getForkConfig({phase0, altair, bellatrix, capella, deneb, electra, fulu, gloas, heze}); const forks = forkConfig.forks; for (const testCase of testCases) { const {epoch, currentFork, nextFork, activeForks} = testCase; diff --git a/packages/beacon-node/test/utils/blocksAndData.ts b/packages/beacon-node/test/utils/blocksAndData.ts index 3f23535e46a8..8a55ddcfe566 100644 --- a/packages/beacon-node/test/utils/blocksAndData.ts +++ b/packages/beacon-node/test/utils/blocksAndData.ts @@ -36,6 +36,7 @@ export const DENEB_FORK_EPOCH = 10; export const ELECTRA_FORK_EPOCH = 20; export const FULU_FORK_EPOCH = 30; export const GLOAS_FORK_EPOCH = 40; +export const HEZE_FORK_EPOCH = 50; export const config = createChainForkConfig({ ...defaultChainConfig, CAPELLA_FORK_EPOCH, @@ -43,6 +44,7 @@ export const config = createChainForkConfig({ ELECTRA_FORK_EPOCH, FULU_FORK_EPOCH, GLOAS_FORK_EPOCH, + HEZE_FORK_EPOCH, }); export const clock = new Clock({ config, @@ -60,6 +62,7 @@ export const slots: Record = { electra: computeStartSlotAtEpoch(ELECTRA_FORK_EPOCH), fulu: computeStartSlotAtEpoch(FULU_FORK_EPOCH), gloas: computeStartSlotAtEpoch(GLOAS_FORK_EPOCH), + heze: computeStartSlotAtEpoch(HEZE_FORK_EPOCH), }; /** diff --git a/packages/config/src/chainConfig/configs/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts index 6025cb88431d..161a54a7b7f9 100644 --- a/packages/config/src/chainConfig/configs/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -60,6 +60,10 @@ export const chainConfig: ChainConfig = { GLOAS_FORK_VERSION: b("0x07000000"), GLOAS_FORK_EPOCH: Infinity, + // HEZE + HEZE_FORK_VERSION: b("0x08000000"), + HEZE_FORK_EPOCH: Infinity, + // Time parameters // --------------------------------------------------------------- // 12 seconds (DEPRECATED) @@ -76,6 +80,9 @@ export const chainConfig: ChainConfig = { SHARD_COMMITTEE_PERIOD: 256, // 2**11 (= 2,048) Eth1 blocks ~8 hours ETH1_FOLLOW_DISTANCE: 2048, + + // 67% of `SLOT_DURATION_MS` + INCLUSION_LIST_DUE_BPS: 6667, // 1667 basis points, ~17% of SLOT_DURATION_MS PROPOSER_REORG_CUTOFF_BPS: 1667, // 3333 basis points, ~33% of SLOT_DURATION_MS @@ -190,6 +197,14 @@ export const chainConfig: ChainConfig = { // `2**12` (= 4096 epochs, ~18 days) MIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTS: 4096, + // HEZE + // 2**4 (= 16) + MAX_REQUEST_INCLUSION_LIST: 16, + // 2**13 (=8192) + MAX_BYTES_PER_INCLUSION_LIST: 8192, + // 2**4 (= 16) + INCLUSION_LIST_COMMITTEE_SIZE: 16, + // Gloas // 2**7 (= 128) payloads MAX_REQUEST_PAYLOADS: 128, diff --git a/packages/config/src/chainConfig/configs/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts index ed9a3a8e22c1..9c2328dc7385 100644 --- a/packages/config/src/chainConfig/configs/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -53,6 +53,9 @@ export const chainConfig: ChainConfig = { // GLOAS GLOAS_FORK_VERSION: b("0x07000001"), GLOAS_FORK_EPOCH: Infinity, + // HEZE + HEZE_FORK_VERSION: b("0x08000001"), + HEZE_FORK_EPOCH: Infinity, // Time parameters // --------------------------------------------------------------- @@ -70,6 +73,8 @@ export const chainConfig: ChainConfig = { SHARD_COMMITTEE_PERIOD: 64, // [customized] process deposits more quickly, but insecure ETH1_FOLLOW_DISTANCE: 16, + // 67% of `SLOT_DURATION_MS` + INCLUSION_LIST_DUE_BPS: 6667, // 1667 basis points, ~17% of SLOT_DURATION_MS PROPOSER_REORG_CUTOFF_BPS: 1667, // 3333 basis points, ~33% of SLOT_DURATION_MS @@ -193,6 +198,14 @@ export const chainConfig: ChainConfig = { // --------------------------------------------------------------- BLOB_SCHEDULE: [], + // HEZE + // 2**4 (= 16) + MAX_REQUEST_INCLUSION_LIST: 16, + // 2**13 (=8192) + MAX_BYTES_PER_INCLUSION_LIST: 8192, + // 2**4 (= 16) + INCLUSION_LIST_COMMITTEE_SIZE: 16, + // Fast Confirmation Rule // --------------------------------------------------------------- CONFIRMATION_BYZANTINE_THRESHOLD: 25, diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index e24135154daa..5f3040e185bd 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -50,6 +50,9 @@ export type ChainConfig = { // GLOAS GLOAS_FORK_VERSION: Uint8Array; GLOAS_FORK_EPOCH: number; + // HEZE + HEZE_FORK_VERSION: Uint8Array; + HEZE_FORK_EPOCH: number; // Time parameters /** @deprecated Use `SLOT_DURATION_MS` instead. */ @@ -74,6 +77,8 @@ export type ChainConfig = { PAYLOAD_ATTESTATION_DUE_BPS: number; PAYLOAD_DUE_BPS: number; + INCLUSION_LIST_DUE_BPS: number; + // Validator cycle INACTIVITY_SCORE_BIAS: number; INACTIVITY_SCORE_RECOVERY_RATE: number; @@ -133,6 +138,11 @@ export type ChainConfig = { // Blob Scheduling BLOB_SCHEDULE: BlobSchedule; + // HEZE + MAX_REQUEST_INCLUSION_LIST: number; + MAX_BYTES_PER_INCLUSION_LIST: number; + INCLUSION_LIST_COMMITTEE_SIZE: number; + // Fast Confirmation Rule CONFIRMATION_BYZANTINE_THRESHOLD: number; }; @@ -174,6 +184,9 @@ export const chainConfigTypes: SpecTypes = { // GLOAS GLOAS_FORK_VERSION: "bytes", GLOAS_FORK_EPOCH: "number", + // HEZE (EIP-7805) + HEZE_FORK_VERSION: "bytes", + HEZE_FORK_EPOCH: "number", // Time parameters SECONDS_PER_SLOT: "number", @@ -197,6 +210,8 @@ export const chainConfigTypes: SpecTypes = { PAYLOAD_ATTESTATION_DUE_BPS: "number", PAYLOAD_DUE_BPS: "number", + INCLUSION_LIST_DUE_BPS: "number", + // Validator cycle INACTIVITY_SCORE_BIAS: "number", INACTIVITY_SCORE_RECOVERY_RATE: "number", @@ -250,6 +265,11 @@ export const chainConfigTypes: SpecTypes = { VALIDATOR_CUSTODY_REQUIREMENT: "number", BALANCE_PER_ADDITIONAL_CUSTODY_GROUP: "number", + // HEZE + MAX_REQUEST_INCLUSION_LIST: "number", + MAX_BYTES_PER_INCLUSION_LIST: "number", + INCLUSION_LIST_COMMITTEE_SIZE: "number", + // Gloas MAX_REQUEST_PAYLOADS: "number", diff --git a/packages/config/src/forkConfig/index.ts b/packages/config/src/forkConfig/index.ts index 47bd518a3f55..0dd3f8a6e9d9 100644 --- a/packages/config/src/forkConfig/index.ts +++ b/packages/config/src/forkConfig/index.ts @@ -85,10 +85,18 @@ export function createForkConfig(config: ChainConfig): ForkConfig { prevVersion: config.FULU_FORK_VERSION, prevForkName: ForkName.fulu, }; + const heze: ForkInfo = { + name: ForkName.heze, + seq: ForkSeq.heze, + epoch: config.HEZE_FORK_EPOCH, + version: config.HEZE_FORK_VERSION, + prevVersion: config.GLOAS_FORK_VERSION, + prevForkName: ForkName.gloas, + }; /** Forks in order order of occurence, `phase0` first */ // Note: Downstream code relies on proper ordering. - const forks = {phase0, altair, bellatrix, capella, deneb, electra, fulu, gloas}; + const forks = {phase0, altair, bellatrix, capella, deneb, electra, fulu, gloas, heze}; // Prevents allocating an array on every getForkInfo() call const forksAscendingEpochOrder = Object.values(forks); diff --git a/packages/config/src/testUtils/config.ts b/packages/config/src/testUtils/config.ts index a3768bb9adf4..8ee0d16d0ccd 100644 --- a/packages/config/src/testUtils/config.ts +++ b/packages/config/src/testUtils/config.ts @@ -60,5 +60,17 @@ export function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { GLOAS_FORK_EPOCH: forkEpoch, BLOB_SCHEDULE: [], }); + case ForkName.heze: + return createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, + FULU_FORK_EPOCH: 0, + GLOAS_FORK_EPOCH: 0, + HEZE_FORK_EPOCH: forkEpoch, + BLOB_SCHEDULE: [], + }); } } diff --git a/packages/config/test/e2e/ensure-config-is-synced.test.ts b/packages/config/test/e2e/ensure-config-is-synced.test.ts index 946b4e7456eb..0df11b628faf 100644 --- a/packages/config/test/e2e/ensure-config-is-synced.test.ts +++ b/packages/config/test/e2e/ensure-config-is-synced.test.ts @@ -15,13 +15,6 @@ import specTestsVersions from "../spec-tests-version.json" with {type: "json"}; const ignoredRemoteConfigFields: (keyof ChainConfig)[] = [ // BLOB_SCHEDULE is an array/JSON format that requires special parsing "BLOB_SCHEDULE" as keyof ChainConfig, - // EIP-7805 (Inclusion Lists) - not yet implemented in Lodestar - "VIEW_FREEZE_CUTOFF_BPS" as keyof ChainConfig, - "INCLUSION_LIST_SUBMISSION_DUE_BPS" as keyof ChainConfig, - "INCLUSION_LIST_DUE_BPS" as keyof ChainConfig, - "PROPOSER_INCLUSION_LIST_CUTOFF_BPS" as keyof ChainConfig, - "MAX_REQUEST_INCLUSION_LIST" as keyof ChainConfig, - "MAX_BYTES_PER_INCLUSION_LIST" as keyof ChainConfig, // Networking params that may be in presets instead of chainConfig "ATTESTATION_SUBNET_COUNT" as keyof ChainConfig, "ATTESTATION_SUBNET_EXTRA_BITS" as keyof ChainConfig, @@ -30,8 +23,6 @@ const ignoredRemoteConfigFields: (keyof ChainConfig)[] = [ "EPOCHS_PER_SHUFFLING_PHASE" as keyof ChainConfig, "PROPOSER_SELECTION_GAP" as keyof ChainConfig, // Future forks not yet implemented in Lodestar - "HEZE_FORK_VERSION" as keyof ChainConfig, - "HEZE_FORK_EPOCH" as keyof ChainConfig, "EIP7928_FORK_VERSION" as keyof ChainConfig, "EIP7928_FORK_EPOCH" as keyof ChainConfig, "EIP8025_FORK_VERSION" as keyof ChainConfig, @@ -45,6 +36,7 @@ const ignoredRemoteConfigFields: (keyof ChainConfig)[] = [ "ELECTRA_FORK_EPOCH", "FULU_FORK_EPOCH", "GLOAS_FORK_EPOCH", + "HEZE_FORK_EPOCH", // Terminal values are network-specific "TERMINAL_TOTAL_DIFFICULTY", "TERMINAL_BLOCK_HASH", diff --git a/packages/params/src/forkName.ts b/packages/params/src/forkName.ts index 439f4f0aa137..e7cca2f75764 100644 --- a/packages/params/src/forkName.ts +++ b/packages/params/src/forkName.ts @@ -10,6 +10,7 @@ export enum ForkName { electra = "electra", fulu = "fulu", gloas = "gloas", + heze = "heze", } /** @@ -24,6 +25,7 @@ export enum ForkSeq { electra = 5, fulu = 6, gloas = 7, + heze = 8, } function exclude(coll: T[], val: U[]): Exclude[] { @@ -127,6 +129,22 @@ export function isForkPostGloas(fork: ForkName): fork is ForkPostGloas { return isForkPostFulu(fork) && fork !== ForkName.fulu; } +export type ForkPreHeze = ForkPreGloas | ForkName.gloas; +export type ForkPostHeze = Exclude; +export const forkPostHeze = exclude(forkAll, [ + ForkName.phase0, + ForkName.altair, + ForkName.bellatrix, + ForkName.capella, + ForkName.deneb, + ForkName.electra, + ForkName.fulu, + ForkName.gloas, +]); +export function isForkPostHeze(fork: ForkName): fork is ForkPostHeze { + return isForkPostGloas(fork) && fork !== ForkName.gloas; +} + /* * Aliases only exported for backwards compatibility. This will be removed in * lodestar v2.0. The types and guards above should be used in all places as diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 2e54b5d7ac6a..00ff475e8b1e 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -168,6 +168,7 @@ export const DOMAIN_BEACON_BUILDER = Uint8Array.from([11, 0, 0, 0]); export const DOMAIN_PTC_ATTESTER = Uint8Array.from([12, 0, 0, 0]); export const DOMAIN_PROPOSER_PREFERENCES = Uint8Array.from([13, 0, 0, 0]); export const DOMAIN_BUILDER_DEPOSIT = Uint8Array.from([14, 0, 0, 0]); +export const DOMAIN_INCLUSION_LIST_COMMITTEE = Uint8Array.from([16, 0, 0, 0]); // Application specific domains @@ -328,3 +329,6 @@ export const BUILDER_PAYMENT_THRESHOLD_NUMERATOR = 6; export const BUILDER_PAYMENT_THRESHOLD_DENOMINATOR = 10; export const BUILDER_DEPOSIT_REQUEST_TYPE = 0x03; export const BUILDER_EXIT_REQUEST_TYPE = 0x04; + +// HEZE +export const INCLUSION_LIST_COMMITTEE_SIZE = 16; diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 2cdd35d1d270..aba80c1cbb7b 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -150,4 +150,7 @@ export const mainnetPreset: BeaconPreset = { BUILDER_REGISTRY_LIMIT: 1099511627776, // 2**40 BUILDER_PENDING_WITHDRAWALS_LIMIT: 1048576, // 2**20 MAX_BUILDERS_PER_WITHDRAWALS_SWEEP: 16384, // 2**14 + + // HEZE + INCLUSION_LIST_COMMITTEE_SIZE: 16, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 7e5d50fa4161..70cc692474bf 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -151,4 +151,7 @@ export const minimalPreset: BeaconPreset = { BUILDER_REGISTRY_LIMIT: 1099511627776, // 2**40 BUILDER_PENDING_WITHDRAWALS_LIMIT: 1048576, // 2**20 MAX_BUILDERS_PER_WITHDRAWALS_SWEEP: 16, // 2**4 + + // HEZE + INCLUSION_LIST_COMMITTEE_SIZE: 16, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 9889020b3f27..746a7c3e84ee 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -112,6 +112,9 @@ export type BeaconPreset = { BUILDER_REGISTRY_LIMIT: number; BUILDER_PENDING_WITHDRAWALS_LIMIT: number; MAX_BUILDERS_PER_WITHDRAWALS_SWEEP: number; + + // HEZE + INCLUSION_LIST_COMMITTEE_SIZE: number; }; /** @@ -229,6 +232,9 @@ export const beaconPresetTypes: BeaconPresetTypes = { BUILDER_REGISTRY_LIMIT: "number", BUILDER_PENDING_WITHDRAWALS_LIMIT: "number", MAX_BUILDERS_PER_WITHDRAWALS_SWEEP: "number", + + // HEZE + INCLUSION_LIST_COMMITTEE_SIZE: "number", }; type BeaconPresetTypes = { diff --git a/packages/params/test/unit/__snapshots__/forkName.test.ts.snap b/packages/params/test/unit/__snapshots__/forkName.test.ts.snap index 4991cf14f722..ce7035e9c447 100644 --- a/packages/params/test/unit/__snapshots__/forkName.test.ts.snap +++ b/packages/params/test/unit/__snapshots__/forkName.test.ts.snap @@ -10,6 +10,7 @@ exports[`forkName > should have valid allForks 1`] = ` "electra", "fulu", "gloas", + "heze", ] `; @@ -22,6 +23,7 @@ exports[`forkName > should have valid post-altair forks 1`] = ` "electra", "fulu", "gloas", + "heze", ] `; @@ -33,6 +35,7 @@ exports[`forkName > should have valid post-bellatrix forks 1`] = ` "electra", "fulu", "gloas", + "heze", ] `; @@ -43,6 +46,7 @@ exports[`forkName > should have valid post-capella forks 1`] = ` "electra", "fulu", "gloas", + "heze", ] `; @@ -52,5 +56,6 @@ exports[`forkName > should have valid post-deneb forks 1`] = ` "electra", "fulu", "gloas", + "heze", ] `; diff --git a/packages/state-transition/src/block/processExecutionPayloadBid.ts b/packages/state-transition/src/block/processExecutionPayloadBid.ts index 2ccf86c536ea..9ecb8a8284de 100644 --- a/packages/state-transition/src/block/processExecutionPayloadBid.ts +++ b/packages/state-transition/src/block/processExecutionPayloadBid.ts @@ -1,15 +1,21 @@ import {PublicKey, Signature, verify} from "@chainsafe/blst"; -import {BUILDER_INDEX_SELF_BUILD, GENESIS_SLOT, PAYLOAD_BUILDER_VERSION, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {gloas, ssz} from "@lodestar/types"; +import { + BUILDER_INDEX_SELF_BUILD, + ForkSeq, + GENESIS_SLOT, + PAYLOAD_BUILDER_VERSION, + SLOTS_PER_EPOCH, +} from "@lodestar/params"; +import {gloas, heze, ssz} from "@lodestar/types"; import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils"; import {G2_POINT_AT_INFINITY} from "../constants/constants.js"; import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js"; -import {CachedBeaconStateGloas} from "../types.js"; +import {CachedBeaconStateGloas, CachedBeaconStateHeze} from "../types.js"; import {canBuilderCoverBid, isActiveBuilder} from "../util/gloas.js"; import {getBlockRootAtSlot, getCurrentEpoch, getRandaoMix} from "../util/index.js"; export function processExecutionPayloadBid( - state: CachedBeaconStateGloas, + state: CachedBeaconStateGloas | CachedBeaconStateHeze, signedBid: gloas.SignedExecutionPayloadBid ): void { const bid = signedBid.message; @@ -41,7 +47,7 @@ export function processExecutionPayloadBid( } // Verify that the builder has funds to cover the bid - if (!canBuilderCoverBid(state, builderIndex, amount)) { + if (!canBuilderCoverBid(state as CachedBeaconStateGloas, builderIndex, amount)) { throw Error(`Invalid execution payload bid: builder ${builderIndex} has insufficient balance`); } @@ -99,11 +105,17 @@ export function processExecutionPayloadBid( state.builderPendingPayments.set(SLOTS_PER_EPOCH + (bid.slot % SLOTS_PER_EPOCH), pendingPaymentView); } - state.latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid); + if (state.config.getForkSeq(state.slot) >= ForkSeq.heze) { + (state as CachedBeaconStateHeze).latestExecutionPayloadBid = ssz.heze.ExecutionPayloadBid.toViewDU( + bid as heze.ExecutionPayloadBid + ); + } else { + (state as CachedBeaconStateGloas).latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid); + } } function verifyExecutionPayloadBidSignature( - state: CachedBeaconStateGloas, + state: CachedBeaconStateGloas | CachedBeaconStateHeze, pubkey: Uint8Array, signedBid: gloas.SignedExecutionPayloadBid ): boolean { diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index 6054001a6027..020ca8cd994e 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -12,6 +12,7 @@ import { BeaconStateExecutions, BeaconStateFulu, BeaconStateGloas, + BeaconStateHeze, BeaconStatePhase0, } from "./types.js"; @@ -136,6 +137,7 @@ export type CachedBeaconStateDeneb = CachedBeaconState; export type CachedBeaconStateElectra = CachedBeaconState; export type CachedBeaconStateFulu = CachedBeaconState; export type CachedBeaconStateGloas = CachedBeaconState; +export type CachedBeaconStateHeze = 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 9a73c5b7e99f..2f01e0d73126 100644 --- a/packages/state-transition/src/cache/types.ts +++ b/packages/state-transition/src/cache/types.ts @@ -11,6 +11,7 @@ export type BeaconStateDeneb = CompositeViewDU>; export type BeaconStateFulu = CompositeViewDU>; export type BeaconStateGloas = CompositeViewDU>; +export type BeaconStateHeze = CompositeViewDU>; export type BeaconStateAllForks = CompositeViewDU>; export type BeaconStateExecutions = CompositeViewDU>; diff --git a/packages/state-transition/src/index.ts b/packages/state-transition/src/index.ts index 5fd6b6be2316..0525ae4b61a3 100644 --- a/packages/state-transition/src/index.ts +++ b/packages/state-transition/src/index.ts @@ -52,6 +52,7 @@ export { type IBeaconStateViewElectra, type IBeaconStateViewFulu, type IBeaconStateViewGloas, + type IBeaconStateViewHeze, isStatePostAltair, isStatePostBellatrix, isStatePostCapella, @@ -59,6 +60,7 @@ export { isStatePostElectra, isStatePostFulu, isStatePostGloas, + isStatePostHeze, } from "./stateView/interface.js"; export {createBeaconStateView, createBeaconStateViewForHistoricalRegen} from "./stateView/stateViewFactory.js"; export type { @@ -71,6 +73,7 @@ export type { BeaconStateExecutions, BeaconStateFulu, BeaconStateGloas, + BeaconStateHeze, // Non-cached states BeaconStatePhase0, CachedBeaconStateAllForks, @@ -82,6 +85,7 @@ export type { CachedBeaconStateExecutions, CachedBeaconStateFulu, CachedBeaconStateGloas, + CachedBeaconStateHeze, CachedBeaconStatePhase0, } from "./types.js"; export * from "./util/index.js"; diff --git a/packages/state-transition/src/lightClient/spec/utils.ts b/packages/state-transition/src/lightClient/spec/utils.ts index a571614e2e2e..ab7656e0fd7e 100644 --- a/packages/state-transition/src/lightClient/spec/utils.ts +++ b/packages/state-transition/src/lightClient/spec/utils.ts @@ -197,11 +197,18 @@ export function upgradeLightClientHeader( // Break if no further upgrades is required else fall through if (ForkSeq[targetFork] <= ForkSeq.fulu) break; + // biome-ignore lint/suspicious/noFallthroughSwitchClause: We need fall-through behavior here case ForkName.gloas: // No changes to LightClientHeader in Gloas // Break if no further upgrades is required else fall through if (ForkSeq[targetFork] <= ForkSeq.gloas) break; + + case ForkName.heze: + // No changes to LightClientHeader in Heze + + // Break if no further upgrades is required else fall through + if (ForkSeq[targetFork] <= ForkSeq.heze) break; } return upgradedHeader; } diff --git a/packages/state-transition/src/signatureSets/executionPayloadBid.ts b/packages/state-transition/src/signatureSets/executionPayloadBid.ts index cebad9261b8e..76f80b017296 100644 --- a/packages/state-transition/src/signatureSets/executionPayloadBid.ts +++ b/packages/state-transition/src/signatureSets/executionPayloadBid.ts @@ -1,14 +1,16 @@ import {BeaconConfig} from "@lodestar/config"; -import {DOMAIN_BEACON_BUILDER} from "@lodestar/params"; -import {Slot, gloas, ssz} from "@lodestar/types"; +import {DOMAIN_BEACON_BUILDER, ForkSeq} from "@lodestar/params"; +import {ExecutionPayloadBid, Slot, ssz} from "@lodestar/types"; import {computeSigningRoot} from "../util/index.js"; export function getExecutionPayloadBidSigningRoot( config: BeaconConfig, stateSlot: Slot, - bid: gloas.ExecutionPayloadBid + bid: ExecutionPayloadBid ): Uint8Array { const domain = config.getDomain(stateSlot, DOMAIN_BEACON_BUILDER); + const sszType = + config.getForkSeq(stateSlot) >= ForkSeq.heze ? ssz.heze.ExecutionPayloadBid : ssz.gloas.ExecutionPayloadBid; - return computeSigningRoot(ssz.gloas.ExecutionPayloadBid, bid, domain); + return computeSigningRoot(sszType, bid, domain); } diff --git a/packages/state-transition/src/slot/index.ts b/packages/state-transition/src/slot/index.ts index e373343fda3c..4022590901d3 100644 --- a/packages/state-transition/src/slot/index.ts +++ b/packages/state-transition/src/slot/index.ts @@ -10,6 +10,7 @@ export {upgradeStateToDeneb} from "./upgradeStateToDeneb.js"; export {upgradeStateToElectra} from "./upgradeStateToElectra.js"; export {upgradeStateToFulu} from "./upgradeStateToFulu.js"; export {upgradeStateToGloas} from "./upgradeStateToGloas.js"; +export {upgradeStateToHeze} from "./upgradeStateToHeze.js"; /** * Dial state to next slot. Common for all forks diff --git a/packages/state-transition/src/slot/upgradeStateToHeze.ts b/packages/state-transition/src/slot/upgradeStateToHeze.ts new file mode 100644 index 000000000000..412efe625aa0 --- /dev/null +++ b/packages/state-transition/src/slot/upgradeStateToHeze.ts @@ -0,0 +1,91 @@ +import {ssz} from "@lodestar/types"; +import {getCachedBeaconState} from "../cache/stateCache.js"; +import {CachedBeaconStateGloas, CachedBeaconStateHeze} from "../types.js"; + +/** + * Upgrade a state from Gloas to Heze. + * Spec: heze/fork.md `upgrade_to_heze`. + */ +export function upgradeStateToHeze(stateGloas: CachedBeaconStateGloas): CachedBeaconStateHeze { + const {config} = stateGloas; + + ssz.gloas.BeaconState.commitViewDU(stateGloas); + const stateHezeCloned = stateGloas; + + const stateHezeView = ssz.heze.BeaconState.defaultViewDU(); + + stateHezeView.genesisTime = stateHezeCloned.genesisTime; + stateHezeView.genesisValidatorsRoot = stateHezeCloned.genesisValidatorsRoot; + stateHezeView.slot = stateHezeCloned.slot; + stateHezeView.fork = ssz.phase0.Fork.toViewDU({ + previousVersion: stateGloas.fork.currentVersion, + currentVersion: config.HEZE_FORK_VERSION, + epoch: stateGloas.epochCtx.epoch, + }); + stateHezeView.latestBlockHeader = stateHezeCloned.latestBlockHeader; + stateHezeView.blockRoots = stateHezeCloned.blockRoots; + stateHezeView.stateRoots = stateHezeCloned.stateRoots; + stateHezeView.historicalRoots = stateHezeCloned.historicalRoots; + stateHezeView.eth1Data = stateHezeCloned.eth1Data; + stateHezeView.eth1DataVotes = stateHezeCloned.eth1DataVotes; + stateHezeView.eth1DepositIndex = stateHezeCloned.eth1DepositIndex; + stateHezeView.validators = stateHezeCloned.validators; + stateHezeView.balances = stateHezeCloned.balances; + stateHezeView.randaoMixes = stateHezeCloned.randaoMixes; + stateHezeView.slashings = stateHezeCloned.slashings; + stateHezeView.previousEpochParticipation = stateHezeCloned.previousEpochParticipation; + stateHezeView.currentEpochParticipation = stateHezeCloned.currentEpochParticipation; + stateHezeView.justificationBits = stateHezeCloned.justificationBits; + stateHezeView.previousJustifiedCheckpoint = stateHezeCloned.previousJustifiedCheckpoint; + stateHezeView.currentJustifiedCheckpoint = stateHezeCloned.currentJustifiedCheckpoint; + stateHezeView.finalizedCheckpoint = stateHezeCloned.finalizedCheckpoint; + stateHezeView.inactivityScores = stateHezeCloned.inactivityScores; + stateHezeView.currentSyncCommittee = stateHezeCloned.currentSyncCommittee; + stateHezeView.nextSyncCommittee = stateHezeCloned.nextSyncCommittee; + stateHezeView.latestBlockHash = stateHezeCloned.latestBlockHash; + stateHezeView.nextWithdrawalIndex = stateHezeCloned.nextWithdrawalIndex; + stateHezeView.nextWithdrawalValidatorIndex = stateHezeCloned.nextWithdrawalValidatorIndex; + stateHezeView.historicalSummaries = stateHezeCloned.historicalSummaries; + stateHezeView.depositRequestsStartIndex = stateHezeCloned.depositRequestsStartIndex; + stateHezeView.depositBalanceToConsume = stateHezeCloned.depositBalanceToConsume; + stateHezeView.exitBalanceToConsume = stateHezeCloned.exitBalanceToConsume; + stateHezeView.earliestExitEpoch = stateHezeCloned.earliestExitEpoch; + stateHezeView.consolidationBalanceToConsume = stateHezeCloned.consolidationBalanceToConsume; + stateHezeView.earliestConsolidationEpoch = stateHezeCloned.earliestConsolidationEpoch; + stateHezeView.pendingDeposits = stateHezeCloned.pendingDeposits; + stateHezeView.pendingPartialWithdrawals = stateHezeCloned.pendingPartialWithdrawals; + stateHezeView.pendingConsolidations = stateHezeCloned.pendingConsolidations; + stateHezeView.proposerLookahead = stateHezeCloned.proposerLookahead; + stateHezeView.builders = stateHezeCloned.builders; + stateHezeView.nextWithdrawalBuilderIndex = stateHezeCloned.nextWithdrawalBuilderIndex; + stateHezeView.executionPayloadAvailability = stateHezeCloned.executionPayloadAvailability; + stateHezeView.builderPendingPayments = stateHezeCloned.builderPendingPayments; + stateHezeView.builderPendingWithdrawals = stateHezeCloned.builderPendingWithdrawals; + + // [Modified in Heze:EIP7805] inclusion_list_bits = Bitvector[INCLUSION_LIST_COMMITTEE_SIZE]() (default zero) + const oldBid = stateHezeCloned.latestExecutionPayloadBid; + const newBid = ssz.heze.ExecutionPayloadBid.defaultViewDU(); + newBid.parentBlockHash = oldBid.parentBlockHash; + newBid.parentBlockRoot = oldBid.parentBlockRoot; + newBid.blockHash = oldBid.blockHash; + newBid.prevRandao = oldBid.prevRandao; + newBid.feeRecipient = oldBid.feeRecipient; + newBid.gasLimit = oldBid.gasLimit; + newBid.builderIndex = oldBid.builderIndex; + newBid.slot = oldBid.slot; + newBid.value = oldBid.value; + newBid.executionPayment = oldBid.executionPayment; + newBid.blobKzgCommitments = oldBid.blobKzgCommitments; + newBid.executionRequestsRoot = oldBid.executionRequestsRoot; + stateHezeView.latestExecutionPayloadBid = newBid; + + stateHezeView.payloadExpectedWithdrawals = stateHezeCloned.payloadExpectedWithdrawals; + stateHezeView.ptcWindow = stateHezeCloned.ptcWindow; + + const stateHeze = getCachedBeaconState(stateHezeView, stateGloas); + stateHeze.commit(); + // biome-ignore lint/complexity/useLiteralKeys: It is a protected attribute + stateHeze["clearCache"](); + + return stateHeze; +} diff --git a/packages/state-transition/src/stateTransition.ts b/packages/state-transition/src/stateTransition.ts index e803ef90d765..554184953d46 100644 --- a/packages/state-transition/src/stateTransition.ts +++ b/packages/state-transition/src/stateTransition.ts @@ -16,6 +16,7 @@ import { upgradeStateToDeneb, upgradeStateToElectra, upgradeStateToGloas, + upgradeStateToHeze, } from "./slot/index.js"; import {upgradeStateToFulu} from "./slot/upgradeStateToFulu.js"; import { @@ -26,6 +27,7 @@ import { CachedBeaconStateDeneb, CachedBeaconStateElectra, CachedBeaconStateFulu, + CachedBeaconStateGloas, CachedBeaconStatePhase0, } from "./types.js"; import {computeEpochAtSlot} from "./util/index.js"; @@ -278,6 +280,9 @@ function processSlotsWithTransientCache( if (stateEpoch === config.GLOAS_FORK_EPOCH) { postState = upgradeStateToGloas(postState as CachedBeaconStateFulu) as CachedBeaconStateAllForks; } + if (stateEpoch === config.HEZE_FORK_EPOCH) { + postState = upgradeStateToHeze(postState as CachedBeaconStateGloas) as CachedBeaconStateAllForks; + } { const timer = metrics?.epochTransitionStepTime.startTimer({step: EpochTransitionStep.finalProcessEpoch}); diff --git a/packages/state-transition/src/stateView/interface.ts b/packages/state-transition/src/stateView/interface.ts index b0425279d05c..7387e71b1e4a 100644 --- a/packages/state-transition/src/stateView/interface.ts +++ b/packages/state-transition/src/stateView/interface.ts @@ -9,6 +9,7 @@ import { ForkPostElectra, ForkPostFulu, ForkPostGloas, + ForkPostHeze, isForkPostAltair, isForkPostBellatrix, isForkPostCapella, @@ -16,6 +17,7 @@ import { isForkPostElectra, isForkPostFulu, isForkPostGloas, + isForkPostHeze, } from "@lodestar/params"; import { BeaconBlock, @@ -38,6 +40,7 @@ import { electra, fulu, gloas, + heze, phase0, rewards, } from "@lodestar/types"; @@ -268,18 +271,26 @@ export interface IBeaconStateViewGloas extends IBeaconStateViewFulu { withParentPayloadApplied(executionRequests: gloas.ExecutionRequests): IBeaconStateViewGloas; } +/** Heze+ state fields — use isStatePostHeze() guard */ +export interface IBeaconStateViewHeze extends IBeaconStateViewGloas { + forkName: ForkPostHeze; + /** Modified in heze: ExecutionPayloadBid carries `inclusion_list_bits`. */ + latestExecutionPayloadBid: heze.ExecutionPayloadBid; +} + /** * Type constraint for the concrete BeaconStateView class. - * Requires all fields from the latest fork interface (IBeaconStateViewGloas) but keeps + * Requires all fields from the latest fork interface (IBeaconStateViewHeze) but keeps * forkName as ForkName since the class wraps any fork's state. * Sub-interfaces retain their narrowed forkName discriminants for caller-side type guards. */ export type IBeaconStateViewLatestFork = Omit< - IBeaconStateViewGloas, - "forkName" | "latestExecutionPayloadHeader" | "payloadBlockNumber" + IBeaconStateViewHeze, + "forkName" | "latestExecutionPayloadHeader" | "latestExecutionPayloadBid" | "payloadBlockNumber" > & { forkName: ForkName; latestExecutionPayloadHeader: ExecutionPayloadHeader; + latestExecutionPayloadBid: ExecutionPayloadBid; payloadBlockNumber: number; }; @@ -338,3 +349,7 @@ export function isStatePostFulu(state: IBeaconStateView): state is IBeaconStateV export function isStatePostGloas(state: IBeaconStateView): state is IBeaconStateViewGloas { return isForkPostGloas(state.forkName); } + +export function isStatePostHeze(state: IBeaconStateView): state is IBeaconStateViewHeze { + return isForkPostHeze(state.forkName); +} diff --git a/packages/state-transition/src/types.ts b/packages/state-transition/src/types.ts index 02a84f2b4c08..686c05d38e15 100644 --- a/packages/state-transition/src/types.ts +++ b/packages/state-transition/src/types.ts @@ -10,6 +10,7 @@ export type { CachedBeaconStateExecutions, CachedBeaconStateFulu, CachedBeaconStateGloas, + CachedBeaconStateHeze, CachedBeaconStatePhase0, } from "./cache/stateCache.js"; export type { @@ -22,6 +23,7 @@ export type { BeaconStateExecutions, BeaconStateFulu, BeaconStateGloas, + BeaconStateHeze, BeaconStatePhase0, ShufflingGetter, } from "./cache/types.js"; diff --git a/packages/state-transition/src/util/genesis.ts b/packages/state-transition/src/util/genesis.ts index 8ee6b9fda3a2..fc32c2562879 100644 --- a/packages/state-transition/src/util/genesis.ts +++ b/packages/state-transition/src/util/genesis.ts @@ -334,6 +334,12 @@ export function initializeBeaconStateFromEth1( stateGloas.fork.currentVersion = config.GLOAS_FORK_VERSION; } + if (fork >= ForkSeq.heze) { + const stateHeze = state as CompositeViewDU; + stateHeze.fork.previousVersion = config.HEZE_FORK_VERSION; + stateHeze.fork.currentVersion = config.HEZE_FORK_VERSION; + } + state.commit(); return state; diff --git a/packages/state-transition/test/unit/upgradeState.test.ts b/packages/state-transition/test/unit/upgradeState.test.ts index 573d819e4ab6..c43ae5630b74 100644 --- a/packages/state-transition/test/unit/upgradeState.test.ts +++ b/packages/state-transition/test/unit/upgradeState.test.ts @@ -94,5 +94,16 @@ function getConfig(fork: ForkName, forkEpoch = 0): ChainForkConfig { FULU_FORK_EPOCH: 0, GLOAS_FORK_EPOCH: forkEpoch, }); + case ForkName.heze: + return createChainForkConfig({ + ALTAIR_FORK_EPOCH: 0, + BELLATRIX_FORK_EPOCH: 0, + CAPELLA_FORK_EPOCH: 0, + DENEB_FORK_EPOCH: 0, + ELECTRA_FORK_EPOCH: 0, + FULU_FORK_EPOCH: 0, + GLOAS_FORK_EPOCH: 0, + HEZE_FORK_EPOCH: forkEpoch, + }); } } diff --git a/packages/types/src/heze/index.ts b/packages/types/src/heze/index.ts new file mode 100644 index 000000000000..f34bd0a13167 --- /dev/null +++ b/packages/types/src/heze/index.ts @@ -0,0 +1,5 @@ +export * from "./types.js"; + +import * as ssz from "./sszTypes.js"; +import * as ts from "./types.js"; +export {ts, ssz}; diff --git a/packages/types/src/heze/sszTypes.ts b/packages/types/src/heze/sszTypes.ts new file mode 100644 index 000000000000..d247591f775f --- /dev/null +++ b/packages/types/src/heze/sszTypes.ts @@ -0,0 +1,112 @@ +import {BitVectorType, ContainerType, ListCompositeType, VectorBasicType} from "@chainsafe/ssz"; +import {INCLUSION_LIST_COMMITTEE_SIZE, MAX_TRANSACTIONS_PER_PAYLOAD} from "@lodestar/params"; +import {ssz as bellatrixSsz} from "../bellatrix/index.js"; +import {ssz as gloasSsz} from "../gloas/index.js"; +import {ssz as primitiveSsz} from "../primitive/index.js"; + +const {Slot, Root, BLSSignature, ValidatorIndex} = primitiveSsz; + +export const InclusionListCommittee = new VectorBasicType(ValidatorIndex, INCLUSION_LIST_COMMITTEE_SIZE); + +// Per InclusionList container; bound is MAX_TRANSACTIONS_PER_PAYLOAD. +export const InclusionListTransactions = new ListCompositeType(bellatrixSsz.Transaction, MAX_TRANSACTIONS_PER_PAYLOAD); + +// Aggregated IL transactions surfaced in PayloadAttributes/EL: bounded by total committee output. +export const AggregatedInclusionListTransactions = new ListCompositeType( + bellatrixSsz.Transaction, + MAX_TRANSACTIONS_PER_PAYLOAD * INCLUSION_LIST_COMMITTEE_SIZE +); + +export const InclusionList = new ContainerType( + { + slot: Slot, + validatorIndex: ValidatorIndex, + inclusionListCommitteeRoot: Root, + transactions: InclusionListTransactions, + }, + {typeName: "InclusionList", jsonCase: "eth2"} +); + +export const SignedInclusionList = new ContainerType( + { + message: InclusionList, + signature: BLSSignature, + }, + {typeName: "SignedInclusionList", jsonCase: "eth2"} +); + +export const InclusionListByCommitteeIndicesRequest = new ContainerType( + { + slot: Slot, + committeeIndices: new BitVectorType(INCLUSION_LIST_COMMITTEE_SIZE), + }, + {typeName: "InclusionListByCommitteeIndicesRequest", jsonCase: "eth2"} +); + +export const ExecutionPayloadBid = new ContainerType( + { + ...gloasSsz.ExecutionPayloadBid.fields, + inclusionListBits: new BitVectorType(INCLUSION_LIST_COMMITTEE_SIZE), // [New in Heze:EIP7805] + }, + {typeName: "ExecutionPayloadBid", jsonCase: "eth2"} +); + +export const SignedExecutionPayloadBid = new ContainerType( + { + message: ExecutionPayloadBid, + signature: BLSSignature, + }, + {typeName: "SignedExecutionPayloadBid", jsonCase: "eth2"} +); + +export const DataColumnSidecar = gloasSsz.DataColumnSidecar; +export const DataColumnSidecars = gloasSsz.DataColumnSidecars; + +export const BeaconState = new ContainerType( + { + ...gloasSsz.BeaconState.fields, + latestExecutionPayloadBid: ExecutionPayloadBid, // [Modified in Heze:EIP7805] + }, + {typeName: "BeaconState", jsonCase: "eth2"} +); + +export const BeaconBlockBody = new ContainerType( + { + ...gloasSsz.BeaconBlockBody.fields, + signedExecutionPayloadBid: SignedExecutionPayloadBid, // [Modified in Heze:EIP7805] + }, + {typeName: "BeaconBlockBody", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const BeaconBlock = new ContainerType( + { + ...gloasSsz.BeaconBlock.fields, + body: BeaconBlockBody, + }, + {typeName: "BeaconBlock", jsonCase: "eth2", cachePermanentRootStruct: true} +); + +export const SignedBeaconBlock = new ContainerType( + { + message: BeaconBlock, + signature: BLSSignature, + }, + {typeName: "SignedBeaconBlock", jsonCase: "eth2"} +); + +// PayloadAttributes primarily for SSE event +export const PayloadAttributes = new ContainerType( + { + ...gloasSsz.PayloadAttributes.fields, + inclusionListTransactions: AggregatedInclusionListTransactions, + }, + {typeName: "PayloadAttributes", jsonCase: "eth2"} +); + +export const SSEPayloadAttributes = new ContainerType( + { + ...bellatrixSsz.SSEPayloadAttributesCommon.fields, + payloadAttributes: PayloadAttributes, + }, + {typeName: "SSEPayloadAttributes", jsonCase: "eth2"} +); diff --git a/packages/types/src/heze/types.ts b/packages/types/src/heze/types.ts new file mode 100644 index 000000000000..13aac8e143dd --- /dev/null +++ b/packages/types/src/heze/types.ts @@ -0,0 +1,16 @@ +import {ValueOf} from "@chainsafe/ssz"; +import * as ssz from "./sszTypes.js"; + +export type InclusionListCommittee = ValueOf; +export type InclusionList = ValueOf; +export type SignedInclusionList = ValueOf; +export type InclusionListByCommitteeIndicesRequest = ValueOf; + +export type ExecutionPayloadBid = ValueOf; +export type SignedExecutionPayloadBid = ValueOf; + +export type BeaconState = ValueOf; +export type BeaconBlockBody = ValueOf; +export type BeaconBlock = ValueOf; +export type SignedBeaconBlock = ValueOf; +export type SSEPayloadAttributes = ValueOf; diff --git a/packages/types/src/sszTypes.ts b/packages/types/src/sszTypes.ts index c6763c66564d..e4bd286511c1 100644 --- a/packages/types/src/sszTypes.ts +++ b/packages/types/src/sszTypes.ts @@ -7,6 +7,7 @@ import {ssz as denebSsz} from "./deneb/index.js"; import {ssz as electraSsz} from "./electra/index.js"; import {ssz as fuluSsz} from "./fulu/index.js"; import {ssz as gloasSsz} from "./gloas/index.js"; +import {ssz as hezeSsz} from "./heze/index.js"; import {ssz as phase0Ssz} from "./phase0/index.js"; export * from "./primitive/sszTypes.js"; @@ -33,6 +34,17 @@ const typesByFork = { ...fuluSsz, ...gloasSsz, }, + [ForkName.heze]: { + ...phase0Ssz, + ...altairSsz, + ...bellatrixSsz, + ...capellaSsz, + ...denebSsz, + ...electraSsz, + ...fuluSsz, + ...gloasSsz, + ...hezeSsz, + }, }; // Export these types to ensure that each fork is a superset of the previous one (with overridden types obviously) @@ -46,6 +58,7 @@ export const deneb = typesByFork[ForkName.deneb]; export const electra = typesByFork[ForkName.electra]; export const fulu = typesByFork[ForkName.fulu]; export const gloas = typesByFork[ForkName.gloas]; +export const heze = typesByFork[ForkName.heze]; /** * A type of union of forks must accept as any parameter the UNION of all fork types. diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 781f36dcc473..e1818df21dd7 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -15,6 +15,7 @@ import {ts as deneb} from "./deneb/index.js"; import {ts as electra} from "./electra/index.js"; import {ts as fulu} from "./fulu/index.js"; import {ts as gloas} from "./gloas/index.js"; +import {ts as heze} from "./heze/index.js"; import {ts as phase0} from "./phase0/index.js"; import {Slot} from "./primitive/types.js"; @@ -25,6 +26,7 @@ export {ts as deneb} from "./deneb/index.js"; export {ts as electra} from "./electra/index.js"; export {ts as fulu} from "./fulu/index.js"; export {ts as gloas} from "./gloas/index.js"; +export {ts as heze} from "./heze/index.js"; export {ts as phase0} from "./phase0/index.js"; export * from "./primitive/types.js"; @@ -326,6 +328,47 @@ type TypesByFork = { DataColumnSidecar: gloas.DataColumnSidecar; DataColumnSidecars: gloas.DataColumnSidecars; }; + [ForkName.heze]: { + BeaconBlockHeader: phase0.BeaconBlockHeader; + SignedBeaconBlockHeader: phase0.SignedBeaconBlockHeader; + BeaconBlock: heze.BeaconBlock; + BeaconBlockBody: heze.BeaconBlockBody; + BeaconState: heze.BeaconState; + SignedBeaconBlock: heze.SignedBeaconBlock; + Metadata: fulu.Metadata; + Status: fulu.Status; + LightClientHeader: deneb.LightClientHeader; + LightClientBootstrap: electra.LightClientBootstrap; + LightClientUpdate: electra.LightClientUpdate; + LightClientFinalityUpdate: electra.LightClientFinalityUpdate; + LightClientOptimisticUpdate: electra.LightClientOptimisticUpdate; + LightClientStore: electra.LightClientStore; + BlindedBeaconBlock: electra.BlindedBeaconBlock; + BlindedBeaconBlockBody: electra.BlindedBeaconBlockBody; + SignedBlindedBeaconBlock: electra.SignedBlindedBeaconBlock; + ExecutionPayload: gloas.ExecutionPayload; + ExecutionPayloadHeader: deneb.ExecutionPayloadHeader; + BuilderBid: electra.BuilderBid; + SignedBuilderBid: electra.SignedBuilderBid; + SSEPayloadAttributes: heze.SSEPayloadAttributes; + BlockContents: fulu.BlockContents; + SignedBlockContents: fulu.SignedBlockContents; + ExecutionPayloadAndBlobsBundle: fulu.ExecutionPayloadAndBlobsBundle; + BlobsBundle: fulu.BlobsBundle; + SyncCommittee: altair.SyncCommittee; + SyncAggregate: altair.SyncAggregate; + SingleAttestation: electra.SingleAttestation; + Attestation: electra.Attestation; + IndexedAttestation: electra.IndexedAttestation; + IndexedAttestationBigint: electra.IndexedAttestationBigint; + AttesterSlashing: electra.AttesterSlashing; + AggregateAndProof: electra.AggregateAndProof; + SignedAggregateAndProof: electra.SignedAggregateAndProof; + ExecutionRequests: electra.ExecutionRequests; + ExecutionPayloadBid: heze.ExecutionPayloadBid; + DataColumnSidecar: gloas.DataColumnSidecar; + DataColumnSidecars: gloas.DataColumnSidecars; + }; }; export type TypesFor = K extends void diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index ccbe0cdf32cd..bf5aa317886d 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -103,6 +103,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record - name: HEZE_FORK_EPOCH#heze - sources: [] + sources: + - file: packages/config/src/chainConfig/configs/mainnet.ts + search: "HEZE_FORK_EPOCH:" spec: | HEZE_FORK_EPOCH: Epoch = 18446744073709551615 - name: HEZE_FORK_VERSION#heze - sources: [] + sources: + - file: packages/config/src/chainConfig/configs/mainnet.ts + search: "HEZE_FORK_VERSION:" spec: | HEZE_FORK_VERSION: Version = '0x08000000' @@ -383,7 +387,9 @@ - name: INCLUSION_LIST_DUE_BPS#heze - sources: [] + sources: + - file: packages/config/src/chainConfig/configs/mainnet.ts + search: "INCLUSION_LIST_DUE_BPS:" spec: | INCLUSION_LIST_DUE_BPS: uint64 = 6667 @@ -417,7 +423,9 @@ - name: MAX_BYTES_PER_INCLUSION_LIST#heze - sources: [] + sources: + - file: packages/config/src/chainConfig/configs/mainnet.ts + search: "MAX_BYTES_PER_INCLUSION_LIST:" spec: | MAX_BYTES_PER_INCLUSION_LIST = 8192 @@ -478,7 +486,9 @@ - name: MAX_REQUEST_INCLUSION_LIST#heze - sources: [] + sources: + - file: packages/config/src/chainConfig/configs/mainnet.ts + search: "MAX_REQUEST_INCLUSION_LIST:" spec: | MAX_REQUEST_INCLUSION_LIST = 16 diff --git a/specrefs/constants.yml b/specrefs/constants.yml index 7eb9dab55a00..2f6787fd7cb0 100644 --- a/specrefs/constants.yml +++ b/specrefs/constants.yml @@ -250,7 +250,9 @@ - name: DOMAIN_INCLUSION_LIST_COMMITTEE#heze - sources: [] + sources: + - file: packages/params/src/index.ts + search: export const DOMAIN_INCLUSION_LIST_COMMITTEE = spec: | DOMAIN_INCLUSION_LIST_COMMITTEE: DomainType = '0x10000000' diff --git a/specrefs/containers.yml b/specrefs/containers.yml index 6461b202a5e1..ec8ca4219283 100644 --- a/specrefs/containers.yml +++ b/specrefs/containers.yml @@ -636,7 +636,9 @@ - name: BeaconState#heze - sources: [] + sources: + - file: packages/types/src/heze/sszTypes.ts + search: export const BeaconState = spec: | class BeaconState(Container): @@ -1073,7 +1075,9 @@ - name: ExecutionPayloadBid#heze - sources: [] + sources: + - file: packages/types/src/heze/sszTypes.ts + search: export const ExecutionPayloadBid = spec: | class ExecutionPayloadBid(Container): @@ -1258,7 +1262,9 @@ - name: InclusionList#heze - sources: [] + sources: + - file: packages/types/src/heze/sszTypes.ts + search: export const InclusionList = spec: | class InclusionList(Container): @@ -1706,7 +1712,9 @@ - name: SignedExecutionPayloadBid#heze - sources: [] + sources: + - file: packages/types/src/heze/sszTypes.ts + search: export const SignedExecutionPayloadBid = spec: | class SignedExecutionPayloadBid(Container): @@ -1726,7 +1734,9 @@ - name: SignedInclusionList#heze - sources: [] + sources: + - file: packages/types/src/heze/sszTypes.ts + search: export const SignedInclusionList = spec: | class SignedInclusionList(Container): diff --git a/specrefs/presets.yml b/specrefs/presets.yml index cb7bef8a6500..9d31eac7da73 100644 --- a/specrefs/presets.yml +++ b/specrefs/presets.yml @@ -179,7 +179,9 @@ - name: INCLUSION_LIST_COMMITTEE_SIZE#heze - sources: [] + sources: + - file: packages/params/src/presets/mainnet.ts + search: "INCLUSION_LIST_COMMITTEE_SIZE:" spec: | INCLUSION_LIST_COMMITTEE_SIZE: uint64 = 16