Skip to content

Commit

Permalink
Initial commit for eip-7732 on fulu
Browse files Browse the repository at this point in the history
This commit introduces changes to support EIP-7732 in the Fulu fork:
- Execution payloads are removed from the beacon block structure.
- Slot intervals are increased to 4 to align with EIP-7732 timing changes.
- Refactored validators and consensus object pools for compatibility.
  • Loading branch information
Tomi-3-0 committed Dec 18, 2024
1 parent 44531ad commit 76176e9
Show file tree
Hide file tree
Showing 29 changed files with 1,216 additions and 560 deletions.
61 changes: 15 additions & 46 deletions beacon_chain/beacon_chain_db_immutable.nim
Original file line number Diff line number Diff line change
Expand Up @@ -427,78 +427,47 @@ type
genesis_validators_root*: Eth2Digest
slot*: Slot
fork*: Fork

# History
latest_block_header*: BeaconBlockHeader
## `latest_block_header.state_root == ZERO_HASH` temporarily

block_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
## Needed to process attestations, older to newer

state_roots*: HashArray[Limit SLOTS_PER_HISTORICAL_ROOT, Eth2Digest]
historical_roots*: HashList[Eth2Digest, Limit HISTORICAL_ROOTS_LIMIT]
## Frozen in Capella, replaced by historical_summaries

# Eth1
eth1_data*: Eth1Data
eth1_data_votes*:
HashList[Eth1Data, Limit(EPOCHS_PER_ETH1_VOTING_PERIOD * SLOTS_PER_EPOCH)]
eth1_deposit_index*: uint64

# Registry
validators*:
HashList[ValidatorStatusCapella, Limit VALIDATOR_REGISTRY_LIMIT]
validators*: HashList[Validator, Limit VALIDATOR_REGISTRY_LIMIT]
balances*: HashList[Gwei, Limit VALIDATOR_REGISTRY_LIMIT]

# Randomness
randao_mixes*: HashArray[Limit EPOCHS_PER_HISTORICAL_VECTOR, Eth2Digest]

# Slashings
slashings*: HashArray[Limit EPOCHS_PER_SLASHINGS_VECTOR, Gwei]
## Per-epoch sums of slashed effective balances

# Participation
previous_epoch_participation*: EpochParticipationFlags
current_epoch_participation*: EpochParticipationFlags

# Finality
justification_bits*: JustificationBits
## Bit set for every recent justified epoch

previous_justified_checkpoint*: Checkpoint
current_justified_checkpoint*: Checkpoint
finalized_checkpoint*: Checkpoint

# Inactivity
inactivity_scores*: HashList[uint64, Limit VALIDATOR_REGISTRY_LIMIT]

# Light client sync committees
inactivity_scores*: InactivityScores
current_sync_committee*: SyncCommittee
next_sync_committee*: SyncCommittee

# Execution
latest_execution_payload_header*: fulu.ExecutionPayloadHeader

# Withdrawals
next_withdrawal_index*: WithdrawalIndex
next_withdrawal_validator_index*: uint64

# Deep history valid from Capella onwards
historical_summaries*:
HashList[HistoricalSummary, Limit HISTORICAL_ROOTS_LIMIT]

deposit_requests_start_index*: uint64 # [New in Electra:EIP6110]
deposit_balance_to_consume*: Gwei # [New in Electra:EIP7251]
exit_balance_to_consume*: Gwei # [New in Electra:EIP7251]
earliest_exit_epoch*: Epoch # [New in Electra:EIP7251]
consolidation_balance_to_consume*: Gwei # [New in Electra:EIP7251]
earliest_consolidation_epoch*: Epoch # [New in Electra:EIP7251]
pending_deposits*: HashList[PendingDeposit, Limit PENDING_DEPOSITS_LIMIT]
## [New in Electra:EIP7251]

# [New in Electra:EIP7251]
deposit_requests_start_index*: uint64
deposit_balance_to_consume*: Gwei
exit_balance_to_consume*: Gwei
earliest_exit_epoch*: Epoch
consolidation_balance_to_consume*: Gwei
earliest_consolidation_epoch*: Epoch
pending_deposits*:
HashList[PendingDeposit, Limit PENDING_DEPOSITS_LIMIT]
pending_partial_withdrawals*:
HashList[PendingPartialWithdrawal, Limit PENDING_PARTIAL_WITHDRAWALS_LIMIT]
pending_consolidations*:
HashList[PendingConsolidation, Limit PENDING_CONSOLIDATIONS_LIMIT]
## [New in Electra:EIP7251]

# [New in ePBS:eip7732]
latest_block_hash*: Eth2Digest
latest_full_slot*: Slot
latest_withdrawals_root*: Eth2Digest
43 changes: 27 additions & 16 deletions beacon_chain/consensus_object_pools/blob_quarantine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -73,35 +73,46 @@ func hasBlob*(
func popBlobs*(
quarantine: var BlobQuarantine, digest: Eth2Digest,
blck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock |
fulu.SignedBeaconBlock):
seq[ref BlobSidecar] =
fulu.SignedBeaconBlock): seq[ref BlobSidecar] =
var r: seq[ref BlobSidecar] = @[]
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
var b: ref BlobSidecar
if quarantine.blobs.pop((digest, BlobIndex idx, kzg_commitment), b):
r.add(b)

# Handle `fulu` blocks: skip processing blobs
when typeof(blck).kind == ConsensusFork.Fulu:
return r
else:
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
var b: ref BlobSidecar
if quarantine.blobs.pop((digest, BlobIndex idx, kzg_commitment), b):
r.add(b)
r

func hasBlobs*(quarantine: BlobQuarantine,
blck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock |
fulu.SignedBeaconBlock): bool =
# Having a fulu SignedBeaconBlock is incorrect atm, but
# shall be fixed once data columns are rebased to fulu
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
if (blck.root, BlobIndex idx, kzg_commitment) notin quarantine.blobs:
return false
when typeof(blck).kind == ConsensusFork.Fulu:
return false
else:
for idx, kzg_commitment in blck.message.body.blob_kzg_commitments:
if (blck.root, BlobIndex idx, kzg_commitment) notin quarantine.blobs:
return false
true

func blobFetchRecord*(quarantine: BlobQuarantine,
blck: deneb.SignedBeaconBlock | electra.SignedBeaconBlock |
fulu.SignedBeaconBlock): BlobFetchRecord =
var indices: seq[BlobIndex]
for i in 0..<len(blck.message.body.blob_kzg_commitments):
let idx = BlobIndex(i)
if not quarantine.blobs.hasKey(
(blck.root, idx, blck.message.body.blob_kzg_commitments[i])):
indices.add(idx)
BlobFetchRecord(block_root: blck.root, indices: indices)
# Skip blob fetching logic for the Fulu fork
when typeof(blck).kind == ConsensusFork.Fulu:
return BlobFetchRecord(block_root: blck.root, indices: @[]) # Empty record
else:
var indices: seq[BlobIndex]
for i in 0..<len(blck.message.body.blob_kzg_commitments):
let idx = BlobIndex(i)
if not quarantine.blobs.hasKey(
(blck.root, idx, blck.message.body.blob_kzg_commitments[i])):
indices.add(idx)
BlobFetchRecord(block_root: blck.root, indices: indices)

func init*(
T: type BlobQuarantine, onBlobSidecarCallback: OnBlobSidecarCallback): T =
Expand Down
17 changes: 12 additions & 5 deletions beacon_chain/consensus_object_pools/block_dag.nim
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,18 @@ func init*(
deneb.SomeBeaconBlock | deneb.TrustedBeaconBlock |
electra.SomeBeaconBlock | electra.TrustedBeaconBlock |
fulu.SomeBeaconBlock | fulu.TrustedBeaconBlock): BlockRef =
BlockRef.init(
root, Opt.some blck.body.execution_payload.block_hash,
executionValid =
executionValid or blck.body.execution_payload.block_hash == ZERO_HASH,
blck.slot)
when typeof(blck).kind < ConsensusFork.Fulu:
BlockRef.init(
root, Opt.some blck.body.execution_payload.block_hash,
executionValid =
executionValid or blck.body.execution_payload.block_hash == ZERO_HASH,
blck.slot)
else:
BlockRef.init(
root,
Opt.none(Eth2Digest),
executionValid = true,
blck.slot)

func parent*(bs: BlockSlot): BlockSlot =
## Return a blockslot representing the previous slot, using the parent block
Expand Down
8 changes: 6 additions & 2 deletions beacon_chain/consensus_object_pools/blockchain_dag.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1461,7 +1461,9 @@ proc computeRandaoMix(
bdata: ForkedTrustedSignedBeaconBlock): Opt[Eth2Digest] =
## Compute the requested RANDAO mix for `bdata` without `state`, if possible.
withBlck(bdata):
when consensusFork >= ConsensusFork.Bellatrix:
when consensusFork >= ConsensusFork.Fulu:
return Opt.none(Eth2Digest)
elif consensusFork >= ConsensusFork.Bellatrix:
if forkyBlck.message.is_execution_block:
var mix = eth2digest(forkyBlck.message.body.randao_reveal.toRaw())
mix.data.mxor forkyBlck.message.body.execution_payload.prev_randao.data
Expand Down Expand Up @@ -2311,7 +2313,9 @@ proc loadExecutionBlockHash*(
return Opt.none(Eth2Digest)

withBlck(blockData):
when consensusFork >= ConsensusFork.Bellatrix:
when consensusFork >= ConsensusFork.Fulu:
Opt.some ZERO_HASH
elif consensusFork >= ConsensusFork.Bellatrix:
Opt.some forkyBlck.message.body.execution_payload.block_hash
else:
Opt.some ZERO_HASH
Expand Down
3 changes: 2 additions & 1 deletion beacon_chain/consensus_object_pools/blockchain_list.nim
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ proc store*(clist: ChainListRef, signedBlock: ForkedSignedBeaconBlock,
proc checkBlobs(signedBlock: ForkedSignedBeaconBlock,
blobsOpt: Opt[BlobSidecars]): Result[void, VerifierError] =
withBlck(signedBlock):
when consensusFork >= ConsensusFork.Deneb:
when consensusFork >= ConsensusFork.Deneb and
consensusFork != ConsensusFork.Fulu:
if blobsOpt.isSome():
let blobs = blobsOpt.get()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ type
func init*(T: type DataColumnQuarantine): T =
T()

func shortLog*(x: seq[DataColumnFetchRecord]): string =
"[" & x.mapIt(shortLog(it.block_root) & shortLog(it.indices)).join(", ") & "]"
# func shortLog*(x: seq[DataColumnFetchRecord]): string =
# "[" & x.mapIt(shortLog(it.block_root) & shortLog(it.indices.mapIt($it).join(", "))).join(", ") & "]"

func put*(quarantine: var DataColumnQuarantine,
dataColumnSidecar: ref DataColumnSidecar) =
Expand Down
7 changes: 6 additions & 1 deletion beacon_chain/el/el_manager.nim
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,12 @@ proc sendNewPayload*(
let
requests = m.elConnections.mapIt:
let req =
when typeof(blck).kind >= ConsensusFork.Electra:
when typeof(blck).kind == ConsensusFork.Fulu:
let versioned_hashes: seq[VersionedHash] = @[]
sendNewPayloadToSingleEL(
it, payload, versioned_hashes,
FixedBytes[32] blck.parent_root.data)
elif typeof(blck).kind >= ConsensusFork.Electra:
# https://github.com/ethereum/execution-apis/blob/4140e528360fea53c34a766d86a000c6c039100e/src/engine/prague.md#engine_newpayloadv4
let versioned_hashes = mapIt(
blck.body.blob_kzg_commitments,
Expand Down
94 changes: 71 additions & 23 deletions beacon_chain/el/engine_api_conversions.nim
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import
kzg4844/[kzg_abi, kzg],
../spec/datatypes/[bellatrix, capella, deneb, electra, fulu],
../spec/forks,
web3/[engine_api, engine_api_types]

from std/sequtils import mapIt
Expand Down Expand Up @@ -300,30 +301,77 @@ func asEngineExecutionPayload*(blockBody: capella.BeaconBlockBody):
withdrawals: mapIt(executionPayload.withdrawals, it.toEngineWithdrawal))

func asEngineExecutionPayload*(
blockBody: deneb.BeaconBlockBody | electra.BeaconBlockBody |
fulu.BeaconBlockBody):
ExecutionPayloadV3 =
template executionPayload(): untyped = blockBody.execution_payload
blockBody: deneb.BeaconBlockBody | electra.BeaconBlockBody | fulu.BeaconBlockBody
): ExecutionPayloadV3 =
let executionPayload =
when typeof(blockBody).kind == ConsensusFork.Electra:
blockBody.execution_payload
elif typeof(blockBody).kind == ConsensusFork.Deneb:
blockBody.execution_payload
elif typeof(blockBody).kind == ConsensusFork.Fulu:
blockBody.signed_execution_payload_header.message
else:
raise newException(ValueError, "Unsupported BeaconBlockBody type")

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.data.to(Bytes32),
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))
when typeof(blockBody).kind == ConsensusFork.Electra:
result = 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.data.to(Bytes32),
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))
elif typeof(blockBody).kind == ConsensusFork.Deneb:
result = 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.data.to(Bytes32),
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))
elif typeof(blockBody).kind == ConsensusFork.Fulu:
result = engine_api.ExecutionPayloadV3(
parentHash: executionPayload.parent_block_hash.asBlockHash,
feeRecipient: default(Address),
stateRoot: executionPayload.parent_block_hash.asBlockHash, #[TODO]#
receiptsRoot: executionPayload.parent_block_hash.asBlockHash, #[TODO]#
logsBloom: default(FixedBytes[BYTES_PER_LOGS_BLOOM]),
prevRandao: default(FixedBytes[32]),
blockNumber: Quantity(0),
gasLimit: Quantity(executionPayload.gas_limit),
gasUsed: Quantity(0),
timestamp: Quantity(executionPayload.slot),
extraData: DynamicBytes[0, MAX_EXTRA_DATA_BYTES](@[]),
baseFeePerGas: default(UInt256),
blockHash: executionPayload.block_hash.asBlockHash,
transactions: @[],
withdrawals: @[],
blobGasUsed: Quantity(0),
excessBlobGas: Quantity(0))
else:
raise newException(ValueError, "Unsupported BeaconBlockBody type")
Loading

0 comments on commit 76176e9

Please sign in to comment.