Skip to content

Commit

Permalink
Fix protocol schedule for devnets (hyperledger#7429)
Browse files Browse the repository at this point in the history
* add `ProtocolSchedule::milestoneFor` to retrieve milestones for every hardfork in the genesis file
* add `setMilestones` and `milestoneFor` to TransitionProtocolSchedule
* refactored all checks for hardforks in the engine API to use hard fork ids
* added tests to test that the engine API v2 endpoints return UNSUPPORTED_FORK past Cancun

Signed-off-by: Daniel Lehrner <[email protected]>

---------

Signed-off-by: Daniel Lehrner <[email protected]>
Signed-off-by: Sally MacFarlane <[email protected]>
Co-authored-by: Sally MacFarlane <[email protected]>
  • Loading branch information
daniellehrner and macfarla authored Aug 12, 2024
1 parent fab2393 commit 2158a68
Show file tree
Hide file tree
Showing 23 changed files with 566 additions and 201 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

### Bug fixes
- Correct entrypoint in Docker evmtool [#7430](https://github.com/hyperledger/besu/pull/7430)
- Fix protocol schedule check for devnets [#7429](https://github.com/hyperledger/besu/pull/7429)
- Fix behaviour when starting in a pre-merge network [#7431](https://github.com/hyperledger/besu/pull/7431)

## 24.7.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.hyperledger.besu.ethereum.core.MiningParameters;
import org.hyperledger.besu.ethereum.core.PermissionTransactionFilter;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.mainnet.HardforkId;
import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
Expand Down Expand Up @@ -241,6 +242,13 @@ public String listMilestones() {
return transitionUtils.dispatchFunctionAccordingToMergeState(ProtocolSchedule::listMilestones);
}

@Override
public Optional<Long> milestoneFor(final HardforkId hardforkId) {
return mergeContext.isPostMerge()
? transitionUtils.getPostMergeObject().milestoneFor(hardforkId)
: transitionUtils.getPreMergeObject().milestoneFor(hardforkId);
}

/**
* Sets transaction filter.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.SYNCING;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.VALID;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine.WithdrawalsValidatorProvider.getWithdrawalsValidator;
import static org.hyperledger.besu.ethereum.mainnet.HardforkId.MainnetHardforkId.CANCUN;

import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator.ForkchoiceResult;
Expand All @@ -38,7 +39,6 @@
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Withdrawal;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;

import java.util.List;
Expand All @@ -54,7 +54,7 @@
public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJsonRpcMethod {
private static final Logger LOG = LoggerFactory.getLogger(AbstractEngineForkchoiceUpdated.class);
private final MergeMiningCoordinator mergeCoordinator;
protected final Long cancunTimestamp;
protected final Optional<Long> cancunMilestone;

public AbstractEngineForkchoiceUpdated(
final Vertx vertx,
Expand All @@ -65,9 +65,7 @@ public AbstractEngineForkchoiceUpdated(
super(vertx, protocolSchedule, protocolContext, engineCallListener);

this.mergeCoordinator = mergeCoordinator;
Optional<ScheduledProtocolSpec.Hardfork> cancun =
protocolSchedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun"));
cancunTimestamp = cancun.map(ScheduledProtocolSpec.Hardfork::milestone).orElse(Long.MAX_VALUE);
cancunMilestone = protocolSchedule.milestoneFor(CANCUN);
}

protected ValidationResult<RpcErrorType> validateParameter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;

Expand Down Expand Up @@ -51,20 +52,22 @@ public String getName() {
@Override
protected Optional<JsonRpcErrorResponse> isPayloadAttributesValid(
final Object requestId, final EnginePayloadAttributesParameter payloadAttributes) {
if (payloadAttributes.getTimestamp() >= cancunTimestamp) {
if (payloadAttributes.getParentBeaconBlockRoot() == null
|| payloadAttributes.getParentBeaconBlockRoot().isEmpty()) {
return Optional.of(new JsonRpcErrorResponse(requestId, RpcErrorType.UNSUPPORTED_FORK));
} else {
return Optional.of(
new JsonRpcErrorResponse(requestId, RpcErrorType.INVALID_PAYLOAD_ATTRIBUTES));
}
} else if (payloadAttributes.getParentBeaconBlockRoot() != null) {

if (payloadAttributes.getParentBeaconBlockRoot() != null) {
LOG.error(
"Parent beacon block root hash present in payload attributes before cancun hardfork");
"Parent beacon block root hash present in payload attributes before Cancun hardfork");
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
} else {
return Optional.empty();
}

return Optional.empty();
}

@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
if (cancunMilestone.isPresent() && blockTimestamp >= cancunMilestone.get()) {
return ValidationResult.invalid(RpcErrorType.UNSUPPORTED_FORK);
}

return ValidationResult.valid();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;

import static org.hyperledger.besu.ethereum.mainnet.HardforkId.MainnetHardforkId.CANCUN;

import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
Expand All @@ -22,7 +24,6 @@
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.ScheduledProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;

import java.util.Optional;
Expand All @@ -33,7 +34,6 @@

public class EngineForkchoiceUpdatedV3 extends AbstractEngineForkchoiceUpdated {

private final Optional<ScheduledProtocolSpec.Hardfork> supportedHardFork;
private static final Logger LOG = LoggerFactory.getLogger(EngineForkchoiceUpdatedV3.class);

public EngineForkchoiceUpdatedV3(
Expand All @@ -43,11 +43,6 @@ public EngineForkchoiceUpdatedV3(
final MergeMiningCoordinator mergeCoordinator,
final EngineCallListener engineCallListener) {
super(vertx, protocolSchedule, protocolContext, mergeCoordinator, engineCallListener);
this.supportedHardFork =
protocolSchedule.hardforkFor(
s ->
s.fork().name().equalsIgnoreCase("Cancun")
|| s.fork().name().equalsIgnoreCase("Prague"));
}

@Override
Expand Down Expand Up @@ -80,18 +75,7 @@ protected ValidationResult<RpcErrorType> validateParameter(

@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
if (protocolSchedule.isPresent()) {
if (supportedHardFork.isPresent() && blockTimestamp >= supportedHardFork.get().milestone()) {
return ValidationResult.valid();
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK,
"Cancun configured to start at timestamp: " + supportedHardFork.get().milestone());
}
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK, "Configuration error, no schedule for Cancun fork set");
}
return ForkSupportHelper.validateForkSupported(CANCUN, cancunMilestone, blockTimestamp);
}

@Override
Expand All @@ -101,12 +85,16 @@ protected Optional<JsonRpcErrorResponse> isPayloadAttributesValid(
LOG.error(
"Parent beacon block root hash not present in payload attributes after cancun hardfork");
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
} else if (payloadAttributes.getTimestamp().longValue() == 0) {
}

if (payloadAttributes.getTimestamp() == 0) {
return Optional.of(new JsonRpcErrorResponse(requestId, getInvalidPayloadAttributesError()));
} else if (payloadAttributes.getTimestamp() < supportedHardFork.get().milestone()) {
}

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

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;

import static org.hyperledger.besu.ethereum.mainnet.HardforkId.MainnetHardforkId.CANCUN;

import org.hyperledger.besu.consensus.merge.PayloadWrapper;
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.ethereum.ProtocolContext;
Expand All @@ -24,7 +26,6 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;

import java.util.Optional;
Expand All @@ -33,7 +34,7 @@

public class EngineGetPayloadV2 extends AbstractEngineGetPayload {

private final Optional<ScheduledProtocolSpec.Hardfork> cancun;
private final Optional<Long> cancunMilestone;

public EngineGetPayloadV2(
final Vertx vertx,
Expand All @@ -49,7 +50,7 @@ public EngineGetPayloadV2(
mergeMiningCoordinator,
blockResultFactory,
engineCallListener);
this.cancun = schedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun"));
cancunMilestone = schedule.milestoneFor(CANCUN);
}

@Override
Expand All @@ -67,20 +68,10 @@ protected JsonRpcResponse createResponse(

@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
if (protocolSchedule.isPresent()) {
if (cancun.isPresent() && blockTimestamp >= cancun.get().milestone()) {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK,
"Cancun configured to start at timestamp: "
+ cancun.get().milestone()
+ " please call engine_getPayloadV3");
} else {
return ValidationResult.valid();
}
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK,
"Configuration error, no schedule for Cancun fork set, not sure when to stop honoring use of V2");
if (cancunMilestone.isPresent() && blockTimestamp >= cancunMilestone.get()) {
return ValidationResult.invalid(RpcErrorType.UNSUPPORTED_FORK);
}

return ValidationResult.valid();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;

import static org.hyperledger.besu.ethereum.mainnet.HardforkId.MainnetHardforkId.CANCUN;

import org.hyperledger.besu.consensus.merge.PayloadWrapper;
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.ethereum.ProtocolContext;
Expand All @@ -24,7 +26,6 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;

import java.util.Optional;
Expand All @@ -33,7 +34,7 @@

public class EngineGetPayloadV3 extends AbstractEngineGetPayload {

private final Optional<ScheduledProtocolSpec.Hardfork> cancun;
private final Optional<Long> cancunMilestone;

public EngineGetPayloadV3(
final Vertx vertx,
Expand All @@ -49,7 +50,7 @@ public EngineGetPayloadV3(
mergeMiningCoordinator,
blockResultFactory,
engineCallListener);
this.cancun = schedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Cancun"));
cancunMilestone = schedule.milestoneFor(CANCUN);
}

@Override
Expand All @@ -67,17 +68,6 @@ protected JsonRpcResponse createResponse(

@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
if (protocolSchedule.isPresent()) {
if (cancun.isPresent() && blockTimestamp >= cancun.get().milestone()) {
return ValidationResult.valid();
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK,
"Cancun configured to start at timestamp: " + cancun.get().milestone());
}
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK, "Configuration error, no schedule for Cancun fork set");
}
return ForkSupportHelper.validateForkSupported(CANCUN, cancunMilestone, blockTimestamp);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;

import static org.hyperledger.besu.ethereum.mainnet.HardforkId.MainnetHardforkId.PRAGUE;

import org.hyperledger.besu.consensus.merge.PayloadWrapper;
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.ethereum.ProtocolContext;
Expand All @@ -24,7 +26,6 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.BlockResultFactory;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;

import java.util.Optional;
Expand All @@ -33,7 +34,7 @@

public class EngineGetPayloadV4 extends AbstractEngineGetPayload {

private final Optional<ScheduledProtocolSpec.Hardfork> prague;
private final Optional<Long> pragueMilestone;

public EngineGetPayloadV4(
final Vertx vertx,
Expand All @@ -49,7 +50,7 @@ public EngineGetPayloadV4(
mergeMiningCoordinator,
blockResultFactory,
engineCallListener);
this.prague = schedule.hardforkFor(s -> s.fork().name().equalsIgnoreCase("Prague"));
pragueMilestone = schedule.milestoneFor(PRAGUE);
}

@Override
Expand All @@ -67,17 +68,6 @@ protected JsonRpcResponse createResponse(

@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
if (protocolSchedule.isPresent()) {
if (prague.isPresent() && blockTimestamp >= prague.get().milestone()) {
return ValidationResult.valid();
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK,
"Prague configured to start at timestamp: " + prague.get().milestone());
}
} else {
return ValidationResult.invalid(
RpcErrorType.UNSUPPORTED_FORK, "Configuration error, no schedule for Prague fork set");
}
return ForkSupportHelper.validateForkSupported(PRAGUE, pragueMilestone, blockTimestamp);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;

import static org.hyperledger.besu.ethereum.mainnet.HardforkId.MainnetHardforkId.CANCUN;

import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.ethereum.ProtocolContext;
Expand All @@ -33,6 +35,7 @@
import io.vertx.core.Vertx;

public class EngineNewPayloadV2 extends AbstractEngineNewPayload {
private final Optional<Long> cancunMilestone;

public EngineNewPayloadV2(
final Vertx vertx,
Expand All @@ -42,6 +45,7 @@ public EngineNewPayloadV2(
final EthPeers ethPeers,
final EngineCallListener engineCallListener) {
super(vertx, protocolSchedule, protocolContext, mergeCoordinator, ethPeers, engineCallListener);
cancunMilestone = protocolSchedule.milestoneFor(CANCUN);
}

@Override
Expand Down Expand Up @@ -74,4 +78,13 @@ protected ValidationResult<RpcErrorType> validateBlobs(
final ProtocolSpec protocolSpec) {
return ValidationResult.valid();
}

@Override
protected ValidationResult<RpcErrorType> validateForkSupported(final long blockTimestamp) {
if (cancunMilestone.isPresent() && blockTimestamp >= cancunMilestone.get()) {
return ValidationResult.invalid(RpcErrorType.UNSUPPORTED_FORK);
}

return ValidationResult.valid();
}
}
Loading

0 comments on commit 2158a68

Please sign in to comment.