initial Electra support skeleton (#5946)

This commit is contained in:
tersec 2024-02-24 13:44:15 +00:00 committed by GitHub
parent feec45ba76
commit d09bf3b587
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 792 additions and 158 deletions

View File

@ -508,7 +508,8 @@ proc new*(T: type BeaconChainDB,
kvStore db.openKvStore("altair_blocks").expectDb(),
kvStore db.openKvStore("bellatrix_blocks").expectDb(),
kvStore db.openKvStore("capella_blocks").expectDb(),
kvStore db.openKvStore("deneb_blocks").expectDb()]
kvStore db.openKvStore("deneb_blocks").expectDb(),
kvStore db.openKvStore("electra_blocks").expectDb()]
stateRoots = kvStore db.openKvStore("state_roots", true).expectDb()
@ -517,7 +518,8 @@ proc new*(T: type BeaconChainDB,
kvStore db.openKvStore("altair_state_no_validators").expectDb(),
kvStore db.openKvStore("bellatrix_state_no_validators").expectDb(),
kvStore db.openKvStore("capella_state_no_validator_pubkeys").expectDb(),
kvStore db.openKvStore("deneb_state_no_validator_pubkeys").expectDb()]
kvStore db.openKvStore("deneb_state_no_validator_pubkeys").expectDb(),
kvStore db.openKvStore("electra_state_no_validator_pubkeys").expectDb()]
stateDiffs = kvStore db.openKvStore("state_diffs").expectDb()
summaries = kvStore db.openKvStore("beacon_block_summaries", true).expectDb()
@ -789,7 +791,8 @@ proc putBlock*(
proc putBlock*(
db: BeaconChainDB,
value: bellatrix.TrustedSignedBeaconBlock |
capella.TrustedSignedBeaconBlock | deneb.TrustedSignedBeaconBlock) =
capella.TrustedSignedBeaconBlock | deneb.TrustedSignedBeaconBlock |
electra.TrustedSignedBeaconBlock) =
db.withManyWrites:
db.blocks[type(value).kind].putSZSSZ(value.root.data, value)
db.putBeaconBlockSummary(value.root, value.message.toBeaconBlockSummary())
@ -839,6 +842,10 @@ template toBeaconStateNoImmutableValidators(state: deneb.BeaconState):
DenebBeaconStateNoImmutableValidators =
isomorphicCast[DenebBeaconStateNoImmutableValidators](state)
template toBeaconStateNoImmutableValidators(state: electra.BeaconState):
ElectraBeaconStateNoImmutableValidators =
isomorphicCast[ElectraBeaconStateNoImmutableValidators](state)
proc putState*(
db: BeaconChainDB, key: Eth2Digest,
value: phase0.BeaconState | altair.BeaconState) =
@ -848,7 +855,8 @@ proc putState*(
proc putState*(
db: BeaconChainDB, key: Eth2Digest,
value: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState) =
value: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState |
electra.BeaconState) =
db.updateImmutableValidators(value.validators.asSeq())
db.statesNoVal[type(value).kind].putSZSSZ(
key.data, toBeaconStateNoImmutableValidators(value))
@ -976,7 +984,7 @@ proc getBlock*(
proc getBlock*[
X: bellatrix.TrustedSignedBeaconBlock | capella.TrustedSignedBeaconBlock |
deneb.TrustedSignedBeaconBlock](
deneb.TrustedSignedBeaconBlock | electra.TrustedSignedBeaconBlock](
db: BeaconChainDB, key: Eth2Digest,
T: type X): Opt[T] =
# We only store blocks that we trust in the database
@ -1031,7 +1039,7 @@ proc getBlockSSZ*(
proc getBlockSSZ*[
X: bellatrix.TrustedSignedBeaconBlock | capella.TrustedSignedBeaconBlock |
deneb.TrustedSignedBeaconBlock](
deneb.TrustedSignedBeaconBlock | electra.TrustedSignedBeaconBlock](
db: BeaconChainDB, key: Eth2Digest, data: var seq[byte], T: type X): bool =
let dataPtr = addr data # Short-lived
var success = true
@ -1080,7 +1088,7 @@ proc getBlockSZ*(
proc getBlockSZ*[
X: bellatrix.TrustedSignedBeaconBlock | capella.TrustedSignedBeaconBlock |
deneb.TrustedSignedBeaconBlock](
deneb.TrustedSignedBeaconBlock | electra.TrustedSignedBeaconBlock](
db: BeaconChainDB, key: Eth2Digest, data: var seq[byte], T: type X): bool =
let dataPtr = addr data # Short-lived
func decode(data: openArray[byte]) =
@ -1178,7 +1186,8 @@ proc getStateOnlyMutableValidators(
proc getStateOnlyMutableValidators(
immutableValidators: openArray[ImmutableValidatorData2],
store: KvStoreRef, key: openArray[byte],
output: var (capella.BeaconState | deneb.BeaconState),
output: var (capella.BeaconState | deneb.BeaconState |
electra.BeaconState),
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible
@ -1263,7 +1272,8 @@ proc getState*(
proc getState*(
db: BeaconChainDB, key: Eth2Digest,
output: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState |
electra.BeaconState),
rollback: RollbackProc): bool =
## Load state into `output` - BeaconState is large so we want to avoid
## re-allocating it if possible
@ -1483,7 +1493,7 @@ iterator getAncestorSummaries*(db: BeaconChainDB, root: Eth2Digest):
# Backwards compat for reading old databases, or those that for whatever
# reason lost a summary along the way..
static: doAssert ConsensusFork.high == ConsensusFork.Deneb
static: doAssert ConsensusFork.high == ConsensusFork.Electra
while true:
if db.v0.backend.getSnappySSZ(
subkey(BeaconBlockSummary, res.root), res.summary) == GetResult.found:
@ -1498,6 +1508,8 @@ iterator getAncestorSummaries*(db: BeaconChainDB, root: Eth2Digest):
res.summary = blck.get().message.toBeaconBlockSummary()
elif (let blck = db.getBlock(res.root, deneb.TrustedSignedBeaconBlock); blck.isSome()):
res.summary = blck.get().message.toBeaconBlockSummary()
elif (let blck = db.getBlock(res.root, electra.TrustedSignedBeaconBlock); blck.isSome()):
res.summary = blck.get().message.toBeaconBlockSummary()
else:
break

View File

@ -77,6 +77,8 @@ proc initLightClient*(
case node.dag.cfg.consensusForkAtEpoch(
forkyBlck.message.slot.epoch)
of ConsensusFork.Electra:
debugRaiseAssert "initLightClient"
of ConsensusFork.Deneb:
callForkchoiceUpdated(PayloadAttributesV3)
of ConsensusFork.Capella:

View File

@ -483,7 +483,8 @@ func init(
func init(
T: type AttestationCache,
state: altair.HashedBeaconState | bellatrix.HashedBeaconState |
capella.HashedBeaconState | deneb.HashedBeaconState,
capella.HashedBeaconState | deneb.HashedBeaconState |
electra.HashedBeaconState,
cache: var StateCache): T =
# Load attestations that are scheduled for being given rewards for
let

View File

@ -69,7 +69,8 @@ func hasBlob*(
func popBlobs*(
quarantine: var BlobQuarantine, digest: Eth2Digest,
blck: deneb.SignedBeaconBlock): seq[ref BlobSidecar] =
blck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock):
seq[ref BlobSidecar] =
var r: seq[ref BlobSidecar] = @[]
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
var b: ref BlobSidecar
@ -77,8 +78,9 @@ func popBlobs*(
r.add(b)
r
func hasBlobs*(quarantine: BlobQuarantine, blck: deneb.SignedBeaconBlock):
bool =
func hasBlobs*(
quarantine: BlobQuarantine,
blck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock): bool =
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
if (blck.root, BlobIndex idx, kzg_commitment) notin quarantine.blobs:
return false

View File

@ -73,7 +73,8 @@ func init*(
T: type BlockRef, root: Eth2Digest, executionValid: bool,
blck: bellatrix.SomeBeaconBlock | bellatrix.TrustedBeaconBlock |
capella.SomeBeaconBlock | capella.TrustedBeaconBlock |
deneb.SomeBeaconBlock | deneb.TrustedBeaconBlock): BlockRef =
deneb.SomeBeaconBlock | deneb.TrustedBeaconBlock |
electra.SomeBeaconBlock | electra.TrustedBeaconBlock): BlockRef =
BlockRef.init(
root, Opt.some Eth2Digest(blck.body.execution_payload.block_hash),
executionValid =

View File

@ -293,10 +293,11 @@ type
OnBellatrixBlockAdded* = OnBlockAdded[bellatrix.TrustedSignedBeaconBlock]
OnCapellaBlockAdded* = OnBlockAdded[capella.TrustedSignedBeaconBlock]
OnDenebBlockAdded* = OnBlockAdded[deneb.TrustedSignedBeaconBlock]
OnElectraBlockAdded* = OnBlockAdded[electra.TrustedSignedBeaconBlock]
OnForkyBlockAdded* =
OnPhase0BlockAdded | OnAltairBlockAdded | OnBellatrixBlockAdded |
OnCapellaBlockAdded | OnDenebBlockAdded
OnCapellaBlockAdded | OnDenebBlockAdded | OnElectraBlockAdded
HeadChangeInfoObject* = object
slot*: Slot
@ -328,7 +329,9 @@ type
optimistic* {.serializedFieldName: "execution_optimistic".}: Option[bool]
template OnBlockAddedCallback*(kind: static ConsensusFork): auto =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
typedesc[OnElectraBlockAdded]
elif kind == ConsensusFork.Deneb:
typedesc[OnDenebBlockAdded]
elif kind == ConsensusFork.Capella:
typedesc[OnCapellaBlockAdded]

View File

@ -294,8 +294,7 @@ iterator pop*(quarantine: var Quarantine, root: Eth2Digest):
proc addBlobless*(
quarantine: var Quarantine, finalizedSlot: Slot,
signedBlock: deneb.SignedBeaconBlock): bool =
signedBlock: deneb.SignedBeaconBlock | electra.SignedBeaconBlock): bool =
if not isViable(finalizedSlot, signedBlock.message.slot):
quarantine.addUnviable(signedBlock.root)
return false
@ -306,8 +305,10 @@ proc addBlobless*(
return true
debug "block quarantine: Adding blobless", blck = shortLog(signedBlock)
quarantine.blobless[signedBlock.root] = signedBlock
quarantine.missing.del(signedBlock.root)
debugRaiseAssert "addBlobless; needs consideration how to handle deneb and electra"
when not (signedBlock is electra.SignedBeaconBlock):
quarantine.blobless[signedBlock.root] = signedBlock
quarantine.missing.del(signedBlock.root)
true
func popBlobless*(quarantine: var Quarantine, root: Eth2Digest):

View File

@ -268,8 +268,11 @@ proc getForkedBlock*(db: BeaconChainDB, root: Eth2Digest):
Opt[ForkedTrustedSignedBeaconBlock] =
# When we only have a digest, we don't know which fork it's from so we try
# them one by one - this should be used sparingly
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
if (let blck = db.getBlock(root, deneb.TrustedSignedBeaconBlock);
static: doAssert high(ConsensusFork) == ConsensusFork.Electra
if (let blck = db.getBlock(root, electra.TrustedSignedBeaconBlock);
blck.isSome()):
ok(ForkedTrustedSignedBeaconBlock.init(blck.get()))
elif (let blck = db.getBlock(root, deneb.TrustedSignedBeaconBlock);
blck.isSome()):
ok(ForkedTrustedSignedBeaconBlock.init(blck.get()))
elif (let blck = db.getBlock(root, capella.TrustedSignedBeaconBlock);
@ -1002,6 +1005,12 @@ proc applyBlock(
state_transition(
dag.cfg, state, data, cache, info,
dag.updateFlags + {slotProcessed}, noRollback)
of ConsensusFork.Electra:
let data = getBlock(dag, bid, electra.TrustedSignedBeaconBlock).valueOr:
return err("Block load failed")
state_transition(
dag.cfg, state, data, cache, info,
dag.updateFlags + {slotProcessed}, noRollback)
proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
validatorMonitor: ref ValidatorMonitor, updateFlags: UpdateFlags,
@ -1155,11 +1164,12 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
let
configFork = case dag.headState.kind
of ConsensusFork.Phase0: genesisFork(cfg)
of ConsensusFork.Altair: altairFork(cfg)
of ConsensusFork.Phase0: genesisFork(cfg)
of ConsensusFork.Altair: altairFork(cfg)
of ConsensusFork.Bellatrix: bellatrixFork(cfg)
of ConsensusFork.Capella: capellaFork(cfg)
of ConsensusFork.Deneb: denebFork(cfg)
of ConsensusFork.Capella: capellaFork(cfg)
of ConsensusFork.Deneb: denebFork(cfg)
of ConsensusFork.Electra: electraFork(cfg)
stateFork = getStateField(dag.headState, fork)
# Here, we check only the `current_version` field because the spec
@ -2398,6 +2408,8 @@ proc updateHead*(
of ConsensusFork.Deneb:
if dag.vanityLogs.onUpgradeToDeneb != nil:
dag.vanityLogs.onUpgradeToDeneb()
of ConsensusFork.Electra:
debugRaiseAssert "updateHead"
if dag.vanityLogs.onKnownBlsToExecutionChange != nil and
checkBlsToExecutionChanges(

View File

@ -379,7 +379,16 @@ proc runProposalForkchoiceUpdated*(
payloadAttributes = some fcPayloadAttributes)
debug "Fork-choice updated for proposal", status
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
static: doAssert high(ConsensusFork) == ConsensusFork.Electra
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "runProposalForkchoiceUpdated, probably will be a new payload attributes type here"
callForkchoiceUpdated(PayloadAttributesV3(
timestamp: Quantity timestamp,
prevRandao: FixedBytes[32] randomData,
suggestedFeeRecipient: feeRecipient,
withdrawals:
toEngineWithdrawals get_expected_withdrawals(forkyState.data),
parentBeaconBlockRoot: beaconHead.blck.bid.root.asBlockHash))
when consensusFork >= ConsensusFork.Deneb:
callForkchoiceUpdated(PayloadAttributesV3(
timestamp: Quantity timestamp,

View File

@ -561,6 +561,32 @@ func asEngineExecutionPayload*(executionPayload: deneb.ExecutionPayload):
blobGasUsed: Quantity(executionPayload.blob_gas_used),
excessBlobGas: Quantity(executionPayload.excess_blob_gas))
func asEngineExecutionPayload*(executionPayload: electra.ExecutionPayload):
ExecutionPayloadV3 =
debugRaiseAssert "asEngineExecutionPayload for electra.ExecutionPayload probably won't use ExecutionPayloadV3"
template getTypedTransaction(tt: bellatrix.Transaction): TypedTransaction =
TypedTransaction(tt.distinctBase)
engine_api.ExecutionPayloadV3(
parentHash: executionPayload.parent_hash.asBlockHash,
feeRecipient: Address(executionPayload.fee_recipient.data),
stateRoot: executionPayload.state_root.asBlockHash,
receiptsRoot: executionPayload.receipts_root.asBlockHash,
logsBloom:
FixedBytes[BYTES_PER_LOGS_BLOOM](executionPayload.logs_bloom.data),
prevRandao: executionPayload.prev_randao.asBlockHash,
blockNumber: Quantity(executionPayload.block_number),
gasLimit: Quantity(executionPayload.gas_limit),
gasUsed: Quantity(executionPayload.gas_used),
timestamp: Quantity(executionPayload.timestamp),
extraData: DynamicBytes[0, MAX_EXTRA_DATA_BYTES](executionPayload.extra_data),
baseFeePerGas: executionPayload.base_fee_per_gas,
blockHash: executionPayload.block_hash.asBlockHash,
transactions: mapIt(executionPayload.transactions, it.getTypedTransaction),
withdrawals: mapIt(executionPayload.withdrawals, it.asEngineWithdrawal),
blobGasUsed: Quantity(executionPayload.blob_gas_used),
excessBlobGas: Quantity(executionPayload.excess_blob_gas))
func isConnected(connection: ELConnection): bool =
connection.web3.isSome
@ -752,6 +778,10 @@ template EngineApiResponseType*(T: type capella.ExecutionPayloadForSigning): typ
template EngineApiResponseType*(T: type deneb.ExecutionPayloadForSigning): type =
engine_api.GetPayloadV3Response
template EngineApiResponseType*(T: type electra.ExecutionPayloadForSigning): type =
debugRaiseAssert "EngineApiResponseType electra.ExecutionPayloadForSigning; presumably will be a GetPayloadV4Response"
engine_api.GetPayloadV3Response
template toEngineWithdrawals*(withdrawals: seq[capella.Withdrawal]): seq[WithdrawalV1] =
mapIt(withdrawals, toEngineWithdrawal(it))
@ -850,9 +880,15 @@ proc getPayload*(m: ELManager,
deadline.cancelSoon()
if bestPayloadIdx.isSome:
return ok requests[bestPayloadIdx.get].value().asConsensusType
when PayloadType.kind != ConsensusFork.Electra:
if bestPayloadIdx.isSome:
return ok requests[bestPayloadIdx.get].value().asConsensusType
else:
return err()
else:
# right now, asConsensusType is confused by Deneb and Electra sharing a
# Payload type. this will probably be resolved in time naturally.
debugRaiseAssert "getPayload ForkyExecutionPayloadForSigning"
return err()
proc waitELToSyncDeposits(connection: ELConnection,

View File

@ -447,6 +447,8 @@ iterator getBlockIds*(
if not getPartialState(
db, historical_roots, historical_summaries, stateSlot, state[]):
state = nil # No `return` in iterators
of ConsensusFork.Electra:
debugRaiseAssert "getBlockIds"
if state == nil:
break

View File

@ -328,7 +328,7 @@ proc newExecutionPayload*(
proc getExecutionValidity(
elManager: ELManager,
blck: bellatrix.SignedBeaconBlock | capella.SignedBeaconBlock |
deneb.SignedBeaconBlock):
deneb.SignedBeaconBlock | electra.SignedBeaconBlock):
Future[NewPayloadStatus] {.async: (raises: [CancelledError]).} =
if not blck.message.is_execution_block:
return NewPayloadStatus.valid # vacuously
@ -361,9 +361,10 @@ proc getExecutionValidity(
blck = shortLog(blck)
return NewPayloadStatus.noResponse
proc checkBloblessSignature(self: BlockProcessor,
signed_beacon_block: deneb.SignedBeaconBlock):
Result[void, cstring] =
proc checkBloblessSignature(
self: BlockProcessor,
signed_beacon_block: deneb.SignedBeaconBlock | electra.SignedBeaconBlock):
Result[void, cstring] =
let dag = self.consensusManager.dag
let parent = dag.getBlockRef(signed_beacon_block.message.parent_root).valueOr:
return err("checkBloblessSignature called with orphan block")
@ -674,6 +675,9 @@ proc storeBlock(
template callForkChoiceUpdated: auto =
case self.consensusManager.dag.cfg.consensusForkAtEpoch(
newHead.get.blck.bid.slot.epoch)
of ConsensusFork.Electra:
debugRaiseAssert "storeBlock, probably will become PayloadAttributesV3"
callExpectValidFCU(payloadAttributeType = PayloadAttributesV3)
of ConsensusFork.Deneb:
callExpectValidFCU(payloadAttributeType = PayloadAttributesV3)
of ConsensusFork.Capella:

View File

@ -268,7 +268,8 @@ template validateBeaconBlockBellatrix(
signed_beacon_block:
bellatrix.SignedBeaconBlock |
capella.SignedBeaconBlock |
deneb.SignedBeaconBlock,
deneb.SignedBeaconBlock |
electra.SignedBeaconBlock,
parent: BlockRef): untyped =
# If the execution is enabled for the block -- i.e.
# is_execution_enabled(state, block.body) then validate the following:

View File

@ -830,7 +830,7 @@ template gossipMaxSize(T: untyped): uint32 =
when isFixedSize(T):
fixedPortionSize(T).uint32
elif T is bellatrix.SignedBeaconBlock or T is capella.SignedBeaconBlock or
T is deneb.SignedBeaconBlock:
T is deneb.SignedBeaconBlock or T is electra.SignedBeaconBlock:
GOSSIP_MAX_SIZE
# TODO https://github.com/status-im/nim-ssz-serialization/issues/20 for
# Attestation, AttesterSlashing, and SignedAggregateAndProof, which all
@ -2637,6 +2637,12 @@ proc broadcastBeaconBlock*(
let topic = getBeaconBlocksTopic(node.forkDigests.deneb)
node.broadcast(topic, blck)
proc broadcastBeaconBlock*(
node: Eth2Node, blck: electra.SignedBeaconBlock):
Future[SendResult] {.async: (raises: [CancelledError], raw: true).} =
let topic = getBeaconBlocksTopic(node.forkDigests.electra)
node.broadcast(topic, blck)
proc broadcastBlobSidecar*(
node: Eth2Node, subnet_id: BlobId, blob: deneb.BlobSidecar):
Future[SendResult] {.async: (raises: [CancelledError], raw: true).} =

View File

@ -275,7 +275,8 @@ when const_preset == "gnosis":
doAssert network.cfg.BELLATRIX_FORK_EPOCH < FAR_FUTURE_EPOCH
doAssert network.cfg.CAPELLA_FORK_EPOCH < FAR_FUTURE_EPOCH
doAssert network.cfg.DENEB_FORK_EPOCH < FAR_FUTURE_EPOCH
static: doAssert ConsensusFork.high == ConsensusFork.Deneb
doAssert network.cfg.ELECTRA_FORK_EPOCH == FAR_FUTURE_EPOCH
static: doAssert ConsensusFork.high == ConsensusFork.Electra
elif const_preset == "mainnet":
when incbinEnabled:
@ -340,7 +341,8 @@ elif const_preset == "mainnet":
doAssert network.cfg.BELLATRIX_FORK_EPOCH < FAR_FUTURE_EPOCH
doAssert network.cfg.CAPELLA_FORK_EPOCH < FAR_FUTURE_EPOCH
doAssert network.cfg.DENEB_FORK_EPOCH < FAR_FUTURE_EPOCH
static: doAssert ConsensusFork.high == ConsensusFork.Deneb
doAssert network.cfg.ELECTRA_FORK_EPOCH == FAR_FUTURE_EPOCH
static: doAssert ConsensusFork.high == ConsensusFork.Electra
proc getMetadataForNetwork*(networkName: string): Eth2NetworkMetadata =
template loadRuntimeMetadata(): auto =

View File

@ -137,6 +137,9 @@ func getVanityLogs(stdoutKind: StdoutLogKind): VanityLogs =
func getVanityMascot(consensusFork: ConsensusFork): string =
case consensusFork
of ConsensusFork.Electra:
debugRaiseAssert "getVanityMascot"
" "
of ConsensusFork.Deneb:
"🐟"
of ConsensusFork.Capella:
@ -860,7 +863,8 @@ func forkDigests(node: BeaconNode): auto =
node.dag.forkDigests.altair,
node.dag.forkDigests.bellatrix,
node.dag.forkDigests.capella,
node.dag.forkDigests.deneb]
node.dag.forkDigests.deneb,
node.dag.forkDigests.electra]
forkDigestsArray
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/phase0/p2p-interface.md#attestation-subnet-subscription
@ -1293,7 +1297,8 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) {.async.} =
removeAltairMessageHandlers,
removeAltairMessageHandlers, # bellatrix (altair handlers, different forkDigest)
removeCapellaMessageHandlers,
removeDenebMessageHandlers
removeDenebMessageHandlers,
removeDenebMessageHandlers # Electra (Deneb handler, different forkDigest)
]
for gossipFork in oldGossipForks:
@ -1304,7 +1309,8 @@ proc updateGossipStatus(node: BeaconNode, slot: Slot) {.async.} =
addAltairMessageHandlers,
addAltairMessageHandlers, # bellatrix (altair handlers, different forkDigest)
addCapellaMessageHandlers,
addDenebMessageHandlers
addDenebMessageHandlers,
addDenebMessageHandlers # Electra (Deneb handler, different forkDigest)
]
for gossipFork in newGossipForks:

View File

@ -237,6 +237,9 @@ proc installApiHandlers*(node: SigningNodeRef) =
(GeneralizedIndex(401), request.beaconBlockHeader.data)
of ConsensusFork.Deneb:
(GeneralizedIndex(801), request.beaconBlockHeader.data)
of ConsensusFork.Electra:
debugRaiseAssert "/api/v1/eth2/sign/{validator_key} TODO verify correctness"
(GeneralizedIndex(801), request.beaconBlockHeader.data)
if request.proofs.isNone() or len(request.proofs.get()) == 0:
return errorResponse(Http400, MissingMerkleProofError)

View File

@ -929,6 +929,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
await node.router.routeSignedBeaconBlock(
blck, Opt.some(blck.create_blob_sidecars(
restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)))
of ConsensusFork.Electra:
debugRaiseAssert "/eth/v1/beacon/blocks POST; can't reach here unless in Electra per check above, but this keeps return value consistent"
var blck = restBlock.denebData.signed_block
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.some(blck.create_blob_sidecars(
restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)))
if res.isErr():
return RestApiResponse.jsonError(
@ -1005,6 +1012,13 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
await node.router.routeSignedBeaconBlock(
blck, Opt.some(blck.create_blob_sidecars(
restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)))
of ConsensusFork.Electra:
debugRaiseAssert "electra missing; /eth/v2/beacon/blocks will only trigger this codepath when in Electra"
var blck = restBlock.denebData.signed_block
blck.root = hash_tree_root(blck.message)
await node.router.routeSignedBeaconBlock(
blck, Opt.some(blck.create_blob_sidecars(
restBlock.denebData.kzg_proofs, restBlock.denebData.blobs)))
if res.isErr():
return RestApiResponse.jsonError(
@ -1051,7 +1065,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
RestApiResponse.jsonError(Http500, InvalidAcceptError)
withBlck(bdata.asSigned()):
when consensusFork <= ConsensusFork.Altair:
when consensusFork == ConsensusFork.Electra:
debugRaiseAssert "/eth/v1/beacon/blinded_block POST"
RestApiResponse.jsonError(Http500, "electra missing")
elif consensusFork <= ConsensusFork.Altair:
respondSszOrJson(forkyBlck, consensusFork)
else:
respondSszOrJson(toSignedBlindedBeaconBlock(forkyBlck), consensusFork)
@ -1082,7 +1099,11 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http400, BlockIncorrectFork)
withConsensusFork(currentEpochFork):
when consensusFork >= ConsensusFork.Capella:
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "/eth/v1/beacon/blinded_blocks POST"
return RestApiResponse.jsonError(
Http400, $consensusFork & " builder API unsupported")
elif consensusFork >= ConsensusFork.Capella:
let
restBlock = decodeBodyJsonOrSsz(
consensusFork.SignedBlindedBeaconBlock, body).valueOr:

View File

@ -408,7 +408,13 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return
withBlck(message.blck):
let data =
when consensusFork >= ConsensusFork.Deneb:
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "/eth/v2/validator/blocks/{slot} GET"
let blobsBundle = message.blobsBundleOpt.get()
deneb.BlockContents(
kzg_proofs: blobsBundle.proofs,
blobs: blobsBundle.blobs)
elif consensusFork >= ConsensusFork.Deneb:
let blobsBundle = message.blobsBundleOpt.get()
deneb.BlockContents(
`block`: forkyBlck,
@ -522,7 +528,11 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
contextFork = node.dag.cfg.consensusForkAtEpoch(node.currentSlot.epoch)
withConsensusFork(contextFork):
when consensusFork >= ConsensusFork.Capella:
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "/eth/v1/validator/blinded_blocks/{slot} GET 1"
return RestApiResponse.jsonError(
Http400, "Electra builder API not yet supported")
elif consensusFork >= ConsensusFork.Capella:
let res = await makeBlindedBeaconBlockForHeadAndSlot[
consensusFork.BlindedBeaconBlock](
node, payloadBuilderClient, qrandao,
@ -541,7 +551,11 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
if res.isErr():
return RestApiResponse.jsonError(Http400, res.error())
withBlck(res.get().blck):
return responseVersioned(forkyBlck, contextFork)
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "/eth/v1/validator/blinded_blocks/{slot} GET 2"
return RestApiResponse.jsonError(Http400, "")
else:
return responseVersioned(forkyBlck, contextFork)
func getMaybeBlindedHeaders(
consensusFork: ConsensusFork,
@ -632,7 +646,10 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http400, InvalidRandaoRevealValue)
withConsensusFork(node.dag.cfg.consensusForkAtEpoch(qslot.epoch)):
when consensusFork >= ConsensusFork.Capella:
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "/eth/v3/validator/blocks/{slot} GET 1"
return RestApiResponse.jsonError(Http500, "")
elif consensusFork >= ConsensusFork.Capella:
let
message = (await node.makeMaybeBlindedBeaconBlockForHeadAndSlot(
consensusFork, qrandao, qgraffiti, qhead, qslot)).valueOr:

View File

@ -84,8 +84,8 @@ func get_validator_churn_limit*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/deneb/beacon-chain.md#new-get_validator_activation_churn_limit
func get_validator_activation_churn_limit*(
cfg: RuntimeConfig, state: deneb.BeaconState, cache: var StateCache):
uint64 =
cfg: RuntimeConfig, state: deneb.BeaconState | electra.BeaconState,
cache: var StateCache): uint64 =
## Return the validator activation churn limit for the current epoch.
min(
cfg.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT,
@ -154,7 +154,7 @@ func get_slashing_penalty*(state: ForkyBeaconState,
elif state is altair.BeaconState:
validator_effective_balance div MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR
elif state is bellatrix.BeaconState or state is capella.BeaconState or
state is deneb.BeaconState:
state is deneb.BeaconState or state is electra.BeaconState:
validator_effective_balance div MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX
else:
{.fatal: "invalid BeaconState type".}
@ -172,7 +172,8 @@ func get_proposer_reward(state: ForkyBeaconState, whistleblower_reward: Gwei): G
when state is phase0.BeaconState:
whistleblower_reward div PROPOSER_REWARD_QUOTIENT
elif state is altair.BeaconState or state is bellatrix.BeaconState or
state is capella.BeaconState or state is deneb.BeaconState:
state is capella.BeaconState or state is deneb.BeaconState or
state is electra.BeaconState:
whistleblower_reward * PROPOSER_WEIGHT div WEIGHT_DENOMINATOR
else:
{.fatal: "invalid BeaconState type".}
@ -292,6 +293,20 @@ func get_initial_beacon_block*(state: deneb.HashedBeaconState):
deneb.TrustedSignedBeaconBlock(
message: message, root: hash_tree_root(message))
from ./datatypes/electra import HashedBeaconState, TrustedSignedBeaconBlock
# TODO spec link here when it exists
func get_initial_beacon_block*(state: electra.HashedBeaconState):
electra.TrustedSignedBeaconBlock =
# The genesis block is implicitly trusted
let message = electra.TrustedBeaconBlock(
slot: state.data.slot,
state_root: state.root)
# parent_root, randao_reveal, eth1_data, signature, and body automatically
# initialized to default values.
electra.TrustedSignedBeaconBlock(
message: message, root: hash_tree_root(message))
func get_initial_beacon_block*(state: ForkedHashedBeaconState):
ForkedTrustedSignedBeaconBlock =
withState(state):
@ -549,7 +564,7 @@ func get_attestation_participation_flag_indices(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/deneb/beacon-chain.md#modified-get_attestation_participation_flag_indices
func get_attestation_participation_flag_indices(
state: deneb.BeaconState,
state: deneb.BeaconState | electra.BeaconState,
data: AttestationData, inclusion_delay: uint64): set[TimelyFlag] =
## Return the flag indices that are satisfied by an attestation.
let justified_checkpoint =
@ -613,7 +628,7 @@ func get_base_reward_per_increment*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_base_reward
func get_base_reward(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
index: ValidatorIndex, base_reward_per_increment: Gwei): Gwei =
## Return the base reward for the validator defined by ``index`` with respect
## to the current ``state``.
@ -658,7 +673,8 @@ proc check_attestation*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#new-process_bls_to_execution_change
proc check_bls_to_execution_change*(
genesisFork: Fork, state: capella.BeaconState | deneb.BeaconState,
genesisFork: Fork,
state: capella.BeaconState | deneb.BeaconState | electra.BeaconState,
signed_address_change: SignedBLSToExecutionChange, flags: UpdateFlags):
Result[void, cstring] =
let address_change = signed_address_change.message
@ -746,7 +762,8 @@ proc process_attestation*(
else:
addPendingAttestation(state.previous_epoch_attestations)
elif state is altair.BeaconState or state is bellatrix.BeaconState or
state is capella.BeaconState or state is deneb.BeaconState:
state is capella.BeaconState or state is deneb.BeaconState or
state is electra.BeaconState:
template updateParticipationFlags(epoch_participation: untyped) =
let proposer_reward = get_proposer_reward(
state, attestation, base_reward_per_increment, cache, epoch_participation)
@ -765,7 +782,7 @@ proc process_attestation*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_next_sync_committee_indices
func get_next_sync_committee_keys(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState):
deneb.BeaconState | electra.BeaconState):
array[SYNC_COMMITTEE_SIZE, ValidatorPubKey] =
## Return the sequence of sync committee indices, with possible duplicates,
## for the next sync committee.
@ -825,7 +842,8 @@ func is_partially_withdrawable_validator(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#new-get_expected_withdrawals
func get_expected_withdrawals*(
state: capella.BeaconState | deneb.BeaconState): seq[Withdrawal] =
state: capella.BeaconState | deneb.BeaconState | electra.BeaconState):
seq[Withdrawal] =
let
epoch = get_current_epoch(state)
num_validators = lenu64(state.validators)
@ -862,7 +880,7 @@ func get_expected_withdrawals*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_next_sync_committee
func get_next_sync_committee*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState):
deneb.BeaconState | electra.BeaconState):
SyncCommittee =
## Return the next sync committee, with possible pubkey duplicates.
var res: SyncCommittee
@ -1436,7 +1454,7 @@ func latest_block_root*(state: ForkedHashedBeaconState): Eth2Digest =
func get_sync_committee_cache*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
cache: var StateCache): SyncCommitteeCache =
let period = state.slot.sync_committee_period()

View File

@ -603,6 +603,7 @@ func kzg_commitment_inclusion_proof_gindex*(
# The first member (`randao_reveal`) is 16, subsequent members +1 each.
# If there are ever more than 16 members in `BeaconBlockBody`, indices change!
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/ssz/merkle-proofs.md
debugRaiseAssert "kzg_commitment_inclusion_proof_gindex; ensure still applies to Electra after whatever changes happen"
const
# blob_kzg_commitments
BLOB_KZG_COMMITMENTS_GINDEX =

View File

@ -608,7 +608,9 @@ proc jsonResponseBlock*(t: typedesc[RestApiResponse],
writer.writeField("execution_optimistic", execOpt.get())
writer.writeField("finalized", finalized)
withBlck(data):
writer.writeField("data", forkyBlck)
debugRaiseAssert "jsonResponseBlock: ForkedSignedBeaconBlock"
when consensusFork != ConsensusFork.Electra:
writer.writeField("data", forkyBlck)
writer.endRecord()
stream.getOutput(seq[byte])
except SerializationError:
@ -633,7 +635,9 @@ proc jsonResponseState*(t: typedesc[RestApiResponse],
if execOpt.isSome():
writer.writeField("execution_optimistic", execOpt.get())
withState(data):
writer.writeField("data", forkyState.data)
debugRaiseAssert "jsonResponseBlock: ForkedHashedBeaconState"
when consensusFork != ConsensusFork.Electra:
writer.writeField("data", forkyState.data)
writer.endRecord()
stream.getOutput(seq[byte])
except SerializationError:
@ -1559,6 +1563,9 @@ proc readValue*[BlockType: ProduceBlockResponseV2](
reader.raiseUnexpectedValue("Incorrect deneb block format")
value = ProduceBlockResponseV2(kind: ConsensusFork.Deneb,
denebData: res.get())
of ConsensusFork.Electra:
debugRaiseAssert "readValue ProduceBlockResponseV2"
reader.raiseUnexpectedValue("Incorrect electra block format")
proc readValue*[BlockType: ForkedBlindedBeaconBlock](
reader: var JsonReader[RestJson],
@ -1625,6 +1632,9 @@ proc readValue*[BlockType: ForkedBlindedBeaconBlock](
exc.formatMsg("BlindedBlock") & "]")
value = ForkedBlindedBeaconBlock(kind: ConsensusFork.Deneb,
denebData: res)
of ConsensusFork.Electra:
debugRaiseAssert "readValue ForkedBlindedBeaconBlock"
reader.raiseUnexpectedValue("Electra blinded block format unsupported")
proc readValue*[BlockType: Web3SignerForkedBeaconBlock](
reader: var JsonReader[RestJson],
@ -1927,6 +1937,8 @@ proc readValue*(reader: var JsonReader[RestJson],
assign(
value.denebBody.execution_payload.excess_blob_gas,
ep_src.excess_blob_gas.get())
of ConsensusFork.Electra:
debugRaiseAssert "readValue"
## RestPublishedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson],
@ -2033,6 +2045,16 @@ proc readValue*(reader: var JsonReader[RestJson],
body: body.denebBody
)
)
of ConsensusFork.Electra:
ForkedBeaconBlock.init(
electra.BeaconBlock(
slot: slot.get(),
proposer_index: proposer_index.get(),
parent_root: parent_root.get(),
state_root: state_root.get(),
body: body.electraBody
)
)
)
## RestPublishedSignedBeaconBlock
@ -2099,6 +2121,13 @@ proc readValue*(reader: var JsonReader[RestJson],
signature: signature.get()
)
)
of ConsensusFork.Electra:
ForkedSignedBeaconBlock.init(
electra.SignedBeaconBlock(
message: blck.electraData,
signature: signature.get()
)
)
)
proc readValue*(reader: var JsonReader[RestJson],
@ -2156,6 +2185,8 @@ proc readValue*(reader: var JsonReader[RestJson],
reader.raiseUnexpectedValue("Incorrect signed_block format")
of ConsensusFork.Deneb:
ForkedBeaconBlock.init(blck.denebData.message)
of ConsensusFork.Electra:
ForkedBeaconBlock.init(blck.electraData.message)
))
of "kzg_proofs":
if kzg_proofs.isSome():
@ -2243,6 +2274,16 @@ proc readValue*(reader: var JsonReader[RestJson],
blobs: blobs.get()
)
)
of ConsensusFork.Electra:
value = RestPublishedSignedBlockContents(
kind: ConsensusFork.Electra,
electraData: ElectraSignedBlockContents(
# Constructed to be internally consistent
signed_block: signed_message.get().distinctBase.electraData,
kzg_proofs: kzg_proofs.get(),
blobs: blobs.get()
)
)
## ForkedSignedBeaconBlock
proc readValue*(reader: var JsonReader[RestJson],
@ -2346,6 +2387,9 @@ proc readValue*(reader: var JsonReader[RestJson],
if res.isNone():
reader.raiseUnexpectedValue("Incorrect deneb block format")
value = ForkedSignedBeaconBlock.init(res.get())
of ConsensusFork.Electra:
debugRaiseAssert "readValue 3"
reader.raiseUnexpectedValue("Incorrect electra block format")
withBlck(value):
forkyBlck.root = hash_tree_root(forkyBlck.message)
@ -2369,6 +2413,10 @@ proc writeValue*(
of ConsensusFork.Deneb:
writer.writeField("version", "deneb")
writer.writeField("data", value.denebData)
of ConsensusFork.Electra:
writer.writeField("version", "electra")
debugRaiseAssert "writeValue ForkedSignedBeaconBlock"
#writer.writeField("data", value.electraData)
writer.endRecord()
# ForkedHashedBeaconState is used where a `ForkedBeaconState` normally would
@ -2472,6 +2520,9 @@ proc readValue*(reader: var JsonReader[RestJson],
except SerializationError:
reader.raiseUnexpectedValue("Incorrect deneb beacon state format")
toValue(denebData)
of ConsensusFork.Electra:
debugRaiseAssert "readValue ForkedHashedBeaconState"
reader.raiseUnexpectedValue("Incorrect electra beacon state format")
proc writeValue*(
writer: var JsonWriter[RestJson], value: ForkedHashedBeaconState
@ -2493,6 +2544,10 @@ proc writeValue*(
of ConsensusFork.Deneb:
writer.writeField("version", "deneb")
writer.writeField("data", value.denebData.data)
of ConsensusFork.Electra:
writer.writeField("version", "electra")
debugRaiseAssert "writeValue ForkedHashedBeaconState"
#writer.writeField("data", value.electraData.data)
writer.endRecord()
## SomeForkedLightClientObject
@ -3405,18 +3460,20 @@ proc writeValue*(writer: var JsonWriter[RestJson],
value: ProduceBlockResponseV3) {.raises: [IOError].} =
writer.beginRecord()
withForkyMaybeBlindedBlck(value):
writer.writeField("version", consensusFork.toString())
when isBlinded:
writer.writeField("execution_payload_blinded", "true")
else:
writer.writeField("execution_payload_blinded", "false")
if value.executionValue.isSome():
writer.writeField("execution_payload_value",
$(value.executionValue.get()))
if value.consensusValue.isSome():
writer.writeField("consensus_block_value",
$(value.consensusValue.get()))
writer.writeField("data", forkyMaybeBlindedBlck)
debugRaiseAssert "writeValue ProduceBlockResponseV3"
when consensusFork != ConsensusFork.Electra:
writer.writeField("version", consensusFork.toString())
when isBlinded:
writer.writeField("execution_payload_blinded", "true")
else:
writer.writeField("execution_payload_blinded", "false")
if value.executionValue.isSome():
writer.writeField("execution_payload_value",
$(value.executionValue.get()))
if value.consensusValue.isSome():
writer.writeField("consensus_block_value",
$(value.consensusValue.get()))
writer.writeField("data", forkyMaybeBlindedBlck)
writer.endRecord()
proc readValue*(reader: var JsonReader[RestJson],
@ -3442,7 +3499,9 @@ proc readValue*(reader: var JsonReader[RestJson],
reader.raiseUnexpectedValue("Field `data` is missing")
withConsensusFork(version.get):
when consensusFork >= ConsensusFork.Capella:
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "readValue ProduceBlockResponseV3"
elif consensusFork >= ConsensusFork.Capella:
if blinded.get:
value = ForkedMaybeBlindedBeaconBlock.init(
RestJson.decode(
@ -3560,6 +3619,10 @@ proc decodeBody*(
return err(RestErrorMessage.init(Http400, UnexpectedDecodeError,
[version, $exc.msg]))
ok(RestPublishedSignedBeaconBlock(ForkedSignedBeaconBlock.init(blck)))
of ConsensusFork.Electra:
debugRaiseAssert "decodeBody RestPublishedSignedBeaconBlock"
return err(RestErrorMessage.init(Http400, UnexpectedDecodeError,
[version]))
else:
err(RestErrorMessage.init(Http415, "Invalid content type",
[version, $body.contentType]))
@ -3650,6 +3713,10 @@ proc decodeBody*(
[version, $exc.msg]))
ok(RestPublishedSignedBlockContents(
kind: ConsensusFork.Deneb, denebData: blckContents))
of ConsensusFork.Electra:
debugRaiseAssert "decodeBody RestPublishedSignedBlockContents"
return err(RestErrorMessage.init(
Http400, "electra missing", [version]))
else:
err(RestErrorMessage.init(Http415, "Invalid content type",
[version, $body.contentType]))
@ -3779,6 +3846,11 @@ proc decodeBodyJsonOrSsz*(
[version, $exc.msg]))
ok(RestPublishedSignedBlockContents(
kind: ConsensusFork.Deneb, denebData: blckContents))
of ConsensusFork.Electra:
debugRaiseAssert "decodeBodyJsonOrSsz RestPublishedSignedBlockContents"
return err(
RestErrorMessage.init(Http400, "electra missing",
[version]))
else:
err(RestErrorMessage.init(Http415, "Invalid content type",
[version, $body.contentType]))
@ -3922,6 +3994,9 @@ proc decodeBytes*[T: DecodeConsensysTypes](
let fork = ConsensusFork.decodeString(consensusVersion).valueOr:
return err("Invalid or Unsupported consensus version")
case fork
of ConsensusFork.Electra:
debugRaiseAssert "decodeBytes, DecodeConsensysTypes"
return err("Invalid or Unsupported consensus version")
of ConsensusFork.Deneb:
let blckContents = ? readSszResBytes(deneb.BlockContents, value)
ok(ProduceBlockResponseV2(kind: ConsensusFork.Deneb,
@ -3946,6 +4021,9 @@ proc decodeBytes*[T: DecodeConsensysTypes](
let fork = ConsensusFork.decodeString(consensusVersion).valueOr:
return err("Invalid or Unsupported consensus version")
case fork
of ConsensusFork.Electra:
debugRaiseAssert "decodeBytes DecodeConsensysTypes"
err("Unable to decode blinded block for Electra fork")
of ConsensusFork.Deneb:
let
blck = ? readSszResBytes(deneb_mev.BlindedBeaconBlock, value)
@ -4018,7 +4096,10 @@ proc decodeBytes*[T: ProduceBlockResponseV3](
except ValueError:
return err("Incorrect `Eth-Consensus-Block-Value` header value")
withConsensusFork(fork):
when consensusFork >= ConsensusFork.Capella:
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "decodeBytes ProduceBlockV3"
return err("decodeBytes ProduceBlockV3")
elif consensusFork >= ConsensusFork.Capella:
if blinded:
let contents =
? readSszResBytes(consensusFork.BlindedBlockContents, value)

View File

@ -17,7 +17,7 @@ import
std/[json, tables],
stew/base10, web3/primitives, httputils,
".."/forks,
".."/datatypes/[phase0, altair, bellatrix, deneb],
".."/datatypes/[phase0, altair, bellatrix, deneb, electra],
".."/mev/[capella_mev, deneb_mev]
from ".."/datatypes/capella import BeaconBlockBody
@ -331,6 +331,11 @@ type
kzg_proofs*: deneb.KzgProofs
blobs*: deneb.Blobs
ElectraSignedBlockContents* = object
signed_block*: electra.SignedBeaconBlock
kzg_proofs*: deneb.KzgProofs
blobs*: deneb.Blobs
RestPublishedSignedBlockContents* = object
case kind*: ConsensusFork
of ConsensusFork.Phase0: phase0Data*: phase0.SignedBeaconBlock
@ -338,6 +343,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.SignedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.SignedBeaconBlock
of ConsensusFork.Deneb: denebData*: DenebSignedBlockContents
of ConsensusFork.Electra: electraData*: ElectraSignedBlockContents
RestPublishedBeaconBlock* = distinct ForkedBeaconBlock
@ -348,6 +354,7 @@ type
of ConsensusFork.Bellatrix: bellatrixBody*: bellatrix.BeaconBlockBody
of ConsensusFork.Capella: capellaBody*: capella.BeaconBlockBody
of ConsensusFork.Deneb: denebBody*: deneb.BeaconBlockBody
of ConsensusFork.Electra: electraBody*: electra.BeaconBlockBody
ProduceBlockResponseV2* = object
case kind*: ConsensusFork
@ -356,6 +363,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.BeaconBlock
of ConsensusFork.Capella: capellaData*: capella.BeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.BlockContents
of ConsensusFork.Electra: electraData*: electra.BlockContents
ProduceBlockResponseV3* = ForkedMaybeBlindedBeaconBlock
@ -632,6 +640,8 @@ func init*(T: type ForkedSignedBeaconBlock,
ForkedSignedBeaconBlock.init(contents.capellaData)
of ConsensusFork.Deneb:
ForkedSignedBeaconBlock.init(contents.denebData.signed_block)
of ConsensusFork.Electra:
ForkedSignedBeaconBlock.init(contents.electraData.signed_block)
func init*(t: typedesc[RestPublishedSignedBlockContents],
blck: phase0.BeaconBlock, root: Eth2Digest,
@ -689,6 +699,12 @@ func init*(t: typedesc[RestPublishedSignedBlockContents],
)
)
func init*(t: typedesc[RestPublishedSignedBlockContents],
contents: electra.BeaconBlock, root: Eth2Digest,
signature: ValidatorSig): RestPublishedSignedBlockContents =
debugRaiseAssert "init*(t: typedesc[RestPublishedSignedBlockContents],"
default(RestPublishedSignedBlockContents)
func init*(t: typedesc[StateIdent], v: StateIdentType): StateIdent =
StateIdent(kind: StateQueryKind.Named, value: v)
@ -1025,3 +1041,7 @@ template withBlck*(x: ProduceBlockResponseV2,
const consensusFork {.inject, used.} = ConsensusFork.Deneb
template blck: untyped {.inject.} = x.denebData.blck
body
of ConsensusFork.Electra:
const consensusFork {.inject, used.} = ConsensusFork.Electra
template blck: untyped {.inject.} = x.electraData.blck
body

View File

@ -46,7 +46,8 @@ type
Altair,
Bellatrix,
Capella,
Deneb
Deneb,
Electra
ForkyBeaconState* =
phase0.BeaconState |
@ -71,6 +72,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.HashedBeaconState
of ConsensusFork.Capella: capellaData*: capella.HashedBeaconState
of ConsensusFork.Deneb: denebData*: deneb.HashedBeaconState
of ConsensusFork.Electra: electraData*: electra.HashedBeaconState
ForkyExecutionPayload* =
bellatrix.ExecutionPayload |
@ -158,6 +160,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.BeaconBlock
of ConsensusFork.Capella: capellaData*: capella.BeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.BeaconBlock
of ConsensusFork.Electra: electraData*: electra.BeaconBlock
ForkedMaybeBlindedBeaconBlock* = object
case kind*: ConsensusFork
@ -171,6 +174,8 @@ type
capellaData*: capella_mev.MaybeBlindedBeaconBlock
of ConsensusFork.Deneb:
denebData*: deneb_mev.MaybeBlindedBeaconBlock
of ConsensusFork.Electra:
electraData*: electra.BeaconBlock
consensusValue*: Opt[UInt256]
executionValue*: Opt[UInt256]
@ -185,6 +190,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix_mev.BlindedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella_mev.BlindedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb_mev.BlindedBeaconBlock
of ConsensusFork.Electra: electraData*: electra.BeaconBlock
ForkedTrustedBeaconBlock* = object
case kind*: ConsensusFork
@ -193,6 +199,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.TrustedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.TrustedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.TrustedBeaconBlock
of ConsensusFork.Electra: electraData*: electra.TrustedBeaconBlock
ForkySignedBeaconBlock* =
phase0.SignedBeaconBlock |
@ -209,6 +216,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.SignedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.SignedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.SignedBeaconBlock
of ConsensusFork.Electra: electraData*: electra.SignedBeaconBlock
ForkySignedBlindedBeaconBlock* =
phase0.SignedBeaconBlock |
@ -224,6 +232,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix_mev.SignedBlindedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella_mev.SignedBlindedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb_mev.SignedBlindedBeaconBlock
of ConsensusFork.Electra: electraData*: electra.SignedBeaconBlock
ForkySigVerifiedSignedBeaconBlock* =
phase0.SigVerifiedSignedBeaconBlock |
@ -256,6 +265,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.MsgTrustedSignedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.MsgTrustedSignedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.MsgTrustedSignedBeaconBlock
of ConsensusFork.Electra: electraData*: electra.MsgTrustedSignedBeaconBlock
ForkedTrustedSignedBeaconBlock* = object
case kind*: ConsensusFork
@ -264,6 +274,7 @@ type
of ConsensusFork.Bellatrix: bellatrixData*: bellatrix.TrustedSignedBeaconBlock
of ConsensusFork.Capella: capellaData*: capella.TrustedSignedBeaconBlock
of ConsensusFork.Deneb: denebData*: deneb.TrustedSignedBeaconBlock
of ConsensusFork.Electra: electraData*: electra.TrustedSignedBeaconBlock
SomeForkySignedBeaconBlock* =
ForkySignedBeaconBlock |
@ -377,8 +388,28 @@ template kind*(
deneb_mev.SignedBlindedBeaconBlock]): ConsensusFork =
ConsensusFork.Deneb
template kind*(
x: typedesc[
electra.BeaconState |
electra.HashedBeaconState |
electra.ExecutionPayload |
electra.ExecutionPayloadForSigning |
electra.ExecutionPayloadHeader |
electra.BeaconBlock |
electra.SignedBeaconBlock |
electra.TrustedBeaconBlock |
electra.BeaconBlockBody |
electra.SigVerifiedBeaconBlockBody |
electra.TrustedBeaconBlockBody |
electra.SigVerifiedSignedBeaconBlock |
electra.MsgTrustedSignedBeaconBlock |
electra.TrustedSignedBeaconBlock]): ConsensusFork =
ConsensusFork.Electra
template BeaconState*(kind: static ConsensusFork): auto =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
typedesc[electra.BeaconState]
elif kind == ConsensusFork.Deneb:
typedesc[deneb.BeaconState]
elif kind == ConsensusFork.Capella:
typedesc[capella.BeaconState]
@ -392,7 +423,9 @@ template BeaconState*(kind: static ConsensusFork): auto =
static: raiseAssert "Unreachable"
template BeaconBlock*(kind: static ConsensusFork): auto =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
typedesc[electra.BeaconBlock]
elif kind == ConsensusFork.Deneb:
typedesc[deneb.BeaconBlock]
elif kind == ConsensusFork.Capella:
typedesc[capella.BeaconBlock]
@ -406,7 +439,9 @@ template BeaconBlock*(kind: static ConsensusFork): auto =
static: raiseAssert "Unreachable"
template BeaconBlockBody*(kind: static ConsensusFork): auto =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
typedesc[electra.BeaconBlockBody]
elif kind == ConsensusFork.Deneb:
typedesc[deneb.BeaconBlockBody]
elif kind == ConsensusFork.Capella:
typedesc[capella.BeaconBlockBody]
@ -420,7 +455,9 @@ template BeaconBlockBody*(kind: static ConsensusFork): auto =
static: raiseAssert "Unreachable"
template SignedBeaconBlock*(kind: static ConsensusFork): auto =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
typedesc[electra.SignedBeaconBlock]
elif kind == ConsensusFork.Deneb:
typedesc[deneb.SignedBeaconBlock]
elif kind == ConsensusFork.Capella:
typedesc[capella.SignedBeaconBlock]
@ -434,7 +471,9 @@ template SignedBeaconBlock*(kind: static ConsensusFork): auto =
static: raiseAssert "Unreachable"
template TrustedSignedBeaconBlock*(kind: static ConsensusFork): auto =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
typedesc[electra.TrustedSignedBeaconBlock]
elif kind == ConsensusFork.Deneb:
typedesc[deneb.TrustedSignedBeaconBlock]
elif kind == ConsensusFork.Capella:
typedesc[capella.TrustedSignedBeaconBlock]
@ -448,7 +487,9 @@ template TrustedSignedBeaconBlock*(kind: static ConsensusFork): auto =
static: raiseAssert "Unreachable"
template ExecutionPayloadForSigning*(kind: static ConsensusFork): auto =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
typedesc[electra.ExecutionPayloadForSigning]
elif kind == ConsensusFork.Deneb:
typedesc[deneb.ExecutionPayloadForSigning]
elif kind == ConsensusFork.Capella:
typedesc[capella.ExecutionPayloadForSigning]
@ -489,7 +530,10 @@ template SignedBlindedBeaconBlock*(kind: static ConsensusFork): auto =
template withAll*(
x: typedesc[ConsensusFork], body: untyped): untyped =
static: doAssert ConsensusFork.high == ConsensusFork.Deneb
static: doAssert ConsensusFork.high == ConsensusFork.Electra
block:
const consensusFork {.inject, used.} = ConsensusFork.Electra
body
block:
const consensusFork {.inject, used.} = ConsensusFork.Deneb
body
@ -509,6 +553,9 @@ template withAll*(
template withConsensusFork*(
x: ConsensusFork, body: untyped): untyped =
case x
of ConsensusFork.Electra:
const consensusFork {.inject, used.} = ConsensusFork.Electra
body
of ConsensusFork.Deneb:
const consensusFork {.inject, used.} = ConsensusFork.Deneb
body
@ -567,8 +614,9 @@ template PayloadAttributes*(
{.error: "PayloadAttributes does not support " & $kind.}
# `eth2_merkleization` cannot import `forks` (circular), so the check is here
static: doAssert ConsensusFork.high == ConsensusFork.Deneb,
"eth2_merkleization has been checked and `hash_tree_root` is up to date"
debugRaiseAssert "eth2_merkleization has been checked and `hash_tree_root` is up to date"
static: doAssert ConsensusFork.high == ConsensusFork.Electra,
"eth2_merkleization has been checked and `hash_tree_root` is up to date" # TODO
# TODO when https://github.com/nim-lang/Nim/issues/21086 fixed, use return type
# `ref T`
@ -592,6 +640,10 @@ func new*(T: type ForkedHashedBeaconState, data: deneb.BeaconState):
ref ForkedHashedBeaconState =
(ref T)(kind: ConsensusFork.Deneb, denebData: deneb.HashedBeaconState(
data: data, root: hash_tree_root(data)))
func new*(T: type ForkedHashedBeaconState, data: electra.BeaconState):
ref ForkedHashedBeaconState =
(ref T)(kind: ConsensusFork.Electra, electraData: electra.HashedBeaconState(
data: data, root: hash_tree_root(data)))
template init*(T: type ForkedBeaconBlock, blck: phase0.BeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
@ -603,7 +655,10 @@ template init*(T: type ForkedBeaconBlock, blck: capella.BeaconBlock): T =
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedBeaconBlock, blck: deneb.BeaconBlock): T =
T(kind: ConsensusFork.Deneb, denebData: blck)
template init*(T: type ForkedBeaconBlock, blck: electra.BeaconBlock): T =
T(kind: ConsensusFork.Electra, electraData: blck)
# TODO are these still used?
template init*(T: type ForkedTrustedBeaconBlock, blck: phase0.TrustedBeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
template init*(T: type ForkedTrustedBeaconBlock, blck: altair.TrustedBeaconBlock): T =
@ -623,6 +678,8 @@ template init*(T: type ForkedSignedBeaconBlock, blck: capella.SignedBeaconBlock)
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: deneb.SignedBeaconBlock): T =
T(kind: ConsensusFork.Deneb, denebData: blck)
template init*(T: type ForkedSignedBeaconBlock, blck: electra.SignedBeaconBlock): T =
T(kind: ConsensusFork.Electra, electraData: blck)
func init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
blockRoot: Eth2Digest, signature: ValidatorSig): T =
@ -652,6 +709,11 @@ func init*(T: type ForkedSignedBeaconBlock, forked: ForkedBeaconBlock,
denebData: deneb.SignedBeaconBlock(message: forked.denebData,
root: blockRoot,
signature: signature))
of ConsensusFork.Electra:
T(kind: ConsensusFork.Electra,
electraData: electra.SignedBeaconBlock(message: forked.electraData,
root: blockRoot,
signature: signature))
func init*(T: type ForkedSignedBlindedBeaconBlock,
forked: ForkedBlindedBeaconBlock, blockRoot: Eth2Digest,
@ -678,6 +740,9 @@ func init*(T: type ForkedSignedBlindedBeaconBlock,
T(kind: ConsensusFork.Deneb,
denebData: deneb_mev.SignedBlindedBeaconBlock(message: forked.denebData,
signature: signature))
of ConsensusFork.Electra:
debugRaiseAssert "init*(T: type ForkedSignedBlindedBeaconBlock"
T(kind: ConsensusFork.Electra)
template init*(T: type ForkedSignedBlindedBeaconBlock,
blck: capella_mev.BlindedBeaconBlock, blockRoot: Eth2Digest,
@ -703,6 +768,8 @@ template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: capella.MsgTrust
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: deneb.MsgTrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Deneb, denebData: blck)
template init*(T: type ForkedMsgTrustedSignedBeaconBlock, blck: electra.MsgTrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Electra, electraData: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: phase0.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Phase0, phase0Data: blck)
@ -714,6 +781,8 @@ template init*(T: type ForkedTrustedSignedBeaconBlock, blck: capella.TrustedSign
T(kind: ConsensusFork.Capella, capellaData: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: deneb.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Deneb, denebData: blck)
template init*(T: type ForkedTrustedSignedBeaconBlock, blck: electra.TrustedSignedBeaconBlock): T =
T(kind: ConsensusFork.Electra, electraData: blck)
template toString*(kind: ConsensusFork): string =
case kind
@ -727,9 +796,13 @@ template toString*(kind: ConsensusFork): string =
"capella"
of ConsensusFork.Deneb:
"deneb"
of ConsensusFork.Electra:
"electra"
template init*(T: typedesc[ConsensusFork], value: string): Opt[ConsensusFork] =
case value
of "electra":
Opt.some ConsensusFork.Electra
of "deneb":
Opt.some ConsensusFork.Deneb
of "capella":
@ -754,6 +827,10 @@ template init*(T: type ForkedEpochInfo, info: altair.EpochInfo): T =
template withState*(x: ForkedHashedBeaconState, body: untyped): untyped =
case x.kind
of ConsensusFork.Electra:
const consensusFork {.inject, used.} = ConsensusFork.Electra
template forkyState: untyped {.inject, used.} = x.electraData
body
of ConsensusFork.Deneb:
const consensusFork {.inject, used.} = ConsensusFork.Deneb
template forkyState: untyped {.inject, used.} = x.denebData
@ -780,7 +857,9 @@ template forky*(
ForkedBeaconBlock |
ForkedHashedBeaconState,
kind: static ConsensusFork): untyped =
when kind == ConsensusFork.Deneb:
when kind == ConsensusFork.Electra:
x.electraData
elif kind == ConsensusFork.Deneb:
x.denebData
elif kind == ConsensusFork.Capella:
x.capellaData
@ -855,6 +934,8 @@ func setStateRoot*(x: var ForkedHashedBeaconState, root: Eth2Digest) =
func consensusForkEpoch*(
cfg: RuntimeConfig, consensusFork: ConsensusFork): Epoch =
case consensusFork
of ConsensusFork.Electra:
cfg.ELECTRA_FORK_EPOCH
of ConsensusFork.Deneb:
cfg.DENEB_FORK_EPOCH
of ConsensusFork.Capella:
@ -869,14 +950,16 @@ func consensusForkEpoch*(
func consensusForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): ConsensusFork =
## Return the current fork for the given epoch.
static:
doAssert high(ConsensusFork) == ConsensusFork.Deneb
doAssert high(ConsensusFork) == ConsensusFork.Electra
doAssert ConsensusFork.Electra > ConsensusFork.Deneb
doAssert ConsensusFork.Deneb > ConsensusFork.Capella
doAssert ConsensusFork.Capella > ConsensusFork.Bellatrix
doAssert ConsensusFork.Bellatrix > ConsensusFork.Altair
doAssert ConsensusFork.Altair > ConsensusFork.Phase0
doAssert GENESIS_EPOCH == 0
if epoch >= cfg.DENEB_FORK_EPOCH: ConsensusFork.Deneb
if epoch >= cfg.ELECTRA_FORK_EPOCH: ConsensusFork.Electra
elif epoch >= cfg.DENEB_FORK_EPOCH: ConsensusFork.Deneb
elif epoch >= cfg.CAPELLA_FORK_EPOCH: ConsensusFork.Capella
elif epoch >= cfg.BELLATRIX_FORK_EPOCH: ConsensusFork.Bellatrix
elif epoch >= cfg.ALTAIR_FORK_EPOCH: ConsensusFork.Altair
@ -884,8 +967,10 @@ func consensusForkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): ConsensusFork =
func consensusForkForDigest*(
forkDigests: ForkDigests, forkDigest: ForkDigest): Opt[ConsensusFork] =
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
if forkDigest == forkDigests.deneb:
static: doAssert high(ConsensusFork) == ConsensusFork.Electra
if forkDigest == forkDigests.electra:
ok ConsensusFork.Electra
elif forkDigest == forkDigests.deneb:
ok ConsensusFork.Deneb
elif forkDigest == forkDigests.capella:
ok ConsensusFork.Capella
@ -901,6 +986,8 @@ func consensusForkForDigest*(
func atConsensusFork*(
forkDigests: ForkDigests, consensusFork: ConsensusFork): ForkDigest =
case consensusFork
of ConsensusFork.Electra:
forkDigests.electra
of ConsensusFork.Deneb:
forkDigests.deneb
of ConsensusFork.Capella:
@ -979,6 +1066,10 @@ template withBlck*(
const consensusFork {.inject, used.} = ConsensusFork.Deneb
template forkyBlck: untyped {.inject, used.} = x.denebData
body
of ConsensusFork.Electra:
const consensusFork {.inject, used.} = ConsensusFork.Electra
template forkyBlck: untyped {.inject, used.} = x.electraData
body
func proposer_index*(x: ForkedBeaconBlock): uint64 =
withBlck(x): forkyBlck.proposer_index
@ -1002,7 +1093,8 @@ template getForkedBlockField*(
of ConsensusFork.Altair: unsafeAddr x.altairData.message.y
of ConsensusFork.Bellatrix: unsafeAddr x.bellatrixData.message.y
of ConsensusFork.Capella: unsafeAddr x.capellaData.message.y
of ConsensusFork.Deneb: unsafeAddr x.denebData.message.y)[]
of ConsensusFork.Deneb: unsafeAddr x.denebData.message.y
of ConsensusFork.Electra: unsafeAddr x.electraData.message.y)[]
template signature*(x: ForkedSignedBeaconBlock |
ForkedMsgTrustedSignedBeaconBlock |
@ -1040,6 +1132,12 @@ template withForkyMaybeBlindedBlck*(
b: ForkedMaybeBlindedBeaconBlock,
body: untyped): untyped =
case b.kind
of ConsensusFork.Electra:
const
consensusFork {.inject, used.} = ConsensusFork.Electra
isBlinded {.inject, used.} = false
template forkyMaybeBlindedBlck: untyped {.inject, used.} = b.electraData
body
of ConsensusFork.Deneb:
const consensusFork {.inject, used.} = ConsensusFork.Deneb
template d: untyped = b.denebData
@ -1090,6 +1188,11 @@ template withStateAndBlck*(
ForkedTrustedSignedBeaconBlock,
body: untyped): untyped =
case s.kind
of ConsensusFork.Electra:
const consensusFork {.inject, used.} = ConsensusFork.Electra
template forkyState: untyped {.inject.} = s.electraData
template forkyBlck: untyped {.inject.} = b.electraData
body
of ConsensusFork.Deneb:
const consensusFork {.inject, used.} = ConsensusFork.Deneb
template forkyState: untyped {.inject.} = s.denebData
@ -1188,6 +1291,7 @@ func electraFork*(cfg: RuntimeConfig): Fork =
func forkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Fork =
case cfg.consensusForkAtEpoch(epoch)
of ConsensusFork.Electra: cfg.electraFork
of ConsensusFork.Deneb: cfg.denebFork
of ConsensusFork.Capella: cfg.capellaFork
of ConsensusFork.Bellatrix: cfg.bellatrixFork
@ -1196,6 +1300,7 @@ func forkAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Fork =
func forkVersionAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Version =
case cfg.consensusForkAtEpoch(epoch)
of ConsensusFork.Electra: cfg.ELECTRA_FORK_VERSION
of ConsensusFork.Deneb: cfg.DENEB_FORK_VERSION
of ConsensusFork.Capella: cfg.CAPELLA_FORK_VERSION
of ConsensusFork.Bellatrix: cfg.BELLATRIX_FORK_VERSION
@ -1203,9 +1308,9 @@ func forkVersionAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Version =
of ConsensusFork.Phase0: cfg.GENESIS_FORK_VERSION
func nextForkEpochAtEpoch*(cfg: RuntimeConfig, epoch: Epoch): Epoch =
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
case cfg.consensusForkAtEpoch(epoch)
of ConsensusFork.Deneb: FAR_FUTURE_EPOCH
of ConsensusFork.Electra: FAR_FUTURE_EPOCH
of ConsensusFork.Deneb: cfg.ELECTRA_FORK_EPOCH
of ConsensusFork.Capella: cfg.DENEB_FORK_EPOCH
of ConsensusFork.Bellatrix: cfg.CAPELLA_FORK_EPOCH
of ConsensusFork.Altair: cfg.BELLATRIX_FORK_EPOCH
@ -1218,6 +1323,7 @@ func forkVersion*(cfg: RuntimeConfig, consensusFork: ConsensusFork): Version =
of ConsensusFork.Bellatrix: cfg.BELLATRIX_FORK_VERSION
of ConsensusFork.Capella: cfg.CAPELLA_FORK_VERSION
of ConsensusFork.Deneb: cfg.DENEB_FORK_VERSION
of ConsensusFork.Electra: cfg.ELECTRA_FORK_VERSION
func lcDataForkAtConsensusFork*(
consensusFork: ConsensusFork): LightClientDataFork =
@ -1325,7 +1431,7 @@ func compute_fork_digest*(current_version: Version,
func init*(T: type ForkDigests,
cfg: RuntimeConfig,
genesis_validators_root: Eth2Digest): T =
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
static: doAssert high(ConsensusFork) == ConsensusFork.Electra
T(
phase0:
compute_fork_digest(cfg.GENESIS_FORK_VERSION, genesis_validators_root),

View File

@ -8,7 +8,7 @@
{.push raises: [].}
import
./datatypes/[phase0, altair, bellatrix, capella, deneb],
./datatypes/[phase0, altair, bellatrix, capella, deneb, electra],
./eth2_merkleization
type
@ -957,9 +957,14 @@ func toLightClientHeader*(
altair.SignedBeaconBlock | altair.TrustedSignedBeaconBlock |
bellatrix.SignedBeaconBlock | bellatrix.TrustedSignedBeaconBlock |
capella.SignedBeaconBlock | capella.TrustedSignedBeaconBlock |
deneb.SignedBeaconBlock | deneb.TrustedSignedBeaconBlock,
deneb.SignedBeaconBlock | deneb.TrustedSignedBeaconBlock |
electra.SignedBeaconBlock | electra.TrustedSignedBeaconBlock,
kind: static LightClientDataFork): auto =
when kind == LightClientDataFork.Deneb:
when blck is electra.SignedBeaconBlock or
blck is electra.TrustedSignedBeaconBlock:
debugRaiseAssert "toLightClientHeader"
default(deneb.LightClientHeader)
elif kind == LightClientDataFork.Deneb:
blck.toDenebLightClientHeader()
elif kind == LightClientDataFork.Capella:
blck.toCapellaLightClientHeader()

View File

@ -228,7 +228,7 @@ func verify_blob_sidecar_inclusion_proof*(
ok()
func create_blob_sidecars*(
forkyBlck: deneb.SignedBeaconBlock,
forkyBlck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock,
kzg_proofs: KzgProofs,
blobs: Blobs): seq[BlobSidecar] =
template kzg_commitments: untyped =
@ -382,7 +382,8 @@ func contextEpoch*(update: SomeForkyLightClientUpdate): Epoch =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#is_merge_transition_complete
func is_merge_transition_complete*(
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState): bool =
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState |
electra.BeaconState): bool =
const defaultExecutionPayloadHeader =
default(typeof(state.latest_execution_payload_header))
state.latest_execution_payload_header != defaultExecutionPayloadHeader
@ -398,26 +399,32 @@ func is_execution_block*(blck: SomeForkyBeaconBlock): bool =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#is_merge_transition_block
func is_merge_transition_block(
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState,
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState |
electra.BeaconState,
body: bellatrix.BeaconBlockBody | bellatrix.TrustedBeaconBlockBody |
bellatrix.SigVerifiedBeaconBlockBody |
capella.BeaconBlockBody | capella.TrustedBeaconBlockBody |
capella.SigVerifiedBeaconBlockBody |
deneb.BeaconBlockBody | deneb.TrustedBeaconBlockBody |
deneb.SigVerifiedBeaconBlockBody): bool =
deneb.SigVerifiedBeaconBlockBody |
electra.BeaconBlockBody | electra.TrustedBeaconBlockBody |
electra.SigVerifiedBeaconBlockBody): bool =
const defaultExecutionPayload = default(typeof(body.execution_payload))
not is_merge_transition_complete(state) and
body.execution_payload != defaultExecutionPayload
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#is_execution_enabled
func is_execution_enabled*(
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState,
state: bellatrix.BeaconState | capella.BeaconState | deneb.BeaconState |
electra.BeaconState,
body: bellatrix.BeaconBlockBody | bellatrix.TrustedBeaconBlockBody |
bellatrix.SigVerifiedBeaconBlockBody |
capella.BeaconBlockBody | capella.TrustedBeaconBlockBody |
capella.SigVerifiedBeaconBlockBody |
deneb.BeaconBlockBody | deneb.TrustedBeaconBlockBody |
deneb.SigVerifiedBeaconBlockBody): bool =
deneb.SigVerifiedBeaconBlockBody |
electra.BeaconBlockBody | electra.TrustedBeaconBlockBody |
electra.SigVerifiedBeaconBlockBody): bool =
is_merge_transition_block(state, body) or is_merge_transition_complete(state)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/bellatrix/beacon-chain.md#compute_timestamp_at_slot
@ -449,8 +456,8 @@ func toExecutionWithdrawal*(
# https://eips.ethereum.org/EIPS/eip-4895
proc computeWithdrawalsTrieRoot*(
payload: capella.ExecutionPayload | deneb.ExecutionPayload
): ExecutionHash256 =
payload: capella.ExecutionPayload | deneb.ExecutionPayload |
electra.ExecutionPayload): ExecutionHash256 =
if payload.withdrawals.len == 0:
return EMPTY_ROOT_HASH

View File

@ -159,18 +159,15 @@ func noRollback*(state: var altair.HashedBeaconState) =
func noRollback*(state: var bellatrix.HashedBeaconState) =
trace "Skipping rollback of broken Bellatrix state"
from ./datatypes/capella import
ExecutionPayload, HashedBeaconState, SignedBLSToExecutionChangeList,
asSigVerified
func noRollback*(state: var capella.HashedBeaconState) =
trace "Skipping rollback of broken Capella state"
from ./datatypes/deneb import HashedBeaconState
func noRollback*(state: var deneb.HashedBeaconState) =
trace "Skipping rollback of broken Deneb state"
func noRollback*(state: var electra.HashedBeaconState) =
trace "Skipping rollback of broken Electra state"
func maybeUpgradeStateToAltair(
cfg: RuntimeConfig, state: var ForkedHashedBeaconState) =
# Both process_slots() and state_transition_block() call this, so only run it
@ -225,6 +222,7 @@ func maybeUpgradeState*(
cfg.maybeUpgradeStateToBellatrix(state)
cfg.maybeUpgradeStateToCapella(state)
cfg.maybeUpgradeStateToDeneb(state)
# TODO cfg.maybeUpgradeStateToElectra
proc process_slots*(
cfg: RuntimeConfig, state: var ForkedHashedBeaconState, slot: Slot,
@ -477,6 +475,8 @@ proc makeBeaconBlock*(
])
else:
raiseAssert "Attempt to use non-Deneb payload with post-Deneb state"
elif consensusFork == ConsensusFork.Electra:
debugRaiseAssert "makeBeaconBlock"
else:
static: raiseAssert "Unreachable"
@ -501,6 +501,10 @@ proc makeBeaconBlock*(
case state.kind
of ConsensusFork.Deneb: makeBeaconBlock(deneb)
else: raiseAssert "Attempt to use Deneb payload with non-Deneb state"
elif payloadFork == ConsensusFork.Electra:
case state.kind
of ConsensusFork.Electra: makeBeaconBlock(electra)
else: raiseAssert "Attempt to use Electra payload with non-Electra state"
else:
{.error: "Unsupported fork".}

View File

@ -415,7 +415,8 @@ proc process_voluntary_exit*(
ok()
proc process_bls_to_execution_change*(
cfg: RuntimeConfig, state: var (capella.BeaconState | deneb.BeaconState),
cfg: RuntimeConfig,
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState),
signed_address_change: SignedBLSToExecutionChange): Result[void, cstring] =
? check_bls_to_execution_change(
cfg.genesisFork, state, signed_address_change, {})
@ -486,7 +487,7 @@ func get_proposer_reward*(participant_reward: Gwei): Gwei =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#sync-aggregate-processing
proc process_sync_aggregate*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
sync_aggregate: SomeSyncAggregate, total_active_balance: Gwei,
flags: UpdateFlags,
cache: var StateCache):
@ -687,10 +688,67 @@ proc process_execution_payload*(
ok()
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
# copy of datatypes/electra.nim
type SomeElectraBeaconBlockBody =
electra.BeaconBlockBody | electra.SigVerifiedBeaconBlockBody |
electra.TrustedBeaconBlockBody
# TODO spec ref URL when available
proc process_execution_payload*(
state: var electra.BeaconState, body: SomeElectraBeaconBlockBody,
notify_new_payload: electra.ExecutePayload): Result[void, cstring] =
template payload: auto = body.execution_payload
# Verify consistency of the parent hash with respect to the previous
# execution payload header
if not (payload.parent_hash ==
state.latest_execution_payload_header.block_hash):
return err("process_execution_payload: payload and state parent hash mismatch")
# Verify prev_randao
if not (payload.prev_randao == get_randao_mix(state, get_current_epoch(state))):
return err("process_execution_payload: payload and state randomness mismatch")
# Verify timestamp
if not (payload.timestamp == compute_timestamp_at_slot(state, state.slot)):
return err("process_execution_payload: invalid timestamp")
# [New in Deneb] Verify commitments are under limit
if not (lenu64(body.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK):
return err("process_execution_payload: too many KZG commitments")
# Verify the execution payload is valid
if not notify_new_payload(payload):
return err("process_execution_payload: execution payload invalid")
# Cache execution payload header
state.latest_execution_payload_header = electra.ExecutionPayloadHeader(
parent_hash: payload.parent_hash,
fee_recipient: payload.fee_recipient,
state_root: payload.state_root,
receipts_root: payload.receipts_root,
logs_bloom: payload.logs_bloom,
prev_randao: payload.prev_randao,
block_number: payload.block_number,
gas_limit: payload.gas_limit,
gas_used: payload.gas_used,
timestamp: payload.timestamp,
base_fee_per_gas: payload.base_fee_per_gas,
block_hash: payload.block_hash,
extra_data: payload.extra_data,
transactions_root: hash_tree_root(payload.transactions),
withdrawals_root: hash_tree_root(payload.withdrawals),
blob_gas_used: payload.blob_gas_used,
excess_blob_gas: payload.excess_blob_gas)
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/capella/beacon-chain.md#new-process_withdrawals
func process_withdrawals*(
state: var (capella.BeaconState | deneb.BeaconState),
payload: capella.ExecutionPayload | deneb.ExecutionPayload):
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState),
payload: capella.ExecutionPayload | deneb.ExecutionPayload |
electra.ExecutionPayload):
Result[void, cstring] =
let expected_withdrawals = get_expected_withdrawals(state)
@ -902,3 +960,38 @@ proc process_block*(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/deneb/beacon-chain.md#block-processing
# TODO workaround for https://github.com/nim-lang/Nim/issues/18095
type SomeElectraBlock =
electra.BeaconBlock | electra.SigVerifiedBeaconBlock | electra.TrustedBeaconBlock
proc process_block*(
cfg: RuntimeConfig,
state: var electra.BeaconState, blck: SomeElectraBlock,
flags: UpdateFlags, cache: var StateCache): Result[void, cstring]=
## When there's a new block, we need to verify that the block is sane and
## update the state accordingly - the state is left in an unknown state when
## block application fails (!)
? process_block_header(state, blck, flags, cache)
# Consensus specs v1.4.0 unconditionally assume is_execution_enabled is
# true, but intentionally keep such a check.
if is_execution_enabled(state, blck.body):
? process_withdrawals(state, blck.body.execution_payload)
? process_execution_payload(
state, blck.body,
func(_: electra.ExecutionPayload): bool = true)
? process_randao(state, blck.body, flags, cache)
? process_eth1_data(state, blck.body)
let
total_active_balance = get_total_active_balance(state, cache)
base_reward_per_increment =
get_base_reward_per_increment(total_active_balance)
? process_operations(
cfg, state, blck.body, base_reward_per_increment, flags, cache)
? process_sync_aggregate(
state, blck.body.sync_aggregate, total_active_balance, flags, cache)
ok()

View File

@ -177,7 +177,8 @@ from ./datatypes/deneb import BeaconState
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_unslashed_participating_indices
func get_unslashed_participating_balances*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState): UnslashedParticipatingBalances =
deneb.BeaconState | electra.BeaconState):
UnslashedParticipatingBalances =
let
previous_epoch = get_previous_epoch(state)
current_epoch = get_current_epoch(state)
@ -228,7 +229,7 @@ func get_unslashed_participating_balances*(
func is_unslashed_participating_index(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
flag_index: TimelyFlag, epoch: Epoch, validator_index: ValidatorIndex): bool =
doAssert epoch in [get_previous_epoch(state), get_current_epoch(state)]
# TODO hoist this conditional
@ -445,7 +446,7 @@ proc compute_unrealized_finality*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#justification-and-finalization
proc process_justification_and_finalization*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
balances: UnslashedParticipatingBalances,
flags: UpdateFlags = {}) =
# Initial FFG checkpoint values have a `0x00` stub for `root`.
@ -467,7 +468,7 @@ proc process_justification_and_finalization*(
proc compute_unrealized_finality*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState): FinalityCheckpoints =
deneb.BeaconState | electra.BeaconState): FinalityCheckpoints =
if get_current_epoch(state) <= GENESIS_EPOCH + 1:
return FinalityCheckpoints(
justified: state.current_justified_checkpoint,
@ -658,7 +659,7 @@ func get_attestation_deltas(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_base_reward
func get_base_reward_increment*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
index: ValidatorIndex, base_reward_per_increment: Gwei): Gwei =
## Return the base reward for the validator defined by ``index`` with respect
## to the current ``state``.
@ -669,7 +670,7 @@ func get_base_reward_increment*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#get_flag_index_deltas
func get_flag_index_reward*(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
base_reward: Gwei, active_increments: Gwei,
unslashed_participating_increments: Gwei,
weight, finality_delay: uint64): Gwei =
@ -697,7 +698,7 @@ func get_active_increments*(
iterator get_flag_and_inactivity_deltas*(
cfg: RuntimeConfig,
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
base_reward_per_increment: Gwei, info: var altair.EpochInfo,
finality_delay: uint64):
(ValidatorIndex, Gwei, Gwei, Gwei, Gwei, Gwei, Gwei) =
@ -807,7 +808,7 @@ func process_rewards_and_penalties*(
func process_rewards_and_penalties*(
cfg: RuntimeConfig,
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
info: var altair.EpochInfo) =
if get_current_epoch(state) == GENESIS_EPOCH:
return
@ -914,7 +915,7 @@ func get_adjusted_total_slashing_balance*(
elif state is altair.BeaconState:
PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR
elif state is bellatrix.BeaconState or state is capella.BeaconState or
state is deneb.BeaconState:
state is deneb.BeaconState or state is electra.BeaconState:
PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX
else:
{.fatal: "process_slashings: incorrect BeaconState type".}
@ -1037,7 +1038,8 @@ func process_participation_record_updates*(state: var phase0.BeaconState) =
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#participation-flags-updates
func process_participation_flag_updates*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState)) =
capella.BeaconState | deneb.BeaconState |
electra.BeaconState)) =
state.previous_epoch_participation = state.current_epoch_participation
const zero = 0.ParticipationFlags
@ -1051,7 +1053,8 @@ func process_participation_flag_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#sync-committee-updates
func process_sync_committee_updates*(
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState)) =
capella.BeaconState | deneb.BeaconState |
electra.BeaconState)) =
let next_epoch = get_current_epoch(state) + 1
if next_epoch.is_sync_committee_period():
state.current_sync_committee = state.next_sync_committee
@ -1060,7 +1063,7 @@ func process_sync_committee_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/altair/beacon-chain.md#inactivity-scores
template compute_inactivity_update(
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState,
deneb.BeaconState | electra.BeaconState,
info: altair.EpochInfo, pre_inactivity_score: Gwei): Gwei =
if not is_eligible_validator(info.validators[index]):
continue
@ -1086,7 +1089,7 @@ template compute_inactivity_update(
func process_inactivity_updates*(
cfg: RuntimeConfig,
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
info: altair.EpochInfo) =
# Score updates based on previous epoch participation, skip genesis epoch
if get_current_epoch(state) == GENESIS_EPOCH:
@ -1108,7 +1111,7 @@ func process_inactivity_updates*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#historical-summaries-updates
func process_historical_summaries_update*(
state: var (capella.BeaconState | deneb.BeaconState)):
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState)):
Result[void, cstring] =
# Set historical block root accumulator.
let next_epoch = get_current_epoch(state) + 1
@ -1159,7 +1162,7 @@ proc process_epoch*(
func init*(
info: var altair.EpochInfo,
state: altair.BeaconState | bellatrix.BeaconState | capella.BeaconState |
deneb.BeaconState) =
deneb.BeaconState | electra.BeaconState) =
# init participation, overwriting the full structure
info.balances = get_unslashed_participating_balances(state)
info.validators.setLen(state.validators.len())
@ -1229,7 +1232,7 @@ proc process_epoch*(
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#epoch-processing
proc process_epoch*(
cfg: RuntimeConfig,
state: var (capella.BeaconState | deneb.BeaconState),
state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState),
flags: UpdateFlags, cache: var StateCache, info: var altair.EpochInfo):
Result[void, cstring] =
let epoch = get_current_epoch(state)

View File

@ -2259,6 +2259,9 @@ proc publishBlock*(
publishBlock(it, data.capellaData)
of ConsensusFork.Deneb:
publishBlock(it, data.denebData)
of ConsensusFork.Electra:
debugRaiseAssert "publishBlock RestPublishedSignedBlockContents; denebData will assert via mismatched case object discriminator"
publishBlock(it, data.denebData)
do:
if apiResponse.isErr():
handleCommunicationError()
@ -2305,6 +2308,9 @@ proc publishBlock*(
publishBlock(it, data.capellaData)
of ConsensusFork.Deneb:
publishBlock(it, data.denebData)
of ConsensusFork.Electra:
debugRaiseAssert "publishBlock RestPublishedSignedBlockContents; denebData will create invalid case discriminator"
publishBlock(it, data.denebData)
do:
if apiResponse.isErr():
@ -2461,6 +2467,9 @@ proc publishBlindedBlock*(
publishBlindedBlock(it, data.capellaData)
of ConsensusFork.Deneb:
publishBlindedBlock(it, data.denebData)
of ConsensusFork.Electra:
debugRaiseAssert "publishBlindedBlock ForkedSignedBlindedBeaconBlock; denebData mismatches discriminator"
publishBlindedBlock(it, data.denebData)
do:
if apiResponse.isErr():
handleCommunicationError()
@ -2506,6 +2515,9 @@ proc publishBlindedBlock*(
publishBlindedBlock(it, data.capellaData)
of ConsensusFork.Deneb:
publishBlindedBlock(it, data.denebData)
of ConsensusFork.Electra:
debugRaiseAssert "publishBlindedBlock ForkedSignedBlindedBeaconBlock; denebData mismatches discriminator"
publishBlindedBlock(it, data.denebData)
do:
if apiResponse.isErr():
handleCommunicationError()

View File

@ -96,6 +96,9 @@ proc produceBlock(
data: ForkedBeaconBlock.init(blck),
kzgProofsOpt: Opt.some(kzgProofs),
blobsOpt: Opt.some(blobs)))
of ConsensusFork.Electra:
debugRaiseAssert "produceBlock in block_service.nim"
return Opt.none(PreparedBeaconBlock)
proc produceBlindedBlock(
vc: ValidatorClientRef,
@ -305,8 +308,11 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
blockRoot = hash_tree_root(
when consensusFork < ConsensusFork.Deneb:
forkyMaybeBlindedBlck
else:
elif consensusFork < ConsensusFork.Electra:
forkyMaybeBlindedBlck.`block`
else:
debugRaiseAssert "publishBlockV3 1"
default(Attestation)
)
signingRoot =
compute_block_signing_root(fork, genesisRoot, slot, blockRoot)
@ -318,8 +324,11 @@ proc publishBlockV3(vc: ValidatorClientRef, currentSlot, slot: Slot,
blck = shortLog(
when consensusFork < ConsensusFork.Deneb:
forkyMaybeBlindedBlck
else:
elif consensusFork < ConsensusFork.Electra:
forkyMaybeBlindedBlck.`block`
else:
debugRaiseAssert "publishBlockV3 2"
default(bellatrix.BeaconBlock)
)
block_root = shortLog(blockRoot)
signing_root = shortLog(signingRoot)
@ -572,6 +581,9 @@ proc publishBlockV2(vc: ValidatorClientRef, currentSlot, slot: Slot,
signature: signature),
kzg_proofs: preparedBlock.kzgProofsOpt.get,
blobs: preparedBlock.blobsOpt.get))
of ConsensusFork.Electra:
debugRaiseAssert "publishBlockV2 2"
default(RestPublishedSignedBlockContents)
res =
try:

View File

@ -1316,7 +1316,10 @@ proc proposeBlock(node: BeaconNode,
genesis_validators_root, node.config.localBlockValueBoost)
return withConsensusFork(node.dag.cfg.consensusForkAtEpoch(slot.epoch)):
when consensusFork >= ConsensusFork.Capella:
when consensusFork >= ConsensusFork.Electra:
debugRaiseAssert "proposeBlock; fill in Electra support"
default(BlockRef)
elif consensusFork >= ConsensusFork.Capella:
proposeBlockContinuation(
consensusFork.SignedBlindedBeaconBlock,
consensusFork.ExecutionPayloadForSigning)

View File

@ -565,6 +565,9 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
Web3SignerForkedBeaconBlock(kind: ConsensusFork.Deneb,
data: blck.denebData.toBeaconBlockHeader),
proofs)
of ConsensusFork.Electra:
debugRaiseAssert "getBlockSignature 2"
default(Web3SignerRequest)
elif blck is capella_mev.BlindedBeaconBlock:
case v.data.remoteType
of RemoteSignerType.Web3Signer:
@ -668,6 +671,9 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
Web3SignerForkedBeaconBlock(kind: ConsensusFork.Deneb,
data: forkyMaybeBlindedBlck.`block`.toBeaconBlockHeader),
proofs)
elif consensusFork == ConsensusFork.Electra:
debugRaiseAssert "getBlockSignature 1"
default(Web3SignerRequest)
else:
case blck.kind
of ConsensusFork.Phase0, ConsensusFork.Altair:
@ -711,6 +717,9 @@ proc getBlockSignature*(v: AttachedValidator, fork: Fork,
Web3SignerForkedBeaconBlock(kind: ConsensusFork.Deneb,
data: blck.denebData.toBeaconBlockHeader),
proofs)
of ConsensusFork.Electra:
debugRaiseAssert "getBlockSignature"
return SignatureResult.err("Invalid beacon block fork version")
await v.signData(web3signerRequest)
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/phase0/validator.md#aggregate-signature

View File

@ -98,6 +98,7 @@ template saveSSZFile(filename: string, value: ForkedHashedBeaconState) =
of ConsensusFork.Bellatrix: SSZ.saveFile(filename, value.bellatrixData.data)
of ConsensusFork.Capella: SSZ.saveFile(filename, value.capellaData.data)
of ConsensusFork.Deneb: SSZ.saveFile(filename, value.denebData.data)
of ConsensusFork.Electra: SSZ.saveFile(filename, value.electraData.data)
except IOError:
raiseAssert "error saving SSZ file"

View File

@ -274,7 +274,7 @@ proc collectEpochRewardsAndPenalties*(
proc collectEpochRewardsAndPenalties*(
rewardsAndPenalties: var seq[RewardsAndPenalties],
state: var (altair.BeaconState | bellatrix.BeaconState |
capella.BeaconState | deneb.BeaconState),
capella.BeaconState | deneb.BeaconState | electra.BeaconState),
cache: var StateCache, cfg: RuntimeConfig, flags: UpdateFlags) =
if get_current_epoch(state) == GENESIS_EPOCH:
return

View File

@ -240,7 +240,8 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
seq[altair.TrustedSignedBeaconBlock],
seq[bellatrix.TrustedSignedBeaconBlock],
seq[capella.TrustedSignedBeaconBlock],
seq[deneb.TrustedSignedBeaconBlock])
seq[deneb.TrustedSignedBeaconBlock],
seq[electra.TrustedSignedBeaconBlock])
echo "Loaded head slot ", dag.head.slot,
" selected ", blockRefs.len, " blocks"
@ -266,6 +267,9 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
of ConsensusFork.Deneb:
blocks[4].add dag.db.getBlock(
blck.root, deneb.TrustedSignedBeaconBlock).get()
of ConsensusFork.Electra:
blocks[5].add dag.db.getBlock(
blck.root, electra.TrustedSignedBeaconBlock).get()
let stateData = newClone(dag.headState)
@ -277,7 +281,8 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
(ref altair.HashedBeaconState)(),
(ref bellatrix.HashedBeaconState)(),
(ref capella.HashedBeaconState)(),
(ref deneb.HashedBeaconState)())
(ref deneb.HashedBeaconState)(),
(ref electra.HashedBeaconState)())
withTimer(timers[tLoadState]):
doAssert dag.updateState(
@ -338,6 +343,9 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
of ConsensusFork.Deneb:
doAssert dbBenchmark.getState(
forkyState.root, loadedState[4][].data, noRollback)
of ConsensusFork.Electra:
doAssert dbBenchmark.getState(
forkyState.root, loadedState[5][].data, noRollback)
if forkyState.data.slot.epoch mod 16 == 0:
let loadedRoot = case consensusFork
@ -346,6 +354,7 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
of ConsensusFork.Bellatrix: hash_tree_root(loadedState[2][].data)
of ConsensusFork.Capella: hash_tree_root(loadedState[3][].data)
of ConsensusFork.Deneb: hash_tree_root(loadedState[4][].data)
of ConsensusFork.Electra: hash_tree_root(loadedState[5][].data)
doAssert hash_tree_root(forkyState.data) == loadedRoot
processBlocks(blocks[0])
@ -353,6 +362,7 @@ proc cmdBench(conf: DbConf, cfg: RuntimeConfig) =
processBlocks(blocks[2])
processBlocks(blocks[3])
processBlocks(blocks[4])
processBlocks(blocks[5])
printTimers(false, timers)
@ -366,6 +376,7 @@ proc cmdDumpState(conf: DbConf) =
bellatrixState = (ref bellatrix.HashedBeaconState)()
capellaState = (ref capella.HashedBeaconState)()
denebState = (ref deneb.HashedBeaconState)()
electraState = (ref electra.HashedBeaconState)()
for stateRoot in conf.stateRoot:
if shouldShutDown: quit QuitSuccess
@ -428,6 +439,8 @@ proc cmdDumpBlock(conf: DbConf) =
dump("./", blck.get())
elif (let blck = db.getBlock(root, deneb.TrustedSignedBeaconBlock); blck.isSome):
dump("./", blck.get())
elif (let blck = db.getBlock(root, electra.TrustedSignedBeaconBlock); blck.isSome):
dump("./", blck.get())
else:
echo "Couldn't load ", blockRoot
except CatchableError as e:

View File

@ -142,6 +142,49 @@ proc makeSimulationBlock(
ok(blck)
proc makeSimulationBlock(
cfg: RuntimeConfig,
state: var electra.HashedBeaconState,
proposer_index: ValidatorIndex,
randao_reveal: ValidatorSig,
eth1_data: Eth1Data,
graffiti: GraffitiBytes,
attestations: seq[Attestation],
deposits: seq[Deposit],
exits: BeaconBlockValidatorChanges,
sync_aggregate: SyncAggregate,
execution_payload: electra.ExecutionPayloadForSigning,
bls_to_execution_changes: SignedBLSToExecutionChangeList,
rollback: RollbackHashedProc[electra.HashedBeaconState],
cache: var StateCache,
# TODO:
# `verificationFlags` is needed only in tests and can be
# removed if we don't use invalid signatures there
verificationFlags: UpdateFlags = {}): Result[electra.BeaconBlock, cstring] =
## Create a block for the given state. The latest block applied to it will
## be used for the parent_root value, and the slot will be take from
## state.slot meaning process_slots must be called up to the slot for which
## the block is to be created.
# To create a block, we'll first apply a partial block to the state, skipping
# some validations.
var blck = partialBeaconBlock(
cfg, state, proposer_index, randao_reveal, eth1_data, graffiti,
attestations, deposits, exits, sync_aggregate, execution_payload)
let res = process_block(
cfg, state.data, blck.asSigVerified(), verificationFlags, cache)
if res.isErr:
rollback(state)
return err(res.error())
state.root = hash_tree_root(state.data)
blck.state_root = state.root
ok(blck)
# TODO confutils is an impenetrable black box. how can a help text be added here?
cli do(slots = SLOTS_PER_EPOCH * 7,
validators = SLOTS_PER_EPOCH * 500,
@ -343,6 +386,8 @@ cli do(slots = SLOTS_PER_EPOCH * 7,
addr state.capellaData
elif T is deneb.SignedBeaconBlock:
addr state.denebData
elif T is electra.SignedBeaconBlock:
addr state.electraData
else:
static: doAssert false
message = makeSimulationBlock(
@ -359,7 +404,9 @@ cli do(slots = SLOTS_PER_EPOCH * 7,
eth1ProposalData.deposits,
BeaconBlockValidatorChanges(),
sync_aggregate,
when T is deneb.SignedBeaconBlock:
when T is electra.SignedBeaconBlock:
default(electra.ExecutionPayloadForSigning)
elif T is deneb.SignedBeaconBlock:
default(deneb.ExecutionPayloadForSigning)
elif T is capella.SignedBeaconBlock:
default(capella.ExecutionPayloadForSigning)
@ -432,6 +479,28 @@ cli do(slots = SLOTS_PER_EPOCH * 7,
do:
raiseAssert "withUpdatedState failed"
proc proposeElectraBlock(slot: Slot) =
if rand(r, 1.0) > blockRatio:
return
dag.withUpdatedState(tmpState[], dag.getBlockIdAtSlot(slot).expect("block")) do:
let
newBlock = getNewBlock[electra.SignedBeaconBlock](updatedState, slot, cache)
added = dag.addHeadBlock(verifier, newBlock) do (
blckRef: BlockRef, signedBlock: electra.TrustedSignedBeaconBlock,
epochRef: EpochRef, unrealized: FinalityCheckpoints):
# Callback add to fork choice if valid
attPool.addForkChoice(
epochRef, blckRef, unrealized, signedBlock.message,
blckRef.slot.start_beacon_time)
dag.updateHead(added[], quarantine[], [])
if dag.needStateCachesAndForkChoicePruning():
dag.pruneStateCachesDAG()
attPool.prune()
do:
raiseAssert "withUpdatedState failed"
var
lastEth1BlockAt = genesisTime
eth1BlockNum = 1000
@ -472,6 +541,7 @@ cli do(slots = SLOTS_PER_EPOCH * 7,
if blockRatio > 0.0:
withTimer(timers[t]):
case dag.cfg.consensusForkAtEpoch(slot.epoch)
of ConsensusFork.Electra: proposeElectraBlock(slot)
of ConsensusFork.Deneb: proposeDenebBlock(slot)
of ConsensusFork.Capella: proposeCapellaBlock(slot)
of ConsensusFork.Bellatrix, ConsensusFork.Altair, ConsensusFork.Phase0:

View File

@ -221,6 +221,15 @@ cli do(validatorsDir: string, secretsDir: string,
fork, genesis_validators_root, slot, blockRoot,
validators[proposer]).toValidatorSig())
dump(".", signedBlock)
of ConsensusFork.Electra:
blockRoot = hash_tree_root(message.electraData)
let signedBlock = electra.SignedBeaconBlock(
message: message.electraData,
root: blockRoot,
signature: get_block_signature(
fork, genesis_validators_root, slot, blockRoot,
validators[proposer]).toValidatorSig())
dump(".", signedBlock)
except CatchableError:
raiseAssert "unreachable"
notice "Block proposed", message, blockRoot

View File

@ -47,6 +47,12 @@ func readValue*(r: var JsonReader, a: var seq[byte]) =
func genesisTestRuntimeConfig*(consensusFork: ConsensusFork): RuntimeConfig =
var res = defaultRuntimeConfig
case consensusFork
of ConsensusFork.Electra:
res.ELECTRA_FORK_EPOCH = GENESIS_EPOCH
res.DENEB_FORK_EPOCH = GENESIS_EPOCH
res.CAPELLA_FORK_EPOCH = GENESIS_EPOCH
res.BELLATRIX_FORK_EPOCH = GENESIS_EPOCH
res.ALTAIR_FORK_EPOCH = GENESIS_EPOCH
of ConsensusFork.Deneb:
res.DENEB_FORK_EPOCH = GENESIS_EPOCH
res.CAPELLA_FORK_EPOCH = GENESIS_EPOCH

View File

@ -94,4 +94,5 @@ template runForkBlockTests(consensusFork: static ConsensusFork) =
RandomDir, suiteName, path)
withAll(ConsensusFork):
runForkBlockTests(consensusFork)
when consensusFork != ConsensusFork.Electra:
runForkBlockTests(consensusFork)

View File

@ -25,12 +25,14 @@ suite "Light client" & preset():
headPeriod = 3.SyncCommitteePeriod
let
cfg = block: # Fork schedule so that each `LightClientDataFork` is covered
static: doAssert ConsensusFork.high == ConsensusFork.Deneb
static: doAssert ConsensusFork.high == ConsensusFork.Electra
var res = defaultRuntimeConfig
res.ALTAIR_FORK_EPOCH = 1.Epoch
res.BELLATRIX_FORK_EPOCH = 2.Epoch
res.CAPELLA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 1).Epoch
res.DENEB_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 2).Epoch
debugRaiseAssert "light client test; when this is tested, enable Electra"
res.ELECTRA_FORK_EPOCH = FAR_FUTURE_EPOCH
res
altairStartSlot = cfg.ALTAIR_FORK_EPOCH.start_slot

View File

@ -28,12 +28,14 @@ suite "Light client processor" & preset():
highPeriod = 5.SyncCommitteePeriod
let
cfg = block: # Fork schedule so that each `LightClientDataFork` is covered
static: doAssert ConsensusFork.high == ConsensusFork.Deneb
static: doAssert ConsensusFork.high == ConsensusFork.Electra
var res = defaultRuntimeConfig
res.ALTAIR_FORK_EPOCH = 1.Epoch
res.BELLATRIX_FORK_EPOCH = 2.Epoch
res.CAPELLA_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 1).Epoch
res.DENEB_FORK_EPOCH = (EPOCHS_PER_SYNC_COMMITTEE_PERIOD * 2).Epoch
res.ELECTRA_FORK_EPOCH = FAR_FUTURE_EPOCH
debugRaiseAssert "Light client processor test, once define/works add Electra to tests"
res
const numValidators = SLOTS_PER_EPOCH

View File

@ -17,6 +17,7 @@ import
from std/os import getEnv, osErrorMsg
{.push raises: [].}
{.used.}
const
@ -97,26 +98,33 @@ func init(T: type ForkedBeaconBlock, contents: ProduceBlockResponseV2): T =
return ForkedBeaconBlock.init(contents.capellaData)
of ConsensusFork.Deneb:
return ForkedBeaconBlock.init(contents.denebData.`block`)
of ConsensusFork.Electra:
return ForkedBeaconBlock.init(contents.electraData.`block`)
proc getBlock(fork: ConsensusFork,
feeRecipient = SigningExpectedFeeRecipient): ForkedBeaconBlock =
let
blckData =
case fork
of ConsensusFork.Phase0: Phase0Block
of ConsensusFork.Altair: AltairBlock
of ConsensusFork.Bellatrix: BellatrixBlock % [feeRecipient]
of ConsensusFork.Capella: CapellaBlock % [feeRecipient]
of ConsensusFork.Deneb: DenebBlockContents % [feeRecipient]
contentType = ContentTypeData(
mediaType: MediaType.init("application/json"))
try:
debugRaiseAssert "getBlock; ConsensusFork.Electra shouldn't use DenebBlockContents, but not tested, so do that together"
let
blckData =
case fork
of ConsensusFork.Phase0: Phase0Block
of ConsensusFork.Altair: AltairBlock
of ConsensusFork.Bellatrix: BellatrixBlock % [feeRecipient]
of ConsensusFork.Capella: CapellaBlock % [feeRecipient]
of ConsensusFork.Deneb: DenebBlockContents % [feeRecipient]
of ConsensusFork.Electra: DenebBlockContents % [feeRecipient]
contentType = ContentTypeData(
mediaType: MediaType.init("application/json"))
let b = decodeBytes(ProduceBlockResponseV2,
blckData.toOpenArrayByte(0, len(blckData) - 1),
Opt.some(contentType),
$fork).tryGet()
ForkedBeaconBlock.init(b)
let b = decodeBytes(ProduceBlockResponseV2,
blckData.toOpenArrayByte(0, len(blckData) - 1),
Opt.some(contentType),
$fork).tryGet()
ForkedBeaconBlock.init(b)
except ValueError:
raiseAssert "unreachable"
func init(t: typedesc[Web3SignerForkedBeaconBlock],
forked: ForkedBeaconBlock): Web3SignerForkedBeaconBlock =
@ -135,6 +143,11 @@ func init(t: typedesc[Web3SignerForkedBeaconBlock],
Web3SignerForkedBeaconBlock(
kind: ConsensusFork.Deneb,
data: forked.denebData.toBeaconBlockHeader)
of ConsensusFork.Electra:
debugRaiseAssert "init typedesc[Web3SignerForkedBeaconBlock]"
Web3SignerForkedBeaconBlock(
kind: ConsensusFork.Deneb,
data: forked.electraData.toBeaconBlockHeader)
proc createKeystore(dataDir, pubkey,
store, password: string): Result[void, string] =

View File

@ -64,7 +64,7 @@ proc getTestStates*(
info = ForkedEpochInfo()
cfg = defaultRuntimeConfig
static: doAssert high(ConsensusFork) == ConsensusFork.Deneb
static: doAssert high(ConsensusFork) == ConsensusFork.Electra
if consensusFork >= ConsensusFork.Altair:
cfg.ALTAIR_FORK_EPOCH = 1.Epoch
if consensusFork >= ConsensusFork.Bellatrix:
@ -73,6 +73,8 @@ proc getTestStates*(
cfg.CAPELLA_FORK_EPOCH = 3.Epoch
if consensusFork >= ConsensusFork.Deneb:
cfg.DENEB_FORK_EPOCH = 4.Epoch
if consensusFork >= ConsensusFork.Electra:
cfg.DENEB_FORK_EPOCH = 5.Epoch
for i, epoch in stateEpochs:
let slot = epoch.Epoch.start_slot