Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

removed requirement for block headers in voluntary exit #8461

Merged
merged 6 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,13 @@
import tech.pegasys.teku.cli.BeaconNodeCommand;
import tech.pegasys.teku.infrastructure.json.JsonUtil;
import tech.pegasys.teku.infrastructure.logging.LoggingConfigurator;
import tech.pegasys.teku.infrastructure.time.SystemTimeProvider;
import tech.pegasys.teku.infrastructure.time.TimeProvider;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.config.SpecConfig;
import tech.pegasys.teku.spec.constants.Domain;
import tech.pegasys.teku.spec.datastructures.operations.SignedVoluntaryExit;
import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers;
Expand Down Expand Up @@ -110,7 +114,6 @@ public class VoluntaryExitCommandTest {
@BeforeEach
public void setup(final ClientAndServer server) throws IOException {
this.mockBeaconServer = server;
configureSuccessfulHeadResponse(mockBeaconServer);
configureSuccessfulGenesisResponse(mockBeaconServer);
configureSuccessfulValidatorResponses(mockBeaconServer);
originalSystemIn = System.in;
Expand Down Expand Up @@ -365,7 +368,7 @@ void shouldExitFailureWithNoValidatorKeysFound() throws JsonProcessingException
}

@Test
void shouldExitFailureFutureEpoch() throws JsonProcessingException {
void shouldExitFailureFutureEpoch() throws IOException {
configureSuccessfulSpecResponse(mockBeaconServer);

final List<String> args = getCommandArguments(false, true, List.of("--epoch=1024"));
Expand All @@ -376,6 +379,26 @@ void shouldExitFailureFutureEpoch() throws JsonProcessingException {
.contains("The specified epoch 1024 is greater than current epoch");
}

@Test
void shouldCreateExitForFutureEpochIfOutputFolderDefined(@TempDir final Path tempDir)
throws IOException {
configureSuccessfulSpecResponse(mockBeaconServer, TestSpecFactory.createMinimalCapella());
final List<String> args = new ArrayList<>();
args.addAll(commandArgs);
args.addAll(
List.of(
"--epoch",
"1024",
"--validator-public-keys",
validatorPubKey1,
"--save-exits-path",
tempDir.toAbsolutePath().toString()));

beaconNodeCommand.parse(args.toArray(new String[0]));
final String outString = stdOut.toString(UTF_8);
assertThat(StringUtils.countMatches(outString, "Writing signed exit for")).isEqualTo(1);
}

@Test
void shouldUseCurrentForkDomainForSignatureBeforeDeneb() throws JsonProcessingException {
setUserInput("yes");
Expand Down Expand Up @@ -464,23 +487,21 @@ private void configureSuccessfulSpecResponse(
.respond(response().withStatusCode(200).withBody(getTestSpecJsonString(spec)));
}

private void configureSuccessfulHeadResponse(final ClientAndServer mockBeaconServer)
throws IOException {
final String testHead =
Resources.toString(
Resources.getResource("tech/pegasys/teku/cli/subcommand/voluntary-exit/head.json"),
UTF_8);
mockBeaconServer
.when(request().withPath("/eth/v1/beacon/headers/head"))
.respond(response().withStatusCode(200).withBody(testHead));
}
private void configureSuccessfulGenesisResponse(final ClientAndServer mockBeaconServer) {
final TimeProvider timeProvider = new SystemTimeProvider();
final SpecConfig config = spec.getGenesisSpec().getConfig();
final UInt64 genesisTime =
timeProvider
.getTimeInSeconds()
.minus(1020L * config.getSecondsPerSlot() * config.getSlotsPerEpoch());

private void configureSuccessfulGenesisResponse(final ClientAndServer mockBeaconServer)
throws IOException {
final String testHead =
Resources.toString(
Resources.getResource("tech/pegasys/teku/cli/subcommand/voluntary-exit/genesis.json"),
UTF_8);
String.format(
"{ \"data\": {\"genesis_time\": \"%s\","
+ "\"genesis_validators_root\": \"0xf03f804ff1c97ada13050eb617e66e88e1199c2ce1be0b6b27e36fafb8d3ee48\","
+ "\"genesis_fork_version\": \"0x00004105\"}}",
genesisTime);

mockBeaconServer
.when(request().withPath("/eth/v1/beacon/genesis"))
.respond(response().withStatusCode(200).withBody(testHead));
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
import tech.pegasys.teku.infrastructure.json.JsonUtil;
import tech.pegasys.teku.infrastructure.logging.SubCommandLogger;
import tech.pegasys.teku.infrastructure.logging.ValidatorLogger;
import tech.pegasys.teku.infrastructure.time.SystemTimeProvider;
import tech.pegasys.teku.infrastructure.time.TimeProvider;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.service.serviceutils.layout.DataDirLayout;
import tech.pegasys.teku.spec.Spec;
Expand Down Expand Up @@ -102,6 +104,7 @@ public class VoluntaryExitCommand implements Callable<Integer> {
private TekuConfiguration config;
private final MetricsSystem metricsSystem = new NoOpMetricsSystem();
private Spec spec;
private final TimeProvider timeProvider = new SystemTimeProvider();

static final String WITHDRAWALS_PERMANENT_MESASGE =
"These validators won't be able to be re-activated once this operation is complete.";
Expand Down Expand Up @@ -355,14 +358,12 @@ private String prettyExitMessage(
});
}

private Optional<UInt64> getEpoch() {
return apiClient
.getBlockHeader("head")
.map(response -> spec.computeEpochAtSlot(response.data.header.message.slot));
}

private Optional<Bytes32> getGenesisRoot() {
return typeDefClient.getGenesis().map(GenesisData::getGenesisValidatorsRoot);
private UInt64 getEpochFromGenesisData(final GenesisData genesisData) {
final UInt64 genesisTime = genesisData.getGenesisTime();
final UInt64 currentTime = timeProvider.getTimeInSeconds();
final UInt64 slot =
spec.getGenesisSpec().miscHelpers().computeSlotAtTime(genesisTime, currentTime);
return spec.computeEpochAtSlot(slot);
}

private void initialise() {
Expand Down Expand Up @@ -400,11 +401,12 @@ private void initialise() {
spec = SpecFactory.create(network);
}

validateOrDefaultEpoch();
final Optional<GenesisData> maybeGenesisData = typeDefClient.getGenesis();
validateOrDefaultEpoch(maybeGenesisData);
fork = spec.getForkSchedule().getFork(epoch);

// get genesis time
final Optional<Bytes32> maybeRoot = getGenesisRoot();
final Optional<Bytes32> maybeRoot = maybeGenesisData.map(GenesisData::getGenesisValidatorsRoot);
if (maybeRoot.isEmpty()) {
throw new InvalidConfigurationException(
"Unable to fetch genesis data, cannot generate an exit.");
Expand Down Expand Up @@ -462,8 +464,8 @@ private void initialise() {
}
}

private void validateOrDefaultEpoch() {
final Optional<UInt64> maybeEpoch = getEpoch();
private void validateOrDefaultEpoch(final Optional<GenesisData> maybeGenesisData) {
final Optional<UInt64> maybeEpoch = maybeGenesisData.map(this::getEpochFromGenesisData);

if (epoch == null) {
if (maybeEpoch.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import static java.util.Collections.emptyMap;
import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_NOT_FOUND;
import static tech.pegasys.teku.validator.remote.apiclient.ValidatorApiMethod.GET_AGGREGATE;
import static tech.pegasys.teku.validator.remote.apiclient.ValidatorApiMethod.GET_BLOCK_HEADER;
import static tech.pegasys.teku.validator.remote.apiclient.ValidatorApiMethod.GET_GENESIS;
import static tech.pegasys.teku.validator.remote.apiclient.ValidatorApiMethod.GET_PROPOSER_DUTIES;
import static tech.pegasys.teku.validator.remote.apiclient.ValidatorApiMethod.GET_SYNC_COMMITTEE_CONTRIBUTION;
Expand Down Expand Up @@ -52,7 +51,6 @@
import org.apache.logging.log4j.Logger;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.api.request.v1.validator.BeaconCommitteeSubscriptionRequest;
import tech.pegasys.teku.api.response.v1.beacon.GetBlockHeaderResponse;
import tech.pegasys.teku.api.response.v1.beacon.GetGenesisResponse;
import tech.pegasys.teku.api.response.v1.beacon.GetStateValidatorsResponse;
import tech.pegasys.teku.api.response.v1.beacon.PostDataFailureResponse;
Expand Down Expand Up @@ -96,15 +94,6 @@ public Optional<GetGenesisResponse> getGenesis() {
return get(GET_GENESIS, EMPTY_MAP, createHandler(GetGenesisResponse.class));
}

public Optional<GetBlockHeaderResponse> getBlockHeader(final String blockId) {
return get(
GET_BLOCK_HEADER,
Map.of("block_id", blockId),
EMPTY_MAP,
EMPTY_MAP,
createHandler(GetBlockHeaderResponse.class));
}

/**
* <a
* href="https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Beacon/getStateValidators">GET
Expand Down