diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index 317daa1a45..61a68b0220 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -116,8 +116,6 @@ DEPOSIT_CONTRACT_ADDRESS: 0x00000000219ab540356cBB839Cbe05303d7705Fa GOSSIP_MAX_SIZE: 10485760 # `2**10` (= 1024) MAX_REQUEST_BLOCKS: 1024 -# `2**8` (= 256) -EPOCHS_PER_SUBNET_SUBSCRIPTION: 256 # `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) MIN_EPOCHS_FOR_BLOCK_REQUESTS: 33024 # `10 * 2**20` (=10485760, 10 MiB) @@ -135,9 +133,6 @@ MESSAGE_DOMAIN_VALID_SNAPPY: 0x01000000 SUBNETS_PER_NODE: 2 # 2**8 (= 64) ATTESTATION_SUBNET_COUNT: 64 -ATTESTATION_SUBNET_EXTRA_BITS: 0 -# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS -ATTESTATION_SUBNET_PREFIX_BITS: 6 # Deneb # `2**7` (=128) diff --git a/configs/minimal.yaml b/configs/minimal.yaml index 6b2da84fdb..a5df66585e 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -136,9 +136,6 @@ MESSAGE_DOMAIN_VALID_SNAPPY: 0x01000000 SUBNETS_PER_NODE: 2 # 2**8 (= 64) ATTESTATION_SUBNET_COUNT: 64 -ATTESTATION_SUBNET_EXTRA_BITS: 0 -# ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS -ATTESTATION_SUBNET_PREFIX_BITS: 6 # Deneb # `2**7` (=128) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 795c4aa2e5..5641be8887 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -191,7 +191,6 @@ This section outlines configurations that are used in this spec. |---|---|---| | `GOSSIP_MAX_SIZE` | `10 * 2**20` (= 10485760, 10 MiB) | The maximum allowed size of uncompressed gossip messages. | | `MAX_REQUEST_BLOCKS` | `2**10` (= 1024) | Maximum number of blocks in a single request | -| `EPOCHS_PER_SUBNET_SUBSCRIPTION` | `2**8` (= 256) | Number of epochs on a subnet subscription (~27 hours) | | `MIN_EPOCHS_FOR_BLOCK_REQUESTS` | `MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) | The minimum epoch range over which a node must serve blocks | | `MAX_CHUNK_SIZE` | `10 * 2**20` (=10485760, 10 MiB) | The maximum allowed size of uncompressed req/resp chunked responses. | | `TTFB_TIMEOUT` | `5` | The maximum duration in **seconds** to wait for first byte of request response (time-to-first-byte). | @@ -202,8 +201,6 @@ This section outlines configurations that are used in this spec. | `MESSAGE_DOMAIN_VALID_SNAPPY` | `DomainType('0x01000000')` | 4-byte domain for gossip message-id isolation of *valid* snappy messages | | `SUBNETS_PER_NODE` | `2` | The number of long-lived subnets a beacon node should be subscribed to. | | `ATTESTATION_SUBNET_COUNT` | `2**6` (= 64) | The number of attestation subnets used in the gossipsub protocol. | -| `ATTESTATION_SUBNET_EXTRA_BITS` | `0` | The number of extra bits of a NodeId to use when mapping to a subscribed subnet | -| `ATTESTATION_SUBNET_PREFIX_BITS` | `int(ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS)` | | ### MetaData @@ -1014,30 +1011,23 @@ these connecting clients will be unable to successfully interact starting at the Because Phase 0 does not have shards and thus does not have Shard Committees, there is no stable backbone to the attestation subnets (`beacon_attestation_{subnet_id}`). To provide this stability, each beacon node should: -* Remain subscribed to `SUBNETS_PER_NODE` for `EPOCHS_PER_SUBNET_SUBSCRIPTION` epochs. +* Remain subscribed to `SUBNETS_PER_NODE`. * Maintain advertisement of the selected subnets in their node's ENR `attnets` entry by setting the selected `subnet_id` bits to `True` (e.g. `ENR["attnets"][subnet_id] = True`) for all persistent attestation subnets. -* Select these subnets based on their node-id as specified by the following `compute_subscribed_subnets(node_id, epoch)` function. +* Select these subnets based on their node-id as specified by the following `compute_subscribed_subnets(node_id)` function. ```python -def compute_subscribed_subnet(node_id: NodeID, epoch: Epoch, index: int) -> SubnetID: - node_id_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS) - node_offset = node_id % EPOCHS_PER_SUBNET_SUBSCRIPTION - permutation_seed = hash(uint_to_bytes(uint64((epoch + node_offset) // EPOCHS_PER_SUBNET_SUBSCRIPTION))) - permutated_prefix = compute_shuffled_index( - node_id_prefix, - 1 << ATTESTATION_SUBNET_PREFIX_BITS, - permutation_seed, - ) - return SubnetID((permutated_prefix + index) % ATTESTATION_SUBNET_COUNT) +def compute_subscribed_subnet(node_id: NodeID, index: int) -> SubnetID: + # Select the first few bits that are necessary to encapsulate the size of + # ATTESTATION_SUBNET_COUNT + node_id_prefix = node_id >> (NODE_ID_BITS - int(ceillog2(ATTESTATION_SUBNET_COUNT))) + return SubnetID((node_id_prefix + index) % ATTESTATION_SUBNET_COUNT) ``` ```python -def compute_subscribed_subnets(node_id: NodeID, epoch: Epoch) -> Sequence[SubnetID]: - return [compute_subscribed_subnet(node_id, epoch, index) for index in range(SUBNETS_PER_NODE)] +def compute_subscribed_subnets(node_id: NodeID) -> Sequence[SubnetID]: + return [compute_subscribed_subnet(node_id, index) for index in range(SUBNETS_PER_NODE)] ``` -*Note*: When preparing for a hard fork, a node must select and subscribe to subnets of the future fork versioning at least `EPOCHS_PER_SUBNET_SUBSCRIPTION` epochs in advance of the fork. These new subnets for the fork are maintained in addition to those for the current fork until the fork occurs. After the fork occurs, let the subnets from the previous fork reach the end of life with no replacements. - ## Design decision rationale ### Transport diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/test_config_invariants.py index c58f817f7d..171b947a94 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/unittests/test_config_invariants.py +++ b/tests/core/pyspec/eth2spec/test/phase0/unittests/test_config_invariants.py @@ -78,9 +78,6 @@ def test_networking(spec, state): assert spec.config.MIN_EPOCHS_FOR_BLOCK_REQUESTS == ( spec.config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY + spec.config.CHURN_LIMIT_QUOTIENT // 2 ) - assert spec.config.ATTESTATION_SUBNET_PREFIX_BITS == ( - spec.ceillog2(spec.config.ATTESTATION_SUBNET_COUNT) + spec.config.ATTESTATION_SUBNET_EXTRA_BITS - ) assert spec.config.SUBNETS_PER_NODE <= spec.config.ATTESTATION_SUBNET_COUNT node_id_length = spec.NodeID(1).type_byte_length() # in bytes assert node_id_length * 8 == spec.NODE_ID_BITS # in bits diff --git a/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py b/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py index f5f417bbaf..c8d220b379 100644 --- a/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py +++ b/tests/core/pyspec/eth2spec/test/phase0/unittests/validator/test_validator_unittest.py @@ -486,8 +486,7 @@ def test_get_aggregate_and_proof_signature(spec, state): def run_compute_subscribed_subnets_arguments(spec, rng=random.Random(1111)): node_id = rng.randint(0, 2**256 - 1) - epoch = rng.randint(0, 2**64 - 1) - subnets = spec.compute_subscribed_subnets(node_id, epoch) + subnets = spec.compute_subscribed_subnets(node_id) assert len(subnets) == spec.config.SUBNETS_PER_NODE