Skip to content

Commit

Permalink
calculate subscribed subnet from node id
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdi-aouadi committed Jul 7, 2023
1 parent bb09ea1 commit e0757bd
Show file tree
Hide file tree
Showing 35 changed files with 118 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ public Map<String, String> getConfigMap() {

configAttributes.put("BLS_WITHDRAWAL_PREFIX", getBlsWithdrawalPrefix().toHexString());
configAttributes.put("TARGET_AGGREGATORS_PER_COMMITTEE", getTargetAggregatorsPerCommittee());
configAttributes.put("RANDOM_SUBNETS_PER_VALIDATOR", getRandomSubnetsPerValidator());
configAttributes.put("SUBNETS_PER_NODE", getSubnetsPerNode());
configAttributes.put(
"EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION", getEpochsPerRandomSubnetSubscription());
Expand Down Expand Up @@ -106,10 +105,6 @@ private String getMaxRequestBlocks() {
return Integer.toString(specConfig.getNetworkingConfig().getMaxRequestBlocks());
}

private String getRandomSubnetsPerValidator() {
return Integer.toString(ValidatorConstants.RANDOM_SUBNETS_PER_VALIDATOR);
}

private String getTtfbTimeout() {
return Integer.toString(specConfig.getNetworkingConfig().getTtfbTimeout());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 2
ETH1_FOLLOW_DISTANCE: 16
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ public class SpecConfigReader {
// Phase0 constants which may exist in legacy config files, but should now be ignored
"BLS_WITHDRAWAL_PREFIX",
"TARGET_AGGREGATORS_PER_COMMITTEE",
"RANDOM_SUBNETS_PER_VALIDATOR",
"EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION",
"DOMAIN_BEACON_PROPOSER",
"DOMAIN_BEACON_ATTESTER",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
public class ValidatorConstants {
// Phase0
public static final int TARGET_AGGREGATORS_PER_COMMITTEE = 16;
public static final int RANDOM_SUBNETS_PER_VALIDATOR = 1;
public static final int NODE_ID_BITS = 256;
// Altair
public static final int TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE = 16;
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 1024
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 6 (estimate from xDai mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@
"PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR": "2",
"PROPOSER_REWARD_QUOTIENT": "8",
"PROPOSER_SCORE_BOOST": "70",
"RANDOM_SUBNETS_PER_VALIDATOR": "1",
"SAFE_SLOTS_TO_UPDATE_JUSTIFIED": "8",
"SECONDS_PER_ETH1_BLOCK": "14",
"SECONDS_PER_SLOT": "12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
"PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX": "3",
"PROPOSER_REWARD_QUOTIENT": "8",
"PROPOSER_SCORE_BOOST": "70",
"RANDOM_SUBNETS_PER_VALIDATOR": "1",
"SAFE_SLOTS_TO_UPDATE_JUSTIFIED": "8",
"SECONDS_PER_ETH1_BLOCK": "14",
"SECONDS_PER_SLOT": "12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 2
ETH1_FOLLOW_DISTANCE: 16
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 8
ETH1_FOLLOW_DISTANCE: 2048
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ SAFE_SLOTS_TO_UPDATE_JUSTIFIED: 2
ETH1_FOLLOW_DISTANCE: 16
# 2**4 (= 16)
TARGET_AGGREGATORS_PER_COMMITTEE: 16
# 2**0 (= 1)
RANDOM_SUBNETS_PER_VALIDATOR: 1
# 2**8 (= 256)
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION: 256
# 14 (estimate from Eth1 mainnet)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
"PROPORTIONAL_SLASHING_MULTIPLIER_MERGE": "3",
"PROPOSER_REWARD_QUOTIENT": "8",
"PROPOSER_SCORE_BOOST": "70",
"RANDOM_SUBNETS_PER_VALIDATOR": "1",
"SAFE_SLOTS_TO_UPDATE_JUSTIFIED": "8",
"SECONDS_PER_ETH1_BLOCK": "14",
"SECONDS_PER_SLOT": "12",
Expand Down
1 change: 1 addition & 0 deletions networking/eth2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies {
implementation 'io.libp2p:jvm-libp2p-minimal'
implementation 'org.apache.tuweni:tuweni-ssz'
implementation 'org.xerial.snappy:snappy-java'
implementation 'tech.pegasys.discovery:discovery'

testImplementation testFixtures(project(':infrastructure:metrics'))
testImplementation testFixtures(project(':ethereum:spec'))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,29 @@
import static java.lang.Integer.max;
import static java.lang.Integer.min;
import static java.util.Collections.emptySet;
import static tech.pegasys.teku.spec.logic.common.helpers.MathHelpers.uint64ToBytes;

import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.math.BigInteger;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NavigableSet;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
import org.bouncycastle.math.ec.ECPoint;
import org.ethereum.beacon.discovery.util.Functions;
import tech.pegasys.teku.infrastructure.crypto.Hash;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.config.SpecConfig;
Expand All @@ -49,18 +58,28 @@ public class ValidatorBasedStableSubnetSubscriber implements StableSubnetSubscri
private final Spec spec;
private final int minimumSubnetSubscriptions;
private final int attestationSubnetCount;
private final int attestationSubnetPrefixBits;
private final int epochsPerSubnetSubscription;
private final int subnetsPerNode;

private final Optional<Bytes> discoveryNodeId;

public ValidatorBasedStableSubnetSubscriber(
final AttestationTopicSubscriber persistentSubnetSubscriber,
final Random random,
final Spec spec,
final int minimumSubnetSubscriptions) {
final int minimumSubnetSubscriptions,
final Optional<Bytes> discoveryNodeId) {
this.persistentSubnetSubscriber = persistentSubnetSubscriber;
this.random = random;
this.spec = spec;
this.attestationSubnetCount = spec.getNetworkingConfig().getAttestationSubnetCount();
this.attestationSubnetPrefixBits = spec.getNetworkingConfig().getAttestationSubnetPrefixBits();
this.epochsPerSubnetSubscription = spec.getNetworkingConfig().getEpochsPerSubnetSubscription();
this.subnetsPerNode = spec.getNetworkingConfig().getSubnetsPerNode();
IntStream.range(0, attestationSubnetCount).forEach(availableSubnetIndices::add);
this.minimumSubnetSubscriptions = min(minimumSubnetSubscriptions, attestationSubnetCount);
this.discoveryNodeId = discoveryNodeId;
}

@Override
Expand Down Expand Up @@ -95,9 +114,8 @@ public void onSlot(final UInt64 slot, final int validatorCount) {
private Set<SubnetSubscription> adjustNumberOfSubscriptionsToNumberOfValidators(
UInt64 currentSlot, int validatorCount) {

final int randomSubnetsPerValidator = ValidatorConstants.RANDOM_SUBNETS_PER_VALIDATOR;
final int requiredSubnetSubscriptions =
min(attestationSubnetCount, randomSubnetsPerValidator * validatorCount);
min(attestationSubnetCount, subnetsPerNode * validatorCount);
final int totalNumberOfSubscriptions =
max(requiredSubnetSubscriptions, minimumSubnetSubscriptions);

Expand All @@ -108,7 +126,14 @@ private Set<SubnetSubscription> adjustNumberOfSubscriptionsToNumberOfValidators(
"Updating number of persistent subnet subscriptions from {} to {}",
subnetSubscriptions.size(),
totalNumberOfSubscriptions);
final Set<SubnetSubscription> newSubnetSubscriptions = new HashSet<>();

final List<UInt64> subscribedSubnets =
computeSubscribedSubnets(extractNodeId(), spec.computeEpochAtSlot(currentSlot));

final Set<SubnetSubscription> newSubnetSubscriptions =
subscribedSubnets.stream()
.map(subnetId -> subscribeToSubnet(currentSlot, subnetId.intValue()))
.collect(Collectors.toSet());

while (subnetSubscriptions.size() != totalNumberOfSubscriptions) {
if (subnetSubscriptions.size() < totalNumberOfSubscriptions) {
Expand All @@ -120,8 +145,43 @@ private Set<SubnetSubscription> adjustNumberOfSubscriptionsToNumberOfValidators(
return newSubnetSubscriptions;
}

private UInt256 extractNodeId() {
final ECPoint ecPoint =
Functions.publicKeyToPoint(
discoveryNodeId.orElseThrow(
() -> new IllegalArgumentException("Unable to get discovery node id")));
final Bytes pubKeyUncompressed = Bytes.wrap(ecPoint.getEncoded(false)).slice(1);
BigInteger nodeId = new BigInteger(pubKeyUncompressed.toArray());
return UInt256.valueOf(nodeId);
}

private List<UInt64> computeSubscribedSubnets(final UInt256 nodeId, final UInt64 epoch) {
return IntStream.range(0, subnetsPerNode)
.mapToObj(index -> computeSubscribedSubnet(nodeId, epoch, index))
.collect(Collectors.toList());
}

private UInt64 computeSubscribedSubnet(
final UInt256 nodeId, final UInt64 epoch, final int index) {

final int nodeIdPrefix =
nodeId.shiftRight(ValidatorConstants.NODE_ID_BITS - attestationSubnetPrefixBits).intValue();

final UInt64 nodeOffset = UInt64.valueOf(nodeId.mod(epochsPerSubnetSubscription).toLong());

final Bytes32 permutationSeed =
Hash.sha256(uint64ToBytes(epoch.plus(nodeOffset).dividedBy(epochsPerSubnetSubscription)));

final int permutedPrefix =
spec.atEpoch(epoch)
.miscHelpers()
.computeShuffledIndex(nodeIdPrefix, 1 << attestationSubnetPrefixBits, permutationSeed);

return UInt64.valueOf(permutedPrefix + index % attestationSubnetCount);
}

/**
* Subscribes to a new random subnetId, if any subnetID is available. Returns the new
* Subscribes to a new random subnetId, if any subnetId is available. Returns the new
* SubnetSubscription object.
*
* @param currentSlot the current slot
Expand All @@ -138,6 +198,14 @@ private SubnetSubscription subscribeToNewRandomSubnet(UInt64 currentSlot) {
return subnetSubscription;
}

private SubnetSubscription subscribeToSubnet(UInt64 currentSlot, int subnetId) {
availableSubnetIndices.remove(subnetId);
SubnetSubscription subnetSubscription =
new SubnetSubscription(subnetId, getRandomUnsubscriptionSlot(currentSlot));
subnetSubscriptions.add(subnetSubscription);
return subnetSubscription;
}

/** Unsubscribe from a random subnet */
private void unsubscribeFromRandomSubnet() {
SubnetSubscription subnetSubscription =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.networking.p2p.mock.MockNodeId;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.validator.SubnetSubscription;
Expand Down Expand Up @@ -197,6 +198,6 @@ private void assertSubnetsAreDistinct(Set<SubnetSubscription> subnetSubscription

private StableSubnetSubscriber createStableSubnetSubscriber() {
return new ValidatorBasedStableSubnetSubscriber(
validatorApiChannel, new Random(13241234L), spec, 0);
validatorApiChannel, new Random(13241234L), spec, 0, new MockNodeId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.junit.jupiter.api.Test;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.networking.eth2.Eth2P2PNetwork;
import tech.pegasys.teku.networking.p2p.mock.MockNodeId;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.TestSpecFactory;

Expand Down Expand Up @@ -58,6 +59,7 @@ private ValidatorBasedStableSubnetSubscriber createSubscriber(
new AttestationTopicSubscriber(spec, network),
new Random(),
spec,
minimumSubnetSubscriptions);
minimumSubnetSubscriptions,
new MockNodeId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ public Optional<String> getEnr() {
return discoveryService.getEnr();
}

@Override
public Optional<Bytes> getDiscoveryNodeId() {
return discoveryService.getNodeId();
}

@Override
public Optional<String> getDiscoveryAddress() {
return discoveryService.getDiscoveryAddress();
Expand Down
Loading

0 comments on commit e0757bd

Please sign in to comment.