Skip to content

Commit

Permalink
Implemented engine_forkchoiceUpdatedV4 (#8748)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucassaldanha authored Oct 18, 2024
1 parent 9398cce commit aa23460
Show file tree
Hide file tree
Showing 13 changed files with 543 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV2;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV3;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV4;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadStatusV1;
import tech.pegasys.teku.ethereum.executionclient.schema.Response;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
Expand Down Expand Up @@ -76,6 +77,9 @@ SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV2(
SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV3(
ForkChoiceStateV1 forkChoiceState, Optional<PayloadAttributesV3> payloadAttributes);

SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV4(
ForkChoiceStateV1 forkChoiceState, Optional<PayloadAttributesV4> payloadAttributes);

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

SafeFuture<Response<List<ClientVersionV1>>> getClientVersionV1(ClientVersionV1 clientVersion);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV2;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV3;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV4;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadStatusV1;
import tech.pegasys.teku.ethereum.executionclient.schema.Response;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
Expand Down Expand Up @@ -144,6 +145,14 @@ public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV3(
() -> delegate.forkChoiceUpdatedV3(forkChoiceState, payloadAttributes));
}

@Override
public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV4(
final ForkChoiceStateV1 forkChoiceState,
final Optional<PayloadAttributesV4> payloadAttributes) {
return taskQueue.queueTask(
() -> delegate.forkChoiceUpdatedV4(forkChoiceState, payloadAttributes));
}

@Override
public SafeFuture<Response<List<String>>> exchangeCapabilities(final List<String> capabilities) {
return taskQueue.queueTask(() -> delegate.exchangeCapabilities(capabilities));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* 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.ethereum.executionclient.methods;

import java.util.Optional;
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.ethereum.executionclient.schema.ForkChoiceStateV1;
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV4;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.spec.executionlayer.ForkChoiceState;
import tech.pegasys.teku.spec.executionlayer.PayloadBuildingAttributes;

public class EngineForkChoiceUpdatedV4
extends AbstractEngineJsonRpcMethod<
tech.pegasys.teku.spec.executionlayer.ForkChoiceUpdatedResult> {

private static final Logger LOG = LogManager.getLogger();

public EngineForkChoiceUpdatedV4(final ExecutionEngineClient executionEngineClient) {
super(executionEngineClient);
}

@Override
public String getName() {
return EngineApiMethod.ENGINE_FORK_CHOICE_UPDATED.getName();
}

@Override
public int getVersion() {
return 4;
}

@Override
public SafeFuture<tech.pegasys.teku.spec.executionlayer.ForkChoiceUpdatedResult> execute(
final JsonRpcRequestParams params) {
final ForkChoiceState forkChoiceState = params.getRequiredParameter(0, ForkChoiceState.class);
final Optional<PayloadBuildingAttributes> payloadBuildingAttributes =
params.getOptionalParameter(1, PayloadBuildingAttributes.class);

LOG.trace(
"Calling {}(forkChoiceState={}, payloadAttributes={})",
getVersionedName(),
forkChoiceState,
payloadBuildingAttributes);

final Optional<PayloadAttributesV4> maybePayloadAttributes =
payloadBuildingAttributes.flatMap(
attributes ->
PayloadAttributesV4.fromInternalPayloadBuildingAttributesV4(
payloadBuildingAttributes));

return executionEngineClient
.forkChoiceUpdatedV4(
ForkChoiceStateV1.fromInternalForkChoiceState(forkChoiceState), maybePayloadAttributes)
.thenApply(ResponseUnwrapper::unwrapExecutionClientResponseOrThrow)
.thenApply(ForkChoiceUpdatedResult::asInternalExecutionPayload)
.thenPeek(
forkChoiceUpdatedResult ->
LOG.trace(
"Response {}(forkChoiceState={}, payloadAttributes={}) -> {}",
getVersionedName(),
forkChoiceState,
payloadBuildingAttributes,
forkChoiceUpdatedResult));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV2;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV3;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV4;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadStatusV1;
import tech.pegasys.teku.ethereum.executionclient.schema.Response;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
Expand All @@ -59,8 +60,11 @@ public class MetricRecordingExecutionEngineClient extends MetricRecordingAbstrac
public static final String FORKCHOICE_UPDATED_WITH_ATTRIBUTES_V2_METHOD =
"forkchoice_updated_with_attributesV2";
public static final String FORKCHOICE_UPDATED_V3_METHOD = "forkchoice_updatedV3";
public static final String FORKCHOICE_UPDATED_V4_METHOD = "forkchoice_updatedV4";
public static final String FORKCHOICE_UPDATED_WITH_ATTRIBUTES_V3_METHOD =
"forkchoice_updated_with_attributesV3";
public static final String FORKCHOICE_UPDATED_WITH_ATTRIBUTES_V4_METHOD =
"forkchoice_updated_with_attributesV4";
public static final String GET_PAYLOAD_V3_METHOD = "get_payloadV3";
public static final String GET_PAYLOAD_V4_METHOD = "get_payloadV4";
public static final String NEW_PAYLOAD_V3_METHOD = "new_payloadV3";
Expand Down Expand Up @@ -185,6 +189,17 @@ public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV3(
: FORKCHOICE_UPDATED_V3_METHOD);
}

@Override
public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV4(
final ForkChoiceStateV1 forkChoiceState,
final Optional<PayloadAttributesV4> payloadAttributes) {
return countRequest(
() -> delegate.forkChoiceUpdatedV4(forkChoiceState, payloadAttributes),
payloadAttributes.isPresent()
? FORKCHOICE_UPDATED_WITH_ATTRIBUTES_V4_METHOD
: FORKCHOICE_UPDATED_V4_METHOD);
}

@Override
public SafeFuture<Response<List<String>>> exchangeCapabilities(final List<String> capabilities) {
return countRequest(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* 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.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.List;
import java.util.Objects;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes32;
import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexDeserializer;
import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexSerializer;
import tech.pegasys.teku.infrastructure.bytes.Bytes20;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.executionlayer.PayloadBuildingAttributes;

public class PayloadAttributesV4 extends PayloadAttributesV3 {

@JsonSerialize(using = UInt64AsHexSerializer.class)
@JsonDeserialize(using = UInt64AsHexDeserializer.class)
public final UInt64 targetBlockCount;

@JsonSerialize(using = UInt64AsHexSerializer.class)
@JsonDeserialize(using = UInt64AsHexDeserializer.class)
public final UInt64 maximumBlobCount;

public PayloadAttributesV4(
final @JsonProperty("timestamp") UInt64 timestamp,
final @JsonProperty("prevRandao") Bytes32 prevRandao,
final @JsonProperty("suggestedFeeRecipient") Bytes20 suggestedFeeRecipient,
final @JsonProperty("withdrawals") List<WithdrawalV1> withdrawals,
final @JsonProperty("parentBeaconBlockRoot") Bytes32 parentBeaconBlockRoot,
final @JsonProperty("targetBlobCount") UInt64 targetBlockCount,
final @JsonProperty("maximumBlobCount") UInt64 maximumBlobCount) {
super(timestamp, prevRandao, suggestedFeeRecipient, withdrawals, parentBeaconBlockRoot);

checkNotNull(targetBlockCount, "targetBlockCount");
checkNotNull(maximumBlobCount, "maximumBlobCount");
this.targetBlockCount = targetBlockCount;
this.maximumBlobCount = maximumBlobCount;
}

public static Optional<PayloadAttributesV4> fromInternalPayloadBuildingAttributesV4(
final Optional<PayloadBuildingAttributes> payloadBuildingAttributes) {
return payloadBuildingAttributes.map(
payloadAttributes ->
new PayloadAttributesV4(
payloadAttributes.getTimestamp(),
payloadAttributes.getPrevRandao(),
payloadAttributes.getFeeRecipient(),
getWithdrawals(payloadAttributes),
payloadAttributes.getParentBeaconBlockRoot(),
payloadAttributes
.getTargetBlobCount()
.orElseThrow(
() ->
new IllegalArgumentException(
"targetBlobCount is required for PayloadAttributesV4")),
payloadAttributes
.getMaximumBlobCount()
.orElseThrow(
() ->
new IllegalArgumentException(
"maximumBlobCount is required for PayloadAttributesV4"))));
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
final PayloadAttributesV4 that = (PayloadAttributesV4) o;
return Objects.equals(targetBlockCount, that.targetBlockCount)
&& Objects.equals(maximumBlobCount, that.maximumBlobCount);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), targetBlockCount, maximumBlobCount);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("timestamp", timestamp)
.add("prevRandao", prevRandao)
.add("suggestedFeeRecipient", suggestedFeeRecipient)
.add("withdrawals", withdrawals)
.add("parentBeaconBlockRoot", parentBeaconBlockRoot)
.add("targetBlockCount", targetBlockCount)
.add("maximumBlobCount", maximumBlobCount)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV2;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV3;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV4;
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadStatusV1;
import tech.pegasys.teku.ethereum.executionclient.schema.Response;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
Expand Down Expand Up @@ -238,6 +239,19 @@ public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV3(
return web3JClient.doRequest(web3jRequest, EL_ENGINE_BLOCK_EXECUTION_TIMEOUT);
}

@Override
public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV4(
final ForkChoiceStateV1 forkChoiceState,
final Optional<PayloadAttributesV4> payloadAttributes) {
final Request<?, ForkChoiceUpdatedResultWeb3jResponse> web3jRequest =
new Request<>(
"engine_forkchoiceUpdatedV4",
list(forkChoiceState, payloadAttributes.orElse(null)),
web3JClient.getWeb3jService(),
ForkChoiceUpdatedResultWeb3jResponse.class);
return web3JClient.doRequest(web3jRequest, EL_ENGINE_BLOCK_EXECUTION_TIMEOUT);
}

@Override
public SafeFuture<Response<List<String>>> exchangeCapabilities(final List<String> capabilities) {
final Request<?, ExchangeCapabilitiesWeb3jResponse> web3jRequest =
Expand Down
Loading

0 comments on commit aa23460

Please sign in to comment.