Skip to content

Commit

Permalink
EIP-7742 Add targetBlobCount and maximumBlobCount to engine_forkchoic…
Browse files Browse the repository at this point in the history
…eUpdatedV4

Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
  • Loading branch information
siladu committed Oct 31, 2024
1 parent acede4b commit bf140bb
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public enum RpcMethod {
ENGINE_FORKCHOICE_UPDATED_V1("engine_forkchoiceUpdatedV1"),
ENGINE_FORKCHOICE_UPDATED_V2("engine_forkchoiceUpdatedV2"),
ENGINE_FORKCHOICE_UPDATED_V3("engine_forkchoiceUpdatedV3"),
ENGINE_FORKCHOICE_UPDATED_V4("engine_forkchoiceUpdatedV4"),
ENGINE_EXCHANGE_TRANSITION_CONFIGURATION("engine_exchangeTransitionConfigurationV1"),
ENGINE_GET_CLIENT_VERSION_V1("engine_getClientVersionV1"),
ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1("engine_getPayloadBodiesByHashV1"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;

import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.PRAGUE;

import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EngineForkchoiceUpdatedParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadAttributesParameter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;

import java.util.Optional;

import io.vertx.core.Vertx;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EngineForkchoiceUpdatedV4 extends AbstractEngineForkchoiceUpdated {

private static final Logger LOG = LoggerFactory.getLogger(EngineForkchoiceUpdatedV4.class);
protected final Optional<Long> pragueMilestone;

public EngineForkchoiceUpdatedV4(
final Vertx vertx,
final ProtocolSchedule protocolSchedule,
final ProtocolContext protocolContext,
final MergeMiningCoordinator mergeCoordinator,
final EngineCallListener engineCallListener) {
super(vertx, protocolSchedule, protocolContext, mergeCoordinator, engineCallListener);
this.pragueMilestone = protocolSchedule.milestoneFor(PRAGUE);
}

@Override
public String getName() {
return RpcMethod.ENGINE_FORKCHOICE_UPDATED_V4.getMethodName();
}

@Override
protected ValidationResult<RpcErrorType> validateParameter(
final EngineForkchoiceUpdatedParameter fcuParameter,
final Optional<EnginePayloadAttributesParameter> maybePayloadAttributes) {
if (fcuParameter.getHeadBlockHash() == null) {
return ValidationResult.invalid(
getInvalidPayloadAttributesError(), "Missing head block hash");
} else if (fcuParameter.getSafeBlockHash() == null) {
return ValidationResult.invalid(
getInvalidPayloadAttributesError(), "Missing safe block hash");
} else if (fcuParameter.getFinalizedBlockHash() == null) {
return ValidationResult.invalid(
getInvalidPayloadAttributesError(), "Missing finalized block hash");
}
if (maybePayloadAttributes.isPresent()) {
if (maybePayloadAttributes.get().getParentBeaconBlockRoot() == null) {
return ValidationResult.invalid(
getInvalidPayloadAttributesError(), "Missing parent beacon block root hash");
}
if (maybePayloadAttributes.get().getTargetBlobCount() == null) {
return ValidationResult.invalid(
getInvalidPayloadAttributesError(), "Missing target blob count");
}
if (maybePayloadAttributes.get().getMaximumBlobCount() == null) {
return ValidationResult.invalid(
getInvalidPayloadAttributesError(), "Missing maximum blob count");
}
}
return ValidationResult.valid();
}

@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
return ForkSupportHelper.validateForkSupported(PRAGUE, pragueMilestone, blockTimestamp);
}

@Override
protected Optional<JsonRpcErrorResponse> isPayloadAttributesValid(
final Object requestId, final EnginePayloadAttributesParameter payloadAttributes) {
if (payloadAttributes.getParentBeaconBlockRoot() == null) {
LOG.error(
"Parent beacon block root hash not present in payload attributes after cancun hardfork");
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
}
if (payloadAttributes.getTargetBlobCount() == null) {
LOG.error("targetBlobCount not present in payload attributes after prague hardfork");
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
}
if (payloadAttributes.getMaximumBlobCount() == null) {
LOG.error("maximumBlobCount not present in payload attributes after prague hardfork");
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
}

if (payloadAttributes.getTimestamp() == 0) {
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
}

if (pragueMilestone.isEmpty() || payloadAttributes.getTimestamp() < pragueMilestone.get()) {
return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.UNSUPPORTED_FORK));
}

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import io.vertx.core.json.JsonObject;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;

public class EnginePayloadAttributesParameter {

Expand All @@ -31,20 +32,27 @@ public class EnginePayloadAttributesParameter {
final Address suggestedFeeRecipient;
final List<WithdrawalParameter> withdrawals;
private final Bytes32 parentBeaconBlockRoot;
private final UInt64 targetBlobCount;
private final UInt64 maximumBlobCount;

@JsonCreator
public EnginePayloadAttributesParameter(
@JsonProperty("timestamp") final String timestamp,
@JsonProperty("prevRandao") final String prevRandao,
@JsonProperty("suggestedFeeRecipient") final String suggestedFeeRecipient,
@JsonProperty("withdrawals") final List<WithdrawalParameter> withdrawals,
@JsonProperty("parentBeaconBlockRoot") final String parentBeaconBlockRoot) {
@JsonProperty("parentBeaconBlockRoot") final String parentBeaconBlockRoot,
@JsonProperty("targetBlobCount") final String targetBlobCount,
@JsonProperty("maximumBlobCount") final String maximumBlobCount) {
this.timestamp = Long.decode(timestamp);
this.prevRandao = Bytes32.fromHexString(prevRandao);
this.suggestedFeeRecipient = Address.fromHexString(suggestedFeeRecipient);
this.withdrawals = withdrawals;
this.parentBeaconBlockRoot =
parentBeaconBlockRoot == null ? null : Bytes32.fromHexString(parentBeaconBlockRoot);
this.targetBlobCount = targetBlobCount == null ? null : UInt64.fromHexString(targetBlobCount);
this.maximumBlobCount =
maximumBlobCount == null ? null : UInt64.fromHexString(maximumBlobCount);
}

public Long getTimestamp() {
Expand All @@ -63,6 +71,14 @@ public Bytes32 getParentBeaconBlockRoot() {
return parentBeaconBlockRoot;
}

public UInt64 getTargetBlobCount() {
return targetBlobCount;
}

public UInt64 getMaximumBlobCount() {
return maximumBlobCount;
}

public List<WithdrawalParameter> getWithdrawals() {
return withdrawals;
}
Expand All @@ -81,6 +97,12 @@ public String serialize() {
if (parentBeaconBlockRoot != null) {
json.put("parentBeaconBlockRoot", parentBeaconBlockRoot.toHexString());
}
if (targetBlobCount != null) {
json.put("targetBlobCount", targetBlobCount.toHexString());
}
if (maximumBlobCount != null) {
json.put("maximumBlobCount", maximumBlobCount.toHexString());
}
return json.encode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV2;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV3;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineForkchoiceUpdatedV4;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetBlobsV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetClientVersionV1;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.EngineGetPayloadBodiesByHashV1;
Expand Down Expand Up @@ -177,23 +178,28 @@ protected Map<String, JsonRpcMethod> create() {
}

if (protocolSchedule.anyMatch(p -> p.spec().getName().equalsIgnoreCase("prague"))) {
executionEngineApisSupported.add(
new EngineGetPayloadV4(
consensusEngineServer,
protocolContext,
mergeCoordinator.get(),
blockResultFactory,
engineQosTimer,
protocolSchedule));

executionEngineApisSupported.add(
new EngineNewPayloadV4(
consensusEngineServer,
protocolSchedule,
protocolContext,
mergeCoordinator.get(),
ethPeers,
engineQosTimer));
executionEngineApisSupported.addAll(
List.of(
new EngineGetPayloadV4(
consensusEngineServer,
protocolContext,
mergeCoordinator.get(),
blockResultFactory,
engineQosTimer,
protocolSchedule),
new EngineNewPayloadV4(
consensusEngineServer,
protocolSchedule,
protocolContext,
mergeCoordinator.get(),
ethPeers,
engineQosTimer),
new EngineForkchoiceUpdatedV4(
consensusEngineServer,
protocolSchedule,
protocolContext,
mergeCoordinator.get(),
engineQosTimer)));
}

return mapOf(executionEngineApisSupported);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,8 @@ public void shouldReturnValidWithoutFinalizedWithPayload() {
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
null,
null,
null,
null);
var mockPayloadId =
PayloadIdentifier.forPayloadParams(
Expand Down Expand Up @@ -433,6 +435,8 @@ public void shouldIgnoreUpdateToOldHeadAndNotPreparePayload() {
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
null,
null,
null,
null);

var resp =
Expand Down Expand Up @@ -470,6 +474,8 @@ public void shouldReturnInvalidIfPayloadTimestampNotGreaterThanHead() {
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
emptyList(),
null,
null,
null);

var resp =
Expand All @@ -495,6 +501,8 @@ public void shouldReturnInvalidIfWithdrawalsIsNotNull_WhenWithdrawalsProhibited(
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
emptyList(),
null,
null,
null);

var resp =
Expand All @@ -520,6 +528,8 @@ public void shouldReturnValidIfWithdrawalsIsNull_WhenWithdrawalsProhibited() {
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
null,
null,
null,
null);

var mockPayloadId =
Expand Down Expand Up @@ -564,6 +574,8 @@ public void shouldReturnInvalidIfWithdrawalsIsNull_WhenWithdrawalsAllowed() {
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
null,
null,
null,
null);

var resp =
Expand Down Expand Up @@ -600,6 +612,8 @@ public void shouldReturnValidIfWithdrawalsIsNotNull_WhenWithdrawalsAllowed() {
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
withdrawalParameters,
null,
null,
null);

final Optional<List<Withdrawal>> withdrawals =
Expand Down Expand Up @@ -649,6 +663,8 @@ public void shouldReturnValidIfProtocolScheduleIsEmpty() {
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
null,
null,
null,
null);

var mockPayloadId =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ public void shouldReturnUnsupportedForkIfBlockTimestampIsAfterCancunMilestone()
Bytes32.fromHexStringLenient("0xDEADBEEF").toHexString(),
Address.ECREC.toString(),
null,
null,
null,
null);

final JsonRpcResponse resp = resp(param, Optional.of(payloadParams));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,13 @@ public void serialize_WithdrawalsPresent() {

private EnginePayloadAttributesParameter parameterWithdrawalsOmitted() {
return new EnginePayloadAttributesParameter(
TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, null, null);
TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, null, null, null, null);
}

private EnginePayloadAttributesParameter parameterWithdrawalsPresent() {
final List<WithdrawalParameter> withdrawals = List.of(WITHDRAWAL_PARAM_1, WITHDRAWAL_PARAM_2);
return new EnginePayloadAttributesParameter(
TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, withdrawals, null);
TIMESTAMP, PREV_RANDAO, SUGGESTED_FEE_RECIPIENT_ADDRESS, withdrawals, null, null, null);
}

// TODO: add a parent beacon block root test here
Expand Down

0 comments on commit bf140bb

Please sign in to comment.