Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Last minute cleanups #1244

Closed
wants to merge 10 commits into from
2 changes: 1 addition & 1 deletion configs/constant_presets/mainnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ EFFECTIVE_BALANCE_INCREMENT: 1000000000
GENESIS_FORK_VERSION: 0x00000000
# 0, GENESIS_EPOCH is derived from this constant
GENESIS_SLOT: 0
BLS_WITHDRAWAL_PREFIX: 0
BLS_WITHDRAWAL_PREFIX: 0x00


# Time parameters
Expand Down
2 changes: 1 addition & 1 deletion configs/constant_presets/minimal.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ EFFECTIVE_BALANCE_INCREMENT: 1000000000
GENESIS_FORK_VERSION: 0x00000000
# 0, GENESIS_EPOCH is derived from this constant
GENESIS_SLOT: 0
BLS_WITHDRAWAL_PREFIX: 0
BLS_WITHDRAWAL_PREFIX: 0x00


# Time parameters
Expand Down
6 changes: 3 additions & 3 deletions scripts/build_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
)
from eth2spec.utils.ssz.ssz_typing import (
bit, boolean, Container, List, Vector, uint64,
Bytes4, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
Bytes1, Bytes4, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
)
from eth2spec.utils.bls import (
bls_aggregate_pubkeys,
Expand All @@ -53,7 +53,7 @@
)
from eth2spec.utils.ssz.ssz_typing import (
bit, boolean, Container, List, Vector, Bytes, uint64,
Bytes4, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
Bytes1, Bytes4, Bytes32, Bytes48, Bytes96, Bitlist, Bitvector,
)
from eth2spec.utils.bls import (
bls_aggregate_pubkeys,
Expand Down Expand Up @@ -175,7 +175,7 @@ def combine_constants(old_constants: Dict[str, str], new_constants: Dict[str, st

ignored_dependencies = [
'bit', 'boolean', 'Vector', 'List', 'Container', 'Hash', 'BLSPubkey', 'BLSSignature', 'Bytes', 'BytesN'
'Bytes4', 'Bytes32', 'Bytes48', 'Bytes96', 'Bitlist', 'Bitvector',
'Bytes1', 'Bytes4', 'Bytes32', 'Bytes48', 'Bytes96', 'Bitlist', 'Bitvector',
'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'uint256',
'bytes' # to be removed after updating spec doc
]
Expand Down
19 changes: 9 additions & 10 deletions scripts/function_puller.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,14 @@ def get_spec(file_name: str) -> SpecObject:
row[i] = row[i].strip().strip('`')
if '`' in row[i]:
row[i] = row[i][:row[i].find('`')]
if row[1].startswith('uint') or row[1].startswith('Bytes'):
is_constant_def = True
if row[0][0] not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_':
is_constant_def = False
for c in row[0]:
if c not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789':
is_constant_def = False
if is_constant_def:
constants[row[0]] = row[1].replace('**TBD**', '0x1234567890123456789012345678901234567890')
elif row[1].startswith('uint') or row[1].startswith('Bytes'):
custom_types[row[0]] = row[1]
else:
eligible = True
if row[0][0] not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_':
eligible = False
for c in row[0]:
if c not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789':
eligible = False
if eligible:
constants[row[0]] = row[1].replace('**TBD**', '0x1234567890123456789012345678901234567890')
return functions, custom_types, constants, ssz_objects, inserts
66 changes: 30 additions & 36 deletions specs/core/0_beacon-chain.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ The following values are (non-configurable) constants used throughout the specif
| `BASE_REWARDS_PER_EPOCH` | `5` |
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
| `SECONDS_PER_DAY` | `86400` |
| `JUSTIFICATION_BITS_LENGTH` | `4` |
JustinDrake marked this conversation as resolved.
Show resolved Hide resolved
| `ENDIANNESS` | `'little'` |

## Configuration

Expand All @@ -178,8 +180,6 @@ The following values are (non-configurable) constants used throughout the specif
| `SHUFFLE_ROUND_COUNT` | `90` |
| `MIN_GENESIS_ACTIVE_VALIDATOR_COUNT` | `2**16` (= 65,536) |
| `MIN_GENESIS_TIME` | `1578009600` (Jan 3, 2020) |
| `JUSTIFICATION_BITS_LENGTH` | `4` |
| `ENDIANNESS` | `'little'` |

* For the safety of crosslinks, `TARGET_COMMITTEE_SIZE` exceeds [the recommended minimum committee size of 111](https://vitalik.ca/files/Ithaca201807_Sharding.pdf); with sufficient active validators (at least `SLOTS_PER_EPOCH * TARGET_COMMITTEE_SIZE`), the shuffling algorithm ensures committee sizes of at least `TARGET_COMMITTEE_SIZE`. (Unbiasable randomness with a Verifiable Delay Function (VDF) will improve committee robustness and lower the safe minimum committee size.)

Expand All @@ -198,32 +198,30 @@ The following values are (non-configurable) constants used throughout the specif
| - | - |
| `GENESIS_SLOT` | `Slot(0)` |
| `GENESIS_EPOCH` | `Epoch(0)` |
| `BLS_WITHDRAWAL_PREFIX` | `0` |
| `BLS_WITHDRAWAL_PREFIX` | `Bytes1(b'\x00')` |

### Time parameters

| Name | Value | Unit | Duration |
| Name | Value | Duration |
| - | - | :-: | :-: |
| `MIN_ATTESTATION_INCLUSION_DELAY` | `2**0` (= 1) | slots | 6 seconds |
| `SLOTS_PER_EPOCH` | `2**6` (= 64) | slots | 6.4 minutes |
| `MIN_SEED_LOOKAHEAD` | `2**0` (= 1) | epochs | 6.4 minutes |
| `ACTIVATION_EXIT_DELAY` | `2**2` (= 4) | epochs | 25.6 minutes |
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `2**10` (= 1,024) | slots | ~1.7 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `2**13` (= 8,192) | slots | ~13 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `2**8` (= 256) | epochs | ~27 hours |
| `PERSISTENT_COMMITTEE_PERIOD` | `2**11` (= 2,048) | epochs | 9 days |
| `MAX_EPOCHS_PER_CROSSLINK` | `2**6` (= 64) | epochs | ~7 hours |
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `2**2` (= 4) | epochs | 25.6 minutes |

* `MAX_EPOCHS_PER_CROSSLINK` should be a small constant times `SHARD_COUNT // SLOTS_PER_EPOCH`.
| `MIN_ATTESTATION_INCLUSION_DELAY` | `Slot(2**0)` (= 1) | 6 seconds |
Copy link
Contributor

@djrtwo djrtwo Jun 30, 2019

Choose a reason for hiding this comment

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

None of these should be typed as Slot or Epoch. "5 slots" is not actually a Slot. It's a count of something.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is the thing that is being counted here not a Slot though?

Copy link
Contributor

Choose a reason for hiding this comment

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

Slot was called SlotNumber, as the ID to identify a certain slot; Epoch and Shard are as well.

| `SLOTS_PER_EPOCH` | `Slot(2**6)` (= 64) | 6.4 minutes |
| `MIN_SEED_LOOKAHEAD` | `Epoch(2**0)` (= 1) | 6.4 minutes |
| `ACTIVATION_EXIT_DELAY` | `Epoch(2**2)` (= 4) | 25.6 minutes |
| `SLOTS_PER_ETH1_VOTING_PERIOD` | `Slot(2**10)` (= 1,024) | ~1.7 hours |
| `SLOTS_PER_HISTORICAL_ROOT` | `Slot(2**13)` (= 8,192) | ~13 hours |
| `MIN_VALIDATOR_WITHDRAWABILITY_DELAY` | `Epoch(2**8)` (= 256) | ~27 hours |
| `PERSISTENT_COMMITTEE_PERIOD` | `Epoch(2**11)` (= 2,048) | 9 days |
| `MAX_EPOCHS_PER_CROSSLINK` | `Epoch(2**6)` (= 64) | ~7 hours |
| `MIN_EPOCHS_TO_INACTIVITY_PENALTY` | `Epoch(2**2)` (= 4) | 25.6 minutes |

### State list lengths

| Name | Value | Unit | Duration |
| Name | Value | Duration |
| - | - | :-: | :-: |
| `EPOCHS_PER_HISTORICAL_VECTOR` | `2**16` (= 65,536) | epochs | ~0.8 years |
| `EPOCHS_PER_SLASHINGS_VECTOR` | `2**13` (= 8,192) | epochs | ~36 days |
| `HISTORICAL_ROOTS_LIMIT` | `2**24` (= 16,777,216) | historical roots | ~26,131 years |
| `EPOCHS_PER_HISTORICAL_VECTOR` | `Epoch(2**16)` (= 65,536) | ~0.8 years |
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I disagree:

  • The name EPOCHS_PER_... is consistent with the Epoch type.
  • EPOCHS_PER_HISTORICAL_VECTOR naturally occurs in Epoch summations such as epoch + EPOCHS_PER_HISTORICAL_VECTOR - MIN_SEED_LOOKAHEAD.
  • EPOCHS_PER_HISTORICAL_VECTOR naturally occurs in Epoch modular reductions such as epoch % EPOCHS_PER_HISTORICAL_VECTOR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think in instances where there is a PER in the name, dimensional analysis dictates that they are not Epochs, but `Epochs * HistoricalVectors**(-1).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SLOTS_PER_EPOCH is defined as "the number of slots in an epoch". That's of type Slot, not Slot/Epoch.

Copy link
Contributor

@CarlBeek CarlBeek Jun 30, 2019

Choose a reason for hiding this comment

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

Disagree. The use of SLOTS_PER_EPOCH in slot_to_epoch and in epoch_start_slot stand counter to your argument.

If SLOTS_PER_EPOCH is a Slot then epoch_start_slot's return type is Epoch*Slot and epoch_start_slot is dimensionless.

Copy link
Contributor

Choose a reason for hiding this comment

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

Historical vector here doesn't represent a type, but a non-typed scalar. So you could say we are multiplying by something that doesn't change the type, only the length. Imho I think the debate is silly, and naming is consistent and clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hum, OK. Would you agree that Epochs * HistoricalVectors**(-1) is the same as Epochs because HistoricalVectors is dimensionless? 😂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't care too much either way. Need to go to sleep soon as I can't think straight anymore 💤

Copy link
Contributor

Choose a reason for hiding this comment

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

😂Fine. :) I am not entirely convinced, but I sort of agree enough on the dimensionlessness HistoricalVectors.

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed the need for sleep is real.

| `EPOCHS_PER_SLASHINGS_VECTOR` | `Epoch(2**13)` (= 8,192) | ~36 days |
| `HISTORICAL_ROOTS_LIMIT` | `2**24` (= 16,777,216) | ~26,131 years |
| `VALIDATOR_REGISTRY_LIMIT` | `2**40` (= 1,099,511,627,776) | validator spots | |

### Rewards and penalties
Expand Down Expand Up @@ -541,7 +539,7 @@ class BeaconState(Container):
#### `integer_squareroot`

```python
def integer_squareroot(n: uint64) -> int:
def integer_squareroot(n: uint64) -> uint64:
"""
Return the largest integer ``x`` such that ``x**2 <= n``.
"""
Expand All @@ -564,17 +562,17 @@ def xor(bytes1: Bytes32, bytes2: Bytes32) -> Bytes32:
```

```python
def int_to_bytes(integer: uint64, length: uint64) -> bytes:
def int_to_bytes(n: uint64, length: uint64) -> bytes:
"""
Return the ``length``-byte serialization of ``integer``.
Return the ``length``-byte serialization of ``n``.
"""
return integer.to_bytes(length, ENDIANNESS)
return n.to_bytes(length, ENDIANNESS)
```

#### `bytes_to_int`

```python
def bytes_to_int(data: bytes) -> int:
def bytes_to_int(data: bytes) -> uint64:
"""
Return the integer deserialization of ``data``.
"""
Expand Down Expand Up @@ -670,7 +668,6 @@ def shuffle_index(index: ValidatorIndex, index_count: uint64, seed: Hash) -> Val
Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
"""
assert index < index_count
assert index_count <= 2**40

# Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
# See the 'generalized domain' algorithm on page 3
Expand Down Expand Up @@ -767,7 +764,7 @@ def compute_activation_exit_epoch(epoch: Epoch) -> Epoch:
#### `bls_domain`

```python
def bls_domain(domain_type: uint64, fork_version: bytes=b'\x00' * 4) -> int:
def bls_domain(domain_type: uint64, fork_version: Version=Version()) -> int:
"""
Return the BLS domain for the ``domain_type`` and ``fork_version``.
"""
Expand Down Expand Up @@ -841,7 +838,7 @@ def get_active_validator_indices(state: BeaconState, epoch: Epoch) -> Sequence[V
#### `get_validator_churn_limit`

```python
def get_validator_churn_limit(state: BeaconState) -> int:
def get_validator_churn_limit(state: BeaconState) -> uint64:
"""
Return the validator churn limit for the current epoch.
"""
Expand All @@ -865,7 +862,7 @@ def get_seed(state: BeaconState, epoch: Epoch) -> Hash:
#### `get_committee_count`

```python
def get_committee_count(state: BeaconState, epoch: Epoch) -> int:
def get_committee_count(state: BeaconState, epoch: Epoch) -> uint64:
"""
Return the number of committees at ``epoch``.
"""
Expand Down Expand Up @@ -910,7 +907,7 @@ def get_start_shard(state: BeaconState, epoch: Epoch) -> Shard:
#### `get_shard_delta`

```python
def get_shard_delta(state: BeaconState, epoch: Epoch) -> int:
def get_shard_delta(state: BeaconState, epoch: Epoch) -> uint64:
"""
Return the number of shards to increment ``state.start_shard`` at ``epoch``.
"""
Expand Down Expand Up @@ -1675,8 +1672,8 @@ def process_deposit(state: BeaconState, deposit: Deposit) -> None:
amount = deposit.data.amount
validator_pubkeys = [v.pubkey for v in state.validators]
if pubkey not in validator_pubkeys:
# Verify the deposit signature (proof of possession) for new validators.
# Note: The deposit contract does not check signatures.
# Verify the deposit signature (proof of possession) for new validators
# Note: The deposit contract does not check signatures
# Note: Deposits are valid across forks, hence the deposit domain is retrieved directly from `bls_domain`
if not bls_verify(pubkey, signing_root(deposit.data), deposit.data.signature, bls_domain(DOMAIN_DEPOSIT)):
return
Expand Down Expand Up @@ -1736,10 +1733,7 @@ def process_transfer(state: BeaconState, transfer: Transfer) -> None:
state.balances[transfer.sender] >= transfer.amount + transfer.fee + MAX_EFFECTIVE_BALANCE
)
# Verify that the pubkey is valid
assert (
state.validators[transfer.sender].withdrawal_credentials ==
int_to_bytes(BLS_WITHDRAWAL_PREFIX, length=1) + hash(transfer.pubkey)[1:]
)
assert state.validators[transfer.sender].withdrawal_credentials == BLS_WITHDRAWAL_PREFIX + hash(transfer.pubkey)[1:]
# Verify that the signature is valid
assert bls_verify(transfer.pubkey, signing_root(transfer), transfer.signature, get_domain(state, DOMAIN_TRANSFER))
# Process the transfer
Expand Down
2 changes: 1 addition & 1 deletion specs/core/0_deposit-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ The amount of ETH (rounded down to the closest Gwei) sent to the deposit contrac

One of the `DepositData` fields is `withdrawal_credentials`. It is a commitment to credentials for withdrawing validator balance (e.g. to another validator, or to shards). The first byte of `withdrawal_credentials` is a version number. As of now, the only expected format is as follows:

* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE`
* `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX`
* `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]` where `withdrawal_pubkey` is a BLS pubkey

The private key corresponding to `withdrawal_pubkey` will be required to initiate a withdrawal. It can be stored separately until a withdrawal is required, e.g. in cold storage.
Expand Down
2 changes: 1 addition & 1 deletion specs/validator/0_beacon-chain-validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Validator public keys are [G1 points](../bls_signature.md#g1-points) on the [BLS
A secondary withdrawal private key, `withdrawal_privkey`, must also be securely generated along with the resultant `withdrawal_pubkey`. This `withdrawal_privkey` does not have to be available for signing during the normal lifetime of a validator and can live in "cold storage".

The validator constructs their `withdrawal_credentials` via the following:
* Set `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX_BYTE`.
* Set `withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX`.
* Set `withdrawal_credentials[1:] == hash(withdrawal_pubkey)[1:]`.

### Submit deposit
Expand Down
4 changes: 2 additions & 2 deletions test_libs/pyspec/eth2spec/test/helpers/deposits.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def prepare_genesis_deposits(spec, genesis_validator_count, amount, signed=False
pubkey = pubkeys[validator_index]
privkey = privkeys[validator_index]
# insecurely use pubkey as withdrawal key if no credentials provided
withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:]
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:]
deposit, root, deposit_data_list = build_deposit(
spec,
None,
Expand All @@ -89,7 +89,7 @@ def prepare_state_and_deposit(spec, state, validator_index, amount, withdrawal_c

# insecurely use pubkey as withdrawal key if no credentials provided
if withdrawal_credentials is None:
withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:]
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:]

deposit, root, deposit_data_list = build_deposit(
spec,
Expand Down
2 changes: 1 addition & 1 deletion test_libs/pyspec/eth2spec/test/helpers/genesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
def build_mock_validator(spec, i: int, balance: int):
pubkey = pubkeys[i]
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(pubkey)[1:]
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(pubkey)[1:]
return spec.Validator(
pubkey=pubkeys[i],
withdrawal_credentials=withdrawal_credentials,
Expand Down
2 changes: 1 addition & 1 deletion test_libs/pyspec/eth2spec/test/helpers/transfers.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def get_valid_transfer(spec, state, slot=None, sender_index=None,

# ensure withdrawal_credentials reproducible
state.validators[transfer.sender].withdrawal_credentials = (
spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(transfer.pubkey)[1:]
spec.BLS_WITHDRAWAL_PREFIX + spec.hash(transfer.pubkey)[1:]
)

return transfer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def test_invalid_sig_top_up(spec, state):
def test_invalid_withdrawal_credentials_top_up(spec, state):
validator_index = 0
amount = spec.MAX_EFFECTIVE_BALANCE // 4
withdrawal_credentials = spec.int_to_bytes(spec.BLS_WITHDRAWAL_PREFIX, length=1) + spec.hash(b"junk")[1:]
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX + spec.hash(b"junk")[1:]
deposit = prepare_state_and_deposit(
spec,
state,
Expand Down
3 changes: 2 additions & 1 deletion test_libs/pyspec/eth2spec/utils/ssz/ssz_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ def is_fixed_size(cls):
return True


# Helpers for common BytesN types.
# Helpers for common BytesN types
Bytes1: BytesType = BytesN[1]
Bytes4: BytesType = BytesN[4]
Bytes32: BytesType = BytesN[32]
Bytes48: BytesType = BytesN[48]
Expand Down