Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flat encoding and requests as a side car #7608

Merged
merged 3 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,15 @@ public void Setup()
CallOutputTracer tracer = ci.Arg<CallOutputTracer>();
if (transaction.To == eip7002Account)
{
tracer.ReturnValue = executionWithdrawalRequests.FlatEncodeWithoutType();
Span<byte> buffer = new byte[executionWithdrawalRequests.GetRequestsByteSize()];
executionWithdrawalRequests.FlatEncodeWithoutType(buffer);
tracer.ReturnValue = buffer.ToArray();
}
else if (transaction.To == eip7251Account)
{
tracer.ReturnValue = executionConsolidationRequests.FlatEncodeWithoutType();
Span<byte> buffer = new byte[executionConsolidationRequests.GetRequestsByteSize()];
executionConsolidationRequests.FlatEncodeWithoutType(buffer);
tracer.ReturnValue = buffer.ToArray();
}
else
{
Expand Down Expand Up @@ -120,7 +124,7 @@ .. executionConsolidationRequests
]))
{
Assert.That(processedRequest.RequestType, Is.EqualTo(expectedRequest.RequestType));
Assert.That(processedRequest.RequestData, Is.EqualTo(expectedRequest.RequestData));
Assert.That(processedRequest.RequestData.ToArray(), Is.EqualTo(expectedRequest.RequestData.ToArray()));
}

Assert.That(block.Header.RequestsHash, Is.EqualTo(block.ExecutionRequests.ToArray().CalculateHash()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using Nethermind.Abi;
using Nethermind.Core;
using Nethermind.Core.Collections;
using Nethermind.Core.Crypto;
using Nethermind.Core.ExecutionRequest;
using Nethermind.Core.Extensions;
using Nethermind.Core.Specs;
Expand Down Expand Up @@ -130,50 +128,14 @@ private IEnumerable<ExecutionRequest> ReadRequests(Block block, IWorldState stat

}

public Hash256 CalculateRequestsHash(Block block, IWorldState state, TxReceipt[] receipts, IReleaseSpec spec, out ArrayPoolList<ExecutionRequest> requests)
{
ArrayPoolList<ExecutionRequest> requestsList = new ArrayPoolList<ExecutionRequest>(receipts.Length * 2);
using (SHA256 sha256 = SHA256.Create())
{
using (SHA256 sha256Inner = SHA256.Create())
{
foreach (ExecutionRequest request in ProcessDeposits(receipts, spec))
{
requestsList.AddRange(request);
byte[] requestHash = sha256Inner.ComputeHash(request.FlatEncode());

// Update the outer hash with the result of each inner hash
sha256.TransformBlock(requestHash, 0, requestHash.Length, null, 0);
}
foreach (ExecutionRequest request in ReadRequests(block, state, spec, spec.Eip7002ContractAddress))
{
requestsList.AddRange(request);
byte[] requestHash = sha256Inner.ComputeHash(request.FlatEncode());

sha256.TransformBlock(requestHash, 0, requestHash.Length, null, 0);
}

foreach (ExecutionRequest request in ReadRequests(block, state, spec, spec.Eip7251ContractAddress))
{
requestsList.AddRange(request);
byte[] requestHash = sha256Inner.ComputeHash(request.FlatEncode());

sha256.TransformBlock(requestHash, 0, requestHash.Length, null, 0);
}

// Complete the final hash computation
sha256.TransformFinalBlock(new byte[0], 0, 0);
requests = requestsList;
return new Hash256(sha256.Hash!);
}
}
}

public void ProcessExecutionRequests(Block block, IWorldState state, TxReceipt[] receipts, IReleaseSpec spec)
{
if (!spec.RequestsEnabled)
return;
block.Header.RequestsHash = CalculateRequestsHash(block, state, receipts, spec, out ArrayPoolList<ExecutionRequest> requests);
block.ExecutionRequests = requests;
IEnumerable<ExecutionRequest> requests = ProcessDeposits(receipts, spec)
.Concat(ReadRequests(block, state, spec, spec.Eip7002ContractAddress))
.Concat(ReadRequests(block, state, spec, spec.Eip7251ContractAddress));
block.Header.RequestsHash = requests.CalculateHash();
block.ExecutionRequests = requests.ToArray();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ public BlockBuilder WithReceiptsRoot(Hash256 keccak)
public BlockBuilder WithEmptyRequestsHash()
{
TestObjectInternal.Header.RequestsHash = Array.Empty<ExecutionRequest.ExecutionRequest>().CalculateHash();
TestObjectInternal.ExecutionRequests = new ArrayPoolList<ExecutionRequest.ExecutionRequest>(0);
TestObjectInternal.ExecutionRequests = Array.Empty<ExecutionRequest.ExecutionRequest>();
return this;
}

Expand Down
18 changes: 9 additions & 9 deletions src/Nethermind/Nethermind.Core.Test/Builders/TestItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ public static Hash256 KeccakFromNumber(int i)

public static byte[] SignatureBytes = [.. new Signature("0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac80388256084f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada1c").Bytes, .. KeccakA.Bytes];

public static ExecutionRequest.ExecutionRequest ExecutionRequestA = new() { RequestType = 0, RequestData = ([.. PublicKeyA.Bytes.Slice(0, 48), .. KeccakA.Bytes, .. (BitConverter.GetBytes((ulong)1_000_000_000)), .. SignatureBytes, .. BitConverter.GetBytes((ulong)1)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestB = new() { RequestType = 0, RequestData = ([.. PublicKeyB.Bytes.Slice(0, 48), .. KeccakB.Bytes, .. (BitConverter.GetBytes((ulong)2_000_000_000)), .. SignatureBytes, .. BitConverter.GetBytes((ulong)2)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestC = new() { RequestType = 0, RequestData = ([.. PublicKeyC.Bytes.Slice(0, 48), .. KeccakC.Bytes, .. (BitConverter.GetBytes((ulong)3_000_000_000)), .. SignatureBytes, .. BitConverter.GetBytes((ulong)3)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestD = new() { RequestType = 1, RequestData = ([.. AddressA.Bytes, .. PublicKeyA.Bytes.Slice(0, 48), .. (BitConverter.GetBytes((ulong)1_000_000_000))]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestE = new() { RequestType = 1, RequestData = ([.. AddressB.Bytes, .. PublicKeyB.Bytes.Slice(0, 48), .. (BitConverter.GetBytes((ulong)2_000_000_000))]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestF = new() { RequestType = 1, RequestData = ([.. AddressC.Bytes, .. PublicKeyC.Bytes.Slice(0, 48), .. (BitConverter.GetBytes((ulong)3_000_000_000))]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestG = new() { RequestType = 2, RequestData = ([.. AddressA.Bytes, .. PublicKeyA.Bytes.Slice(0, 48), .. PublicKeyB.Bytes.Slice(0, 48)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestH = new() { RequestType = 2, RequestData = ([.. AddressB.Bytes, .. PublicKeyB.Bytes.Slice(0, 48), .. PublicKeyC.Bytes.Slice(0, 48)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestI = new() { RequestType = 2, RequestData = ([.. AddressC.Bytes, .. PublicKeyC.Bytes.Slice(0, 48), .. PublicKeyA.Bytes.Slice(0, 48)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestA = new() { RequestType = 0, RequestData = (byte[])([.. PublicKeyA.Bytes.Slice(0, 48), .. KeccakA.Bytes, .. (BitConverter.GetBytes((ulong)1_000_000_000)), .. SignatureBytes, .. BitConverter.GetBytes((ulong)1)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestB = new() { RequestType = 0, RequestData = (byte[])([.. PublicKeyB.Bytes.Slice(0, 48), .. KeccakB.Bytes, .. (BitConverter.GetBytes((ulong)2_000_000_000)), .. SignatureBytes, .. BitConverter.GetBytes((ulong)2)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestC = new() { RequestType = 0, RequestData = (byte[])([.. PublicKeyC.Bytes.Slice(0, 48), .. KeccakC.Bytes, .. (BitConverter.GetBytes((ulong)3_000_000_000)), .. SignatureBytes, .. BitConverter.GetBytes((ulong)3)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestD = new() { RequestType = 1, RequestData = (byte[])([.. AddressA.Bytes, .. PublicKeyA.Bytes.Slice(0, 48), .. (BitConverter.GetBytes((ulong)1_000_000_000))]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestE = new() { RequestType = 1, RequestData = (byte[])([.. AddressB.Bytes, .. PublicKeyB.Bytes.Slice(0, 48), .. (BitConverter.GetBytes((ulong)2_000_000_000))]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestF = new() { RequestType = 1, RequestData = (byte[])([.. AddressC.Bytes, .. PublicKeyC.Bytes.Slice(0, 48), .. (BitConverter.GetBytes((ulong)3_000_000_000))]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestG = new() { RequestType = 2, RequestData = (byte[])([.. AddressA.Bytes, .. PublicKeyA.Bytes.Slice(0, 48), .. PublicKeyB.Bytes.Slice(0, 48)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestH = new() { RequestType = 2, RequestData = (byte[])([.. AddressB.Bytes, .. PublicKeyB.Bytes.Slice(0, 48), .. PublicKeyC.Bytes.Slice(0, 48)]) };
public static ExecutionRequest.ExecutionRequest ExecutionRequestI = new() { RequestType = 2, RequestData = (byte[])([.. AddressC.Bytes, .. PublicKeyC.Bytes.Slice(0, 48), .. PublicKeyA.Bytes.Slice(0, 48)]) };

public static IPEndPoint IPEndPointA = IPEndPoint.Parse("10.0.0.1");
public static IPEndPoint IPEndPointB = IPEndPoint.Parse("10.0.0.2");
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Core/Block.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public Transaction[] Transactions
public Hash256? RequestsHash => Header.RequestsHash; // do not add setter here

[JsonIgnore]
public ArrayPoolList<ExecutionRequest.ExecutionRequest>? ExecutionRequests { get; set; }
public ExecutionRequest.ExecutionRequest[]? ExecutionRequests { get; set; }

[JsonIgnore]
public ArrayPoolList<AddressAsKey>? AccountChanges { get; set; }
Expand Down
85 changes: 57 additions & 28 deletions src/Nethermind/Nethermind.Core/ExecutionRequest/ExecutionRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@

using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Security.Cryptography;
using System.Linq;
using System.Security.Cryptography;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;

Expand All @@ -24,60 +23,90 @@ public class ExecutionRequest
public byte RequestType { get; set; }
public byte[]? RequestData { get; set; }

public byte[] FlatEncode()
public void FlatEncode(Span<byte> buffer)
{
byte[] encoded = new byte[RequestData!.Length + 1];
encoded[0] = RequestType;
RequestData.CopyTo(encoded, 1);
return encoded;
if (buffer.Length < RequestData!.Length + 1)
throw new ArgumentException("Buffer too small");

buffer[0] = RequestType;
RequestData.CopyTo(buffer.Slice(1));
}

public override string ToString() => ToString(string.Empty);

public string ToString(string indentation) => @$"{indentation}{nameof(ExecutionRequest)}
{{{nameof(RequestType)}: {RequestType},
{nameof(RequestData)}: {RequestData?.ToHexString()}}}";
{nameof(RequestData)}: {RequestData!.ToHexString()}}}";
}

public static class ExecutionRequestExtensions
{
public static byte[] FlatEncode(this ExecutionRequest[] requests)
public static int GetRequestsByteSize(this IEnumerable<ExecutionRequest> requests)
{
List<byte> encoded = new();
int size = 0;
foreach (ExecutionRequest request in requests)
{
encoded.AddRange(request.FlatEncode());
size += request.RequestData!.Length + 1;
}
return encoded.ToArray();
return size;
}

public static byte[] FlatEncodeWithoutType(this ExecutionRequest[] requests)
public static void FlatEncode(this ExecutionRequest[] requests, Span<byte> buffer)
{
List<byte> encoded = new();
int currentPosition = 0;

foreach (ExecutionRequest request in requests)
{
encoded.AddRange(request.RequestData!);
Span<byte> internalBuffer = new byte[request.RequestData!.Length + 1];
request.FlatEncode(internalBuffer);

// Ensure the buffer has enough space to accommodate the new data
if (currentPosition + internalBuffer.Length > buffer.Length)
{
throw new InvalidOperationException("Buffer is not large enough to hold all data of requests");
}

// Copy the internalBuffer to the buffer at the current position
internalBuffer.CopyTo(buffer.Slice(currentPosition, internalBuffer.Length));
currentPosition += internalBuffer.Length;
}
return encoded.ToArray();
}

public static Hash256 CalculateHash(this ExecutionRequest[] requests)
public static void FlatEncodeWithoutType(this ExecutionRequest[] requests, Span<byte> buffer)
{
int currentPosition = 0;

foreach (ExecutionRequest request in requests)
{
// Ensure the buffer has enough space to accommodate the new data
if (currentPosition + request.RequestData!.Length > buffer.Length)
{
throw new InvalidOperationException("Buffer is not large enough to hold all data of requests");
}

// Copy the RequestData to the buffer at the current position
request.RequestData.CopyTo(buffer.Slice(currentPosition, request.RequestData.Length));
currentPosition += request.RequestData.Length;
}
}

public static Hash256 CalculateHash(this IEnumerable<ExecutionRequest> requests)
{
using (SHA256 sha256 = SHA256.Create())
{
using (SHA256 sha256Inner = SHA256.Create())
Span<byte> concatenatedHashes = new byte[32 * requests.Count()];
int currentPosition = 0;
// Compute sha256 for each request and concatenate them
foreach (ExecutionRequest request in requests)
{
foreach (ExecutionRequest request in requests)
{
byte[] requestHash = sha256Inner.ComputeHash(request.FlatEncode());

// Update the outer hash with the result of each inner hash
sha256.TransformBlock(requestHash, 0, requestHash.Length, null, 0);
}
// Complete the final hash computation
sha256.TransformFinalBlock(new byte[0], 0, 0);
return new Hash256(sha256.Hash!);
Span<byte> requestBuffer = new byte[request.RequestData!.Length + 1];
request.FlatEncode(requestBuffer);
sha256.ComputeHash(requestBuffer.ToArray()).CopyTo(concatenatedHashes.Slice(currentPosition, 32));
currentPosition += 32;
}

// Compute sha256 of the concatenated hashes
return new Hash256(sha256.ComputeHash(concatenatedHashes.ToArray()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ public void ProcessExecutionRequests(Block block, IWorldState state, TxReceipt[]
if (block.IsGenesis)
return;

block.ExecutionRequests = new ArrayPoolList<ExecutionRequest>(Requests.Length);
foreach (var request in Requests)
{
block.ExecutionRequests.Add(request);
}
block.ExecutionRequests = Requests;
block.Header.RequestsHash = Requests.CalculateHash();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ public class GetPayloadV4Result(Block block, UInt256 blockFees, BlobsBundleV1 bl
public ExecutionRequest[]? ExecutionRequests { get; } = ExecutionRequests;

public override string ToString() =>
$"{{ExecutionPayload: {ExecutionPayload}, Fees: {BlockValue}, BlobsBundle blobs count: {BlobsBundle.Blobs.Length}, ShouldOverrideBuilder {ShouldOverrideBuilder}, ExecutionRequests : {ExecutionRequests?.FlatEncode()}}}";
$"{{ExecutionPayload: {ExecutionPayload}, Fees: {BlockValue}, BlobsBundle blobs count: {BlobsBundle.Blobs.Length}, ShouldOverrideBuilder {ShouldOverrideBuilder}, ExecutionRequests count : {ExecutionRequests?.Length}}}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class GetPayloadV4Handler(
{
protected override GetPayloadV4Result GetPayloadResultFromBlock(IBlockProductionContext context)
{
return new(context.CurrentBestBlock!, context.BlockFees, new BlobsBundleV1(context.CurrentBestBlock!), context.CurrentBestBlock!.ExecutionRequests!.ToArray())
return new(context.CurrentBestBlock!, context.BlockFees, new BlobsBundleV1(context.CurrentBestBlock!), context.CurrentBestBlock!.ExecutionRequests!)
{
ShouldOverrideBuilder = censorshipDetector?.GetCensoredBlocks().Contains(new BlockNumberHash(context.CurrentBestBlock!)) ?? false
};
Expand Down