Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/config/beacon_config.zig
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,25 @@ pub const BeaconConfig = struct {
.prev_fork_seq = ForkSeq.deneb,
};

const fulu = ForkInfo{
.fork_seq = ForkSeq.fulu,
.epoch = chain_config.FULU_FORK_EPOCH,
.version = chain_config.FULU_FORK_VERSION,
.prev_version = chain_config.ELECTRA_FORK_VERSION,
.prev_fork_seq = ForkSeq.electra,
};

const forks_ascending_epoch_order = [_]ForkInfo{
phase0,
altair,
bellatrix,
capella,
deneb,
electra,
fulu,
};
const forks_descending_epoch_order = [_]ForkInfo{
fulu,
electra,
deneb,
capella,
Expand Down Expand Up @@ -174,7 +184,7 @@ pub const BeaconConfig = struct {
const fork = self.forkInfoAtEpoch(epoch).fork_seq;
return switch (fork) {
.deneb => self.chain.MAX_BLOBS_PER_BLOCK,
.electra => self.chain.MAX_BLOBS_PER_BLOCK_ELECTRA,
.electra, .fulu => self.chain.MAX_BLOBS_PER_BLOCK_ELECTRA,
else =>
// For forks before Deneb, we assume no blobs
0,
Expand Down
13 changes: 11 additions & 2 deletions src/config/fork.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const ssz = @import("consensus_types");
const Epoch = ssz.primitive.Epoch.Type;
const Version = ssz.primitive.Version.Type;

pub const TOTAL_FORKS = 6;
pub const TOTAL_FORKS = 7;

pub const ForkSeq = enum(u8) {
phase0 = 0,
Expand All @@ -12,7 +12,7 @@ pub const ForkSeq = enum(u8) {
capella = 3,
deneb = 4,
electra = 5,
// TODO: fulu
fulu = 6,

pub fn forkName(self: ForkSeq) []const u8 {
return @tagName(self);
Expand Down Expand Up @@ -68,6 +68,13 @@ pub const ForkSeq = enum(u8) {
else => true,
};
}

pub fn isPostFulu(self: ForkSeq) bool {
return switch (self) {
inline .phase0, .altair, .bellatrix, .capella, .deneb, .electra => false,
else => true,
};
}
};

pub fn forkSeqByForkName(fork_name: []const u8) ForkSeq {
Expand Down Expand Up @@ -96,6 +103,7 @@ test "fork - forkName" {
try std.testing.expectEqualSlices(u8, "capella", ForkSeq.capella.forkName());
try std.testing.expectEqualSlices(u8, "deneb", ForkSeq.deneb.forkName());
try std.testing.expectEqualSlices(u8, "electra", ForkSeq.electra.forkName());
try std.testing.expectEqualSlices(u8, "fulu", ForkSeq.fulu.forkName());
}

test "fork - forkSeqByForkName" {
Expand All @@ -105,4 +113,5 @@ test "fork - forkSeqByForkName" {
try std.testing.expect(ForkSeq.capella == forkSeqByForkName("capella"));
try std.testing.expect(ForkSeq.deneb == forkSeqByForkName("deneb"));
try std.testing.expect(ForkSeq.electra == forkSeqByForkName("electra"));
try std.testing.expect(ForkSeq.fulu == forkSeqByForkName("fulu"));
}
163 changes: 163 additions & 0 deletions src/consensus_types/fulu.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
const std = @import("std");
const ssz = @import("ssz");
const p = @import("primitive.zig");
const c = @import("constants");
const preset = @import("preset").preset;
const phase0 = @import("phase0.zig");
const altair = @import("altair.zig");
const bellatrix = @import("bellatrix.zig");
const capella = @import("capella.zig");
const deneb = @import("deneb.zig");
const electra = @import("electra.zig");

// Fulu reuses most types from Electra
pub const Fork = phase0.Fork;
pub const ForkData = phase0.ForkData;
pub const Checkpoint = phase0.Checkpoint;
pub const Validator = phase0.Validator;
pub const AttestationData = phase0.AttestationData;
pub const PendingAttestation = phase0.PendingAttestation;
pub const Eth1Data = phase0.Eth1Data;
pub const HistoricalBatch = phase0.HistoricalBatch;
pub const DepositMessage = phase0.DepositMessage;
pub const DepositData = phase0.DepositData;
pub const BeaconBlockHeader = phase0.BeaconBlockHeader;
pub const SigningData = phase0.SigningData;
pub const ProposerSlashing = phase0.ProposerSlashing;
pub const Deposit = phase0.Deposit;
pub const VoluntaryExit = phase0.VoluntaryExit;
pub const SignedVoluntaryExit = phase0.SignedVoluntaryExit;
pub const Eth1Block = phase0.Eth1Block;
pub const HistoricalBlockRoots = phase0.HistoricalBlockRoots;
pub const HistoricalStateRoots = phase0.HistoricalStateRoots;
pub const ProposerSlashings = phase0.ProposerSlashings;
pub const Deposits = phase0.Deposits;
pub const VoluntaryExits = phase0.VoluntaryExits;

pub const SyncAggregate = altair.SyncAggregate;
pub const SyncCommittee = altair.SyncCommittee;
pub const SyncCommitteeMessage = altair.SyncCommitteeMessage;
pub const SyncCommitteeContribution = altair.SyncCommitteeContribution;
pub const ContributionAndProof = altair.ContributionAndProof;
pub const SignedContributionAndProof = altair.SignedContributionAndProof;
pub const SyncAggregatorSelectionData = altair.SyncAggregatorSelectionData;

pub const PowBlock = bellatrix.PowBlock;

pub const Withdrawal = capella.Withdrawal;
pub const BLSToExecutionChange = capella.BLSToExecutionChange;
pub const SignedBLSToExecutionChange = capella.SignedBLSToExecutionChange;
pub const SignedBLSToExecutionChanges = capella.SignedBLSToExecutionChanges;
pub const HistoricalSummary = capella.HistoricalSummary;

pub const BlobIdentifier = deneb.BlobIdentifier;
pub const BlobKzgCommitments = deneb.BlobKzgCommitments;

// Reuse Electra types
pub const PendingDeposit = electra.PendingDeposit;
pub const PendingPartialWithdrawal = electra.PendingPartialWithdrawal;
pub const PendingConsolidation = electra.PendingConsolidation;
pub const DepositRequest = electra.DepositRequest;
pub const WithdrawalRequest = electra.WithdrawalRequest;
pub const ConsolidationRequest = electra.ConsolidationRequest;
pub const ExecutionRequests = electra.ExecutionRequests;
pub const SingleAttestation = electra.SingleAttestation;
pub const Attestation = electra.Attestation;
pub const Attestations = electra.Attestations;
pub const IndexedAttestation = electra.IndexedAttestation;
pub const AttesterSlashing = electra.AttesterSlashing;
pub const AttesterSlashings = electra.AttesterSlashings;
pub const AggregateAndProof = electra.AggregateAndProof;
pub const SignedAggregateAndProof = electra.SignedAggregateAndProof;
pub const SignedBeaconBlockHeader = electra.SignedBeaconBlockHeader;

// Execution payload remains the same as Electra
pub const ExecutionPayload = electra.ExecutionPayload;
pub const ExecutionPayloadHeader = electra.ExecutionPayloadHeader;

// DAS-related custom types
pub const RowIndex = p.Uint64;
pub const ColumnIndex = p.Uint64;
pub const CustodyIndex = p.Uint64;
pub const Cell = ssz.ByteVectorType(c.BYTES_PER_FIELD_ELEMENT * preset.FIELD_ELEMENTS_PER_CELL);

// New containers for Data Availability Sampling
pub const DataColumnSidecar = ssz.VariableContainerType(struct {
index: ColumnIndex,
column: ssz.FixedListType(Cell, preset.MAX_BLOB_COMMITMENTS_PER_BLOCK),
kzg_commitments: ssz.FixedListType(p.KZGCommitment, preset.MAX_BLOB_COMMITMENTS_PER_BLOCK),
kzg_proofs: ssz.FixedListType(p.KZGProof, preset.MAX_BLOB_COMMITMENTS_PER_BLOCK),
signed_block_header: SignedBeaconBlockHeader,
kzg_commitments_inclusion_proof: ssz.FixedVectorType(p.Bytes32, preset.KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH),
});

pub const MatrixEntry = ssz.FixedContainerType(struct {
cell: Cell,
kzg_proof: p.KZGProof,
column_index: ColumnIndex,
row_index: RowIndex,
});

// Light client types
pub const LightClientHeader = electra.LightClientHeader;
pub const LightClientBootstrap = electra.LightClientBootstrap;
pub const LightClientUpdate = electra.LightClientUpdate;
pub const LightClientFinalityUpdate = electra.LightClientFinalityUpdate;
pub const LightClientOptimisticUpdate = electra.LightClientOptimisticUpdate;

// BeaconBlockBody
pub const BeaconBlockBody = electra.BeaconBlockBody;
pub const BeaconBlock = electra.BeaconBlock;
pub const BlindedBeaconBlockBody = electra.BlindedBeaconBlockBody;
pub const BlindedBeaconBlock = electra.BlindedBeaconBlock;
pub const SignedBlindedBeaconBlock = electra.SignedBlindedBeaconBlock;

// BeaconState with new proposer_lookahead field
pub const BeaconState = ssz.VariableContainerType(struct {
genesis_time: p.Uint64,
genesis_validators_root: p.Root,
slot: p.Slot,
fork: Fork,
latest_block_header: BeaconBlockHeader,
block_roots: HistoricalBlockRoots,
state_roots: HistoricalStateRoots,
historical_roots: ssz.FixedListType(p.Root, preset.HISTORICAL_ROOTS_LIMIT),
eth1_data: Eth1Data,
eth1_data_votes: phase0.Eth1DataVotes,
eth1_deposit_index: p.Uint64,
validators: ssz.FixedListType(Validator, preset.VALIDATOR_REGISTRY_LIMIT),
balances: ssz.FixedListType(p.Gwei, preset.VALIDATOR_REGISTRY_LIMIT),
randao_mixes: ssz.FixedVectorType(p.Bytes32, preset.EPOCHS_PER_HISTORICAL_VECTOR),
slashings: ssz.FixedVectorType(p.Gwei, preset.EPOCHS_PER_SLASHINGS_VECTOR),
previous_epoch_participation: ssz.FixedListType(p.Uint8, preset.VALIDATOR_REGISTRY_LIMIT),
current_epoch_participation: ssz.FixedListType(p.Uint8, preset.VALIDATOR_REGISTRY_LIMIT),
justification_bits: ssz.BitVectorType(c.JUSTIFICATION_BITS_LENGTH),
previous_justified_checkpoint: Checkpoint,
current_justified_checkpoint: Checkpoint,
finalized_checkpoint: Checkpoint,
inactivity_scores: ssz.FixedListType(p.Uint64, preset.VALIDATOR_REGISTRY_LIMIT),
current_sync_committee: SyncCommittee,
next_sync_committee: SyncCommittee,
latest_execution_payload_header: ExecutionPayloadHeader,
next_withdrawal_index: p.WithdrawalIndex,
next_withdrawal_validator_index: p.ValidatorIndex,
historical_summaries: ssz.FixedListType(HistoricalSummary, preset.HISTORICAL_ROOTS_LIMIT),
deposit_requests_start_index: p.Uint64,
deposit_balance_to_consume: p.Gwei,
exit_balance_to_consume: p.Gwei,
earliest_exit_epoch: p.Epoch,
consolidation_balance_to_consume: p.Gwei,
earliest_consolidation_epoch: p.Epoch,
pending_deposits: ssz.FixedListType(PendingDeposit, preset.PENDING_DEPOSITS_LIMIT),
pending_partial_withdrawals: ssz.FixedListType(PendingPartialWithdrawal, preset.PENDING_PARTIAL_WITHDRAWALS_LIMIT),
pending_consolidations: ssz.FixedListType(PendingConsolidation, preset.PENDING_CONSOLIDATIONS_LIMIT),
proposer_lookahead: ssz.FixedVectorType(p.ValidatorIndex, (preset.MIN_SEED_LOOKAHEAD + 1) * preset.SLOTS_PER_EPOCH),
});

pub const SignedBeaconBlock = ssz.VariableContainerType(struct {
message: BeaconBlock,
signature: p.BLSSignature,
});

// Blob sidecar reuses Electra definition
pub const BlobSidecar = electra.BlobSidecar;
3 changes: 3 additions & 0 deletions src/consensus_types/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub const capella = @import("capella.zig");
pub const deneb = @import("deneb.zig");
pub const electra = @import("electra.zig");

pub const fulu = @import("fulu.zig");

test {
testing.refAllDecls(primitive);
testing.refAllDecls(phase0);
Expand All @@ -17,6 +19,7 @@ test {
testing.refAllDecls(capella);
testing.refAllDecls(deneb);
testing.refAllDecls(electra);
testing.refAllDecls(fulu);
}

const src = blk: {
Expand Down
4 changes: 2 additions & 2 deletions src/state_transition/block/slash_validator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ pub fn slashValidator(
.phase0 => preset.MIN_SLASHING_PENALTY_QUOTIENT,
.altair => preset.MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR,
.bellatrix, .capella, .deneb => preset.MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX,
.electra => preset.MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA,
.electra, .fulu => preset.MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA,
};

decreaseBalance(state, slashed_index, @divFloor(effective_balance, min_slashing_penalty_quotient));

// apply proposer and whistleblower rewards
// TODO(ssz): define WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA
const whistleblower_reward = switch (state.*) {
.electra => @divFloor(effective_balance, preset.WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA),
.electra, .fulu => @divFloor(effective_balance, preset.WHISTLEBLOWER_REWARD_QUOTIENT_ELECTRA),
else => @divFloor(effective_balance, preset.WHISTLEBLOWER_REWARD_QUOTIENT),
};

Expand Down
3 changes: 3 additions & 0 deletions src/state_transition/cache/epoch_cache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,9 @@ pub const EpochCache = struct {
return @intCast((committees_since_epoch_start + committee_index) % c.ATTESTATION_SUBNET_COUNT);
}

/// Gets the beacon proposer for a slot. This is for pre-Fulu forks only.
/// NOTE: For the Fulu fork, use `CachedBeaconStateAllForks.getBeaconProposer()` instead,
/// which properly accesses `proposer_lookahead` from the state.
pub fn getBeaconProposer(self: *const EpochCache, slot: Slot) !ValidatorIndex {
const epoch = computeEpochAtSlot(slot);
if (epoch != self.epoch) return error.NotCurrentEpoch;
Expand Down
30 changes: 30 additions & 0 deletions src/state_transition/cache/state_cache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,36 @@ pub const CachedBeaconStateAllForks = struct {
// TODO: implement getCachedBeaconState
// this is used to create a CachedBeaconStateAllForks based on a tree and an exising CachedBeaconStateAllForks at fork transition
// implement this once we switch to TreeView

/// Gets the beacon proposer index for a given slot.
/// For the Fulu fork, this uses `proposer_lookahead` from the state.
/// For earlier forks, this uses `EpochCache.getBeaconProposer()`.
pub fn getBeaconProposer(self: *const CachedBeaconStateAllForks, slot: ssz.primitive.Slot.Type) !ValidatorIndex {
const preset_import = @import("preset").preset;
const computeEpochAtSlot = @import("../utils/epoch.zig").computeEpochAtSlot;

// For Fulu, use proposer_lookahead from state
if (self.state.isFulu()) {
const current_epoch = computeEpochAtSlot(self.state.slot());
const slot_epoch = computeEpochAtSlot(slot);

// proposer_lookahead covers current_epoch through current_epoch + MIN_SEED_LOOKAHEAD
const lookahead_start_epoch = current_epoch;
const lookahead_end_epoch = current_epoch + preset_import.MIN_SEED_LOOKAHEAD;

if (slot_epoch < lookahead_start_epoch or slot_epoch > lookahead_end_epoch) {
return error.SlotOutsideProposerLookahead;
}

const proposer_lookahead = self.state.proposerLookahead();
const epoch_offset = slot_epoch - lookahead_start_epoch;
const slot_in_epoch = slot % preset_import.SLOTS_PER_EPOCH;
const index = epoch_offset * preset_import.SLOTS_PER_EPOCH + slot_in_epoch;

return proposer_lookahead[index];
}
return self.getEpochCache().getBeaconProposer(slot);
}
};

test "CachedBeaconStateAllForks.clone()" {
Expand Down
8 changes: 6 additions & 2 deletions src/state_transition/epoch/process_epoch.zig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const processHistoricalRootsUpdate = @import("./process_historical_roots_update.
const processParticipationRecordUpdates = @import("./process_participation_record_updates.zig").processParticipationRecordUpdates;
const processParticipationFlagUpdates = @import("./process_participation_flag_updates.zig").processParticipationFlagUpdates;
const processSyncCommitteeUpdates = @import("./process_sync_committee_updates.zig").processSyncCommitteeUpdates;
const processProposerLookahead = @import("../utils/fulu_helpers.zig").processProposerLookahead;

// TODO: add metrics
pub fn processEpoch(allocator: std.mem.Allocator, cached_state: *CachedBeaconStateAllForks, cache: *EpochTransitionCache) !void {
Expand Down Expand Up @@ -62,6 +63,9 @@ pub fn processEpoch(allocator: std.mem.Allocator, cached_state: *CachedBeaconSta

try processSyncCommitteeUpdates(allocator, cached_state);

// TODO(fulu)
// processProposerLookahead(fork, state);
if (state.isFulu()) {
const epoch_cache = cached_state.getEpochCache();
const effective_balance_increments = epoch_cache.getEffectiveBalanceIncrements();
try processProposerLookahead(allocator, state, effective_balance_increments);
}
}
1 change: 1 addition & 0 deletions src/state_transition/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const EpochShuffling = @import("./utils/epoch_shuffling.zig");
pub const SignedBlock = @import("./types/signed_block.zig").SignedBlock;
pub const SignedBeaconBlock = @import("./types/beacon_block.zig").SignedBeaconBlock;
pub const Attestations = @import("./types/attestation.zig").Attestations;
pub const fulu_helpers = @import("./utils/fulu_helpers.zig");

test {
testing.refAllDecls(@This());
Expand Down
Loading