mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 21:17:54 -05:00
Shanghai Engine API Updates (#4945)
Update engine API to include some new changes introduced in - https://github.com/ethereum/execution-apis/pull/338 - https://github.com/ethereum/execution-apis/pull/337 Signed-off-by: Simon Dudley <simon.dudley@consensys.net> Signed-off-by: Zhenyang Shi <wcgcyx@gmail.com> Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
This commit is contained in:
@@ -119,7 +119,8 @@ public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJso
|
||||
}
|
||||
|
||||
// TODO: post-merge cleanup, this should be unnecessary after merge
|
||||
if (!mergeContext.get().isCheckpointPostMergeSync()
|
||||
if (requireTerminalPoWBlockValidation()
|
||||
&& !mergeContext.get().isCheckpointPostMergeSync()
|
||||
&& !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newHead)
|
||||
&& !mergeContext.get().isChainPruningEnabled()) {
|
||||
logForkchoiceUpdatedCall(INVALID, forkChoice);
|
||||
@@ -154,7 +155,7 @@ public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJso
|
||||
"Invalid payload attributes: {}",
|
||||
() ->
|
||||
maybePayloadAttributes.map(EnginePayloadAttributesParameter::serialize).orElse(null));
|
||||
return new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES);
|
||||
return new JsonRpcErrorResponse(requestId, getInvalidPayloadError());
|
||||
}
|
||||
|
||||
if (!result.isValid()) {
|
||||
@@ -217,9 +218,6 @@ public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJso
|
||||
new EngineUpdateForkchoiceResult(
|
||||
INVALID, latestValid.orElse(null), null, result.getErrorMessage()));
|
||||
break;
|
||||
case INVALID_PAYLOAD_ATTRIBUTES:
|
||||
response = new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES);
|
||||
break;
|
||||
case IGNORE_UPDATE_TO_OLD_HEAD:
|
||||
response =
|
||||
new JsonRpcSuccessResponse(
|
||||
@@ -300,6 +298,14 @@ public abstract class AbstractEngineForkchoiceUpdated extends ExecutionEngineJso
|
||||
requestId, new EngineUpdateForkchoiceResult(SYNCING, null, null, Optional.empty()));
|
||||
}
|
||||
|
||||
protected boolean requireTerminalPoWBlockValidation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected JsonRpcError getInvalidPayloadError() {
|
||||
return JsonRpcError.INVALID_PARAMS;
|
||||
}
|
||||
|
||||
// fcU calls are synchronous, no need to make volatile
|
||||
private long lastFcuInfoLog = System.currentTimeMillis();
|
||||
private static final String logMessage =
|
||||
|
||||
@@ -165,7 +165,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
||||
"Computed block hash %s does not match block hash parameter %s",
|
||||
newBlockHeader.getBlockHash(), blockParam.getBlockHash());
|
||||
LOG.debug(errorMessage);
|
||||
return respondWithInvalid(reqId, blockParam, null, INVALID_BLOCK_HASH, errorMessage);
|
||||
return respondWithInvalid(reqId, blockParam, null, getInvalidBlockHashStatus(), errorMessage);
|
||||
}
|
||||
// do we already have this payload
|
||||
if (protocolContext.getBlockchain().getBlockByHash(newBlockHeader.getBlockHash()).isPresent()) {
|
||||
@@ -208,7 +208,8 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
||||
}
|
||||
|
||||
// TODO: post-merge cleanup
|
||||
if (!mergeContext.get().isCheckpointPostMergeSync()
|
||||
if (requireTerminalPoWBlockValidation()
|
||||
&& !mergeContext.get().isCheckpointPostMergeSync()
|
||||
&& !mergeCoordinator.latestValidAncestorDescendsFromTerminal(newBlockHeader)
|
||||
&& !mergeContext.get().isChainPruningEnabled()) {
|
||||
mergeCoordinator.addBadBlock(block, Optional.empty());
|
||||
@@ -308,6 +309,14 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet
|
||||
invalidStatus, latestValidHash, Optional.of(validationError)));
|
||||
}
|
||||
|
||||
protected boolean requireTerminalPoWBlockValidation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected EngineStatus getInvalidBlockHashStatus() {
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
private void logImportedBlockInfo(final Block block, final double timeInS) {
|
||||
LOG.info(
|
||||
String.format(
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
|
||||
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.response.JsonRpcError;
|
||||
import org.hyperledger.besu.ethereum.mainnet.TimestampSchedule;
|
||||
|
||||
import io.vertx.core.Vertx;
|
||||
@@ -36,4 +37,14 @@ public class EngineForkchoiceUpdatedV1 extends AbstractEngineForkchoiceUpdated {
|
||||
public String getName() {
|
||||
return RpcMethod.ENGINE_FORKCHOICE_UPDATED_V1.getMethodName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requireTerminalPoWBlockValidation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonRpcError getInvalidPayloadError() {
|
||||
return JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
|
||||
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID_BLOCK_HASH;
|
||||
|
||||
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
|
||||
import org.hyperledger.besu.ethereum.ProtocolContext;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
||||
@@ -39,4 +41,14 @@ public class EngineNewPayloadV1 extends AbstractEngineNewPayload {
|
||||
public String getName() {
|
||||
return RpcMethod.ENGINE_NEW_PAYLOAD_V1.getMethodName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requireTerminalPoWBlockValidation() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EngineStatus getInvalidBlockHashStatus() {
|
||||
return INVALID_BLOCK_HASH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
private static final EngineForkchoiceUpdatedParameter mockFcuParam =
|
||||
new EngineForkchoiceUpdatedParameter(mockHash, mockHash, mockHash);
|
||||
|
||||
private static final BlockHeaderTestFixture blockHeaderBuilder =
|
||||
protected static final BlockHeaderTestFixture blockHeaderBuilder =
|
||||
new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE);
|
||||
|
||||
@Mock private ProtocolSpec protocolSpec;
|
||||
@@ -104,7 +104,7 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
|
||||
@Mock private MergeContext mergeContext;
|
||||
|
||||
@Mock private MergeMiningCoordinator mergeCoordinator;
|
||||
@Mock protected MergeMiningCoordinator mergeCoordinator;
|
||||
|
||||
@Mock private MutableBlockchain blockchain;
|
||||
|
||||
@@ -138,21 +138,6 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
mockFcuParam, Optional.empty(), mock(ForkchoiceResult.class), SYNCING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnInvalidOnBadTerminalBlock() {
|
||||
BlockHeader mockHeader = blockHeaderBuilder.buildHeader();
|
||||
|
||||
when(mergeCoordinator.getOrSyncHeadByHash(mockHeader.getHash(), Hash.ZERO))
|
||||
.thenReturn(Optional.of(mockHeader));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(false);
|
||||
assertSuccessWithPayloadForForkchoiceResult(
|
||||
new EngineForkchoiceUpdatedParameter(mockHeader.getHash(), Hash.ZERO, Hash.ZERO),
|
||||
Optional.empty(),
|
||||
mock(ForkchoiceResult.class),
|
||||
INVALID,
|
||||
Optional.of(Hash.ZERO));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnInvalidWithLatestValidHashOnBadBlock() {
|
||||
BlockHeader mockHeader = blockHeaderBuilder.buildHeader();
|
||||
@@ -181,7 +166,9 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
BlockHeader mockHeader = blockHeaderBuilder.buildHeader();
|
||||
when(mergeCoordinator.getOrSyncHeadByHash(mockHeader.getHash(), Hash.ZERO))
|
||||
.thenReturn(Optional.of(mockHeader));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
}
|
||||
|
||||
assertSuccessWithPayloadForForkchoiceResult(
|
||||
new EngineForkchoiceUpdatedParameter(mockHeader.getHash(), Hash.ZERO, Hash.ZERO),
|
||||
@@ -199,7 +186,9 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
.timestamp(parent.getTimestamp())
|
||||
.buildHeader();
|
||||
when(blockchain.getBlockHeader(parent.getHash())).thenReturn(Optional.of(parent));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
}
|
||||
when(mergeCoordinator.isDescendantOf(any(), any())).thenReturn(true);
|
||||
when(mergeContext.isSyncing()).thenReturn(false);
|
||||
when(mergeCoordinator.getOrSyncHeadByHash(mockHeader.getHash(), parent.getHash()))
|
||||
@@ -244,7 +233,9 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
BlockHeader mockHeader = blockHeaderBuilder.buildHeader();
|
||||
when(mergeCoordinator.getOrSyncHeadByHash(mockHeader.getHash(), Hash.ZERO))
|
||||
.thenReturn(Optional.of(mockHeader));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
}
|
||||
|
||||
var payloadParams =
|
||||
new EnginePayloadAttributesParameter(
|
||||
@@ -427,7 +418,9 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
|
||||
when(mergeCoordinator.getOrSyncHeadByHash(mockHeader.getHash(), Hash.ZERO))
|
||||
.thenReturn(Optional.of(mockHeader));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
}
|
||||
|
||||
var ignoreOldHeadUpdateRes = ForkchoiceResult.withIgnoreUpdateToOldHead(mockHeader);
|
||||
when(mergeCoordinator.updateForkChoice(any(), any(), any())).thenReturn(ignoreOldHeadUpdateRes);
|
||||
@@ -481,7 +474,7 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
mockHeader.getHash(), Hash.ZERO, mockParent.getHash()),
|
||||
Optional.of(payloadParams));
|
||||
|
||||
assertInvalidForkchoiceState(resp, JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES);
|
||||
assertInvalidForkchoiceState(resp, expectedInvalidPayloadError());
|
||||
verify(engineCallListener, times(1)).executionEngineCalled();
|
||||
}
|
||||
|
||||
@@ -505,7 +498,7 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
mockHeader.getHash(), Hash.ZERO, mockParent.getHash()),
|
||||
Optional.of(payloadParams));
|
||||
|
||||
assertInvalidForkchoiceState(resp, JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES);
|
||||
assertInvalidForkchoiceState(resp, expectedInvalidPayloadError());
|
||||
verify(engineCallListener, times(1)).executionEngineCalled();
|
||||
}
|
||||
|
||||
@@ -569,7 +562,7 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
mockHeader.getHash(), Hash.ZERO, mockParent.getHash()),
|
||||
Optional.of(payloadParams));
|
||||
|
||||
assertInvalidForkchoiceState(resp, JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES);
|
||||
assertInvalidForkchoiceState(resp, expectedInvalidPayloadError());
|
||||
verify(engineCallListener, times(1)).executionEngineCalled();
|
||||
}
|
||||
|
||||
@@ -667,7 +660,9 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
when(blockchain.getBlockHeader(any())).thenReturn(Optional.of(mockHeader));
|
||||
when(mergeCoordinator.getOrSyncHeadByHash(mockHeader.getHash(), Hash.ZERO))
|
||||
.thenReturn(Optional.of(mockHeader));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(true);
|
||||
}
|
||||
when(mergeCoordinator.isDescendantOf(any(), any())).thenReturn(true);
|
||||
}
|
||||
|
||||
@@ -680,7 +675,7 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
fcuParam, payloadParam, forkchoiceResult, expectedStatus, Optional.empty());
|
||||
}
|
||||
|
||||
private EngineUpdateForkchoiceResult assertSuccessWithPayloadForForkchoiceResult(
|
||||
protected EngineUpdateForkchoiceResult assertSuccessWithPayloadForForkchoiceResult(
|
||||
final EngineForkchoiceUpdatedParameter fcuParam,
|
||||
final Optional<EnginePayloadAttributesParameter> payloadParam,
|
||||
final ForkchoiceResult forkchoiceResult,
|
||||
@@ -724,6 +719,14 @@ public abstract class AbstractEngineForkchoiceUpdatedTest {
|
||||
return res;
|
||||
}
|
||||
|
||||
protected boolean validateTerminalPoWBlock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected JsonRpcError expectedInvalidPayloadError() {
|
||||
return JsonRpcError.INVALID_PARAMS;
|
||||
}
|
||||
|
||||
private JsonRpcResponse resp(
|
||||
final EngineForkchoiceUpdatedParameter forkchoiceParam,
|
||||
final Optional<EnginePayloadAttributesParameter> payloadParam) {
|
||||
|
||||
@@ -17,14 +17,12 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.ACCEPTED;
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID;
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID_BLOCK_HASH;
|
||||
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.parameters.WithdrawalParameterTestFixture.WITHDRAWAL_PARAM_1;
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError.INVALID_PARAMS;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
@@ -42,6 +40,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.EnginePayloadParameter;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.UnsignedLongParameter;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter;
|
||||
@@ -108,13 +107,13 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
|
||||
@Mock private MergeContext mergeContext;
|
||||
|
||||
@Mock private MergeMiningCoordinator mergeCoordinator;
|
||||
@Mock protected MergeMiningCoordinator mergeCoordinator;
|
||||
|
||||
@Mock private MutableBlockchain blockchain;
|
||||
@Mock protected MutableBlockchain blockchain;
|
||||
|
||||
@Mock private EthPeers ethPeers;
|
||||
|
||||
@Mock private EngineCallListener engineCallListener;
|
||||
@Mock protected EngineCallListener engineCallListener;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
@@ -169,8 +168,10 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
.thenReturn(Optional.of(mock(BlockHeader.class)));
|
||||
when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class)))
|
||||
.thenReturn(Optional.empty());
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(true);
|
||||
}
|
||||
|
||||
var resp = resp(mockPayload(mockHeader, Collections.emptyList()));
|
||||
|
||||
@@ -194,24 +195,6 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
assertValidResponse(mockHeader, resp);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnInvalidOnBadTerminalBlock() {
|
||||
BlockHeader mockHeader = createBlockHeader();
|
||||
when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty());
|
||||
when(blockchain.getBlockHeader(mockHeader.getParentHash()))
|
||||
.thenReturn(Optional.of(mock(BlockHeader.class)));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(false);
|
||||
|
||||
var resp = resp(mockPayload(mockHeader, Collections.emptyList()));
|
||||
|
||||
EnginePayloadStatusResult res = fromSuccessResp(resp);
|
||||
assertThat(res.getLatestValidHash()).isEqualTo(Optional.of(Hash.ZERO));
|
||||
assertThat(res.getStatusAsString()).isEqualTo(INVALID.name());
|
||||
verify(mergeCoordinator, atLeastOnce()).addBadBlock(any(), any());
|
||||
verify(engineCallListener, times(1)).executionEngineCalled();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnInvalidWithLatestValidHashIsABadBlock() {
|
||||
BlockHeader mockHeader = createBlockHeader();
|
||||
@@ -266,8 +249,10 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
.thenReturn(Optional.of(mock(BlockHeader.class)));
|
||||
when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class)))
|
||||
.thenReturn(Optional.of(mockHash));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(true);
|
||||
}
|
||||
when(mergeCoordinator.rememberBlock(any())).thenThrow(new MerkleTrieException("missing leaf"));
|
||||
|
||||
var resp = resp(mockPayload(mockHeader, Collections.emptyList()));
|
||||
@@ -286,7 +271,7 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
|
||||
EnginePayloadStatusResult res = fromSuccessResp(resp);
|
||||
assertThat(res.getLatestValidHash()).isEmpty();
|
||||
assertThat(res.getStatusAsString()).isEqualTo(INVALID_BLOCK_HASH.name());
|
||||
assertThat(res.getStatusAsString()).isEqualTo(getExpectedInvalidBlockHashStatus().name());
|
||||
verify(engineCallListener, times(1)).executionEngineCalled();
|
||||
}
|
||||
|
||||
@@ -300,7 +285,7 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
|
||||
EnginePayloadStatusResult res = fromSuccessResp(resp);
|
||||
assertThat(res.getLatestValidHash()).isEmpty();
|
||||
assertThat(res.getStatusAsString()).isEqualTo(INVALID_BLOCK_HASH.name());
|
||||
assertThat(res.getStatusAsString()).isEqualTo(getExpectedInvalidBlockHashStatus().name());
|
||||
verify(engineCallListener, times(1)).executionEngineCalled();
|
||||
}
|
||||
|
||||
@@ -468,14 +453,14 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
assertValidResponse(mockHeader, resp);
|
||||
}
|
||||
|
||||
private JsonRpcResponse resp(final EnginePayloadParameter payload) {
|
||||
protected JsonRpcResponse resp(final EnginePayloadParameter payload) {
|
||||
return method.response(
|
||||
new JsonRpcRequestContext(
|
||||
new JsonRpcRequest(
|
||||
"2.0", RpcMethod.ENGINE_EXECUTE_PAYLOAD.getMethodName(), new Object[] {payload})));
|
||||
}
|
||||
|
||||
private EnginePayloadParameter mockPayload(final BlockHeader header, final List<String> txs) {
|
||||
protected EnginePayloadParameter mockPayload(final BlockHeader header, final List<String> txs) {
|
||||
return new EnginePayloadParameter(
|
||||
header.getHash(),
|
||||
header.getParentHash(),
|
||||
@@ -524,13 +509,23 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
.thenReturn(Optional.of(mock(BlockHeader.class)));
|
||||
when(mergeCoordinator.getLatestValidAncestor(any(BlockHeader.class)))
|
||||
.thenReturn(Optional.of(mockHash));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(true);
|
||||
if (validateTerminalPoWBlock()) {
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(true);
|
||||
}
|
||||
when(mergeCoordinator.rememberBlock(any())).thenReturn(value);
|
||||
return mockHeader;
|
||||
}
|
||||
|
||||
private EnginePayloadStatusResult fromSuccessResp(final JsonRpcResponse resp) {
|
||||
protected boolean validateTerminalPoWBlock() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected ExecutionEngineJsonRpcMethod.EngineStatus getExpectedInvalidBlockHashStatus() {
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
protected EnginePayloadStatusResult fromSuccessResp(final JsonRpcResponse resp) {
|
||||
assertThat(resp.getType()).isEqualTo(JsonRpcResponseType.SUCCESS);
|
||||
return Optional.of(resp)
|
||||
.map(JsonRpcSuccessResponse.class::cast)
|
||||
@@ -547,7 +542,7 @@ public abstract class AbstractEngineNewPayloadTest {
|
||||
.get();
|
||||
}
|
||||
|
||||
private BlockHeader createBlockHeader() {
|
||||
protected BlockHeader createBlockHeader() {
|
||||
BlockHeader parentBlockHeader =
|
||||
new BlockHeaderTestFixture().baseFeePerGas(Wei.ONE).buildHeader();
|
||||
BlockHeader mockHeader =
|
||||
|
||||
@@ -15,8 +15,18 @@
|
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator;
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
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.response.JsonRpcError;
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -35,8 +45,33 @@ public class EngineForkchoiceUpdatedV1Test extends AbstractEngineForkchoiceUpdat
|
||||
assertThat(method.getName()).isEqualTo("engine_forkchoiceUpdatedV1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnInvalidOnBadTerminalBlock() {
|
||||
BlockHeader mockHeader = blockHeaderBuilder.buildHeader();
|
||||
|
||||
when(mergeCoordinator.getOrSyncHeadByHash(mockHeader.getHash(), Hash.ZERO))
|
||||
.thenReturn(Optional.of(mockHeader));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(mockHeader)).thenReturn(false);
|
||||
assertSuccessWithPayloadForForkchoiceResult(
|
||||
new EngineForkchoiceUpdatedParameter(mockHeader.getHash(), Hash.ZERO, Hash.ZERO),
|
||||
Optional.empty(),
|
||||
mock(MergeMiningCoordinator.ForkchoiceResult.class),
|
||||
INVALID,
|
||||
Optional.of(Hash.ZERO));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMethodName() {
|
||||
return RpcMethod.ENGINE_FORKCHOICE_UPDATED_V1.getMethodName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateTerminalPoWBlock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonRpcError expectedInvalidPayloadError() {
|
||||
return JsonRpcError.INVALID_PAYLOAD_ATTRIBUTES;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,22 @@
|
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.engine;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID;
|
||||
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod.EngineStatus.INVALID_BLOCK_HASH;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.ExecutionEngineJsonRpcMethod;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.EnginePayloadStatusResult;
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -32,4 +48,32 @@ public class EngineNewPayloadV1Test extends AbstractEngineNewPayloadTest {
|
||||
public void shouldReturnExpectedMethodName() {
|
||||
assertThat(method.getName()).isEqualTo("engine_newPayloadV1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnInvalidOnBadTerminalBlock() {
|
||||
BlockHeader mockHeader = createBlockHeader();
|
||||
when(blockchain.getBlockByHash(mockHeader.getHash())).thenReturn(Optional.empty());
|
||||
when(blockchain.getBlockHeader(mockHeader.getParentHash()))
|
||||
.thenReturn(Optional.of(mock(BlockHeader.class)));
|
||||
when(mergeCoordinator.latestValidAncestorDescendsFromTerminal(any(BlockHeader.class)))
|
||||
.thenReturn(false);
|
||||
|
||||
var resp = resp(mockPayload(mockHeader, Collections.emptyList()));
|
||||
|
||||
EnginePayloadStatusResult res = fromSuccessResp(resp);
|
||||
assertThat(res.getLatestValidHash()).isEqualTo(Optional.of(Hash.ZERO));
|
||||
assertThat(res.getStatusAsString()).isEqualTo(INVALID.name());
|
||||
verify(mergeCoordinator, atLeastOnce()).addBadBlock(any(), any());
|
||||
verify(engineCallListener, times(1)).executionEngineCalled();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateTerminalPoWBlock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExecutionEngineJsonRpcMethod.EngineStatus getExpectedInvalidBlockHashStatus() {
|
||||
return INVALID_BLOCK_HASH;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user