Skip to content

Commit

Permalink
feat:init state from eth1
Browse files Browse the repository at this point in the history
Signed-off-by: Chen Kai <[email protected]>
  • Loading branch information
GrapeBaBa committed Oct 27, 2024
1 parent 159048b commit f27f314
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 13 deletions.
60 changes: 60 additions & 0 deletions src/consensus/helpers/balance.zig
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ pub fn decreaseBalance(state: *const consensus.BeaconState, index: primitives.Va
}
}

/// getMaxEffectiveBalance returns the maximum effective balance for `validator`.
/// @param validator - The validator to get the maximum effective balance for.
/// @returns The maximum effective balance for `validator`.
/// Spec pseudocode definition:
/// def get_max_effective_balance(validator: Validator) -> Gwei:
/// """
/// Get max effective balance for ``validator``.
/// """
/// if has_compounding_withdrawal_credential(validator):
/// return MAX_EFFECTIVE_BALANCE_ELECTRA
/// else:
/// return MIN_ACTIVATION_BALANCE
pub fn getMaxEffectiveBalance(validator: *const consensus.Validator) primitives.Gwei {
// Get max effective balance for `validator`.
if (validator_helper.hasCompoundingWithdrawalCredential(validator)) {
return preset.ActivePreset.get().MAX_EFFECTIVE_BALANCE_ELECTRA;
} else {
return preset.ActivePreset.get().MIN_ACTIVATION_BALANCE;
}
}

test "test getTotalBalance" {
preset.ActivePreset.set(preset.Presets.minimal);
defer preset.ActivePreset.reset();
Expand Down Expand Up @@ -330,3 +351,42 @@ test "test decreaseBalance" {
state.balances()[2],
);
}

test "test getMaxEffectiveBalance" {
preset.ActivePreset.set(preset.Presets.minimal);
defer preset.ActivePreset.reset();

const validator = consensus.Validator{
.pubkey = undefined,
.withdrawal_credentials = [_]u8{0x2} ++ [_]u8{0} ** 31,
.effective_balance = 10000000000,
.slashed = false,
.activation_eligibility_epoch = 0,
.activation_epoch = 0,
.exit_epoch = 10,
.withdrawable_epoch = 10,
};

const max_effective_balance = getMaxEffectiveBalance(&validator);
try std.testing.expectEqual(
preset.ActivePreset.get().MAX_EFFECTIVE_BALANCE_ELECTRA,
max_effective_balance,
);

const validator1 = consensus.Validator{
.pubkey = undefined,
.withdrawal_credentials = [_]u8{0} ** 32,
.effective_balance = 10000000000,
.slashed = false,
.activation_eligibility_epoch = 0,
.activation_epoch = 0,
.exit_epoch = 10,
.withdrawable_epoch = 10,
};

const max_effective_balance1 = getMaxEffectiveBalance(&validator1);
try std.testing.expectEqual(
preset.ActivePreset.get().MIN_ACTIVATION_BALANCE,
max_effective_balance1,
);
}
91 changes: 84 additions & 7 deletions src/consensus/helpers/genesis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,94 @@ const electra = @import("../../consensus/electra/types.zig");
const deneb = @import("../../consensus/deneb/types.zig");
const validator_helper = @import("../../consensus/helpers/validator.zig");
const balance_helper = @import("../../consensus/helpers/balance.zig");
const committee_helper = @import("../../consensus/helpers/committee.zig");
const ssz = @import("../../ssz/ssz.zig");

/// isValidGenesisState verifies the validity of a genesis state.
/// @param state - The state.
/// @param allocator - The allocator.
/// @returns True if the state is valid, false otherwise.
/// Spec pseudocode definition:
/// def is_valid_genesis_state(state: BeaconState) -> bool:
/// if state.genesis_time < config.MIN_GENESIS_TIME:
/// return False
/// if len(get_active_validator_indices(state, GENESIS_EPOCH)) < config.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT:
/// return False
/// return True
pub fn isValidGenesisState(state: *consensus.BeaconState, allocator: std.mem.Allocator) !bool {
if (state.genesisTime() < configs.ActiveConfig.get().MIN_GENESIS_TIME) {
return false;
}
const indices = try validator_helper.getActiveValidatorIndices(state, constants.GENESIS_EPOCH, allocator);
defer allocator.free(indices);
if (indices.len < configs.ActiveConfig.get().MIN_GENESIS_ACTIVE_VALIDATOR_COUNT) {
return false;
}
return true;
}

/// initializeBeaconStateFromEth1 initializes the beacon state from the eth1 block hash, timestamp, and deposits.
/// @param fork_type - The fork type.
/// @param eth1_block_hash - The eth1 block hash.
/// @param eth1_timestamp - The eth1 timestamp.
/// @param deposits - The deposits.
/// @param execution_payload_header - The execution payload header.
/// @param allocator - The allocator.
/// @returns The initialized beacon state.
/// Spec pseudocode definition:
/// def initialize_beacon_state_from_eth1(eth1_block_hash: Hash32,
/// eth1_timestamp: uint64,
/// deposits: Sequence[Deposit],
/// execution_payload_header: ExecutionPayloadHeader=ExecutionPayloadHeader()
/// ) -> BeaconState:
/// fork = Fork(
/// previous_version=config.ELECTRA_FORK_VERSION, # [Modified in Electra:EIP6110] for testing only
/// current_version=config.ELECTRA_FORK_VERSION, # [Modified in Electra:EIP6110]
/// epoch=GENESIS_EPOCH,
/// )
/// state = BeaconState(
/// genesis_time=eth1_timestamp + config.GENESIS_DELAY,
/// fork=fork,
/// eth1_data=Eth1Data(block_hash=eth1_block_hash, deposit_count=uint64(len(deposits))),
/// latest_block_header=BeaconBlockHeader(body_root=hash_tree_root(BeaconBlockBody())),
/// randao_mixes=[eth1_block_hash] * EPOCHS_PER_HISTORICAL_VECTOR, # Seed RANDAO with Eth1 entropy
/// deposit_requests_start_index=UNSET_DEPOSIT_REQUESTS_START_INDEX, # [New in Electra:EIP6110]
/// )
///
/// # Process deposits
/// leaves = list(map(lambda deposit: deposit.data, deposits))
/// for index, deposit in enumerate(deposits):
/// deposit_data_list = List[DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH](*leaves[:index + 1])
/// state.eth1_data.deposit_root = hash_tree_root(deposit_data_list)
/// process_deposit(state, deposit)
///
/// # Process deposit balance updates
/// for deposit in state.pending_balance_deposits:
/// increase_balance(state, deposit.index, deposit.amount)
/// state.pending_balance_deposits = []
///
/// # Process activations
/// for index, validator in enumerate(state.validators):
/// balance = state.balances[index]
/// # [Modified in Electra:EIP7251]
/// validator.effective_balance = min(
/// balance - balance % EFFECTIVE_BALANCE_INCREMENT, get_max_effective_balance(validator))
/// if validator.effective_balance >= MIN_ACTIVATION_BALANCE:
/// validator.activation_eligibility_epoch = GENESIS_EPOCH
/// validator.activation_epoch = GENESIS_EPOCH
///
/// # Set genesis validators root for domain separation and chain versioning
/// state.genesis_validators_root = hash_tree_root(state.validators)
///
/// # Fill in sync committees
/// # Note: A duplicate committee is assigned for the current and next committee at genesis
/// state.current_sync_committee = get_next_sync_committee(state)
/// state.next_sync_committee = get_next_sync_committee(state)
///
/// # Initialize the execution payload header
/// state.latest_execution_payload_header = execution_payload_header
///
/// return state
pub fn initializeBeaconStateFromEth1(
fork_type: primitives.ForkType,
eth1_block_hash: primitives.Hash32,
Expand Down Expand Up @@ -235,7 +310,7 @@ pub fn initializeBeaconStateFromEth1(
for (state.validators(), 0..) |*validator, index| {
const balance = state.balances()[index];
const max_balance = if (state == .electra)
preset.ActivePreset.get().MAX_EFFECTIVE_BALANCE_ELECTRA
balance_helper.getMaxEffectiveBalance(validator)
else
preset.ActivePreset.get().MAX_EFFECTIVE_BALANCE;
validator.effective_balance = @min(
Expand All @@ -251,12 +326,14 @@ pub fn initializeBeaconStateFromEth1(
// Set genesis validators root for domain separation and chain versioning
try ssz.hashTreeRoot(state.validators(), state.genesisValidatorsRootPtr(), allocator);

// // Fill in sync committees
// state.current_sync_committee = try get_next_sync_committee(&state);
// state.next_sync_committee = try get_next_sync_committee(&state);
//
// // Initialize the execution payload header
// state.latest_execution_payload_header = execution_payload_header;
// Fill in sync committees
state.setCurrentSyncCommittee(try committee_helper.getNextSyncCommittee(&state, allocator));
state.setNextSyncCommittee(try committee_helper.getNextSyncCommittee(&state, allocator));

if (execution_payload_header != null) {
// Initialize the execution payload header
state.setLatestExecutionPayloadHeader(execution_payload_header.?);
}

return state;
}
Expand Down
10 changes: 5 additions & 5 deletions src/consensus/helpers/merkle.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const constants = @import("../../primitives/constants.zig");
const preset = @import("../../presets/preset.zig");
const sha256 = std.crypto.hash.sha2.Sha256;

/// verifyMerkleProof verifies a merkle proof.
/// isValidMerkleBranch verifies a merkle proof.
/// @param leaf - The leaf value.
/// @param branch - The branch.
/// @param depth - The depth.
Expand All @@ -25,7 +25,7 @@ const sha256 = std.crypto.hash.sha2.Sha256;
/// else:
/// value = hash(value + branch[i])
/// return value == root
pub fn verifyMerkleProof(leaf: primitives.Bytes32, branch: []const primitives.Bytes32, depth: u64, index: u64, root: primitives.Root) !bool {
pub fn isValidMerkleBranch(leaf: primitives.Bytes32, branch: []const primitives.Bytes32, depth: u64, index: u64, root: primitives.Root) !bool {
var value: [32]u8 = leaf;
var i: u64 = 0;
while (i < depth) : (i += 1) {
Expand All @@ -42,13 +42,13 @@ pub fn verifyMerkleProof(leaf: primitives.Bytes32, branch: []const primitives.By
return std.mem.eql(u8, &value, &root);
}

test "verifyMerkleProof" {
test isValidMerkleBranch {
const leaf: primitives.Bytes32 = undefined;
const branch: [32]primitives.Bytes32 = undefined;
const root: primitives.Root = undefined;
const depth: u64 = 0;
const index: u64 = 0;
try std.testing.expect(try verifyMerkleProof(leaf, &branch, depth, index, root));
try std.testing.expect(try isValidMerkleBranch(leaf, &branch, depth, index, root));
}

test "verifyMerkleProof with valid branch" {
Expand All @@ -57,5 +57,5 @@ test "verifyMerkleProof with valid branch" {
const root: primitives.Root = [_]u8{ 228, 209, 245, 144, 152, 7, 227, 251, 129, 176, 248, 115, 30, 139, 1, 35, 21, 112, 168, 110, 176, 175, 25, 181, 52, 215, 85, 95, 22, 63, 166, 194 };
const depth: u64 = 5;
const index: u64 = 0;
try std.testing.expect(try verifyMerkleProof(leaf, &branch, depth, index, root));
try std.testing.expect(try isValidMerkleBranch(leaf, &branch, depth, index, root));
}
17 changes: 16 additions & 1 deletion src/consensus/helpers/validator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -389,11 +389,26 @@ pub fn slashValidator(state: *consensus.BeaconState, slashed_index: primitives.V
balance_helper.increaseBalance(state, whistleblower, whistleblower_reward - proposer_reward);
}

/// isCompoundingWithdrawalCredential checks if a withdrawal credential is a compounding withdrawal credential.
/// @param withdrawal_credentials The withdrawal credential to check.
/// @return True if the withdrawal credential is a compounding withdrawal credential, false otherwise.
/// Spec pseudocode definition:
/// def is_compounding_withdrawal_credential(withdrawal_credentials: Bytes32) -> bool:
/// return withdrawal_credentials[:1] == COMPOUNDING_WITHDRAWAL_PREFIX
pub fn isCompoundingWithdrawalCredential(withdrawal_credentials: primitives.Bytes32) bool {
return withdrawal_credentials[0] == constants.COMPOUNDING_WITHDRAWAL_PREFIX;
}

pub fn hasCompoundingWithdrawalCredential(validator: *consensus.Validator) bool {
/// hasCompoundingWithdrawalCredential checks if a validator has a compounding withdrawal credential.
/// @param validator The validator to check.
/// @return True if the validator has a compounding withdrawal credential, false otherwise.
/// Spec pseudocode definition:
/// def has_compounding_withdrawal_credential(validator: Validator) -> bool:
/// """
/// Check if ``validator`` has an 0x02 prefixed "compounding" withdrawal credential.
/// """
/// return is_compounding_withdrawal_credential(validator.withdrawal_credentials)
pub fn hasCompoundingWithdrawalCredential(validator: *const consensus.Validator) bool {
// Check if validator has an 0x02 prefixed "compounding" withdrawal credential
return isCompoundingWithdrawalCredential(validator.withdrawal_credentials);
}
Expand Down
50 changes: 50 additions & 0 deletions src/consensus/types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,56 @@ pub const BeaconState = union(primitives.ForkType) {
deneb: capella.BeaconState,
electra: electra.BeaconState,

pub fn setLatestExecutionPayloadHeader(self: *BeaconState, header: ExecutionPayloadHeader) void {
const supported_forks = [_]primitives.ForkType{
.bellatrix,
.capella,
.deneb,
.electra,
};

inline for (supported_forks) |f| {
if (std.meta.activeTag(self.*) == f) {
@field(self, @tagName(f)).latest_execution_payload_header = header;
return;
}
}
}

pub fn setCurrentSyncCommittee(self: *BeaconState, sync_committee: SyncCommittee) void {
const supported_forks = [_]primitives.ForkType{
.altair,
.bellatrix,
.capella,
.deneb,
.electra,
};

inline for (supported_forks) |f| {
if (std.meta.activeTag(self.*) == f) {
@field(self, @tagName(f)).current_sync_committee = sync_committee;
return;
}
}
}

pub fn setNextSyncCommittee(self: *BeaconState, sync_committee: SyncCommittee) void {
const supported_forks = [_]primitives.ForkType{
.altair,
.bellatrix,
.capella,
.deneb,
.electra,
};

inline for (supported_forks) |f| {
if (std.meta.activeTag(self.*) == f) {
@field(self, @tagName(f)).next_sync_committee = sync_committee;
return;
}
}
}

pub fn forkedBeaconState(self: *BeaconState) *BeaconState {
return self;
}
Expand Down

0 comments on commit f27f314

Please sign in to comment.