Skip to content

Commit

Permalink
feat:init validator helper
Browse files Browse the repository at this point in the history
Signed-off-by: Chen Kai <[email protected]>
  • Loading branch information
GrapeBaBa committed Oct 4, 2024
1 parent 54acd4b commit dbfad85
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 2 deletions.
34 changes: 34 additions & 0 deletions src/configs/config.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
const std = @import("std");
const primitives = @import("../primitives/types.zig");
const preset = @import("../presets/preset.zig");

pub const ActiveConfig = struct {
var config: Config = undefined;
var mutex = std.Thread.Mutex{};
var is_initialized = std.atomic.Value(bool).init(false);

pub fn set(presets: preset.Presets) void {
if (is_initialized.swap(true, .acquire)) {
return;
}

mutex.lock();
defer mutex.unlock();

config = switch (presets) {
.mainnet => mainnet_config,
.minimal => minimal_config,
};
}

pub fn get() Config {
if (!is_initialized.load(.acquire)) {
@panic("ActiveConfig not initialized");
}
return config;
}
};

pub const Config = struct {
PRESET_BASE: []const u8,
Expand Down Expand Up @@ -238,3 +266,9 @@ test "minimal config has correct MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT" {
test "minimal config has correct MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA" {
try std.testing.expectEqual(minimal_config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA, 64000000000);
}

test "test ActiveConfig" {
ActiveConfig.set(preset.Presets.mainnet);
const active_config = ActiveConfig.get();
try std.testing.expectEqual(active_config.PRESET_BASE, "mainnet");
}
2 changes: 1 addition & 1 deletion src/consensus/electra/types.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const std = @import("std");
pub const primitives = @import("../../primitives/types.zig");
const primitives = @import("../../primitives/types.zig");
const preset = @import("../../presets/preset.zig");
const consensus = @import("../../consensus/types.zig");
const phase0 = @import("../../consensus/phase0/types.zig");
Expand Down
154 changes: 154 additions & 0 deletions src/consensus/helpers/validator.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
const std = @import("std");
const primitives = @import("../../primitives/types.zig");
const consensus = @import("../../consensus/types.zig");
const configs = @import("../../configs/config.zig");
const constants = @import("../../primitives/constants.zig");
const preset = @import("../../presets/preset.zig");
const phase0 = @import("../../consensus/phase0/types.zig");

/// Check if a validator is active at a given epoch.
/// A validator is active if the current epoch is greater than or equal to the validator's activation epoch and less than the validator's exit epoch.
/// @param validator The validator to check.
/// @param epoch The epoch to check.
/// @return True if the validator is active, false otherwise.
/// Spec pseudocode definition:
///
/// def is_active_validator(validator: Validator, epoch: Epoch) -> bool:
/// """
/// Check if ``validator`` is active.
/// """
/// return validator.activation_epoch <= epoch < validator.exit_epoch
pub fn isActiveValidator(validator: *const consensus.Validator, epoch: primitives.Epoch) bool {
return validator.activation_epoch <= epoch and epoch < validator.exit_epoch;
}

/// isEligibleForActivationQueue carries out the logic for IsEligibleForActivationQueue
/// Spec pseudocode definition:
///
/// def is_eligible_for_activation_queue(validator: Validator) -> bool:
/// """
/// Check if ``validator`` is eligible to be placed into the activation queue.
/// """
/// return (
/// validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH
/// and validator.effective_balance == MAX_EFFECTIVE_BALANCE
/// )
pub fn isEligibleForActivationQueue(validator: *const consensus.Validator) bool {
return validator.activation_eligibility_epoch == constants.FAR_FUTURE_EPOCH and
validator.effective_balance == preset.ActivePreset.get().MIN_ACTIVATION_BALANCE;
}

/// isEligibleForActivation checks if a validator is eligible for activation.
/// A validator is eligible for activation if it is not yet activated and its activation eligibility epoch is less than or equal to the finalized epoch.
/// @param state The beacon state.
/// @param validator The validator to check.
/// @return True if the validator is eligible for activation, false otherwise.
/// Spec pseudocode definition:
///
/// def is_eligible_for_activation(state: BeaconState, validator: Validator) -> bool:
/// """
/// Check if ``validator`` is eligible for activation.
/// """
/// return (
/// validator.activation_eligibility_epoch <= state.finalized_checkpoint.epoch
/// and validator.activation_epoch == FAR_FUTURE_EPOCH
/// )
pub fn isEligibleForActivation(state: *const consensus.BeaconState, validator: *const consensus.Validator) bool {
return
// Placement in queue is finalized
validator.activation_eligibility_epoch <= state.finalizedCheckpointEpoch() and
// Has not yet been activated
validator.activation_epoch == constants.FAR_FUTURE_EPOCH;
}

test "test isActiveValidator" {
const validator = consensus.Validator{
.pubkey = undefined,
.withdrawal_credentials = undefined,
.effective_balance = 0,
.slashed = false,
.activation_eligibility_epoch = 0,
.activation_epoch = 0,
.exit_epoch = 10,
.withdrawable_epoch = 0,
};
const epoch: primitives.Epoch = 5;
const result = isActiveValidator(&validator, epoch);
try std.testing.expectEqual(result, true);
}

test "test isEligibleForActivationQueue" {
preset.ActivePreset.set(preset.Presets.mainnet);
const validator = consensus.Validator{
.pubkey = undefined,
.withdrawal_credentials = undefined,
.effective_balance = preset.ActivePreset.get().MIN_ACTIVATION_BALANCE,
.slashed = false,
.activation_eligibility_epoch = constants.FAR_FUTURE_EPOCH,
.activation_epoch = 0,
.exit_epoch = 0,
.withdrawable_epoch = 0,
};
const result = isEligibleForActivationQueue(&validator);
try std.testing.expectEqual(result, true);
}

test "test isEligibleForActivation" {
const finalized_checkpoint = consensus.Checkpoint{
.epoch = 5,
.root = .{0} ** 32,
};
const state = consensus.BeaconState{
.phase0 = phase0.BeaconState{
.genesis_time = 0,
.genesis_validators_root = undefined,
.slot = 0,
.fork = undefined,
.block_roots = undefined,
.state_roots = undefined,
.historical_roots = undefined,
.eth1_data = undefined,
.eth1_data_votes = undefined,
.eth1_deposit_index = 0,
.validators = undefined,
.balances = undefined,
.randao_mixes = undefined,
.slashings = undefined,
.previous_epoch_attestations = undefined,
.current_epoch_attestations = undefined,
.justification_bits = undefined,
.previous_justified_checkpoint = undefined,
.current_justified_checkpoint = undefined,
.finalized_checkpoint = @constCast(&finalized_checkpoint),
.latest_block_header = undefined,
},
};

const validator = consensus.Validator{
.pubkey = undefined,
.withdrawal_credentials = undefined,
.effective_balance = 0,
.slashed = false,
.activation_eligibility_epoch = 0,
.activation_epoch = constants.FAR_FUTURE_EPOCH,
.exit_epoch = 0,
.withdrawable_epoch = 0,
};

const result = isEligibleForActivation(&state, &validator);
try std.testing.expectEqual(result, true);

const validator2 = consensus.Validator{
.pubkey = undefined,
.withdrawal_credentials = undefined,
.effective_balance = 0,
.slashed = false,
.activation_eligibility_epoch = 10,
.activation_epoch = constants.FAR_FUTURE_EPOCH,
.exit_epoch = 0,
.withdrawable_epoch = 0,
};

const result2 = isEligibleForActivation(&state, &validator2);
try std.testing.expectEqual(result2, false);
}
2 changes: 1 addition & 1 deletion src/consensus/phase0/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub const BeaconState = struct {
justification_bits: []bool,
previous_justified_checkpoint: *consensus.Checkpoint,
current_justified_checkpoint: *consensus.Checkpoint,
finalized_checkpoint: *consensus.Checkpoint,
finalized_checkpoint: ?*consensus.Checkpoint,
};

test "test BeaconState" {
Expand Down
25 changes: 25 additions & 0 deletions src/consensus/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,16 @@ pub const BeaconState = union(primitives.ForkType) {
capella: capella.BeaconState,
deneb: capella.BeaconState,
electra: electra.BeaconState,

pub fn finalizedCheckpointEpoch(self: *const BeaconState) primitives.Epoch {
return switch (self.*) {
inline else => |state| getCheckpointEpoch(state.finalized_checkpoint),
};
}

fn getCheckpointEpoch(checkpoint: ?*Checkpoint) primitives.Epoch {
return if (checkpoint) |c| c.epoch else @as(primitives.Epoch, 0);
}
};

test "test Attestation" {
Expand Down Expand Up @@ -857,3 +867,18 @@ test "test BeaconState" {

try std.testing.expectEqual(state.phase0.genesis_time, 0);
}

test "test Validator" {
const validator = Validator{
.pubkey = undefined,
.withdrawal_credentials = undefined,
.effective_balance = 0,
.slashed = false,
.activation_eligibility_epoch = 0,
.activation_epoch = 0,
.exit_epoch = 0,
.withdrawable_epoch = 0,
};

try std.testing.expectEqual(validator.effective_balance, 0);
}
33 changes: 33 additions & 0 deletions src/presets/preset.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
const std = @import("std");
const primitives = @import("../primitives/types.zig");

pub const ActivePreset = struct {
var preset: BeaconPreset = undefined;
var mutex = std.Thread.Mutex{};
var is_initialized = std.atomic.Value(bool).init(false);

pub fn set(presets: Presets) void {
if (is_initialized.swap(true, .acquire)) {
return;
}

mutex.lock();
defer mutex.unlock();

preset = switch (presets) {
.mainnet => mainnet_preset,
.minimal => minimal_preset,
};
}

pub fn get() BeaconPreset {
if (!is_initialized.load(.acquire)) {
@panic("ActivePreset not initialized");
}
return preset;
}
};

pub const Presets = enum {
mainnet,
minimal,
Expand Down Expand Up @@ -328,3 +355,9 @@ test "minimal preset" {
try std.testing.expectEqual(minimal_preset.MIN_SLASHING_PENALTY_QUOTIENT_ELECTRA, 4096);
try std.testing.expectEqual(minimal_preset.MIN_ACTIVATION_BALANCE, 32000000000);
}

test "test ActivePreset" {
ActivePreset.set(Presets.mainnet);
const active_preset = ActivePreset.get();
try std.testing.expectEqual(active_preset.MAX_BYTES_PER_TRANSACTION, 1073741824);
}
1 change: 1 addition & 0 deletions src/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub const bellatrix = @import("consensus/bellatrix/types.zig");
pub const capella = @import("consensus/capella/types.zig");
pub const deneb = @import("consensus/deneb/types.zig");
pub const electra = @import("consensus/electra/types.zig");
pub const validator_helpers = @import("consensus/helpers/validator.zig");

test {
@import("std").testing.refAllDeclsRecursive(@This());
Expand Down

0 comments on commit dbfad85

Please sign in to comment.