Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eip6110: Queue deposit requests and apply them during epoch processing #3818

Merged
merged 72 commits into from
Oct 4, 2024

Conversation

mkalinin
Copy link
Collaborator

@mkalinin mkalinin commented Jun 26, 2024

Description

Introduces majority of things described in #3689 (comment), specifically:

  • Queues full deposit request objects and process them on the epoch processing, rate limits a number of deposit signature verifications per epoch by the max number of deposit requests allowed to be processed (MAX_PENDING_DEPOSITS_PER_EPOCH)
  • Finalizes deposit request position in the queue before applying it to the state. The outcome is that no new validator is created before the corresponding deposit is finalized hence no fork aware (pubkey, index) cache is required.
  • Eth1 bridge deposits are processed as before this change, the corresponding entry with the entire balance is created in the pending_deposits queue to ensure the deposit will pass through the activation churn.
  • No deposit request is processed until Eth1 bridge covers the gap during the transition period. This prevents the scenario when deposit request can easily front-run the Eth1 bridge deposit because of the large follow distance and create validator with the same pubkey but malicious withdrawal credentials.
  • Refactors process_pending_deposits by moving deposit applying to apply_pending_deposit

Other than the above, the logic of the previous process_pending_balance_deposits function remains.

Additionally, moves switch_to_compounding_validator to process_deposit_request. Removes switch_to_compounding_validator from the deposit flow in favour of #3918.

Points of discussion and open questions

  • Due to refactor that facilitates spec reading there are two places where validatorIndex is looked up by the pubkey (process_pending_deposits and apply_pending_deposit functions), this happens for each pending deposit that is being processed. There is a less readable workaround where validatorIndex is resolved once, but I am not sure if it is necessary because client implementations are likely to use cache in both cases.
  • MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING is set to 16, should it be more? The activation churn is limited by 256 ETH which would mean 256 signature verifications in the worst case. The most optimal scenario of an attack resulting in 256 sig verifications would entail creation of 128 1-ETH validators (the first deposit would be to create a validator with eth1 creds, the second would be to switch the validator to compounding creds); it seems that employing such an attack is quite discouraging because it requires decent amount of ETH with no substantial gain. Should we even have this limitation if the churn could do the limit?
  • This PR does not explore an optimisation with two queues that was discussed previously, it is planned to be a part of a separate PR once this PR gets merged.

Testing

Many thanks to @james-prysm for helping to write and adjust the tests!

  • apply_pending_deposits checks
  • Deposit transition period checks -- the logic has changed and part of it is in process_pending_deposit
  • Repeat test_process_deposit_requests scenarious in application to process_pending_deposit
  • Finalized deposit position check
  • MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING check
  • Revisit test_process_pending_deposit (is_deposit_applied, is_churn_limit_reached etc)

Link to a more comprehensive test plan: https://hackmd.io/mqV7TaFyTq--vEMcB5msJw

Supersedes #3689

else:
validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
validator = state.validators[validator_index]
# Validator is exiting, do not consume the churn
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this condition validator.exit_epoch < FAR_FUTURE_EPOCH match

if get_current_epoch(state) <= validator.withdrawable_epoch:
return False

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is to postpone deposit processing for an exiting validator until it has fully withdrawn. And then do the top-up without affecting WS period.

@james-prysm
Copy link
Contributor

james-prysm commented Jun 26, 2024

Due to refactor that facilitates spec reading there are two places where validatorIndex is looked up by the pubkey (get_activation_churn_consumption and apply_pending_deposit functions), this happens for each pending deposit that is being processed. There is a less readable workaround where validatorIndex is resolved once, but I am not sure if it is necessary because client implementations are likely to use cache in both cases.

does this mean that the cache should continue to be used as opposed to the previous pr that looked for its removal in #3689

reading through I think my question is answered. we need it based on this PR

@mkalinin mkalinin requested review from hwwhww and fradamt June 28, 2024 06:16

```python
def get_validator_from_deposit(pubkey: BLSPubkey, withdrawal_credentials: Bytes32, amount: uint64) -> Validator:
if is_compounding_withdrawal_credential(withdrawal_credentials):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use get_max_effective_balance instead? You can create an instance of Validator first and then call get_max_effective_balance.

withdrawal_credentials=validator.withdrawal_credentials,
amount=excess_balance,
signature=bls.G2_POINT_AT_INFINITY,
slot=GENESIS_SLOT,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the consequence if I set this to state.slot instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the excess balance will wait for when state.slot is finalized before being applied even in the case when there is enough activation churn to let the balance in. The GENESIS_SLOT is used to bypass that finality check as that slot is always finalized

Comment on lines +660 to +661
signature=bls.G2_POINT_AT_INFINITY,
slot=GENESIS_SLOT,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should define meaningful constants for both bls.G2_POINT_AT_INFINITY and GENESIS_SLOT. How about aliasing them as

  • UNSET_SIGNATURE and
  • UNSET_DEPOSIT_SLOT

By seeing only the point at infinity and the genesis slot, the readers wouldn't know what they mean.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have put comments instead of aliasing those two. It is a bit difficult to incorporate the semantics into these constants in both cases

@jtraglia
Copy link
Member

jtraglia commented Oct 3, 2024

AIUI we would merge in #3918 which will simplify this PR a bit further
does this align with your understanding @mkalinin ?

yes, the plan is to wait for that PR and then merge this one

@mkalinin We've merged #3918. Any additional changes you'd like to make?

@jtraglia
Copy link
Member

jtraglia commented Oct 3, 2024

After merging in dev, the test_pending_consolidation_future_epoch test fails. I probably messed something up but it's not clear to me what is wrong. Do you know?

@mkalinin
Copy link
Collaborator Author

mkalinin commented Oct 4, 2024

After merging in dev, the test_pending_consolidation_future_epoch test fails. I probably messed something up but it's not clear to me what is wrong. Do you know?

Fixed now (the change of this test from the dev wasn’t applied to this branch)

@mkalinin We've merged #3918. Any additional changes you'd like to make?

The corresponding changes were already made, so the PR is ready for review and merging into dev

"""
assert is_post_electra(spec)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be not as these methods are called from post electra tests only

- pre-state ('pre')
- post-state ('post').
"""
assert is_post_electra(spec)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it needed?

tests/generators/epoch_processing/main.py Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.