From b62696bf2a736612d98892c0f4e50ce65864e482 Mon Sep 17 00:00:00 2001
From: Chen Kai <281165273grape@gmail.com>
Date: Sun, 13 Oct 2024 21:45:04 +0800
Subject: [PATCH] feat:Add more helper

Signed-off-by: Chen Kai <281165273grape@gmail.com>
---
 src/consensus/altair/types.zig        | 100 ++++++------
 src/consensus/bellatrix/types.zig     |   8 +-
 src/consensus/capella/types.zig       |  18 +-
 src/consensus/deneb/types.zig         |   2 +-
 src/consensus/helpers/attestation.zig | 226 ++++++++++++++++++++++++++
 src/consensus/helpers/balance.zig     |   8 +-
 src/consensus/helpers/block_root.zig  |  10 +-
 src/consensus/helpers/committee.zig   |  12 +-
 src/consensus/helpers/epoch.zig       |   8 +-
 src/consensus/helpers/seed.zig        |   8 +-
 src/consensus/helpers/validator.zig   |  18 +-
 src/consensus/phase0/types.zig        |  14 +-
 src/consensus/types.zig               |  74 +++++----
 13 files changed, 367 insertions(+), 139 deletions(-)

diff --git a/src/consensus/altair/types.zig b/src/consensus/altair/types.zig
index 421bf4c..339dc65 100644
--- a/src/consensus/altair/types.zig
+++ b/src/consensus/altair/types.zig
@@ -5,41 +5,41 @@ const consensus = @import("../../consensus/types.zig");
 const phase0 = @import("../../consensus/phase0/types.zig");
 
 pub const LightClientHeader = struct {
-    beacon: ?*consensus.BeaconBlockHeader,
+    beacon: consensus.BeaconBlockHeader,
 };
 
 pub const LightClientOptimisticUpdate = struct {
-    attested_header: ?*consensus.LightClientHeader,
-    sync_aggregate: ?*consensus.SyncAggregate,
+    attested_header: consensus.LightClientHeader,
+    sync_aggregate: consensus.SyncAggregate,
     signature_slot: primitives.Slot,
 };
 
 pub const LightClientFinalityUpdate = struct {
-    attested_header: ?*consensus.LightClientHeader,
-    finalized_header: ?*consensus.LightClientHeader,
+    attested_header: consensus.LightClientHeader,
+    finalized_header: consensus.LightClientHeader,
     finality_branch: primitives.FinalityBranch,
-    sync_aggregate: ?*consensus.SyncAggregate,
+    sync_aggregate: consensus.SyncAggregate,
     signature_slot: primitives.Slot,
 };
 
 pub const LightClientUpdate = struct {
-    attested_header: ?*consensus.LightClientHeader,
-    next_sync_committee: ?*consensus.SyncCommittee,
+    attested_header: consensus.LightClientHeader,
+    next_sync_committee: consensus.SyncCommittee,
     next_sync_committee_branch: primitives.NextSyncCommitteeBranch,
-    finalized_header: ?*consensus.LightClientHeader,
+    finalized_header: consensus.LightClientHeader,
     finality_branch: primitives.FinalityBranch,
-    sync_aggregate: ?*consensus.SyncAggregate,
+    sync_aggregate: consensus.SyncAggregate,
     signature_slot: primitives.Slot,
 };
 
 pub const LightClientBootstrap = struct {
-    header: ?*consensus.LightClientHeader,
-    current_sync_committee: ?*consensus.SyncCommittee,
+    header: consensus.LightClientHeader,
+    current_sync_committee: consensus.SyncCommittee,
     current_sync_committee_branch: primitives.CurrentSyncCommitteeBranch,
 };
 
 pub const SignedVoluntaryExit = struct {
-    message: ?*consensus.VoluntaryExit,
+    message: consensus.VoluntaryExit,
     signature: primitives.BLSSignature,
 };
 
@@ -70,12 +70,12 @@ pub const SyncCommitteeContribution = struct {
 
 pub const ContributionAndProof = struct {
     aggregator_index: primitives.ValidatorIndex,
-    aggregate: ?*consensus.SyncCommitteeContribution,
+    contribution: consensus.SyncCommitteeContribution,
     selection_proof: primitives.BLSSignature,
 };
 
 pub const SignedContributionAndProof = struct {
-    message: ?*consensus.ContributionAndProof,
+    message: consensus.ContributionAndProof,
     signature: primitives.BLSSignature,
 };
 
@@ -86,10 +86,10 @@ pub const BeaconBlockBody = @Type(
             .fields = @typeInfo(phase0.BeaconBlockBody).@"struct".fields ++ &[_]std.builtin.Type.StructField{
                 .{
                     .name = "sync_aggregate",
-                    .type = ?*consensus.SyncAggregate,
+                    .type = consensus.SyncAggregate,
                     .default_value = null,
                     .is_comptime = false,
-                    .alignment = @alignOf(?*consensus.SyncAggregate),
+                    .alignment = @alignOf(consensus.SyncAggregate),
                 },
             },
             .decls = &.{},
@@ -112,17 +112,17 @@ pub const BeaconState = @Type(
                 },
                 .{
                     .name = "current_sync_committee",
-                    .type = ?*consensus.SyncCommittee,
+                    .type = consensus.SyncCommittee,
                     .default_value = null,
                     .is_comptime = false,
-                    .alignment = @alignOf(?*consensus.SyncCommittee),
+                    .alignment = @alignOf(consensus.SyncCommittee),
                 },
                 .{
                     .name = "next_sync_committee",
-                    .type = ?*consensus.SyncCommittee,
+                    .type = consensus.SyncCommittee,
                     .default_value = null,
                     .is_comptime = false,
-                    .alignment = @alignOf(?*consensus.SyncCommittee),
+                    .alignment = @alignOf(consensus.SyncCommittee),
                 },
             },
             .decls = &.{},
@@ -180,11 +180,11 @@ test "test BeaconBlockBody" {
 
 test "test SignedVoluntaryExit" {
     const exit = SignedVoluntaryExit{
-        .message = null,
+        .message = undefined,
         .signature = undefined,
     };
 
-    try std.testing.expectEqual(exit.message, null);
+    try std.testing.expectEqual(exit.message, undefined);
 }
 
 test "test SyncAggregate" {
@@ -231,7 +231,7 @@ test "test SyncCommitteeContribution" {
 test "test ContributionAndProof" {
     const contribution = ContributionAndProof{
         .aggregator_index = 0,
-        .aggregate = null,
+        .contribution = undefined,
         .selection_proof = undefined,
     };
 
@@ -240,30 +240,30 @@ test "test ContributionAndProof" {
 
 test "test SignedContributionAndProof" {
     const contribution = SignedContributionAndProof{
-        .message = null,
+        .message = undefined,
         .signature = undefined,
     };
 
-    try std.testing.expectEqual(contribution.message, null);
+    try std.testing.expectEqual(contribution.message, undefined);
 }
 
 test "test LightClientHeader" {
     const header = LightClientHeader{
-        .beacon = null,
+        .beacon = undefined,
     };
 
-    try std.testing.expectEqual(header.beacon, null);
+    try std.testing.expectEqual(header.beacon, undefined);
 }
 
 test "test LightClientOptimisticUpdate" {
     const update = LightClientOptimisticUpdate{
-        .attested_header = null,
-        .sync_aggregate = null,
+        .attested_header = undefined,
+        .sync_aggregate = undefined,
         .signature_slot = 0,
     };
 
-    try std.testing.expectEqual(update.attested_header, null);
-    try std.testing.expectEqual(update.sync_aggregate, null);
+    try std.testing.expectEqual(update.attested_header, undefined);
+    try std.testing.expectEqual(update.sync_aggregate, undefined);
     try std.testing.expectEqual(update.signature_slot, 0);
 }
 
@@ -275,17 +275,17 @@ test "test LightClientFinalityUpdate" {
     };
 
     const update = LightClientFinalityUpdate{
-        .attested_header = null,
-        .finalized_header = null,
+        .attested_header = undefined,
+        .finalized_header = undefined,
         .finality_branch = finality_branch,
-        .sync_aggregate = null,
+        .sync_aggregate = undefined,
         .signature_slot = 0,
     };
 
-    try std.testing.expectEqual(update.attested_header, null);
-    try std.testing.expectEqual(update.finalized_header, null);
+    try std.testing.expectEqual(update.attested_header, undefined);
+    try std.testing.expectEqual(update.finalized_header, undefined);
     try std.testing.expect(update.finality_branch.altair.len == 6);
-    try std.testing.expectEqual(update.sync_aggregate, null);
+    try std.testing.expectEqual(update.sync_aggregate, undefined);
     try std.testing.expectEqual(update.signature_slot, 0);
 }
 
@@ -303,21 +303,21 @@ test "test LightClientUpdate" {
     };
 
     const update = LightClientUpdate{
-        .attested_header = null,
-        .next_sync_committee = null,
+        .attested_header = undefined,
+        .next_sync_committee = undefined,
         .next_sync_committee_branch = next_sync_committee_branch,
-        .finalized_header = null,
+        .finalized_header = undefined,
         .finality_branch = finality_branch,
-        .sync_aggregate = null,
+        .sync_aggregate = undefined,
         .signature_slot = 0,
     };
 
-    try std.testing.expectEqual(update.attested_header, null);
-    try std.testing.expectEqual(update.next_sync_committee, null);
+    try std.testing.expectEqual(update.attested_header, undefined);
+    try std.testing.expectEqual(update.next_sync_committee, undefined);
     try std.testing.expect(update.next_sync_committee_branch.altair.len == 5);
-    try std.testing.expectEqual(update.finalized_header, null);
+    try std.testing.expectEqual(update.finalized_header, undefined);
     try std.testing.expect(update.finality_branch.altair.len == 6);
-    try std.testing.expectEqual(update.sync_aggregate, null);
+    try std.testing.expectEqual(update.sync_aggregate, undefined);
     try std.testing.expectEqual(update.signature_slot, 0);
 }
 
@@ -329,12 +329,12 @@ test "test LightClientBootstrap" {
     };
 
     const bootstrap = LightClientBootstrap{
-        .header = null,
-        .current_sync_committee = null,
+        .header = undefined,
+        .current_sync_committee = undefined,
         .current_sync_committee_branch = current_sync_committee_branch,
     };
 
-    try std.testing.expectEqual(bootstrap.header, null);
-    try std.testing.expectEqual(bootstrap.current_sync_committee, null);
+    try std.testing.expectEqual(bootstrap.header, undefined);
+    try std.testing.expectEqual(bootstrap.current_sync_committee, undefined);
     try std.testing.expect(bootstrap.current_sync_committee_branch.altair.len == 5);
 }
diff --git a/src/consensus/bellatrix/types.zig b/src/consensus/bellatrix/types.zig
index f06ff3b..e5524aa 100644
--- a/src/consensus/bellatrix/types.zig
+++ b/src/consensus/bellatrix/types.zig
@@ -54,10 +54,10 @@ pub const BeaconBlockBody = @Type(
             .fields = @typeInfo(altair.BeaconBlockBody).@"struct".fields ++ &[_]std.builtin.Type.StructField{
                 .{
                     .name = "execution_payload",
-                    .type = ?*consensus.ExecutionPayload,
+                    .type = consensus.ExecutionPayload,
                     .default_value = null,
                     .is_comptime = false,
-                    .alignment = @alignOf(?*consensus.ExecutionPayload),
+                    .alignment = @alignOf(consensus.ExecutionPayload),
                 },
             },
             .decls = &.{},
@@ -73,10 +73,10 @@ pub const BeaconState = @Type(
             .fields = @typeInfo(altair.BeaconState).@"struct".fields ++ &[_]std.builtin.Type.StructField{
                 .{
                     .name = "latest_execution_payload_header",
-                    .type = ?*consensus.ExecutionPayloadHeader,
+                    .type = consensus.ExecutionPayloadHeader,
                     .default_value = null,
                     .is_comptime = false,
-                    .alignment = @alignOf(?*consensus.ExecutionPayloadHeader),
+                    .alignment = @alignOf(consensus.ExecutionPayloadHeader),
                 },
             },
             .decls = &.{},
diff --git a/src/consensus/capella/types.zig b/src/consensus/capella/types.zig
index 5b7b054..099d151 100644
--- a/src/consensus/capella/types.zig
+++ b/src/consensus/capella/types.zig
@@ -19,10 +19,10 @@ pub const LightClientHeader = @Type(
             .fields = @typeInfo(altair.LightClientHeader).@"struct".fields ++ &[_]std.builtin.Type.StructField{
                 .{
                     .name = "execution",
-                    .type = ?*consensus.ExecutionPayloadHeader,
+                    .type = consensus.ExecutionPayloadHeader,
                     .default_value = null,
                     .is_comptime = false,
-                    .alignment = @alignOf(?*consensus.ExecutionPayloadHeader),
+                    .alignment = @alignOf(consensus.ExecutionPayloadHeader),
                 },
                 .{
                     .name = "execution_branch",
@@ -52,7 +52,7 @@ pub const BLSToExecutionChange = struct {
 };
 
 pub const SignedBLSToExecutionChange = struct {
-    message: ?*consensus.BLSToExecutionChange,
+    message: consensus.BLSToExecutionChange,
     signature: primitives.BLSSignature,
 };
 
@@ -243,13 +243,13 @@ test "test BeaconState" {
 
 test "test LightClientHeader" {
     const header = LightClientHeader{
-        .beacon = null,
-        .execution = null,
+        .beacon = undefined,
+        .execution = undefined,
         .execution_branch = undefined,
     };
 
-    try std.testing.expectEqual(header.beacon, null);
-    try std.testing.expectEqual(header.execution, null);
+    try std.testing.expectEqual(header.beacon, undefined);
+    try std.testing.expectEqual(header.execution, undefined);
 }
 
 test "test Withdrawal" {
@@ -275,11 +275,11 @@ test "test BLSToExecutionChange" {
 
 test "test SignedBLSToExecutionChange" {
     const change = SignedBLSToExecutionChange{
-        .message = null,
+        .message = undefined,
         .signature = undefined,
     };
 
-    try std.testing.expectEqual(change.message, null);
+    try std.testing.expectEqual(change.message, undefined);
 }
 
 test "test HistoricalSummary" {
diff --git a/src/consensus/deneb/types.zig b/src/consensus/deneb/types.zig
index d632c76..e7f0377 100644
--- a/src/consensus/deneb/types.zig
+++ b/src/consensus/deneb/types.zig
@@ -14,7 +14,7 @@ pub const BlobSidecar = struct {
     blob: primitives.Blob,
     kzg_commitment: primitives.KZGCommitment,
     kzg_proof: primitives.KZGProof,
-    signed_block_header: ?*consensus.SignedBeaconBlockHeader,
+    signed_block_header: consensus.SignedBeaconBlockHeader,
     kzg_commitment_inclusion_proof: []primitives.Bytes32,
 };
 
diff --git a/src/consensus/helpers/attestation.zig b/src/consensus/helpers/attestation.zig
index 4b0a5f1..e79d96c 100644
--- a/src/consensus/helpers/attestation.zig
+++ b/src/consensus/helpers/attestation.zig
@@ -7,6 +7,8 @@ const preset = @import("../../presets/preset.zig");
 const phase0 = @import("../../consensus/phase0/types.zig");
 const altair = @import("../../consensus/altair/types.zig");
 const epoch_helper = @import("../../consensus/helpers/epoch.zig");
+const committee_helper = @import("../../consensus/helpers/committee.zig");
+const electra = @import("../../consensus/electra/types.zig");
 
 /// isSlashableAttestationData checks if two attestations are slashable according to Casper FFG rules.
 /// @param data_1 The first attestation data.
@@ -32,6 +34,106 @@ pub fn isSlashableAttestationData(data1: consensus.AttestationData, data2: conse
         (data1.source.epoch < data2.source.epoch and data2.target.epoch < data1.target.epoch));
 }
 
+/// getCommitteeIndices returns the indices of the committee for the given `committeeBits`.
+/// @param committeeBits The committee bits.
+/// @param allocator The allocator to use.
+/// @return The indices of the committee.
+/// Spec pseudocode definition:
+/// def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]:
+///     return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit]
+pub fn getCommitteeIndices(committeeBits: []const bool, allocator: std.mem.Allocator) ![]primitives.CommitteeIndex {
+    var indices = try std.ArrayList(primitives.CommitteeIndex).initCapacity(allocator, committeeBits.len);
+    defer indices.deinit();
+
+    for (committeeBits, 0..) |bit, index| {
+        if (bit) {
+            try indices.append(@as(primitives.CommitteeIndex, index));
+        }
+    }
+
+    return indices.toOwnedSlice();
+}
+
+/// getAttestingIndices returns the indices of the validators that are attesting to the given attestation.
+/// @param state The state.
+/// @param attestation The attestation.
+/// @param allocator The allocator to use.
+/// @return The indices of the validators that are attesting to the given attestation.
+/// Spec pseudocode definition:
+/// def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
+///     """
+///     Return the set of attesting indices corresponding to ``aggregation_bits`` and ``committee_bits``.
+///    """
+///    output: Set[ValidatorIndex] = set()
+///    committee_indices = get_committee_indices(attestation.committee_bits)
+///    committee_offset = 0
+///    for index in committee_indices:
+///        committee = get_beacon_committee(state, attestation.data.slot, index)
+///        committee_attesters = set(
+///            index for i, index in enumerate(committee) if attestation.aggregation_bits[committee_offset + i])
+///        output = output.union(committee_attesters)
+///
+///        committee_offset += len(committee)
+///   return output
+/// Before electra:
+/// def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
+///    """
+///    Return the set of attesting indices corresponding to ``data`` and ``bits``.
+///   """
+///   committee = get_beacon_committee(state, attestation.data.slot, attestation.data.index)
+///   return set(index for i, index in enumerate(committee) if attestation.aggregation_bits[i])
+pub fn getAttestingIndices(state: *const consensus.BeaconState, attestation: *const consensus.Attestation, allocator: std.mem.Allocator) !std.AutoHashMap(primitives.ValidatorIndex, void) {
+    var output = std.AutoHashMap(primitives.ValidatorIndex, void).init(allocator);
+    errdefer output.deinit();
+
+    switch (state.*) {
+        .electra => {
+            const committee_indices = try getCommitteeIndices(attestation.electra.committee_bits, allocator);
+            defer allocator.free(committee_indices);
+
+            var committeeOffset: usize = 0;
+
+            for (committee_indices) |committee_index| {
+                const committee = try committee_helper.getBeaconCommittee(state, attestation.data().slot, committee_index, allocator);
+                defer allocator.free(committee);
+                try processElectraCommittee(committee, attestation, committeeOffset, &output);
+                committeeOffset += committee.len;
+            }
+        },
+        else => {
+            const committee = try committee_helper.getBeaconCommittee(state, attestation.data().slot, attestation.data().index, allocator);
+            defer allocator.free(committee);
+            try processRegularCommittee(committee, attestation, &output);
+        },
+    }
+    return output;
+}
+
+fn processElectraCommittee(
+    committee: []const primitives.ValidatorIndex,
+    attestation: *const consensus.Attestation,
+    committee_offset: usize,
+    output: *std.AutoHashMap(primitives.ValidatorIndex, void),
+) !void {
+    for (committee, 0..) |validator_index, i| {
+        if (attestation.aggregationBits()[committee_offset + i]) {
+            try output.put(validator_index, {});
+        }
+    }
+}
+
+fn processRegularCommittee(
+    committee: []const primitives.ValidatorIndex,
+    attestation: *const consensus.Attestation,
+    output: *std.AutoHashMap(primitives.ValidatorIndex, void),
+) !void {
+    for (committee, 0..) |validator_index, i| {
+        if (attestation.aggregationBits()[i]) {
+            try output.put(validator_index, {});
+        }
+    }
+}
+
 test "test isSlashableAttestationData" {
     const data1 = consensus.AttestationData{
         .slot = 0,
@@ -94,3 +196,127 @@ test "test isSlashableAttestationData" {
     try std.testing.expectEqual(isSlashableAttestationData(data3, data4), true);
     try std.testing.expectEqual(isSlashableAttestationData(data1, data4), false);
 }
+
+test "test getCommitteeIndices" {
+    const committeeBits = [_]bool{ true, false, true, false, true, false, true, false };
+    const allocator = std.testing.allocator;
+    const indices = try getCommitteeIndices(&committeeBits, allocator);
+    defer allocator.free(indices);
+    try std.testing.expectEqual(4, indices.len);
+    try std.testing.expectEqual(0, indices[0]);
+    try std.testing.expectEqual(2, indices[1]);
+    try std.testing.expectEqual(4, indices[2]);
+    try std.testing.expectEqual(6, indices[3]);
+}
+
+test "test getAttestingIndices" {
+    preset.ActivePreset.set(preset.Presets.minimal);
+    defer preset.ActivePreset.reset();
+    const finalized_checkpoint = consensus.Checkpoint{
+        .epoch = 5,
+        .root = .{0} ** 32,
+    };
+    var validators = std.ArrayList(consensus.Validator).init(std.testing.allocator);
+    defer validators.deinit();
+    const validator1 = consensus.Validator{
+        .pubkey = undefined,
+        .withdrawal_credentials = undefined,
+        .effective_balance = 0,
+        .slashed = false,
+        .activation_eligibility_epoch = 0,
+        .activation_epoch = 0,
+        .exit_epoch = 10,
+        .withdrawable_epoch = 10,
+    };
+    const validator2 = consensus.Validator{
+        .pubkey = undefined,
+        .withdrawal_credentials = undefined,
+        .effective_balance = 0,
+        .slashed = false,
+        .activation_eligibility_epoch = 0,
+        .activation_epoch = 0,
+        .exit_epoch = 20,
+        .withdrawable_epoch = 20,
+    };
+    for (0..1000) |_| {
+        try validators.append(validator1);
+        try validators.append(validator2);
+    }
+
+    var block_roots = std.ArrayList(primitives.Root).init(std.testing.allocator);
+    defer block_roots.deinit();
+    const block_root1 = .{0} ** 32;
+    const block_root2 = .{1} ** 32;
+    const block_root3 = .{2} ** 32;
+    try block_roots.append(block_root1);
+    try block_roots.append(block_root2);
+    try block_roots.append(block_root3);
+
+    var randao_mixes = try std.ArrayList(primitives.Bytes32).initCapacity(std.testing.allocator, preset.ActivePreset.get().EPOCHS_PER_HISTORICAL_VECTOR);
+    defer randao_mixes.deinit();
+    for (0..preset.ActivePreset.get().EPOCHS_PER_HISTORICAL_VECTOR) |slot_index| {
+        try randao_mixes.append(.{@as(u8, @intCast(slot_index))} ** 32);
+    }
+
+    var aggregation_bits = [_]bool{ true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true, false, true };
+    var committee_bits = [_]bool{ true, false, true, false };
+    const attestation = consensus.Attestation{
+        .electra = electra.Attestation{
+            .data = consensus.AttestationData{
+                .slot = 100,
+                .index = 1,
+                .beacon_block_root = .{0} ** 32,
+                .source = consensus.Checkpoint{
+                    .epoch = 0,
+                    .root = .{0} ** 32,
+                },
+                .target = consensus.Checkpoint{
+                    .epoch = 0,
+                    .root = .{0} ** 32,
+                },
+            },
+            .aggregation_bits = &aggregation_bits,
+            .signature = undefined,
+            .committee_bits = &committee_bits,
+        },
+    };
+
+    const state = consensus.BeaconState{
+        .electra = electra.BeaconState{
+            .genesis_time = 0,
+            .genesis_validators_root = .{0} ** 32,
+            .slot = 100,
+            .fork = undefined,
+            .block_roots = block_roots.items,
+            .state_roots = undefined,
+            .historical_roots = undefined,
+            .eth1_data = undefined,
+            .eth1_data_votes = undefined,
+            .eth1_deposit_index = 0,
+            .validators = validators.items,
+            .balances = &[_]u64{},
+            .randao_mixes = randao_mixes.items,
+            .slashings = &[_]u64{},
+            .justification_bits = undefined,
+            .previous_justified_checkpoint = undefined,
+            .current_justified_checkpoint = undefined,
+            .finalized_checkpoint = finalized_checkpoint,
+            .latest_block_header = undefined,
+            .inactivity_scores = &[_]u64{},
+            .current_sync_committee = undefined,
+            .next_sync_committee = undefined,
+            .previous_epoch_attestations = undefined,
+            .current_epoch_attestations = undefined,
+            .latest_execution_payload_header = undefined,
+            .historical_summaries = undefined,
+            .pending_balance_deposits = undefined,
+            .pending_partial_withdrawals = undefined,
+            .pending_consolidations = undefined,
+            .deposit_requests_start_index = 0,
+        },
+    };
+
+    var indices = try getAttestingIndices(&state, &attestation, std.testing.allocator);
+    defer indices.deinit();
+    try std.testing.expect(indices.count() == 32);
+}
diff --git a/src/consensus/helpers/balance.zig b/src/consensus/helpers/balance.zig
index c651c34..2b6ef3d 100644
--- a/src/consensus/helpers/balance.zig
+++ b/src/consensus/helpers/balance.zig
@@ -48,7 +48,7 @@ pub fn getTotalActiveBalance(state: *const consensus.BeaconState, allocator: std
 test "test getTotalBalance" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -104,7 +104,7 @@ test "test getTotalBalance" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -128,7 +128,7 @@ test "test getTotalBalance" {
 test "test getTotalActiveBalance" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -184,7 +184,7 @@ test "test getTotalActiveBalance" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
diff --git a/src/consensus/helpers/block_root.zig b/src/consensus/helpers/block_root.zig
index 668860c..1e7ec08 100644
--- a/src/consensus/helpers/block_root.zig
+++ b/src/consensus/helpers/block_root.zig
@@ -46,7 +46,7 @@ pub fn getBlockRoot(state: *const consensus.BeaconState, epoch: primitives.Epoch
 test "test get_block_root_at_slot" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -104,7 +104,7 @@ test "test get_block_root_at_slot" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -135,7 +135,7 @@ test "test get_block_root_at_slot" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -150,7 +150,7 @@ test "test get_block_root_at_slot" {
 test "test get_block_root" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -205,7 +205,7 @@ test "test get_block_root" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
diff --git a/src/consensus/helpers/committee.zig b/src/consensus/helpers/committee.zig
index 65e20e7..4334ed7 100644
--- a/src/consensus/helpers/committee.zig
+++ b/src/consensus/helpers/committee.zig
@@ -130,7 +130,7 @@ pub fn getBeaconProposerIndex(state: *const consensus.BeaconState, allocator: st
 test "test getCommitteeCountPerSlot" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -186,7 +186,7 @@ test "test getCommitteeCountPerSlot" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -219,7 +219,7 @@ test "test computeCommittee" {
 test "test getBeaconCommittee" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -286,7 +286,7 @@ test "test getBeaconCommittee" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -304,7 +304,7 @@ test "test getBeaconCommittee" {
 test "test getBeaconProposerIndex" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -371,7 +371,7 @@ test "test getBeaconProposerIndex" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
diff --git a/src/consensus/helpers/epoch.zig b/src/consensus/helpers/epoch.zig
index 0310355..2a8063c 100644
--- a/src/consensus/helpers/epoch.zig
+++ b/src/consensus/helpers/epoch.zig
@@ -114,7 +114,7 @@ test "test get_current_epoch" {
     preset.ActivePreset.set(preset.Presets.mainnet);
     defer preset.ActivePreset.reset();
 
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -167,7 +167,7 @@ test "test get_current_epoch" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -182,7 +182,7 @@ test "test get_current_epoch" {
 test "test get_previous_epoch" {
     preset.ActivePreset.set(preset.Presets.mainnet);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -231,7 +231,7 @@ test "test get_previous_epoch" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
diff --git a/src/consensus/helpers/seed.zig b/src/consensus/helpers/seed.zig
index 4a0c4c6..6b5a11b 100644
--- a/src/consensus/helpers/seed.zig
+++ b/src/consensus/helpers/seed.zig
@@ -50,7 +50,7 @@ pub fn getSeed(state: *const consensus.BeaconState, epoch: primitives.Epoch, dom
 test "test get_randao_mix" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -95,7 +95,7 @@ test "test get_randao_mix" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -116,7 +116,7 @@ test "test get_randao_mix" {
 test "test get_seed" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -172,7 +172,7 @@ test "test get_seed" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
diff --git a/src/consensus/helpers/validator.zig b/src/consensus/helpers/validator.zig
index 73630c8..a9ef0f7 100644
--- a/src/consensus/helpers/validator.zig
+++ b/src/consensus/helpers/validator.zig
@@ -179,7 +179,7 @@ test "test getValidatorChurnLimit" {
     defer preset.ActivePreset.reset();
     configs.ActiveConfig.set(preset.Presets.minimal);
     defer configs.ActiveConfig.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -236,7 +236,7 @@ test "test getValidatorChurnLimit" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -274,7 +274,7 @@ test "test getValidatorChurnLimit" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -320,7 +320,7 @@ test "test isEligibleForActivationQueue" {
 }
 
 test "test isEligibleForActivation" {
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -346,7 +346,7 @@ test "test isEligibleForActivation" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
         },
     };
@@ -413,7 +413,7 @@ test "test isSlashableValidator" {
 }
 
 test "test_getActiveValidatorIndices_withTwoActiveValidators" {
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -466,7 +466,7 @@ test "test_getActiveValidatorIndices_withTwoActiveValidators" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
@@ -482,7 +482,7 @@ test "test_getActiveValidatorIndices_withTwoActiveValidators" {
 test "test computeProposerIndex" {
     preset.ActivePreset.set(preset.Presets.minimal);
     defer preset.ActivePreset.reset();
-    var finalized_checkpoint = consensus.Checkpoint{
+    const finalized_checkpoint = consensus.Checkpoint{
         .epoch = 5,
         .root = .{0} ** 32,
     };
@@ -538,7 +538,7 @@ test "test computeProposerIndex" {
             .justification_bits = undefined,
             .previous_justified_checkpoint = undefined,
             .current_justified_checkpoint = undefined,
-            .finalized_checkpoint = &finalized_checkpoint,
+            .finalized_checkpoint = finalized_checkpoint,
             .latest_block_header = undefined,
             .inactivity_scores = undefined,
             .current_sync_committee = undefined,
diff --git a/src/consensus/phase0/types.zig b/src/consensus/phase0/types.zig
index bcc7944..0df2df7 100644
--- a/src/consensus/phase0/types.zig
+++ b/src/consensus/phase0/types.zig
@@ -5,13 +5,13 @@ const consensus = @import("../../consensus/types.zig");
 
 pub const Attestation = struct {
     aggregation_bits: []bool,
-    data: ?*consensus.AttestationData,
+    data: consensus.AttestationData,
     signature: primitives.BLSSignature,
 };
 
 pub const BeaconBlockBody = struct {
     randao_reveal: primitives.BLSSignature,
-    eth1_data: *consensus.Eth1Data, // Eth1 data vote
+    eth1_data: consensus.Eth1Data, // Eth1 data vote
     graffiti: primitives.Bytes32, // Arbitrary data
     // Operations
     proposer_slashings: []consensus.ProposerSlashing,
@@ -26,11 +26,11 @@ pub const BeaconState = struct {
     genesis_validators_root: primitives.Root,
     slot: primitives.Slot,
     fork: consensus.Fork,
-    latest_block_header: ?*consensus.BeaconBlockHeader,
+    latest_block_header: consensus.BeaconBlockHeader,
     block_roots: []primitives.Root,
     state_roots: []primitives.Root,
     historical_roots: []primitives.Root,
-    eth1_data: ?*consensus.Eth1Data,
+    eth1_data: consensus.Eth1Data,
     eth1_data_votes: []consensus.Eth1Data,
     eth1_deposit_index: u64,
     validators: []consensus.Validator,
@@ -40,9 +40,9 @@ pub const BeaconState = struct {
     previous_epoch_attestations: []consensus.PendingAttestation,
     current_epoch_attestations: []consensus.PendingAttestation,
     justification_bits: []bool,
-    previous_justified_checkpoint: *consensus.Checkpoint,
-    current_justified_checkpoint: *consensus.Checkpoint,
-    finalized_checkpoint: *consensus.Checkpoint,
+    previous_justified_checkpoint: consensus.Checkpoint,
+    current_justified_checkpoint: consensus.Checkpoint,
+    finalized_checkpoint: consensus.Checkpoint,
 };
 
 test "test BeaconState" {
diff --git a/src/consensus/types.zig b/src/consensus/types.zig
index 1f23b44..df68427 100644
--- a/src/consensus/types.zig
+++ b/src/consensus/types.zig
@@ -52,7 +52,7 @@ pub const AttestationData = struct {
 pub const IndexedAttestation = struct {
     // # [Modified in Electra:EIP7549] size: MAX_VALIDATORS_PER_COMMITTEE * MAX_COMMITTEES_PER_SLOT
     attesting_indices: []primitives.ValidatorIndex,
-    data: ?*AttestationData,
+    data: AttestationData,
     signature: primitives.BLSSignature,
 };
 
@@ -69,16 +69,6 @@ pub const Eth1Data = struct {
     block_hash: primitives.Hash32,
 };
 
-pub fn HistoricalBatchType(comptime T: preset.BeaconPreset) type {
-    return struct {
-        block_roots: [T.SLOTS_PER_HISTORICAL_ROOT]primitives.Root,
-        state_roots: [T.SLOTS_PER_HISTORICAL_ROOT]primitives.Root,
-    };
-}
-
-pub const HistoricalBatchMainnet = HistoricalBatchType(preset.mainnet_preset);
-pub const HistoricalBatchMininal = HistoricalBatchType(preset.minimal_preset);
-
 pub const HistoricalBatch = struct {
     block_roots: []primitives.Root,
     state_roots: []primitives.Root,
@@ -111,8 +101,8 @@ pub const SigningData = struct {
 };
 
 pub const AttesterSlashing = struct {
-    attestation_1: ?*IndexedAttestation, // # [Modified in Electra:EIP7549]
-    attestation_2: ?*IndexedAttestation, // # [Modified in Electra:EIP7549]
+    attestation_1: IndexedAttestation, // # [Modified in Electra:EIP7549]
+    attestation_2: IndexedAttestation, // # [Modified in Electra:EIP7549]
 };
 
 pub const Attestation = union(primitives.ForkType) {
@@ -122,11 +112,23 @@ pub const Attestation = union(primitives.ForkType) {
     capella: phase0.Attestation,
     deneb: phase0.Attestation,
     electra: electra.Attestation,
+
+    pub fn data(self: *const Attestation) AttestationData {
+        return switch (self.*) {
+            inline else => |attestation| attestation.data,
+        };
+    }
+
+    pub fn aggregationBits(self: *const Attestation) []bool {
+        return switch (self.*) {
+            inline else => |attestation| attestation.aggregation_bits,
+        };
+    }
 };
 
 pub const Deposit = struct {
     proof: [constants.DEPOSIT_CONTRACT_TREE_DEPTH + 1]primitives.Bytes32,
-    data: ?*DepositData,
+    data: DepositData,
 };
 
 pub const VoluntaryExit = struct {
@@ -144,13 +146,13 @@ pub const SignedVoluntaryExit = union(primitives.ForkType) {
 };
 
 pub const SignedBeaconBlockHeader = struct {
-    message: ?*BeaconBlockHeader,
+    message: BeaconBlockHeader,
     signature: primitives.BLSSignature,
 };
 
 pub const ProposerSlashing = struct {
-    signed_header_1: ?*SignedBeaconBlockHeader,
-    signed_header_2: ?*SignedBeaconBlockHeader,
+    signed_header_1: SignedBeaconBlockHeader,
+    signed_header_2: SignedBeaconBlockHeader,
 };
 
 pub const Eth1Block = struct {
@@ -161,7 +163,7 @@ pub const Eth1Block = struct {
 
 pub const AggregateAndProof = struct {
     aggregator_index: primitives.ValidatorIndex,
-    aggregate: ?*Attestation,
+    aggregate: Attestation,
     selection_proof: primitives.BLSSignature,
 };
 
@@ -224,7 +226,7 @@ pub const BeaconBlock = struct {
     proposer_index: primitives.ValidatorIndex,
     parent_root: primitives.Root,
     state_root: primitives.Root,
-    body: *BeaconBlockBody,
+    body: BeaconBlockBody,
 };
 
 pub const BeaconBlockBody = union(primitives.ForkType) {
@@ -237,7 +239,7 @@ pub const BeaconBlockBody = union(primitives.ForkType) {
 };
 
 pub const SignedBeaconBlock = struct {
-    message: ?*BeaconBlock,
+    message: BeaconBlock,
     signature: primitives.BLSSignature,
 };
 
@@ -604,11 +606,11 @@ test "test LightClientHeader" {
 
     const header1 = LightClientHeader{
         .altair = altair.LightClientHeader{
-            .beacon = null,
+            .beacon = undefined,
         },
     };
 
-    try std.testing.expectEqual(header1.altair.beacon, null);
+    try std.testing.expectEqual(header1.altair.beacon, undefined);
 }
 
 test "test LightClientOptimisticUpdate" {
@@ -620,13 +622,13 @@ test "test LightClientOptimisticUpdate" {
 
     const update1 = LightClientOptimisticUpdate{
         .altair = altair.LightClientOptimisticUpdate{
-            .attested_header = null,
-            .sync_aggregate = null,
+            .attested_header = undefined,
+            .sync_aggregate = undefined,
             .signature_slot = 0,
         },
     };
 
-    try std.testing.expectEqual(update1.altair.attested_header, null);
+    try std.testing.expectEqual(update1.altair.attested_header, undefined);
 }
 
 test "test LightClientFinalityUpdate" {
@@ -644,10 +646,10 @@ test "test LightClientFinalityUpdate" {
 
     const update1 = LightClientFinalityUpdate{
         .altair = altair.LightClientFinalityUpdate{
-            .attested_header = null,
-            .finalized_header = null,
+            .attested_header = undefined,
+            .finalized_header = undefined,
             .finality_branch = finality_branch,
-            .sync_aggregate = null,
+            .sync_aggregate = undefined,
             .signature_slot = 0,
         },
     };
@@ -676,12 +678,12 @@ test "test LightClientUpdate" {
 
     const update1 = LightClientUpdate{
         .altair = altair.LightClientUpdate{
-            .attested_header = null,
-            .next_sync_committee = null,
+            .attested_header = undefined,
+            .next_sync_committee = undefined,
             .next_sync_committee_branch = next_sync_committee_branch,
-            .finalized_header = null,
+            .finalized_header = undefined,
             .finality_branch = finality_branch,
-            .sync_aggregate = null,
+            .sync_aggregate = undefined,
             .signature_slot = 0,
         },
     };
@@ -704,8 +706,8 @@ test "test LightClientBootstrap" {
 
     const bootstrap1 = LightClientBootstrap{
         .altair = altair.LightClientBootstrap{
-            .header = null,
-            .current_sync_committee = null,
+            .header = undefined,
+            .current_sync_committee = undefined,
             .current_sync_committee_branch = current_sync_committee_branch,
         },
     };
@@ -777,12 +779,12 @@ test "test SignedBLSToExecutionChange" {
 
     const change1 = SignedBLSToExecutionChange{
         .capella = capella.SignedBLSToExecutionChange{
-            .message = null,
+            .message = undefined,
             .signature = undefined,
         },
     };
 
-    try std.testing.expectEqual(change1.capella.message, null);
+    try std.testing.expectEqual(change1.capella.message, undefined);
 }
 
 test "test HistoricalSummary" {