From 0a86ab4b59a71530cfb7f7188495b089f02acac2 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 7 Nov 2023 12:49:20 +1100 Subject: [PATCH 1/6] Introduce a shuffling prefix for subnet determination --- specs/phase0/p2p-interface.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index a374443b8c..00e6ee86da 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -203,7 +203,8 @@ This section outlines configurations that are used in this spec. | `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)` | | +| `ATTESTATION_SUBNET_PREFIX_BITS` | `int(ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS)` | +| `ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS` | `3` | The number of bits used to shuffle nodes to a new subnet within `EPOCHS_PER_SUBNET_SUBSCRIPTION` | | ### MetaData @@ -1013,7 +1014,8 @@ Because Phase 0 does not have shards and thus does not have Shard Committees, th ```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 + shuffling_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) + node_offset = (shuffling_prefix + (shuffling_prefix * (EPOCHS_PER_SUBNET_SUBSCRIPTION // 1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS))) % 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, From ec9fbf24a266f2d98131204d487d0ac704cfe23b Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 8 Nov 2023 12:00:10 +1100 Subject: [PATCH 2/6] Split the bits in the calculation to clarify the logic --- specs/phase0/p2p-interface.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 00e6ee86da..35df0f3589 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -1013,12 +1013,12 @@ Because Phase 0 does not have shards and thus does not have Shard Committees, th ```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) - shuffling_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) - node_offset = (shuffling_prefix + (shuffling_prefix * (EPOCHS_PER_SUBNET_SUBSCRIPTION // 1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS))) % EPOCHS_PER_SUBNET_SUBSCRIPTION - permutation_seed = hash(uint_to_bytes(uint64((epoch + node_offset) // EPOCHS_PER_SUBNET_SUBSCRIPTION))) + subnet_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS) + shuffling_bits = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) % (1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) + epoch_transition = (subnet_prefix + (shuffling_bits * (EPOCHS_PER_SUBNET_SUBSCRIPTION >> ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS))) % EPOCHS_PER_SUBNET_SUBSCRIPTION + permutation_seed = hash(uint_to_bytes(uint64((epoch + epoch_transition) // EPOCHS_PER_SUBNET_SUBSCRIPTION))) permutated_prefix = compute_shuffled_index( - node_id_prefix, + subnet_prefix, 1 << ATTESTATION_SUBNET_PREFIX_BITS, permutation_seed, ) From 22def22367781c0a950f3f5a7f20567642efeacc Mon Sep 17 00:00:00 2001 From: Age Manning Date: Thu, 30 Nov 2023 12:44:45 +1100 Subject: [PATCH 3/6] Update specs/phase0/p2p-interface.md Co-authored-by: Divma <26765164+divagant-martian@users.noreply.github.com> --- specs/phase0/p2p-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 35df0f3589..85ee8f0ac9 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -1014,7 +1014,7 @@ Because Phase 0 does not have shards and thus does not have Shard Committees, th ```python def compute_subscribed_subnet(node_id: NodeID, epoch: Epoch, index: int) -> SubnetID: subnet_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS) - shuffling_bits = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) % (1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) + shuffling_bits = (node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS)) % (1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) epoch_transition = (subnet_prefix + (shuffling_bits * (EPOCHS_PER_SUBNET_SUBSCRIPTION >> ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS))) % EPOCHS_PER_SUBNET_SUBSCRIPTION permutation_seed = hash(uint_to_bytes(uint64((epoch + epoch_transition) // EPOCHS_PER_SUBNET_SUBSCRIPTION))) permutated_prefix = compute_shuffled_index( From 48e685c6fd188a327d14a43edd02110456822582 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Tue, 9 Jan 2024 23:14:21 +0800 Subject: [PATCH 4/6] Update config files --- configs/mainnet.yaml | 1 + configs/minimal.yaml | 1 + specs/phase0/p2p-interface.md | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configs/mainnet.yaml b/configs/mainnet.yaml index e0f9128b70..9da292e378 100644 --- a/configs/mainnet.yaml +++ b/configs/mainnet.yaml @@ -138,6 +138,7 @@ ATTESTATION_SUBNET_COUNT: 64 ATTESTATION_SUBNET_EXTRA_BITS: 0 # ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS ATTESTATION_SUBNET_PREFIX_BITS: 6 +ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS: 3 # Deneb # `2**7` (=128) diff --git a/configs/minimal.yaml b/configs/minimal.yaml index cdfbca3a2c..98ef69aac3 100644 --- a/configs/minimal.yaml +++ b/configs/minimal.yaml @@ -139,6 +139,7 @@ ATTESTATION_SUBNET_COUNT: 64 ATTESTATION_SUBNET_EXTRA_BITS: 0 # ceillog2(ATTESTATION_SUBNET_COUNT) + ATTESTATION_SUBNET_EXTRA_BITS ATTESTATION_SUBNET_PREFIX_BITS: 6 +ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS: 3 # Deneb # `2**7` (=128) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index 85ee8f0ac9..e93a838996 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -202,7 +202,7 @@ 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_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)` | | `ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS` | `3` | The number of bits used to shuffle nodes to a new subnet within `EPOCHS_PER_SUBNET_SUBSCRIPTION` | | From 2fe834694d47f0ff540ace7d1080365d7644eba0 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Mon, 15 Jan 2024 19:40:03 +1100 Subject: [PATCH 5/6] Add temporary values for lint --- specs/phase0/p2p-interface.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index e93a838996..d81f127a90 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -1014,8 +1014,10 @@ Because Phase 0 does not have shards and thus does not have Shard Committees, th ```python def compute_subscribed_subnet(node_id: NodeID, epoch: Epoch, index: int) -> SubnetID: subnet_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS) - shuffling_bits = (node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS)) % (1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) - epoch_transition = (subnet_prefix + (shuffling_bits * (EPOCHS_PER_SUBNET_SUBSCRIPTION >> ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS))) % EPOCHS_PER_SUBNET_SUBSCRIPTION + shuffling_bit_size = NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS + shuffling_bits = (node_id >> shuffling_bit_size) % (1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) + shuffling_multiplier = EPOCHS_PER_SUBNET_SUBSCRIPTION >> ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS + epoch_transition = (subnet_prefix + (shuffling_bits * shuffling_multiplier)) % EPOCHS_PER_SUBNET_SUBSCRIPTION permutation_seed = hash(uint_to_bytes(uint64((epoch + epoch_transition) // EPOCHS_PER_SUBNET_SUBSCRIPTION))) permutated_prefix = compute_shuffled_index( subnet_prefix, From 1ec248a19d579b54c22aedf578905ce337ab5d78 Mon Sep 17 00:00:00 2001 From: Hsiao-Wei Wang Date: Mon, 15 Jan 2024 23:27:00 +0800 Subject: [PATCH 6/6] Fix lint --- specs/phase0/p2p-interface.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/specs/phase0/p2p-interface.md b/specs/phase0/p2p-interface.md index d81f127a90..bfe51c70eb 100644 --- a/specs/phase0/p2p-interface.md +++ b/specs/phase0/p2p-interface.md @@ -1014,10 +1014,16 @@ Because Phase 0 does not have shards and thus does not have Shard Committees, th ```python def compute_subscribed_subnet(node_id: NodeID, epoch: Epoch, index: int) -> SubnetID: subnet_prefix = node_id >> (NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS) - shuffling_bit_size = NODE_ID_BITS - ATTESTATION_SUBNET_PREFIX_BITS - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS + shuffling_bit_size = ( + NODE_ID_BITS + - ATTESTATION_SUBNET_PREFIX_BITS + - ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS + ) shuffling_bits = (node_id >> shuffling_bit_size) % (1 << ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS) shuffling_multiplier = EPOCHS_PER_SUBNET_SUBSCRIPTION >> ATTESTATION_SUBNET_SHUFFLING_PREFIX_BITS - epoch_transition = (subnet_prefix + (shuffling_bits * shuffling_multiplier)) % EPOCHS_PER_SUBNET_SUBSCRIPTION + epoch_transition = ( + (subnet_prefix + (shuffling_bits * shuffling_multiplier)) % EPOCHS_PER_SUBNET_SUBSCRIPTION + ) permutation_seed = hash(uint_to_bytes(uint64((epoch + epoch_transition) // EPOCHS_PER_SUBNET_SUBSCRIPTION))) permutated_prefix = compute_shuffled_index( subnet_prefix,