diff --git a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v1_node_health.json b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v1_node_health.json index 2efe4b39f74..0ec02da4584 100644 --- a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v1_node_health.json +++ b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/paths/_eth_v1_node_health.json @@ -26,7 +26,7 @@ "content" : { } }, "400" : { - "description" : "The request could not be processed, check the response for more information.", + "description" : "Invalid syncing status code", "content" : { "application/json" : { "schema" : { diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealth.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealth.java index dae10871222..8a0540a0ca2 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealth.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealth.java @@ -22,11 +22,13 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.javalin.http.Header; +import java.util.Optional; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import tech.pegasys.teku.api.ChainDataProvider; import tech.pegasys.teku.api.DataProvider; import tech.pegasys.teku.api.SyncDataProvider; +import tech.pegasys.teku.api.exceptions.BadRequestException; import tech.pegasys.teku.infrastructure.restapi.endpoints.EndpointMetadata; import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiEndpoint; import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; @@ -53,6 +55,7 @@ public GetHealth(final DataProvider provider) { .response(SC_OK, "Node is ready") .response(SC_PARTIAL_CONTENT, "Node is syncing but can serve incomplete data") .response(SC_SERVICE_UNAVAILABLE, "Node not initialized or having issues") + .withBadRequestResponse(Optional.of("Invalid syncing status code")) .build()); this.syncProvider = syncProvider; this.chainDataProvider = chainDataProvider; @@ -72,7 +75,13 @@ public void handleRequest(RestApiRequest request) throws JsonProcessingException private int getResponseCodeFromQueryParams(final RestApiRequest request) { try { - return request.getOptionalQueryParameter(SYNCING_PARAMETER).orElse(SC_PARTIAL_CONTENT); + final int responseCode = + request.getOptionalQueryParameter(SYNCING_PARAMETER).orElse(SC_PARTIAL_CONTENT); + if (responseCode < 100 || responseCode > 599) { + throw new BadRequestException("Invalid syncing status code"); + } else { + return responseCode; + } } catch (IllegalArgumentException ex) { LOG.trace("Illegal parameter in GetHealth", ex); } diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java index 60a92fdfcd9..fbc17089965 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java @@ -15,6 +15,7 @@ import static jakarta.servlet.http.HttpServletResponse.SC_CONTINUE; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.Mockito.when; import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; @@ -28,6 +29,9 @@ import com.fasterxml.jackson.core.JsonProcessingException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import tech.pegasys.teku.api.exceptions.BadRequestException; import tech.pegasys.teku.beacon.sync.events.SyncState; import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; @@ -111,6 +115,18 @@ public void shouldReturnUnavailableWhenStoreNotAvailable() throws Exception { assertThat(request.getResponseCode()).isEqualTo(SC_SERVICE_UNAVAILABLE); } + @ParameterizedTest(name = "syncingStatus: {0}") + @ValueSource(ints = {98, 600}) + public void shouldThrowBadRequestWhenInvalidSyncingStatusOutsideBounds(final int syncingStatus) { + when(chainDataProvider.isStoreAvailable()).thenReturn(true); + when(syncService.getCurrentSyncState()).thenReturn(SyncState.SYNCING); + request.setOptionalQueryParameter(SYNCING_STATUS, String.valueOf(syncingStatus)); + + assertThatThrownBy(() -> handler.handleRequest(request)) + .isInstanceOf(BadRequestException.class) + .hasMessageContaining("Invalid syncing status code"); + } + @Test void metadata_shouldHandle400() throws JsonProcessingException { verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/P2PConfig.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/P2PConfig.java index 02aece90761..1edeac1a496 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/P2PConfig.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/P2PConfig.java @@ -15,6 +15,7 @@ import static com.google.common.base.Preconditions.checkNotNull; +import java.time.Duration; import java.util.OptionalInt; import java.util.function.Consumer; import tech.pegasys.teku.infrastructure.exceptions.InvalidConfigurationException; @@ -25,6 +26,7 @@ import tech.pegasys.teku.networking.p2p.network.config.NetworkConfig; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.config.NetworkingSpecConfig; +import tech.pegasys.teku.spec.config.SpecConfig; public class P2PConfig { @@ -182,14 +184,21 @@ public P2PConfig build() { isGossipScoringEnabled ? GossipConfigurator.scoringEnabled(spec) : GossipConfigurator.NOOP; + final SpecConfig specConfig = spec.getGenesisSpecConfig(); final Eth2Context eth2Context = Eth2Context.builder() - .activeValidatorCount(spec.getGenesisSpecConfig().getMinGenesisActiveValidatorCount()) + .activeValidatorCount(specConfig.getMinGenesisActiveValidatorCount()) .gossipEncoding(gossipEncoding) .build(); - networkConfig.gossipConfig(c -> gossipConfigurator.configure(c, eth2Context)); - - NetworkConfig networkConfig = this.networkConfig.build(); + networkConfig.gossipConfig( + builder -> { + gossipConfigurator.configure(builder, eth2Context); + builder.seenTTL( + Duration.ofSeconds( + (long) specConfig.getSecondsPerSlot() * specConfig.getSlotsPerEpoch() * 2)); + }); + + final NetworkConfig networkConfig = this.networkConfig.build(); discoveryConfig.listenUdpPortDefault(networkConfig.getListenPort()); discoveryConfig.advertisedUdpPortDefault(OptionalInt.of(networkConfig.getAdvertisedPort()));