-
Notifications
You must be signed in to change notification settings - Fork 634
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
Sync ethereum/eth2.0-specs#374 part1: types, constants, deposit_helpers #1700
Conversation
I think I just ran this locally: >>> import eth_utils
>>> eth_utils.denoms
<class 'eth_utils.currency.denoms'>
>>> eth_utils.denoms.gwei
1000000000
>>> eth_utils.denoms.gwei == 10**9
True |
@djrtwo |
aaahh. I see Reviewing PR now |
def test_defaults(sample_beacon_state_params): | ||
state = BeaconState(**sample_beacon_state_params) | ||
assert state.validator_registry == sample_beacon_state_params['validator_registry'] | ||
assert state.validator_registry_latest_change_slot == sample_beacon_state_params['validator_registry_latest_change_slot'] # noqa: E501 | ||
|
||
|
||
def test_validator_registry_and_balances_length(sample_beacon_state_params, far_future_slot): | ||
# When len(BeaconState.validator_registry) != len(BeaconState.validtor_balances) | ||
with pytest.raises(ValueError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is ValidationError
a more appropriate error here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A user should never be able to provide data/input that would cause this to trigger (via signed messages, txs, etc). A developer could. Does that make it a ValidationError
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@djrtwo yes, that's also what I thought! We should ensure len(BeaconState.validator_registry) == len(BeaconState.validtor_balances)
during writing eth
APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ValidationError
if it is possible for this code path to be encountered under some form of live conditions like somehow ending up with an invalid state where the registry and balances get out of sync.ValueError
for lower level errors, normally indicative of us having some kind of broken code which is passing in the wrong type of value or a malformed value.
Admittedly these two definitions are not fully independent. Maybe rule of thumb is: 1) A user should never see a ValueError
, nor should anything like the ethereum/tests
end up triggering a ValueError
. ValidationError
may occasionally show up for users and is likely a regular result for many of the ethereum/tests
style tests which test edge cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm. I'm still a bit unclear on this.
There is an invariant that and addition to or removal from one of these arrays should always require an symmetric addition/removal from the other array. All helper functions such as add_pending_validator
should enforce this invariant.
The state would only be out of sync if one of these helper functions was broken or if a user decided to manipulate/create a state directly with mismatched arrays. Because of the assumed atomicity of operations affecting the length of these two arrays, the network should never be able to provide data that gets them out of sync. This is different than say, the network providing an invalid block that throws a ValidationError
when processing.
I somewhat think ValueError
is appropriate here, but I am still trying to grok the difference and hope for some more clarity :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pipermerriam thanks for clarifying! FYI the reason why we put validator balances into a separate list in BeaconState (#1647) was clarified here by Justin:
It's an optimisation to minimise the amount of hashing when computing the beacon state root. The
validator_registry
(which contains most of the state) changes slowly and requires little hashing effort to maintain. Thevalidator_balances
is a smaller part of the state with much higher churn, hence why it is segregated.
So I do think this ValueError
here fits "for lower level errors, normally indicative of us having some kind of broken code which is passing in the wrong type of value or a malformed value" since it's for avoiding reckless coding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 seems like this could fit either case and that's expected since the two cases do have some conceptual overlap. No strong opinion of what should be done if anything here.
def test_defaults(sample_beacon_state_params): | ||
state = BeaconState(**sample_beacon_state_params) | ||
assert state.validator_registry == sample_beacon_state_params['validator_registry'] | ||
assert state.validator_registry_latest_change_slot == sample_beacon_state_params['validator_registry_latest_change_slot'] # noqa: E501 | ||
|
||
|
||
def test_validator_registry_and_balances_length(sample_beacon_state_params, far_future_slot): | ||
# When len(BeaconState.validator_registry) != len(BeaconState.validtor_balances) | ||
with pytest.raises(ValueError): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A user should never be able to provide data/input that would cause this to trigger (via signed messages, txs, etc). A developer could. Does that make it a ValidationError
?
cba7498
to
08f4472
Compare
eth/beacon/helpers.py
Outdated
slot: SlotNumber, | ||
epoch_length: int, | ||
target_committee_size: int, | ||
shard_count: int) -> Iterable[Iterable[ShardCommittee]]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor nitpick
Return type here would be more correct as a Tuple
type.
latest_status_change_slot=latest_status_change_slot, | ||
activation_slot=FAR_FUTURE_SLOT, | ||
exit_slot=FAR_FUTURE_SLOT, | ||
withdrawal_slot=FAR_FUTURE_SLOT, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that we are using FAR_FUTURE_SLOT
to represent the concept of undefined or None
since it works out to something like 5 billion centuries in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is essentially an "unset" flag on the var. It works nicely because we can use it in status checks.'
example: is_active -- v.activation_slot <= state.slot < v.exit_slot
- in the case that neither
activation_slot
norexit_slot
have been updated, the validator is not active. - in the case that
activation_slot
is set but is in the future, the validator is non active - in the case that
activation_slot
is in the past, butexit_slot
is not yet set, then the validator is active - in the case that
activation_slot
is in the pastand
exit_slot` has been set but is still in the future, the validator is active - in the case that
activation_slot
andexit_slot
are in the past, then the validator is not active and is instead exited.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any way that a validator could set any of these three fields to this value themselves? If so, it might be useful to explicitely define 2**64 - 1
as a disallowed value so that we have strong assurances that when any of these values is equal to 2**64 -1
we know that it means unset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that seems reasonable.
These values can only change via state transitions that a validator can trigger but not control the exact value of (e.g. requesting and exit
which would set their exit_slot
as state.slot + ENTRY_EXIT_DELAY
, or getting penalized which would set theirpenalization_slot
to state.slot
). These state transitions all change the value from FAR_FUTURE_SLOT
to a value that is a function of the current state.slot
Define `GWEI_PER_ETH` in `eth/beacon/constants.py` and replace `denoms.gwei` with it.
1. Move `FAR_FUTURE_SLOT` to `eth.beacon.constants` 2. Rename `get_pending_validator` to `create_pending_validator` 3. Add some docstrings
08f4472
to
d2f76bd
Compare
@djrtwo I'm going to merge it. Feel free to give post-merge review if any, I'll amend in the part2 PR. :) |
What was wrong?
ethereum/consensus-specs#374 updated a loooot logic of validator status.
How was it fixed?
SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD
.DepositData
value
toamount
, amount in Gwei.ValidatorRecord
activation_slot
,exit_slot
,penalized_slot
,withdrawal_slot
are usedto determine if a validator is active.status_flags
is for indicating that the validator has initialized exist or being withdrawable.ValidatorRegistryDeltaBlock
eth.beacon.helpers
get_new_shuffing
get_shuffling
slot: SlotNumber
parameter: Invariant - ifget_shuffling(seed, validators, shard, slot)
returns some valuex
, it should return the same valuex
for the same seed and shard and possible future modifications of validators forever in phase 0, and until the ~1 year deletion delay in phase 2 and in the future.get_active_validator_indices
: addslot: SlotNumber
parameter.BeaconState
BeaconState.update_validator(validator_index: ValidatorIndex, validator: ValidatorRecord, balance: Gwei)
API.len(validator_registry) == len(validator_balances)
denoms.gwei != GWEI_PER_ETH
🙈GWEI_PER_ETH
ineth/beacon/constants.py
and replacedenoms.gwei
with it.Cute Animal Picture