diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d7628c3eec..43ad1c5b977 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,13 @@ ## Unreleased Changes ### Breaking Changes +`--Xvalidators-builder-registration-default-gas-limit` is removed in favour of `--validators-builder-registration-default-gas-limit` ### Additions and Improvements +- Default the gas limit to 36 million for externally produced blocks - Optimized blobs validation pipeline +- Remove delay when fetching blobs from the local EL on block arrival -### Bug Fixes \ No newline at end of file +### Bug Fixes +- Fix `--version` command output [#8960](https://github.com/Consensys/teku/issues/8960) +- Fix issue (introduced in `24.12.1`) with peer stability when the upperbound is set to a high number \ No newline at end of file diff --git a/acceptance-tests/build.gradle b/acceptance-tests/build.gradle index f732ec2b4fa..79b3c6f52c0 100644 --- a/acceptance-tests/build.gradle +++ b/acceptance-tests/build.gradle @@ -1,4 +1,6 @@ dependencies { + testImplementation 'io.tmio:tuweni-units' + acceptanceTestImplementation project(":infrastructure:bls") acceptanceTestImplementation project(':infrastructure:time') acceptanceTestImplementation project(':data:serializer') diff --git a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/LocalValidatorKeysAcceptanceTest.java b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/LocalValidatorKeysAcceptanceTest.java index ab9fd540dde..b5f75dc3f71 100644 --- a/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/LocalValidatorKeysAcceptanceTest.java +++ b/acceptance-tests/src/acceptance-test/java/tech/pegasys/teku/test/acceptance/LocalValidatorKeysAcceptanceTest.java @@ -83,7 +83,7 @@ void shouldMaintainValidatorsInMutableClient() throws Exception { api.assertLocalValidatorListing(validatorKeystores.getPublicKeys()); api.assertValidatorGasLimit( - validatorKeystores.getPublicKeys().get(1), UInt64.valueOf(30000000)); + validatorKeystores.getPublicKeys().get(1), UInt64.valueOf(36_000_000)); // generate voluntary exit api.generateVoluntaryExitAndCheckValidatorIndex(validatorKeystores.getPublicKeys().get(1), 1); diff --git a/beacon/pow/src/main/java/tech/pegasys/teku/beacon/pow/api/MinGenesisTimeBlockEventChannel.java b/beacon/pow/src/main/java/tech/pegasys/teku/beacon/pow/api/MinGenesisTimeBlockEventChannel.java deleted file mode 100644 index 7ba101fc9f1..00000000000 --- a/beacon/pow/src/main/java/tech/pegasys/teku/beacon/pow/api/MinGenesisTimeBlockEventChannel.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.beacon.pow.api; - -import tech.pegasys.teku.ethereum.pow.api.MinGenesisTimeBlockEvent; - -public interface MinGenesisTimeBlockEventChannel { - void onMinGenesisTimeBlock(MinGenesisTimeBlockEvent event); -} diff --git a/build.gradle b/build.gradle index 7f04f2a384d..e06251b765f 100644 --- a/build.gradle +++ b/build.gradle @@ -984,7 +984,6 @@ subprojects { runtimeOnly 'org.apache.logging.log4j:log4j-core' runtimeOnly 'org.apache.logging.log4j:log4j-slf4j-impl' - testImplementation 'io.tmio:tuweni-junit' testImplementation 'org.assertj:assertj-core' testImplementation 'org.mockito:mockito-core' testImplementation 'org.junit.jupiter:junit-jupiter-api' diff --git a/data/serializer/build.gradle b/data/serializer/build.gradle index 4302d4d8e80..f24eb8983ed 100644 --- a/data/serializer/build.gradle +++ b/data/serializer/build.gradle @@ -3,11 +3,9 @@ dependencies { api 'io.swagger.core.v3:swagger-annotations' implementation project(':ethereum:execution-types') - implementation project(':ethereum:jackson-deserializers') implementation project(':ethereum:spec') implementation project(':infrastructure:bls') implementation project(':infrastructure:bytes') - implementation project(':infrastructure:jackson') implementation project(':infrastructure:async') implementation 'io.tmio:tuweni-units' diff --git a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/interfaces/SignedBlindedBlock.java b/data/serializer/src/main/java/tech/pegasys/teku/api/schema/interfaces/SignedBlindedBlock.java deleted file mode 100644 index 3429bdb17a7..00000000000 --- a/data/serializer/src/main/java/tech/pegasys/teku/api/schema/interfaces/SignedBlindedBlock.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.api.schema.interfaces; - -import io.swagger.v3.oas.annotations.media.Schema; -import tech.pegasys.teku.api.schema.altair.SignedBeaconBlockAltair; -import tech.pegasys.teku.api.schema.bellatrix.SignedBlindedBeaconBlockBellatrix; -import tech.pegasys.teku.api.schema.capella.SignedBlindedBeaconBlockCapella; -import tech.pegasys.teku.api.schema.deneb.SignedBlindedBeaconBlockDeneb; -import tech.pegasys.teku.api.schema.electra.SignedBlindedBeaconBlockElectra; -import tech.pegasys.teku.api.schema.phase0.SignedBeaconBlockPhase0; - -@Schema( - oneOf = { - SignedBeaconBlockPhase0.class, - SignedBeaconBlockAltair.class, - SignedBlindedBeaconBlockBellatrix.class, - SignedBlindedBeaconBlockCapella.class, - SignedBlindedBeaconBlockDeneb.class, - SignedBlindedBeaconBlockElectra.class - }) -public interface SignedBlindedBlock {} diff --git a/eth-reference-tests/build.gradle b/eth-reference-tests/build.gradle index 91cb2a10c90..6ebc8cf2cba 100644 --- a/eth-reference-tests/build.gradle +++ b/eth-reference-tests/build.gradle @@ -25,7 +25,6 @@ dependencies { referenceTestImplementation 'com.fasterxml.jackson.core:jackson-databind' referenceTestImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' referenceTestImplementation 'io.tmio:tuweni-bytes' - referenceTestImplementation 'io.tmio:tuweni-junit' referenceTestImplementation 'io.tmio:tuweni-ssz' referenceTestImplementation 'org.xerial.snappy:snappy-java' } diff --git a/ethereum/execution-types/build.gradle b/ethereum/execution-types/build.gradle index c8ce4745c85..b9503a7dba8 100644 --- a/ethereum/execution-types/build.gradle +++ b/ethereum/execution-types/build.gradle @@ -3,7 +3,7 @@ dependencies { implementation project(':infrastructure:crypto') implementation project(':infrastructure:json') - testFixturesApi project(':infrastructure:jackson') + testFixturesApi 'com.fasterxml.jackson.core:jackson-databind' testImplementation project(':ethereum:json-types') testImplementation testFixtures(project(':infrastructure:json')) diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineApiMethod.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineApiMethod.java index a47654c47fe..44ec33d7a4c 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineApiMethod.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineApiMethod.java @@ -16,8 +16,7 @@ public enum EngineApiMethod { ENGINE_NEW_PAYLOAD("engine_newPayload"), ENGINE_GET_PAYLOAD("engine_getPayload"), - ENGINE_FORK_CHOICE_UPDATED("engine_forkchoiceUpdated"), - ENGINE_GET_BLOBS("engine_getBlobs"); + ENGINE_FORK_CHOICE_UPDATED("engine_forkchoiceUpdated"); private final String name; diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetBlobsV1.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetBlobsV1.java deleted file mode 100644 index 40426616b87..00000000000 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetBlobsV1.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2024 - * - * 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.ethereum.executionclient.methods; - -import java.util.List; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient; -import tech.pegasys.teku.ethereum.executionclient.response.ResponseUnwrapper; -import tech.pegasys.teku.infrastructure.async.SafeFuture; -import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.Spec; -import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSchema; -import tech.pegasys.teku.spec.datastructures.execution.BlobAndProof; -import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; -import tech.pegasys.teku.spec.schemas.SchemaDefinitions; -import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; - -public class EngineGetBlobsV1 extends AbstractEngineJsonRpcMethod> { - - private static final Logger LOG = LogManager.getLogger(); - private final Spec spec; - - public EngineGetBlobsV1(final ExecutionEngineClient executionEngineClient, final Spec spec) { - super(executionEngineClient); - this.spec = spec; - } - - @Override - public String getName() { - return EngineApiMethod.ENGINE_GET_BLOBS.getName(); - } - - @Override - public int getVersion() { - return 1; - } - - @Override - public boolean isOptional() { - return true; - } - - @Override - public SafeFuture> execute(final JsonRpcRequestParams params) { - - final List blobVersionedHashes = - params.getRequiredListParameter(0, VersionedHash.class); - - final UInt64 slot = params.getRequiredParameter(1, UInt64.class); - - LOG.trace( - "Calling {}(blobVersionedHashes={}, slot={})", - getVersionedName(), - blobVersionedHashes, - slot); - - return executionEngineClient - .getBlobsV1(blobVersionedHashes) - .thenApply(ResponseUnwrapper::unwrapExecutionClientResponseOrThrow) - .thenApply( - response -> { - final SchemaDefinitions schemaDefinitions = spec.atSlot(slot).getSchemaDefinitions(); - final BlobSchema blobSchema = - SchemaDefinitionsDeneb.required(schemaDefinitions).getBlobSchema(); - return response.stream() - .map( - blobAndProofV1 -> - blobAndProofV1 == null - ? null - : blobAndProofV1.asInternalBlobsAndProofs(blobSchema)) - .toList(); - }) - .thenPeek( - blobsAndProofs -> - LOG.trace( - "Response {}(blobVersionedHashes={}) -> {}", - getVersionedName(), - blobVersionedHashes, - blobsAndProofs)); - } -} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineJsonRpcMethod.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineJsonRpcMethod.java index 8c41f711697..ddc4b4f196e 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineJsonRpcMethod.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineJsonRpcMethod.java @@ -28,12 +28,6 @@ default boolean isDeprecated() { return false; } - // TODO should be remove once all ELs implement engine_getBlobsV1. It has been added only to - // better handle the use case when the method is missing in the EL side - default boolean isOptional() { - return false; - } - default String getVersionedName() { return getVersion() == 0 ? getName() : getName() + "V" + getVersion(); } diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/BlobAndProofV1.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/BlobAndProofV1.java index 1a73026a865..041fdbbbab6 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/BlobAndProofV1.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/BlobAndProofV1.java @@ -52,11 +52,6 @@ public BlobAndProof asInternalBlobsAndProofs(final BlobSchema blobSchema) { return new BlobAndProof(new Blob(blobSchema, blob), new KZGProof(proof)); } - public static BlobAndProofV1 fromInternalBlobsBundle(final BlobAndProof blobAndProof) { - return new BlobAndProofV1( - blobAndProof.blob().getBytes(), blobAndProof.proof().getBytesCompressed()); - } - @Override public boolean equals(final Object o) { if (this == o) { diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ConsolidationRequestV1.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ConsolidationRequestV1.java deleted file mode 100644 index 92bb0f96463..00000000000 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/ConsolidationRequestV1.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2024 - * - * 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.ethereum.executionclient.schema; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.google.common.base.MoreObjects; -import java.util.Objects; -import org.apache.tuweni.bytes.Bytes48; -import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes20Deserializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes20Serializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes48Deserializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.BytesSerializer; -import tech.pegasys.teku.infrastructure.bytes.Bytes20; - -public class ConsolidationRequestV1 { - @JsonSerialize(using = Bytes20Serializer.class) - @JsonDeserialize(using = Bytes20Deserializer.class) - public final Bytes20 sourceAddress; - - @JsonSerialize(using = BytesSerializer.class) - @JsonDeserialize(using = Bytes48Deserializer.class) - public final Bytes48 sourcePubkey; - - @JsonSerialize(using = BytesSerializer.class) - @JsonDeserialize(using = Bytes48Deserializer.class) - public final Bytes48 targetPubkey; - - public ConsolidationRequestV1( - @JsonProperty("sourceAddress") final Bytes20 sourceAddress, - @JsonProperty("sourcePubkey") final Bytes48 sourcePubkey, - @JsonProperty("targetPubkey") final Bytes48 targetPubkey) { - checkNotNull(sourceAddress, "sourceAddress"); - checkNotNull(sourcePubkey, "sourcePubkey"); - checkNotNull(targetPubkey, "targetPubkey"); - this.sourceAddress = sourceAddress; - this.sourcePubkey = sourcePubkey; - this.targetPubkey = targetPubkey; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final ConsolidationRequestV1 that = (ConsolidationRequestV1) o; - return Objects.equals(sourceAddress, that.sourceAddress) - && Objects.equals(sourcePubkey, that.sourcePubkey) - && Objects.equals(targetPubkey, that.targetPubkey); - } - - @Override - public int hashCode() { - return Objects.hash(sourceAddress, sourceAddress, targetPubkey); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("sourceAddress", sourceAddress) - .add("sourcePubkey", sourcePubkey) - .add("targetPubkey", targetPubkey) - .toString(); - } -} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/DepositRequestV1.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/DepositRequestV1.java deleted file mode 100644 index 1fe6256e062..00000000000 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/schema/DepositRequestV1.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2024 - * - * 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.ethereum.executionclient.schema; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.google.common.base.MoreObjects; -import java.util.Objects; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.bytes.Bytes48; -import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes32Deserializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes48Deserializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.BytesDeserializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.BytesSerializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexDeserializer; -import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexSerializer; -import tech.pegasys.teku.infrastructure.unsigned.UInt64; - -public class DepositRequestV1 { - @JsonSerialize(using = BytesSerializer.class) - @JsonDeserialize(using = Bytes48Deserializer.class) - public final Bytes48 pubkey; - - @JsonSerialize(using = BytesSerializer.class) - @JsonDeserialize(using = Bytes32Deserializer.class) - public final Bytes32 withdrawalCredentials; - - @JsonSerialize(using = UInt64AsHexSerializer.class) - @JsonDeserialize(using = UInt64AsHexDeserializer.class) - public final UInt64 amount; - - @JsonSerialize(using = BytesSerializer.class) - @JsonDeserialize(using = BytesDeserializer.class) - public final Bytes signature; - - @JsonSerialize(using = UInt64AsHexSerializer.class) - @JsonDeserialize(using = UInt64AsHexDeserializer.class) - public final UInt64 index; - - public DepositRequestV1( - @JsonProperty("pubkey") final Bytes48 pubkey, - @JsonProperty("withdrawalCredentials") final Bytes32 withdrawalCredentials, - @JsonProperty("amount") final UInt64 amount, - @JsonProperty("signature") final Bytes signature, - @JsonProperty("index") final UInt64 index) { - checkNotNull(pubkey, "pubkey"); - checkNotNull(withdrawalCredentials, "withdrawalCredentials"); - checkNotNull(amount, "amount"); - checkNotNull(signature, "signature"); - checkNotNull(index, "index"); - this.pubkey = pubkey; - this.withdrawalCredentials = withdrawalCredentials; - this.amount = amount; - this.signature = signature; - this.index = index; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final DepositRequestV1 that = (DepositRequestV1) o; - return Objects.equals(pubkey, that.pubkey) - && Objects.equals(withdrawalCredentials, that.withdrawalCredentials) - && Objects.equals(amount, that.amount) - && Objects.equals(signature, that.signature) - && Objects.equals(index, that.index); - } - - @Override - public int hashCode() { - return Objects.hash(pubkey, withdrawalCredentials, amount, signature, index); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("pubkey", pubkey) - .add("withdrawalCredentials", withdrawalCredentials) - .add("amount", amount) - .add("signature", signature) - .add("index", index) - .toString(); - } -} diff --git a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/DefaultExecutionWeb3jClientProvider.java b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/DefaultExecutionWeb3jClientProvider.java index dd3465735b6..49814585d96 100644 --- a/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/DefaultExecutionWeb3jClientProvider.java +++ b/ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/web3j/DefaultExecutionWeb3jClientProvider.java @@ -23,6 +23,11 @@ import tech.pegasys.teku.infrastructure.time.TimeProvider; public class DefaultExecutionWeb3jClientProvider implements ExecutionWeb3jClientProvider { + private static final String[] NON_CRITICAL_METHODS = + new String[] { + "engine_exchangeCapabilities", "engine_getClientVersionV1", "engine_getBlobsV1" + }; + private final String eeEndpoint; private final Duration timeout; private final Optional jwtConfig; @@ -58,8 +63,7 @@ private synchronized void buildClient() { .jwtConfigOpt(jwtConfig) .timeProvider(timeProvider) .executionClientEventsPublisher(executionClientEventsPublisher) - .nonCriticalMethods( - "engine_exchangeCapabilities", "engine_getClientVersionV1", "engine_getBlobsV1") + .nonCriticalMethods(NON_CRITICAL_METHODS) .build(); this.alreadyBuilt = true; } diff --git a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetBlobsV1Test.java b/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetBlobsV1Test.java deleted file mode 100644 index 6501e6a2aaa..00000000000 --- a/ethereum/executionclient/src/test/java/tech/pegasys/teku/ethereum/executionclient/methods/EngineGetBlobsV1Test.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2024 - * - * 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.ethereum.executionclient.methods; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient; -import tech.pegasys.teku.ethereum.executionclient.response.InvalidRemoteResponseException; -import tech.pegasys.teku.ethereum.executionclient.schema.BlobAndProofV1; -import tech.pegasys.teku.ethereum.executionclient.schema.Response; -import tech.pegasys.teku.infrastructure.async.SafeFuture; -import tech.pegasys.teku.infrastructure.unsigned.UInt64; -import tech.pegasys.teku.spec.Spec; -import tech.pegasys.teku.spec.TestSpecFactory; -import tech.pegasys.teku.spec.config.SpecConfigDeneb; -import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; -import tech.pegasys.teku.spec.datastructures.execution.BlobAndProof; -import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; -import tech.pegasys.teku.spec.util.DataStructureUtil; - -public class EngineGetBlobsV1Test { - - private final Spec spec = TestSpecFactory.createMinimalElectra(); - private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); - private final ExecutionEngineClient executionEngineClient = mock(ExecutionEngineClient.class); - private EngineGetBlobsV1 jsonRpcMethod; - - @BeforeEach - public void setUp() { - jsonRpcMethod = new EngineGetBlobsV1(executionEngineClient, spec); - } - - @Test - public void shouldReturnExpectedNameAndVersion() { - assertThat(jsonRpcMethod.getName()).isEqualTo("engine_getBlobs"); - assertThat(jsonRpcMethod.isOptional()).isTrue(); - assertThat(jsonRpcMethod.getVersion()).isEqualTo(1); - assertThat(jsonRpcMethod.getVersionedName()).isEqualTo("engine_getBlobsV1"); - } - - @Test - public void blobVersionedHashesParamIsRequired() { - final JsonRpcRequestParams params = new JsonRpcRequestParams.Builder().build(); - - assertThatThrownBy(() -> jsonRpcMethod.execute(params)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Missing required parameter at index 0"); - - verifyNoInteractions(executionEngineClient); - } - - @Test - public void slotParamIsRequired() { - final List versionedHashes = dataStructureUtil.randomVersionedHashes(4); - - final JsonRpcRequestParams params = - new JsonRpcRequestParams.Builder().add(versionedHashes).build(); - - assertThatThrownBy(() -> jsonRpcMethod.execute(params)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Missing required parameter at index 1"); - - verifyNoInteractions(executionEngineClient); - } - - @Test - public void shouldReturnFailedExecutionWhenEngineClientRequestFails() { - final List versionedHashes = dataStructureUtil.randomVersionedHashes(4); - final String errorResponseFromClient = "error!"; - - when(executionEngineClient.getBlobsV1(any())) - .thenReturn(dummyFailedResponse(errorResponseFromClient)); - - final JsonRpcRequestParams params = - new JsonRpcRequestParams.Builder().add(versionedHashes).add(UInt64.ZERO).build(); - - assertThat(jsonRpcMethod.execute(params)) - .failsWithin(1, TimeUnit.SECONDS) - .withThrowableOfType(ExecutionException.class) - .withRootCauseInstanceOf(InvalidRemoteResponseException.class) - .withMessageContaining( - "Invalid remote response from the execution client: %s", errorResponseFromClient); - } - - @Test - public void shouldCallGetBlobsV1AndParseResponseSuccessfully() { - final List versionedHashes = dataStructureUtil.randomVersionedHashes(4); - final List blobSidecars = - dataStructureUtil.randomBlobSidecars( - SpecConfigDeneb.required(spec.getGenesisSpecConfig()).getMaxBlobsPerBlock()); - - when(executionEngineClient.getBlobsV1(eq(versionedHashes))) - .thenReturn(dummySuccessfulResponse(blobSidecars)); - - final JsonRpcRequestParams params = - new JsonRpcRequestParams.Builder().add(versionedHashes).add(UInt64.ZERO).build(); - - jsonRpcMethod = new EngineGetBlobsV1(executionEngineClient, spec); - - final List expectedResponse = - blobSidecars.stream() - .map(blobSidecar -> new BlobAndProof(blobSidecar.getBlob(), blobSidecar.getKZGProof())) - .toList(); - assertThat(jsonRpcMethod.execute(params)).isCompletedWithValue(expectedResponse); - - verify(executionEngineClient).getBlobsV1(eq(versionedHashes)); - verifyNoMoreInteractions(executionEngineClient); - } - - private SafeFuture>> dummySuccessfulResponse( - final List blobSidecars) { - return SafeFuture.completedFuture( - new Response<>( - blobSidecars.stream() - .map( - blobSidecar -> - new BlobAndProofV1( - blobSidecar.getBlob().getBytes(), - blobSidecar.getKZGProof().getBytesCompressed())) - .toList())); - } - - private SafeFuture>> dummyFailedResponse( - final String errorMessage) { - return SafeFuture.completedFuture(Response.withErrorMessage(errorMessage)); - } -} diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitor.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitor.java index 8ecc3afbcce..d24fd65a763 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitor.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitor.java @@ -18,7 +18,6 @@ import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; -import java.util.stream.Stream; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import tech.pegasys.teku.ethereum.events.SlotEventsChannel; @@ -41,7 +40,6 @@ public class EngineCapabilitiesMonitor implements SlotEventsChannel { private final Spec spec; private final EventLogger eventLogger; private final Supplier> capabilitiesSupplier; - private final Supplier> optionalCapabilitiesSupplier; private final ExecutionEngineClient executionEngineClient; public EngineCapabilitiesMonitor( @@ -53,8 +51,6 @@ public EngineCapabilitiesMonitor( this.eventLogger = eventLogger; this.capabilitiesSupplier = Suppliers.memoize(() -> new ArrayList<>(engineMethodsResolver.getCapabilities())); - this.optionalCapabilitiesSupplier = - Suppliers.memoize(() -> new ArrayList<>(engineMethodsResolver.getOptionalCapabilities())); this.executionEngineClient = executionEngineClient; } @@ -83,35 +79,20 @@ private boolean slotIsApplicable(final UInt64 slot) { private SafeFuture monitor() { final List capabilities = capabilitiesSupplier.get(); - final List optionalCapabilities = optionalCapabilitiesSupplier.get(); return executionEngineClient - .exchangeCapabilities( - Stream.concat(capabilities.stream(), optionalCapabilities.stream()).toList()) + .exchangeCapabilities(capabilities) .thenApply(ResponseUnwrapper::unwrapExecutionClientResponseOrThrow) .thenAccept( engineCapabilities -> { - LOG.debug("Engine API capabilities response: " + engineCapabilities); + LOG.debug("Engine API capabilities response: {}", engineCapabilities); final List missingEngineCapabilities = capabilities.stream() - .filter( - capability -> - !engineCapabilities.contains(capability) - && !optionalCapabilities.contains(capability)) - .toList(); - - final List missingOptionalCapabilities = - optionalCapabilities.stream() - .filter( - optionalCapability -> !engineCapabilities.contains(optionalCapability)) + .filter(capability -> !engineCapabilities.contains(capability)) .toList(); if (!missingEngineCapabilities.isEmpty()) { - eventLogger.missingEngineApiCapabilities(missingEngineCapabilities, false); - } - - if (!missingOptionalCapabilities.isEmpty()) { - eventLogger.missingEngineApiCapabilities(missingOptionalCapabilities, true); + eventLogger.missingEngineApiCapabilities(missingEngineCapabilities); } }); } diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineJsonRpcMethodsResolver.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineJsonRpcMethodsResolver.java index ce182addfea..bcf580c3659 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineJsonRpcMethodsResolver.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/EngineJsonRpcMethodsResolver.java @@ -13,7 +13,6 @@ package tech.pegasys.teku.ethereum.executionlayer; -import java.util.List; import java.util.Set; import java.util.function.Supplier; import tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod; @@ -25,19 +24,10 @@ public interface EngineJsonRpcMethodsResolver { EngineJsonRpcMethod getMethod( EngineApiMethod method, Supplier milestoneSupplier, Class resultType); - EngineJsonRpcMethod> getListMethod( - EngineApiMethod method, Supplier milestoneSupplier, Class resultType); - /** * Get CL capabilities required for the engine_exchangeCapabilities * request */ Set getCapabilities(); - - /** - * TODO this optionality notion should be removed once all ELs implement the engine_getBlobsV1 RPC - * method. It has been added to ensure a softer and better logging when the method is missing only - */ - Set getOptionalCapabilities(); } diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java index 581f494cb0a..64f4ffdb089 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/ExecutionClientHandlerImpl.java @@ -24,6 +24,7 @@ import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; +import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSchema; import tech.pegasys.teku.spec.datastructures.execution.BlobAndProof; import tech.pegasys.teku.spec.datastructures.execution.ClientVersion; import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload; @@ -36,6 +37,8 @@ import tech.pegasys.teku.spec.executionlayer.PayloadBuildingAttributes; import tech.pegasys.teku.spec.executionlayer.PayloadStatus; import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; +import tech.pegasys.teku.spec.schemas.SchemaDefinitions; +import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb; public class ExecutionClientHandlerImpl implements ExecutionClientHandler { @@ -130,16 +133,25 @@ public SafeFuture> engineGetClientVersion(final ClientVersio clientVersions.stream().map(ClientVersionV1::asInternalClientVersion).toList()); } + /** Unlikely the {@link BlobSchema} to change with upcoming forks */ @Override public SafeFuture> engineGetBlobs( final List blobVersionedHashes, final UInt64 slot) { - final JsonRpcRequestParams params = - new JsonRpcRequestParams.Builder().add(blobVersionedHashes).add(slot).build(); - return engineMethodsResolver - .getListMethod( - EngineApiMethod.ENGINE_GET_BLOBS, - () -> spec.atSlot(slot).getMilestone(), - BlobAndProof.class) - .execute(params); + return executionEngineClient + .getBlobsV1(blobVersionedHashes) + .thenApply(ResponseUnwrapper::unwrapExecutionClientResponseOrThrow) + .thenApply( + response -> { + final SchemaDefinitions schemaDefinitions = spec.atSlot(slot).getSchemaDefinitions(); + final BlobSchema blobSchema = + SchemaDefinitionsDeneb.required(schemaDefinitions).getBlobSchema(); + return response.stream() + .map( + blobAndProofV1 -> + blobAndProofV1 == null + ? null + : blobAndProofV1.asInternalBlobsAndProofs(blobSchema)) + .toList(); + }); } } diff --git a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java index 0651980f143..992aa0e5095 100644 --- a/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java +++ b/ethereum/executionlayer/src/main/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolver.java @@ -14,14 +14,12 @@ package tech.pegasys.teku.ethereum.executionlayer; import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_FORK_CHOICE_UPDATED; -import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_GET_BLOBS; import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_GET_PAYLOAD; import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_NEW_PAYLOAD; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -31,7 +29,6 @@ import tech.pegasys.teku.ethereum.executionclient.methods.EngineForkChoiceUpdatedV1; import tech.pegasys.teku.ethereum.executionclient.methods.EngineForkChoiceUpdatedV2; import tech.pegasys.teku.ethereum.executionclient.methods.EngineForkChoiceUpdatedV3; -import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetBlobsV1; import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetPayloadV1; import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetPayloadV2; import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetPayloadV3; @@ -109,7 +106,6 @@ private Map> denebSupportedMethods() { methods.put(ENGINE_NEW_PAYLOAD, new EngineNewPayloadV3(executionEngineClient)); methods.put(ENGINE_GET_PAYLOAD, new EngineGetPayloadV3(executionEngineClient, spec)); methods.put(ENGINE_FORK_CHOICE_UPDATED, new EngineForkChoiceUpdatedV3(executionEngineClient)); - methods.put(ENGINE_GET_BLOBS, new EngineGetBlobsV1(executionEngineClient, spec)); return methods; } @@ -120,7 +116,6 @@ private Map> electraSupportedMethods() { methods.put(ENGINE_NEW_PAYLOAD, new EngineNewPayloadV4(executionEngineClient)); methods.put(ENGINE_GET_PAYLOAD, new EngineGetPayloadV4(executionEngineClient, spec)); methods.put(ENGINE_FORK_CHOICE_UPDATED, new EngineForkChoiceUpdatedV3(executionEngineClient)); - methods.put(ENGINE_GET_BLOBS, new EngineGetBlobsV1(executionEngineClient, spec)); return methods; } @@ -143,39 +138,10 @@ public EngineJsonRpcMethod getMethod( return foundMethod; } - @Override - @SuppressWarnings({"unchecked", "unused"}) - public EngineJsonRpcMethod> getListMethod( - final EngineApiMethod method, - final Supplier milestoneSupplier, - final Class resultType) { - final SpecMilestone milestone = milestoneSupplier.get(); - final Map> milestoneMethods = - methodsByMilestone.getOrDefault(milestone, Collections.emptyMap()); - final EngineJsonRpcMethod> foundMethod = - (EngineJsonRpcMethod>) milestoneMethods.get(method); - if (foundMethod == null) { - throw new IllegalArgumentException( - "Can't find method with name " + method.getName() + " for milestone " + milestone); - } - return foundMethod; - } - @Override public Set getCapabilities() { return methodsByMilestone.values().stream() .flatMap(methods -> methods.values().stream()) - .filter(method -> !method.isOptional()) - .filter(method -> !method.isDeprecated()) - .map(EngineJsonRpcMethod::getVersionedName) - .collect(Collectors.toSet()); - } - - @Override - public Set getOptionalCapabilities() { - return methodsByMilestone.values().stream() - .flatMap(methods -> methods.values().stream()) - .filter(EngineJsonRpcMethod::isOptional) .filter(method -> !method.isDeprecated()) .map(EngineJsonRpcMethod::getVersionedName) .collect(Collectors.toSet()); diff --git a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitorTest.java b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitorTest.java index 9849430c6f1..ff4d6c5343c 100644 --- a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitorTest.java +++ b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/EngineCapabilitiesMonitorTest.java @@ -25,7 +25,6 @@ import java.util.HashSet; import java.util.List; -import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient; @@ -44,18 +43,14 @@ public class EngineCapabilitiesMonitorTest { mock(EngineJsonRpcMethodsResolver.class); private final ExecutionEngineClient executionEngineClient = mock(ExecutionEngineClient.class); - private final List engineCapabilities = List.of("method1", "method2", "method3"); private final List capabilities = List.of("method1", "method2"); - private final List optionalCapabilities = List.of("method3"); private EngineCapabilitiesMonitor engineCapabilitiesMonitor; @BeforeEach public void setUp() { when(engineMethodsResolver.getCapabilities()).thenReturn(new HashSet<>(capabilities)); - when(engineMethodsResolver.getOptionalCapabilities()) - .thenReturn(new HashSet<>(optionalCapabilities)); - mockEngineCapabilitiesResponse(engineCapabilities); + mockEngineCapabilitiesResponse(capabilities); engineCapabilitiesMonitor = new EngineCapabilitiesMonitor( spec, eventLogger, engineMethodsResolver, executionEngineClient); @@ -69,18 +64,7 @@ public void logsWarningIfEngineDoesNotSupportCapabilities() { // 3rd slot in epoch engineCapabilitiesMonitor.onSlot(UInt64.valueOf(2)); - verify(eventLogger).missingEngineApiCapabilities(List.of("method2"), false); - } - - @Test - public void logsWarningIfEngineDoesNotSupportOptionalCapabilities() { - // engine only supports one of the methods - mockEngineCapabilitiesResponse(List.of("method1", "method2")); - - // 3rd slot in epoch - engineCapabilitiesMonitor.onSlot(UInt64.valueOf(2)); - - verify(eventLogger).missingEngineApiCapabilities(List.of("method3"), true); + verify(eventLogger).missingEngineApiCapabilities(List.of("method2")); } @Test @@ -145,8 +129,7 @@ public void doesNotRunMonitoringIfNotAtRequiredSlot() { } private void mockEngineCapabilitiesResponse(final List engineCapabilities) { - when(executionEngineClient.exchangeCapabilities( - Stream.concat(capabilities.stream(), optionalCapabilities.stream()).toList())) + when(executionEngineClient.exchangeCapabilities(capabilities)) .thenReturn(SafeFuture.completedFuture(new Response<>(engineCapabilities))); } diff --git a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolverTest.java b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolverTest.java index 79d6577e40a..a98ad90fbb8 100644 --- a/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolverTest.java +++ b/ethereum/executionlayer/src/test/java/tech/pegasys/teku/ethereum/executionlayer/MilestoneBasedEngineJsonRpcMethodsResolverTest.java @@ -18,7 +18,6 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.mockito.Mockito.mock; import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_FORK_CHOICE_UPDATED; -import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_GET_BLOBS; import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_GET_PAYLOAD; import static tech.pegasys.teku.ethereum.executionclient.methods.EngineApiMethod.ENGINE_NEW_PAYLOAD; @@ -34,7 +33,6 @@ import tech.pegasys.teku.ethereum.executionclient.methods.EngineForkChoiceUpdatedV1; import tech.pegasys.teku.ethereum.executionclient.methods.EngineForkChoiceUpdatedV2; import tech.pegasys.teku.ethereum.executionclient.methods.EngineForkChoiceUpdatedV3; -import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetBlobsV1; import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetPayloadV1; import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetPayloadV2; import tech.pegasys.teku.ethereum.executionclient.methods.EngineGetPayloadV3; @@ -163,8 +161,7 @@ private static Stream denebMethods() { return Stream.of( arguments(ENGINE_NEW_PAYLOAD, EngineNewPayloadV3.class), arguments(ENGINE_GET_PAYLOAD, EngineGetPayloadV3.class), - arguments(ENGINE_FORK_CHOICE_UPDATED, EngineForkChoiceUpdatedV3.class), - arguments(ENGINE_GET_BLOBS, EngineGetBlobsV1.class)); + arguments(ENGINE_FORK_CHOICE_UPDATED, EngineForkChoiceUpdatedV3.class)); } @Test @@ -200,8 +197,7 @@ private static Stream electraMethods() { return Stream.of( arguments(ENGINE_NEW_PAYLOAD, EngineNewPayloadV4.class), arguments(ENGINE_GET_PAYLOAD, EngineGetPayloadV4.class), - arguments(ENGINE_FORK_CHOICE_UPDATED, EngineForkChoiceUpdatedV3.class), - arguments(ENGINE_GET_BLOBS, EngineGetBlobsV1.class)); + arguments(ENGINE_FORK_CHOICE_UPDATED, EngineForkChoiceUpdatedV3.class)); } @Test @@ -229,18 +225,4 @@ void getsCapabilities() { "engine_newPayloadV4", "engine_getPayloadV4"); } - - @Test - void getsOptionalCapabilities() { - final Spec spec = - TestSpecFactory.createMinimalWithCapellaDenebAndElectraForkEpoch( - UInt64.ONE, UInt64.valueOf(2), UInt64.valueOf(3)); - - final MilestoneBasedEngineJsonRpcMethodsResolver engineMethodsResolver = - new MilestoneBasedEngineJsonRpcMethodsResolver(spec, executionEngineClient); - - final Set capabilities = engineMethodsResolver.getOptionalCapabilities(); - - assertThat(capabilities).containsExactlyInAnyOrder("engine_getBlobsV1"); - } } diff --git a/ethereum/jackson-deserializers/build.gradle b/ethereum/jackson-deserializers/build.gradle deleted file mode 100644 index 1b32471b6bc..00000000000 --- a/ethereum/jackson-deserializers/build.gradle +++ /dev/null @@ -1,5 +0,0 @@ -dependencies { - implementation project(':infrastructure:bytes') - implementation project(':infrastructure:jackson') - implementation project(':ethereum:execution-types') -} \ No newline at end of file diff --git a/ethereum/jackson-deserializers/src/main/java/tech/pegasys/teku/ethereum/jackson/Eth1AddressDeserializer.java b/ethereum/jackson-deserializers/src/main/java/tech/pegasys/teku/ethereum/jackson/Eth1AddressDeserializer.java deleted file mode 100644 index 5f789385890..00000000000 --- a/ethereum/jackson-deserializers/src/main/java/tech/pegasys/teku/ethereum/jackson/Eth1AddressDeserializer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.ethereum.jackson; - -import com.fasterxml.jackson.core.JacksonException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonMappingException; -import java.io.IOException; -import tech.pegasys.teku.ethereum.execution.types.Eth1Address; - -public class Eth1AddressDeserializer extends JsonDeserializer { - - @Override - public Eth1Address deserialize(final JsonParser p, final DeserializationContext ctxt) - throws JacksonException { - try { - return Eth1Address.fromHexString(p.getValueAsString()); - } catch (RuntimeException | IOException ex) { - throw new JsonMappingException(p, ex.getMessage(), ex); - } - } -} diff --git a/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java b/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java index 1842ee7dff5..d4e3f27132d 100644 --- a/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java +++ b/ethereum/networks/src/main/java/tech/pegasys/teku/networks/Eth2NetworkConfiguration.java @@ -751,6 +751,9 @@ private Builder reset() { eth1DepositContractAddress = null; eth1DepositContractDeployBlock = Optional.empty(); trustedSetup = Optional.empty(); + terminalBlockHashOverride = Optional.empty(); + terminalBlockHashEpochOverride = Optional.empty(); + totalTerminalDifficultyOverride = Optional.empty(); return this; } @@ -802,7 +805,11 @@ public Builder applyMainnetNetworkDefaults() { // Nimbus "enr:-LK4QA8FfhaAjlb_BXsXxSfiysR7R52Nhi9JBt4F8SPssu8hdE1BXQQEtVDC3qStCW60LSO7hEsVHv5zm8_6Vnjhcn0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAN4aBKJc2VjcDI1NmsxoQJerDhsJ-KxZ8sHySMOCmTO6sHM3iCFQ6VMvLTe948MyYN0Y3CCI4yDdWRwgiOM", - "enr:-LK4QKWrXTpV9T78hNG6s8AM6IO4XH9kFT91uZtFg1GcsJ6dKovDOr1jtAAFPnS2lvNltkOGA9k29BUN7lFh_sjuc9QBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhANAdd-Jc2VjcDI1NmsxoQLQa6ai7y9PMN5hpLe5HmiJSlYzMuzP7ZhwRiwHvqNXdoN0Y3CCI4yDdWRwgiOM"); + "enr:-LK4QKWrXTpV9T78hNG6s8AM6IO4XH9kFT91uZtFg1GcsJ6dKovDOr1jtAAFPnS2lvNltkOGA9k29BUN7lFh_sjuc9QBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhANAdd-Jc2VjcDI1NmsxoQLQa6ai7y9PMN5hpLe5HmiJSlYzMuzP7ZhwRiwHvqNXdoN0Y3CCI4yDdWRwgiOM") + .terminalBlockHashEpochOverride(UInt64.valueOf(146875)) + .terminalBlockHashOverride( + Bytes32.fromHexString( + "0x55b11b918355b1ef9c5db810302ebad0bf2544255b530cdce90674d5887bb286")); } private Builder applySepoliaNetworkDefaults() { @@ -827,7 +834,11 @@ private Builder applySepoliaNetworkDefaults() { // Another bootnode "enr:-L64QC9Hhov4DhQ7mRukTOz4_jHm4DHlGL726NWH4ojH1wFgEwSin_6H95Gs6nW2fktTWbPachHJ6rUFu0iJNgA0SB2CARqHYXR0bmV0c4j__________4RldGgykDb6UBOQAABx__________-CaWSCdjSCaXCEA-2vzolzZWNwMjU2azGhA17lsUg60R776rauYMdrAz383UUgESoaHEzMkvm4K6k6iHN5bmNuZXRzD4N0Y3CCIyiDdWRwgiMo", // Lodestart bootnode - "enr:-KG4QJejf8KVtMeAPWFhN_P0c4efuwu1pZHELTveiXUeim6nKYcYcMIQpGxxdgT2Xp9h-M5pr9gn2NbbwEAtxzu50Y8BgmlkgnY0gmlwhEEVkQCDaXA2kCoBBPnAEJg4AAAAAAAAAAGJc2VjcDI1NmsxoQLEh_eVvk07AQABvLkTGBQTrrIOQkzouMgSBtNHIRUxOIN1ZHCCIyiEdWRwNoIjKA"); + "enr:-KG4QJejf8KVtMeAPWFhN_P0c4efuwu1pZHELTveiXUeim6nKYcYcMIQpGxxdgT2Xp9h-M5pr9gn2NbbwEAtxzu50Y8BgmlkgnY0gmlwhEEVkQCDaXA2kCoBBPnAEJg4AAAAAAAAAAGJc2VjcDI1NmsxoQLEh_eVvk07AQABvLkTGBQTrrIOQkzouMgSBtNHIRUxOIN1ZHCCIyiEdWRwNoIjKA") + .terminalBlockHashEpochOverride(UInt64.valueOf(3599)) + .terminalBlockHashOverride( + Bytes32.fromHexString( + "0xd07cce9785d39c0dd2409b7d8e69d6bff26a69a0fa5308ac781c63ffe2a37bc1")); } private Builder applyLuksoNetworkDefaults() { @@ -860,7 +871,11 @@ public Builder applyGnosisNetworkDefaults() { "enr:-Ly4QCD5D99p36WafgTSxB6kY7D2V1ca71C49J4VWI2c8UZCCPYBvNRWiv0-HxOcbpuUdwPVhyWQCYm1yq2ZH0ukCbQBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCCS-QxAgAAZP__________gmlkgnY0gmlwhI1eYVSJc2VjcDI1NmsxoQJJMSV8iSZ8zvkgbi8cjIGEUVJeekLqT0LQha_co-siT4hzeW5jbmV0cwCDdGNwgiMog3VkcIIjKA", "enr:-KK4QKXJq1QOVWuJAGige4uaT8LRPQGCVRf3lH3pxjaVScMRUfFW1eiiaz8RwOAYvw33D4EX-uASGJ5QVqVCqwccxa-Bi4RldGgykCGm-DYDAABk__________-CaWSCdjSCaXCEM0QnzolzZWNwMjU2azGhAhNvrRkpuK4MWTf3WqiOXSOePL8Zc-wKVpZ9FQx_BDadg3RjcIIjKIN1ZHCCIyg", "enr:-LO4QO87Rn2ejN3SZdXkx7kv8m11EZ3KWWqoIN5oXwQ7iXR9CVGd1dmSyWxOL1PGsdIqeMf66OZj4QGEJckSi6okCdWBpIdhdHRuZXRziAAAAABgAAAAhGV0aDKQPr_UhAQAAGT__________4JpZIJ2NIJpcIQj0iX1iXNlY3AyNTZrMaEDd-_eqFlWWJrUfEp8RhKT9NxdYaZoLHvsp3bbejPyOoeDdGNwgiMog3VkcIIjKA", - "enr:-LK4QIJUAxX9uNgW4ACkq8AixjnSTcs9sClbEtWRq9F8Uy9OEExsr4ecpBTYpxX66cMk6pUHejCSX3wZkK2pOCCHWHEBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpA-v9SEBAAAZP__________gmlkgnY0gmlwhCPSnDuJc2VjcDI1NmsxoQNuaAjFE-ANkH3pbeBdPiEIwjR5kxFuKaBWxHkqFuPz5IN0Y3CCIyiDdWRwgiMo"); + "enr:-LK4QIJUAxX9uNgW4ACkq8AixjnSTcs9sClbEtWRq9F8Uy9OEExsr4ecpBTYpxX66cMk6pUHejCSX3wZkK2pOCCHWHEBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpA-v9SEBAAAZP__________gmlkgnY0gmlwhCPSnDuJc2VjcDI1NmsxoQNuaAjFE-ANkH3pbeBdPiEIwjR5kxFuKaBWxHkqFuPz5IN0Y3CCIyiDdWRwgiMo") + .terminalBlockHashEpochOverride(UInt64.valueOf(394147)) + .terminalBlockHashOverride( + Bytes32.fromHexString( + "0xf5cff68065ac6014bb7c9aa731d4d4084de0994f807ac1df3856308b3c9b2b48")); } public Builder applyChiadoNetworkDefaults() { @@ -891,7 +906,11 @@ public Builder applyChiadoNetworkDefaults() { // GnosisDAO Bootnode: 35.206.174.92 "enr:-KG4QF7z4LUdMfgwvh-fS-MDv_1hPSUCqGfyOWGLNJuoBHKFAMSHz8geQn8v3qDDbuSQKud3WIAjKqR4gqJoLBUEJ08ZhGV0aDKQDc1ElgAAAG___________4JpZIJ2NIJpcIQjzq5ciXNlY3AyNTZrMaECt7YO363pV54d3QdgnluL5kxzhCR_k0yM9C-G6bqMGoKDdGNwgiMog3VkcIIjKA", // GnosisDAO Bootnode: 35.210.126.23 - "enr:-LK4QCUTEmZrT1AgCKdyVgwnHL5J0VSoxsyjruAtwo-owBTBVEOyAnQRVNXlcW5aL-ycntk5oHDrKCR-DXZAlUAKpjEBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCdM7Z1BAAAb___________gmlkgnY0gmlwhCPSfheJc2VjcDI1NmsxoQNpdf8U9pzsU9m6Hzgd1rmTI-On-QImJnkZBGqDp4org4N0Y3CCIyiDdWRwgiMo"); + "enr:-LK4QCUTEmZrT1AgCKdyVgwnHL5J0VSoxsyjruAtwo-owBTBVEOyAnQRVNXlcW5aL-ycntk5oHDrKCR-DXZAlUAKpjEBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpCdM7Z1BAAAb___________gmlkgnY0gmlwhCPSfheJc2VjcDI1NmsxoQNpdf8U9pzsU9m6Hzgd1rmTI-On-QImJnkZBGqDp4org4N0Y3CCIyiDdWRwgiMo") + .terminalBlockHashEpochOverride(UInt64.valueOf(27263)) + .terminalBlockHashOverride( + Bytes32.fromHexString( + "0x39f44fc16dc964e8d2d1637b99e12992be4a4f766a66658da730e20e511ced64")); } private Builder applyHoleskyNetworkDefaults() { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java index f4cfac0dba1..afd05688137 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/executionlayer/ExecutionLayerChannel.java @@ -120,8 +120,7 @@ SafeFuture engineForkChoiceUpdated( ForkChoiceState forkChoiceState, Optional payloadBuildingAttributes); - SafeFuture engineNewPayload( - NewPayloadRequest newPayloadRequest, final UInt64 slot); + SafeFuture engineNewPayload(NewPayloadRequest newPayloadRequest, UInt64 slot); SafeFuture> engineGetClientVersion(ClientVersion clientVersion); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/helpers/MiscHelpersDeneb.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/helpers/MiscHelpersDeneb.java index ebf9e188b45..87953843804 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/helpers/MiscHelpersDeneb.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/logic/versions/deneb/helpers/MiscHelpersDeneb.java @@ -37,8 +37,12 @@ import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecarSchema; import tech.pegasys.teku.spec.datastructures.blocks.BeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; +import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockHeader; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.BeaconBlockBody; +import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BeaconBlockBodyDeneb; import tech.pegasys.teku.spec.datastructures.blocks.blockbody.versions.deneb.BeaconBlockBodySchemaDeneb; +import tech.pegasys.teku.spec.datastructures.execution.BlobAndProof; +import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobIdentifier; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; import tech.pegasys.teku.spec.datastructures.type.SszKZGProof; import tech.pegasys.teku.spec.logic.common.helpers.MiscHelpers; @@ -266,6 +270,32 @@ public BlobSidecar constructBlobSidecar( index, blob, commitment, proof, signedBeaconBlock.asHeader(), kzgCommitmentInclusionProof); } + public BlobSidecar constructBlobSidecarFromBlobAndProof( + final BlobIdentifier blobIdentifier, + final BlobAndProof blobAndProof, + final BeaconBlockBodyDeneb beaconBlockBodyDeneb, + final SignedBeaconBlockHeader signedBeaconBlockHeader) { + + final SszKZGCommitment sszKZGCommitment = + beaconBlockBodyDeneb.getBlobKzgCommitments().get(blobIdentifier.getIndex().intValue()); + + final BlobSidecar blobSidecar = + blobSidecarSchema.create( + blobIdentifier.getIndex(), + blobAndProof.blob(), + sszKZGCommitment, + new SszKZGProof(blobAndProof.proof()), + signedBeaconBlockHeader, + computeKzgCommitmentInclusionProof(blobIdentifier.getIndex(), beaconBlockBodyDeneb)); + + blobSidecar.markSignatureAsValidated(); + blobSidecar.markKzgCommitmentInclusionProofAsValidated(); + // assume kzg validation done by local EL + blobSidecar.markKzgAsValidated(); + + return blobSidecar; + } + public boolean verifyBlobKzgCommitmentInclusionProof(final BlobSidecar blobSidecar) { if (blobSidecar.isKzgCommitmentInclusionProofValidated()) { return true; diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/interop/MockStartDepositGeneratorTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/interop/MockStartDepositGeneratorTest.java index 44d11829600..1554b3f0ca9 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/interop/MockStartDepositGeneratorTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/interop/MockStartDepositGeneratorTest.java @@ -16,12 +16,10 @@ import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; -import java.security.Security; import java.util.Arrays; import java.util.List; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.jupiter.api.Test; import tech.pegasys.teku.bls.BLSKeyPair; import tech.pegasys.teku.bls.BLSSecretKey; @@ -60,10 +58,6 @@ class MockStartDepositGeneratorTest { private final Spec spec = TestSpecFactory.createDefault(); private final MockStartDepositGenerator generator = new MockStartDepositGenerator(spec); - static { - Security.addProvider(new BouncyCastleProvider()); - } - @Test public void shouldGenerateDepositData() { final List keyPairs = diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/operations/DepositTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/operations/DepositTest.java index 5769bfb7860..fe8b1c9fd2d 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/operations/DepositTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/operations/DepositTest.java @@ -24,15 +24,12 @@ import java.util.Objects; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.junit.BouncyCastleExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tech.pegasys.teku.infrastructure.ssz.SszTestUtils; import tech.pegasys.teku.infrastructure.ssz.collections.SszBytes32Vector; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.util.DataStructureUtil; -@ExtendWith(BouncyCastleExtension.class) class DepositTest { private final DataStructureUtil dataStructureUtil = new DataStructureUtil(TestSpecFactory.createDefault()); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/HistoricalBatchTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/HistoricalBatchTest.java index 3ca75e9921b..4bb6aeaf0a3 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/HistoricalBatchTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/HistoricalBatchTest.java @@ -18,9 +18,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import java.util.stream.IntStream; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.junit.BouncyCastleExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tech.pegasys.teku.infrastructure.ssz.SszTestUtils; import tech.pegasys.teku.infrastructure.ssz.collections.SszMutableBytes32Vector; import tech.pegasys.teku.spec.Spec; @@ -28,7 +26,6 @@ import tech.pegasys.teku.spec.datastructures.state.HistoricalBatch.HistoricalBatchSchema; import tech.pegasys.teku.spec.util.DataStructureUtil; -@ExtendWith(BouncyCastleExtension.class) public class HistoricalBatchTest { private static final Spec SPEC = TestSpecFactory.createMainnetPhase0(); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateSchemaTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateSchemaTest.java index 015ac23ba02..353f9bc3ea1 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateSchemaTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateSchemaTest.java @@ -23,9 +23,7 @@ import it.unimi.dsi.fastutil.ints.IntList; import java.util.List; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.junit.BouncyCastleExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tech.pegasys.teku.infrastructure.ssz.SszTestUtils; import tech.pegasys.teku.infrastructure.ssz.schema.SszPrimitiveSchemas; import tech.pegasys.teku.infrastructure.ssz.schema.SszVectorSchema; @@ -40,7 +38,6 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.MutableBeaconState; import tech.pegasys.teku.spec.util.DataStructureUtil; -@ExtendWith(BouncyCastleExtension.class) public abstract class AbstractBeaconStateSchemaTest< T extends BeaconState, TMutable extends MutableBeaconState> { diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java index 18421bada2e..3da8c63fd16 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/state/beaconstate/common/AbstractBeaconStateTest.java @@ -15,9 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import org.apache.tuweni.junit.BouncyCastleExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.config.SpecConfig; @@ -27,7 +25,6 @@ import tech.pegasys.teku.spec.schemas.registry.SchemaRegistry; import tech.pegasys.teku.spec.util.DataStructureUtil; -@ExtendWith(BouncyCastleExtension.class) public abstract class AbstractBeaconStateTest< T extends BeaconState, TMutable extends MutableBeaconState> { diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/block/BlockProcessorTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/block/BlockProcessorTest.java index 4b146409389..96ecf5a5f68 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/block/BlockProcessorTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/block/BlockProcessorTest.java @@ -21,9 +21,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.Bytes48; -import org.apache.tuweni.junit.BouncyCastleExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tech.pegasys.teku.bls.BLSPublicKey; import tech.pegasys.teku.bls.BLSSignature; import tech.pegasys.teku.infrastructure.ssz.SszList; @@ -45,7 +43,6 @@ import tech.pegasys.teku.spec.logic.common.statetransition.exceptions.BlockProcessingException; import tech.pegasys.teku.spec.util.DataStructureUtil; -@ExtendWith(BouncyCastleExtension.class) public abstract class BlockProcessorTest { protected final Spec spec = createSpec(); protected final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/util/BeaconStateUtilTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/util/BeaconStateUtilTest.java index 93876a268f4..cff95833239 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/util/BeaconStateUtilTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/common/util/BeaconStateUtilTest.java @@ -17,9 +17,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static tech.pegasys.teku.spec.config.SpecConfig.GENESIS_SLOT; -import org.apache.tuweni.junit.BouncyCastleExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecVersion; @@ -31,7 +29,6 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.BeaconState; import tech.pegasys.teku.spec.util.DataStructureUtil; -@ExtendWith(BouncyCastleExtension.class) public class BeaconStateUtilTest { private final Spec spec = TestSpecFactory.createMinimalPhase0(); private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/helpers/BellatrixTransitionHelpersTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/helpers/BellatrixTransitionHelpersTest.java index a95bc2e08ae..f4139234907 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/helpers/BellatrixTransitionHelpersTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/logic/versions/bellatrix/helpers/BellatrixTransitionHelpersTest.java @@ -16,6 +16,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import static tech.pegasys.teku.infrastructure.async.SafeFuture.completedFuture; @@ -97,6 +98,8 @@ void shouldBeValidWhenTerminalBlockHashMatchesInActivationEpoch() { .getBellatrixTransitionHelpers() .orElseThrow() .validateMergeBlock(executionLayer, payload, blockSlot); + // Verify EL is never called if hash is configured and matches + verifyNoMoreInteractions(executionLayer); assertPayloadResultStatus(result, ExecutionPayloadStatus.VALID); } diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/type/Bytes32Supplier.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/type/Bytes32Supplier.java deleted file mode 100644 index 1ea025dc6f9..00000000000 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/type/Bytes32Supplier.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.spec.propertytest.suppliers.type; - -import net.jqwik.api.Arbitraries; -import net.jqwik.api.Arbitrary; -import net.jqwik.api.ArbitrarySupplier; -import org.apache.tuweni.bytes.Bytes32; - -public class Bytes32Supplier implements ArbitrarySupplier { - @Override - public Arbitrary get() { - return Arbitraries.bytes().array(byte[].class).ofSize(32).map(Bytes32::wrap); - } -} diff --git a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/type/UInt64Supplier.java b/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/type/UInt64Supplier.java deleted file mode 100644 index d4d3f11851e..00000000000 --- a/ethereum/spec/src/testFixtures/java/tech/pegasys/teku/spec/propertytest/suppliers/type/UInt64Supplier.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.spec.propertytest.suppliers.type; - -import net.jqwik.api.Arbitraries; -import net.jqwik.api.Arbitrary; -import net.jqwik.api.ArbitrarySupplier; -import tech.pegasys.teku.infrastructure.unsigned.UInt64; - -public class UInt64Supplier implements ArbitrarySupplier { - @Override - public Arbitrary get() { - return Arbitraries.longs().map(UInt64::fromLongBits); - } -} diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlobSidecarManagerImpl.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlobSidecarManagerImpl.java index fc20d0c60e8..22609e00b69 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlobSidecarManagerImpl.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlobSidecarManagerImpl.java @@ -66,9 +66,7 @@ public BlobSidecarManagerImpl( invalidBlobSidecarRoots, (tracker) -> new ForkChoiceBlobSidecarsAvailabilityChecker(spec, recentChainData, tracker, kzg), - // we don't care to set maxBlobsPerBlock since it isn't used with this immediate validation - // flow - (block) -> new BlockBlobSidecarsTracker(block.getSlotAndBlockRoot(), UInt64.ZERO)); + (block) -> new BlockBlobSidecarsTracker(block.getSlotAndBlockRoot())); } @VisibleForTesting diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java index 64c89d91ba1..83faba90209 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTracker.java @@ -40,13 +40,15 @@ public class BlockBlobSidecarsTracker { private static final Logger LOG = LogManager.getLogger(); + private static final UInt64 CREATION_TIMING_IDX = UInt64.MAX_VALUE; private static final UInt64 BLOCK_ARRIVAL_TIMING_IDX = CREATION_TIMING_IDX.decrement(); - private static final UInt64 RPC_FETCH_TIMING_IDX = BLOCK_ARRIVAL_TIMING_IDX.decrement(); - private static final UInt64 LOCAL_EL_FETCH_TIMING_IDX = RPC_FETCH_TIMING_IDX.decrement(); + private static final UInt64 RPC_BLOCK_FETCH_TIMING_IDX = BLOCK_ARRIVAL_TIMING_IDX.decrement(); + private static final UInt64 RPC_BLOBS_FETCH_TIMING_IDX = RPC_BLOCK_FETCH_TIMING_IDX.decrement(); + private static final UInt64 LOCAL_EL_BLOBS_FETCH_TIMING_IDX = + RPC_BLOBS_FETCH_TIMING_IDX.decrement(); private final SlotAndBlockRoot slotAndBlockRoot; - private final UInt64 maxBlobsPerBlock; private final AtomicReference> block = new AtomicReference<>(Optional.empty()); @@ -56,8 +58,9 @@ public class BlockBlobSidecarsTracker { private final NavigableMap blobSidecars = new ConcurrentSkipListMap<>(); private final SafeFuture blobSidecarsComplete = new SafeFuture<>(); - private volatile boolean rpcFetchTriggered = false; - private volatile boolean localElFetchTriggered = false; + private volatile boolean localElBlobsFetchTriggered = false; + private volatile boolean rpcBlockFetchTriggered = false; + private volatile boolean rpcBlobsFetchTriggered = false; private final Optional> maybeDebugTimings; @@ -69,12 +72,9 @@ public class BlockBlobSidecarsTracker { * tracker instance will be used, so no synchronization is required * * @param slotAndBlockRoot slot and block root to create tracker for - * @param maxBlobsPerBlock max number of blobs per block for the slot */ - public BlockBlobSidecarsTracker( - final SlotAndBlockRoot slotAndBlockRoot, final UInt64 maxBlobsPerBlock) { + public BlockBlobSidecarsTracker(final SlotAndBlockRoot slotAndBlockRoot) { this.slotAndBlockRoot = slotAndBlockRoot; - this.maxBlobsPerBlock = maxBlobsPerBlock; if (LOG.isDebugEnabled()) { // don't need a concurrent hashmap since we'll interact with it from synchronized BlobSidecar // pool methods @@ -112,31 +112,13 @@ public Optional getBlobSidecar(final UInt64 index) { public Stream getMissingBlobSidecars() { final Optional blockCommitmentsCount = getBlockKzgCommitmentsCount(); - if (blockCommitmentsCount.isPresent()) { - return UInt64.range(UInt64.ZERO, UInt64.valueOf(blockCommitmentsCount.get())) - .filter(blobIndex -> !blobSidecars.containsKey(blobIndex)) - .map(blobIndex -> new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), blobIndex)); - } + checkState(blockCommitmentsCount.isPresent(), "Block must be known to call this method"); - if (blobSidecars.isEmpty()) { - return Stream.of(); - } - - // We may return maxBlobsPerBlock because we don't know the block - return UInt64.range(UInt64.ZERO, maxBlobsPerBlock) + return UInt64.range(UInt64.ZERO, UInt64.valueOf(blockCommitmentsCount.get())) .filter(blobIndex -> !blobSidecars.containsKey(blobIndex)) .map(blobIndex -> new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), blobIndex)); } - public Stream getUnusedBlobSidecarsForBlock() { - final Optional blockCommitmentsCount = getBlockKzgCommitmentsCount(); - checkState(blockCommitmentsCount.isPresent(), "Block must me known to call this method"); - - final UInt64 firstUnusedIndex = UInt64.valueOf(blockCommitmentsCount.get()); - return UInt64.range(firstUnusedIndex, maxBlobsPerBlock) - .map(blobIndex -> new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), blobIndex)); - } - public boolean add(final BlobSidecar blobSidecar) { checkArgument( blobSidecar.getBlockRoot().equals(slotAndBlockRoot.getBlockRoot()), @@ -247,24 +229,35 @@ public boolean isComplete() { return blobSidecarsComplete.isDone(); } - public boolean isRpcFetchTriggered() { - return rpcFetchTriggered; + public boolean isLocalElBlobsFetchTriggered() { + return localElBlobsFetchTriggered; } - public void setRpcFetchTriggered() { - this.rpcFetchTriggered = true; + public void setLocalElBlobsFetchTriggered() { + this.localElBlobsFetchTriggered = true; maybeDebugTimings.ifPresent( - debugTimings -> debugTimings.put(RPC_FETCH_TIMING_IDX, System.currentTimeMillis())); + debugTimings -> + debugTimings.put(LOCAL_EL_BLOBS_FETCH_TIMING_IDX, System.currentTimeMillis())); } - public boolean isLocalElFetchTriggered() { - return localElFetchTriggered; + public boolean isRpcBlockFetchTriggered() { + return rpcBlockFetchTriggered; } - public void setLocalElFetchTriggered() { - this.localElFetchTriggered = true; + public void setRpcBlockFetchTriggered() { + this.rpcBlockFetchTriggered = true; maybeDebugTimings.ifPresent( - debugTimings -> debugTimings.put(LOCAL_EL_FETCH_TIMING_IDX, System.currentTimeMillis())); + debugTimings -> debugTimings.put(RPC_BLOCK_FETCH_TIMING_IDX, System.currentTimeMillis())); + } + + public boolean isRpcBlobsFetchTriggered() { + return rpcBlobsFetchTriggered; + } + + public void setRpcBlobsFetchTriggered() { + this.rpcBlobsFetchTriggered = true; + maybeDebugTimings.ifPresent( + debugTimings -> debugTimings.put(RPC_BLOBS_FETCH_TIMING_IDX, System.currentTimeMillis())); } private boolean areBlobsComplete() { @@ -315,22 +308,31 @@ private void printDebugTimings(final Map debugTimings) { .append(debugTimings.getOrDefault(BLOCK_ARRIVAL_TIMING_IDX, 0L) - creationTime) .append("ms - "); - if (debugTimings.containsKey(LOCAL_EL_FETCH_TIMING_IDX)) { + if (debugTimings.containsKey(LOCAL_EL_BLOBS_FETCH_TIMING_IDX)) { + timingsReport + .append("Local EL blobs fetch delay ") + .append(debugTimings.get(LOCAL_EL_BLOBS_FETCH_TIMING_IDX) - creationTime) + .append("ms - "); + } else { + timingsReport.append("Local EL blobs fetch wasn't required - "); + } + + if (debugTimings.containsKey(RPC_BLOCK_FETCH_TIMING_IDX)) { timingsReport - .append("Local EL fetch delay ") - .append(debugTimings.get(LOCAL_EL_FETCH_TIMING_IDX) - creationTime) + .append("RPC block fetch delay ") + .append(debugTimings.get(RPC_BLOCK_FETCH_TIMING_IDX) - creationTime) .append("ms - "); } else { - timingsReport.append("Local EL fetch wasn't required - "); + timingsReport.append("RPC block fetch wasn't required - "); } - if (debugTimings.containsKey(RPC_FETCH_TIMING_IDX)) { + if (debugTimings.containsKey(RPC_BLOBS_FETCH_TIMING_IDX)) { timingsReport - .append("RPC fetch delay ") - .append(debugTimings.get(RPC_FETCH_TIMING_IDX) - creationTime) + .append("RPC blobs fetch delay ") + .append(debugTimings.get(RPC_BLOBS_FETCH_TIMING_IDX) - creationTime) .append("ms"); } else { - timingsReport.append("RPC fetch wasn't required"); + timingsReport.append("RPC blobs fetch wasn't required"); } LOG.debug(timingsReport.toString()); @@ -342,8 +344,9 @@ public String toString() { .add("slotAndBlockRoot", slotAndBlockRoot) .add("isBlockPresent", block.get().isPresent()) .add("isComplete", isComplete()) - .add("rpcFetchTriggered", rpcFetchTriggered) - .add("localElFetchTriggered", localElFetchTriggered) + .add("localElBlobsFetchTriggered", localElBlobsFetchTriggered) + .add("rpcBlockFetchTriggered", rpcBlockFetchTriggered) + .add("rpcBlobsFetchTriggered", rpcBlobsFetchTriggered) .add("blockImportOnCompletionEnabled", blockImportOnCompletionEnabled.get()) .add( "blobSidecars", diff --git a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java index 0bfb291d0e2..e4b09d381e0 100644 --- a/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java +++ b/ethereum/statetransition/src/main/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImpl.java @@ -48,9 +48,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.SpecVersion; -import tech.pegasys.teku.spec.config.SpecConfigDeneb; import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecar; -import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSidecarSchema; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlock; import tech.pegasys.teku.spec.datastructures.blocks.SignedBeaconBlockHeader; import tech.pegasys.teku.spec.datastructures.blocks.SlotAndBlockRoot; @@ -58,7 +56,6 @@ import tech.pegasys.teku.spec.datastructures.execution.BlobAndProof; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.BlobIdentifier; import tech.pegasys.teku.spec.datastructures.type.SszKZGCommitment; -import tech.pegasys.teku.spec.datastructures.type.SszKZGProof; import tech.pegasys.teku.spec.executionlayer.ExecutionLayerChannel; import tech.pegasys.teku.spec.logic.versions.deneb.helpers.MiscHelpersDeneb; import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash; @@ -92,6 +89,7 @@ public class BlockBlobSidecarsTrackersPoolImpl extends AbstractIgnoringFutureHis static final String GAUGE_BLOB_SIDECARS_LABEL = "blob_sidecars"; static final String GAUGE_BLOB_SIDECARS_TRACKERS_LABEL = "blob_sidecars_trackers"; + // RPC fetching delay timings static final UInt64 MAX_WAIT_RELATIVE_TO_ATT_DUE_MILLIS = UInt64.valueOf(1500); static final UInt64 MIN_WAIT_MILLIS = UInt64.valueOf(500); static final UInt64 TARGET_WAIT_MILLIS = UInt64.valueOf(1000); @@ -154,7 +152,7 @@ public class BlockBlobSidecarsTrackersPoolImpl extends AbstractIgnoringFutureHis this.maxTrackers = maxTrackers; this.sizeGauge = sizeGauge; this.poolStatsCounters = poolStatsCounters; - this.trackerFactory = (slotAndBlockRoot) -> createTracker(spec, slotAndBlockRoot); + this.trackerFactory = BlockBlobSidecarsTracker::new; initMetrics(sizeGauge, poolStatsCounters); } @@ -209,15 +207,6 @@ private static void initMetrics( }); } - private static BlockBlobSidecarsTracker createTracker( - final Spec spec, final SlotAndBlockRoot slotAndBlockRoot) { - return new BlockBlobSidecarsTracker( - slotAndBlockRoot, - UInt64.valueOf( - SpecConfigDeneb.required(spec.atSlot(slotAndBlockRoot.getSlot()).getConfig()) - .getMaxBlobsPerBlock())); - } - @Override public synchronized void onNewBlobSidecar( final BlobSidecar blobSidecar, final RemoteOrigin remoteOrigin) { @@ -230,12 +219,25 @@ public synchronized void onNewBlobSidecar( final SlotAndBlockRoot slotAndBlockRoot = blobSidecar.getSlotAndBlockRoot(); - final BlockBlobSidecarsTracker blobSidecarsTracker = - getOrCreateBlobSidecarsTracker( - slotAndBlockRoot, - newTracker -> onFirstSeen(slotAndBlockRoot, Optional.of(remoteOrigin)), - existingTracker -> {}); + getOrCreateBlobSidecarsTracker( + slotAndBlockRoot, + newTracker -> { + addBlobSidecarToTracker(newTracker, slotAndBlockRoot, blobSidecar, remoteOrigin); + onFirstSeen(slotAndBlockRoot, Optional.of(remoteOrigin)); + }, + existingTracker -> + addBlobSidecarToTracker(existingTracker, slotAndBlockRoot, blobSidecar, remoteOrigin)); + + if (orderedBlobSidecarsTrackers.add(slotAndBlockRoot)) { + sizeGauge.set(orderedBlobSidecarsTrackers.size(), GAUGE_BLOB_SIDECARS_TRACKERS_LABEL); + } + } + private void addBlobSidecarToTracker( + final BlockBlobSidecarsTracker blobSidecarsTracker, + final SlotAndBlockRoot slotAndBlockRoot, + final BlobSidecar blobSidecar, + final RemoteOrigin remoteOrigin) { if (blobSidecarsTracker.add(blobSidecar)) { sizeGauge.set(++totalBlobSidecars, GAUGE_BLOB_SIDECARS_LABEL); countBlobSidecar(remoteOrigin); @@ -246,10 +248,6 @@ public synchronized void onNewBlobSidecar( } else { countDuplicateBlobSidecar(remoteOrigin); } - - if (orderedBlobSidecarsTrackers.add(slotAndBlockRoot)) { - sizeGauge.set(orderedBlobSidecarsTrackers.size(), GAUGE_BLOB_SIDECARS_TRACKERS_LABEL); - } } private void publishRecoveredBlobSidecar(final BlobSidecar blobSidecar) { @@ -326,7 +324,7 @@ public synchronized void onCompletedBlockAndBlobSidecars( long addedBlobs = blobSidecars.stream() - .map( + .filter( blobSidecar -> { final boolean isNew = blobSidecarsTracker.add(blobSidecar); if (isNew) { @@ -335,7 +333,6 @@ public synchronized void onCompletedBlockAndBlobSidecars( } return isNew; }) - .filter(Boolean::booleanValue) .count(); totalBlobSidecars += (int) addedBlobs; sizeGauge.set(totalBlobSidecars, GAUGE_BLOB_SIDECARS_LABEL); @@ -427,7 +424,13 @@ public synchronized Optional getBlock(final Bytes32 blockRoot @Override public synchronized Set getAllRequiredBlobSidecars() { return blockBlobSidecarsTrackers.values().stream() - .flatMap(BlockBlobSidecarsTracker::getMissingBlobSidecars) + .flatMap( + tracker -> { + if (tracker.getBlock().isEmpty()) { + return Stream.empty(); + } + return tracker.getMissingBlobSidecars(); + }) .collect(Collectors.toSet()); } @@ -495,25 +498,24 @@ private BlockBlobSidecarsTracker internalOnNewBlock( countBlock(remoteOrigin); - if (existingTracker.isRpcFetchTriggered()) { - // block has been set for the first time and we previously triggered fetching of - // missing blobSidecars. So we may have requested to fetch more sidecars - // than the block actually requires. Let's drop them. - existingTracker - .getUnusedBlobSidecarsForBlock() - .forEach( - blobIdentifier -> - requiredBlobSidecarDroppedSubscribers.deliver( - RequiredBlobSidecarDroppedSubscriber::onRequiredBlobSidecarDropped, - blobIdentifier)); - - // if we attempted to fetch via RPC, we missed the opportunity to complete the - // tracker via local EL (local El fetch requires the block to be known) - // Let's try now - if (!existingTracker.isLocalElFetchTriggered() && !existingTracker.isComplete()) { - fetchMissingContentFromLocalEL(slotAndBlockRoot) - .finish(this::logLocalElBlobsLookupFailure); - } + if (!existingTracker.isComplete()) { + // we missed the opportunity to complete the blob sidecars via local EL and RPC + // (since the block is required to be known) Let's try now + asyncRunner + .runAsync( + () -> + fetchMissingBlobsFromLocalEL(slotAndBlockRoot) + .handleException(this::logLocalElBlobsLookupFailure) + .thenRun( + () -> { + // only run if RPC block fetch has happened + // (no blobs RPC fetch has occurred) + if (existingTracker.isRpcBlockFetchTriggered()) { + fetchMissingBlockOrBlobsFromRPC(slotAndBlockRoot); + } + }) + .handleException(this::logBlockOrBlobsRPCFailure)) + .ifExceptionGetsHereRaiseABug(); } }); @@ -575,7 +577,7 @@ private BlockBlobSidecarsTracker getOrCreateBlobSidecarsTracker( } private void makeRoomForNewTracker() { - while (blockBlobSidecarsTrackers.size() > (maxTrackers - 1)) { + while (blockBlobSidecarsTrackers.size() > maxTrackers - 1) { final SlotAndBlockRoot toRemove = orderedBlobSidecarsTrackers.pollFirst(); if (toRemove == null) { break; @@ -591,27 +593,24 @@ private void onFirstSeen( if (isLocalBlockProduction) { return; } - - final Duration fetchDelay = calculateFetchDelay(slotAndBlockRoot); + // delay RPC fetching + final SafeFuture rpcFetchDelay = + asyncRunner.getDelayedFuture(calculateRpcFetchDelay(slotAndBlockRoot)); asyncRunner - .runAfterDelay( + .runAsync( () -> - this.fetchMissingContentFromLocalEL(slotAndBlockRoot) + // fetch blobs from EL with no delay + fetchMissingBlobsFromLocalEL(slotAndBlockRoot) .handleException(this::logLocalElBlobsLookupFailure) - .thenRun(() -> this.fetchMissingContentFromRemotePeers(slotAndBlockRoot)), - fetchDelay) - .finish( - error -> - LOG.error("An error occurred while attempting to fetch missing blobs.", error)); - } - - private void logLocalElBlobsLookupFailure(final Throwable error) { - LOG.warn("Local EL blobs lookup failed: {}", getRootCauseMessage(error)); + .thenCompose(__ -> rpcFetchDelay) + .thenRun(() -> fetchMissingBlockOrBlobsFromRPC(slotAndBlockRoot)) + .handleException(this::logBlockOrBlobsRPCFailure)) + .ifExceptionGetsHereRaiseABug(); } @VisibleForTesting - Duration calculateFetchDelay(final SlotAndBlockRoot slotAndBlockRoot) { + Duration calculateRpcFetchDelay(final SlotAndBlockRoot slotAndBlockRoot) { final UInt64 slot = slotAndBlockRoot.getSlot(); if (slot.isLessThan(getCurrentSlot())) { @@ -641,28 +640,21 @@ Duration calculateFetchDelay(final SlotAndBlockRoot slotAndBlockRoot) { return Duration.ofMillis(finalTime.minus(nowMillis).intValue()); } - private synchronized SafeFuture fetchMissingContentFromLocalEL( + private synchronized SafeFuture fetchMissingBlobsFromLocalEL( final SlotAndBlockRoot slotAndBlockRoot) { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = blockBlobSidecarsTrackers.get(slotAndBlockRoot.getBlockRoot()); - if (blockBlobSidecarsTracker == null) { - return SafeFuture.COMPLETE; - } - - if (blockBlobSidecarsTracker.isComplete()) { - return SafeFuture.COMPLETE; - } - - if (blockBlobSidecarsTracker.getBlock().isEmpty()) { + if (blockBlobSidecarsTracker == null + || blockBlobSidecarsTracker.isComplete() + || blockBlobSidecarsTracker.getBlock().isEmpty()) { return SafeFuture.COMPLETE; } - blockBlobSidecarsTracker.setLocalElFetchTriggered(); + final List missingBlobsIdentifiers = + blockBlobSidecarsTracker.getMissingBlobSidecars().toList(); final SpecVersion specVersion = spec.atSlot(slotAndBlockRoot.getSlot()); - final BlobSidecarSchema blobSidecarSchema = - specVersion.getSchemaDefinitions().toVersionDeneb().orElseThrow().getBlobSidecarSchema(); final MiscHelpersDeneb miscHelpersDeneb = specVersion.miscHelpers().toVersionDeneb().orElseThrow(); final SignedBeaconBlockHeader signedBeaconBlockHeader = @@ -679,9 +671,6 @@ private synchronized SafeFuture fetchMissingContentFromLocalEL( final SszList sszKZGCommitments = beaconBlockBodyDeneb.getBlobKzgCommitments(); - final List missingBlobsIdentifiers = - blockBlobSidecarsTracker.getMissingBlobSidecars().toList(); - final List versionedHashes = missingBlobsIdentifiers.stream() .map( @@ -692,6 +681,8 @@ private synchronized SafeFuture fetchMissingContentFromLocalEL( .getKZGCommitment())) .toList(); + blockBlobSidecarsTracker.setLocalElBlobsFetchTriggered(); + poolStatsCounters .labels(COUNTER_SIDECAR_TYPE, COUNTER_LOCAL_EL_FETCH_SUBTYPE) .inc(versionedHashes.size()); @@ -708,16 +699,15 @@ private synchronized SafeFuture fetchMissingContentFromLocalEL( for (int index = 0; index < blobAndProofs.size(); index++) { final Optional blobAndProof = blobAndProofs.get(index); + final BlobIdentifier blobIdentifier = missingBlobsIdentifiers.get(index); if (blobAndProof.isEmpty()) { - LOG.trace("Blob not found on local EL: {}", missingBlobsIdentifiers.get(index)); + LOG.trace("Blob not found on local EL: {}", blobIdentifier); continue; } final BlobSidecar blobSidecar = - createBlobSidecarFromBlobAndProof( - blobSidecarSchema, - miscHelpersDeneb, - missingBlobsIdentifiers.get(index), + miscHelpersDeneb.constructBlobSidecarFromBlobAndProof( + blobIdentifier, blobAndProof.get(), beaconBlockBodyDeneb, signedBeaconBlockHeader); @@ -726,57 +716,32 @@ private synchronized SafeFuture fetchMissingContentFromLocalEL( }); } - private BlobSidecar createBlobSidecarFromBlobAndProof( - final BlobSidecarSchema blobSidecarSchema, - final MiscHelpersDeneb miscHelpersDeneb, - final BlobIdentifier blobIdentifier, - final BlobAndProof blobAndProof, - final BeaconBlockBodyDeneb beaconBlockBodyDeneb, - final SignedBeaconBlockHeader signedBeaconBlockHeader) { - - final SszKZGCommitment sszKZGCommitment = - beaconBlockBodyDeneb.getBlobKzgCommitments().get(blobIdentifier.getIndex().intValue()); - - final BlobSidecar blobSidecar = - blobSidecarSchema.create( - blobIdentifier.getIndex(), - blobAndProof.blob(), - sszKZGCommitment, - new SszKZGProof(blobAndProof.proof()), - signedBeaconBlockHeader, - miscHelpersDeneb.computeKzgCommitmentInclusionProof( - blobIdentifier.getIndex(), beaconBlockBodyDeneb)); - - blobSidecar.markSignatureAsValidated(); - blobSidecar.markKzgCommitmentInclusionProofAsValidated(); - // assume kzg validation done by local EL - blobSidecar.markKzgAsValidated(); - - return blobSidecar; + private void logLocalElBlobsLookupFailure(final Throwable error) { + LOG.warn("Local EL blobs lookup failed: {}", getRootCauseMessage(error)); } - private synchronized void fetchMissingContentFromRemotePeers( + private synchronized void fetchMissingBlockOrBlobsFromRPC( final SlotAndBlockRoot slotAndBlockRoot) { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = blockBlobSidecarsTrackers.get(slotAndBlockRoot.getBlockRoot()); - if (blockBlobSidecarsTracker == null) { + if (blockBlobSidecarsTracker == null || blockBlobSidecarsTracker.isComplete()) { return; } - if (blockBlobSidecarsTracker.isComplete()) { - return; - } + if (blockBlobSidecarsTracker.getBlock().isEmpty()) { - blockBlobSidecarsTracker.setRpcFetchTriggered(); + blockBlobSidecarsTracker.setRpcBlockFetchTriggered(); - if (blockBlobSidecarsTracker.getBlock().isEmpty()) { poolStatsCounters.labels(COUNTER_BLOCK_TYPE, COUNTER_RPC_FETCH_SUBTYPE).inc(); requiredBlockRootSubscribers.deliver( RequiredBlockRootSubscriber::onRequiredBlockRoot, blockBlobSidecarsTracker.getSlotAndBlockRoot().getBlockRoot()); + return; } + blockBlobSidecarsTracker.setRpcBlobsFetchTriggered(); + blockBlobSidecarsTracker .getMissingBlobSidecars() .forEach( @@ -787,24 +752,27 @@ private synchronized void fetchMissingContentFromRemotePeers( }); } - private void dropMissingContent(final BlockBlobSidecarsTracker blockBlobSidecarsTracker) { + private void logBlockOrBlobsRPCFailure(final Throwable error) { + LOG.error("An error occurred while attempting to fetch block or blobs via RPC.", error); + } - if (!blockBlobSidecarsTracker.isRpcFetchTriggered()) { - return; - } + private void dropMissingContent(final BlockBlobSidecarsTracker blockBlobSidecarsTracker) { - if (blockBlobSidecarsTracker.getBlock().isEmpty()) { + if (blockBlobSidecarsTracker.isRpcBlockFetchTriggered() + && blockBlobSidecarsTracker.getBlock().isEmpty()) { requiredBlockRootDroppedSubscribers.deliver( RequiredBlockRootDroppedSubscriber::onRequiredBlockRootDropped, blockBlobSidecarsTracker.getSlotAndBlockRoot().getBlockRoot()); } - blockBlobSidecarsTracker - .getMissingBlobSidecars() - .forEach( - blobIdentifier -> - requiredBlobSidecarDroppedSubscribers.deliver( - RequiredBlobSidecarDroppedSubscriber::onRequiredBlobSidecarDropped, - blobIdentifier)); + if (blockBlobSidecarsTracker.isRpcBlobsFetchTriggered()) { + blockBlobSidecarsTracker + .getMissingBlobSidecars() + .forEach( + blobIdentifier -> + requiredBlobSidecarDroppedSubscribers.deliver( + RequiredBlobSidecarDroppedSubscriber::onRequiredBlobSidecarDropped, + blobIdentifier)); + } } } diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTrackerTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTrackerTest.java index 275fb2fcada..662c97d818d 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTrackerTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/blobs/BlockBlobSidecarsTrackerTest.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; @@ -65,11 +64,10 @@ public class BlockBlobSidecarsTrackerTest { @Test void isNotCompletedJustAfterCreation() { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); SafeFutureAssert.assertThatSafeFuture(blockBlobSidecarsTracker.getCompletionFuture()) .isNotCompleted(); - assertThat(blockBlobSidecarsTracker.getMissingBlobSidecars()).isEmpty(); assertThat(blockBlobSidecarsTracker.getBlock()).isEmpty(); assertThat(blockBlobSidecarsTracker.getBlobSidecars()).isEmpty(); assertThat(blockBlobSidecarsTracker.getSlotAndBlockRoot()).isEqualTo(slotAndBlockRoot); @@ -81,7 +79,7 @@ void isNotCompletedJustAfterCreation() { @Test void setBlock_shouldAcceptCorrectBlock() { BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); blockBlobSidecarsTracker.setBlock(block); SafeFutureAssert.assertThatSafeFuture(blockBlobSidecarsTracker.getCompletionFuture()) @@ -95,7 +93,7 @@ void setBlock_shouldAcceptCorrectBlock() { @Test void setBlock_shouldThrowWithWrongBlock() { BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(dataStructureUtil.randomSlotAndBlockRoot(), maxBlobsPerBlock); + new BlockBlobSidecarsTracker(dataStructureUtil.randomSlotAndBlockRoot()); assertThatThrownBy(() -> blockBlobSidecarsTracker.setBlock(block)) .isInstanceOf(IllegalArgumentException.class); } @@ -103,7 +101,7 @@ void setBlock_shouldThrowWithWrongBlock() { @Test void setBlock_shouldAcceptBlockTwice() { BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); blockBlobSidecarsTracker.setBlock(block); blockBlobSidecarsTracker.setBlock(block); assertThat(blockBlobSidecarsTracker.getBlock()).isEqualTo(Optional.of(block)); @@ -115,7 +113,7 @@ void setBlock_immediatelyCompletesWithBlockWithoutBlobs() { final SlotAndBlockRoot slotAndBlockRoot = block.getSlotAndBlockRoot(); final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); final SafeFuture completionFuture = blockBlobSidecarsTracker.getCompletionFuture(); SafeFutureAssert.assertThatSafeFuture(completionFuture).isNotCompleted(); @@ -135,7 +133,7 @@ void getCompletionFuture_returnsIndependentFutures() { final SlotAndBlockRoot slotAndBlockRoot = block.getSlotAndBlockRoot(); final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); final SafeFuture completionFuture1 = blockBlobSidecarsTracker.getCompletionFuture(); final SafeFuture completionFuture2 = blockBlobSidecarsTracker.getCompletionFuture(); final SafeFuture completionFuture3 = blockBlobSidecarsTracker.getCompletionFuture(); @@ -168,23 +166,18 @@ void getCompletionFuture_returnsIndependentFutures() { @Test void add_shouldWorkTillCompletionWhenAddingBlobsBeforeBlockIsSet() { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock.plus(1)); - final BlobSidecar toAdd = blobSidecarsForBlock.get(0); + new BlockBlobSidecarsTracker(slotAndBlockRoot); + final BlobSidecar toAdd = blobSidecarsForBlock.getFirst(); final Map added = new HashMap<>(); final SafeFuture completionFuture = blockBlobSidecarsTracker.getCompletionFuture(); added.put(toAdd.getIndex(), toAdd); blockBlobSidecarsTracker.add(toAdd); - // we don't know the block, missing blobs are max blobs minus the blob we already have - final Set potentialMissingBlobs = - UInt64.range(UInt64.valueOf(1), maxBlobsPerBlock.plus(1)) - .map(index -> new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), index)) - .collect(Collectors.toSet()); - SafeFutureAssert.assertThatSafeFuture(completionFuture).isNotCompleted(); - assertThat(blockBlobSidecarsTracker.getMissingBlobSidecars()) - .containsExactlyInAnyOrderElementsOf(potentialMissingBlobs); + assertThatThrownBy(blockBlobSidecarsTracker::getMissingBlobSidecars) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Block must be known to call this method"); assertThat(blockBlobSidecarsTracker.getBlobSidecars()) .containsExactlyInAnyOrderEntriesOf(added); @@ -224,7 +217,7 @@ void add_shouldWorkTillCompletionWhenAddingBlobsBeforeBlockIsSet() { @Test void add_shouldWorkWhenBlockIsSetFirst() { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); final SafeFuture completionFuture = blockBlobSidecarsTracker.getCompletionFuture(); blockBlobSidecarsTracker.setBlock(block); @@ -249,7 +242,7 @@ void add_shouldWorkWhenBlockIsSetFirst() { @Test void add_shouldThrowWhenAddingInconsistentBlobSidecar() { BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(dataStructureUtil.randomSlotAndBlockRoot(), maxBlobsPerBlock); + new BlockBlobSidecarsTracker(dataStructureUtil.randomSlotAndBlockRoot()); assertThatThrownBy(() -> blockBlobSidecarsTracker.add(dataStructureUtil.randomBlobSidecar())) .isInstanceOf(IllegalArgumentException.class); } @@ -257,108 +250,29 @@ void add_shouldThrowWhenAddingInconsistentBlobSidecar() { @Test void add_shouldAcceptAcceptSameBlobSidecarTwice() { BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); blockBlobSidecarsTracker.setBlock(block); blockBlobSidecarsTracker.setBlock(block); assertThat(blockBlobSidecarsTracker.getBlock()).isEqualTo(Optional.of(block)); } @Test - void getMissingBlobSidecars_shouldReturnPartialBlobsIdentifierWhenBlockIsUnknown() { + void getMissingBlobSidecars_shouldThrowWhenBlockIsUnknown() { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); final BlobSidecar toAdd = blobSidecarsForBlock.get(2); blockBlobSidecarsTracker.add(toAdd); - final List knownMissing = - blobIdentifiersForBlock.stream() - .filter(blobIdentifier -> !blobIdentifier.getIndex().equals(UInt64.valueOf(2))) - .collect(Collectors.toList()); - - assertThat(blockBlobSidecarsTracker.getMissingBlobSidecars()) - .containsExactlyInAnyOrderElementsOf(knownMissing); - } - - @Test - void getUnusedBlobSidecarsForBlock_shouldReturnShouldFailIfBlockIsUnknown() { - final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); - - assertThatThrownBy(blockBlobSidecarsTracker::getUnusedBlobSidecarsForBlock) - .isInstanceOf(IllegalStateException.class); - } - - @Test - void getUnusedBlobSidecarsForBlock_shouldReturnEmptySetIfBlockIsFull() { - final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); - - blockBlobSidecarsTracker.setBlock(block); - - assertThat(blockBlobSidecarsTracker.getUnusedBlobSidecarsForBlock()).isEmpty(); - } - - @Test - void getUnusedBlobSidecarsForBlock_shouldReturnUnusedBlobSpace() { - final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock.plus(2)); - - blockBlobSidecarsTracker.setBlock(block); - - final Set expectedUnusedBlobs = - UInt64.range(maxBlobsPerBlock, maxBlobsPerBlock.plus(2)) - .map(index -> new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), index)) - .collect(Collectors.toSet()); - - assertThat(blockBlobSidecarsTracker.getUnusedBlobSidecarsForBlock()) - .containsExactlyInAnyOrderElementsOf(expectedUnusedBlobs); - } - - @Test - void getUnusedBlobSidecarsForBlock_shouldReturnAllMaxBlobsPerBlockIfBlockIsEmpty() { - - final SignedBeaconBlock block = dataStructureUtil.randomSignedBeaconBlockWithEmptyCommitments(); - final SlotAndBlockRoot slotAndBlockRoot = block.getSlotAndBlockRoot(); - - final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock.plus(2)); - - blockBlobSidecarsTracker.setBlock(block); - - final Set expectedUnusedBlobs = - UInt64.range(UInt64.ZERO, maxBlobsPerBlock.plus(2)) - .map(index -> new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), index)) - .collect(Collectors.toSet()); - - assertThat(blockBlobSidecarsTracker.getUnusedBlobSidecarsForBlock()) - .containsExactlyInAnyOrderElementsOf(expectedUnusedBlobs); - } - - @Test - void getMissingBlobSidecars_shouldRespectMaxBlobsPerBlock() { - final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); - final BlobSidecar toAdd = - dataStructureUtil - .createRandomBlobSidecarBuilder() - .signedBeaconBlockHeader(block.asHeader()) - .index(UInt64.valueOf(100)) - .build(); - - blockBlobSidecarsTracker.add(toAdd); - - final List knownMissing = - blobIdentifiersForBlock.subList(0, maxBlobsPerBlock.intValue()); - - assertThat(blockBlobSidecarsTracker.getMissingBlobSidecars()) - .containsExactlyInAnyOrderElementsOf(knownMissing); + assertThatThrownBy(blockBlobSidecarsTracker::getMissingBlobSidecars) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Block must be known to call this method"); } @Test void shouldNotIgnoreExcessiveBlobSidecarWhenBlockIsUnknownAndWePruneItLater() { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); final BlobSidecar legitBlobSidecar = createBlobSidecar(UInt64.valueOf(2)); final BlobSidecar excessiveBlobSidecar1 = createBlobSidecar(maxBlobsPerBlock); @@ -382,7 +296,7 @@ void shouldNotIgnoreExcessiveBlobSidecarWhenBlockIsUnknownAndWePruneItLater() { @Test void add_shouldIgnoreExcessiveBlobSidecarWhenBlockIsKnown() { final BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); blockBlobSidecarsTracker.setBlock(block); @@ -400,7 +314,7 @@ void add_shouldIgnoreExcessiveBlobSidecarWhenBlockIsKnown() { @Test void enableBlockImportOnCompletion_shouldImportOnlyOnceWhenCalled() { BlockBlobSidecarsTracker blockBlobSidecarsTracker = - new BlockBlobSidecarsTracker(slotAndBlockRoot, maxBlobsPerBlock); + new BlockBlobSidecarsTracker(slotAndBlockRoot); blockBlobSidecarsTracker.setBlock(block); diff --git a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImplTest.java b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImplTest.java index 2dad121a9eb..65b0c20c6d6 100644 --- a/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImplTest.java +++ b/ethereum/statetransition/src/test/java/tech/pegasys/teku/statetransition/util/BlockBlobSidecarsTrackersPoolImplTest.java @@ -15,6 +15,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -123,6 +124,8 @@ public void setup() { blockBlobSidecarsTrackersPool.subscribeRequiredBlobSidecarDropped( requiredBlobSidecarDroppedEvents::add); blockBlobSidecarsTrackersPool.subscribeNewBlobSidecar(newBlobSidecarEvents::add); + when(executionLayer.engineGetBlobs(any(), eq(currentSlot))) + .thenReturn(SafeFuture.completedFuture(List.of())); when(blobSidecarPublisher.apply(any())).thenReturn(SafeFuture.COMPLETE); setSlot(currentSlot); } @@ -463,7 +466,7 @@ public void onCompletedBlockAndBlobSidecars_shouldCreateTrackerIgnoringHistorica assertThat(blockBlobSidecarsTracker.getBlobSidecars().values()) .containsExactlyInAnyOrderElementsOf(blobSidecars); assertThat(blockBlobSidecarsTracker.getBlock()).isPresent(); - assertThat(blockBlobSidecarsTracker.isRpcFetchTriggered()).isFalse(); + assertThat(blockBlobSidecarsTracker.isRpcBlockFetchTriggered()).isFalse(); assertThatSafeFuture(blockBlobSidecarsTracker.getCompletionFuture()).isCompleted(); assertBlobSidecarsCount(blobSidecars.size()); @@ -493,7 +496,7 @@ public void onCompletedBlockAndBlobSidecars_shouldNotTriggerFetch() { assertThat(blockBlobSidecarsTracker.getBlobSidecars().values()) .containsExactlyInAnyOrderElementsOf(blobSidecars); assertThat(blockBlobSidecarsTracker.getBlock()).isPresent(); - assertThat(blockBlobSidecarsTracker.isRpcFetchTriggered()).isFalse(); + assertThat(blockBlobSidecarsTracker.isRpcBlockFetchTriggered()).isFalse(); assertThatSafeFuture(blockBlobSidecarsTracker.getCompletionFuture()).isNotCompleted(); assertBlobSidecarsCount(0); @@ -511,7 +514,7 @@ public void onCompletedBlockAndBlobSidecars_shouldNotTriggerFetch() { blockBlobSidecarsTrackersPool.getOrCreateBlockBlobSidecarsTracker(block); assertThat(blockBlobSidecarsTracker.getBlock()).isPresent(); - assertThat(blockBlobSidecarsTracker.isRpcFetchTriggered()).isFalse(); + assertThat(blockBlobSidecarsTracker.isRpcBlockFetchTriggered()).isFalse(); assertThatSafeFuture(blockBlobSidecarsTracker.getCompletionFuture()).isNotCompleted(); assertBlobSidecarsCount(0); @@ -671,7 +674,8 @@ void shouldFetchMissingBlobSidecarsFromLocalELFirst() { (slotAndRoot) -> { when(tracker.add(any())).thenReturn(true); when(tracker.getMissingBlobSidecars()) - .thenAnswer(__ -> missingBlobIdentifiers.stream()); + .thenAnswer(__ -> missingBlobIdentifiers.stream()) + .thenAnswer(__ -> Stream.empty()); when(tracker.getBlock()).thenReturn(Optional.of(block)); return tracker; }); @@ -694,7 +698,7 @@ void shouldFetchMissingBlobSidecarsFromLocalELFirst() { assertThat(requiredBlobSidecarDroppedEvents).isEmpty(); // local el fetch triggered - verify(tracker).setLocalElFetchTriggered(); + verify(tracker).setLocalElBlobsFetchTriggered(); // prepare partial response of 3 blobAndProofs final List> blobAndProofsFromEL = @@ -794,7 +798,7 @@ void shouldFetchMissingBlobSidecarsViaRPCWhenELLookupFails() { } @Test - void shouldFetchMissingBlockAndBlobSidecars() { + void shouldFetchMissingBlock() { final SignedBeaconBlock block = dataStructureUtil.randomSignedBeaconBlock(currentSlot); final BlobSidecar blobSidecar = dataStructureUtil @@ -803,14 +807,8 @@ void shouldFetchMissingBlockAndBlobSidecars() { .index(UInt64.valueOf(2)) .build(); - final Set missingBlobs = - Set.of( - new BlobIdentifier(block.getRoot(), UInt64.ONE), - new BlobIdentifier(block.getRoot(), UInt64.ZERO)); - final BlockBlobSidecarsTracker mockedTracker = mock(BlockBlobSidecarsTracker.class); when(mockedTracker.getBlock()).thenReturn(Optional.empty()); - when(mockedTracker.getMissingBlobSidecars()).thenReturn(missingBlobs.stream()); when(mockedTracker.getSlotAndBlockRoot()).thenReturn(block.getSlotAndBlockRoot()); mockedTrackersFactory = Optional.of((__) -> mockedTracker); @@ -821,91 +819,14 @@ void shouldFetchMissingBlockAndBlobSidecars() { asyncRunner.executeQueuedActions(); - verify(mockedTracker).setRpcFetchTriggered(); - verify(mockedTracker, never()).setLocalElFetchTriggered(); + verify(mockedTracker).setRpcBlockFetchTriggered(); + verify(mockedTracker, never()).setLocalElBlobsFetchTriggered(); assertThat(requiredBlockRootEvents).containsExactly(block.getRoot()); - assertThat(requiredBlobSidecarEvents).containsExactlyElementsOf(missingBlobs); assertStats("block", "rpc_fetch", 1); - assertStats("blob_sidecar", "rpc_fetch", missingBlobs.size()); assertThat(requiredBlockRootDroppedEvents).isEmpty(); - assertThat(requiredBlobSidecarDroppedEvents).isEmpty(); - } - - @Test - void shouldDropBlobSidecarsThatHasBeenFetchedButNotPresentInBlock() { - final SignedBeaconBlock block = dataStructureUtil.randomSignedBeaconBlock(currentSlot); - - final SlotAndBlockRoot slotAndBlockRoot = new SlotAndBlockRoot(currentSlot, block.getRoot()); - final BlobSidecar blobSidecar = - dataStructureUtil - .createRandomBlobSidecarBuilder() - .signedBeaconBlockHeader(block.asHeader()) - .index(UInt64.valueOf(2)) - .build(); - - final Set blobsNotPresentInBlock = - Set.of( - new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), UInt64.valueOf(2)), - new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), UInt64.valueOf(3))); - - mockedTrackersFactory = - Optional.of( - (slotAndRoot) -> { - BlockBlobSidecarsTracker tracker = mock(BlockBlobSidecarsTracker.class); - when(tracker.getBlock()).thenReturn(Optional.empty()); - when(tracker.getSlotAndBlockRoot()).thenReturn(slotAndBlockRoot); - when(tracker.setBlock(block)).thenReturn(true); - when(tracker.isRpcFetchTriggered()).thenReturn(true); - when(tracker.getUnusedBlobSidecarsForBlock()) - .thenReturn(blobsNotPresentInBlock.stream()); - return tracker; - }); - - blockBlobSidecarsTrackersPool.onNewBlobSidecar(blobSidecar, RemoteOrigin.GOSSIP); - - blockBlobSidecarsTrackersPool.onNewBlock(block, Optional.empty()); - - assertThat(requiredBlobSidecarDroppedEvents).containsExactlyElementsOf(blobsNotPresentInBlock); - } - - @Test - void shouldNotDropUnusedBlobSidecarsIfFetchingHasNotOccurred() { - final SignedBeaconBlock block = dataStructureUtil.randomSignedBeaconBlock(currentSlot); - - final SlotAndBlockRoot slotAndBlockRoot = new SlotAndBlockRoot(currentSlot, block.getRoot()); - final BlobSidecar blobSidecar = - dataStructureUtil - .createRandomBlobSidecarBuilder() - .signedBeaconBlockHeader(block.asHeader()) - .index(UInt64.valueOf(2)) - .build(); - - final Set blobsNotUserInBlock = - Set.of( - new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), UInt64.valueOf(2)), - new BlobIdentifier(slotAndBlockRoot.getBlockRoot(), UInt64.valueOf(3))); - - mockedTrackersFactory = - Optional.of( - (slotAndRoot) -> { - BlockBlobSidecarsTracker tracker = mock(BlockBlobSidecarsTracker.class); - when(tracker.getBlock()).thenReturn(Optional.empty()); - when(tracker.getSlotAndBlockRoot()).thenReturn(slotAndBlockRoot); - when(tracker.setBlock(block)).thenReturn(true); - when(tracker.isRpcFetchTriggered()).thenReturn(false); - when(tracker.getUnusedBlobSidecarsForBlock()) - .thenReturn(blobsNotUserInBlock.stream()); - return tracker; - }); - - blockBlobSidecarsTrackersPool.onNewBlobSidecar(blobSidecar, RemoteOrigin.GOSSIP); - - blockBlobSidecarsTrackersPool.onNewBlock(block, Optional.empty()); - - assertThat(requiredBlobSidecarDroppedEvents).isEmpty(); } @Test @@ -945,10 +866,10 @@ void shouldDropPossiblyFetchedBlobSidecars() { Optional.of( (slotAndRoot) -> { BlockBlobSidecarsTracker tracker = mock(BlockBlobSidecarsTracker.class); - when(tracker.getMissingBlobSidecars()).thenReturn(missingBlobs.stream()); + when(tracker.getMissingBlobSidecars()).thenAnswer(__ -> missingBlobs.stream()); when(tracker.getBlock()).thenReturn(Optional.of(block)); when(tracker.getSlotAndBlockRoot()).thenReturn(block.getSlotAndBlockRoot()); - when(tracker.isRpcFetchTriggered()).thenReturn(true); + when(tracker.isRpcBlobsFetchTriggered()).thenReturn(true); return tracker; }); @@ -967,7 +888,7 @@ void shouldDropPossiblyFetchedBlobSidecars() { } @Test - void shouldTryToFetchFromLocalELWhenBlockArrivesAfterRPCFetch() { + void shouldTryToFetchBlobSidecarsWhenBlockArrivesAfterRPCFetch() { final SignedBeaconBlock block = dataStructureUtil.randomSignedBeaconBlock(currentSlot); final Set missingBlobs = @@ -991,8 +912,8 @@ void shouldTryToFetchFromLocalELWhenBlockArrivesAfterRPCFetch() { when(tracker.getBlock()).thenReturn(Optional.empty()); when(tracker.setBlock(any())).thenReturn(true); when(tracker.getSlotAndBlockRoot()).thenReturn(block.getSlotAndBlockRoot()); - when(tracker.isRpcFetchTriggered()).thenReturn(true); - when(tracker.isLocalElFetchTriggered()).thenReturn(false); + when(tracker.isRpcBlockFetchTriggered()).thenReturn(true); + when(tracker.isLocalElBlobsFetchTriggered()).thenReturn(true); return tracker; }); @@ -1001,7 +922,7 @@ void shouldTryToFetchFromLocalELWhenBlockArrivesAfterRPCFetch() { assertThat(asyncRunner.hasDelayedActions()).isTrue(); asyncRunner.executeQueuedActions(); - verify(tracker, never()).setLocalElFetchTriggered(); + verify(tracker, never()).setLocalElBlobsFetchTriggered(); when(tracker.getBlock()).thenReturn(Optional.of(block)); @@ -1011,7 +932,10 @@ void shouldTryToFetchFromLocalELWhenBlockArrivesAfterRPCFetch() { blockBlobSidecarsTrackersPool.onNewBlock(block, Optional.empty()); - verify(tracker).setLocalElFetchTriggered(); + assertThat(asyncRunner.hasDelayedActions()).isTrue(); + asyncRunner.executeQueuedActions(); + + verify(tracker).setLocalElBlobsFetchTriggered(); verify(executionLayer).engineGetBlobs(any(), any()); } @@ -1032,7 +956,7 @@ void shouldDropPossiblyFetchedBlock() { when(tracker.getBlock()).thenReturn(Optional.empty()); when(tracker.getSlotAndBlockRoot()) .thenReturn(signedBeaconBlock.getSlotAndBlockRoot()); - when(tracker.isRpcFetchTriggered()).thenReturn(true); + when(tracker.isRpcBlockFetchTriggered()).thenReturn(true); return tracker; }); @@ -1067,7 +991,7 @@ void shouldNotDropPossiblyFetchedBlockIfFetchHasNotOccurred() { when(tracker.getBlock()).thenReturn(Optional.empty()); when(tracker.getSlotAndBlockRoot()) .thenReturn(signedBeaconBlock.getSlotAndBlockRoot()); - when(tracker.isRpcFetchTriggered()).thenReturn(false); + when(tracker.isRpcBlockFetchTriggered()).thenReturn(false); return tracker; }); @@ -1093,14 +1017,15 @@ void shouldRespectTargetWhenBlockIsEarly() { // blocks arrives at slot start timeProvider.advanceTimeBySeconds(startSlotInSeconds.longValue()); - final Duration fetchDelay = blockBlobSidecarsTrackersPool.calculateFetchDelay(slotAndBlockRoot); + final Duration fetchDelay = + blockBlobSidecarsTrackersPool.calculateRpcFetchDelay(slotAndBlockRoot); // we can wait the full target assertThat(fetchDelay).isEqualTo(Duration.ofMillis(TARGET_WAIT_MILLIS.longValue())); } @Test - void calculateFetchDelay_shouldRespectMinimumWhenBlockIsLate() { + void calculateBlockFetchDelay_shouldRespectMinimumWhenRpcIsLate() { final SlotAndBlockRoot slotAndBlockRoot = new SlotAndBlockRoot(currentSlot, dataStructureUtil.randomBytes32()); @@ -1112,14 +1037,15 @@ void calculateFetchDelay_shouldRespectMinimumWhenBlockIsLate() { // blocks arrives 200ms before attestation due timeProvider.advanceTimeByMillis(startSlotInMillis.plus(3_800).longValue()); - final Duration fetchDelay = blockBlobSidecarsTrackersPool.calculateFetchDelay(slotAndBlockRoot); + final Duration fetchDelay = + blockBlobSidecarsTrackersPool.calculateRpcFetchDelay(slotAndBlockRoot); // we can wait the full target assertThat(fetchDelay).isEqualTo(Duration.ofMillis(MIN_WAIT_MILLIS.longValue())); } @Test - void calculateFetchDelay_shouldRespectTargetWhenBlockIsVeryLate() { + void calculateBlockFetchDelay_shouldRespectTargetWhenRpcIsVeryLate() { final SlotAndBlockRoot slotAndBlockRoot = new SlotAndBlockRoot(currentSlot, dataStructureUtil.randomBytes32()); @@ -1130,14 +1056,15 @@ void calculateFetchDelay_shouldRespectTargetWhenBlockIsVeryLate() { // blocks arrives 1s after attestation due timeProvider.advanceTimeBySeconds(startSlotInSeconds.plus(5).longValue()); - final Duration fetchDelay = blockBlobSidecarsTrackersPool.calculateFetchDelay(slotAndBlockRoot); + final Duration fetchDelay = + blockBlobSidecarsTrackersPool.calculateRpcFetchDelay(slotAndBlockRoot); // we can wait the full target assertThat(fetchDelay).isEqualTo(Duration.ofMillis(TARGET_WAIT_MILLIS.longValue())); } @Test - void calculateFetchDelay_shouldRespectAttestationDueLimit() { + void calculateRpcFetchDelay_shouldRespectAttestationDueLimit() { final SlotAndBlockRoot slotAndBlockRoot = new SlotAndBlockRoot(currentSlot, dataStructureUtil.randomBytes32()); @@ -1157,7 +1084,8 @@ void calculateFetchDelay_shouldRespectAttestationDueLimit() { timeProvider.advanceTimeByMillis(blockArrivalTimeMillis.longValue()); - final Duration fetchDelay = blockBlobSidecarsTrackersPool.calculateFetchDelay(slotAndBlockRoot); + final Duration fetchDelay = + blockBlobSidecarsTrackersPool.calculateRpcFetchDelay(slotAndBlockRoot); // we can only wait 200ms less than target assertThat(fetchDelay) @@ -1166,11 +1094,12 @@ void calculateFetchDelay_shouldRespectAttestationDueLimit() { } @Test - void calculateFetchDelay_shouldReturnZeroIfSlotIsOld() { + void calculateRpcFetchDelay_shouldReturnZeroIfSlotIsOld() { final SlotAndBlockRoot slotAndBlockRoot = new SlotAndBlockRoot(currentSlot.minus(1), dataStructureUtil.randomBytes32()); - final Duration fetchDelay = blockBlobSidecarsTrackersPool.calculateFetchDelay(slotAndBlockRoot); + final Duration fetchDelay = + blockBlobSidecarsTrackersPool.calculateRpcFetchDelay(slotAndBlockRoot); assertThat(fetchDelay).isEqualTo(Duration.ZERO); } @@ -1400,8 +1329,6 @@ private BlockBlobSidecarsTracker trackerFactory(final SlotAndBlockRoot slotAndBl if (mockedTrackersFactory.isPresent()) { return mockedTrackersFactory.get().apply(slotAndBlockRoot); } - return new BlockBlobSidecarsTracker( - slotAndBlockRoot, - UInt64.valueOf(spec.getMaxBlobsPerBlockForHighestMilestone().orElseThrow())); + return new BlockBlobSidecarsTracker(slotAndBlockRoot); } } diff --git a/fork-choice-tests/build.gradle b/fork-choice-tests/build.gradle index 0225812d304..403ffbe49a5 100644 --- a/fork-choice-tests/build.gradle +++ b/fork-choice-tests/build.gradle @@ -19,5 +19,4 @@ dependencies { integrationTestImplementation 'com.fasterxml.jackson.core:jackson-databind' integrationTestImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' integrationTestImplementation 'io.tmio:tuweni-bytes' - integrationTestImplementation 'io.tmio:tuweni-junit' } diff --git a/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java b/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java index 3e69f57fc11..4355d4c3002 100644 --- a/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java +++ b/fuzz/src/test/java/tech/pegasys/teku/fuzz/FuzzUtilTest.java @@ -22,9 +22,7 @@ import java.util.List; import java.util.Optional; import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.junit.BouncyCastleExtension; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.xerial.snappy.Snappy; import tech.pegasys.teku.fuzz.input.AttestationFuzzInput; import tech.pegasys.teku.fuzz.input.AttesterSlashingFuzzInput; @@ -69,7 +67,6 @@ import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.electra.BeaconStateSchemaElectra; import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra; -@ExtendWith(BouncyCastleExtension.class) class FuzzUtilTest { private final Spec spec = TestSpecFactory.createMinimalElectra(); diff --git a/gradle/versions.gradle b/gradle/versions.gradle index c4cfaa95c82..6fa62a2d5f6 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -79,7 +79,6 @@ dependencyManagement { dependencySet(group: 'io.tmio', version: '2.4.2') { entry 'tuweni-bytes' entry 'tuweni-crypto' - entry 'tuweni-junit' entry 'tuweni-ssz' entry 'tuweni-units' } diff --git a/infrastructure/jackson/build.gradle b/infrastructure/jackson/build.gradle deleted file mode 100644 index 3f1451d6923..00000000000 --- a/infrastructure/jackson/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ -dependencies { - api 'com.fasterxml.jackson.core:jackson-databind' - api 'io.swagger.core.v3:swagger-annotations' - - implementation project(':infrastructure:bytes') - - implementation 'io.tmio:tuweni-units' -} \ No newline at end of file diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/ByteArrayDeserializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/ByteArrayDeserializer.java deleted file mode 100644 index 5b64a8a0003..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/ByteArrayDeserializer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import java.io.IOException; - -public class ByteArrayDeserializer extends JsonDeserializer { - - @Override - public byte[] deserialize(final JsonParser p, final DeserializationContext ctxt) - throws IOException { - ObjectCodec oc = p.getCodec(); - JsonNode node = oc.readTree(p); - checkArgument(node.isArray(), "Expected array but did not appear to be one!"); - byte[] data = new byte[node.size()]; - for (int i = 0; i < node.size(); i++) { - final int current = node.get(i).asInt(-1); - checkArgument( - current >= 0 && current <= 255, - "Expected %s to be a byte value between 0 and 255 inclusive", - node.get(i)); - data[i] = (byte) current; - } - return data; - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/ByteArraySerializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/ByteArraySerializer.java deleted file mode 100644 index 1c97c40d7fc..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/ByteArraySerializer.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import java.io.IOException; - -public class ByteArraySerializer extends JsonSerializer { - @Override - public void serialize( - final byte[] value, final JsonGenerator gen, final SerializerProvider serializers) - throws IOException { - gen.writeStartArray(); - for (int i = 0; i < value.length; i++) { - final int s = value[i] & 0xff; - gen.writeString(String.format("%d", s)); - } - gen.writeEndArray(); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes20Deserializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes20Deserializer.java deleted file mode 100644 index e9d53b33024..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes20Deserializer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import java.io.IOException; -import tech.pegasys.teku.infrastructure.bytes.Bytes20; - -public class Bytes20Deserializer extends JsonDeserializer { - - @Override - public Bytes20 deserialize(final JsonParser p, final DeserializationContext ctxt) - throws IOException { - return Bytes20.fromHexString(p.getValueAsString()); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes20Serializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes20Serializer.java deleted file mode 100644 index 1ff0dc2e281..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes20Serializer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import java.io.IOException; -import java.util.Locale; -import tech.pegasys.teku.infrastructure.bytes.Bytes20; - -public class Bytes20Serializer extends JsonSerializer { - @Override - public void serialize( - final Bytes20 value, final JsonGenerator gen, final SerializerProvider serializers) - throws IOException { - gen.writeString(value.toHexString().toLowerCase(Locale.ROOT)); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes4Deserializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes4Deserializer.java deleted file mode 100644 index 4aca1c976cb..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes4Deserializer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import java.io.IOException; -import tech.pegasys.teku.infrastructure.bytes.Bytes4; - -public class Bytes4Deserializer extends JsonDeserializer { - - @Override - public Bytes4 deserialize(final JsonParser p, final DeserializationContext ctxt) - throws IOException { - return Bytes4.fromHexString(p.getValueAsString()); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes4Serializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes4Serializer.java deleted file mode 100644 index 996401c3d24..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes4Serializer.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import java.io.IOException; -import java.util.Locale; -import tech.pegasys.teku.infrastructure.bytes.Bytes4; - -public class Bytes4Serializer extends JsonSerializer { - @Override - public void serialize( - final Bytes4 value, final JsonGenerator gen, final SerializerProvider serializers) - throws IOException { - gen.writeString(value.toHexString().toLowerCase(Locale.ROOT)); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/BytesDeserializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/BytesDeserializer.java deleted file mode 100644 index 449f8654999..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/BytesDeserializer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import java.io.IOException; -import org.apache.tuweni.bytes.Bytes; - -public class BytesDeserializer extends JsonDeserializer { - - @Override - public Bytes deserialize(final JsonParser p, final DeserializationContext ctxt) - throws IOException { - return Bytes.fromHexString(p.getValueAsString()); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/DoubleDeserializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/DoubleDeserializer.java deleted file mode 100644 index ba8bce97e68..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/DoubleDeserializer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import java.io.IOException; - -public class DoubleDeserializer extends JsonDeserializer { - - @Override - public Double deserialize(final JsonParser p, final DeserializationContext ctxt) - throws IOException { - return Double.valueOf(p.getValueAsString()); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/DoubleSerializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/DoubleSerializer.java deleted file mode 100644 index 5da417213a0..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/DoubleSerializer.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.bytes; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import java.io.IOException; -import java.math.RoundingMode; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.Locale; - -public class DoubleSerializer extends JsonSerializer { - private static final DecimalFormatSymbols US_SYMBOLS = new DecimalFormatSymbols(Locale.US); - - @Override - public void serialize( - final Double value, final JsonGenerator gen, final SerializerProvider serializers) - throws IOException { - gen.writeString(formatValue(value)); - } - - private String formatValue(final Double value) { - DecimalFormat df = new DecimalFormat("#.####", US_SYMBOLS); - df.setRoundingMode(RoundingMode.HALF_UP); - return df.format(value); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt256Deserializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt256Deserializer.java deleted file mode 100644 index 1370bc9b6d4..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt256Deserializer.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.uints; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import java.io.IOException; -import java.math.BigInteger; -import org.apache.tuweni.units.bigints.UInt256; - -public class UInt256Deserializer extends JsonDeserializer { - - @Override - public UInt256 deserialize(final JsonParser p, final DeserializationContext ctxt) - throws IOException { - String value = p.getValueAsString(); - if (value.startsWith("0x")) { - return UInt256.fromHexString(p.getValueAsString()); - } - - return UInt256.valueOf(new BigInteger(value)); - } -} diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt256Serializer.java b/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt256Serializer.java deleted file mode 100644 index 899c2d4bc1c..00000000000 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt256Serializer.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.infrastructure.jackson.deserializers.uints; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import java.io.IOException; -import org.apache.tuweni.units.bigints.UInt256; - -public class UInt256Serializer extends JsonSerializer { - @Override - public void serialize( - final UInt256 value, final JsonGenerator gen, final SerializerProvider serializers) - throws IOException { - gen.writeString(value.toDecimalString()); - } -} diff --git a/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/EventLogger.java b/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/EventLogger.java index 651eff10f2a..4893ec3e908 100644 --- a/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/EventLogger.java +++ b/infrastructure/logging/src/main/java/tech/pegasys/teku/infrastructure/logging/EventLogger.java @@ -162,13 +162,11 @@ public void executionClientRecovered() { info("Execution Client is responding to requests again after a previous failure", Color.GREEN); } - // TODO remove the isOptional param when all ELs implement the engine_getBlob - public void missingEngineApiCapabilities( - final List missingCapabilities, final boolean isOptional) { + public void missingEngineApiCapabilities(final List missingCapabilities) { warn( String.format( - "Execution Client does not support %s Engine API methods: %s. Make sure it is upgraded to a compatible version.", - isOptional ? "optional" : "required", missingCapabilities), + "Execution Client does not support required Engine API methods: %s. Make sure it is upgraded to a compatible version.", + missingCapabilities), Color.YELLOW); } diff --git a/infrastructure/logging/src/main/resources/log4j2.xml b/infrastructure/logging/src/main/resources/log4j2.xml index 0951c51df9e..ef33cc2196e 100644 --- a/infrastructure/logging/src/main/resources/log4j2.xml +++ b/infrastructure/logging/src/main/resources/log4j2.xml @@ -1,5 +1,5 @@ - + diff --git a/infrastructure/logging/src/testFixtures/resources/log4j2-test.xml b/infrastructure/logging/src/testFixtures/resources/log4j2-test.xml index af79b71c72c..cd811ce3ae3 100644 --- a/infrastructure/logging/src/testFixtures/resources/log4j2-test.xml +++ b/infrastructure/logging/src/testFixtures/resources/log4j2-test.xml @@ -1,5 +1,5 @@ - + doStart() { - return SafeFuture.COMPLETE; - } - - @Override - protected SafeFuture doStop() { - return SafeFuture.COMPLETE; - } -} diff --git a/infrastructure/time/src/test/java/tech/pegasys/teku/infrastructure/time/ThrottlerTest.java b/infrastructure/time/src/test/java/tech/pegasys/teku/infrastructure/time/ThrottlerTest.java index cec34889f42..80d9c927dc3 100644 --- a/infrastructure/time/src/test/java/tech/pegasys/teku/infrastructure/time/ThrottlerTest.java +++ b/infrastructure/time/src/test/java/tech/pegasys/teku/infrastructure/time/ThrottlerTest.java @@ -22,8 +22,8 @@ public class ThrottlerTest { private final AtomicInteger resource = new AtomicInteger(0); - private final UInt64 throttingPeriod = UInt64.valueOf(10); - private final Throttler throttler = new Throttler<>(resource, throttingPeriod); + private final UInt64 throttlingPeriod = UInt64.valueOf(10); + private final Throttler throttler = new Throttler<>(resource, throttlingPeriod); @Test public void init_mustThrowWhenThrottlingPeriodIsNull() { @@ -59,19 +59,19 @@ public void invoke_shouldThrottle() { assertThat(resource.get()).isEqualTo(1); // Repeatedly invoke at initial time - for (int i = 0; i < throttingPeriod.times(2).intValue(); i++) { + for (int i = 0; i < throttlingPeriod.times(2).intValue(); i++) { throttler.invoke(initialTime, AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(1); } // Increment time and invoke up to limit - for (int i = 0; i < throttingPeriod.intValue(); i++) { + for (int i = 0; i < throttlingPeriod.intValue(); i++) { throttler.invoke(initialTime.plus(i), AtomicInteger::incrementAndGet); } assertThat(resource.get()).isEqualTo(1); // Invoke at boundary - throttler.invoke(initialTime.plus(throttingPeriod), AtomicInteger::incrementAndGet); + throttler.invoke(initialTime.plus(throttlingPeriod), AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(2); } @@ -81,11 +81,11 @@ public void invoke_shouldNotThrottleAcrossSparseInvocations() { throttler.invoke(initialTime, AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(1); - throttler.invoke(initialTime.plus(throttingPeriod.times(2)), AtomicInteger::incrementAndGet); + throttler.invoke(initialTime.plus(throttlingPeriod.times(2)), AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(2); throttler.invoke( - initialTime.plus(throttingPeriod.times(3)).plus(1), AtomicInteger::incrementAndGet); + initialTime.plus(throttlingPeriod.times(3)).plus(1), AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(3); } @@ -108,19 +108,21 @@ public void invoke_shouldThrottleBasedOnLastSuccessfulInvocation() { assertThat(resource.get()).isEqualTo(1); // Don't throttle under the next threshold - throttler.invoke(lastInvocation.plus(throttingPeriod).minus(1), AtomicInteger::incrementAndGet); + throttler.invoke( + lastInvocation.plus(throttlingPeriod).minus(1), AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(1); // Invoke once we pass the current threshold - lastInvocation = lastInvocation.plus(throttingPeriod.times(2)).plus(1); + lastInvocation = lastInvocation.plus(throttlingPeriod.times(2)).plus(1); throttler.invoke(lastInvocation, AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(2); // Don't throttle under the next threshold - throttler.invoke(lastInvocation.plus(throttingPeriod).minus(1), AtomicInteger::incrementAndGet); + throttler.invoke( + lastInvocation.plus(throttlingPeriod).minus(1), AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(2); // Invoke at next threshold - throttler.invoke(lastInvocation.plus(throttingPeriod), AtomicInteger::incrementAndGet); + throttler.invoke(lastInvocation.plus(throttlingPeriod), AtomicInteger::incrementAndGet); assertThat(resource.get()).isEqualTo(3); } } diff --git a/infrastructure/yaml/build.gradle b/infrastructure/yaml/build.gradle index e184a680e03..91430265c1e 100644 --- a/infrastructure/yaml/build.gradle +++ b/infrastructure/yaml/build.gradle @@ -1,5 +1,4 @@ dependencies { - implementation project(':infrastructure:jackson') implementation 'io.tmio:tuweni-bytes' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml' diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes32Deserializer.java b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/Bytes32Deserializer.java similarity index 90% rename from infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes32Deserializer.java rename to infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/Bytes32Deserializer.java index 5fcd75d8ef1..e3ecac932e9 100644 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes32Deserializer.java +++ b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/Bytes32Deserializer.java @@ -1,5 +1,5 @@ /* - * Copyright Consensys Software Inc., 2022 + * Copyright Consensys Software Inc., 2024 * * 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 @@ -11,7 +11,7 @@ * specific language governing permissions and limitations under the License. */ -package tech.pegasys.teku.infrastructure.jackson.deserializers.bytes; +package tech.pegasys.teku.data.yaml; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/BytesSerializer.java b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/BytesSerializer.java similarity index 90% rename from infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/BytesSerializer.java rename to infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/BytesSerializer.java index 2fafab35ae0..83439aa4f53 100644 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/BytesSerializer.java +++ b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/BytesSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright Consensys Software Inc., 2022 + * Copyright Consensys Software Inc., 2024 * * 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 @@ -11,7 +11,7 @@ * specific language governing permissions and limitations under the License. */ -package tech.pegasys.teku.infrastructure.jackson.deserializers.bytes; +package tech.pegasys.teku.data.yaml; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; @@ -21,6 +21,7 @@ import org.apache.tuweni.bytes.Bytes; public class BytesSerializer extends JsonSerializer { + @Override public void serialize( final Bytes value, final JsonGenerator gen, final SerializerProvider provider) diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt64Deserializer.java b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/UInt64Deserializer.java similarity index 90% rename from infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt64Deserializer.java rename to infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/UInt64Deserializer.java index 44cc016d84a..f20c2720762 100644 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt64Deserializer.java +++ b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/UInt64Deserializer.java @@ -1,5 +1,5 @@ /* - * Copyright Consensys Software Inc., 2022 + * Copyright Consensys Software Inc., 2024 * * 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 @@ -11,7 +11,7 @@ * specific language governing permissions and limitations under the License. */ -package tech.pegasys.teku.infrastructure.jackson.deserializers.uints; +package tech.pegasys.teku.data.yaml; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt64Serializer.java b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/UInt64Serializer.java similarity index 87% rename from infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt64Serializer.java rename to infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/UInt64Serializer.java index 49ff1af4a30..f0513d21304 100644 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/uints/UInt64Serializer.java +++ b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/UInt64Serializer.java @@ -1,5 +1,5 @@ /* - * Copyright Consensys Software Inc., 2022 + * Copyright Consensys Software Inc., 2024 * * 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 @@ -11,7 +11,7 @@ * specific language governing permissions and limitations under the License. */ -package tech.pegasys.teku.infrastructure.jackson.deserializers.uints; +package tech.pegasys.teku.data.yaml; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; @@ -20,10 +20,11 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; public class UInt64Serializer extends JsonSerializer { + @Override public void serialize( final UInt64 value, final JsonGenerator gen, final SerializerProvider serializers) throws IOException { - gen.writeString(value.toString()); + gen.writeNumber(value.bigIntegerValue()); } } diff --git a/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/YamlProvider.java b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/YamlProvider.java index b3f2fe47ff7..fb232601b18 100644 --- a/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/YamlProvider.java +++ b/infrastructure/yaml/src/main/java/tech/pegasys/teku/data/yaml/YamlProvider.java @@ -14,43 +14,35 @@ package tech.pegasys.teku.data.yaml; import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.Version; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.Module; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.io.UncheckedIOException; import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; -import tech.pegasys.teku.infrastructure.jackson.deserializers.bytes.Bytes32Deserializer; -import tech.pegasys.teku.infrastructure.jackson.deserializers.bytes.BytesSerializer; import tech.pegasys.teku.infrastructure.unsigned.UInt64; public class YamlProvider { private final ObjectMapper objectMapper; public YamlProvider(final Module... modules) { - this.objectMapper = new ObjectMapper(new YAMLFactory()); + objectMapper = new ObjectMapper(new YAMLFactory()); addTekuMappers(); Stream.of(modules).forEach(objectMapper::registerModule); } private void addTekuMappers() { - SimpleModule module = new SimpleModule("TekuYaml", new Version(1, 0, 0, null, null, null)); + final SimpleModule module = + new SimpleModule("TekuYaml", new Version(1, 0, 0, null, null, null)); module.addDeserializer(UInt64.class, new UInt64Deserializer()); module.addSerializer(UInt64.class, new UInt64Serializer()); module.addDeserializer(Bytes32.class, new Bytes32Deserializer()); @@ -58,10 +50,6 @@ private void addTekuMappers() { objectMapper.registerModule(module).writer(new DefaultPrettyPrinter()); } - public T read(final InputStream data, final Class clazz) throws IOException { - return objectMapper.readValue(data, clazz); - } - public T read(final Bytes data, final Class clazz) throws IOException { return objectMapper.readValue(data.toArrayUnsafe(), clazz); } @@ -95,22 +83,4 @@ public String writeString(final T object) { public ObjectMapper getObjectMapper() { return objectMapper; } - - public static class UInt64Deserializer extends JsonDeserializer { - - @Override - public UInt64 deserialize(final JsonParser p, final DeserializationContext ctxt) - throws IOException { - return UInt64.valueOf(p.getValueAsString()); - } - } - - public static class UInt64Serializer extends JsonSerializer { - @Override - public void serialize( - final UInt64 value, final JsonGenerator gen, final SerializerProvider serializers) - throws IOException { - gen.writeNumber(value.bigIntegerValue()); - } - } } diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2IncomingRequestHandler.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2IncomingRequestHandler.java index 2a1bce8e6f3..9d3c3fdcb83 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2IncomingRequestHandler.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2IncomingRequestHandler.java @@ -33,7 +33,9 @@ public class Eth2IncomingRequestHandler< TRequest extends RpcRequest & SszData, TResponse extends SszData> implements RpcRequestHandler { + private static final Logger LOG = LogManager.getLogger(); + private static final Duration RECEIVE_INCOMING_REQUEST_TIMEOUT = Duration.ofSeconds(10); private final PeerLookup peerLookup; @@ -119,9 +121,8 @@ private void handleRequest( private void ensureRequestReceivedWithinTimeLimit(final RpcStream stream) { asyncRunner - .getDelayedFuture(RECEIVE_INCOMING_REQUEST_TIMEOUT) - .thenAccept( - (__) -> { + .runAfterDelay( + () -> { if (!requestHandled.get()) { LOG.debug( "Failed to receive incoming request data within {} sec for protocol {}. Close stream.", @@ -129,7 +130,8 @@ private void ensureRequestReceivedWithinTimeLimit(final RpcStream stream) { protocolId); stream.closeAbruptly().ifExceptionGetsHereRaiseABug(); } - }) + }, + RECEIVE_INCOMING_REQUEST_TIMEOUT) .ifExceptionGetsHereRaiseABug(); } diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2OutgoingRequestHandler.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2OutgoingRequestHandler.java index 320a5a3f943..be3e39cd95b 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2OutgoingRequestHandler.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/Eth2OutgoingRequestHandler.java @@ -55,7 +55,7 @@ enum State { private static final Logger LOG = LogManager.getLogger(); @VisibleForTesting static final Duration READ_COMPLETE_TIMEOUT = Duration.ofSeconds(10); - @VisibleForTesting static final Duration RESPONSE_CHUNK_ARRIVAL_TIMEOUT = Duration.ofSeconds(30); + @VisibleForTesting static final Duration RESPONSE_CHUNK_ARRIVAL_TIMEOUT = Duration.ofSeconds(10); private final AsyncRunner asyncRunner; private final int maximumResponseChunks; @@ -116,7 +116,7 @@ public void processData(final NodeId nodeId, final RpcStream rpcStream, final By throw new RpcException.ExtraDataAppendedException(" extra data: " + bufToString(data)); } - List maybeResponses = responseDecoder.decodeNextResponses(data); + final List maybeResponses = responseDecoder.decodeNextResponses(data); final int chunksReceived = currentChunkCount.addAndGet(maybeResponses.size()); if (chunksReceived > maximumResponseChunks) { @@ -161,8 +161,8 @@ private String bufToString(final ByteBuf buf) { final int contentSize = Integer.min(buf.readableBytes(), 1024); String bufContent = ""; if (contentSize > 0) { - ByteBuf bufSlice = buf.slice(0, contentSize); - byte[] bytes = new byte[bufSlice.readableBytes()]; + final ByteBuf bufSlice = buf.slice(0, contentSize); + final byte[] bytes = new byte[bufSlice.readableBytes()]; bufSlice.getBytes(0, bytes); bufContent += Bytes.wrap(bytes); if (contentSize < buf.readableBytes()) { @@ -255,9 +255,8 @@ private void ensureNextResponseChunkArrivesInTime( final int previousResponseCount, final AtomicInteger currentResponseCount) { timeoutRunner - .getDelayedFuture(RESPONSE_CHUNK_ARRIVAL_TIMEOUT) - .thenAccept( - (__) -> { + .runAfterDelay( + () -> { if (previousResponseCount == currentResponseCount.get()) { abortRequest( stream, @@ -265,22 +264,23 @@ private void ensureNextResponseChunkArrivesInTime( "Timed out waiting for response chunk " + previousResponseCount, RESPONSE_CHUNK_ARRIVAL_TIMEOUT)); } - }) + }, + RESPONSE_CHUNK_ARRIVAL_TIMEOUT) .ifExceptionGetsHereRaiseABug(); } private void ensureReadCompleteArrivesInTime(final RpcStream stream) { timeoutRunner - .getDelayedFuture(READ_COMPLETE_TIMEOUT) - .thenAccept( - (__) -> { + .runAfterDelay( + () -> { if (!(state.get() == READ_COMPLETE || state.get() == CLOSED)) { abortRequest( stream, new RpcTimeoutException( "Timed out waiting for read channel close", READ_COMPLETE_TIMEOUT)); } - }) + }, + READ_COMPLETE_TIMEOUT) .ifExceptionGetsHereRaiseABug(); } diff --git a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/methods/Eth2RpcMethod.java b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/methods/Eth2RpcMethod.java index d9c6b6c785c..880d6a015d5 100644 --- a/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/methods/Eth2RpcMethod.java +++ b/networking/eth2/src/main/java/tech/pegasys/teku/networking/eth2/rpc/core/methods/Eth2RpcMethod.java @@ -44,7 +44,5 @@ public interface Eth2RpcMethod createOutgoingRequestHandler( - String protocolId, - final TRequest request, - Eth2RpcResponseHandler responseHandler); + String protocolId, TRequest request, Eth2RpcResponseHandler responseHandler); } diff --git a/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PNetworkBuilder.java b/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PNetworkBuilder.java index 733f92be5d2..5b809f77d14 100644 --- a/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PNetworkBuilder.java +++ b/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PNetworkBuilder.java @@ -15,7 +15,6 @@ import static tech.pegasys.teku.networking.p2p.libp2p.LibP2PNetwork.REMOTE_OPEN_STREAMS_RATE_LIMIT; import static tech.pegasys.teku.networking.p2p.libp2p.LibP2PNetwork.REMOTE_PARALLEL_OPEN_STREAMS_COUNT_LIMIT; -import static tech.pegasys.teku.spec.constants.NetworkConstants.MAX_CONCURRENT_REQUESTS; import com.google.common.base.Preconditions; import identify.pb.IdentifyOuterClass; @@ -153,9 +152,7 @@ public P2PNetwork build() { } protected List> createRpcHandlers() { - return rpcMethods.stream() - .map(m -> new RpcHandler<>(asyncRunner, m, MAX_CONCURRENT_REQUESTS)) - .toList(); + return rpcMethods.stream().map(m -> new RpcHandler<>(asyncRunner, m)).toList(); } protected LibP2PGossipNetwork createGossipNetwork() { diff --git a/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PPeer.java b/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PPeer.java index 35248eaee39..b0dc1873a3f 100644 --- a/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PPeer.java +++ b/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PPeer.java @@ -18,6 +18,7 @@ import io.libp2p.core.PeerId; import io.libp2p.core.crypto.PubKey; import io.libp2p.protocol.Identify; +import io.libp2p.protocol.IdentifyController; import java.util.List; import java.util.Map; import java.util.Optional; @@ -28,6 +29,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.infrastructure.async.ThrottlingTaskQueue; import tech.pegasys.teku.networking.p2p.libp2p.rpc.RpcHandler; import tech.pegasys.teku.networking.p2p.network.PeerAddress; import tech.pegasys.teku.networking.p2p.peer.DisconnectReason; @@ -41,11 +43,12 @@ import tech.pegasys.teku.networking.p2p.rpc.RpcRequestHandler; import tech.pegasys.teku.networking.p2p.rpc.RpcResponseHandler; import tech.pegasys.teku.networking.p2p.rpc.RpcStreamController; +import tech.pegasys.teku.spec.constants.NetworkConstants; public class LibP2PPeer implements Peer { private static final Logger LOG = LogManager.getLogger(); - private final Map, RpcHandler> rpcHandlers; + private final Map, ThrottlingRpcHandler> rpcHandlers; private final ReputationManager reputationManager; private final Function peerScoreFunction; private final Connection connection; @@ -71,7 +74,8 @@ public LibP2PPeer( final Function peerScoreFunction) { this.connection = connection; this.rpcHandlers = - rpcHandlers.stream().collect(Collectors.toMap(RpcHandler::getRpcMethod, h -> h)); + rpcHandlers.stream() + .collect(Collectors.toMap(RpcHandler::getRpcMethod, ThrottlingRpcHandler::new)); this.reputationManager = reputationManager; this.peerScoreFunction = peerScoreFunction; this.peerId = connection.secureSession().getRemoteId(); @@ -109,10 +113,6 @@ private PeerClientType getPeerTypeFromAgentString(final String agentVersion) { return EnumUtils.getEnumIgnoreCase(PeerClientType.class, agent, PeerClientType.UNKNOWN); } - public Optional getMaybeAgentString() { - return maybeAgentString; - } - public PubKey getPubKey() { return pubKey; } @@ -161,7 +161,7 @@ private SafeFuture getIdentify() { .muxerSession() .createStream(new Identify()) .getController() - .thenCompose(controller -> controller.id())) + .thenCompose(IdentifyController::id)) .exceptionallyCompose( error -> { LOG.debug("Failed to get peer identity", error); @@ -208,8 +208,8 @@ SafeFuture> sendRequest( final TRequest request, final RespHandler responseHandler) { @SuppressWarnings("unchecked") - RpcHandler rpcHandler = - (RpcHandler) rpcHandlers.get(rpcMethod); + final ThrottlingRpcHandler rpcHandler = + (ThrottlingRpcHandler) rpcHandlers.get(rpcMethod); if (rpcHandler == null) { throw new IllegalArgumentException( "Unknown rpc method invoked: " + String.join(",", rpcMethod.getIds())); @@ -240,4 +240,26 @@ public void adjustReputation(final ReputationAdjustment adjustment) { disconnectCleanly(DisconnectReason.REMOTE_FAULT).ifExceptionGetsHereRaiseABug(); } } + + private static class ThrottlingRpcHandler< + TOutgoingHandler extends RpcRequestHandler, + TRequest, + TRespHandler extends RpcResponseHandler> { + + private final RpcHandler delegate; + + private final ThrottlingTaskQueue requestsQueue = + ThrottlingTaskQueue.create(NetworkConstants.MAX_CONCURRENT_REQUESTS); + + private ThrottlingRpcHandler( + final RpcHandler delegate) { + this.delegate = delegate; + } + + private SafeFuture> sendRequest( + final Connection connection, final TRequest request, final TRespHandler responseHandler) { + return requestsQueue.queueTask( + () -> delegate.sendRequest(connection, request, responseHandler)); + } + } } diff --git a/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandler.java b/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandler.java index f5f85af3c22..b2ae1216695 100644 --- a/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandler.java +++ b/networking/p2p/src/main/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandler.java @@ -38,7 +38,6 @@ import tech.pegasys.teku.infrastructure.async.AsyncRunner; import tech.pegasys.teku.infrastructure.async.SafeFuture; import tech.pegasys.teku.infrastructure.async.SafeFuture.Interruptor; -import tech.pegasys.teku.infrastructure.async.ThrottlingTaskQueue; import tech.pegasys.teku.infrastructure.exceptions.ExceptionUtil; import tech.pegasys.teku.networking.p2p.libp2p.LibP2PNodeId; import tech.pegasys.teku.networking.p2p.libp2p.rpc.RpcHandler.Controller; @@ -63,15 +62,12 @@ public class RpcHandler< private final AsyncRunner asyncRunner; private final RpcMethod rpcMethod; - private final ThrottlingTaskQueue concurrentRequestsQueue; public RpcHandler( final AsyncRunner asyncRunner, - final RpcMethod rpcMethod, - final int maxConcurrentRequests) { + final RpcMethod rpcMethod) { this.asyncRunner = asyncRunner; this.rpcMethod = rpcMethod; - concurrentRequestsQueue = ThrottlingTaskQueue.create(maxConcurrentRequests); } public RpcMethod getRpcMethod() { @@ -80,13 +76,6 @@ public RpcMethod getRpcMethod() { public SafeFuture> sendRequest( final Connection connection, final TRequest request, final TRespHandler responseHandler) { - return concurrentRequestsQueue.queueTask( - () -> sendRequestInternal(connection, request, responseHandler)); - } - - public SafeFuture> sendRequestInternal( - final Connection connection, final TRequest request, final TRespHandler responseHandler) { - final Bytes initialPayload; try { initialPayload = rpcMethod.encodeRequest(request); diff --git a/networking/p2p/src/test/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PPeerTest.java b/networking/p2p/src/test/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PPeerTest.java new file mode 100644 index 00000000000..6e173c9ba68 --- /dev/null +++ b/networking/p2p/src/test/java/tech/pegasys/teku/networking/p2p/libp2p/LibP2PPeerTest.java @@ -0,0 +1,91 @@ +/* + * Copyright Consensys Software Inc., 2025 + * + * 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.networking.p2p.libp2p; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.libp2p.core.Connection; +import io.libp2p.core.security.SecureChannel.Session; +import java.util.List; +import java.util.stream.IntStream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tech.pegasys.teku.infrastructure.async.SafeFuture; +import tech.pegasys.teku.networking.p2p.libp2p.rpc.RpcHandler; +import tech.pegasys.teku.networking.p2p.reputation.ReputationManager; +import tech.pegasys.teku.networking.p2p.rpc.RpcMethod; +import tech.pegasys.teku.networking.p2p.rpc.RpcRequestHandler; +import tech.pegasys.teku.networking.p2p.rpc.RpcResponseHandler; +import tech.pegasys.teku.networking.p2p.rpc.RpcStreamController; +import tech.pegasys.teku.spec.constants.NetworkConstants; + +public class LibP2PPeerTest { + + private final Connection connection = mock(Connection.class); + + @SuppressWarnings("unchecked") + private final RpcHandler> rpcHandler = + mock(RpcHandler.class); + + @SuppressWarnings("unchecked") + private final RpcMethod> rpcMethod = + mock(RpcMethod.class); + + private LibP2PPeer libP2PPeer; + + @BeforeEach + public void init() { + when(rpcHandler.getRpcMethod()).thenReturn(rpcMethod); + final Session secureSession = mock(Session.class); + when(connection.secureSession()).thenReturn(secureSession); + when(connection.closeFuture()).thenReturn(new SafeFuture<>()); + libP2PPeer = + new LibP2PPeer(connection, List.of(rpcHandler), ReputationManager.NOOP, peer -> 0.0); + } + + @SuppressWarnings({"unchecked", "FutureReturnValueIgnored"}) + @Test + public void sendRequest_throttlesRequests() { + + // fill the queue with incomplete futures + final List>> queuedFutures = + IntStream.range(0, NetworkConstants.MAX_CONCURRENT_REQUESTS) + .mapToObj( + __ -> { + final SafeFuture> future = + new SafeFuture<>(); + when(rpcHandler.sendRequest(connection, null, null)).thenReturn(future); + libP2PPeer.sendRequest(rpcMethod, null, null); + return future; + }) + .toList(); + + when(rpcHandler.sendRequest(connection, null, null)) + .thenReturn(SafeFuture.completedFuture(mock(RpcStreamController.class))); + + final SafeFuture> throttledRequest = + libP2PPeer.sendRequest(rpcMethod, null, null); + + // completed request should be throttled + assertThat(throttledRequest).isNotDone(); + + // empty the queue + queuedFutures.forEach(future -> future.complete(mock(RpcStreamController.class))); + + // throttled request should have completed now + assertThat(throttledRequest).isDone(); + } +} diff --git a/networking/p2p/src/test/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandlerTest.java b/networking/p2p/src/test/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandlerTest.java index 4537560323e..844e144ffc0 100644 --- a/networking/p2p/src/test/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandlerTest.java +++ b/networking/p2p/src/test/java/tech/pegasys/teku/networking/p2p/libp2p/rpc/RpcHandlerTest.java @@ -30,7 +30,6 @@ import io.libp2p.core.mux.StreamMuxer.Session; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.IntStream; import kotlin.Unit; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -53,9 +52,8 @@ public class RpcHandlerTest { StubAsyncRunner asyncRunner = new StubAsyncRunner(); RpcMethod> rpcMethod = mock(RpcMethod.class); - int maxConcurrentRequests = 2; RpcHandler> rpcHandler = - new RpcHandler<>(asyncRunner, rpcMethod, maxConcurrentRequests); + new RpcHandler<>(asyncRunner, rpcMethod); Connection connection = mock(Connection.class); Session session = mock(Session.class); @@ -249,39 +247,6 @@ void sendRequest_interruptBeforeInitialPayloadWritten( verify(stream).close(); } - @Test - @SuppressWarnings("FutureReturnValueIgnored") - void requestIsThrottledIfQueueIsFull() { - // fill the queue - IntStream.range(0, maxConcurrentRequests) - .forEach(__ -> rpcHandler.sendRequest(connection, request, responseHandler)); - - final StreamPromise> streamPromise1 = - new StreamPromise<>(new CompletableFuture<>(), new CompletableFuture<>()); - when(session.createStream((ProtocolBinding>) any())) - .thenReturn(streamPromise1); - final Stream stream1 = mock(Stream.class); - streamPromise1.getStream().complete(stream1); - streamPromise1.getController().complete(controller); - final CompletableFuture protocolIdFuture1 = new CompletableFuture<>(); - when(stream1.getProtocol()).thenReturn(protocolIdFuture1); - protocolIdFuture1.complete("test"); - - final SafeFuture> throttledResult = - rpcHandler.sendRequest(connection, request, responseHandler); - - assertThat(throttledResult).isNotDone(); - - // empty the queue - streamPromise.getStream().complete(stream); - streamPromise.getController().complete(controller); - stream.getProtocol().complete("test"); - writeFuture.complete(null); - - // throttled request should have completed now - assertThat(throttledResult).isCompleted(); - } - @SuppressWarnings("UnnecessaryAsync") private Class executeInterrupts( final boolean closeStream, final boolean exceedTimeout) { diff --git a/settings.gradle b/settings.gradle index af4d33cac39..b17af30b975 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,7 +10,6 @@ include 'ethereum:executionclient' include 'ethereum:executionlayer' include 'ethereum:execution-types' include 'ethereum:json-types' -include 'ethereum:jackson-deserializers' include 'ethereum:networks' include 'ethereum:pow:api' include 'ethereum:pow:merkletree' @@ -34,7 +33,6 @@ include 'infrastructure:events' include 'infrastructure:exceptions' include 'infrastructure:http' include 'infrastructure:io' -include 'infrastructure:jackson' include 'infrastructure:json' include 'infrastructure:kzg' include 'infrastructure:metrics' diff --git a/teku/src/main/java/tech/pegasys/teku/AbstractNode.java b/teku/src/main/java/tech/pegasys/teku/AbstractNode.java index cb98c043b0d..c7f640b29b5 100644 --- a/teku/src/main/java/tech/pegasys/teku/AbstractNode.java +++ b/teku/src/main/java/tech/pegasys/teku/AbstractNode.java @@ -39,6 +39,7 @@ import tech.pegasys.teku.infrastructure.logging.StartupLogConfig; import tech.pegasys.teku.infrastructure.metrics.MetricsEndpoint; import tech.pegasys.teku.infrastructure.version.VersionProvider; +import tech.pegasys.teku.networks.Eth2NetworkConfiguration; import tech.pegasys.teku.service.serviceutils.ServiceConfig; import tech.pegasys.teku.service.serviceutils.layout.DataDirLayout; import tech.pegasys.teku.services.ServiceController; @@ -133,28 +134,7 @@ private void reportOverrides(final TekuConfiguration tekuConfig) { .ifPresent(forkEpoch -> STATUS_LOG.warnForkEpochChanged(specMilestone.name(), forkEpoch)); } - tekuConfig - .eth2NetworkConfiguration() - .getTotalTerminalDifficultyOverride() - .ifPresent( - ttdo -> - STATUS_LOG.warnBellatrixParameterChanged( - "TERMINAL_TOTAL_DIFFICULTY", ttdo.toString())); - - tekuConfig - .eth2NetworkConfiguration() - .getTerminalBlockHashOverride() - .ifPresent( - tbho -> - STATUS_LOG.warnBellatrixParameterChanged("TERMINAL_BLOCK_HASH", tbho.toString())); - - tekuConfig - .eth2NetworkConfiguration() - .getTerminalBlockHashEpochOverride() - .ifPresent( - tbheo -> - STATUS_LOG.warnBellatrixParameterChanged( - "TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH", tbheo.toString())); + reportBellatrixMergeOverrides(tekuConfig); // Deneb's epochsStoreBlobs warning, which is not actually a full override final Optional specVersionDeneb = @@ -175,6 +155,56 @@ private void reportOverrides(final TekuConfiguration tekuConfig) { }); } + private void reportBellatrixMergeOverrides(final TekuConfiguration tekuConfig) { + tekuConfig + .eth2NetworkConfiguration() + .getTotalTerminalDifficultyOverride() + .ifPresent( + ttdo -> + STATUS_LOG.warnBellatrixParameterChanged( + "TERMINAL_TOTAL_DIFFICULTY", ttdo.toString())); + + final Optional maybeEth2Network = + tekuConfig.eth2NetworkConfiguration().getEth2Network(); + + final boolean reportTerminalBlockHashOverride; + final boolean reportTerminalBlockHashEpochOverride; + if (maybeEth2Network.isEmpty()) { + reportTerminalBlockHashOverride = true; + reportTerminalBlockHashEpochOverride = true; + } else { + final Eth2NetworkConfiguration defaultConfiguration = + Eth2NetworkConfiguration.builder().applyNetworkDefaults(maybeEth2Network.get()).build(); + reportTerminalBlockHashOverride = + !defaultConfiguration + .getTerminalBlockHashOverride() + .equals(tekuConfig.eth2NetworkConfiguration().getTerminalBlockHashOverride()); + reportTerminalBlockHashEpochOverride = + !defaultConfiguration + .getTerminalBlockHashEpochOverride() + .equals(tekuConfig.eth2NetworkConfiguration().getTerminalBlockHashEpochOverride()); + } + + if (reportTerminalBlockHashOverride) { + tekuConfig + .eth2NetworkConfiguration() + .getTerminalBlockHashOverride() + .ifPresent( + tbho -> + STATUS_LOG.warnBellatrixParameterChanged("TERMINAL_BLOCK_HASH", tbho.toString())); + } + + if (reportTerminalBlockHashEpochOverride) { + tekuConfig + .eth2NetworkConfiguration() + .getTerminalBlockHashEpochOverride() + .ifPresent( + tbheo -> + STATUS_LOG.warnBellatrixParameterChanged( + "TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH", tbheo.toString())); + } + } + @Override public abstract ServiceController getServiceController(); diff --git a/teku/src/main/java/tech/pegasys/teku/Teku.java b/teku/src/main/java/tech/pegasys/teku/Teku.java index cf4cecff13c..0382fabba3e 100644 --- a/teku/src/main/java/tech/pegasys/teku/Teku.java +++ b/teku/src/main/java/tech/pegasys/teku/Teku.java @@ -15,10 +15,8 @@ import java.io.PrintWriter; import java.nio.charset.Charset; -import java.security.Security; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import tech.pegasys.teku.bls.impl.blst.BlstLoader; import tech.pegasys.teku.cli.BeaconNodeCommand; import tech.pegasys.teku.cli.BeaconNodeCommand.StartAction; @@ -31,7 +29,6 @@ public final class Teku { static { // Disable libsodium in tuweni Hash because the check for it's presence can be very slow. System.setProperty("org.apache.tuweni.crypto.useSodium", "false"); - Security.addProvider(new BouncyCastleProvider()); } public static void main(final String[] args) { diff --git a/teku/src/main/java/tech/pegasys/teku/cli/options/ValidatorProposerOptions.java b/teku/src/main/java/tech/pegasys/teku/cli/options/ValidatorProposerOptions.java index ddfa860b4df..165bc95e30c 100644 --- a/teku/src/main/java/tech/pegasys/teku/cli/options/ValidatorProposerOptions.java +++ b/teku/src/main/java/tech/pegasys/teku/cli/options/ValidatorProposerOptions.java @@ -60,12 +60,11 @@ public class ValidatorProposerOptions { ValidatorConfig.DEFAULT_BUILDER_REGISTRATION_DEFAULT_ENABLED; @Option( - names = {"--Xvalidators-builder-registration-default-gas-limit"}, + names = {"--validators-builder-registration-default-gas-limit"}, paramLabel = "", showDefaultValue = Visibility.ALWAYS, description = "Change the default gas limit used for the validators registration.", arity = "1", - hidden = true, converter = UInt64Converter.class) private UInt64 builderRegistrationDefaultGasLimit = ValidatorConfig.DEFAULT_BUILDER_REGISTRATION_GAS_LIMIT; diff --git a/teku/src/test/java/tech/pegasys/teku/cli/options/Eth2NetworkOptionsTest.java b/teku/src/test/java/tech/pegasys/teku/cli/options/Eth2NetworkOptionsTest.java index d90f2eb03e0..495133ccc55 100644 --- a/teku/src/test/java/tech/pegasys/teku/cli/options/Eth2NetworkOptionsTest.java +++ b/teku/src/test/java/tech/pegasys/teku/cli/options/Eth2NetworkOptionsTest.java @@ -127,14 +127,16 @@ void shouldUseAlwaysSendPayloadAttributesIfSpecified() { } @Test - void shouldMergeTransitionsOverrideBeEmptyByDefault() { + void shouldMergeTransitionsOverrideContainsMainnetTransitionByDefault() { final TekuConfiguration config = getTekuConfigurationFromArguments(); assertThat(config.eth2NetworkConfiguration().getTotalTerminalDifficultyOverride()) .isEqualTo(Optional.empty()); assertThat(config.eth2NetworkConfiguration().getTerminalBlockHashOverride()) - .isEqualTo(Optional.empty()); + .contains( + Bytes32.fromHexString( + "0x55b11b918355b1ef9c5db810302ebad0bf2544255b530cdce90674d5887bb286")); assertThat(config.eth2NetworkConfiguration().getTerminalBlockHashEpochOverride()) - .isEqualTo(Optional.empty()); + .contains(UInt64.valueOf(146875)); } @Test diff --git a/teku/src/test/java/tech/pegasys/teku/cli/options/ValidatorOptionsTest.java b/teku/src/test/java/tech/pegasys/teku/cli/options/ValidatorOptionsTest.java index c3ca6e4a966..11229684439 100644 --- a/teku/src/test/java/tech/pegasys/teku/cli/options/ValidatorOptionsTest.java +++ b/teku/src/test/java/tech/pegasys/teku/cli/options/ValidatorOptionsTest.java @@ -197,7 +197,7 @@ public void shouldReportDefaultGasLimitIfRegistrationDefaultGasLimitNotSpecified @Test public void shouldSetDefaultGasLimitIfRegistrationDefaultGasLimitIsSpecified() { - final String[] args = {"--Xvalidators-builder-registration-default-gas-limit", "1000"}; + final String[] args = {"--validators-builder-registration-default-gas-limit", "1000"}; final TekuConfiguration config = getTekuConfigurationFromArguments(args); assertThat( config.validatorClient().getValidatorConfig().getBuilderRegistrationDefaultGasLimit()) diff --git a/validator/api/src/main/java/tech/pegasys/teku/validator/api/ValidatorConfig.java b/validator/api/src/main/java/tech/pegasys/teku/validator/api/ValidatorConfig.java index 059d5487435..623c752e9c7 100644 --- a/validator/api/src/main/java/tech/pegasys/teku/validator/api/ValidatorConfig.java +++ b/validator/api/src/main/java/tech/pegasys/teku/validator/api/ValidatorConfig.java @@ -68,7 +68,7 @@ public class ValidatorConfig { public static final boolean DEFAULT_BUILDER_REGISTRATION_DEFAULT_ENABLED = false; public static final boolean DEFAULT_VALIDATOR_BLINDED_BLOCKS_ENABLED = false; public static final int DEFAULT_VALIDATOR_REGISTRATION_SENDING_BATCH_SIZE = 100; - public static final UInt64 DEFAULT_BUILDER_REGISTRATION_GAS_LIMIT = UInt64.valueOf(30_000_000); + public static final UInt64 DEFAULT_BUILDER_REGISTRATION_GAS_LIMIT = UInt64.valueOf(36_000_000); public static final boolean DEFAULT_OBOL_DVT_SELECTIONS_ENDPOINT_ENABLED = false; public static final boolean DEFAULT_ATTESTATIONS_V2_APIS_ENABLED = false; diff --git a/validator/client/build.gradle b/validator/client/build.gradle index 64cc30b7181..742e1a23937 100644 --- a/validator/client/build.gradle +++ b/validator/client/build.gradle @@ -4,7 +4,6 @@ dependencies { implementation project(':infrastructure:crypto') implementation project(':infrastructure:exceptions') implementation project(':infrastructure:io') - implementation project(':infrastructure:jackson') implementation project(':infrastructure:metrics') implementation project(':infrastructure:http') implementation project(':ethereum:json-types') diff --git a/validator/client/src/main/java/tech/pegasys/teku/validator/SetGasLimitException.java b/validator/client/src/main/java/tech/pegasys/teku/validator/SetGasLimitException.java deleted file mode 100644 index cc0de70fbd0..00000000000 --- a/validator/client/src/main/java/tech/pegasys/teku/validator/SetGasLimitException.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.validator; - -public class SetGasLimitException extends IllegalArgumentException { - - public SetGasLimitException(final String message) { - super(message); - } -} diff --git a/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeyDeserializer.java b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeyDeserializer.java index d859f3ef5a3..2c5e63f6cd6 100644 --- a/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeyDeserializer.java +++ b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeyDeserializer.java @@ -20,6 +20,7 @@ import tech.pegasys.teku.bls.BLSPublicKey; class BLSPublicKeyDeserializer extends JsonDeserializer { + @Override public BLSPublicKey deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException { diff --git a/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeySerializer.java b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeySerializer.java index d7d48bea2dd..9952ac46c07 100644 --- a/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeySerializer.java +++ b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/BLSPublicKeySerializer.java @@ -21,6 +21,7 @@ import tech.pegasys.teku.bls.BLSPublicKey; class BLSPublicKeySerializer extends JsonSerializer { + @Override public void serialize( final BLSPublicKey value, final JsonGenerator gen, final SerializerProvider serializers) diff --git a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes48KeyDeserializer.java b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/Bytes48KeyDeserializer.java similarity index 94% rename from infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes48KeyDeserializer.java rename to validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/Bytes48KeyDeserializer.java index f10eb2c028c..1c5e32ba6ca 100644 --- a/infrastructure/jackson/src/main/java/tech/pegasys/teku/infrastructure/jackson/deserializers/bytes/Bytes48KeyDeserializer.java +++ b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/Bytes48KeyDeserializer.java @@ -11,7 +11,7 @@ * specific language governing permissions and limitations under the License. */ -package tech.pegasys.teku.infrastructure.jackson.deserializers.bytes; +package tech.pegasys.teku.validator.client.proposerconfig.loader; import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.databind.DeserializationContext; diff --git a/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/ProposerConfigLoader.java b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/ProposerConfigLoader.java index 543025c9317..aee1a0383b7 100644 --- a/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/ProposerConfigLoader.java +++ b/validator/client/src/main/java/tech/pegasys/teku/validator/client/proposerconfig/loader/ProposerConfigLoader.java @@ -27,19 +27,18 @@ import tech.pegasys.teku.infrastructure.exceptions.ExceptionUtil; import tech.pegasys.teku.infrastructure.exceptions.InvalidConfigurationException; import tech.pegasys.teku.infrastructure.http.UrlSanitizer; -import tech.pegasys.teku.infrastructure.jackson.deserializers.bytes.Bytes48KeyDeserializer; import tech.pegasys.teku.validator.client.ProposerConfig; public class ProposerConfigLoader { private final ObjectMapper objectMapper; public ProposerConfigLoader() { - this.objectMapper = new ObjectMapper(); + objectMapper = new ObjectMapper(); addTekuMappers(); } private void addTekuMappers() { - SimpleModule module = + final SimpleModule module = new SimpleModule("ProposerConfigLoader", new Version(1, 0, 0, null, null, null)); module.addDeserializer(BLSPublicKey.class, new BLSPublicKeyDeserializer()); module.addSerializer(BLSPublicKey.class, new BLSPublicKeySerializer()); @@ -49,7 +48,7 @@ private void addTekuMappers() { } public ObjectMapper getObjectMapper() { - return this.objectMapper; + return objectMapper; } public ProposerConfig getProposerConfig(final URL source) { diff --git a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/BlindedBlockEndpointNotAvailableException.java b/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/BlindedBlockEndpointNotAvailableException.java deleted file mode 100644 index 5e213df09f3..00000000000 --- a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/BlindedBlockEndpointNotAvailableException.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2022 - * - * 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.validator.remote.typedef; - -public class BlindedBlockEndpointNotAvailableException extends RuntimeException {} diff --git a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/BlockProductionV3FailedException.java b/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/BlockProductionV3FailedException.java deleted file mode 100644 index 17b389b947a..00000000000 --- a/validator/remote/src/main/java/tech/pegasys/teku/validator/remote/typedef/BlockProductionV3FailedException.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Consensys Software Inc., 2023 - * - * 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.validator.remote.typedef; - -public class BlockProductionV3FailedException extends RuntimeException {}