Skip to content

Commit

Permalink
fix: gwei to wei lost conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
madlabman committed Jan 23, 2025
1 parent 7f5dea6 commit ad6d516
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 27 deletions.
3 changes: 2 additions & 1 deletion src/modules/accounting/accounting.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from src.services.bunker import BunkerService
from src.types import BlockStamp, Gwei, ReferenceBlockStamp, StakingModuleId, NodeOperatorGlobalIndex, FinalizationBatches
from src.utils.cache import global_lru_cache as lru_cache
from src.utils.units import gwei_to_wei
from src.variables import ALLOW_REPORTING_IN_BUNKER_MODE
from src.web3py.types import Web3
from src.web3py.extensions.lido_validators import StakingModule
Expand Down Expand Up @@ -289,7 +290,7 @@ def simulate_rebase_after_report(
self._get_slots_elapsed_from_last_report(blockstamp) * chain_conf.seconds_per_slot, # _timeElapsed
# CL values
validators_count, # _clValidators
Web3.to_wei(cl_balance, 'gwei'), # _clBalance
gwei_to_wei(cl_balance), # _clBalance
# EL values
self.w3.lido_contracts.get_withdrawal_balance(blockstamp), # _withdrawalVaultBalance
el_rewards, # _elRewardsVaultBalance
Expand Down
28 changes: 16 additions & 12 deletions src/modules/ejector/ejector.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from src.services.validator_state import LidoValidatorStateService
from src.types import BlockStamp, EpochNumber, Gwei, NodeOperatorGlobalIndex, ReferenceBlockStamp
from src.utils.cache import global_lru_cache as lru_cache
from src.utils.units import gwei_to_wei, wei_to_gwei
from src.utils.validator_state import (
compute_activation_exit_epoch,
get_activation_exit_churn_limit,
Expand Down Expand Up @@ -126,16 +127,16 @@ def get_validators_to_eject(self, blockstamp: ReferenceBlockStamp) -> list[tuple
validators_iterator = iter(self.get_validators_iterator(consensus_version, blockstamp))

validators_to_eject: list[tuple[NodeOperatorGlobalIndex, LidoValidator]] = []
validator_to_eject_balance_sum = 0
total_balance_to_eject_wei = 0

try:
while expected_balance < to_withdraw_amount:
gid, next_validator = next(validators_iterator)
validators_to_eject.append((gid, next_validator))
validator_to_eject_balance_sum += self.w3.to_wei(self._get_predicted_withdrawable_balance(next_validator), "gwei")
expected_balance = (
total_balance_to_eject_wei += self._get_predicted_withdrawable_balance(next_validator)
expected_balance = Wei(
self._get_total_expected_balance([v for (_, v) in validators_to_eject], blockstamp)
+ validator_to_eject_balance_sum
+ total_balance_to_eject_wei
)
except StopIteration:
pass
Expand All @@ -155,7 +156,7 @@ def get_validators_to_eject(self, blockstamp: ReferenceBlockStamp) -> list[tuple

return validators_to_eject

def _get_total_expected_balance(self, vals_to_exit: list[Validator], blockstamp: ReferenceBlockStamp):
def _get_total_expected_balance(self, vals_to_exit: list[Validator], blockstamp: ReferenceBlockStamp) -> Wei:
chain_config = self.get_chain_config(blockstamp)

validators_going_to_exit = self.validators_state_service.get_recently_requested_but_not_exited_validators(blockstamp, chain_config)
Expand All @@ -182,7 +183,7 @@ def _get_total_expected_balance(self, vals_to_exit: list[Validator], blockstamp:
total_available_balance = self._get_total_el_balance(blockstamp)
logger.info({'msg': 'Calculate el balance.', 'value': total_available_balance})

return future_rewards + future_withdrawals + total_available_balance + going_to_withdraw_balance
return Wei(future_rewards + future_withdrawals + total_available_balance + going_to_withdraw_balance)

def get_validators_iterator(self, consensus_version: int, blockstamp: ReferenceBlockStamp):
chain_config = self.get_chain_config(blockstamp)
Expand All @@ -209,16 +210,17 @@ def is_reporting_allowed(self, blockstamp: ReferenceBlockStamp) -> bool:
@lru_cache(maxsize=1)
def _get_withdrawable_lido_validators_balance(self, on_epoch: EpochNumber, blockstamp: BlockStamp) -> Wei:
lido_validators = self.w3.lido_validators.get_lido_validators(blockstamp=blockstamp)
return Wei(
sum(
return sum(
(
self._get_predicted_withdrawable_balance(v)
for v in lido_validators
if is_fully_withdrawable_validator(v.validator, Gwei(int(v.balance)), on_epoch)
)
),
Wei(0),
)

def _get_predicted_withdrawable_balance(self, validator: Validator) -> Gwei:
return Gwei(min(int(validator.balance), get_max_effective_balance(validator.validator)))
def _get_predicted_withdrawable_balance(self, validator: Validator) -> Wei:
return gwei_to_wei(min(Gwei(int(validator.balance)), get_max_effective_balance(validator.validator)))

@lru_cache(maxsize=1)
def _get_total_el_balance(self, blockstamp: BlockStamp) -> Wei:
Expand Down Expand Up @@ -278,7 +280,9 @@ def _get_predicted_withdrawable_epoch_post_electra(
earliest_exit_epoch = state_view.earliest_exit_epoch
exit_balance_to_consume = state_view.exit_balance_to_consume

exit_balance = sum(self._get_predicted_withdrawable_balance(v) for v in validators_to_eject)
exit_balance = wei_to_gwei(
sum((self._get_predicted_withdrawable_balance(v) for v in validators_to_eject), Wei(0))
)
balance_to_process = max(0, exit_balance - exit_balance_to_consume)
additional_epochs = math.ceil(balance_to_process / per_epoch_churn)

Expand Down
11 changes: 7 additions & 4 deletions src/services/bunker.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import logging

from src.constants import TOTAL_BASIS_POINTS, GWEI_TO_WEI
from web3.types import Wei

from src.constants import TOTAL_BASIS_POINTS
from src.metrics.prometheus.validators import (
ALL_VALIDATORS,
LIDO_VALIDATORS,
Expand All @@ -16,6 +18,7 @@
from src.services.bunker_cases.types import BunkerConfig
from src.services.safe_border import filter_slashed_validators
from src.types import BlockStamp, ReferenceBlockStamp, Gwei
from src.utils.units import wei_to_gwei
from src.utils.web3converter import Web3Converter
from src.web3py.types import Web3

Expand Down Expand Up @@ -96,11 +99,11 @@ def get_cl_rebase_for_current_report(self, blockstamp: BlockStamp, simulated_cl_
"""
logger.info({"msg": "Getting CL rebase for frame"})
before_report_total_pooled_ether = self.w3.lido_contracts.lido.total_supply(blockstamp.block_hash)
rebase_diff = Wei(simulated_cl_rebase.post_total_pooled_ether - before_report_total_pooled_ether)

# Can't use from_wei - because rebase can be negative
frame_cl_rebase = (simulated_cl_rebase.post_total_pooled_ether - before_report_total_pooled_ether) // GWEI_TO_WEI
frame_cl_rebase = wei_to_gwei(rebase_diff)
logger.info({"msg": f"Simulated CL rebase for frame: {frame_cl_rebase} Gwei"})
return Gwei(frame_cl_rebase)
return frame_cl_rebase

def _get_config(self, blockstamp: BlockStamp) -> BunkerConfig:
"""Get config values from OracleDaemonConfig contract"""
Expand Down
9 changes: 4 additions & 5 deletions src/services/bunker_cases/abnormal_cl_rebase.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from src.types import ReferenceBlockStamp, Gwei, BlockNumber, SlotNumber, BlockStamp, EpochNumber
from src.utils.events import get_events_in_range
from src.utils.slot import get_blockstamp, get_reference_blockstamp
from src.utils.units import wei_to_gwei
from src.utils.validator_state import calculate_active_effective_balance_sum
from src.web3py.extensions.lido_validators import LidoValidator, LidoValidatorsProvider
from src.web3py.types import Web3
Expand Down Expand Up @@ -219,9 +220,7 @@ def _get_lido_validators_balance_with_vault(
Get Lido validator balance with withdrawals vault balance
"""
real_cl_balance = AbnormalClRebase.calculate_validators_balance_sum(lido_validators)
withdrawals_vault_balance = int(
self.w3.from_wei(self.w3.lido_contracts.get_withdrawal_balance_no_cache(blockstamp), "gwei")
)
withdrawals_vault_balance = wei_to_gwei(self.w3.lido_contracts.get_withdrawal_balance_no_cache(blockstamp))
total_balance = real_cl_balance + withdrawals_vault_balance

consensus_version = self.w3.lido_contracts.accounting_oracle.get_consensus_version(blockstamp.block_hash)
Expand Down Expand Up @@ -265,10 +264,10 @@ def _get_withdrawn_from_vault_between_blocks(
logger.info({"msg": "No ETHDistributed event found. Vault withdrawals: 0 Gwei."})
return Gwei(0)

vault_withdrawals = int(self.w3.from_wei(events[0]['args']['withdrawalsWithdrawn'], 'gwei'))
vault_withdrawals = wei_to_gwei(events[0]['args']['withdrawalsWithdrawn'])
logger.info({"msg": f"Vault withdrawals: {vault_withdrawals} Gwei"})

return Gwei(vault_withdrawals)
return vault_withdrawals

def _get_eth_distributed_events(self, from_block: BlockNumber, to_block: BlockNumber) -> list[EventData]:
"""Get ETHDistributed events between blocks"""
Expand Down
16 changes: 16 additions & 0 deletions src/utils/units.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""A set of utils to convert ether units"""

from web3.types import Wei

from src.constants import GWEI_TO_WEI
from src.types import Gwei


def wei_to_gwei(amount: Wei) -> Gwei:
"""Converts Wei to Gwei rounding down"""
return Gwei(amount // GWEI_TO_WEI)


def gwei_to_wei(amount: Gwei) -> Wei:
"""Converts Gwei to Wei"""
return Wei(amount * GWEI_TO_WEI)
2 changes: 1 addition & 1 deletion src/web3py/extensions/lido_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def merge_validators_with_keys(keys: list[LidoKey], validators: list[Validator])
return lido_validators

@staticmethod
def calculate_total_eth1_bridge_deposits_amount(lido_validators: list[LidoValidator], pending_deposits: list[PendingDeposit]) -> int:
def calculate_total_eth1_bridge_deposits_amount(lido_validators: list[LidoValidator], pending_deposits: list[PendingDeposit]) -> Gwei:
total_eth1_bridge_deposits_amount = 0
for v in lido_validators:
if (
Expand Down
9 changes: 5 additions & 4 deletions tests/modules/ejector/test_ejector.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from src import constants
from src.constants import (
EFFECTIVE_BALANCE_INCREMENT,
GWEI_TO_WEI,
MAX_EFFECTIVE_BALANCE,
MAX_EFFECTIVE_BALANCE_ELECTRA,
MAX_SEED_LOOKAHEAD,
Expand Down Expand Up @@ -402,7 +403,7 @@ def test_get_withdrawable_lido_validators_balance(
)

result = ejector._get_withdrawable_lido_validators_balance(42, ref_blockstamp)
assert result == 42, "Unexpected withdrawable amount"
assert result == 42 * GWEI_TO_WEI, "Unexpected withdrawable amount"

ejector._get_withdrawable_lido_validators_balance(42, ref_blockstamp)
ejector.w3.lido_validators.get_lido_validators.assert_called_once()
Expand All @@ -416,18 +417,18 @@ def test_get_predicted_withdrawable_balance(ejector: Ejector) -> None:

validator = LidoValidatorFactory.build_with_balance(Gwei(42))
result = ejector._get_predicted_withdrawable_balance(validator)
assert result == 42, "Expected validator's balance in gwei"
assert result == 42 * GWEI_TO_WEI, "Expected validator's balance in gwei"

validator = LidoValidatorFactory.build_with_balance(Gwei(MAX_EFFECTIVE_BALANCE + 1))
result = ejector._get_predicted_withdrawable_balance(validator)
assert result == MAX_EFFECTIVE_BALANCE, "Expect MAX_EFFECTIVE_BALANCE"
assert result == MAX_EFFECTIVE_BALANCE * GWEI_TO_WEI, "Expect MAX_EFFECTIVE_BALANCE"

validator = LidoValidatorFactory.build_with_balance(
Gwei(MAX_EFFECTIVE_BALANCE + 1),
meb=MAX_EFFECTIVE_BALANCE_ELECTRA,
)
result = ejector._get_predicted_withdrawable_balance(validator)
assert result == MAX_EFFECTIVE_BALANCE + 1, "Expect MAX_EFFECTIVE_BALANCE + 1"
assert result == (MAX_EFFECTIVE_BALANCE + 1) * GWEI_TO_WEI, "Expect MAX_EFFECTIVE_BALANCE + 1"


@pytest.mark.unit
Expand Down

0 comments on commit ad6d516

Please sign in to comment.