diff --git a/src/Nethermind/Nethermind.Consensus/Requests/ConsensusRequestsProcessor.cs b/src/Nethermind/Nethermind.Consensus/Requests/ConsensusRequestsProcessor.cs
index cefc5943b0c..379dff65d72 100644
--- a/src/Nethermind/Nethermind.Consensus/Requests/ConsensusRequestsProcessor.cs
+++ b/src/Nethermind/Nethermind.Consensus/Requests/ConsensusRequestsProcessor.cs
@@ -32,7 +32,7 @@ public void ProcessRequests(Block block, IWorldState state, TxReceipt[] receipts
requestsList.AddRange(_consolidationRequestsProcessor.ReadConsolidationRequests(block, state, spec));
ConsensusRequest[] requests = requestsList.ToArray();
- Hash256 root = new RequestsTrie(requests).RootHash;
+ Hash256 root = requests.CalculateRootHash();
block.Body.Requests = requests;
block.Header.RequestsRoot = root;
}
diff --git a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
index 1bfbdf072b7..3554e88eb95 100644
--- a/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
+++ b/src/Nethermind/Nethermind.Consensus/Validators/BlockValidator.cs
@@ -466,7 +466,7 @@ private static bool ValidateRequestsHashMatches(BlockHeader header, BlockBody bo
return header.RequestsRoot is null;
}
- return (requestsRoot = new RequestsTrie(body.Requests).RootHash) == header.RequestsRoot;
+ return (requestsRoot = body.Requests.CalculateRootHash()) == header.RequestsRoot;
}
private static string Invalid(Block block) =>
diff --git a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
index 4b5e591949b..7c0a3219482 100644
--- a/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
+++ b/src/Nethermind/Nethermind.Core.Test/Builders/BlockBuilder.cs
@@ -293,7 +293,7 @@ public BlockBuilder WithConsensusRequests(params ConsensusRequest[]? requests)
TestObjectInternal.Header.RequestsRoot = requests is null
? null
- : new RequestsTrie(requests).RootHash;
+ : requests.CalculateRootHash();
return this;
}
diff --git a/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsensusRequest.cs b/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsensusRequest.cs
index e9e5f6d38e1..88103c8aa58 100644
--- a/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsensusRequest.cs
+++ b/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsensusRequest.cs
@@ -5,6 +5,7 @@
using System;
using System.Text.Json.Serialization;
+
namespace Nethermind.Core.ConsensusRequests;
public enum ConsensusRequestsType : byte
@@ -18,6 +19,21 @@ public abstract class ConsensusRequest
{
[JsonIgnore]
public ConsensusRequestsType Type { get; protected set; }
+
+ ///
+ /// Encodes the request into a byte array
+ /// reference: https://eips.ethereum.org/EIPS/eip-7685
+ ///
+ /// request = request_type ++ request_data
+ public abstract byte[] Encode();
+
+ ///
+ /// Decodes the request from a byte array
+ /// reference: https://eips.ethereum.org/EIPS/eip-7685
+ ///
+ /// request = request_type ++ request_data
+ /// request
+ public abstract ConsensusRequest Decode(byte[] data);
}
public static class ConsensusRequestExtensions
@@ -75,4 +91,33 @@ public static (Deposit[]? deposits, WithdrawalRequest[]? withdrawalRequests, Con
return (deposits, withdrawalRequests, consolidationRequests);
}
+
+ public static byte[][] Encode(this ConsensusRequest[]? requests)
+ {
+ if (requests is null) return Array.Empty();
+ byte[][] requestsEncoded = new byte[requests.Length][];
+ for (int i = 0; i < requests.Length; i++)
+ {
+ requestsEncoded[i] = requests[i].Encode();
+ }
+ return requestsEncoded;
+ }
+
+ public static ConsensusRequest Decode(byte[] data)
+ {
+ if (data.Length < 2)
+ {
+ throw new ArgumentException("Invalid data length");
+ }
+
+ ConsensusRequestsType type = (ConsensusRequestsType)data[0];
+ return type switch
+ {
+ ConsensusRequestsType.Deposit => new Deposit().Decode(data),
+ ConsensusRequestsType.WithdrawalRequest => new WithdrawalRequest().Decode(data),
+ ConsensusRequestsType.ConsolidationRequest => new ConsolidationRequest().Decode(data),
+ _ => throw new ArgumentException("Invalid request type")
+ };
+ }
+
}
diff --git a/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsolidationRequest.cs b/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsolidationRequest.cs
index abf79b924a1..75def5d8307 100644
--- a/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsolidationRequest.cs
+++ b/src/Nethermind/Nethermind.Core/ConsensusRequests/ConsolidationRequest.cs
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Linq;
using Nethermind.Core.Extensions;
namespace Nethermind.Core.ConsensusRequests;
@@ -27,5 +28,26 @@ public string ToString(string indentation) => @$"{indentation}{nameof(Consolidat
{nameof(TargetPubkey)}: {TargetPubkey?.Span.ToHexString()},
}}";
+ public override byte[] Encode()
+ {
+ byte[] type = new byte[] { (byte)Type };
+ return type
+ .Concat(SourceAddress?.Bytes ?? Array.Empty())
+ .Concat(SourcePubkey?.ToArray() ?? Array.Empty())
+ .Concat(TargetPubkey?.ToArray() ?? Array.Empty()).ToArray();
+ }
+ public override ConsensusRequest Decode(byte[] data)
+ {
+ if (data.Length < 2)
+ {
+ throw new ArgumentException("Invalid data length");
+ }
+
+ Type = (ConsensusRequestsType)data[0];
+ SourceAddress = new Address(data.Slice(1, Address.Size));
+ SourcePubkey = data.AsMemory().Slice(1 + Address.Size);
+ TargetPubkey = data.AsMemory().Slice(1 + Address.Size + SourcePubkey.Value.Length);
+ return this;
+ }
}
diff --git a/src/Nethermind/Nethermind.Core/ConsensusRequests/Deposit.cs b/src/Nethermind/Nethermind.Core/ConsensusRequests/Deposit.cs
index 50b46fc27c2..d501e90e3b7 100644
--- a/src/Nethermind/Nethermind.Core/ConsensusRequests/Deposit.cs
+++ b/src/Nethermind/Nethermind.Core/ConsensusRequests/Deposit.cs
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0-only
using System;
+using System.Linq;
using Nethermind.Core.Extensions;
namespace Nethermind.Core.ConsensusRequests;
@@ -32,5 +33,31 @@ public string ToString(string indentation) => @$"{indentation}{nameof(Deposit)}
{nameof(Signature)}: {Signature?.ToHexString()},
{nameof(Pubkey)}: {Pubkey?.Span.ToHexString()}}}";
+ public override byte[] Encode()
+ {
+ byte[] type = new byte[] { (byte)Type };
+ return type
+ .Concat(Pubkey?.ToArray() ?? Array.Empty())
+ .Concat(WithdrawalCredentials ?? Array.Empty())
+ .Concat(BitConverter.GetBytes(Amount))
+ .Concat(Signature ?? Array.Empty())
+ .Concat(Index.HasValue ? BitConverter.GetBytes(Index.Value) : Array.Empty()).ToArray();
+ }
+
+ public override ConsensusRequest Decode(byte[] data)
+ {
+ if (data.Length < 2)
+ {
+ throw new ArgumentException("Invalid data length");
+ }
+
+ Type = (ConsensusRequestsType)data[0];
+ Pubkey = data.AsMemory()[1..33];
+ WithdrawalCredentials = data.Slice(1 + Pubkey.Value.Length, 32);
+ Amount = BitConverter.ToUInt64(data, 1 + Pubkey.Value.Length + 32);
+ Signature = data.Slice(1 + Pubkey.Value.Length + 32 + sizeof(ulong));
+ Index = data.Length > 1 + Pubkey.Value.Length + 32 + sizeof(ulong) + Signature!.Length ? BitConverter.ToUInt64(data, 1 + Pubkey.Value.Length + 32 + sizeof(ulong) + Signature!.Length) : null;
+ return this;
+ }
}
diff --git a/src/Nethermind/Nethermind.Core/ConsensusRequests/WithdrawalRequest.cs b/src/Nethermind/Nethermind.Core/ConsensusRequests/WithdrawalRequest.cs
index f9d79f127c7..3560db94faf 100644
--- a/src/Nethermind/Nethermind.Core/ConsensusRequests/WithdrawalRequest.cs
+++ b/src/Nethermind/Nethermind.Core/ConsensusRequests/WithdrawalRequest.cs
@@ -3,7 +3,7 @@
using System;
using Nethermind.Core.Extensions;
-using System.Text;
+using System.Linq;
namespace Nethermind.Core.ConsensusRequests;
@@ -30,4 +30,26 @@ public string ToString(string indentation) => @$"{indentation}{nameof(Withdrawal
{nameof(Amount)}: {Amount}}}";
+ public override byte[] Encode()
+ {
+ byte[] type = new byte[] { (byte)Type };
+ return type
+ .Concat(SourceAddress?.Bytes ?? Array.Empty())
+ .Concat(ValidatorPubkey?.ToArray() ?? Array.Empty())
+ .Concat(BitConverter.GetBytes(Amount)).ToArray();
+ }
+
+ public override ConsensusRequest Decode(byte[] data)
+ {
+ if (data.Length < 2)
+ {
+ throw new ArgumentException("Invalid data length");
+ }
+
+ Type = (ConsensusRequestsType)data[0];
+ SourceAddress = new Address(data.Slice(1, Address.Size));
+ ValidatorPubkey = data.AsMemory().Slice(1 + Address.Size);
+ Amount = BitConverter.ToUInt64(data, 1 + Address.Size + ValidatorPubkey.Value.Length);
+ return this;
+ }
}
diff --git a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV4.cs b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV4.cs
index e0d65da1215..373bc6946a9 100644
--- a/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV4.cs
+++ b/src/Nethermind/Nethermind.Merge.Plugin/Data/ExecutionPayloadV4.cs
@@ -62,7 +62,7 @@ public override bool TryGetBlock([NotNullWhen(true)] out Block? block, UInt256?
}
block.Body.Requests = requests;
- block.Header.RequestsRoot = new RequestsTrie(requests).RootHash;
+ block.Header.RequestsRoot = requests.CalculateRootHash();
}
else
{
diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs
index 0530f141fd8..aa5a9542e6e 100644
--- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs
+++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs
@@ -122,10 +122,11 @@ public class BlockDecoder : IRlpValueDecoder, IRlpStreamDecoder
while (rlpStream.Position < requestsCheck)
{
- requests.Add(Rlp.Decode(rlpStream));
+ requests.Add(ConsensusRequestExtensions.Decode(rlpStream.DecodeByteArray()));
}
rlpStream.Check(requestsCheck);
+
}
}
@@ -303,7 +304,7 @@ public int GetLength(Block? item, RlpBehaviors rlpBehaviors)
while (decoderContext.Position < requestsCheck)
{
- requests.Add(Rlp.Decode(ref decoderContext));
+ requests.Add(ConsensusRequestExtensions.Decode(decoderContext.DecodeByteArray()));
}
decoderContext.Check(requestsCheck);
@@ -359,12 +360,7 @@ public void Encode(RlpStream stream, Block? item, RlpBehaviors rlpBehaviors = Rl
if (requestsLength.HasValue)
{
- stream.StartSequence(requestsLength.Value);
-
- for (int i = 0; i < item.Requests.Length; i++)
- {
- stream.Encode(item.Requests[i]);
- }
+ stream.Encode(item.Requests.Encode());
}
}
diff --git a/src/Nethermind/Nethermind.State/Proofs/RequestsTrie.cs b/src/Nethermind/Nethermind.State/Proofs/RequestsTrie.cs
index d69e1d0c8d7..91156e0b3b2 100644
--- a/src/Nethermind/Nethermind.State/Proofs/RequestsTrie.cs
+++ b/src/Nethermind/Nethermind.State/Proofs/RequestsTrie.cs
@@ -33,3 +33,18 @@ public static Hash256 CalculateRoot(ConsensusRequest[] requests)
return rootHash;
}
}
+
+
+public static class ConsensusRequestExtensions
+{
+ public static Hash256 CalculateRootHash(this ConsensusRequest[]? requests)
+ {
+ Rlp[] encodedRequests = new Rlp[requests!.Length];
+ for (int i = 0; i < encodedRequests.Length; i++)
+ {
+ encodedRequests[i] = Rlp.Encode(requests![i].Encode());
+ }
+
+ return Keccak.Compute(Rlp.Encode(encodedRequests).Bytes);
+ }
+}