From e8f63cfb06fd6e20c03cec52f79f63d70b19ac7a Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Tue, 10 Feb 2026 14:14:52 +0000 Subject: [PATCH 1/2] Move tx block-format wrapping logic from BlockDecoder to TxDecoder Extract the legacy-vs-typed tx wrapping knowledge into static helpers on TxDecoder (GetBlockFormatLength, WriteBlockFormat) so BlockDecoder no longer directly checks TxType.Legacy for encoding decisions. --- .../BlockDecoder.cs | 12 ++---------- .../Nethermind.Serialization.Rlp/TxDecoder.cs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs index a5df5084a34f..1f41d4aebb0a 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs @@ -59,9 +59,7 @@ private static int GetPreEncodedTxLength(Transaction[] txs, byte[][] encodedTxs) int sum = 0; for (int i = 0; i < encodedTxs.Length; i++) { - int len = encodedTxs[i].Length; - // Legacy txs: CL format = block format. Typed txs: block format wraps in RLP byte string. - sum += txs[i].Type == TxType.Legacy ? len : Rlp.LengthOfSequence(len); + sum += TxDecoder.GetBlockFormatLength(txs[i].Type, encodedTxs[i].Length); } return sum; } @@ -128,13 +126,7 @@ public override void Encode(RlpStream stream, Block? item, RlpBehaviors rlpBehav { for (int i = 0; i < encodedTxs.Length; i++) { - byte[] encoded = encodedTxs[i]; - if (item.Transactions[i].Type != TxType.Legacy) - { - // Typed txs: CL format is type||rlp(fields), block format wraps in RLP byte string - stream.StartByteArray(encoded.Length, false); - } - stream.Write(encoded); + TxDecoder.WriteBlockFormat(stream, item.Transactions[i].Type, encodedTxs[i]); } } else diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs index bf3174dd9a74..63b480e7f936 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs @@ -24,6 +24,25 @@ static TxDecoder() Instance = new TxDecoder(static () => TxObjectPool.Get()); Rlp.RegisterDecoder(typeof(Transaction), Instance); } + + /// + /// Gets the block-format length of a pre-encoded CL-format transaction. + /// Legacy txs use the same format; typed txs are wrapped in an RLP byte string. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetBlockFormatLength(TxType type, int clEncodedLength) + => type == TxType.Legacy ? clEncodedLength : Rlp.LengthOfSequence(clEncodedLength); + + /// + /// Writes a pre-encoded CL-format transaction in block format. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBlockFormat(RlpStream stream, TxType type, byte[] clEncoded) + { + if (type != TxType.Legacy) + stream.StartByteArray(clEncoded.Length, false); + stream.Write(clEncoded); + } } public sealed class SystemTxDecoder : TxDecoder; From f86d199f89afd2850d3992d1f06873acd130dd8e Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Wed, 11 Feb 2026 00:08:11 +0000 Subject: [PATCH 2/2] Feedback --- src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs | 4 ++-- src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs index 1f41d4aebb0a..90c559c1ab62 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockDecoder.cs @@ -59,7 +59,7 @@ private static int GetPreEncodedTxLength(Transaction[] txs, byte[][] encodedTxs) int sum = 0; for (int i = 0; i < encodedTxs.Length; i++) { - sum += TxDecoder.GetBlockFormatLength(txs[i].Type, encodedTxs[i].Length); + sum += TxDecoder.GetWrappedTxLength(txs[i].Type, encodedTxs[i].Length); } return sum; } @@ -126,7 +126,7 @@ public override void Encode(RlpStream stream, Block? item, RlpBehaviors rlpBehav { for (int i = 0; i < encodedTxs.Length; i++) { - TxDecoder.WriteBlockFormat(stream, item.Transactions[i].Type, encodedTxs[i]); + TxDecoder.WriteWrappedFormat(stream, item.Transactions[i].Type, encodedTxs[i]); } } else diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs index 63b480e7f936..22d063b13661 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/TxDecoder.cs @@ -30,14 +30,14 @@ static TxDecoder() /// Legacy txs use the same format; typed txs are wrapped in an RLP byte string. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBlockFormatLength(TxType type, int clEncodedLength) + public static int GetWrappedTxLength(TxType type, int clEncodedLength) => type == TxType.Legacy ? clEncodedLength : Rlp.LengthOfSequence(clEncodedLength); /// /// Writes a pre-encoded CL-format transaction in block format. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void WriteBlockFormat(RlpStream stream, TxType type, byte[] clEncoded) + public static void WriteWrappedFormat(RlpStream stream, TxType type, byte[] clEncoded) { if (type != TxType.Legacy) stream.StartByteArray(clEncoded.Length, false);