From 7fd3d05dae7fbfa9c82554e5aaef4fbff6cfbb02 Mon Sep 17 00:00:00 2001 From: Chen Kai <281165273grape@gmail.com> Date: Mon, 4 Nov 2024 13:06:21 +0800 Subject: [PATCH] feat:add more helper Signed-off-by: Chen Kai <281165273grape@gmail.com> --- .../helpers/justification_finalization.zig | 200 +++++++++++++----- src/consensus/types.zig | 36 ++++ src/primitives/constants.zig | 2 + 3 files changed, 180 insertions(+), 58 deletions(-) diff --git a/src/consensus/helpers/justification_finalization.zig b/src/consensus/helpers/justification_finalization.zig index dca8a72..8944101 100644 --- a/src/consensus/helpers/justification_finalization.zig +++ b/src/consensus/helpers/justification_finalization.zig @@ -11,65 +11,149 @@ const epoch_helper = @import("../../consensus/helpers/epoch.zig"); const shuffle_helper = @import("../../consensus/helpers/shuffle.zig"); const balance_helper = @import("../../consensus/helpers/balance.zig"); const committee_helper = @import("../../consensus/helpers/committee.zig"); +const siging_root_helper = @import("../../consensus/helpers/signing_root.zig"); +const block_root_helper = @import("../../consensus/helpers/block_root.zig"); +const validator_helper = @import("../../consensus/helpers/validator.zig"); -// pub fn weighJustificationAndFinalization( -// state: *consensus.BeaconState, -// total_active_balance: primitives.Gwei, -// previous_epoch_target_balance: primitives.Gwei, -// current_epoch_target_balance: primitives.Gwei, -// ) void { -// const previous_epoch = epoch_helper.getPreviousEpoch(state); -// const current_epoch = epoch_helper.getCurrentEpoch(state); -// const old_previous_justified_checkpoint = state.p; -// const old_current_justified_checkpoint = state.current_justified_checkpoint; -// -// // Process justifications -// state.previous_justified_checkpoint = state.current_justified_checkpoint; -// -// // Shift justification bits -// var i: usize = constants.JUSTIFICATION_BITS_LENGTH - 1; -// while (i > 0) : (i -= 1) { -// state.justification_bits[i] = state.justification_bits[i - 1]; -// } -// state.justification_bits[0] = 0; -// -// if (previous_epoch_target_balance * 3 >= total_active_balance * 2) { -// state.current_justified_checkpoint = consensus.Checkpoint{ -// .epoch = previous_epoch, -// .root = getBlockRoot(state, previous_epoch), -// }; -// state.justification_bits[1] = 1; -// } -// -// if (current_epoch_target_balance * 3 >= total_active_balance * 2) { -// state.current_justified_checkpoint = Checkpoint{ -// .epoch = current_epoch, -// .root = getBlockRoot(state, current_epoch), -// }; -// state.justification_bits[0] = 1; -// } -// -// // Process finalizations -// const bits = state.justification_bits; -// -// // The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source -// if (allBitsSet(bits[1..4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch) { -// state.finalized_checkpoint = old_previous_justified_checkpoint; -// } -// // The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source -// if (allBitsSet(bits[1..3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch) { -// state.finalized_checkpoint = old_previous_justified_checkpoint; -// } -// // The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source -// if (allBitsSet(bits[0..3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch) { -// state.finalized_checkpoint = old_current_justified_checkpoint; -// } -// // The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source -// if (allBitsSet(bits[0..2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch) { -// state.finalized_checkpoint = old_current_justified_checkpoint; -// } -// } +/// weighJustificationAndFinalization weighs justification and finalization for the current epoch. +/// +/// Spec pseudocode definition: +/// def weigh_justification_and_finalization(state: BeaconState, +/// total_active_balance: Gwei, +/// previous_epoch_target_balance: Gwei, +/// current_epoch_target_balance: Gwei) -> None: +/// previous_epoch = get_previous_epoch(state) +/// current_epoch = get_current_epoch(state) +/// old_previous_justified_checkpoint = state.previous_justified_checkpoint +/// old_current_justified_checkpoint = state.current_justified_checkpoint +/// +/// # Process justifications +/// state.previous_justified_checkpoint = state.current_justified_checkpoint +/// state.justification_bits[1:] = state.justification_bits[:JUSTIFICATION_BITS_LENGTH - 1] +/// state.justification_bits[0] = 0b0 +/// if previous_epoch_target_balance * 3 >= total_active_balance * 2: +/// state.current_justified_checkpoint = Checkpoint(epoch=previous_epoch, +/// root=get_block_root(state, previous_epoch)) +/// state.justification_bits[1] = 0b1 +/// if current_epoch_target_balance * 3 >= total_active_balance * 2: +/// state.current_justified_checkpoint = Checkpoint(epoch=current_epoch, +/// root=get_block_root(state, current_epoch)) +/// state.justification_bits[0] = 0b1 +/// +/// # Process finalizations +/// bits = state.justification_bits +/// # The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source +/// if all(bits[1:4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch: +/// state.finalized_checkpoint = old_previous_justified_checkpoint +/// # The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source +/// if all(bits[1:3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch: +/// state.finalized_checkpoint = old_previous_justified_checkpoint +/// # The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source +/// if all(bits[0:3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch: +/// state.finalized_checkpoint = old_current_justified_checkpoint +/// # The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source +/// if all(bits[0:2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch: +/// state.finalized_checkpoint = old_current_justified_checkpoint +pub fn weighJustificationAndFinalization( + state: *consensus.BeaconState, + total_active_balance: primitives.Gwei, + previous_epoch_target_balance: primitives.Gwei, + current_epoch_target_balance: primitives.Gwei, +) !void { + const previous_epoch = epoch_helper.getPreviousEpoch(state); + const current_epoch = epoch_helper.getCurrentEpoch(state); + const old_previous_justified_checkpoint = state.previousJustifiedCheckpoint(); + const old_current_justified_checkpoint = state.currentJustifiedCheckpoint(); + + // Process justifications + state.setPreviousJustifiedCheckpoint(&state.currentJustifiedCheckpoint()); + + // Shift justification bits + var i: usize = constants.JUSTIFICATION_BITS_LENGTH - 1; + while (i > 0) : (i -= 1) { + state.justificationBits()[i] = state.justificationBits()[i - 1]; + } + state.justificationBits()[0] = false; + + if (previous_epoch_target_balance * 3 >= total_active_balance * 2) { + const root = try block_root_helper.getBlockRoot(state, previous_epoch); + state.setCurrentJustifiedCheckpoint(&consensus.Checkpoint{ + .epoch = previous_epoch, + .root = root, + }); + state.justificationBits()[1] = true; + } + + if (current_epoch_target_balance * 3 >= total_active_balance * 2) { + const root = try block_root_helper.getBlockRoot(state, current_epoch); + state.setCurrentJustifiedCheckpoint(&consensus.Checkpoint{ + .epoch = current_epoch, + .root = root, + }); + state.justificationBits()[0] = true; + } + + // Process finalizations + const bits = state.justificationBits(); + + // The 2nd/3rd/4th most recent epochs are justified, the 2nd using the 4th as source + if (allBitsSet(bits[1..4]) and old_previous_justified_checkpoint.epoch + 3 == current_epoch) { + state.setFinalizedCheckpoint(&old_previous_justified_checkpoint); + } + // The 2nd/3rd most recent epochs are justified, the 2nd using the 3rd as source + if (allBitsSet(bits[1..3]) and old_previous_justified_checkpoint.epoch + 2 == current_epoch) { + state.setFinalizedCheckpoint(&old_previous_justified_checkpoint); + } + // The 1st/2nd/3rd most recent epochs are justified, the 1st using the 3rd as source + if (allBitsSet(bits[0..3]) and old_current_justified_checkpoint.epoch + 2 == current_epoch) { + state.setFinalizedCheckpoint(&old_current_justified_checkpoint); + } + // The 1st/2nd most recent epochs are justified, the 1st using the 2nd as source + if (allBitsSet(bits[0..2]) and old_current_justified_checkpoint.epoch + 1 == current_epoch) { + state.setFinalizedCheckpoint(&old_current_justified_checkpoint); + } +} + +/// processJustificationAndFinalization processes justification and finalization for the current epoch. +/// +/// Spec pseudocode definition: +/// def process_justification_and_finalization(state: BeaconState) -> None: +/// # Initial FFG checkpoint values have a `0x00` stub for `root`. +/// # Skip FFG updates in the first two epochs to avoid corner cases that might result in modifying this stub. +/// if get_current_epoch(state) <= GENESIS_EPOCH + 1: +/// return +/// previous_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, get_previous_epoch(state)) +/// current_indices = get_unslashed_participating_indices(state, TIMELY_TARGET_FLAG_INDEX, get_current_epoch(state)) +/// total_active_balance = get_total_active_balance(state) +/// previous_target_balance = get_total_balance(state, previous_indices) +/// current_target_balance = get_total_balance(state, current_indices) +/// weigh_justification_and_finalization(state, total_active_balance, previous_target_balance, current_target_balance) +pub fn processJustificationAndFinalization(state: *consensus.BeaconState, allocator: std.mem.Allocator) !void { + // Initial FFG checkpoint values have a `0x00` stub for `root`. + // Skip FFG updates in the first two epochs to avoid corner cases that might result in modifying this stub. + if (epoch_helper.getCurrentEpoch(state) <= constants.GENESIS_EPOCH + 1) { + return; + } + + const previous_indices = try validator_helper.getUnslashedParticipatingIndices(state, constants.TIMELY_TARGET_FLAG_INDEX, epoch_helper.getPreviousEpoch(state), allocator); + var previous_indices_map = std.AutoHashMap(primitives.ValidatorIndex, void).init(allocator); + defer previous_indices_map.deinit(); + for (previous_indices) |index| { + try previous_indices_map.put(index, {}); + } + const current_indices = try validator_helper.getUnslashedParticipatingIndices(state, constants.TIMELY_TARGET_FLAG_INDEX, epoch_helper.getCurrentEpoch(state), allocator); + var current_indices_map = std.AutoHashMap(primitives.ValidatorIndex, void).init(allocator); + defer current_indices_map.deinit(); + for (current_indices) |index| { + try current_indices_map.put(index, {}); + } + const total_active_balance = try balance_helper.getTotalActiveBalance(state, allocator); + const previous_target_balance = balance_helper.getTotalBalance(state, &previous_indices_map); + const current_target_balance = balance_helper.getTotalBalance(state, ¤t_indices_map); + + try weighJustificationAndFinalization(state, total_active_balance, previous_target_balance, current_target_balance); +} fn allBitsSet(bits: []const bool) bool { - return !std.mem.containsAtLeast(bool, bits, 1, false); + return !std.mem.containsAtLeast(bool, bits, 1, &[_]bool{false}); } diff --git a/src/consensus/types.zig b/src/consensus/types.zig index 4558137..313c42b 100644 --- a/src/consensus/types.zig +++ b/src/consensus/types.zig @@ -747,6 +747,42 @@ pub const BeaconState = union(primitives.ForkType) { }; } + pub fn currentJustifiedCheckpoint(self: *const BeaconState) Checkpoint { + return switch (self.*) { + inline else => |state| state.current_justified_checkpoint, + }; + } + + pub fn setCurrentJustifiedCheckpoint(self: *BeaconState, checkpoint: *const Checkpoint) void { + switch (self.*) { + inline else => |*state| state.current_justified_checkpoint = checkpoint.*, + } + } + + pub fn previousJustifiedCheckpoint(self: *const BeaconState) Checkpoint { + return switch (self.*) { + inline else => |state| state.previous_justified_checkpoint, + }; + } + + pub fn setPreviousJustifiedCheckpoint(self: *BeaconState, checkpoint: *const Checkpoint) void { + switch (self.*) { + inline else => |*state| state.previous_justified_checkpoint = checkpoint.*, + } + } + + pub fn justificationBits(self: *const BeaconState) []bool { + return switch (self.*) { + inline else => |state| state.justification_bits, + }; + } + + pub fn setFinalizedCheckpoint(self: *BeaconState, checkpoint: *const Checkpoint) void { + switch (self.*) { + inline else => |*state| state.finalized_checkpoint = checkpoint.*, + } + } + /// inactivityScores returns the inactivity scores of the given state. pub fn inactivityScores(self: *const BeaconState) []u64 { return switch (self.*) { diff --git a/src/primitives/constants.zig b/src/primitives/constants.zig index 72bf2bc..2185db8 100644 --- a/src/primitives/constants.zig +++ b/src/primitives/constants.zig @@ -46,3 +46,5 @@ pub const UNSET_DEPOSIT_REQUESTS_START_INDEX: u64 = std.math.maxInt(u64); pub const COMPOUNDING_WITHDRAWAL_PREFIX: types.Bytes1 = 0x02; pub const DOMAIN_SYNC_COMMITTEE: types.DomainType = .{ 0x07, 0x00, 0x00, 0x00 }; pub const DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF: types.DomainType = .{ 0x08, 0x00, 0x00, 0x00 }; + +pub const TIMELY_TARGET_FLAG_INDEX: u3 = 1;