Skip to content

Commit f738577

Browse files
rjnrohitMarekM25ak88smartprogrammer93LukaszRozmej
authored
Exclude empty outputs in requests (#7720)
Co-authored-by: MarekM25 <[email protected]> Co-authored-by: ak88 <[email protected]> Co-authored-by: Ahmad Bitar <[email protected]> Co-authored-by: lukasz.rozmej <[email protected]> Co-authored-by: ak88 <[email protected]>
1 parent 3969858 commit f738577

File tree

6 files changed

+87
-56
lines changed

6 files changed

+87
-56
lines changed

src/Nethermind/Nethermind.Consensus/ExecutionRequests/ExecutionRequestProcessor.cs

+26-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
22
// SPDX-License-Identifier: LGPL-3.0-only
33

4+
45
using System;
56
using System.Collections.Generic;
67
using System.Linq;
@@ -54,12 +55,15 @@ public ExecutionRequestsProcessor(ITransactionProcessor transactionProcessor)
5455
_consolidationTransaction.Hash = _consolidationTransaction.CalculateHash();
5556
}
5657

57-
public byte[] ProcessDeposits(TxReceipt[] receipts, IReleaseSpec spec)
58+
public void ProcessDeposits(TxReceipt[] receipts, IReleaseSpec spec, ArrayPoolList<byte[]> requests)
5859
{
5960
if (!spec.DepositsEnabled)
60-
return [];
61+
return;
6162

62-
using ArrayPoolList<byte> depositRequests = new(receipts.Length * 2);
63+
using ArrayPoolList<byte> depositRequests = new(receipts.Length * 2 + 1)
64+
{
65+
(byte)ExecutionRequestType.Deposit
66+
};
6367

6468
for (int i = 0; i < receipts.Length; i++)
6569
{
@@ -79,7 +83,8 @@ public byte[] ProcessDeposits(TxReceipt[] receipts, IReleaseSpec spec)
7983
}
8084
}
8185

82-
return depositRequests.ToArray();
86+
if (depositRequests.Count > 1)
87+
requests.Add(depositRequests.ToArray());
8388
}
8489

8590
private void DecodeDepositRequest(LogEntry log, Span<byte> buffer)
@@ -107,34 +112,45 @@ private void DecodeDepositRequest(LogEntry log, Span<byte> buffer)
107112
}
108113
}
109114

110-
111-
private byte[] ReadRequests(Block block, IWorldState state, IReleaseSpec spec, Address contractAddress)
115+
private void ReadRequests(Block block, IWorldState state, IReleaseSpec spec, Address contractAddress, ArrayPoolList<byte[]> requests)
112116
{
113117
bool isWithdrawalRequests = contractAddress == spec.Eip7002ContractAddress;
114118

115119
int requestsByteSize = isWithdrawalRequests ? ExecutionRequestExtensions.WithdrawalRequestsBytesSize : ExecutionRequestExtensions.ConsolidationRequestsBytesSize;
116120

117121
if (!(isWithdrawalRequests ? spec.WithdrawalRequestsEnabled : spec.ConsolidationRequestsEnabled) || !state.AccountExists(contractAddress))
118-
return [];
122+
return;
119123

120124
CallOutputTracer tracer = new();
121125

122126
_transactionProcessor.Execute(isWithdrawalRequests ? _withdrawalTransaction : _consolidationTransaction, new BlockExecutionContext(block.Header), tracer);
123127

124128
if (tracer.ReturnValue is null || tracer.ReturnValue.Length == 0)
125129
{
126-
return [];
130+
return;
127131
}
128132

129133
int validLength = tracer.ReturnValue.Length - (tracer.ReturnValue.Length % requestsByteSize);
130-
return tracer.ReturnValue.AsSpan(0, validLength).ToArray();
134+
135+
if (validLength == 0) return;
136+
137+
Span<byte> buffer = stackalloc byte[validLength + 1];
138+
buffer[0] = isWithdrawalRequests ? (byte)ExecutionRequestType.WithdrawalRequest : (byte)ExecutionRequestType.ConsolidationRequest;
139+
tracer.ReturnValue.AsSpan(0, validLength).CopyTo(buffer.Slice(1));
140+
requests.Add(buffer.ToArray());
131141
}
132142

133143
public void ProcessExecutionRequests(Block block, IWorldState state, TxReceipt[] receipts, IReleaseSpec spec)
134144
{
135145
if (!spec.RequestsEnabled)
136146
return;
137-
block.ExecutionRequests = new byte[][] { ProcessDeposits(receipts, spec), ReadRequests(block, state, spec, spec.Eip7002ContractAddress), ReadRequests(block, state, spec, spec.Eip7251ContractAddress) };
147+
148+
using ArrayPoolList<byte[]> requests = new(3);
149+
150+
ProcessDeposits(receipts, spec, requests);
151+
ReadRequests(block, state, spec, spec.Eip7002ContractAddress, requests);
152+
ReadRequests(block, state, spec, spec.Eip7251ContractAddress, requests);
153+
block.ExecutionRequests = requests.ToArray();
138154
block.Header.RequestsHash = ExecutionRequestExtensions.CalculateHashFromFlatEncodedRequests(block.ExecutionRequests);
139155
}
140156
}

src/Nethermind/Nethermind.Core.Test/Builders/TestExecutionRequest.cs

+21-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
22
// SPDX-License-Identifier: LGPL-3.0-only
33

4-
using System;
54
using System.Linq;
65
using Nethermind.Core.Collections;
76
using Nethermind.Core.ExecutionRequest;
@@ -19,7 +18,7 @@ public byte[][]? RequestDataParts
1918
set
2019
{
2120
_requestDataParts = value;
22-
RequestData = value is null ? null : Bytes.Concat(value.AsSpan());
21+
RequestData = value is null ? null : Bytes.Concat(value);
2322
}
2423
}
2524
}
@@ -32,18 +31,30 @@ public static ArrayPoolList<byte[]> GetFlatEncodedRequests(
3231
TestExecutionRequest[] consolidationRequests
3332
)
3433
{
35-
return new(ExecutionRequestExtensions.RequestPartsCount)
34+
var result = new ArrayPoolList<byte[]>(ExecutionRequestExtensions.MaxRequestsCount);
35+
36+
if (depositRequests.Length > 0)
3637
{
37-
FlatEncodeRequests(depositRequests, depositRequests.Length * ExecutionRequestExtensions.DepositRequestsBytesSize),
38-
FlatEncodeRequests(withdrawalRequests, withdrawalRequests.Length * ExecutionRequestExtensions.WithdrawalRequestsBytesSize),
39-
FlatEncodeRequests(consolidationRequests, consolidationRequests.Length * ExecutionRequestExtensions.ConsolidationRequestsBytesSize)
40-
};
38+
result.Add(FlatEncodeRequests(depositRequests, depositRequests.Length * ExecutionRequestExtensions.DepositRequestsBytesSize, (byte)ExecutionRequestType.Deposit));
39+
}
40+
41+
if (withdrawalRequests.Length > 0)
42+
{
43+
result.Add(FlatEncodeRequests(withdrawalRequests, withdrawalRequests.Length * ExecutionRequestExtensions.WithdrawalRequestsBytesSize, (byte)ExecutionRequestType.WithdrawalRequest));
44+
}
45+
46+
if (consolidationRequests.Length > 0)
47+
{
48+
result.Add(FlatEncodeRequests(consolidationRequests, consolidationRequests.Length * ExecutionRequestExtensions.ConsolidationRequestsBytesSize, (byte)ExecutionRequestType.ConsolidationRequest));
49+
}
50+
51+
return result;
4152

42-
static byte[] FlatEncodeRequests(TestExecutionRequest[] requests, int bufferSize)
53+
static byte[] FlatEncodeRequests(ExecutionRequest.ExecutionRequest[] requests, int bufferSize, byte type)
4354
{
44-
using ArrayPoolList<byte> buffer = new(bufferSize);
55+
using ArrayPoolList<byte> buffer = new(bufferSize + 1) { type };
4556

46-
foreach (TestExecutionRequest request in requests)
57+
foreach (ExecutionRequest.ExecutionRequest request in requests)
4758
{
4859
buffer.AddRange(request.RequestData!);
4960
}

src/Nethermind/Nethermind.Core/ExecutionRequest/ExecutionRequestExtensions.cs

+30-26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
22
// SPDX-License-Identifier: LGPL-3.0-only
33

4-
54
using System;
65
using System.Buffers;
76
using System.Collections.Generic;
@@ -18,11 +17,11 @@ public static class ExecutionRequestExtensions
1817
public const int DepositRequestsBytesSize = PublicKeySize /*pubkey: Bytes48 */ + Hash256.Size /*withdrawal_credentials: Bytes32 */ + sizeof(ulong) /*amount: uint64*/ + 96 /*signature: Bytes96*/ + sizeof(ulong) /*index: uint64*/;
1918
public const int WithdrawalRequestsBytesSize = Address.Size + PublicKeySize /*validator_pubkey: Bytes48*/ + sizeof(ulong) /*amount: uint64*/;
2019
public const int ConsolidationRequestsBytesSize = Address.Size + PublicKeySize /*source_pubkey: Bytes48*/ + PublicKeySize /*target_pubkey: Bytes48*/;
21-
public const int RequestPartsCount = 3;
20+
public const int MaxRequestsCount = 3;
2221
private const int PublicKeySize = 48;
2322

24-
public static readonly byte[][] EmptyRequests = [[], [], []];
25-
public static readonly Hash256 EmptyRequestsHash = CalculateHashFromFlatEncodedRequests(EmptyRequests);
23+
public static byte[][] EmptyRequests = [];
24+
public static Hash256 EmptyRequestsHash = CalculateHashFromFlatEncodedRequests(EmptyRequests);
2625

2726
public static int GetRequestsByteSize(this IEnumerable<ExecutionRequest> requests)
2827
{
@@ -37,29 +36,22 @@ public static int GetRequestsByteSize(this IEnumerable<ExecutionRequest> request
3736
[SkipLocalsInit]
3837
public static Hash256 CalculateHashFromFlatEncodedRequests(byte[][]? flatEncodedRequests)
3938
{
40-
// make sure that length is exactly 3
41-
if (flatEncodedRequests is null || flatEncodedRequests.Length != RequestPartsCount)
39+
// make sure that length is 3 or less elements
40+
if (flatEncodedRequests is null || flatEncodedRequests.Length > MaxRequestsCount)
4241
{
43-
throw new ArgumentException("Flat encoded requests must be an array of 3 elements");
42+
throw new ArgumentException("Flat encoded requests must be an array of 3 or less elements");
4443
}
4544

46-
byte[] concatenatedHashes = new byte[Hash256.Size * RequestPartsCount];
47-
int currentPosition = 0;
48-
byte type = 0;
49-
// Allocate the buffer once outside the loop
50-
Span<byte> requestBuffer = stackalloc byte[Math.Max(Math.Max(flatEncodedRequests[0].Length, flatEncodedRequests[1].Length), flatEncodedRequests[2].Length) + 1];
51-
// Compute sha256 for each request and concatenate them
45+
using SHA256 sha256 = SHA256.Create();
46+
using ArrayPoolList<byte> concatenatedHashes = new(Hash256.Size * MaxRequestsCount);
5247
foreach (byte[] requests in flatEncodedRequests)
5348
{
54-
requestBuffer[0] = type;
55-
requests.CopyTo(requestBuffer.Slice(1, requests.Length));
56-
SHA256.HashData(requestBuffer[..(requests.Length + 1)]).CopyTo(concatenatedHashes.AsSpan(currentPosition, Hash256.Size));
57-
currentPosition += Hash256.Size;
58-
type++;
49+
if (requests.Length <= 1) continue;
50+
concatenatedHashes.AddRange(sha256.ComputeHash(requests));
5951
}
6052

6153
// Compute sha256 of the concatenated hashes
62-
return new Hash256(SHA256.HashData(concatenatedHashes));
54+
return new Hash256(sha256.ComputeHash(concatenatedHashes.ToArray()));
6355
}
6456

6557

@@ -70,16 +62,28 @@ public static ArrayPoolList<byte[]> GetFlatEncodedRequests(
7062
ExecutionRequest[] consolidationRequests
7163
)
7264
{
73-
return new(RequestPartsCount)
65+
var result = new ArrayPoolList<byte[]>(MaxRequestsCount);
66+
67+
if (depositRequests.Length > 0)
68+
{
69+
result.Add(FlatEncodeRequests(depositRequests, depositRequests.Length * DepositRequestsBytesSize, (byte)ExecutionRequestType.Deposit));
70+
}
71+
72+
if (withdrawalRequests.Length > 0)
7473
{
75-
FlatEncodeRequests(depositRequests, depositRequests.Length * DepositRequestsBytesSize),
76-
FlatEncodeRequests(withdrawalRequests, withdrawalRequests.Length * WithdrawalRequestsBytesSize),
77-
FlatEncodeRequests(consolidationRequests, consolidationRequests.Length * ConsolidationRequestsBytesSize)
78-
};
74+
result.Add(FlatEncodeRequests(withdrawalRequests, withdrawalRequests.Length * WithdrawalRequestsBytesSize, (byte)ExecutionRequestType.WithdrawalRequest));
75+
}
76+
77+
if (consolidationRequests.Length > 0)
78+
{
79+
result.Add(FlatEncodeRequests(consolidationRequests, consolidationRequests.Length * ConsolidationRequestsBytesSize, (byte)ExecutionRequestType.ConsolidationRequest));
80+
}
81+
82+
return result;
7983

80-
static byte[] FlatEncodeRequests(ExecutionRequest[] requests, int bufferSize)
84+
static byte[] FlatEncodeRequests(ExecutionRequest[] requests, int bufferSize, byte type)
8185
{
82-
using ArrayPoolList<byte> buffer = new(bufferSize);
86+
using ArrayPoolList<byte> buffer = new(bufferSize + 1) { type };
8387

8488
foreach (ExecutionRequest request in requests)
8589
{

src/Nethermind/Nethermind.Merge.AuRa.Test/AuRaMergeEngineModuleTests.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ int ErrorCode
6464
=> base.forkchoiceUpdatedV2_should_validate_withdrawals(input);
6565

6666
[TestCase(
67-
"0xd25128557a58fe7bb6346d779cfc86a1f5bd9bff4786a118097aebdf3128f46d",
68-
"0xcbf0d15de352e744aba609aca74846ede5fc3ffd00ca506914b498b00470cbf8",
67+
"0x1270af16dfea9b40aa9381529cb2629008fea35386041f52c07034ea8c038a05",
68+
"0xea3bdca86662fa8b5399f2c3ff494ced747f07834740ead723ebe023852e9ea1",
6969
"0xd75d320c3a98a02ec7fe2abdcb1769bd063fec04d73f1735810f365ac12bc4ba",
70-
"0xc9763e9904d3fe5b")]
70+
"0x7389011914b1ca84")]
7171
public override Task Should_process_block_as_expected_V4(string latestValidHash, string blockHash, string stateRoot, string payloadId)
7272
=> base.Should_process_block_as_expected_V4(latestValidHash, blockHash, stateRoot, payloadId);
7373

src/Nethermind/Nethermind.Merge.Plugin.Test/EngineModuleTests.V4.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ namespace Nethermind.Merge.Plugin.Test;
2424
public partial class EngineModuleTests
2525
{
2626
[TestCase(
27-
"0xd7e58364f16b4a329b959b166f9c32323cb135669335db5dadd0344568f8dc9a",
28-
"0xfafb92e8ece12d5fcfa867df9ae6865c5bd8aaf0b277c244552bfe869f61fb26",
27+
"0x9233c931ff3c17ae124b9aa2ca8db1c641a2dd87fa2d7e00030b274bcc33f928",
28+
"0xe97fdbfa2fcf60073d9579d87b127cdbeffbe6c7387b9e1e836eb7f8fb2d9548",
2929
"0xa272b2f949e4a0e411c9b45542bd5d0ef3c311b5f26c4ed6b7a8d4f605a91154",
30-
"0x774c6aff527bbc68")]
30+
"0x2fc07c25edadc149")]
3131
public virtual async Task Should_process_block_as_expected_V4(string latestValidHash, string blockHash,
3232
string stateRoot, string payloadId)
3333
{
@@ -108,7 +108,7 @@ public virtual async Task Should_process_block_as_expected_V4(string latestValid
108108
Array.Empty<Transaction>(),
109109
Array.Empty<BlockHeader>(),
110110
withdrawals);
111-
GetPayloadV4Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block), executionRequests: new byte[][] { [], [], [] });
111+
GetPayloadV4Result expectedPayload = new(block, UInt256.Zero, new BlobsBundleV1(block), executionRequests: []);
112112

113113
response = await RpcTest.TestSerializedRequest(rpc, "engine_getPayloadV4", expectedPayloadId);
114114
successResponse = chain.JsonSerializer.Deserialize<JsonRpcSuccessResponse>(response);
@@ -121,7 +121,7 @@ public virtual async Task Should_process_block_as_expected_V4(string latestValid
121121
}));
122122

123123
response = await RpcTest.TestSerializedRequest(rpc, "engine_newPayloadV4",
124-
chain.JsonSerializer.Serialize(ExecutionPayloadV3.Create(block)), "[]", Keccak.Zero.ToString(true), "[\"0x\",\"0x\",\"0x\"]");
124+
chain.JsonSerializer.Serialize(ExecutionPayloadV3.Create(block)), "[]", Keccak.Zero.ToString(true), "[]");
125125
successResponse = chain.JsonSerializer.Deserialize<JsonRpcSuccessResponse>(response);
126126

127127
successResponse.Should().NotBeNull();

src/Nethermind/Nethermind.Merge.Plugin/Data/IExecutionPayloadParams.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ public ValidationResult ValidateParams(IReleaseSpec spec, int version, out strin
4848
return ValidationResult.Fail;
4949
}
5050

51-
if (ExecutionRequests.Length != ExecutionRequestExtensions.RequestPartsCount)
51+
if (ExecutionRequests.Length > ExecutionRequestExtensions.MaxRequestsCount)
5252
{
53-
error = "Execution requests must have exactly three items";
53+
error = $"Execution requests must have less than {ExecutionRequestExtensions.MaxRequestsCount} items";
5454
return ValidationResult.Invalid;
5555
}
5656

0 commit comments

Comments
 (0)