Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add engine_getClientVersionV1 interface + ability to get commit hash #8070

Merged
merged 12 commits into from
Mar 13, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static org.assertj.core.api.Assumptions.assumeThat;
import static org.assertj.core.api.InstanceOfAssertFactories.INTEGER;
import static org.assertj.core.api.InstanceOfAssertFactories.LIST;
import static org.assertj.core.api.InstanceOfAssertFactories.MAP;
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
import static org.mockito.Mockito.mock;
import static tech.pegasys.teku.spec.SpecMilestone.CAPELLA;
Expand Down Expand Up @@ -46,6 +47,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import tech.pegasys.teku.ethereum.executionclient.events.ExecutionClientEventsChannel;
import tech.pegasys.teku.ethereum.executionclient.schema.ClientVersionV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3;
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult;
Expand All @@ -54,6 +56,7 @@
import tech.pegasys.teku.ethereum.executionclient.schema.Response;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.bytes.Bytes20;
import tech.pegasys.teku.infrastructure.bytes.Bytes4;
import tech.pegasys.teku.infrastructure.json.JsonTestUtil;
import tech.pegasys.teku.infrastructure.time.StubTimeProvider;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
Expand Down Expand Up @@ -204,6 +207,36 @@ public void exchangeCapabilities_shouldBuildRequestAndResponseSuccessfully() thr
assertThat(requestData.get("params")).asInstanceOf(LIST).containsExactly(consensusCapabilities);
}

@TestTemplate
public void getClientVersionV1_shouldBuildRequestAndResponseSuccessfully() throws Exception {
final ClientVersionV1 consensusClientVersion =
new ClientVersionV1("TK", "teku", "1.0.0", Bytes4.fromHexString("87fa8ca7"));
final ClientVersionV1 executionClientVersion =
new ClientVersionV1("BU", "besu", "1.0.0", Bytes4.fromHexString("8dba2981"));

final JsonRpcResponse responseBody = new JsonRpcResponse(List.of(executionClientVersion));
mockSuccessfulResponse(objectMapper.writeValueAsString(responseBody));

final SafeFuture<Response<List<ClientVersionV1>>> response =
eeClient.getClientVersionV1(consensusClientVersion);
assertThat(response)
.succeedsWithin(1, TimeUnit.SECONDS)
.isEqualTo(new Response<>(List.of(executionClientVersion)));

final Map<String, Object> requestData = takeRequest();
verifyJsonRpcMethodCall(requestData, "engine_getClientVersionV1");
assertThat(requestData.get("params"))
.asInstanceOf(LIST)
.hasSize(1)
.first()
.asInstanceOf(MAP)
.hasSize(4)
.containsEntry("code", "TK")
.containsEntry("name", "teku")
.containsEntry("version", "1.0.0")
.containsEntry("commit", "0x87fa8ca7");
}

@TestTemplate
@SuppressWarnings("unchecked")
public void newPayloadV3_shouldBuildRequestAndResponseSuccessfully() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.ethereum.executionclient.schema.ClientVersionV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3;
Expand Down Expand Up @@ -65,4 +66,6 @@ SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV3(
ForkChoiceStateV1 forkChoiceState, Optional<PayloadAttributesV3> payloadAttributes);

SafeFuture<Response<List<String>>> exchangeCapabilities(List<String> capabilities);

SafeFuture<Response<List<ClientVersionV1>>> getClientVersionV1(ClientVersionV1 clientVersion);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import tech.pegasys.teku.ethereum.executionclient.schema.ClientVersionV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3;
Expand Down Expand Up @@ -127,4 +128,10 @@ public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV3(
public SafeFuture<Response<List<String>>> exchangeCapabilities(final List<String> capabilities) {
return taskQueue.queueTask(() -> delegate.exchangeCapabilities(capabilities));
}

@Override
public SafeFuture<Response<List<ClientVersionV1>>> getClientVersionV1(
final ClientVersionV1 clientVersion) {
return taskQueue.queueTask(() -> delegate.getClientVersionV1(clientVersion));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.tuweni.bytes.Bytes32;
import org.hyperledger.besu.plugin.services.MetricsSystem;
import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient;
import tech.pegasys.teku.ethereum.executionclient.schema.ClientVersionV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2;
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3;
Expand Down Expand Up @@ -59,6 +60,8 @@ public class MetricRecordingExecutionEngineClient extends MetricRecordingAbstrac
"forkchoice_updated_with_attributesV3";
public static final String GET_PAYLOAD_V3_METHOD = "get_payloadV3";
public static final String NEW_PAYLOAD_V3_METHOD = "new_payloadV3";
public static final String EXCHANGE_CAPABILITIES_METHOD = "exchange_capabilities";
public static final String GET_CLIENT_VERSION_V1_METHOD = "get_client_versionV1";

private final ExecutionEngineClient delegate;

Expand Down Expand Up @@ -160,6 +163,14 @@ public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV3(

@Override
public SafeFuture<Response<List<String>>> exchangeCapabilities(final List<String> capabilities) {
return delegate.exchangeCapabilities(capabilities);
return countRequest(
() -> delegate.exchangeCapabilities(capabilities), EXCHANGE_CAPABILITIES_METHOD);
}

@Override
public SafeFuture<Response<List<ClientVersionV1>>> getClientVersionV1(
final ClientVersionV1 clientVersion) {
return countRequest(
() -> delegate.getClientVersionV1(clientVersion), GET_CLIENT_VERSION_V1_METHOD);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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 tech.pegasys.teku.ethereum.executionclient.serialization.Bytes4Deserializer;
import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes4Serializer;
import tech.pegasys.teku.infrastructure.bytes.Bytes4;
import tech.pegasys.teku.spec.datastructures.execution.ClientVersion;

public class ClientVersionV1 {

public final String code;
public final String name;
public final String version;

@JsonSerialize(using = Bytes4Serializer.class)
@JsonDeserialize(using = Bytes4Deserializer.class)
public final Bytes4 commit;

public ClientVersionV1(
@JsonProperty("code") String code,
@JsonProperty("name") String name,
@JsonProperty("version") String version,
@JsonProperty("commit") Bytes4 commit) {
checkNotNull(code, "code");
checkNotNull(name, "name");
checkNotNull(version, "version");
checkNotNull(commit, "commit");
this.code = code;
this.name = name;
this.version = version;
this.commit = commit;
}

public static ClientVersionV1 fromInternalClientVersion(final ClientVersion clientVersion) {
return new ClientVersionV1(
clientVersion.code(),
clientVersion.name(),
clientVersion.version(),
clientVersion.commit());
}

public static ClientVersion asInternalClientVersion(final ClientVersionV1 clientVersionV1) {
return new ClientVersion(
clientVersionV1.code,
clientVersionV1.name,
clientVersionV1.version,
clientVersionV1.commit);
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final ClientVersionV1 that = (ClientVersionV1) o;
return Objects.equals(code, that.code)
&& Objects.equals(name, that.name)
&& Objects.equals(version, that.version)
&& Objects.equals(commit, that.commit);
}

@Override
public int hashCode() {
return Objects.hash(code, name, version, commit);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("code", code)
.add("name", name)
.add("version", version)
.add("commit", commit)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.executionclient.serialization;

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<Bytes4> {

@Override
public Bytes4 deserialize(final JsonParser p, final DeserializationContext ctxt)
throws IOException {
return Bytes4.fromHexString(p.getValueAsString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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.executionclient.serialization;

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<Bytes4> {
@Override
public void serialize(
final Bytes4 value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeString(value.toHexString().toLowerCase(Locale.ROOT));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ private synchronized void buildClient() {
.jwtConfigOpt(jwtConfig)
.timeProvider(timeProvider)
.executionClientEventsPublisher(executionClientEventsPublisher)
.nonCriticalMethods("engine_exchangeCapabilities")
.nonCriticalMethods("engine_exchangeCapabilities", "engine_getClientVersionV1")
.build();
this.alreadyBuilt = true;
}
Expand Down
Loading