Skip to content

Commit

Permalink
Add cli option to override the altair fork block and enable it (#3961)
Browse files Browse the repository at this point in the history
  • Loading branch information
ajsutton authored May 10, 2021
1 parent fe1c983 commit 7f81050
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private TekuNode(final SimpleHttpClient httpClient, final Network network, final
super(network, TEKU_DOCKER_IMAGE, LOG);
this.httpClient = httpClient;
this.config = config;
this.spec = SpecFactory.getDefault().create(config.getNetworkName());
this.spec = SpecFactory.create(config.getNetworkName());

container
.withWorkingDirectory(WORKING_DIRECTORY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class Eth2NetworkConfiguration {
private final int startupTargetPeerCount;
private final int startupTimeoutSeconds;
private final List<String> discoveryBootnodes;
private final Optional<UInt64> altairForkSlot;
private final Eth1Address eth1DepositContractAddress;
private final Optional<UInt64> eth1DepositContractDeployBlock;
private final boolean balanceAttackMitigationEnabled;
Expand All @@ -57,14 +58,16 @@ private Eth2NetworkConfiguration(
final List<String> discoveryBootnodes,
final Eth1Address eth1DepositContractAddress,
final Optional<UInt64> eth1DepositContractDeployBlock,
final boolean balanceAttackMitigationEnabled) {
final boolean balanceAttackMitigationEnabled,
final Optional<UInt64> altairForkSlot) {
this.spec = spec;
this.constants = constants;
this.initialState = initialState;
this.usingCustomInitialState = usingCustomInitialState;
this.startupTargetPeerCount = startupTargetPeerCount;
this.startupTimeoutSeconds = startupTimeoutSeconds;
this.discoveryBootnodes = discoveryBootnodes;
this.altairForkSlot = altairForkSlot;
this.eth1DepositContractAddress =
eth1DepositContractAddress == null
? new Eth1Address(spec.getGenesisSpecConfig().getDepositContractAddress())
Expand Down Expand Up @@ -130,6 +133,10 @@ public boolean isBalanceAttackMitigationEnabled() {
return balanceAttackMitigationEnabled;
}

public Optional<UInt64> getAltairForkSlot() {
return altairForkSlot;
}

@Override
public String toString() {
return constants;
Expand All @@ -145,11 +152,12 @@ public static class Builder {
private Eth1Address eth1DepositContractAddress;
private Optional<UInt64> eth1DepositContractDeployBlock = Optional.empty();
private boolean balanceAttackMitigationEnabled = false;
private Optional<UInt64> altairForkSlot = Optional.empty();

public Eth2NetworkConfiguration build() {
checkNotNull(constants, "Missing constants");

final Spec spec = SpecFactory.getDefault().create(constants);
final Spec spec = SpecFactory.create(constants, altairForkSlot);
// if the deposit contract was not set, default from constants
if (eth1DepositContractAddress == null) {
eth1DepositContractAddress(
Expand All @@ -165,7 +173,8 @@ public Eth2NetworkConfiguration build() {
discoveryBootnodes,
eth1DepositContractAddress,
eth1DepositContractDeployBlock,
balanceAttackMitigationEnabled);
balanceAttackMitigationEnabled,
altairForkSlot);
}

public Builder constants(final String constants) {
Expand Down Expand Up @@ -228,6 +237,11 @@ public Builder balanceAttackMitigationEnabled(final boolean balanceAttackMitigat
return this;
}

public Builder altairForkSlot(final UInt64 altairForkSlot) {
this.altairForkSlot = Optional.of(altairForkSlot);
return this;
}

public Builder applyNetworkDefaults(final String networkName) {
Eth2Network.fromStringLenient(networkName)
.ifPresentOrElse(this::applyNetworkDefaults, () -> reset().constants(networkName));
Expand Down
34 changes: 21 additions & 13 deletions ethereum/spec/src/main/java/tech/pegasys/teku/spec/SpecFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,35 @@

package tech.pegasys.teku.spec;

import java.util.Optional;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.config.SpecConfig;
import tech.pegasys.teku.spec.config.SpecConfigBuilder;
import tech.pegasys.teku.spec.config.SpecConfigLoader;

public interface SpecFactory {
SpecFactory PHASE0 = new Phase0SpecFactory();
public class SpecFactory {

static SpecFactory getDefault() {
return PHASE0;
public static Spec create(String configName) {
return create(configName, Optional.empty());
}

default Spec create(String configName) {
return create(SpecConfigLoader.loadConfig(configName));
public static Spec create(String configName, final Optional<UInt64> altairForkSlot) {
final SpecConfig config =
SpecConfigLoader.loadConfig(
configName,
builder ->
altairForkSlot.ifPresent(forkSlot -> overrideAltairForkSlot(builder, forkSlot)));
return create(config, altairForkSlot);
}

Spec create(SpecConfig config);

class Phase0SpecFactory implements SpecFactory {
private static void overrideAltairForkSlot(
final SpecConfigBuilder builder, final UInt64 forkSlot) {
builder.altairBuilder(altairBuilder -> altairBuilder.altairForkSlot(forkSlot));
}

@Override
public Spec create(SpecConfig config) {
return Spec.create(config, SpecMilestone.PHASE0);
}
public static Spec create(final SpecConfig config, final Optional<UInt64> altairForkSlot) {
final SpecMilestone highestMilestoneSupported =
altairForkSlot.map(__ -> SpecMilestone.ALTAIR).orElse(SpecMilestone.PHASE0);
return Spec.create(config, highestMilestoneSupported);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import tech.pegasys.teku.infrastructure.io.resource.ResourceLoader;
import tech.pegasys.teku.spec.networks.Eth2Network;
Expand All @@ -28,9 +29,14 @@
public class SpecConfigLoader {

public static SpecConfig loadConfig(final String configName) {
return loadConfig(configName, __ -> {});
}

public static SpecConfig loadConfig(
final String configName, final Consumer<SpecConfigBuilder> modifier) {
final SpecConfigReader reader = new SpecConfigReader();
processConfig(configName, reader::read);
return reader.build();
return reader.build(modifier);
}

public static SpecConfig loadConfig(final Map<String, ?> config) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public Map<UInt64, SyncSubcommitteeAssignments> getSyncSubcommittees(
final UInt64 currentSyncCommitteePeriod = computeSyncCommitteePeriod(currentEpoch);
checkArgument(
isStateUsableForCommitteeCalculationAtEpoch(state, epoch),
"State must be in the same or previous sync committee period. Cannot calculate epoch {} from state at slot {}",
"State must be in the same or previous sync committee period. Cannot calculate epoch %s from state at slot %s",
epoch,
state.getSlot());
final BeaconStateAltair altairState = BeaconStateAltair.required(state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ public class SpecFactoryTest {

@Test
public void defaultFactoryShouldOnlySupportPhase0_mainnet() {
final Spec spec = SpecFactory.getDefault().create("mainnet");
final Spec spec = SpecFactory.create("mainnet");
assertThat(spec.getForkSchedule().getSupportedMilestones())
.containsExactly(SpecMilestone.PHASE0);
}

@ParameterizedTest(name = "{0}")
@MethodSource("getKnownConfigNames")
public void defaultFactoryShouldOnlySupportPhase0(final String configName) {
final Spec spec = SpecFactory.getDefault().create(configName);
final Spec spec = SpecFactory.create(configName);
assertThat(spec.getForkSchedule().getSupportedMilestones())
.containsExactly(SpecMilestone.PHASE0);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.infrastructure.logging.ColorConsolePrinter.Color;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;

public class StatusLogger {
Expand All @@ -47,6 +48,13 @@ public void onStartup(final String version) {
+ "You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0");
}

public void warnForkSlotChanged(final String milestoneName, final UInt64 newSlot) {
log.warn(
print(
milestoneName + " configuration has been overridden to activate at slot " + newSlot,
Color.YELLOW));
}

public void fatalError(final String description, final Throwable cause) {
log.fatal("Exiting due to fatal error in {}", description, cause);
}
Expand Down
10 changes: 10 additions & 0 deletions teku/src/main/java/tech/pegasys/teku/AbstractNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import tech.pegasys.teku.service.serviceutils.ServiceConfig;
import tech.pegasys.teku.service.serviceutils.layout.DataDirLayout;
import tech.pegasys.teku.services.ServiceController;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.util.config.Constants;

public abstract class AbstractNode implements Node {
Expand All @@ -56,6 +57,7 @@ protected AbstractNode(final TekuConfiguration tekuConfig) {
LoggingConfigurator.update(tekuConfig.loggingConfig());

STATUS_LOG.onStartup(VersionProvider.VERSION);
reportForkSlotOverrides(tekuConfig);
this.metricsEndpoint = new MetricsEndpoint(tekuConfig.metricsConfig(), vertx);
final MetricsSystem metricsSystem = metricsEndpoint.getMetricsSystem();
final TekuDefaultExceptionHandler subscriberExceptionHandler =
Expand All @@ -75,6 +77,14 @@ protected AbstractNode(final TekuConfiguration tekuConfig) {
Constants.setConstants(tekuConfig.eth2NetworkConfiguration().getConstants());
}

private void reportForkSlotOverrides(final TekuConfiguration tekuConfig) {
tekuConfig
.eth2NetworkConfiguration()
.getAltairForkSlot()
.ifPresent(
forkSlot -> STATUS_LOG.warnForkSlotChanged(SpecMilestone.ALTAIR.name(), forkSlot));
}

protected abstract ServiceController getServiceController();

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import picocli.CommandLine;
import picocli.CommandLine.Option;
import tech.pegasys.teku.config.TekuConfiguration;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.networks.Eth2NetworkConfiguration;

public class Eth2NetworkOptions {
Expand Down Expand Up @@ -47,6 +48,14 @@ public class Eth2NetworkOptions {
arity = "1")
private String eth1DepositContractAddress = null; // Depends on network configuration

@Option(
names = {"--Xnetwork-altair-fork-slot"},
hidden = true,
paramLabel = "<slot>",
description = "Override the Altair fork activation slot.",
arity = "1")
private UInt64 altairForkSlot;

@Option(
names = {"--Xstartup-target-peer-count"},
paramLabel = "<NUMBER>",
Expand Down Expand Up @@ -134,5 +143,8 @@ private void configureEth2Network(Eth2NetworkConfiguration.Builder builder) {
if (forkChoiceBalanceAttackMitigationEnabled != null) {
builder.balanceAttackMitigationEnabled(forkChoiceBalanceAttackMitigationEnabled);
}
if (altairForkSlot != null) {
builder.altairForkSlot(altairForkSlot);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ private Spec getSpec() {
return apiClient
.getConfigSpec()
.map(response -> SpecConfigLoader.loadConfig(response.data))
.map(specConfig -> SpecFactory.getDefault().create(specConfig))
.map(specConfig -> SpecFactory.create(specConfig, Optional.empty()))
.orElseThrow();
} catch (Exception ex) {
SUB_COMMAND_LOG.error(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2021 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package tech.pegasys.teku.cli.options;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import tech.pegasys.teku.cli.AbstractBeaconNodeCommandTest;
import tech.pegasys.teku.config.TekuConfiguration;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;

class Eth2NetworkOptionsTest extends AbstractBeaconNodeCommandTest {
@Test
void shouldNotEnableAltairByDefault() {
final TekuConfiguration config = getTekuConfigurationFromArguments();
final Spec spec = config.eth2NetworkConfiguration().getSpec();
assertThat(spec.getForkSchedule().getHighestSupportedMilestone())
.isEqualTo(SpecMilestone.PHASE0);
}

@Test
void shouldUseAltairForkBlockIfSpecified() {
final TekuConfiguration config =
getTekuConfigurationFromArguments("--Xnetwork-altair-fork-slot", "64");
final Spec spec = config.eth2NetworkConfiguration().getSpec();
assertThat(spec.getForkSchedule().getSpecMilestoneAtSlot(UInt64.valueOf(64)))
.isEqualTo(SpecMilestone.ALTAIR);
}
}

0 comments on commit 7f81050

Please sign in to comment.