Remove placeholders
Remove all custody and VDF placeholders (56 lines less!). A few notes on the placeholder fields and logic:
* All placeholder fields were dummy fields that can easily be restored in the phase 1 hard fork.
* One special case to the above is `custody_bit_0_validator_indices` in `SlashableVoteData` which was renamed to `validator_indices`. Renaming it back is *not* a spec change because SSZ field names are [no longer part of the spec](a9328157a8 (diff-8d8fe480a35579c7be2f976d9b321216)
).
* The placeholder logic was written using generalised functions (e.g. `bls_verify_multiple` vs `bls_verify`, and `indices(slashable_vote_data)` vs `slashable_vote_data.validator_indices`). This generality was unnecessary because it was not triggered when all custody bits were 0. This means we can simplify the logic without being inconsistent with phase 1.
Rationale:
* Keep phase 0 (likely far harder to deliver than phase 1) as clean as possible
* Focus on upgrade paths and incremental releases
* Custody is still under research—keep the design space open
This commit is contained in:
parent
5c2b595c2d
commit
6c824ffee4
|
@ -30,7 +30,6 @@
|
||||||
- [Attestations](#attestations)
|
- [Attestations](#attestations)
|
||||||
- [`Attestation`](#attestation)
|
- [`Attestation`](#attestation)
|
||||||
- [`AttestationData`](#attestationdata)
|
- [`AttestationData`](#attestationdata)
|
||||||
- [`AttestationDataAndCustodyBit`](#attestationdataandcustodybit)
|
|
||||||
- [Deposits](#deposits)
|
- [Deposits](#deposits)
|
||||||
- [`Deposit`](#deposit)
|
- [`Deposit`](#deposit)
|
||||||
- [`DepositData`](#depositdata)
|
- [`DepositData`](#depositdata)
|
||||||
|
@ -104,7 +103,6 @@
|
||||||
- [Attestations](#attestations-1)
|
- [Attestations](#attestations-1)
|
||||||
- [Deposits](#deposits-1)
|
- [Deposits](#deposits-1)
|
||||||
- [Exits](#exits-1)
|
- [Exits](#exits-1)
|
||||||
- [Custody](#custody)
|
|
||||||
- [Per-epoch processing](#per-epoch-processing)
|
- [Per-epoch processing](#per-epoch-processing)
|
||||||
- [Helpers](#helpers)
|
- [Helpers](#helpers)
|
||||||
- [Eth1 data](#eth1-data-1)
|
- [Eth1 data](#eth1-data-1)
|
||||||
|
@ -292,10 +290,8 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
# Validator indices with custody bit equal to 0
|
# Validator indices
|
||||||
'custody_bit_0_indices': ['uint24'],
|
'validator_indices': ['uint24'],
|
||||||
# Validator indices with custody bit equal to 1
|
|
||||||
'custody_bit_1_indices': ['uint24'],
|
|
||||||
# Attestation data
|
# Attestation data
|
||||||
'data': AttestationData,
|
'data': AttestationData,
|
||||||
# Aggregate signature
|
# Aggregate signature
|
||||||
|
@ -313,8 +309,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
'data': AttestationData,
|
'data': AttestationData,
|
||||||
# Attester aggregation bitfield
|
# Attester aggregation bitfield
|
||||||
'aggregation_bitfield': 'bytes',
|
'aggregation_bitfield': 'bytes',
|
||||||
# Custody bitfield
|
|
||||||
'custody_bitfield': 'bytes',
|
|
||||||
# BLS aggregate signature
|
# BLS aggregate signature
|
||||||
'aggregate_signature': 'bytes96',
|
'aggregate_signature': 'bytes96',
|
||||||
}
|
}
|
||||||
|
@ -343,17 +337,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
##### `AttestationDataAndCustodyBit`
|
|
||||||
|
|
||||||
```python
|
|
||||||
{
|
|
||||||
# Attestation data
|
|
||||||
data: AttestationData,
|
|
||||||
# Custody bit
|
|
||||||
custody_bit: bool,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Deposits
|
#### Deposits
|
||||||
|
|
||||||
##### `Deposit`
|
##### `Deposit`
|
||||||
|
@ -436,16 +419,11 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
'proposer_slashings': [ProposerSlashing],
|
'proposer_slashings': [ProposerSlashing],
|
||||||
'casper_slashings': [CasperSlashing],
|
'casper_slashings': [CasperSlashing],
|
||||||
'attestations': [Attestation],
|
'attestations': [Attestation],
|
||||||
'custody_reseeds': [CustodyReseed],
|
|
||||||
'custody_challenges': [CustodyChallenge],
|
|
||||||
'custody_responses': [CustodyResponse],
|
|
||||||
'deposits': [Deposit],
|
'deposits': [Deposit],
|
||||||
'exits': [Exit],
|
'exits': [Exit],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`CustodyReseed`, `CustodyChallenge`, and `CustodyResponse` will be defined in phase 1; for now, put dummy classes as these lists will remain empty throughout phase 0.
|
|
||||||
|
|
||||||
#### `ProposalSignedData`
|
#### `ProposalSignedData`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -479,7 +457,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
|
|
||||||
# Randomness and committees
|
# Randomness and committees
|
||||||
'latest_randao_mixes': ['bytes32'],
|
'latest_randao_mixes': ['bytes32'],
|
||||||
'latest_vdf_outputs': ['bytes32'],
|
|
||||||
'previous_epoch_start_shard': 'uint64',
|
'previous_epoch_start_shard': 'uint64',
|
||||||
'current_epoch_start_shard': 'uint64',
|
'current_epoch_start_shard': 'uint64',
|
||||||
'previous_epoch_calculation_slot': 'uint64',
|
'previous_epoch_calculation_slot': 'uint64',
|
||||||
|
@ -487,9 +464,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
'previous_epoch_randao_mix': 'bytes32',
|
'previous_epoch_randao_mix': 'bytes32',
|
||||||
'current_epoch_randao_mix': 'bytes32',
|
'current_epoch_randao_mix': 'bytes32',
|
||||||
|
|
||||||
# Custody challenges
|
|
||||||
'custody_challenges': [CustodyChallenge],
|
|
||||||
|
|
||||||
# Finality
|
# Finality
|
||||||
'previous_justified_slot': 'uint64',
|
'previous_justified_slot': 'uint64',
|
||||||
'justified_slot': 'uint64',
|
'justified_slot': 'uint64',
|
||||||
|
@ -531,10 +505,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
'exit_count': 'uint64',
|
'exit_count': 'uint64',
|
||||||
# Status flags
|
# Status flags
|
||||||
'status_flags': 'uint64',
|
'status_flags': 'uint64',
|
||||||
# Slot of latest custody reseed
|
|
||||||
'latest_custody_reseed_slot': 'uint64',
|
|
||||||
# Slot of second-latest custody reseed
|
|
||||||
'penultimate_custody_reseed_slot': 'uint64',
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -557,8 +527,6 @@ Code snippets appearing in `this style` are to be interpreted as Python code. Be
|
||||||
'data': AttestationData,
|
'data': AttestationData,
|
||||||
# Attester aggregation bitfield
|
# Attester aggregation bitfield
|
||||||
'aggregation_bitfield': 'bytes',
|
'aggregation_bitfield': 'bytes',
|
||||||
# Custody bitfield
|
|
||||||
'custody_bitfield': 'bytes',
|
|
||||||
# Slot the attestation was included
|
# Slot the attestation was included
|
||||||
'slot_included': 'uint64',
|
'slot_included': 'uint64',
|
||||||
}
|
}
|
||||||
|
@ -1092,24 +1060,14 @@ def get_domain(fork: Fork,
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) -> bool:
|
def verify_slashable_vote_data(state: BeaconState, vote_data: SlashableVoteData) -> bool:
|
||||||
if len(vote_data.custody_bit_0_indices) + len(vote_data.custody_bit_1_indices) > MAX_CASPER_VOTES:
|
if len(vote_data.validator_indices) > MAX_CASPER_VOTES:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return bls_verify_multiple(
|
return bls_verify(
|
||||||
pubkeys=[
|
pubkey=bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.validator_indices]),
|
||||||
bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.custody_bit_0_indices]),
|
message=hash_tree_root(AttestationData(vote_data.data)),
|
||||||
bls_aggregate_pubkeys([state.validator_registry[i].pubkey for i in vote_data.custody_bit_1_indices]),
|
|
||||||
],
|
|
||||||
messages=[
|
|
||||||
hash_tree_root(AttestationDataAndCustodyBit(vote_data.data, False)),
|
|
||||||
hash_tree_root(AttestationDataAndCustodyBit(vote_data.data, True)),
|
|
||||||
],
|
|
||||||
signature=vote_data.aggregate_signature,
|
signature=vote_data.aggregate_signature,
|
||||||
domain=get_domain(
|
domain=get_domain(state.fork, vote_data.data.slot, DOMAIN_ATTESTATION),
|
||||||
state.fork,
|
|
||||||
vote_data.data.slot,
|
|
||||||
DOMAIN_ATTESTATION,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1198,9 +1156,6 @@ A valid block with slot `GENESIS_SLOT` (a "genesis block") has the following val
|
||||||
proposer_slashings=[],
|
proposer_slashings=[],
|
||||||
casper_slashings=[],
|
casper_slashings=[],
|
||||||
attestations=[],
|
attestations=[],
|
||||||
custody_reseeds=[],
|
|
||||||
custody_challenges=[],
|
|
||||||
custody_responses=[],
|
|
||||||
deposits=[],
|
deposits=[],
|
||||||
exits=[],
|
exits=[],
|
||||||
),
|
),
|
||||||
|
@ -1232,7 +1187,6 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
|
|
||||||
# Randomness and committees
|
# Randomness and committees
|
||||||
latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)],
|
latest_randao_mixes=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH)],
|
||||||
latest_vdf_outputs=[ZERO_HASH for _ in range(LATEST_RANDAO_MIXES_LENGTH // EPOCH_LENGTH)],
|
|
||||||
previous_epoch_start_shard=GENESIS_START_SHARD,
|
previous_epoch_start_shard=GENESIS_START_SHARD,
|
||||||
current_epoch_start_shard=GENESIS_START_SHARD,
|
current_epoch_start_shard=GENESIS_START_SHARD,
|
||||||
previous_epoch_calculation_slot=GENESIS_SLOT,
|
previous_epoch_calculation_slot=GENESIS_SLOT,
|
||||||
|
@ -1240,9 +1194,6 @@ def get_initial_beacon_state(initial_validator_deposits: List[Deposit],
|
||||||
previous_epoch_randao_mix=ZERO_HASH,
|
previous_epoch_randao_mix=ZERO_HASH,
|
||||||
current_epoch_randao_mix=ZERO_HASH,
|
current_epoch_randao_mix=ZERO_HASH,
|
||||||
|
|
||||||
# Custody challenges
|
|
||||||
custody_challenges=[],
|
|
||||||
|
|
||||||
# Finality
|
# Finality
|
||||||
previous_justified_slot=GENESIS_SLOT,
|
previous_justified_slot=GENESIS_SLOT,
|
||||||
justified_slot=GENESIS_SLOT,
|
justified_slot=GENESIS_SLOT,
|
||||||
|
@ -1340,8 +1291,6 @@ def process_deposit(state: BeaconState,
|
||||||
penalized_slot=FAR_FUTURE_SLOT,
|
penalized_slot=FAR_FUTURE_SLOT,
|
||||||
exit_count=0,
|
exit_count=0,
|
||||||
status_flags=0,
|
status_flags=0,
|
||||||
latest_custody_reseed_slot=GENESIS_SLOT,
|
|
||||||
penultimate_custody_reseed_slot=GENESIS_SLOT,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled.
|
# Note: In phase 2 registry indices that have been withdrawn for a long time will be recycled.
|
||||||
|
@ -1489,8 +1438,7 @@ For each `casper_slashing` in `block.body.casper_slashings`:
|
||||||
|
|
||||||
* Let `slashable_vote_data_1 = casper_slashing.slashable_vote_data_1`.
|
* Let `slashable_vote_data_1 = casper_slashing.slashable_vote_data_1`.
|
||||||
* Let `slashable_vote_data_2 = casper_slashing.slashable_vote_data_2`.
|
* Let `slashable_vote_data_2 = casper_slashing.slashable_vote_data_2`.
|
||||||
* Let `indices(slashable_vote_data) = slashable_vote_data.custody_bit_0_indices + slashable_vote_data.custody_bit_1_indices`.
|
* Let `intersection = [x for x in slashable_vote_data_1.validator_indices if x in slashable_vote_data_2.validator_indices]`.
|
||||||
* Let `intersection = [x for x in indices(slashable_vote_data_1) if x in indices(slashable_vote_data_2)]`.
|
|
||||||
* Verify that `len(intersection) >= 1`.
|
* Verify that `len(intersection) >= 1`.
|
||||||
* Verify that `slashable_vote_data_1.data != slashable_vote_data_2.data`.
|
* Verify that `slashable_vote_data_1.data != slashable_vote_data_2.data`.
|
||||||
* Verify that `is_double_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)` or `is_surround_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)`.
|
* Verify that `is_double_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)` or `is_surround_vote(slashable_vote_data_1.data, slashable_vote_data_2.data)`.
|
||||||
|
@ -1512,9 +1460,9 @@ For each `attestation` in `block.body.attestations`:
|
||||||
* `aggregate_signature` verification:
|
* `aggregate_signature` verification:
|
||||||
* Let `participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield)`.
|
* Let `participants = get_attestation_participants(state, attestation.data, attestation.aggregation_bitfield)`.
|
||||||
* Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`.
|
* Let `group_public_key = bls_aggregate_pubkeys([state.validator_registry[v].pubkey for v in participants])`.
|
||||||
* Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationDataAndCustodyBit(attestation.data, False)), signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`.
|
* Verify that `bls_verify(pubkey=group_public_key, message=hash_tree_root(AttestationData(attestation.data)), signature=attestation.aggregate_signature, domain=get_domain(state.fork, attestation.data.slot, DOMAIN_ATTESTATION))`.
|
||||||
* [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`.
|
* [TO BE REMOVED IN PHASE 1] Verify that `attestation.data.shard_block_root == ZERO_HASH`.
|
||||||
* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`.
|
* Append `PendingAttestation(data=attestation.data, aggregation_bitfield=attestation.aggregation_bitfield, slot_included=state.slot)` to `state.latest_attestations`.
|
||||||
|
|
||||||
#### Deposits
|
#### Deposits
|
||||||
|
|
||||||
|
@ -1564,10 +1512,6 @@ For each `exit` in `block.body.exits`:
|
||||||
* Verify that `bls_verify(pubkey=validator.pubkey, message=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.slot, DOMAIN_EXIT))`.
|
* Verify that `bls_verify(pubkey=validator.pubkey, message=exit_message, signature=exit.signature, domain=get_domain(state.fork, exit.slot, DOMAIN_EXIT))`.
|
||||||
* Run `initiate_validator_exit(state, exit.validator_index)`.
|
* Run `initiate_validator_exit(state, exit.validator_index)`.
|
||||||
|
|
||||||
#### Custody
|
|
||||||
|
|
||||||
[TO BE REMOVED IN PHASE 1] Verify that `len(block.body.custody_reseeds) == len(block.body.custody_challenges) == len(block.body.custody_responses) == 0`.
|
|
||||||
|
|
||||||
## Per-epoch processing
|
## Per-epoch processing
|
||||||
|
|
||||||
The steps below happen when `state.slot % EPOCH_LENGTH == 0`.
|
The steps below happen when `state.slot % EPOCH_LENGTH == 0`.
|
||||||
|
|
Loading…
Reference in New Issue