remove specials

This commit is contained in:
Danny Ryan 2018-12-06 19:02:23 -06:00
parent 40fd893fc1
commit 80e224be8c
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
1 changed files with 233 additions and 227 deletions

View File

@ -17,20 +17,25 @@
- [Time parameters](#time-parameters) - [Time parameters](#time-parameters)
- [Reward and penalty quotients](#reward-and-penalty-quotients) - [Reward and penalty quotients](#reward-and-penalty-quotients)
- [Status codes](#status-codes) - [Status codes](#status-codes)
- [Special record types](#special-record-types) - [Max transactions](#max-transactions)
- [Validator registry delta flags](#validator-registry-delta-flags) - [Validator registry delta flags](#validator-registry-delta-flags)
- [Signature domains](#signature-domains) - [Signature domains](#signature-domains)
- [Data structures](#data-structures) - [Data structures](#data-structures)
- [Deposits](#deposits) - [Deposits](#deposits)
- [`DepositParametersRecord`](#depositparametersrecord) - [`DepositParametersRecord`](#depositparametersrecord)
- [Beacon chain transactions](#beacon-chain-transactions)
- [`AttestationRecord`](#attestationrecord)
- [`AttestationData`](#attestationdata)
- [`ProposerSlashingRecord`](#proposerslashingrecord)
- [`CasperSlashingRecord`](#casperslashingrecord)
- [`SpecialAttestationData`](#specialattestationdata)
- [`DepositRecord`](#depositproofrecord)
- [`ExitRecord`](#voluntaryexitrecord)
- [Beacon chain blocks](#beacon-chain-blocks) - [Beacon chain blocks](#beacon-chain-blocks)
- [`BeaconBlockHeader`](#beaconblockheader) - [`BeaconBlockHeader`](#beaconblockheader)
- [`BeaconBlockBody`](#beaconblockbody) - [`BeaconBlockBody`](#beaconblockbody)
- [`BeaconBlock`](#beaconblock) - [`BeaconBlock`](#beaconblock)
- [`AttestationRecord`](#attestationrecord)
- [`AttestationData`](#attestationdata)
- [`ProposalSignedData`](#proposalsigneddata) - [`ProposalSignedData`](#proposalsigneddata)
- [`SpecialRecord`](#specialrecord)
- [Beacon chain state](#beacon-chain-state) - [Beacon chain state](#beacon-chain-state)
- [`BeaconState`](#beaconstate) - [`BeaconState`](#beaconstate)
- [`ValidatorRecord`](#validatorrecord) - [`ValidatorRecord`](#validatorrecord)
@ -40,12 +45,6 @@
- [`CandidatePoWReceiptRootRecord`](#candidatepowreceiptrootrecord) - [`CandidatePoWReceiptRootRecord`](#candidatepowreceiptrootrecord)
- [`PendingAttestationRecord`](#pendingattestationrecord) - [`PendingAttestationRecord`](#pendingattestationrecord)
- [`ForkData`](#forkdata) - [`ForkData`](#forkdata)
- [Specials](#specials)
- [`VoluntaryExitSpecial`](#voluntaryexitspecial)
- [`CasperSlashingSpecial`](#casperslashingspecial)
- [`SpecialAttestationData`](#specialattestationdata)
- [`ProposerSlashingSpecial`](#proposerslashingspecial)
- [`DepositProofSpecial`](#depositproofspecial)
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract) - [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
- [Deposit arguments](#deposit-arguments) - [Deposit arguments](#deposit-arguments)
- [`Deposit` logs](#deposit-logs) - [`Deposit` logs](#deposit-logs)
@ -68,20 +67,21 @@
- [`get_effective_balance`](#get_effective_balance) - [`get_effective_balance`](#get_effective_balance)
- [`get_new_validator_registry_delta_chain_tip`](#get_new_validator_registry_delta_chain_tip) - [`get_new_validator_registry_delta_chain_tip`](#get_new_validator_registry_delta_chain_tip)
- [`get_domain`](#get_domain) - [`get_domain`](#get_domain)
- [`verify_special_attestation_data`](#verify_special_attestation_data)
- [`integer_squareroot`](#integer_squareroot) - [`integer_squareroot`](#integer_squareroot)
- [On startup](#on-startup) - [On startup](#on-startup)
- [Routine for activating a validator](#routine-for-activating-a-validator) - [Routine for activating a validator](#routine-for-activating-a-validator)
- [Routine for exiting a validator](#routine-for-exiting-a-validator) - [Routine for exiting a validator](#routine-for-exiting-a-validator)
- [Per-slot processing](#per-slot-processing) - [Per-slot processing](#per-slot-processing)
- [Proposer signature](#proposer-signature) - [Proposer signature](#proposer-signature)
- [Attestations](#attestations)
- [RANDAO](#randao) - [RANDAO](#randao)
- [PoW receipt root](#pow-receipt-root) - [PoW receipt root](#pow-receipt-root)
- [Special objects](#special-objects) - [Transactions](#transactions)
- [`VOLUNTARY_EXIT`](#voluntary_exit) - [Proposer slashings](#proposer-slashing)
- [`CASPER_SLASHING`](#casper_slashing) - [Casper slashings](#casper-slashing)
- [`PROPOSER_SLASHING`](#proposer_slashing) - [Attestations](#attestations)
- [`DEPOSIT_PROOF`](#deposit_proof) - [Deposits](#deposits)
- [Exits](#exits)
- [Per-epoch processing](#per-epoch-processing) - [Per-epoch processing](#per-epoch-processing)
- [Helpers](#helpers) - [Helpers](#helpers)
- [Receipt roots](#receipt-roots) - [Receipt roots](#receipt-roots)
@ -200,14 +200,15 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
| `EXITED_WITHOUT_PENALTY` | `3` | | `EXITED_WITHOUT_PENALTY` | `3` |
| `EXITED_WITH_PENALTY` | `4` | | `EXITED_WITH_PENALTY` | `4` |
### Special record types ### Max transactions
| Name | Value | Maximum count | | Name | Value |
| - | - | :-: | | - | - | :-: |
| `VOLUNTARY_EXIT` | `0` | `16` | | `MAX_PROPOSER_SLASHINGS` | `2**4` (= 16) |
| `CASPER_SLASHING` | `1` | `16` | | `MAX_CASPER_SLASHINGS` | `2**4` (= 16) |
| `PROPOSER_SLASHING` | `2` | `16` | | `MAX_ATTESTATIONS` | `2**7` (= 128) |
| `DEPOSIT_PROOF` | `3` | `16` | | `MAX_DEPOSITS` | `2**4` (= 16) |
| `MAX_EXITS` | `2**4` (= 16) |
### Validator registry delta flags ### Validator registry delta flags
@ -244,40 +245,7 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
} }
``` ```
### Beacon chain blocks ### Beacon chain transactions
#### `BeaconBlockHeader`
```python
{
'slot': 'uint64',
# Skip list of ancestor beacon block hashes
# i'th item is the most recent ancestor whose slot is a multiple of 2**i for i = 0, ..., 31
'ancestor_hashes': ['hash32'],
'state_root': 'hash32',
'randao_reveal': 'hash32',
'candidate_pow_receipt_root': 'hash32',
'signature': ['uint384'],
}
```
#### `BeaconBlockBody`
```python
{
'attestations': [AttestationRecord],
'specials': [SpecialRecord],
}
```
#### `BeaconBlock`
```python
{
'header': BeaconBlockHeader,
'body': BeaconBlockBody,
}
```
#### `AttestationRecord` #### `AttestationRecord`
@ -317,6 +285,120 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
} }
``` ```
#### `ProposerSlashingRecord`
```python
{
# Proposer index
'proposer_index': 'uint24',
# First proposal data
'proposal_data_1': ProposalSignedData,
# First proposal signature
'proposal_signature_1': '[uint384]',
# Second proposal data
'proposal_data_2': ProposalSignedData,
# Second proposal signature
'proposal_signature_2': '[uint384]',
}
```
#### `CasperSlashingRecord`
```python
{
# First vote
vote_1: SpecialAttestationData,
# Second vote
vote_2: SpecialAttestationData,
}
```
#### `SpecialAttestationData`
```python
{
# Proof-of-custody indices (0 bits)
'aggregate_signature_poc_0_indices': '[uint24]',
# Proof-of-custody indices (1 bits)
'aggregate_signature_poc_1_indices': '[uint24]',
# Attestation data
'data': AttestationData,
# Aggregate signature
'aggregate_signature': '[uint384]',
}
```
#### `DepositRecord`
```python
{
# Receipt Merkle branch
'merkle_branch': '[hash32]',
# Merkle tree index
'merkle_tree_index': 'uint64',
# Deposit data
'deposit_data': {
# Deposit parameters
'deposit_parameters': DepositParametersRecord,
# Value in Gwei
'value': 'uint64',
# Timestamp from deposit contract
'timestamp': 'uint64',
},
}
```
#### `ExitRecord`
```python
{
# Minimum slot for processing exit
'slot': 'unit64',
# Index of the exiting validator
'validator_index': 'uint64',
# Validator signature
'signature': '[uint384]',
}
```
### Beacon chain blocks
#### `BeaconBlockHeader`
```python
{
'slot': 'uint64',
# Skip list of ancestor beacon block hashes
# i'th item is the most recent ancestor whose slot is a multiple of 2**i for i = 0, ..., 31
'ancestor_hashes': ['hash32'],
'state_root': 'hash32',
'randao_reveal': 'hash32',
'candidate_pow_receipt_root': 'hash32',
'signature': ['uint384'],
}
```
#### `BeaconBlockBody`
```python
{
'attestations': [AttestationRecord],
'proposer_slashings': [ProposerSlashingRecord],
'casper_slashings': [CasperSlashingRecord],
'deposits': [DepositRecord],
'exits': [ExitRecord],
}
```
#### `BeaconBlock`
```python
{
'header': BeaconBlockHeader,
'body': BeaconBlockBody,
}
```
#### `ProposalSignedData` #### `ProposalSignedData`
```python ```python
@ -330,17 +412,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
} }
``` ```
#### `SpecialRecord`
```python
{
# Kind
'kind': 'uint64',
# Data
'data': 'bytes',
}
```
### Beacon chain state ### Beacon chain state
#### `BeaconState` #### `BeaconState`
@ -482,84 +553,6 @@ Unless otherwise indicated, code appearing in `this style` is to be interpreted
} }
``` ```
### Specials
#### `VoluntaryExitSpecial`
```python
{
# Minimum slot for processing exit
'slot': 'unit64',
# Index of the exiting validator
'validator_index': 'uint64',
# Validator signature
'signature': '[uint384]',
}
```
#### `CasperSlashingSpecial`
```python
{
# First vote
vote_1: SpecialAttestationData,
# Second vote
vote_2: SpecialAttestationData,
}
```
#### `SpecialAttestationData`
```python
{
# Proof-of-custody indices (0 bits)
'aggregate_signature_poc_0_indices': '[uint24]',
# Proof-of-custody indices (1 bits)
'aggregate_signature_poc_1_indices': '[uint24]',
# Attestation data
'data': AttestationData,
# Aggregate signature
'aggregate_signature': '[uint384]',
}
```
#### `ProposerSlashingSpecial`
```python
{
# Proposer index
'proposer_index': 'uint24',
# First proposal data
'proposal_data_1': ProposalSignedData,
# First proposal signature
'proposal_signature_1': '[uint384]',
# Second proposal data
'proposal_data_2': ProposalSignedData,
# Second proposal signature
'proposal_signature_2': '[uint384]',
}
```
#### `DepositProofSpecial`
```python
{
# Receipt Merkle branch
'merkle_branch': '[hash32]',
# Merkle tree index
'merkle_tree_index': 'uint64',
# Deposit data
'deposit_data': {
# Deposit parameters
'deposit_parameters': DepositParametersRecord,
# Value in Gwei
'value': 'uint64',
# Timestamp from deposit contract
'timestamp': 'uint64',
},
}
```
## Ethereum 1.0 deposit contract ## Ethereum 1.0 deposit contract
The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards when the EVM2.0 is deployed and the shards have state. The initial deployment phases of Ethereum 2.0 are implemented without consensus changes to Ethereum 1.0. A deposit contract at address `DEPOSIT_CONTRACT_ADDRESS` is added to Ethereum 1.0 for deposits of ETH to the beacon chain. Validator balances will be withdrawable to the shards when the EVM2.0 is deployed and the shards have state.
@ -960,6 +953,15 @@ def get_domain(fork_data: ForkData,
) * 2**32 + domain_type ) * 2**32 + domain_type
``` ```
#### `verify_special_attestation_data`
```python
def verify_special_attestation_data(state: State, obj: SpecialAttestationData) -> bool:
pubs = [aggregate_pubkey([state.validators[i].pubkey for i in obj.aggregate_signature_poc_0_indices]),
aggregate_pubkey([state.validators[i].pubkey for i in obj.aggregate_signature_poc_1_indices])]
return BLSMultiVerify(pubkeys=pubs, msgs=[SSZTreeHash(obj)+bytes1(0), SSZTreeHash(obj)+bytes1(1), sig=aggregate_signature)
```
#### `integer_squareroot` #### `integer_squareroot`
```python ```python
@ -981,14 +983,21 @@ A valid block with slot `INITIAL_SLOT_NUMBER` (a "genesis block") has the follow
```python ```python
{ {
'slot': INITIAL_SLOT_NUMBER, 'header': BeaconBlockHeader(
'randao_reveal': ZERO_HASH, slot=INITIAL_SLOT_NUMBER,
'candidate_pow_receipt_root': ZERO_HASH, ancestor_hashes=[ZERO_HASH for i in range(32)],
'ancestor_hashes': [ZERO_HASH for i in range(32)], state_root=STARTUP_STATE_ROOT,
'state_root': STARTUP_STATE_ROOT, randao_reveal=ZERO_HASH,
'attestations': [], candidate_pow_receipt_root=ZERO_HASH,
'specials': [], proposer_signature=[0, 0]
'proposer_signature': [0, 0], ),
'body': BeaconBlockBody(
proposer_slashings=[],
casper_slashings=[],
attestations=[],
deposits=[],
exits=[]
),
} }
``` ```
@ -1236,9 +1245,54 @@ If there is no block from the proposer at state.slot:
* Let `proposal_hash = hash(ProposalSignedData(state.slot, BEACON_CHAIN_SHARD_NUMBER, block_hash_without_sig))`. * Let `proposal_hash = hash(ProposalSignedData(state.slot, BEACON_CHAIN_SHARD_NUMBER, block_hash_without_sig))`.
* Verify that `BLSVerify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, data=proposal_hash, sig=block.header.signature, domain=get_domain(state.fork_data, state.slot, DOMAIN_PROPOSAL))`. * Verify that `BLSVerify(pubkey=state.validator_registry[get_beacon_proposer_index(state, state.slot)].pubkey, data=proposal_hash, sig=block.header.signature, domain=get_domain(state.fork_data, state.slot, DOMAIN_PROPOSAL))`.
### Attestations ### RANDAO
* Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS_PER_BLOCK`. * Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`.
* Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`.
* Verify that `repeat_hash(block.header.randao_reveal, proposer.randao_skips + 1) == proposer.randao_commitment`.
* Set `state.randao_mix = xor(state.randao_mix, block.header.randao_reveal)`.
* Set `proposer.randao_commitment = block.header.randao_reveal`.
* Set `proposer.randao_skips = 0`.
### PoW receipt root
* If `block.header.candidate_pow_receipt_root` is `x.candidate_pow_receipt_root` for some `x` in `state.candidate_pow_receipt_roots`, set `x.votes += 1`.
* Otherwise, append to `state.candidate_pow_receipt_roots` a new `CandidatePoWReceiptRootRecord(candidate_pow_receipt_root=block.header.candidate_pow_receipt_root, votes=1)`.
### Transactions
#### Proposer slashings
Verify that `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`.
For each `proposer_slashing` in `block.body.proposer_slashings`:
* Let `proposer = state.validator_registry[proposer_slashing.proposer_index]`
* Verify that `BLSVerify(pubkey=proposer.pubkey, msg=hash(proposer_slashing.proposal_data_1), sig=proposer_slashing.proposal_signature_1, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_1.slot, DOMAIN_PROPOSAL))`.
* Verify that `BLSVerify(pubkey=proposer.pubkey, msg=hash(proposer_slashing.proposal_data_2), sig=proposer_slashing.proposal_signature_2, domain=get_domain(state.fork_data, proposer_slashing.proposal_data_2.slot, DOMAIN_PROPOSAL))`.
* Verify that `proposer_slashing.proposal_data_1 != proposer_slashing.proposal_data_2`.
* Verify that `proposer_slashing.proposal_data_1.slot == proposer_slashing.proposal_data_2.slot`.
* Verify that `proposer.status != EXITED_WITH_PENALTY`.
* Run `exit_validator(proposer_slashing.proposer_index, state, penalize=True, current_slot=state.slot)`.
#### Casper slashings
Verify that `len(block.body.casper_slashings) <= MAX_CASPER_SLASHINGS`.
For each `casper_slashing` in `block.body.casper_slashings`:
* Verify that `verify_special_attestation_data(casper_slashing.vote_1)`.
* Verify that `verify_special_attestation_data(casper_slashing.vote_2)`.
* Verify that `casper_slashing.vote_1.data != casper_slashing.vote_2.data`.
* Let `indices(vote) = vote.aggregate_signature_poc_0_indices + vote.aggregate_signature_poc_1_indices`.
* Let `intersection = [x for x in indices(casper_slashing.vote_1) if x in indices(casper_slashing.vote_2)]`.
* Verify that `len(intersection) >= 1`.
* Verify that `casper_slashing.vote_1.data.justified_slot + 1 < casper_slashing.vote_2.data.justified_slot + 1 == casper_slashing.vote_2.data.slot < casper_slashing.vote_1.data.slot` or `casper_slashing.vote_1.data.slot == casper_slashing.vote_2.data.slot`.
* For each [validator](#dfn-validator) index `i` in `intersection`, if `state.validator_registry[i].status` does not equal `EXITED_WITH_PENALTY`, then run `exit_validator(i, state, penalize=True, current_slot=state.slot)`
#### Attestations
Verify that `len(block.body.attestations) <= MAX_ATTESTATIONS`.
For each `attestation` in `block.body.attestations`: For each `attestation` in `block.body.attestations`:
@ -1254,75 +1308,14 @@ For each `attestation` in `block.body.attestations`:
* [TO BE REMOVED IN PHASE 1] Verify that `shard_block_hash == ZERO_HASH`. * [TO BE REMOVED IN PHASE 1] Verify that `shard_block_hash == ZERO_HASH`.
* Append `PendingAttestationRecord(data=attestation.data, participation_bitfield=attestation.participation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`. * Append `PendingAttestationRecord(data=attestation.data, participation_bitfield=attestation.participation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot)` to `state.latest_attestations`.
### RANDAO #### Deposits
* Let `repeat_hash(x, n) = x if n == 0 else repeat_hash(hash(x), n-1)`. Verify that `len(block.body.deposits) <= MAX_DEPOSITS`.
* Let `proposer = state.validator_registry[get_beacon_proposer_index(state, state.slot)]`.
* Verify that `repeat_hash(block.header.randao_reveal, proposer.randao_skips + 1) == proposer.randao_commitment`.
* Set `state.randao_mix = xor(state.randao_mix, block.header.randao_reveal)`.
* Set `proposer.randao_commitment = block.header.randao_reveal`.
* Set `proposer.randao_skips = 0`.
### PoW receipt root For each `deposit` in `block.body.deposits`:
* If `block.header.candidate_pow_receipt_root` is `x.candidate_pow_receipt_root` for some `x` in `state.candidate_pow_receipt_roots`, set `x.votes += 1`. * Let `serialized_deposit_data` be the serialized form of `deposit.deposit_data`. It should be the `DepositParametersRecord` followed by 8 bytes for `deposit_data.value` and 8 bytes for `deposit_data.timestamp`. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-chain-deposit-contract) of which the hash was placed into the Merkle tree.
* Otherwise, append to `state.candidate_pow_receipt_roots` a new `CandidatePoWReceiptRootRecord(candidate_pow_receipt_root=block.header.candidate_pow_receipt_root, votes=1)`. * Use the following procedure to verify `deposit.merkle_branch`, setting `leaf=serialized_deposit_data`, `depth=DEPOSIT_CONTRACT_TREE_DEPTH` and `root=state.processed_pow_receipt_root`:
### Special objects
* Verify that the quantity of each type of object in `block.body.specials` is less than or equal to its maximum (see table at the top).
* Verify that objects are sorted in order of `kind`. That is, `block.body.specials[i+1].kind >= block.body.specials[i].kind` for `0 <= i < len(block.body.specials-1)`.
For each `special` in `block.body.specials`:
* Verify that `special.kind` is a valid value.
* Verify that `special.data` deserializes according to the format for the given `kind` (see format definitions in "Data structures" above).
* Process `special.data` as specified below for each kind.
#### `VOLUNTARY_EXIT`
* Let `validator = state.validator_registry[validator_index]`.
* Verify that `BLSVerify(pubkey=validator.pubkey, msg=ZERO_HASH, sig=signature, domain=get_domain(state.fork_data, slot, DOMAIN_EXIT))`.
* Verify that `validator.status == ACTIVE`.
* Verify that `state.slot >= slot`.
* Verify that `state.slot >= validator.latest_status_change_slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD`.
* Run `exit_validator(validator_index, state, penalize=False, current_slot=state.slot)`.
#### `CASPER_SLASHING`
Let `verify_special_attestation_data` be the following helper:
```python
def verify_special_attestation_data(state: State, obj: SpecialAttestationData) -> bool:
pubs = [aggregate_pubkey([state.validators[i].pubkey for i in obj.aggregate_signature_poc_0_indices]),
aggregate_pubkey([state.validators[i].pubkey for i in obj.aggregate_signature_poc_1_indices])]
return BLSMultiVerify(pubkeys=pubs, msgs=[SSZTreeHash(obj)+bytes1(0), SSZTreeHash(obj)+bytes1(1), sig=aggregate_signature)
```
* Verify that `verify_special_attestation_data(vote_1)`.
* Verify that `verify_special_attestation_data(vote_2)`.
* Verify that `vote_1.data != vote_2.data`.
* Let `indices(vote) = vote.aggregate_signature_poc_0_indices + vote.aggregate_signature_poc_1_indices`.
* Let `intersection = [x for x in indices(vote_1) if x in indices(vote_2)]`.
* Verify that `len(intersection) >= 1`.
* Verify that `vote_1.data.justified_slot + 1 < vote_2.data.justified_slot + 1 == vote_2.data.slot < vote_1.data.slot` or `vote_1.data.slot == vote_2.data.slot`.
For each [validator](#dfn-validator) index `i` in `intersection`, if `state.validator_registry[i].status` does not equal `EXITED_WITH_PENALTY`, then run `exit_validator(i, state, penalize=True, current_slot=state.slot)`
#### `PROPOSER_SLASHING`
* Verify that `BLSVerify(pubkey=state.validator_registry[proposer_index].pubkey, msg=hash(proposal_data_1), sig=proposal_signature_1, domain=get_domain(state.fork_data, proposal_data_1.slot, DOMAIN_PROPOSAL))`.
* Verify that `BLSVerify(pubkey=state.validator_registry[proposer_index].pubkey, msg=hash(proposal_data_2), sig=proposal_signature_2, domain=get_domain(state.fork_data, proposal_data_2.slot, DOMAIN_PROPOSAL))`.
* Verify that `proposal_data_1 != proposal_data_2`.
* Verify that `proposal_data_1.slot == proposal_data_2.slot`.
* Verify that `state.validator_registry[proposer_index].status != EXITED_WITH_PENALTY`.
* Run `exit_validator(proposer_index, state, penalize=True, current_slot=state.slot)`.
#### `DEPOSIT_PROOF`
Let `serialized_deposit_data` be the serialized form of `deposit_data. It should be the `DepositParametersRecord` followed by 8 bytes for `deposit_data.value` and 8 bytes for `deposit_data.timestamp`. That is, it should match `deposit_data` in the [Ethereum 1.0 deposit contract](#ethereum-10-chain-deposit-contract) of which the hash was placed into the Merkle tree.
Use the following procedure to verify the `merkle_branch`, setting `leaf=serialized_deposit_data`, `depth=DEPOSIT_CONTRACT_TREE_DEPTH` and `root=state.processed_pow_receipt_root`:
```python ```python
def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int, root: Hash32) -> bool: def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int, root: Hash32) -> bool:
@ -1335,22 +1328,35 @@ def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int,
return value == root return value == root
``` ```
* Verify that `state.slot - (deposit_data.timestamp - state.genesis_time) // SLOT_DURATION < ZERO_BALANCE_VALIDATOR_TTL`. * Verify that `state.slot - (deposit.deposit_data.timestamp - state.genesis_time) // SLOT_DURATION < ZERO_BALANCE_VALIDATOR_TTL`.
* Run the following: * Run the following:
```python ```python
process_deposit( process_deposit(
state=state, state=state,
pubkey=deposit_data.deposit_parameters.pubkey, pubkey=deposit.deposit_data.deposit_parameters.pubkey,
deposit=deposit_data.value, deposit=deposit.deposit_data.value,
proof_of_possession=deposit_data.deposit_parameters.proof_of_possession, proof_of_possession=deposit.deposit_data.deposit_parameters.proof_of_possession,
withdrawal_credentials=deposit_data.deposit_parameters.withdrawal_credentials, withdrawal_credentials=deposit.deposit_data.deposit_parameters.withdrawal_credentials,
randao_commitment=deposit_data.deposit_parameters.randao_commitment, randao_commitment=deposit.deposit_data.deposit_parameters.randao_commitment,
status=PENDING_ACTIVATION, status=PENDING_ACTIVATION,
current_slot=state.slot current_slot=state.slot
) )
``` ```
#### Exits
Verify that `len(block.body.exits) <= MAX_EXITS`.
For each `exit` in `block.body.exits`:
* Let `validator = state.validator_registry[exit.validator_index]`.
* Verify that `BLSVerify(pubkey=validator.pubkey, msg=ZERO_HASH, sig=exit.signature, domain=get_domain(state.fork_data, exit.slot, DOMAIN_EXIT))`.
* Verify that `validator.status == ACTIVE`.
* Verify that `state.slot >= exit.slot`.
* Verify that `state.slot >= validator.latest_status_change_slot + SHARD_PERSISTENT_COMMITTEE_CHANGE_PERIOD`.
* Run `exit_validator(validator_index, state, penalize=False, current_slot=state.slot)`.
## 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`.