Skip to content

Commit

Permalink
Use PR#3433 style parameters to replace INTERVALS_PER_SLOT time set…
Browse files Browse the repository at this point in the history
…ting
  • Loading branch information
hwwhww committed Sep 20, 2023
1 parent 69d34dc commit 3ae5518
Show file tree
Hide file tree
Showing 14 changed files with 94 additions and 26 deletions.
8 changes: 8 additions & 0 deletions presets/mainnet/altair.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 256
MIN_SYNC_COMMITTEE_PARTICIPANTS: 1
# SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD (= 32 * 256)
UPDATE_TIMEOUT: 8192


# Validator duties
# ---------------------------------------------------------------
# 4000ms
SYNC_MESSAGE_DUE_MS: 4000
# 8000ms
CONTRIBUTION_DUE_MS: 8000
16 changes: 15 additions & 1 deletion presets/mainnet/phase0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,18 @@ MAX_ATTESTATIONS: 128
# 2**4 (= 16)
MAX_DEPOSITS: 16
# 2**4 (= 16)
MAX_VOLUNTARY_EXITS: 16
MAX_VOLUNTARY_EXITS: 16


# Fork choice
# ---------------------------------------------------------------
# 4000ms
LATE_BLOCK_CUTOFF_MS: 4000


# Validator duties
# ---------------------------------------------------------------
# 4000ms
ATTESTATION_DUE_MS: 4000
# 8000ms
AGGREGATE_DUE_MS: 8000
8 changes: 8 additions & 0 deletions presets/minimal/altair.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ EPOCHS_PER_SYNC_COMMITTEE_PERIOD: 8
MIN_SYNC_COMMITTEE_PARTICIPANTS: 1
# SLOTS_PER_EPOCH * EPOCHS_PER_SYNC_COMMITTEE_PERIOD (= 8 * 8)
UPDATE_TIMEOUT: 64


# Validator duties
# ---------------------------------------------------------------
# [customized] 2000ms
SYNC_MESSAGE_DUE_MS: 2000
# [customized] 4000ms
CONTRIBUTION_DUE_MS: 4000
16 changes: 15 additions & 1 deletion presets/minimal/phase0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,18 @@ MAX_ATTESTATIONS: 128
# 2**4 (= 16)
MAX_DEPOSITS: 16
# 2**4 (= 16)
MAX_VOLUNTARY_EXITS: 16
MAX_VOLUNTARY_EXITS: 16


# Fork choice
# ---------------------------------------------------------------
# [customized] 2000ms
LATE_BLOCK_CUTOFF_MS: 2000


# Validator duties
# ---------------------------------------------------------------
# [customized] 2000ms
ATTESTATION_DUE_MS: 2000
# [customized] 4000ms
AGGREGATE_DUE_MS: 4000
6 changes: 3 additions & 3 deletions specs/altair/light-client/p2p-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ This topic is used to propagate the latest `LightClientFinalityUpdate` to light

The following validations MUST pass before forwarding the `finality_update` on the network.
- _[IGNORE]_ The `finalized_header.beacon.slot` is greater than that of all previously forwarded `finality_update`s
- _[IGNORE]_ The `finality_update` is received after the block at `signature_slot` was given enough time to propagate through the network -- i.e. validate that one-third of `finality_update.signature_slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot, with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance)
- _[IGNORE]_ The `finality_update` is received after the block at `signature_slot` was given enough time to propagate through the network -- i.e. validate that `SYNC_MESSAGE_DUE_MS` milliseconds after the start of the `finality_update.signature_slot` slot has transpired, with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance.

For full nodes, the following validations MUST additionally pass before forwarding the `finality_update` on the network.
- _[IGNORE]_ The received `finality_update` matches the locally computed one exactly (as defined in [`create_light_client_finality_update`](./full-node.md#create_light_client_finality_update))
Expand Down Expand Up @@ -88,7 +88,7 @@ This topic is used to propagate the latest `LightClientOptimisticUpdate` to ligh

The following validations MUST pass before forwarding the `optimistic_update` on the network.
- _[IGNORE]_ The `attested_header.beacon.slot` is greater than that of all previously forwarded `optimistic_update`s
- _[IGNORE]_ The `optimistic_update` is received after the block at `signature_slot` was given enough time to propagate through the network -- i.e. validate that one-third of `optimistic_update.signature_slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot, with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance)
- _[IGNORE]_ The `optimistic_update` is received after the block at `signature_slot` was given enough time to propagate through the network -- i.e. validate that `SYNC_MESSAGE_DUE_MS` milliseconds after the start of the `optimistic_update.signature_slot` slot has transpired, with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance.

For full nodes, the following validations MUST additionally pass before forwarding the `optimistic_update` on the network.
- _[IGNORE]_ The received `optimistic_update` matches the locally computed one exactly (as defined in [`create_light_client_optimistic_update`](./full-node.md#create_light_client_optimistic_update))
Expand Down Expand Up @@ -276,4 +276,4 @@ Whenever fork choice selects a new head block with a sync aggregate participatio
- If `finalized_header.beacon.slot` increased, a `LightClientFinalityUpdate` SHOULD be broadcasted to the pubsub topic `light_client_finality_update` if no matching message has not yet been forwarded as part of gossip validation.
- If `attested_header.beacon.slot` increased, a `LightClientOptimisticUpdate` SHOULD be broadcasted to the pubsub topic `light_client_optimistic_update` if no matching message has not yet been forwarded as part of gossip validation.

These messages SHOULD be broadcasted after one-third of `slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot). To ensure that the corresponding block was given enough time to propagate through the network, they SHOULD NOT be sent earlier. Note that this is different from how other messages are handled, e.g., attestations, which may be sent early.
These messages SHOULD be broadcasted after `SYNC_MESSAGE_DUE_MS` milliseconds after the start of the slot. To ensure that the corresponding block was given enough time to propagate through the network, they SHOULD NOT be sent earlier. Note that this is different from how other messages are handled, e.g., attestations, which may be sent early.
12 changes: 10 additions & 2 deletions specs/altair/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This is an accompanying document to [Altair -- The Beacon Chain](./beacon-chain.
- [Prerequisites](#prerequisites)
- [Constants](#constants)
- [Misc](#misc)
- [Presets](#presets)
- [Containers](#containers)
- [`SyncCommitteeMessage`](#synccommitteemessage)
- [`SyncCommitteeContribution`](#synccommitteecontribution)
Expand Down Expand Up @@ -71,6 +72,13 @@ Please see this document before continuing and use as a reference throughout.
| `TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE` | `2**4` (= 16) | validators |
| `SYNC_COMMITTEE_SUBNET_COUNT` | `4` | The number of sync committee subnets used in the gossipsub aggregation protocol. |

## Presets

| Name | Value |
| --------------------- | ----------- |
| `SYNC_MESSAGE_DUE_MS` | `4000` |
| `CONTRIBUTION_DUE_MS` | `8000` |

## Containers

### `SyncCommitteeMessage`
Expand Down Expand Up @@ -263,7 +271,7 @@ This process occurs each slot.
If a validator is in the current sync committee (i.e. `is_assigned_to_sync_committee()` above returns `True`), then for every `slot` in the current sync committee period, the validator should prepare a `SyncCommitteeMessage` for the previous slot (`slot - 1`) according to the logic in `get_sync_committee_message` as soon as they have determined the head block of `slot - 1`. This means that when assigned to `slot` a `SyncCommitteeMessage` is prepared and broadcast in `slot-1 ` instead of `slot`.

This logic is triggered upon the same conditions as when producing an attestation.
Meaning, a sync committee member should produce and broadcast a `SyncCommitteeMessage` either when (a) the validator has received a valid block from the expected block proposer for the current `slot` or (b) one-third of the slot has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of the slot) -- whichever comes first.
Meaning, a sync committee member should produce and broadcast a `SyncCommitteeMessage` either when (a) the validator has received a valid block from the expected block proposer for the current `slot` or (b) `SYNC_MESSAGE_DUE_MS` milliseconds after the start of the slot has transpired -- whichever comes first.

`get_sync_committee_message(state, block_root, validator_index, privkey)` assumes the parameter `state` is the head state corresponding to processing the block up to the current slot as determined by the fork choice (including any empty slots up to the current slot processed with `process_slots` on top of the latest block), `block_root` is the root of the head block, `validator_index` is the index of the validator in the registry `state.validators` controlled by `privkey`, and `privkey` is the BLS private key for the validator.

Expand Down Expand Up @@ -380,7 +388,7 @@ The collection of input signatures should include one signature per validator wh

##### Broadcast sync committee contribution

If the validator is selected to aggregate (`is_sync_committee_aggregator()`), then they broadcast their best aggregate as a `SignedContributionAndProof` to the global aggregate channel (`sync_committee_contribution_and_proof` topic) two-thirds of the way through the `slot`-that is, `SECONDS_PER_SLOT * 2 / INTERVALS_PER_SLOT` seconds after the start of `slot`.
If the validator is selected to aggregate (`is_sync_committee_aggregator()`), then they broadcast their best aggregate as a `SignedContributionAndProof` to the global aggregate channel (`sync_committee_contribution_and_proof` topic) `CONTRIBUTION_DUE_MS` milliseconds after the start of `slot` has transpired.

Selection proofs are provided in `ContributionAndProof` to prove to the gossip channel that the validator has been selected as an aggregator.

Expand Down
4 changes: 2 additions & 2 deletions specs/bellatrix/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:

# Add proposer score boost if the block is timely
time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
is_before_late_block_cutoff = time_into_slot * 1000 < LATE_BLOCK_CUTOFF_MS
is_first_block = store.proposer_boost_root == Root()
if get_current_slot(store) == block.slot and is_before_attesting_interval and is_first_block:
if get_current_slot(store) == block.slot and is_before_late_block_cutoff and is_first_block:
store.proposer_boost_root = hash_tree_root(block)

# Update checkpoints in store if necessary
Expand Down
4 changes: 2 additions & 2 deletions specs/capella/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:

# Add proposer score boost if the block is timely
time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
is_before_late_block_cutoff = time_into_slot * 1000 < LATE_BLOCK_CUTOFF_MS
is_first_block = store.proposer_boost_root == Root()
if get_current_slot(store) == block.slot and is_before_attesting_interval and is_first_block:
if get_current_slot(store) == block.slot and is_before_late_block_cutoff and is_first_block:
store.proposer_boost_root = hash_tree_root(block)

# Update checkpoints in store if necessary
Expand Down
4 changes: 2 additions & 2 deletions specs/deneb/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:

# Add proposer score boost if the block is timely
time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
is_before_late_block_cutoff = time_into_slot * 1000 < LATE_BLOCK_CUTOFF_MS
is_first_block = store.proposer_boost_root == Root()
if get_current_slot(store) == block.slot and is_before_attesting_interval and is_first_block:
if get_current_slot(store) == block.slot and is_before_late_block_cutoff and is_first_block:
store.proposer_boost_root = hash_tree_root(block)

# Update checkpoints in store if necessary
Expand Down
14 changes: 7 additions & 7 deletions specs/phase0/fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

- [Introduction](#introduction)
- [Fork choice](#fork-choice)
- [Constant](#constant)
- [Presets](#presets)
- [Configuration](#configuration)
- [Helpers](#helpers)
- [`LatestMessage`](#latestmessage)
Expand Down Expand Up @@ -68,11 +68,11 @@ Any of the above handlers that trigger an unhandled exception (e.g. a failed ass
5) **Implementation**: The implementation found in this specification is constructed for ease of understanding rather than for optimization in computation, space, or any other resource. A number of optimized alternatives can be found [here](https://github.com/protolambda/lmd-ghost).


### Constant
### Presets

| Name | Value |
| -------------------- | ----------- |
| `INTERVALS_PER_SLOT` | `uint64(3)` |
| Name | Value |
| ---------------------- | ----------- |
| `LATE_BLOCK_CUTOFF_MS` | `4000` |

### Configuration

Expand Down Expand Up @@ -538,9 +538,9 @@ def on_block(store: Store, signed_block: SignedBeaconBlock) -> None:

# Add proposer score boost if the block is timely
time_into_slot = (store.time - store.genesis_time) % SECONDS_PER_SLOT
is_before_attesting_interval = time_into_slot < SECONDS_PER_SLOT // INTERVALS_PER_SLOT
is_before_late_block_cutoff = time_into_slot * 1000 < LATE_BLOCK_CUTOFF_MS
is_first_block = store.proposer_boost_root == Root()
if get_current_slot(store) == block.slot and is_before_attesting_interval and is_first_block:
if get_current_slot(store) == block.slot and is_before_late_block_cutoff and is_first_block:
store.proposer_boost_root = hash_tree_root(block)

# Update checkpoints in store if necessary
Expand Down
12 changes: 10 additions & 2 deletions specs/phase0/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This is an accompanying document to [Phase 0 -- The Beacon Chain](./beacon-chain
- [Prerequisites](#prerequisites)
- [Constants](#constants)
- [Misc](#misc)
- [Presets](#presets)
- [Containers](#containers)
- [`Eth1Block`](#eth1block)
- [`AggregateAndProof`](#aggregateandproof)
Expand Down Expand Up @@ -89,6 +90,13 @@ All terminology, constants, functions, and protocol mechanics defined in the [Ph
| - | - | :-: | :-: |
| `TARGET_AGGREGATORS_PER_COMMITTEE` | `2**4` (= 16) | validators |

## Presets

| Name | Value |
| --------------------- | ----------- |
| `ATTESTATION_DUE_MS` | `4000` |
| `AGGREGATE_DUE_MS` | `8000` |

## Containers

### `Eth1Block`
Expand Down Expand Up @@ -445,7 +453,7 @@ def get_block_signature(state: BeaconState, block: BeaconBlock, privkey: int) ->

A validator is expected to create, sign, and broadcast an attestation during each epoch. The `committee`, assigned `index`, and assigned `slot` for which the validator performs this role during an epoch are defined by `get_committee_assignment(state, epoch, validator_index)`.

A validator should create and broadcast the `attestation` to the associated attestation subnet when either (a) the validator has received a valid block from the expected block proposer for the assigned `slot` or (b) `1 / INTERVALS_PER_SLOT` of the `slot` has transpired (`SECONDS_PER_SLOT / INTERVALS_PER_SLOT` seconds after the start of `slot`) -- whichever comes _first_.
A validator should create and broadcast the `attestation` to the associated attestation subnet when either (a) the validator has received a valid block from the expected block proposer for the assigned `slot` or (b) `ATTESTATION_DUE_MS` milliseconds after the start of `slot` has transpired -- whichever comes _first_.

*Note*: Although attestations during `GENESIS_EPOCH` do not count toward FFG finality, these initial attestations do give weight to the fork choice, are rewarded, and should be made.

Expand Down Expand Up @@ -570,7 +578,7 @@ def get_aggregate_signature(attestations: Sequence[Attestation]) -> BLSSignature

#### Broadcast aggregate

If the validator is selected to aggregate (`is_aggregator`), then they broadcast their best aggregate as a `SignedAggregateAndProof` to the global aggregate channel (`beacon_aggregate_and_proof`) `2 / INTERVALS_PER_SLOT` of the way through the `slot`-that is, `SECONDS_PER_SLOT * 2 / INTERVALS_PER_SLOT` seconds after the start of `slot`.
If the validator is selected to aggregate (`is_aggregator`), then they broadcast their best aggregate as a `SignedAggregateAndProof` to the global aggregate channel (`beacon_aggregate_and_proof`) `AGGREGATE_DUE_MS` milliseconds after the start of `slot` has transpired.

Selection proofs are provided in `AggregateAndProof` to prove to the gossip channel that the validator has been selected as an aggregator.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,10 @@ def test_weight_denominator(spec, state):
@spec_state_test
def test_inactivity_score(spec, state):
assert spec.config.INACTIVITY_SCORE_BIAS <= spec.config.INACTIVITY_SCORE_RECOVERY_RATE


@with_altair_and_later
@spec_state_test
def test_fork_choice(spec, state):
assert spec.SYNC_MESSAGE_DUE_MS < spec.config.SECONDS_PER_SLOT * 1000
assert spec.CONTRIBUTION_DUE_MS < spec.config.SECONDS_PER_SLOT * 1000
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ def test_proposer_boost(spec, state):

# Process block on timely arrival just before end of boost interval
time = (store.genesis_time + block.slot * spec.config.SECONDS_PER_SLOT +
spec.config.SECONDS_PER_SLOT // spec.INTERVALS_PER_SLOT - 1)
(spec.LATE_BLOCK_CUTOFF_MS - 1) // 1000)
on_tick_and_append_step(spec, store, time, test_steps)
yield from add_block(spec, store, signed_block, test_steps)
assert store.proposer_boost_root == spec.hash_tree_root(block)
Expand Down Expand Up @@ -524,7 +524,7 @@ def test_proposer_boost_root_same_slot_untimely_block(spec, state):

# Process block on untimely arrival in the same slot
time = (store.genesis_time + block.slot * spec.config.SECONDS_PER_SLOT +
spec.config.SECONDS_PER_SLOT // spec.INTERVALS_PER_SLOT)
spec.LATE_BLOCK_CUTOFF_MS // 1000)
on_tick_and_append_step(spec, store, time, test_steps)
yield from add_block(spec, store, signed_block, test_steps)

Expand Down Expand Up @@ -559,7 +559,7 @@ def test_proposer_boost_is_first_block(spec, state):

# Process block on timely arrival just before end of boost interval
time = (store.genesis_time + block_a.slot * spec.config.SECONDS_PER_SLOT +
spec.config.SECONDS_PER_SLOT // spec.INTERVALS_PER_SLOT - 1)
(spec.LATE_BLOCK_CUTOFF_MS - 1) // 1000)
on_tick_and_append_step(spec, store, time, test_steps)
yield from add_block(spec, store, signed_block_a, test_steps)
# `proposer_boost_root` is now `block_a`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,6 @@ def test_networking(spec, state):
@with_all_phases
@spec_state_test
def test_fork_choice(spec, state):
assert spec.INTERVALS_PER_SLOT < spec.config.SECONDS_PER_SLOT
assert spec.ATTESTATION_DUE_MS < spec.config.SECONDS_PER_SLOT * 1000
assert spec.AGGREGATE_DUE_MS < spec.config.SECONDS_PER_SLOT * 1000
assert spec.config.PROPOSER_SCORE_BOOST <= 100

0 comments on commit 3ae5518

Please sign in to comment.