From 4b16e60517a1f0381b52ae1b8015e394ec59cf12 Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Wed, 4 Dec 2024 14:51:54 +0100 Subject: [PATCH 1/9] feat: account pending deposits for AO state report --- src/constants.py | 1 + src/modules/accounting/accounting.py | 3 ++- src/web3py/extensions/lido_validators.py | 12 +++++++++ tests/factory/no_registry.py | 26 +++++++++++++++++++ .../accounting/test_accounting_module.py | 11 +++++--- tests/web3_extentions/test_lido_validators.py | 18 +++++++++++++ 6 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/constants.py b/src/constants.py index f4baf41d3..222b47e6b 100644 --- a/src/constants.py +++ b/src/constants.py @@ -13,6 +13,7 @@ # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#gwei-values EFFECTIVE_BALANCE_INCREMENT = 2 ** 0 * 10 ** 9 MAX_EFFECTIVE_BALANCE = 32 * 10 ** 9 +MIN_ACTIVATION_BALANCE = 32 * 10 ** 9 # https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#execution MAX_WITHDRAWALS_PER_PAYLOAD = 2 ** 4 # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#withdrawal-prefixes diff --git a/src/modules/accounting/accounting.py b/src/modules/accounting/accounting.py index 030f7e0ba..5d7325d93 100644 --- a/src/modules/accounting/accounting.py +++ b/src/modules/accounting/accounting.py @@ -217,7 +217,8 @@ def _get_consensus_lido_state(self, blockstamp: ReferenceBlockStamp) -> tuple[Va lido_validators = self.w3.lido_validators.get_lido_validators(blockstamp) count = len(lido_validators) - total_balance = Gwei(sum(int(validator.balance) for validator in lido_validators)) + pending_deposits_sum = self.w3.lido_validators.get_lido_validators_pending_deposits_sum(blockstamp) + total_balance = Gwei(sum(int(validator.balance) for validator in lido_validators) + pending_deposits_sum) logger.info({'msg': 'Calculate lido state on CL. (Validators count, Total balance in gwei)', 'value': (count, total_balance)}) return ValidatorsCount(count), ValidatorsBalance(total_balance) diff --git a/src/web3py/extensions/lido_validators.py b/src/web3py/extensions/lido_validators.py index 6e813e20b..c2c4c062d 100644 --- a/src/web3py/extensions/lido_validators.py +++ b/src/web3py/extensions/lido_validators.py @@ -6,6 +6,7 @@ from eth_typing import ChecksumAddress from web3.module import Module +from src.constants import FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE from src.providers.consensus.types import Validator from src.providers.keys.types import LidoKey from src.types import BlockStamp, StakingModuleId, NodeOperatorId, NodeOperatorGlobalIndex, StakingModuleAddress @@ -148,6 +149,17 @@ def get_lido_validators(self, blockstamp: BlockStamp) -> list[LidoValidator]: return self.merge_validators_with_keys(lido_keys, validators) + @lru_cache(maxsize=1) + def get_lido_validators_pending_deposits_sum(self, blockstamp: BlockStamp) -> int: + lido_validators = self.get_lido_validators(blockstamp) + + pending_deposits_sum = 0 + for validator in lido_validators: + if int(validator.balance) == 0 and int(validator.validator.activation_epoch) == FAR_FUTURE_EPOCH: + pending_deposits_sum += MIN_ACTIVATION_BALANCE + + return pending_deposits_sum + def _kapi_sanity_check(self, keys_count_received: int, blockstamp: BlockStamp): stats = self.w3.lido_contracts.lido.get_beacon_stat(blockstamp.block_hash) diff --git a/tests/factory/no_registry.py b/tests/factory/no_registry.py index eee95c6c5..1d2dd3f84 100644 --- a/tests/factory/no_registry.py +++ b/tests/factory/no_registry.py @@ -23,6 +23,19 @@ class ValidatorStateFactory(Web3Factory): class ValidatorFactory(Web3Factory): __model__ = Validator + @classmethod + def build_pending_deposit_vals(cls, **kwargs: Any): + return cls.build( + balance=str(0), + validator=ValidatorStateFactory.build( + activation_eligibility_epoch=str(FAR_FUTURE_EPOCH), + activation_epoch=str(FAR_FUTURE_EPOCH), + exit_epoch=str(FAR_FUTURE_EPOCH), + effective_balance=str(0), + ), + **kwargs + ) + class LidoKeyFactory(Web3Factory): __model__ = LidoKey @@ -53,6 +66,19 @@ def build_with_activation_epoch_bound(cls, max_value: int, **kwargs: Any): validator=ValidatorStateFactory.build(activation_epoch=str(faker.pyint(max_value=max_value - 1))), **kwargs ) + @classmethod + def build_pending_deposit_vals(cls, **kwargs: Any): + return cls.build( + balance=str(0), + validator=ValidatorStateFactory.build( + activation_eligibility_epoch=str(FAR_FUTURE_EPOCH), + activation_epoch=str(FAR_FUTURE_EPOCH), + exit_epoch=str(FAR_FUTURE_EPOCH), + effective_balance=str(0), + ), + **kwargs + ) + @classmethod def build_not_active_vals(cls, epoch, **kwargs: Any): return cls.build( diff --git a/tests/modules/accounting/test_accounting_module.py b/tests/modules/accounting/test_accounting_module.py index c0124b555..cf357bb25 100644 --- a/tests/modules/accounting/test_accounting_module.py +++ b/tests/modules/accounting/test_accounting_module.py @@ -6,6 +6,7 @@ from web3.types import Wei from src import variables +from src.constants import MIN_ACTIVATION_BALANCE from src.modules.accounting import accounting as accounting_module from src.modules.accounting.accounting import Accounting from src.modules.accounting.accounting import logger as accounting_logger @@ -21,7 +22,6 @@ from tests.factory.configs import ChainConfigFactory, FrameConfigFactory from tests.factory.contract_responses import LidoReportRebaseFactory from tests.factory.no_registry import LidoValidatorFactory, StakingModuleFactory -from tests.web3_extentions.test_lido_validators import blockstamp @pytest.fixture(autouse=True) @@ -101,13 +101,18 @@ def test_get_updated_modules_stats(accounting: Accounting): @pytest.mark.usefixtures("lido_validators") def test_get_consensus_lido_state(accounting: Accounting): bs = ReferenceBlockStampFactory.build() - validators = LidoValidatorFactory.batch(10) + validators = [ + *[LidoValidatorFactory.build_pending_deposit_vals() for _ in range(3)], + *[LidoValidatorFactory.build_not_active_vals(bs.ref_epoch) for _ in range(3)], + *[LidoValidatorFactory.build_active_vals(bs.ref_epoch) for _ in range(2)], + *[LidoValidatorFactory.build_exit_vals(bs.ref_epoch) for _ in range(2)], + ] accounting.w3.lido_validators.get_lido_validators = Mock(return_value=validators) count, balance = accounting._get_consensus_lido_state(bs) assert count == 10 - assert balance == sum((int(val.balance) for val in validators)) + assert balance == sum((int(val.balance) for val in validators)) + 3 * MIN_ACTIVATION_BALANCE @pytest.mark.unit diff --git a/tests/web3_extentions/test_lido_validators.py b/tests/web3_extentions/test_lido_validators.py index 2a28b37ab..75dc9a979 100644 --- a/tests/web3_extentions/test_lido_validators.py +++ b/tests/web3_extentions/test_lido_validators.py @@ -2,6 +2,7 @@ import pytest +from src.constants import MIN_ACTIVATION_BALANCE from src.modules.accounting.types import BeaconStat from src.web3py.extensions.lido_validators import CountOfKeysDiffersException from tests.factory.blockstamp import ReferenceBlockStampFactory @@ -38,6 +39,23 @@ def test_get_lido_validators(web3, lido_validators, contracts): assert v.lido_id.key == v.validator.pubkey +@pytest.mark.unit +def test_get_lido_validators_pending_deposits_sum(web3, lido_validators, contracts): + validators = [ValidatorFactory.build_pending_deposit_vals() for _ in range(5)] + validators.extend(ValidatorFactory.batch(30)) + lido_keys = LidoKeyFactory.generate_for_validators(validators[:15]) + lido_keys.extend(LidoKeyFactory.batch(10)) + + web3.lido_validators._kapi_sanity_check = Mock() + + web3.cc.get_validators = Mock(return_value=validators) + web3.kac.get_used_lido_keys = Mock(return_value=lido_keys) + + pending_deposits_sum = web3.lido_validators.get_lido_validators_pending_deposits_sum(blockstamp) + + assert pending_deposits_sum == 5 * MIN_ACTIVATION_BALANCE + + @pytest.mark.unit def test_kapi_has_lesser_keys_than_deposited_validators_count(web3, lido_validators, contracts): validators = ValidatorFactory.batch(10) From 18fc7e8e3f34c4241742ad7bd1c613b6f595a094 Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Thu, 5 Dec 2024 13:39:20 +0100 Subject: [PATCH 2/9] feat: account pending deposits for abnormal rebase calc --- src/modules/accounting/accounting.py | 2 +- .../bunker_cases/abnormal_cl_rebase.py | 3 ++- src/web3py/extensions/lido_validators.py | 19 ++++++++----------- tests/modules/accounting/bunker/conftest.py | 16 ++++++++++++++-- .../bunker/test_bunker_abnormal_cl_rebase.py | 2 ++ tests/web3_extentions/test_lido_validators.py | 5 +++-- 6 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/modules/accounting/accounting.py b/src/modules/accounting/accounting.py index 5d7325d93..e64f7ee09 100644 --- a/src/modules/accounting/accounting.py +++ b/src/modules/accounting/accounting.py @@ -217,7 +217,7 @@ def _get_consensus_lido_state(self, blockstamp: ReferenceBlockStamp) -> tuple[Va lido_validators = self.w3.lido_validators.get_lido_validators(blockstamp) count = len(lido_validators) - pending_deposits_sum = self.w3.lido_validators.get_lido_validators_pending_deposits_sum(blockstamp) + pending_deposits_sum = self.w3.lido_validators.calculate_pending_deposits_sum(lido_validators) total_balance = Gwei(sum(int(validator.balance) for validator in lido_validators) + pending_deposits_sum) logger.info({'msg': 'Calculate lido state on CL. (Validators count, Total balance in gwei)', 'value': (count, total_balance)}) diff --git a/src/services/bunker_cases/abnormal_cl_rebase.py b/src/services/bunker_cases/abnormal_cl_rebase.py index ef74a7fca..2e663fcb1 100644 --- a/src/services/bunker_cases/abnormal_cl_rebase.py +++ b/src/services/bunker_cases/abnormal_cl_rebase.py @@ -216,10 +216,11 @@ 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) + pending_deposits_sum = LidoValidatorsProvider.calculate_pending_deposits_sum(lido_validators) withdrawals_vault_balance = int( self.w3.from_wei(self.w3.lido_contracts.get_withdrawal_balance_no_cache(blockstamp), "gwei") ) - return Gwei(real_cl_balance + withdrawals_vault_balance) + return Gwei(real_cl_balance + pending_deposits_sum + withdrawals_vault_balance) def _get_withdrawn_from_vault_between_blocks( self, prev_blockstamp: BlockStamp, ref_blockstamp: ReferenceBlockStamp diff --git a/src/web3py/extensions/lido_validators.py b/src/web3py/extensions/lido_validators.py index c2c4c062d..525ebf977 100644 --- a/src/web3py/extensions/lido_validators.py +++ b/src/web3py/extensions/lido_validators.py @@ -149,17 +149,6 @@ def get_lido_validators(self, blockstamp: BlockStamp) -> list[LidoValidator]: return self.merge_validators_with_keys(lido_keys, validators) - @lru_cache(maxsize=1) - def get_lido_validators_pending_deposits_sum(self, blockstamp: BlockStamp) -> int: - lido_validators = self.get_lido_validators(blockstamp) - - pending_deposits_sum = 0 - for validator in lido_validators: - if int(validator.balance) == 0 and int(validator.validator.activation_epoch) == FAR_FUTURE_EPOCH: - pending_deposits_sum += MIN_ACTIVATION_BALANCE - - return pending_deposits_sum - def _kapi_sanity_check(self, keys_count_received: int, blockstamp: BlockStamp): stats = self.w3.lido_contracts.lido.get_beacon_stat(blockstamp.block_hash) @@ -184,6 +173,14 @@ def merge_validators_with_keys(keys: list[LidoKey], validators: list[Validator]) return lido_validators + @staticmethod + def calculate_pending_deposits_sum(lido_validators: list[LidoValidator]) -> int: + return sum( + MIN_ACTIVATION_BALANCE + for validator in lido_validators + if int(validator.balance) == 0 and int(validator.validator.activation_epoch) == FAR_FUTURE_EPOCH + ) + @lru_cache(maxsize=1) def get_lido_validators_by_node_operators(self, blockstamp: BlockStamp) -> ValidatorsByNodeOperator: merged_validators = self.get_lido_validators(blockstamp) diff --git a/tests/modules/accounting/bunker/conftest.py b/tests/modules/accounting/bunker/conftest.py index 68b01e80e..c6df7477a 100644 --- a/tests/modules/accounting/bunker/conftest.py +++ b/tests/modules/accounting/bunker/conftest.py @@ -9,6 +9,7 @@ from src.services.bunker_cases.abnormal_cl_rebase import AbnormalClRebase from src.services.bunker_cases.types import BunkerConfig from src.types import BlockNumber, BlockStamp, ReferenceBlockStamp +from tests.modules.ejector.test_exit_order_state_service import FAR_FUTURE_EPOCH def simple_ref_blockstamp(block_number: int) -> ReferenceBlockStamp: @@ -25,7 +26,9 @@ def simple_key(pubkey: str) -> LidoKey: return key -def simple_validator(index, pubkey, balance, slashed=False, withdrawable_epoch='', exit_epoch='100500') -> Validator: +def simple_validator( + index, pubkey, balance, slashed=False, withdrawable_epoch='', exit_epoch='100500', activation_epoch="0" +) -> Validator: return Validator( index=str(index), balance=str(balance), @@ -36,7 +39,7 @@ def simple_validator(index, pubkey, balance, slashed=False, withdrawable_epoch=' effective_balance=str(32 * 10**9), slashed=slashed, activation_eligibility_epoch='', - activation_epoch='0', + activation_epoch=activation_epoch, exit_epoch=exit_epoch, withdrawable_epoch=withdrawable_epoch, ), @@ -134,6 +137,7 @@ def _get_withdrawal_vault_balance(blockstamp: BlockStamp): 31: 2 * 10**18, 33: 2 * 10**18, 40: 2 * 10**18, + 50: 2 * 10**18, } return balance[blockstamp.block_number] @@ -199,6 +203,14 @@ def _get_validators(state: ReferenceBlockStamp, _=None): simple_validator(4, '0x04', 32 * 10**9), simple_validator(5, '0x05', (32 * 10**9) + 824112), ], + 50: [ + simple_validator(4, '0x00', balance=0, activation_epoch=FAR_FUTURE_EPOCH), + simple_validator(1, '0x01', 32 * 10**9), + simple_validator(2, '0x02', 32 * 10**9), + simple_validator(3, '0x03', (32 * 10**9) + 333333), + simple_validator(4, '0x04', balance=0, activation_epoch=FAR_FUTURE_EPOCH), + simple_validator(5, '0x05', (32 * 10**9) + 824112), + ], 1000: [ simple_validator(0, '0x00', 32 * 10**9), simple_validator(1, '0x01', 32 * 10**9), diff --git a/tests/modules/accounting/bunker/test_bunker_abnormal_cl_rebase.py b/tests/modules/accounting/bunker/test_bunker_abnormal_cl_rebase.py index a85c46288..a004d6847 100644 --- a/tests/modules/accounting/bunker/test_bunker_abnormal_cl_rebase.py +++ b/tests/modules/accounting/bunker/test_bunker_abnormal_cl_rebase.py @@ -90,6 +90,7 @@ def test_is_abnormal_cl_rebase( @pytest.mark.parametrize( ("blockstamp", "expected_rebase"), [ + (simple_ref_blockstamp(50), 512000000), (simple_ref_blockstamp(40), 420650924), (simple_ref_blockstamp(20), 140216974), (simple_ref_blockstamp(123), 1120376622), @@ -234,6 +235,7 @@ def test_calculate_cl_rebase_between_blocks( @pytest.mark.parametrize( ("blockstamp", "expected_result"), [ + (simple_ref_blockstamp(50), 98001157445), (simple_ref_blockstamp(40), 98001157445), (simple_ref_blockstamp(20), 77999899300), ], diff --git a/tests/web3_extentions/test_lido_validators.py b/tests/web3_extentions/test_lido_validators.py index 75dc9a979..bd26579b1 100644 --- a/tests/web3_extentions/test_lido_validators.py +++ b/tests/web3_extentions/test_lido_validators.py @@ -40,7 +40,7 @@ def test_get_lido_validators(web3, lido_validators, contracts): @pytest.mark.unit -def test_get_lido_validators_pending_deposits_sum(web3, lido_validators, contracts): +def test_calc_pending_deposits_sum(web3, lido_validators, contracts): validators = [ValidatorFactory.build_pending_deposit_vals() for _ in range(5)] validators.extend(ValidatorFactory.batch(30)) lido_keys = LidoKeyFactory.generate_for_validators(validators[:15]) @@ -51,7 +51,8 @@ def test_get_lido_validators_pending_deposits_sum(web3, lido_validators, contrac web3.cc.get_validators = Mock(return_value=validators) web3.kac.get_used_lido_keys = Mock(return_value=lido_keys) - pending_deposits_sum = web3.lido_validators.get_lido_validators_pending_deposits_sum(blockstamp) + lido_validators = web3.lido_validators.get_lido_validators(blockstamp) + pending_deposits_sum = web3.lido_validators.calculate_pending_deposits_sum(lido_validators) assert pending_deposits_sum == 5 * MIN_ACTIVATION_BALANCE From 6a97881fe0397c3c41925224c3249b17a0346219 Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Fri, 20 Dec 2024 13:09:54 +0100 Subject: [PATCH 3/9] fix: type for constants --- src/constants.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/constants.py b/src/constants.py index 222b47e6b..52ff3b612 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,3 +1,5 @@ +from src.types import Gwei + # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#misc from src.types import Gwei @@ -12,8 +14,8 @@ PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX = 3 # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#gwei-values EFFECTIVE_BALANCE_INCREMENT = 2 ** 0 * 10 ** 9 -MAX_EFFECTIVE_BALANCE = 32 * 10 ** 9 -MIN_ACTIVATION_BALANCE = 32 * 10 ** 9 +MAX_EFFECTIVE_BALANCE = Gwei(32 * 10 ** 9) +MIN_ACTIVATION_BALANCE = Gwei(32 * 10 ** 9) # https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#execution MAX_WITHDRAWALS_PER_PAYLOAD = 2 ** 4 # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#withdrawal-prefixes From 175e800c86c7a9b1eb1f86a5eb3586e356ad44bf Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Fri, 20 Dec 2024 13:10:10 +0100 Subject: [PATCH 4/9] fix: note for `calculate_pending_deposits_sum` --- src/web3py/extensions/lido_validators.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/web3py/extensions/lido_validators.py b/src/web3py/extensions/lido_validators.py index 525ebf977..90758e1ef 100644 --- a/src/web3py/extensions/lido_validators.py +++ b/src/web3py/extensions/lido_validators.py @@ -175,6 +175,8 @@ def merge_validators_with_keys(keys: list[LidoKey], validators: list[Validator]) @staticmethod def calculate_pending_deposits_sum(lido_validators: list[LidoValidator]) -> int: + # NOTE: Using 32 ETH as a default validator pending balance is OK for the current protocol implementation. + # It must be changed in case of validators consolidation feature implementation. return sum( MIN_ACTIVATION_BALANCE for validator in lido_validators From d5656a4c5de81b4599b82c10e4d8183f4cd23bda Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Fri, 20 Dec 2024 16:51:40 +0100 Subject: [PATCH 5/9] fix: weak pubkey random in generated object for tests --- tests/factory/no_registry.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/factory/no_registry.py b/tests/factory/no_registry.py index 1d2dd3f84..9b2264314 100644 --- a/tests/factory/no_registry.py +++ b/tests/factory/no_registry.py @@ -3,6 +3,7 @@ from typing import Any from faker import Faker +from hexbytes import HexBytes from pydantic_factories import Use from src.constants import FAR_FUTURE_EPOCH @@ -19,6 +20,12 @@ class ValidatorStateFactory(Web3Factory): exit_epoch = FAR_FUTURE_EPOCH + @classmethod + def build(cls, **kwargs: Any): + if 'pubkey' not in kwargs: + kwargs['pubkey'] = HexBytes(faker.binary(length=48)).hex() + return super().build(**kwargs) + class ValidatorFactory(Web3Factory): __model__ = Validator From 27439335b27273bba0f7966cf129038a66552154 Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Tue, 7 Jan 2025 15:50:59 +0100 Subject: [PATCH 6/9] fix: review --- src/constants.py | 2 +- src/modules/accounting/accounting.py | 11 ++++++----- src/web3py/extensions/lido_validators.py | 4 ++-- tests/modules/accounting/test_accounting_module.py | 4 ++-- tests/web3_extentions/test_lido_validators.py | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/constants.py b/src/constants.py index 52ff3b612..d4e3d079a 100644 --- a/src/constants.py +++ b/src/constants.py @@ -15,7 +15,7 @@ # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#gwei-values EFFECTIVE_BALANCE_INCREMENT = 2 ** 0 * 10 ** 9 MAX_EFFECTIVE_BALANCE = Gwei(32 * 10 ** 9) -MIN_ACTIVATION_BALANCE = Gwei(32 * 10 ** 9) +LIDO_DEPOSIT_AMOUNT = Gwei(32 * 10 ** 9) # https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#execution MAX_WITHDRAWALS_PER_PAYLOAD = 2 ** 4 # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#withdrawal-prefixes diff --git a/src/modules/accounting/accounting.py b/src/modules/accounting/accounting.py index e64f7ee09..10d5c2e92 100644 --- a/src/modules/accounting/accounting.py +++ b/src/modules/accounting/accounting.py @@ -216,12 +216,13 @@ def get_updated_modules_stats( def _get_consensus_lido_state(self, blockstamp: ReferenceBlockStamp) -> tuple[ValidatorsCount, ValidatorsBalance]: lido_validators = self.w3.lido_validators.get_lido_validators(blockstamp) - count = len(lido_validators) - pending_deposits_sum = self.w3.lido_validators.calculate_pending_deposits_sum(lido_validators) - total_balance = Gwei(sum(int(validator.balance) for validator in lido_validators) + pending_deposits_sum) + validators_count = len(lido_validators) + active_balance = sum(int(validator.balance) for validator in lido_validators) + pending_deposits = self.w3.lido_validators.calculate_pending_deposits_sum(lido_validators) + total_balance = Gwei(active_balance + pending_deposits) - logger.info({'msg': 'Calculate lido state on CL. (Validators count, Total balance in gwei)', 'value': (count, total_balance)}) - return ValidatorsCount(count), ValidatorsBalance(total_balance) + logger.info({'msg': f'Calculate Lido state on CL. {validators_count=}, {active_balance=}, {pending_deposits=}, {total_balance=} (Gwei)'}) + return ValidatorsCount(validators_count), ValidatorsBalance(total_balance) def _get_finalization_data(self, blockstamp: ReferenceBlockStamp) -> tuple[FinalizationShareRate, FinalizationBatches]: simulation = self.simulate_full_rebase(blockstamp) diff --git a/src/web3py/extensions/lido_validators.py b/src/web3py/extensions/lido_validators.py index 90758e1ef..b1fddc23a 100644 --- a/src/web3py/extensions/lido_validators.py +++ b/src/web3py/extensions/lido_validators.py @@ -6,7 +6,7 @@ from eth_typing import ChecksumAddress from web3.module import Module -from src.constants import FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE +from src.constants import FAR_FUTURE_EPOCH, LIDO_DEPOSIT_AMOUNT from src.providers.consensus.types import Validator from src.providers.keys.types import LidoKey from src.types import BlockStamp, StakingModuleId, NodeOperatorId, NodeOperatorGlobalIndex, StakingModuleAddress @@ -178,7 +178,7 @@ def calculate_pending_deposits_sum(lido_validators: list[LidoValidator]) -> int: # NOTE: Using 32 ETH as a default validator pending balance is OK for the current protocol implementation. # It must be changed in case of validators consolidation feature implementation. return sum( - MIN_ACTIVATION_BALANCE + LIDO_DEPOSIT_AMOUNT for validator in lido_validators if int(validator.balance) == 0 and int(validator.validator.activation_epoch) == FAR_FUTURE_EPOCH ) diff --git a/tests/modules/accounting/test_accounting_module.py b/tests/modules/accounting/test_accounting_module.py index cf357bb25..a69effa17 100644 --- a/tests/modules/accounting/test_accounting_module.py +++ b/tests/modules/accounting/test_accounting_module.py @@ -6,7 +6,7 @@ from web3.types import Wei from src import variables -from src.constants import MIN_ACTIVATION_BALANCE +from src.constants import LIDO_DEPOSIT_AMOUNT from src.modules.accounting import accounting as accounting_module from src.modules.accounting.accounting import Accounting from src.modules.accounting.accounting import logger as accounting_logger @@ -112,7 +112,7 @@ def test_get_consensus_lido_state(accounting: Accounting): count, balance = accounting._get_consensus_lido_state(bs) assert count == 10 - assert balance == sum((int(val.balance) for val in validators)) + 3 * MIN_ACTIVATION_BALANCE + assert balance == sum((int(val.balance) for val in validators)) + 3 * LIDO_DEPOSIT_AMOUNT @pytest.mark.unit diff --git a/tests/web3_extentions/test_lido_validators.py b/tests/web3_extentions/test_lido_validators.py index bd26579b1..fb393f2e5 100644 --- a/tests/web3_extentions/test_lido_validators.py +++ b/tests/web3_extentions/test_lido_validators.py @@ -2,7 +2,7 @@ import pytest -from src.constants import MIN_ACTIVATION_BALANCE +from src.constants import LIDO_DEPOSIT_AMOUNT from src.modules.accounting.types import BeaconStat from src.web3py.extensions.lido_validators import CountOfKeysDiffersException from tests.factory.blockstamp import ReferenceBlockStampFactory @@ -54,7 +54,7 @@ def test_calc_pending_deposits_sum(web3, lido_validators, contracts): lido_validators = web3.lido_validators.get_lido_validators(blockstamp) pending_deposits_sum = web3.lido_validators.calculate_pending_deposits_sum(lido_validators) - assert pending_deposits_sum == 5 * MIN_ACTIVATION_BALANCE + assert pending_deposits_sum == 5 * LIDO_DEPOSIT_AMOUNT @pytest.mark.unit From 32ee2a11c690276bf15b17963e986fd772c4fb19 Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Tue, 7 Jan 2025 17:11:48 +0100 Subject: [PATCH 7/9] fix: after rebase --- src/constants.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/constants.py b/src/constants.py index d4e3d079a..786e5ed44 100644 --- a/src/constants.py +++ b/src/constants.py @@ -15,7 +15,6 @@ # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#gwei-values EFFECTIVE_BALANCE_INCREMENT = 2 ** 0 * 10 ** 9 MAX_EFFECTIVE_BALANCE = Gwei(32 * 10 ** 9) -LIDO_DEPOSIT_AMOUNT = Gwei(32 * 10 ** 9) # https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#execution MAX_WITHDRAWALS_PER_PAYLOAD = 2 ** 4 # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#withdrawal-prefixes @@ -32,6 +31,8 @@ MIN_ACTIVATION_BALANCE = Gwei(2 ** 5 * 10 ** 9) MAX_EFFECTIVE_BALANCE_ELECTRA = Gwei(2 ** 11 * 10 ** 9) +LIDO_DEPOSIT_AMOUNT = MIN_ACTIVATION_BALANCE + # Local constants GWEI_TO_WEI = 10 ** 9 SHARE_RATE_PRECISION_E27 = 10 ** 27 From 820eb43666087f43dc7b0eba87e136b125987122 Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Thu, 9 Jan 2025 09:52:57 +0100 Subject: [PATCH 8/9] fix: after rebase --- src/constants.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/constants.py b/src/constants.py index 786e5ed44..743cc90e8 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,8 +1,6 @@ from src.types import Gwei # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#misc -from src.types import Gwei - FAR_FUTURE_EPOCH = 2 ** 64 - 1 # https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters-1 MIN_VALIDATOR_WITHDRAWABILITY_DELAY = 2 ** 8 From 349c6244fa569d2ff0ef27a2115c4730e35324cc Mon Sep 17 00:00:00 2001 From: vgorkavenko Date: Thu, 9 Jan 2025 09:58:58 +0100 Subject: [PATCH 9/9] tests: build validators using `LidoValidatorFactory` --- tests/web3_extentions/test_lido_validators.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/tests/web3_extentions/test_lido_validators.py b/tests/web3_extentions/test_lido_validators.py index fb393f2e5..f775373f3 100644 --- a/tests/web3_extentions/test_lido_validators.py +++ b/tests/web3_extentions/test_lido_validators.py @@ -41,17 +41,9 @@ def test_get_lido_validators(web3, lido_validators, contracts): @pytest.mark.unit def test_calc_pending_deposits_sum(web3, lido_validators, contracts): - validators = [ValidatorFactory.build_pending_deposit_vals() for _ in range(5)] - validators.extend(ValidatorFactory.batch(30)) - lido_keys = LidoKeyFactory.generate_for_validators(validators[:15]) - lido_keys.extend(LidoKeyFactory.batch(10)) - - web3.lido_validators._kapi_sanity_check = Mock() + lido_validators = LidoValidatorFactory.batch(30) + lido_validators.extend(LidoValidatorFactory.build_pending_deposit_vals() for _ in range(5)) - web3.cc.get_validators = Mock(return_value=validators) - web3.kac.get_used_lido_keys = Mock(return_value=lido_keys) - - lido_validators = web3.lido_validators.get_lido_validators(blockstamp) pending_deposits_sum = web3.lido_validators.calculate_pending_deposits_sum(lido_validators) assert pending_deposits_sum == 5 * LIDO_DEPOSIT_AMOUNT