Skip to content

Commit

Permalink
feat: use is_electra_activated
Browse files Browse the repository at this point in the history
  • Loading branch information
madlabman committed Jan 24, 2025
1 parent 00dc0c3 commit 6587905
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 95 deletions.
3 changes: 1 addition & 2 deletions src/modules/accounting/accounting.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,7 @@ def _get_consensus_lido_state(self, blockstamp: ReferenceBlockStamp) -> tuple[Va

consensus_version = self.w3.lido_contracts.accounting_oracle.get_consensus_version(blockstamp.block_hash)
if consensus_version > 2:
spec = self.w3.cc.get_config_spec()
if blockstamp.ref_epoch >= int(spec.ELECTRA_FORK_EPOCH):
if self.w3.cc.is_electra_activated(blockstamp.ref_epoch):
state = self.w3.cc.get_state_view(blockstamp)
total_lido_eth1_bridge_deposits_amount = self.w3.lido_validators.calculate_total_eth1_bridge_deposits_amount(
lido_validators, state.pending_deposits
Expand Down
14 changes: 6 additions & 8 deletions src/modules/ejector/ejector.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,11 @@ def _get_predicted_withdrawable_epoch(
"""
Returns epoch when all validators in queue and validators_to_eject will be withdrawn.
"""
spec = self.w3.cc.get_config_spec()

if blockstamp.ref_epoch < int(spec.ELECTRA_FORK_EPOCH):
return self._get_predicted_withdrawable_epoch_pre_electra(blockstamp, validators_to_eject)
if self.w3.cc.is_electra_activated(blockstamp.ref_epoch):
return self._get_predicted_withdrawable_epoch_post_electra(blockstamp, validators_to_eject)

return self._get_predicted_withdrawable_epoch_post_electra(blockstamp, validators_to_eject)
return self._get_predicted_withdrawable_epoch_pre_electra(blockstamp, validators_to_eject)

def _get_predicted_withdrawable_epoch_pre_electra(
self,
Expand Down Expand Up @@ -320,11 +319,10 @@ def _get_latest_exit_epoch(self, blockstamp: ReferenceBlockStamp) -> tuple[Epoch
@lru_cache(maxsize=1)
def _get_sweep_delay_in_epochs(self, blockstamp: ReferenceBlockStamp) -> int:
"""Returns amount of epochs that will take to sweep all validators in chain."""
spec = self.w3.cc.get_config_spec()
chain_config = self.get_chain_config(blockstamp)
electra_epoch = int(spec.ELECTRA_FORK_EPOCH)
if self.get_consensus_version(blockstamp) < 3 or blockstamp.ref_epoch < electra_epoch:
if self.get_consensus_version(blockstamp) < 3 or not self.w3.cc.is_electra_activated(blockstamp.ref_epoch):
return self._get_sweep_delay_in_epochs_pre_pectra(blockstamp)

chain_config = self.get_chain_config(blockstamp)
state = self.w3.cc.get_state_view(blockstamp)
return get_sweep_delay_in_epochs_post_pectra(state, chain_config)

Expand Down
5 changes: 5 additions & 0 deletions src/providers/consensus/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class ConsensusClient(HTTPProvider):
state_id
State identifier. Can be one of: "head" (canonical head in node's view), "genesis", "finalized", "justified", <slot>, <hex encoded stateRoot with 0x prefix>.
"""

PROVIDER_EXCEPTION = ConsensusClientError
PROMETHEUS_HISTOGRAM = CL_REQUESTS_DURATION

Expand All @@ -52,6 +53,10 @@ class ConsensusClient(HTTPProvider):
API_GET_SPEC = 'eth/v1/config/spec'
API_GET_GENESIS = 'eth/v1/beacon/genesis'

def is_electra_activated(self, epoch: EpochNumber) -> bool:
spec = self.get_config_spec()
return epoch >= spec.ELECTRA_FORK_EPOCH

def get_config_spec(self) -> BeaconSpecResponse:
"""Spec: https://ethereum.github.io/beacon-APIs/#/Config/getSpec"""
data, _ = self._get(self.API_GET_SPEC)
Expand Down
2 changes: 1 addition & 1 deletion src/providers/consensus/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class BeaconSpecResponse(FromResponse):
SECONDS_PER_SLOT: str
DEPOSIT_CONTRACT_ADDRESS: str
SLOTS_PER_HISTORICAL_ROOT: str
ELECTRA_FORK_EPOCH: str = str(FAR_FUTURE_EPOCH)
ELECTRA_FORK_EPOCH: int = FAR_FUTURE_EPOCH


@dataclass
Expand Down
10 changes: 8 additions & 2 deletions src/services/bunker.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,17 @@ def is_bunker_mode(
logger.info({"msg": "Bunker ON. CL rebase is negative"})
return True

cl_spec = self.w3.cc.get_config_spec()
consensus_version = self.w3.lido_contracts.accounting_oracle.get_consensus_version(blockstamp.block_hash)
web3_converter = Web3Converter(chain_config, frame_config)
high_midterm_slashing_penalty = MidtermSlashingPenalty.is_high_midterm_slashing_penalty(
blockstamp, consensus_version, cl_spec, web3_converter, all_validators, lido_validators, current_report_cl_rebase, last_report_ref_slot
blockstamp,
consensus_version,
self.w3.cc.is_electra_activated,
web3_converter,
all_validators,
lido_validators,
current_report_cl_rebase,
last_report_ref_slot,
)
if high_midterm_slashing_penalty:
logger.info({"msg": "Bunker ON. High midterm slashing penalty"})
Expand Down
3 changes: 1 addition & 2 deletions src/services/bunker_cases/abnormal_cl_rebase.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,7 @@ def _get_lido_validators_balance_with_vault(
consensus_version = self.w3.lido_contracts.accounting_oracle.get_consensus_version(blockstamp.block_hash)
if consensus_version > 2:
epoch = EpochNumber(blockstamp.slot_number // self.c_conf.slots_per_epoch)
spec = self.w3.cc.get_config_spec()
if epoch >= int(spec.ELECTRA_FORK_EPOCH):
if self.w3.cc.is_electra_activated(epoch):
state = self.w3.cc.get_state_view(blockstamp)
pending_deposits_sum = LidoValidatorsProvider.calculate_total_eth1_bridge_deposits_amount(
lido_validators, state.pending_deposits
Expand Down
67 changes: 37 additions & 30 deletions src/services/bunker_cases/midterm_slashing_penalty.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import logging
from collections import defaultdict
from typing import Callable

from src.constants import (
EFFECTIVE_BALANCE_INCREMENT,
EPOCHS_PER_SLASHINGS_VECTOR,
MAX_EFFECTIVE_BALANCE,
MIN_VALIDATOR_WITHDRAWABILITY_DELAY,
PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX,
EFFECTIVE_BALANCE_INCREMENT,
MAX_EFFECTIVE_BALANCE,
)
from src.providers.consensus.types import Validator, BeaconSpecResponse
from src.types import EpochNumber, Gwei, ReferenceBlockStamp, FrameNumber, SlotNumber
from src.providers.consensus.types import Validator
from src.types import EpochNumber, FrameNumber, Gwei, ReferenceBlockStamp, SlotNumber
from src.utils.validator_state import calculate_total_active_effective_balance
from src.utils.web3converter import Web3Converter
from src.web3py.extensions.lido_validators import LidoValidator
Expand All @@ -20,17 +21,16 @@


class MidtermSlashingPenalty:

@staticmethod
def is_high_midterm_slashing_penalty(
blockstamp: ReferenceBlockStamp,
consensus_version: int,
cl_spec: BeaconSpecResponse,
is_electra_activated: Callable[[EpochNumber], bool],
web3_converter: Web3Converter,
all_validators: list[Validator],
lido_validators: list[LidoValidator],
current_report_cl_rebase: Gwei,
last_report_ref_slot: SlotNumber
last_report_ref_slot: SlotNumber,
) -> bool:
"""
Check if there is a high midterm slashing penalty in the future frames.
Expand Down Expand Up @@ -66,8 +66,14 @@ def is_high_midterm_slashing_penalty(
blockstamp.ref_epoch, all_slashed_validators, total_balance, future_frames_lido_validators
)
else:
frames_lido_midterm_penalties = MidtermSlashingPenalty.get_future_midterm_penalty_sum_in_frames_post_electra(
blockstamp.ref_epoch, cl_spec, all_slashed_validators, total_balance, future_frames_lido_validators,
frames_lido_midterm_penalties = (
MidtermSlashingPenalty.get_future_midterm_penalty_sum_in_frames_post_electra(
blockstamp.ref_epoch,
is_electra_activated,
all_slashed_validators,
total_balance,
future_frames_lido_validators,
)
)
max_lido_midterm_penalty = max(frames_lido_midterm_penalties.values())
logger.info({"msg": f"Max lido midterm penalty: {max_lido_midterm_penalty}"})
Expand All @@ -84,8 +90,7 @@ def is_high_midterm_slashing_penalty(

@staticmethod
def get_slashed_validators_with_impact_on_midterm_penalties(
validators: list[Validator],
ref_epoch: EpochNumber
validators: list[Validator], ref_epoch: EpochNumber
) -> list[Validator]:
"""
Get slashed validators which have impact on midterm penalties
Expand All @@ -104,6 +109,7 @@ def get_slashed_validators_with_impact_on_midterm_penalties(
https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#slash_validator
"""

def is_have_impact(v: Validator) -> bool:
return v.validator.slashed and int(v.validator.withdrawable_epoch) > ref_epoch

Expand Down Expand Up @@ -169,11 +175,10 @@ def get_future_midterm_penalty_sum_in_frames_pre_electra(
"""Calculate sum of midterm penalties in each frame"""
per_frame_midterm_penalty_sum: dict[FrameNumber, Gwei] = {}
for (frame_number, _), validators_in_future_frame in per_frame_validators.items():
per_frame_midterm_penalty_sum[frame_number] = MidtermSlashingPenalty.predict_midterm_penalty_in_frame_pre_electra(
ref_epoch,
all_slashed_validators,
total_balance,
validators_in_future_frame
per_frame_midterm_penalty_sum[frame_number] = (
MidtermSlashingPenalty.predict_midterm_penalty_in_frame_pre_electra(
ref_epoch, all_slashed_validators, total_balance, validators_in_future_frame
)
)

return per_frame_midterm_penalty_sum
Expand All @@ -183,7 +188,7 @@ def predict_midterm_penalty_in_frame_pre_electra(
ref_epoch: EpochNumber,
all_slashed_validators: list[Validator],
total_balance: Gwei,
midterm_penalized_validators_in_frame: list[LidoValidator]
midterm_penalized_validators_in_frame: list[LidoValidator],
) -> Gwei:
"""Predict penalty in frame"""
penalty_in_frame = 0
Expand All @@ -200,21 +205,23 @@ def predict_midterm_penalty_in_frame_pre_electra(
@staticmethod
def get_future_midterm_penalty_sum_in_frames_post_electra(
ref_epoch: EpochNumber,
cl_spec: BeaconSpecResponse,
is_electra_activated: Callable[[EpochNumber], bool],
all_slashed_validators: list[Validator],
total_balance: Gwei,
per_frame_validators: SlashedValidatorsFrameBuckets,
) -> dict[FrameNumber, Gwei]:
"""Calculate sum of midterm penalties in each frame"""
per_frame_midterm_penalty_sum: dict[FrameNumber, Gwei] = {}
for (frame_number, frame_ref_epoch), validators_in_future_frame in per_frame_validators.items():
per_frame_midterm_penalty_sum[frame_number] = MidtermSlashingPenalty.predict_midterm_penalty_in_frame_post_electra(
ref_epoch,
frame_ref_epoch,
cl_spec,
all_slashed_validators,
total_balance,
validators_in_future_frame
per_frame_midterm_penalty_sum[frame_number] = (
MidtermSlashingPenalty.predict_midterm_penalty_in_frame_post_electra(
ref_epoch,
frame_ref_epoch,
is_electra_activated,
all_slashed_validators,
total_balance,
validators_in_future_frame,
)
)

return per_frame_midterm_penalty_sum
Expand All @@ -223,10 +230,10 @@ def get_future_midterm_penalty_sum_in_frames_post_electra(
def predict_midterm_penalty_in_frame_post_electra(
report_ref_epoch: EpochNumber,
frame_ref_epoch: EpochNumber,
cl_spec: BeaconSpecResponse,
is_electra_activated: Callable[[EpochNumber], bool],
all_slashed_validators: list[Validator],
total_balance: Gwei,
midterm_penalized_validators_in_frame: list[LidoValidator]
midterm_penalized_validators_in_frame: list[LidoValidator],
) -> Gwei:
"""Predict penalty in frame"""
penalty_in_frame = 0
Expand All @@ -236,7 +243,7 @@ def predict_midterm_penalty_in_frame_post_electra(
report_ref_epoch, all_slashed_validators, EpochNumber(midterm_penalty_epoch)
)

if frame_ref_epoch < int(cl_spec.ELECTRA_FORK_EPOCH):
if not is_electra_activated(frame_ref_epoch):
penalty_in_frame += MidtermSlashingPenalty.get_validator_midterm_penalty(
validator, len(bound_slashed_validators), total_balance
)
Expand All @@ -250,7 +257,7 @@ def predict_midterm_penalty_in_frame_post_electra(
def get_validator_midterm_penalty(
validator: LidoValidator,
bound_slashed_validators_count: int,
total_balance: Gwei
total_balance: Gwei,
) -> Gwei:
"""
Calculate midterm penalty for particular validator
Expand Down Expand Up @@ -312,7 +319,7 @@ def get_frame_cl_rebase_from_report_cl_rebase(
web3_converter: Web3Converter,
report_cl_rebase: Gwei,
curr_report_blockstamp: ReferenceBlockStamp,
last_report_ref_slot: SlotNumber
last_report_ref_slot: SlotNumber,
) -> Gwei:
"""Get frame rebase from report rebase"""
last_report_ref_epoch = web3_converter.get_epoch_by_slot(last_report_ref_slot)
Expand Down
Loading

0 comments on commit 6587905

Please sign in to comment.