Merge remote-tracking branch 'upstream/deposit-queue' into deposit-queue
This commit is contained in:
commit
093590ee11
|
@ -22,6 +22,7 @@
|
||||||
- [`_fft_field`](#_fft_field)
|
- [`_fft_field`](#_fft_field)
|
||||||
- [`fft_field`](#fft_field)
|
- [`fft_field`](#fft_field)
|
||||||
- [`coset_fft_field`](#coset_fft_field)
|
- [`coset_fft_field`](#coset_fft_field)
|
||||||
|
- [`compute_verify_cell_kzg_proof_batch_challenge`](#compute_verify_cell_kzg_proof_batch_challenge)
|
||||||
- [Polynomials in coefficient form](#polynomials-in-coefficient-form)
|
- [Polynomials in coefficient form](#polynomials-in-coefficient-form)
|
||||||
- [`polynomial_eval_to_coeff`](#polynomial_eval_to_coeff)
|
- [`polynomial_eval_to_coeff`](#polynomial_eval_to_coeff)
|
||||||
- [`add_polynomialcoeff`](#add_polynomialcoeff)
|
- [`add_polynomialcoeff`](#add_polynomialcoeff)
|
||||||
|
@ -34,7 +35,9 @@
|
||||||
- [KZG multiproofs](#kzg-multiproofs)
|
- [KZG multiproofs](#kzg-multiproofs)
|
||||||
- [`compute_kzg_proof_multi_impl`](#compute_kzg_proof_multi_impl)
|
- [`compute_kzg_proof_multi_impl`](#compute_kzg_proof_multi_impl)
|
||||||
- [`verify_kzg_proof_multi_impl`](#verify_kzg_proof_multi_impl)
|
- [`verify_kzg_proof_multi_impl`](#verify_kzg_proof_multi_impl)
|
||||||
|
- [`verify_cell_kzg_proof_batch_impl`](#verify_cell_kzg_proof_batch_impl)
|
||||||
- [Cell cosets](#cell-cosets)
|
- [Cell cosets](#cell-cosets)
|
||||||
|
- [`coset_shift_for_cell`](#coset_shift_for_cell)
|
||||||
- [`coset_for_cell`](#coset_for_cell)
|
- [`coset_for_cell`](#coset_for_cell)
|
||||||
- [Cells](#cells-1)
|
- [Cells](#cells-1)
|
||||||
- [Cell computation](#cell-computation)
|
- [Cell computation](#cell-computation)
|
||||||
|
@ -222,6 +225,52 @@ def coset_fft_field(vals: Sequence[BLSFieldElement],
|
||||||
return fft_field(vals, roots_of_unity, inv)
|
return fft_field(vals, roots_of_unity, inv)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `compute_verify_cell_kzg_proof_batch_challenge`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def compute_verify_cell_kzg_proof_batch_challenge(row_commitments: Sequence[KZGCommitment],
|
||||||
|
row_indices: Sequence[RowIndex],
|
||||||
|
column_indices: Sequence[ColumnIndex],
|
||||||
|
cosets_evals: Sequence[CosetEvals],
|
||||||
|
proofs: Sequence[KZGProof]) -> BLSFieldElement:
|
||||||
|
"""
|
||||||
|
Compute a random challenge r used in the universal verification equation.
|
||||||
|
This is used in verify_cell_kzg_proof_batch_impl.
|
||||||
|
|
||||||
|
To compute the challenge, `RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN` is used as a hash prefix.
|
||||||
|
"""
|
||||||
|
# input the domain separator
|
||||||
|
hashinput = RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN
|
||||||
|
|
||||||
|
# input the degree bound of the polynomial
|
||||||
|
hashinput += int.to_bytes(FIELD_ELEMENTS_PER_BLOB, 8, KZG_ENDIANNESS)
|
||||||
|
|
||||||
|
# input the field elements per cell
|
||||||
|
hashinput += int.to_bytes(FIELD_ELEMENTS_PER_CELL, 8, KZG_ENDIANNESS)
|
||||||
|
|
||||||
|
# input the number of commitments
|
||||||
|
num_commitments = len(row_commitments)
|
||||||
|
hashinput += int.to_bytes(num_commitments, 8, KZG_ENDIANNESS)
|
||||||
|
|
||||||
|
# input the number of cells
|
||||||
|
num_cells = len(row_indices)
|
||||||
|
hashinput += int.to_bytes(num_cells, 8, KZG_ENDIANNESS)
|
||||||
|
|
||||||
|
# input all commitments
|
||||||
|
for commitment in row_commitments:
|
||||||
|
hashinput += commitment
|
||||||
|
|
||||||
|
# input each cell with its indices and proof
|
||||||
|
for k in range(num_cells):
|
||||||
|
hashinput += int.to_bytes(row_indices[k], 8, KZG_ENDIANNESS)
|
||||||
|
hashinput += int.to_bytes(column_indices[k], 8, KZG_ENDIANNESS)
|
||||||
|
for eval in cosets_evals[k]:
|
||||||
|
hashinput += bls_field_to_bytes(eval)
|
||||||
|
hashinput += proofs[k]
|
||||||
|
|
||||||
|
return hash_to_bls_field(hashinput)
|
||||||
|
```
|
||||||
|
|
||||||
### Polynomials in coefficient form
|
### Polynomials in coefficient form
|
||||||
|
|
||||||
#### `polynomial_eval_to_coeff`
|
#### `polynomial_eval_to_coeff`
|
||||||
|
@ -423,14 +472,132 @@ def verify_kzg_proof_multi_impl(commitment: KZGCommitment,
|
||||||
]))
|
]))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### `verify_cell_kzg_proof_batch_impl`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def verify_cell_kzg_proof_batch_impl(row_commitments: Sequence[KZGCommitment],
|
||||||
|
row_indices: Sequence[RowIndex],
|
||||||
|
column_indices: Sequence[ColumnIndex],
|
||||||
|
cosets_evals: Sequence[CosetEvals],
|
||||||
|
proofs: Sequence[KZGProof]) -> bool:
|
||||||
|
"""
|
||||||
|
Verify a set of cells, given their corresponding proofs and their coordinates (row_index, column_index) in the blob
|
||||||
|
matrix. The i-th cell is in row row_indices[i] and in column column_indices[i].
|
||||||
|
The list of all commitments is provided in row_commitments_bytes.
|
||||||
|
|
||||||
|
This function is the internal implementation of verify_cell_kzg_proof_batch.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The verification equation that we will check is pairing (LL, LR) = pairing (RL, [1]), where
|
||||||
|
# LL = sum_k r^k proofs[k],
|
||||||
|
# LR = [s^n]
|
||||||
|
# RL = RLC - RLI + RLP, where
|
||||||
|
# RLC = sum_i weights[i] commitments[i]
|
||||||
|
# RLI = [sum_k r^k interpolation_poly_k(s)]
|
||||||
|
# RLP = sum_k (r^k * h_k^n) proofs[k]
|
||||||
|
#
|
||||||
|
# Here, the variables have the following meaning:
|
||||||
|
# - k < len(row_indices) is an index iterating over all cells in the input
|
||||||
|
# - r is a random coefficient, derived from hashing all data provided by the prover
|
||||||
|
# - s is the secret embedded in the KZG setup
|
||||||
|
# - n = FIELD_ELEMENTS_PER_CELL is the size of the evaluation domain
|
||||||
|
# - i ranges over all rows that are touched
|
||||||
|
# - weights[i] is a weight computed for row i. It depends on r and on which cells are in row i
|
||||||
|
# - interpolation_poly_k is the interpolation polynomial for the kth cell
|
||||||
|
# - h_k is the coset shift specifying the evaluation domain of the kth cell
|
||||||
|
|
||||||
|
# Preparation
|
||||||
|
num_cells = len(row_indices)
|
||||||
|
n = FIELD_ELEMENTS_PER_CELL
|
||||||
|
num_rows = len(row_commitments)
|
||||||
|
|
||||||
|
# Step 1: Compute a challenge r and its powers r^0, ..., r^{num_cells-1}
|
||||||
|
r = compute_verify_cell_kzg_proof_batch_challenge(
|
||||||
|
row_commitments,
|
||||||
|
row_indices,
|
||||||
|
column_indices,
|
||||||
|
cosets_evals,
|
||||||
|
proofs
|
||||||
|
)
|
||||||
|
r_powers = compute_powers(r, num_cells)
|
||||||
|
|
||||||
|
# Step 2: Compute LL = sum_k r^k proofs[k]
|
||||||
|
ll = bls.bytes48_to_G1(g1_lincomb(proofs, r_powers))
|
||||||
|
|
||||||
|
# Step 3: Compute LR = [s^n]
|
||||||
|
lr = bls.bytes96_to_G2(KZG_SETUP_G2_MONOMIAL[n])
|
||||||
|
|
||||||
|
# Step 4: Compute RL = RLC - RLI + RLP
|
||||||
|
# Step 4.1: Compute RLC = sum_i weights[i] commitments[i]
|
||||||
|
# Step 4.1a: Compute weights[i]: the sum of all r^k for which cell k is in row i.
|
||||||
|
# Note: we do that by iterating over all k and updating the correct weights[i] accordingly
|
||||||
|
weights = [0] * num_rows
|
||||||
|
for k in range(num_cells):
|
||||||
|
i = row_indices[k]
|
||||||
|
weights[i] = (weights[i] + int(r_powers[k])) % BLS_MODULUS
|
||||||
|
# Step 4.1b: Linearly combine the weights with the commitments to get RLC
|
||||||
|
rlc = bls.bytes48_to_G1(g1_lincomb(row_commitments, weights))
|
||||||
|
|
||||||
|
# Step 4.2: Compute RLI = [sum_k r^k interpolation_poly_k(s)]
|
||||||
|
# Note: an efficient implementation would use the IDFT based method explained in the blog post
|
||||||
|
sum_interp_polys_coeff = [0]
|
||||||
|
for k in range(num_cells):
|
||||||
|
interp_poly_coeff = interpolate_polynomialcoeff(coset_for_cell(column_indices[k]), cosets_evals[k])
|
||||||
|
interp_poly_scaled_coeff = multiply_polynomialcoeff([r_powers[k]], interp_poly_coeff)
|
||||||
|
sum_interp_polys_coeff = add_polynomialcoeff(sum_interp_polys_coeff, interp_poly_scaled_coeff)
|
||||||
|
rli = bls.bytes48_to_G1(g1_lincomb(KZG_SETUP_G1_MONOMIAL[:n], sum_interp_polys_coeff))
|
||||||
|
|
||||||
|
# Step 4.3: Compute RLP = sum_k (r^k * h_k^n) proofs[k]
|
||||||
|
weighted_r_powers = []
|
||||||
|
for k in range(num_cells):
|
||||||
|
h_k = int(coset_shift_for_cell(column_indices[k]))
|
||||||
|
h_k_pow = pow(h_k, n, BLS_MODULUS)
|
||||||
|
wrp = (int(r_powers[k]) * h_k_pow) % BLS_MODULUS
|
||||||
|
weighted_r_powers.append(wrp)
|
||||||
|
rlp = bls.bytes48_to_G1(g1_lincomb(proofs, weighted_r_powers))
|
||||||
|
|
||||||
|
# Step 4.4: Compute RL = RLC - RLI + RLP
|
||||||
|
rl = bls.add(rlc, bls.neg(rli))
|
||||||
|
rl = bls.add(rl, rlp)
|
||||||
|
|
||||||
|
# Step 5: Check pairing (LL, LR) = pairing (RL, [1])
|
||||||
|
return (bls.pairing_check([
|
||||||
|
[ll, lr],
|
||||||
|
[rl, bls.neg(bls.bytes96_to_G2(KZG_SETUP_G2_MONOMIAL[0]))],
|
||||||
|
]))
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Cell cosets
|
### Cell cosets
|
||||||
|
|
||||||
|
#### `coset_shift_for_cell`
|
||||||
|
|
||||||
|
```python
|
||||||
|
def coset_shift_for_cell(cell_index: CellIndex) -> BLSFieldElement:
|
||||||
|
"""
|
||||||
|
Get the shift that determines the coset for a given ``cell_index``.
|
||||||
|
Precisely, consider the group of roots of unity of order FIELD_ELEMENTS_PER_CELL * CELLS_PER_EXT_BLOB.
|
||||||
|
Let G = {1, g, g^2, ...} denote its subgroup of order FIELD_ELEMENTS_PER_CELL.
|
||||||
|
Then, the coset is defined as h * G = {h, hg, hg^2, ...} for an element h.
|
||||||
|
This function returns h.
|
||||||
|
"""
|
||||||
|
assert cell_index < CELLS_PER_EXT_BLOB
|
||||||
|
roots_of_unity_brp = bit_reversal_permutation(
|
||||||
|
compute_roots_of_unity(FIELD_ELEMENTS_PER_EXT_BLOB)
|
||||||
|
)
|
||||||
|
return roots_of_unity_brp[FIELD_ELEMENTS_PER_CELL * cell_index]
|
||||||
|
```
|
||||||
|
|
||||||
#### `coset_for_cell`
|
#### `coset_for_cell`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def coset_for_cell(cell_index: CellIndex) -> Coset:
|
def coset_for_cell(cell_index: CellIndex) -> Coset:
|
||||||
"""
|
"""
|
||||||
Get the coset for a given ``cell_index``.
|
Get the coset for a given ``cell_index``.
|
||||||
|
Precisely, consider the group of roots of unity of order FIELD_ELEMENTS_PER_CELL * CELLS_PER_EXT_BLOB.
|
||||||
|
Let G = {1, g, g^2, ...} denote its subgroup of order FIELD_ELEMENTS_PER_CELL.
|
||||||
|
Then, the coset is defined as h * G = {h, hg, hg^2, ...}.
|
||||||
|
This function, returns the coset.
|
||||||
"""
|
"""
|
||||||
assert cell_index < CELLS_PER_EXT_BLOB
|
assert cell_index < CELLS_PER_EXT_BLOB
|
||||||
roots_of_unity_brp = bit_reversal_permutation(
|
roots_of_unity_brp = bit_reversal_permutation(
|
||||||
|
@ -511,18 +678,15 @@ def verify_cell_kzg_proof_batch(row_commitments_bytes: Sequence[Bytes48],
|
||||||
proofs_bytes: Sequence[Bytes48]) -> bool:
|
proofs_bytes: Sequence[Bytes48]) -> bool:
|
||||||
"""
|
"""
|
||||||
Verify a set of cells, given their corresponding proofs and their coordinates (row_index, column_index) in the blob
|
Verify a set of cells, given their corresponding proofs and their coordinates (row_index, column_index) in the blob
|
||||||
matrix. The list of all commitments is also provided in row_commitments_bytes.
|
matrix. The i-th cell is in row = row_indices[i] and in column = column_indices[i].
|
||||||
|
The list of all commitments is provided in row_commitments_bytes.
|
||||||
|
|
||||||
This function implements the naive algorithm of checking every cell
|
This function implements the universal verification equation that has been introduced here:
|
||||||
individually; an efficient algorithm can be found here:
|
|
||||||
https://ethresear.ch/t/a-universal-verification-equation-for-data-availability-sampling/13240
|
https://ethresear.ch/t/a-universal-verification-equation-for-data-availability-sampling/13240
|
||||||
|
|
||||||
This implementation does not require randomness, but for the algorithm that
|
|
||||||
requires it, `RANDOM_CHALLENGE_KZG_CELL_BATCH_DOMAIN` should be used to compute
|
|
||||||
the challenge value.
|
|
||||||
|
|
||||||
Public method.
|
Public method.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
assert len(cells) == len(proofs_bytes) == len(row_indices) == len(column_indices)
|
assert len(cells) == len(proofs_bytes) == len(row_indices) == len(column_indices)
|
||||||
for commitment_bytes in row_commitments_bytes:
|
for commitment_bytes in row_commitments_bytes:
|
||||||
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
|
assert len(commitment_bytes) == BYTES_PER_COMMITMENT
|
||||||
|
@ -535,18 +699,13 @@ def verify_cell_kzg_proof_batch(row_commitments_bytes: Sequence[Bytes48],
|
||||||
for proof_bytes in proofs_bytes:
|
for proof_bytes in proofs_bytes:
|
||||||
assert len(proof_bytes) == BYTES_PER_PROOF
|
assert len(proof_bytes) == BYTES_PER_PROOF
|
||||||
|
|
||||||
# Get commitments via row indices
|
|
||||||
commitments_bytes = [row_commitments_bytes[row_index] for row_index in row_indices]
|
|
||||||
|
|
||||||
# Get objects from bytes
|
# Get objects from bytes
|
||||||
commitments = [bytes_to_kzg_commitment(commitment_bytes) for commitment_bytes in commitments_bytes]
|
row_commitments = [bytes_to_kzg_commitment(commitment_bytes) for commitment_bytes in row_commitments_bytes]
|
||||||
cosets_evals = [cell_to_coset_evals(cell) for cell in cells]
|
cosets_evals = [cell_to_coset_evals(cell) for cell in cells]
|
||||||
proofs = [bytes_to_kzg_proof(proof_bytes) for proof_bytes in proofs_bytes]
|
proofs = [bytes_to_kzg_proof(proof_bytes) for proof_bytes in proofs_bytes]
|
||||||
|
|
||||||
return all(
|
# Do the actual verification
|
||||||
verify_kzg_proof_multi_impl(commitment, coset_for_cell(column_index), coset_evals, proof)
|
return verify_cell_kzg_proof_batch_impl(row_commitments, row_indices, column_indices, cosets_evals, proofs)
|
||||||
for commitment, column_index, coset_evals, proof in zip(commitments, column_indices, cosets_evals, proofs)
|
|
||||||
)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Reconstruction
|
## Reconstruction
|
||||||
|
|
|
@ -44,16 +44,16 @@
|
||||||
- [`BeaconState`](#beaconstate)
|
- [`BeaconState`](#beaconstate)
|
||||||
- [Helper functions](#helper-functions)
|
- [Helper functions](#helper-functions)
|
||||||
- [Predicates](#predicates)
|
- [Predicates](#predicates)
|
||||||
- [Updated `compute_proposer_index`](#updated-compute_proposer_index)
|
- [Modified `compute_proposer_index`](#modified-compute_proposer_index)
|
||||||
- [Updated `is_eligible_for_activation_queue`](#updated-is_eligible_for_activation_queue)
|
- [Modified `is_eligible_for_activation_queue`](#modified-is_eligible_for_activation_queue)
|
||||||
- [New `is_compounding_withdrawal_credential`](#new-is_compounding_withdrawal_credential)
|
- [New `is_compounding_withdrawal_credential`](#new-is_compounding_withdrawal_credential)
|
||||||
- [New `has_compounding_withdrawal_credential`](#new-has_compounding_withdrawal_credential)
|
- [New `has_compounding_withdrawal_credential`](#new-has_compounding_withdrawal_credential)
|
||||||
- [New `has_execution_withdrawal_credential`](#new-has_execution_withdrawal_credential)
|
- [New `has_execution_withdrawal_credential`](#new-has_execution_withdrawal_credential)
|
||||||
- [Updated `is_fully_withdrawable_validator`](#updated-is_fully_withdrawable_validator)
|
- [Modified `is_fully_withdrawable_validator`](#modified-is_fully_withdrawable_validator)
|
||||||
- [Updated `is_partially_withdrawable_validator`](#updated-is_partially_withdrawable_validator)
|
- [Modified `is_partially_withdrawable_validator`](#modified-is_partially_withdrawable_validator)
|
||||||
- [Misc](#misc-1)
|
- [Misc](#misc-1)
|
||||||
- [`get_committee_indices`](#get_committee_indices)
|
- [New `get_committee_indices`](#new-get_committee_indices)
|
||||||
- [`get_validator_max_effective_balance`](#get_validator_max_effective_balance)
|
- [New `get_validator_max_effective_balance`](#new-get_validator_max_effective_balance)
|
||||||
- [Beacon state accessors](#beacon-state-accessors)
|
- [Beacon state accessors](#beacon-state-accessors)
|
||||||
- [New `get_balance_churn_limit`](#new-get_balance_churn_limit)
|
- [New `get_balance_churn_limit`](#new-get_balance_churn_limit)
|
||||||
- [New `get_activation_exit_churn_limit`](#new-get_activation_exit_churn_limit)
|
- [New `get_activation_exit_churn_limit`](#new-get_activation_exit_churn_limit)
|
||||||
|
@ -61,28 +61,27 @@
|
||||||
- [New `get_active_balance`](#new-get_active_balance)
|
- [New `get_active_balance`](#new-get_active_balance)
|
||||||
- [New `get_pending_balance_to_withdraw`](#new-get_pending_balance_to_withdraw)
|
- [New `get_pending_balance_to_withdraw`](#new-get_pending_balance_to_withdraw)
|
||||||
- [Modified `get_attesting_indices`](#modified-get_attesting_indices)
|
- [Modified `get_attesting_indices`](#modified-get_attesting_indices)
|
||||||
- [New `get_activation_churn_consumption`](#new-get_activation_churn_consumption)
|
|
||||||
- [Modified `get_next_sync_committee_indices`](#modified-get_next_sync_committee_indices)
|
- [Modified `get_next_sync_committee_indices`](#modified-get_next_sync_committee_indices)
|
||||||
- [Beacon state mutators](#beacon-state-mutators)
|
- [Beacon state mutators](#beacon-state-mutators)
|
||||||
- [Updated `initiate_validator_exit`](#updated--initiate_validator_exit)
|
- [Modified `initiate_validator_exit`](#modified-initiate_validator_exit)
|
||||||
- [New `switch_to_compounding_validator`](#new-switch_to_compounding_validator)
|
- [New `switch_to_compounding_validator`](#new-switch_to_compounding_validator)
|
||||||
- [New `queue_excess_active_balance`](#new-queue_excess_active_balance)
|
- [New `queue_excess_active_balance`](#new-queue_excess_active_balance)
|
||||||
- [New `queue_entire_balance_and_reset_validator`](#new-queue_entire_balance_and_reset_validator)
|
- [New `queue_entire_balance_and_reset_validator`](#new-queue_entire_balance_and_reset_validator)
|
||||||
- [New `compute_exit_epoch_and_update_churn`](#new-compute_exit_epoch_and_update_churn)
|
- [New `compute_exit_epoch_and_update_churn`](#new-compute_exit_epoch_and_update_churn)
|
||||||
- [New `compute_consolidation_epoch_and_update_churn`](#new-compute_consolidation_epoch_and_update_churn)
|
- [New `compute_consolidation_epoch_and_update_churn`](#new-compute_consolidation_epoch_and_update_churn)
|
||||||
- [Updated `slash_validator`](#updated-slash_validator)
|
- [Modified `slash_validator`](#modified-slash_validator)
|
||||||
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
||||||
- [Epoch processing](#epoch-processing)
|
- [Epoch processing](#epoch-processing)
|
||||||
- [Updated `process_epoch`](#updated-process_epoch)
|
- [Modified `process_epoch`](#modified-process_epoch)
|
||||||
- [Updated `process_registry_updates`](#updated--process_registry_updates)
|
- [Modified `process_registry_updates`](#modified-process_registry_updates)
|
||||||
- [New `apply_pending_deposit`](#new-apply_pending_deposit)
|
- [New `apply_pending_deposit`](#new-apply_pending_deposit)
|
||||||
- [New `process_pending_deposits`](#new-process_pending_deposits)
|
- [New `process_pending_deposits`](#new-process_pending_deposits)
|
||||||
- [New `process_pending_consolidations`](#new-process_pending_consolidations)
|
- [New `process_pending_consolidations`](#new-process_pending_consolidations)
|
||||||
- [Updated `process_effective_balance_updates`](#updated-process_effective_balance_updates)
|
- [Modified `process_effective_balance_updates`](#modified-process_effective_balance_updates)
|
||||||
- [Block processing](#block-processing)
|
- [Block processing](#block-processing)
|
||||||
- [Withdrawals](#withdrawals)
|
- [Withdrawals](#withdrawals)
|
||||||
- [Updated `get_expected_withdrawals`](#updated-get_expected_withdrawals)
|
- [Modified `get_expected_withdrawals`](#modified-get_expected_withdrawals)
|
||||||
- [Updated `process_withdrawals`](#updated-process_withdrawals)
|
- [Modified `process_withdrawals`](#modified-process_withdrawals)
|
||||||
- [Execution payload](#execution-payload)
|
- [Execution payload](#execution-payload)
|
||||||
- [Modified `process_execution_payload`](#modified-process_execution_payload)
|
- [Modified `process_execution_payload`](#modified-process_execution_payload)
|
||||||
- [Operations](#operations)
|
- [Operations](#operations)
|
||||||
|
@ -90,10 +89,10 @@
|
||||||
- [Attestations](#attestations)
|
- [Attestations](#attestations)
|
||||||
- [Modified `process_attestation`](#modified-process_attestation)
|
- [Modified `process_attestation`](#modified-process_attestation)
|
||||||
- [Deposits](#deposits)
|
- [Deposits](#deposits)
|
||||||
- [Updated `apply_deposit`](#updated--apply_deposit)
|
- [Modified `apply_deposit`](#modified-apply_deposit)
|
||||||
- [New `is_valid_deposit_signature`](#new-is_valid_deposit_signature)
|
- [New `is_valid_deposit_signature`](#new-is_valid_deposit_signature)
|
||||||
- [Voluntary exits](#voluntary-exits)
|
- [Voluntary exits](#voluntary-exits)
|
||||||
- [Updated `process_voluntary_exit`](#updated-process_voluntary_exit)
|
- [Modified `process_voluntary_exit`](#modified-process_voluntary_exit)
|
||||||
- [Execution layer withdrawal requests](#execution-layer-withdrawal-requests)
|
- [Execution layer withdrawal requests](#execution-layer-withdrawal-requests)
|
||||||
- [New `process_withdrawal_request`](#new-process_withdrawal_request)
|
- [New `process_withdrawal_request`](#new-process_withdrawal_request)
|
||||||
- [Deposit requests](#deposit-requests)
|
- [Deposit requests](#deposit-requests)
|
||||||
|
@ -113,7 +112,7 @@ Electra is a consensus-layer upgrade containing a number of features. Including:
|
||||||
* [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): Increase the MAX_EFFECTIVE_BALANCE
|
* [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): Increase the MAX_EFFECTIVE_BALANCE
|
||||||
* [EIP-7549](https://eips.ethereum.org/EIPS/eip-7549): Move committee index outside Attestation
|
* [EIP-7549](https://eips.ethereum.org/EIPS/eip-7549): Move committee index outside Attestation
|
||||||
|
|
||||||
*Note:* This specification is built upon [Deneb](../../deneb/beacon_chain.md) and is under active development.
|
*Note:* This specification is built upon [Deneb](../deneb/beacon_chain.md) and is under active development.
|
||||||
|
|
||||||
## Constants
|
## Constants
|
||||||
|
|
||||||
|
@ -440,9 +439,9 @@ class BeaconState(Container):
|
||||||
|
|
||||||
### Predicates
|
### Predicates
|
||||||
|
|
||||||
#### Updated `compute_proposer_index`
|
#### Modified `compute_proposer_index`
|
||||||
|
|
||||||
*Note*: The function is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA` preset.
|
*Note*: The function `compute_proposer_index` is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32) -> ValidatorIndex:
|
def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex], seed: Bytes32) -> ValidatorIndex:
|
||||||
|
@ -463,7 +462,9 @@ def compute_proposer_index(state: BeaconState, indices: Sequence[ValidatorIndex]
|
||||||
i += 1
|
i += 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Updated `is_eligible_for_activation_queue`
|
#### Modified `is_eligible_for_activation_queue`
|
||||||
|
|
||||||
|
*Note*: The function `is_eligible_for_activation_queue` is modified to use `MIN_ACTIVATION_BALANCE` instead of `MAX_EFFECTIVE_BALANCE`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def is_eligible_for_activation_queue(validator: Validator) -> bool:
|
def is_eligible_for_activation_queue(validator: Validator) -> bool:
|
||||||
|
@ -503,7 +504,9 @@ def has_execution_withdrawal_credential(validator: Validator) -> bool:
|
||||||
return has_compounding_withdrawal_credential(validator) or has_eth1_withdrawal_credential(validator)
|
return has_compounding_withdrawal_credential(validator) or has_eth1_withdrawal_credential(validator)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Updated `is_fully_withdrawable_validator`
|
#### Modified `is_fully_withdrawable_validator`
|
||||||
|
|
||||||
|
*Note*: The function `is_fully_withdrawable_validator` is modified to use `has_execution_withdrawal_credential` instead of `has_eth1_withdrawal_credential`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def is_fully_withdrawable_validator(validator: Validator, balance: Gwei, epoch: Epoch) -> bool:
|
def is_fully_withdrawable_validator(validator: Validator, balance: Gwei, epoch: Epoch) -> bool:
|
||||||
|
@ -517,7 +520,9 @@ def is_fully_withdrawable_validator(validator: Validator, balance: Gwei, epoch:
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Updated `is_partially_withdrawable_validator`
|
#### Modified `is_partially_withdrawable_validator`
|
||||||
|
|
||||||
|
*Note*: The function `is_partially_withdrawable_validator` is modified to use `get_validator_max_effective_balance` instead of `MAX_EFFECTIVE_BALANCE` and `has_execution_withdrawal_credential` instead of `has_eth1_withdrawal_credential`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> bool:
|
def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) -> bool:
|
||||||
|
@ -536,14 +541,14 @@ def is_partially_withdrawable_validator(validator: Validator, balance: Gwei) ->
|
||||||
|
|
||||||
### Misc
|
### Misc
|
||||||
|
|
||||||
#### `get_committee_indices`
|
#### New `get_committee_indices`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]:
|
def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]:
|
||||||
return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit]
|
return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `get_validator_max_effective_balance`
|
#### New `get_validator_max_effective_balance`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_validator_max_effective_balance(validator: Validator) -> Gwei:
|
def get_validator_max_effective_balance(validator: Validator) -> Gwei:
|
||||||
|
@ -608,6 +613,8 @@ def get_pending_balance_to_withdraw(state: BeaconState, validator_index: Validat
|
||||||
|
|
||||||
#### Modified `get_attesting_indices`
|
#### Modified `get_attesting_indices`
|
||||||
|
|
||||||
|
*Note*: The function `get_attesting_indices` is modified to support EIP7549.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
|
def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[ValidatorIndex]:
|
||||||
"""
|
"""
|
||||||
|
@ -627,30 +634,9 @@ def get_attesting_indices(state: BeaconState, attestation: Attestation) -> Set[V
|
||||||
return output
|
return output
|
||||||
```
|
```
|
||||||
|
|
||||||
#### New `get_activation_churn_consumption`
|
|
||||||
|
|
||||||
```python
|
|
||||||
def get_activation_churn_consumption(state: BeaconState, deposit: PendingDeposit) -> Gwei:
|
|
||||||
"""
|
|
||||||
Return amount of activation churn consumed by the ``deposit``.
|
|
||||||
"""
|
|
||||||
validator_pubkeys = [v.pubkey for v in state.validators]
|
|
||||||
|
|
||||||
if deposit.pubkey not in validator_pubkeys:
|
|
||||||
return deposit.amount
|
|
||||||
else:
|
|
||||||
validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
|
|
||||||
validator = state.validators[validator_index]
|
|
||||||
# Validator is exiting, do not consume the churn
|
|
||||||
if validator.exit_epoch < FAR_FUTURE_EPOCH:
|
|
||||||
return Gwei(0)
|
|
||||||
else:
|
|
||||||
return deposit.amount
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Modified `get_next_sync_committee_indices`
|
#### Modified `get_next_sync_committee_indices`
|
||||||
|
|
||||||
*Note*: The function is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA` preset.
|
*Note*: The function `get_next_sync_committee_indices` is modified to use `MAX_EFFECTIVE_BALANCE_ELECTRA`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]:
|
def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorIndex]:
|
||||||
|
@ -679,7 +665,9 @@ def get_next_sync_committee_indices(state: BeaconState) -> Sequence[ValidatorInd
|
||||||
|
|
||||||
### Beacon state mutators
|
### Beacon state mutators
|
||||||
|
|
||||||
#### Updated `initiate_validator_exit`
|
#### Modified `initiate_validator_exit`
|
||||||
|
|
||||||
|
*Note*: The function `initiate_validator_exit` is modified to use the new `compute_exit_epoch_and_update_churn` function.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
def initiate_validator_exit(state: BeaconState, index: ValidatorIndex) -> None:
|
||||||
|
@ -728,6 +716,7 @@ def queue_excess_active_balance(state: BeaconState, index: ValidatorIndex) -> No
|
||||||
```
|
```
|
||||||
|
|
||||||
#### New `queue_entire_balance_and_reset_validator`
|
#### New `queue_entire_balance_and_reset_validator`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None:
|
def queue_entire_balance_and_reset_validator(state: BeaconState, index: ValidatorIndex) -> None:
|
||||||
balance = state.balances[index]
|
balance = state.balances[index]
|
||||||
|
@ -797,7 +786,9 @@ def compute_consolidation_epoch_and_update_churn(state: BeaconState, consolidati
|
||||||
return state.earliest_consolidation_epoch
|
return state.earliest_consolidation_epoch
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Updated `slash_validator`
|
#### Modified `slash_validator`
|
||||||
|
|
||||||
|
*Note*: The function `slash_validator` is modified to change how the slashing penalty and proposer/whistleblower rewards are calculated in accordance with EIP7251.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def slash_validator(state: BeaconState,
|
def slash_validator(state: BeaconState,
|
||||||
|
@ -831,7 +822,10 @@ def slash_validator(state: BeaconState,
|
||||||
|
|
||||||
### Epoch processing
|
### Epoch processing
|
||||||
|
|
||||||
#### Updated `process_epoch`
|
#### Modified `process_epoch`
|
||||||
|
|
||||||
|
*Note*: The function `process_epoch` is modified to call updated functions and to process pending balance deposits and pending consolidations which are new in Electra.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_epoch(state: BeaconState) -> None:
|
def process_epoch(state: BeaconState) -> None:
|
||||||
process_justification_and_finalization(state)
|
process_justification_and_finalization(state)
|
||||||
|
@ -850,9 +844,9 @@ def process_epoch(state: BeaconState) -> None:
|
||||||
process_sync_committee_updates(state)
|
process_sync_committee_updates(state)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Updated `process_registry_updates`
|
#### Modified `process_registry_updates`
|
||||||
|
|
||||||
`process_registry_updates` uses the updated definition of `initiate_validator_exit`
|
*Note*: The function `process_registry_updates` is modified to use the updated definition of `initiate_validator_exit`
|
||||||
and changes how the activation epochs are computed for eligible validators.
|
and changes how the activation epochs are computed for eligible validators.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
@ -878,11 +872,9 @@ def process_registry_updates(state: BeaconState) -> None:
|
||||||
#### New `apply_pending_deposit`
|
#### New `apply_pending_deposit`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def apply_pending_deposit(state: BeaconState, deposit: PendingDeposit) -> bool:
|
def apply_pending_deposit(state: BeaconState, deposit: PendingDeposit) -> None:
|
||||||
"""
|
"""
|
||||||
Applies ``deposit`` to the ``state``.
|
Applies ``deposit`` to the ``state``.
|
||||||
Returns ``True`` if ``deposit`` has been successfully applied
|
|
||||||
and can be removed from the queue.
|
|
||||||
"""
|
"""
|
||||||
validator_pubkeys = [v.pubkey for v in state.validators]
|
validator_pubkeys = [v.pubkey for v in state.validators]
|
||||||
if deposit.pubkey not in validator_pubkeys:
|
if deposit.pubkey not in validator_pubkeys:
|
||||||
|
@ -896,32 +888,22 @@ def apply_pending_deposit(state: BeaconState, deposit: PendingDeposit) -> bool:
|
||||||
add_validator_to_registry(state, deposit.pubkey, deposit.withdrawal_credentials, deposit.amount)
|
add_validator_to_registry(state, deposit.pubkey, deposit.withdrawal_credentials, deposit.amount)
|
||||||
else:
|
else:
|
||||||
validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
|
validator_index = ValidatorIndex(validator_pubkeys.index(deposit.pubkey))
|
||||||
|
# Increase balance
|
||||||
|
increase_balance(state, validator_index, deposit.amount)
|
||||||
|
# If validator has not exited, check if valid deposit switch to compounding credentials.
|
||||||
validator = state.validators[validator_index]
|
validator = state.validators[validator_index]
|
||||||
# Validator is exiting, postpone the deposit until after withdrawable epoch
|
if (
|
||||||
if validator.exit_epoch < FAR_FUTURE_EPOCH:
|
validator.exit_epoch < get_current_epoch(state)
|
||||||
if get_current_epoch(state) <= validator.withdrawable_epoch:
|
and is_compounding_withdrawal_credential(deposit.withdrawal_credentials)
|
||||||
return False
|
and has_eth1_withdrawal_credential(validator)
|
||||||
# Deposited balance will never become active. Increase balance but do not consume churn
|
and is_valid_deposit_signature(
|
||||||
else:
|
deposit.pubkey,
|
||||||
increase_balance(state, validator_index, deposit.amount)
|
deposit.withdrawal_credentials,
|
||||||
# Validator is not exiting, attempt to process deposit
|
deposit.amount,
|
||||||
else:
|
deposit.signature
|
||||||
# Increase balance
|
)
|
||||||
increase_balance(state, validator_index, deposit.amount)
|
):
|
||||||
# Check if valid deposit switch to compounding credentials.
|
switch_to_compounding_validator(state, validator_index)
|
||||||
if (
|
|
||||||
is_compounding_withdrawal_credential(deposit.withdrawal_credentials)
|
|
||||||
and has_eth1_withdrawal_credential(validator)
|
|
||||||
and is_valid_deposit_signature(
|
|
||||||
deposit.pubkey,
|
|
||||||
deposit.withdrawal_credentials,
|
|
||||||
deposit.amount,
|
|
||||||
deposit.signature
|
|
||||||
)
|
|
||||||
):
|
|
||||||
switch_to_compounding_validator(state, validator_index)
|
|
||||||
|
|
||||||
return True
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### New `process_pending_deposits`
|
#### New `process_pending_deposits`
|
||||||
|
@ -959,19 +941,30 @@ def process_pending_deposits(state: BeaconState) -> None:
|
||||||
if next_deposit_index >= MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING:
|
if next_deposit_index >= MAX_PENDING_DEPOSITS_PER_EPOCH_PROCESSING:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Check if deposit fits in the churn, otherwise, do no more deposit processing in this epoch.
|
# Read validator state
|
||||||
churn_consumption = get_activation_churn_consumption(state, deposit)
|
is_validator_exited = False
|
||||||
if processed_amount + churn_consumption > available_for_processing:
|
is_validator_withdrawn = False
|
||||||
is_churn_limit_reached = True
|
validator_pubkeys = [v.pubkey for v in state.validators]
|
||||||
break
|
if deposit.pubkey:
|
||||||
|
validator = state.validators[ValidatorIndex(validator_pubkeys.index(deposit.pubkey))]
|
||||||
|
is_validator_exited = validator.exit_epoch < FAR_FUTURE_EPOCH
|
||||||
|
is_validator_withdrawn = validator.withdrawable_epoch < get_current_epoch(state)
|
||||||
|
|
||||||
# Consume churn and apply deposit
|
if is_validator_withdrawn:
|
||||||
processed_amount += churn_consumption
|
# Deposited balance will never become active. Increase balance but do not consume churn
|
||||||
is_deposit_applied = apply_pending_deposit(state, deposit)
|
apply_pending_deposit(state, deposit)
|
||||||
|
elif is_validator_exited:
|
||||||
# Postpone deposit if it has not been applied.
|
# Validator is exiting, postpone the deposit until after withdrawable epoch
|
||||||
if not is_deposit_applied:
|
|
||||||
deposits_to_postpone.append(deposit)
|
deposits_to_postpone.append(deposit)
|
||||||
|
else:
|
||||||
|
# Check if deposit fits in the churn, otherwise, do no more deposit processing in this epoch.
|
||||||
|
is_churn_limit_reached = processed_amount + deposit.amount > available_for_processing
|
||||||
|
if is_churn_limit_reached:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Consume churn and apply deposit.
|
||||||
|
processed_amount += deposit.amount
|
||||||
|
apply_pending_deposit(state, deposit)
|
||||||
|
|
||||||
# Regardless of how the deposit was handled, we move on in the queue.
|
# Regardless of how the deposit was handled, we move on in the queue.
|
||||||
next_deposit_index += 1
|
next_deposit_index += 1
|
||||||
|
@ -1011,9 +1004,9 @@ def process_pending_consolidations(state: BeaconState) -> None:
|
||||||
state.pending_consolidations = state.pending_consolidations[next_pending_consolidation:]
|
state.pending_consolidations = state.pending_consolidations[next_pending_consolidation:]
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Updated `process_effective_balance_updates`
|
#### Modified `process_effective_balance_updates`
|
||||||
|
|
||||||
`process_effective_balance_updates` is updated with a new limit for the maximum effective balance.
|
*Note*: The function `process_effective_balance_updates` is modified to use the new limit for the maximum effective balance.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_effective_balance_updates(state: BeaconState) -> None:
|
def process_effective_balance_updates(state: BeaconState) -> None:
|
||||||
|
@ -1023,6 +1016,7 @@ def process_effective_balance_updates(state: BeaconState) -> None:
|
||||||
HYSTERESIS_INCREMENT = uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT)
|
HYSTERESIS_INCREMENT = uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT)
|
||||||
DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
|
DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
|
||||||
UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
|
UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
|
||||||
|
# [Modified in Electra:EIP7251]
|
||||||
EFFECTIVE_BALANCE_LIMIT = (
|
EFFECTIVE_BALANCE_LIMIT = (
|
||||||
MAX_EFFECTIVE_BALANCE_ELECTRA if has_compounding_withdrawal_credential(validator)
|
MAX_EFFECTIVE_BALANCE_ELECTRA if has_compounding_withdrawal_credential(validator)
|
||||||
else MIN_ACTIVATION_BALANCE
|
else MIN_ACTIVATION_BALANCE
|
||||||
|
@ -1050,7 +1044,9 @@ def process_block(state: BeaconState, block: BeaconBlock) -> None:
|
||||||
|
|
||||||
#### Withdrawals
|
#### Withdrawals
|
||||||
|
|
||||||
##### Updated `get_expected_withdrawals`
|
##### Modified `get_expected_withdrawals`
|
||||||
|
|
||||||
|
*Note*: The function `get_expected_withdrawals` is modified to support EIP7251.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64]:
|
def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal], uint64]:
|
||||||
|
@ -1106,7 +1102,9 @@ def get_expected_withdrawals(state: BeaconState) -> Tuple[Sequence[Withdrawal],
|
||||||
return withdrawals, partial_withdrawals_count
|
return withdrawals, partial_withdrawals_count
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Updated `process_withdrawals`
|
##### Modified `process_withdrawals`
|
||||||
|
|
||||||
|
*Note*: The function `process_withdrawals` is modified to support EIP7251.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
|
def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
|
||||||
|
@ -1272,9 +1270,9 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
|
||||||
|
|
||||||
##### Deposits
|
##### Deposits
|
||||||
|
|
||||||
###### Updated `apply_deposit`
|
###### Modified `apply_deposit`
|
||||||
|
|
||||||
*NOTE*: `process_deposit` is updated with a new definition of `apply_deposit`.
|
*Note*: The function `process_deposit` is modified to support EIP7251.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def apply_deposit(state: BeaconState,
|
def apply_deposit(state: BeaconState,
|
||||||
|
@ -1297,7 +1295,7 @@ def apply_deposit(state: BeaconState,
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
# Increase balance by deposit amount
|
# Increase balance by deposit amount
|
||||||
# [Modified in Electra:EIP-7251]
|
# [Modified in Electra:EIP7251]
|
||||||
state.pending_deposits.append(PendingDeposit(
|
state.pending_deposits.append(PendingDeposit(
|
||||||
pubkey=pubkey,
|
pubkey=pubkey,
|
||||||
withdrawal_credentials=withdrawal_credentials,
|
withdrawal_credentials=withdrawal_credentials,
|
||||||
|
@ -1325,7 +1323,10 @@ def is_valid_deposit_signature(pubkey: BLSPubkey,
|
||||||
```
|
```
|
||||||
|
|
||||||
##### Voluntary exits
|
##### Voluntary exits
|
||||||
###### Updated `process_voluntary_exit`
|
|
||||||
|
###### Modified `process_voluntary_exit`
|
||||||
|
|
||||||
|
*Note*: The function `process_voluntary_exit` is modified to ensure the validator has no pending withdrawals in the queue.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
|
def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVoluntaryExit) -> None:
|
||||||
|
@ -1353,8 +1354,6 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu
|
||||||
|
|
||||||
###### New `process_withdrawal_request`
|
###### New `process_withdrawal_request`
|
||||||
|
|
||||||
*Note*: This function is new in Electra following EIP-7002 and EIP-7251.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_withdrawal_request(
|
def process_withdrawal_request(
|
||||||
state: BeaconState,
|
state: BeaconState,
|
||||||
|
@ -1422,8 +1421,6 @@ def process_withdrawal_request(
|
||||||
|
|
||||||
###### New `process_deposit_request`
|
###### New `process_deposit_request`
|
||||||
|
|
||||||
*Note*: This function is new in Electra:EIP6110.
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
|
def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None:
|
||||||
# Set deposit request start index
|
# Set deposit request start index
|
||||||
|
|
|
@ -126,6 +126,8 @@ def test_verify_cell_kzg_proof(spec):
|
||||||
@spec_test
|
@spec_test
|
||||||
@single_phase
|
@single_phase
|
||||||
def test_verify_cell_kzg_proof_batch(spec):
|
def test_verify_cell_kzg_proof_batch(spec):
|
||||||
|
|
||||||
|
# test with a single blob / commitment
|
||||||
blob = get_sample_blob(spec)
|
blob = get_sample_blob(spec)
|
||||||
commitment = spec.blob_to_kzg_commitment(blob)
|
commitment = spec.blob_to_kzg_commitment(blob)
|
||||||
cells, proofs = spec.compute_cells_and_kzg_proofs(blob)
|
cells, proofs = spec.compute_cells_and_kzg_proofs(blob)
|
||||||
|
@ -140,6 +142,94 @@ def test_verify_cell_kzg_proof_batch(spec):
|
||||||
proofs_bytes=[proofs[0], proofs[4]],
|
proofs_bytes=[proofs[0], proofs[4]],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# now test with three blobs / commitments
|
||||||
|
all_blobs = []
|
||||||
|
all_commitments = []
|
||||||
|
all_cells = []
|
||||||
|
all_proofs = []
|
||||||
|
for _ in range(3):
|
||||||
|
blob = get_sample_blob(spec)
|
||||||
|
commitment = spec.blob_to_kzg_commitment(blob)
|
||||||
|
cells, proofs = spec.compute_cells_and_kzg_proofs(blob)
|
||||||
|
|
||||||
|
assert len(cells) == len(proofs)
|
||||||
|
|
||||||
|
all_blobs.append(blob)
|
||||||
|
all_commitments.append(commitment)
|
||||||
|
all_cells.append(cells)
|
||||||
|
all_proofs.append(proofs)
|
||||||
|
|
||||||
|
# the cells of interest
|
||||||
|
row_indices = [0, 0, 1, 2, 1]
|
||||||
|
column_indices = [0, 4, 0, 1, 2]
|
||||||
|
cells = [all_cells[i][j] for (i, j) in zip(row_indices, column_indices)]
|
||||||
|
proofs = [all_proofs[i][j] for (i, j) in zip(row_indices, column_indices)]
|
||||||
|
|
||||||
|
# do the check
|
||||||
|
assert spec.verify_cell_kzg_proof_batch(
|
||||||
|
row_commitments_bytes=all_commitments,
|
||||||
|
row_indices=row_indices,
|
||||||
|
column_indices=column_indices,
|
||||||
|
cells=cells,
|
||||||
|
proofs_bytes=proofs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@with_eip7594_and_later
|
||||||
|
@spec_test
|
||||||
|
@single_phase
|
||||||
|
def test_verify_cell_kzg_proof_batch_invalid(spec):
|
||||||
|
|
||||||
|
# test with a single blob / commitment
|
||||||
|
blob = get_sample_blob(spec)
|
||||||
|
commitment = spec.blob_to_kzg_commitment(blob)
|
||||||
|
cells, proofs = spec.compute_cells_and_kzg_proofs(blob)
|
||||||
|
|
||||||
|
assert len(cells) == len(proofs)
|
||||||
|
|
||||||
|
assert not spec.verify_cell_kzg_proof_batch(
|
||||||
|
row_commitments_bytes=[commitment],
|
||||||
|
row_indices=[0, 0],
|
||||||
|
column_indices=[0, 4],
|
||||||
|
cells=[cells[0], cells[5]], # Note: this is where it should go wrong
|
||||||
|
proofs_bytes=[proofs[0], proofs[4]],
|
||||||
|
)
|
||||||
|
|
||||||
|
# now test with three blobs / commitments
|
||||||
|
all_blobs = []
|
||||||
|
all_commitments = []
|
||||||
|
all_cells = []
|
||||||
|
all_proofs = []
|
||||||
|
for _ in range(3):
|
||||||
|
blob = get_sample_blob(spec)
|
||||||
|
commitment = spec.blob_to_kzg_commitment(blob)
|
||||||
|
cells, proofs = spec.compute_cells_and_kzg_proofs(blob)
|
||||||
|
|
||||||
|
assert len(cells) == len(proofs)
|
||||||
|
|
||||||
|
all_blobs.append(blob)
|
||||||
|
all_commitments.append(commitment)
|
||||||
|
all_cells.append(cells)
|
||||||
|
all_proofs.append(proofs)
|
||||||
|
|
||||||
|
# the cells of interest
|
||||||
|
row_indices = [0, 0, 1, 2, 1]
|
||||||
|
column_indices = [0, 4, 0, 1, 2]
|
||||||
|
cells = [all_cells[i][j] for (i, j) in zip(row_indices, column_indices)]
|
||||||
|
proofs = [all_proofs[i][j] for (i, j) in zip(row_indices, column_indices)]
|
||||||
|
|
||||||
|
# let's change one of the cells. Then it should not verify
|
||||||
|
cells[1] = all_cells[1][3]
|
||||||
|
|
||||||
|
# do the check
|
||||||
|
assert not spec.verify_cell_kzg_proof_batch(
|
||||||
|
row_commitments_bytes=all_commitments,
|
||||||
|
row_indices=row_indices,
|
||||||
|
column_indices=column_indices,
|
||||||
|
cells=cells,
|
||||||
|
proofs_bytes=proofs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@with_eip7594_and_later
|
@with_eip7594_and_later
|
||||||
@spec_test
|
@spec_test
|
||||||
|
|
|
@ -80,3 +80,29 @@ def test_fork_random_misc_balances(spec, phases, state):
|
||||||
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
|
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
|
||||||
def test_fork_random_large_validator_set(spec, phases, state):
|
def test_fork_random_large_validator_set(spec, phases, state):
|
||||||
yield from run_fork_test(phases[ELECTRA], state)
|
yield from run_fork_test(phases[ELECTRA], state)
|
||||||
|
|
||||||
|
|
||||||
|
@with_phases(phases=[DENEB], other_phases=[ELECTRA])
|
||||||
|
@spec_test
|
||||||
|
@with_state
|
||||||
|
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
|
||||||
|
def test_fork_pre_activation(spec, phases, state):
|
||||||
|
post_spec = phases[ELECTRA]
|
||||||
|
state.validators[0].activation_epoch = spec.FAR_FUTURE_EPOCH
|
||||||
|
post_state = yield from run_fork_test(post_spec, state)
|
||||||
|
|
||||||
|
assert len(post_state.pending_deposits) > 0
|
||||||
|
|
||||||
|
|
||||||
|
@with_phases(phases=[DENEB], other_phases=[ELECTRA])
|
||||||
|
@spec_test
|
||||||
|
@with_state
|
||||||
|
@with_meta_tags(ELECTRA_FORK_TEST_META_TAGS)
|
||||||
|
def test_fork_has_compounding_withdrawal_credential(spec, phases, state):
|
||||||
|
post_spec = phases[ELECTRA]
|
||||||
|
validator = state.validators[0]
|
||||||
|
state.balances[0] = post_spec.MIN_ACTIVATION_BALANCE + 1
|
||||||
|
validator.withdrawal_credentials = post_spec.COMPOUNDING_WITHDRAWAL_PREFIX + validator.withdrawal_credentials[1:]
|
||||||
|
post_state = yield from run_fork_test(post_spec, state)
|
||||||
|
|
||||||
|
assert len(post_state.pending_deposits) > 0
|
||||||
|
|
|
@ -63,3 +63,5 @@ def run_fork_test(post_spec, pre_state):
|
||||||
assert post_state.fork.epoch == post_spec.get_current_epoch(post_state)
|
assert post_state.fork.epoch == post_spec.get_current_epoch(post_state)
|
||||||
|
|
||||||
yield 'post', post_state
|
yield 'post', post_state
|
||||||
|
|
||||||
|
return post_state
|
||||||
|
|
Loading…
Reference in New Issue