diff --git a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V4.cs b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V4.cs index f480e135dd5..16c80668503 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V4.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V4.cs @@ -200,6 +200,39 @@ public async Task NewPayloadV4_reject_payload_with_bad_authorization_list_rlp() Assert.That(response.Data.Status, Is.EqualTo("INVALID")); } + [Test] + public async Task NewPayloadV4_reject_payload_with_bad_execution_requests() + { + ExecutionRequestsProcessorMock executionRequestsProcessorMock = new(); + using MergeTestBlockchain chain = await CreateBlockchain(Prague.Instance, null, null, null, executionRequestsProcessorMock); + IEngineRpcModule rpc = CreateEngineModule(chain); + Hash256 lastHash = (await ProduceBranchV4(rpc, chain, 10, CreateParentBlockRequestOnHead(chain.BlockTree), true, withRequests: true)) + .LastOrDefault()?.BlockHash ?? Keccak.Zero; + + Block TestBlock = Build.A.Block.WithNumber(chain.BlockTree.Head!.Number + 1).TestObject; + ExecutionPayloadV3 executionPayload = ExecutionPayloadV3.Create(TestBlock); + + // must reject if execution requests types are not in ascending order + var response = await rpc.engine_newPayloadV4( + executionPayload, + [], + TestBlock.ParentBeaconBlockRoot, + executionRequests: [Bytes.FromHexString("0x0001"), Bytes.FromHexString("0x0101"), Bytes.FromHexString("0x0101")] + ); + + Assert.That(response.ErrorCode, Is.EqualTo(ErrorCodes.InvalidParams)); + + //must reject if one of the execution requests size is <= 1 byte + response = await rpc.engine_newPayloadV4( + executionPayload, + [], + TestBlock.ParentBeaconBlockRoot, + executionRequests: [Bytes.FromHexString("0x0001"), Bytes.FromHexString("0x01"), Bytes.FromHexString("0x0101")] + ); + + Assert.That(response.ErrorCode, Is.EqualTo(ErrorCodes.InvalidParams)); + } + [TestCase(30)] public async Task can_progress_chain_one_by_one_v4(int count) { @@ -247,7 +280,7 @@ private async Task> ProduceBranchV4(IEngineRpcMo ExecutionPayloadV3? getPayloadResult = await BuildAndGetPayloadOnBranchV4(rpc, chain, parentHeader, parentBlock.Timestamp + 12, random ?? TestItem.KeccakA, Address.Zero); - PayloadStatusV1 payloadStatusResponse = (await rpc.engine_newPayloadV4(getPayloadResult, [], Keccak.Zero, executionRequests: withRequests ? ExecutionRequestsProcessorMock.Requests : new byte[][] { [], [], [] })).Data; + PayloadStatusV1 payloadStatusResponse = (await rpc.engine_newPayloadV4(getPayloadResult, [], Keccak.Zero, executionRequests: withRequests ? ExecutionRequestsProcessorMock.Requests : new byte[][] { })).Data; payloadStatusResponse.Status.Should().Be(PayloadStatus.Valid); if (setHead) { diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs index 87860936d86..41e6f931b3f 100644 --- a/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs +++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs @@ -51,7 +51,23 @@ public ValidationResult ValidateParams(IReleaseSpec spec, int version, out strin if (ExecutionRequests.Length > ExecutionRequestExtensions.MaxRequestsCount) { error = $"Execution requests must have less than {ExecutionRequestExtensions.MaxRequestsCount} items"; - return ValidationResult.Invalid; + return ValidationResult.Fail; + } + + // verification of the requests + for (int i = 0; i < ExecutionRequests.Length; i++) + { + if (ExecutionRequests[i] == null || ExecutionRequests[i].Length <= 1) + { + error = "Execution request data must be longer than 1 byte"; + return ValidationResult.Fail; + } + + if (i > 0 && ExecutionRequests[i][0] <= ExecutionRequests[i - 1][0]) + { + error = "Execution requests must not contain duplicates and be ordered by request_type in ascending order"; + return ValidationResult.Fail; + } } }