diff --git a/src/Nethermind/Nethermind.Core.Test/RlpTests.cs b/src/Nethermind/Nethermind.Core.Test/RlpTests.cs index d0d1e912160c..6dc0d45afc26 100644 --- a/src/Nethermind/Nethermind.Core.Test/RlpTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/RlpTests.cs @@ -568,6 +568,5 @@ private static byte[] BuildLongFormRlp(int prefix, int contentLength) } return data; } - } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs index 515765ec3c25..b650109c7859 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessage.cs @@ -34,6 +34,12 @@ public BlockBodiesMessage(BlockBody?[] bodies) Bodies = new OwnedBlockBodies(bodies); } + public override void Dispose() + { + base.Dispose(); + Bodies?.Dispose(); + } + public override string ToString() => $"{nameof(BlockBodiesMessage)}({Bodies?.Bodies?.Length ?? 0})"; } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs index 58b7c399e179..e667c9f70ccf 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V62/Messages/BlockBodiesMessageSerializer.cs @@ -51,14 +51,24 @@ public int GetLength(BlockBodiesMessage message, out int contentLength) public BlockBodiesMessage Deserialize(IByteBuffer byteBuffer) { - NettyBufferMemoryOwner memoryOwner = new(byteBuffer); + NettyBufferMemoryOwner? memoryOwner = new(byteBuffer); Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); int startingPosition = ctx.Position; - BlockBody[]? bodies = ctx.DecodeArray(_blockBodyDecoder, false, limit: RlpLimit); - byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startingPosition)); + try + { + BlockBody[]? bodies = ctx.DecodeArray(_blockBodyDecoder, false, limit: RlpLimit); + OwnedBlockBodies ownedBodies = new(bodies, memoryOwner); + memoryOwner = null; + byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startingPosition)); - return new() { Bodies = new(bodies, memoryOwner) }; + return new() { Bodies = ownedBodies }; + } + catch + { + memoryOwner?.Dispose(); + throw; + } } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs index 365001580965..2437bdc197b2 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessage.cs @@ -23,8 +23,8 @@ public class AccountRangeMessage : SnapMessageBase public override void Dispose() { base.Dispose(); - PathsWithAccounts.Dispose(); - Proofs.Dispose(); + PathsWithAccounts?.Dispose(); + Proofs?.Dispose(); } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs index e7889eb9ecfa..a91495c25f78 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs @@ -50,31 +50,43 @@ public void Serialize(IByteBuffer byteBuffer, AccountRangeMessage message) public AccountRangeMessage Deserialize(IByteBuffer byteBuffer) { - NettyBufferMemoryOwner memoryOwner = new(byteBuffer); + NettyBufferMemoryOwner? memoryOwner = new(byteBuffer); Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); int startPos = ctx.Position; - - ctx.ReadSequenceLength(); - AccountRangeMessage message = new(); - message.RequestId = ctx.DecodeLong(); + ArrayPoolList? pathsWithAccounts = null; - int pwasCheck = ctx.ReadSequenceLength() + ctx.Position; - int count = ctx.PeekNumberOfItemsRemaining(pwasCheck); - ctx.GuardLimit(count, SnapMessageLimits.AccountRangeEntriesRlpLimit); - ArrayPoolList pathsWithAccounts = new(count); - for (int i = 0; i < count; i++) + try { ctx.ReadSequenceLength(); - pathsWithAccounts.Add(new PathWithAccount(ctx.DecodeKeccak(), _decoder.Decode(ref ctx))); - } + message.RequestId = ctx.DecodeLong(); - message.PathsWithAccounts = pathsWithAccounts; - message.Proofs = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); + int pwasCheck = ctx.ReadSequenceLength() + ctx.Position; + int count = ctx.PeekNumberOfItemsRemaining(pwasCheck); + ctx.GuardLimit(count, SnapMessageLimits.AccountRangeEntriesRlpLimit); + pathsWithAccounts = new ArrayPoolList(count); + for (int i = 0; i < count; i++) + { + ctx.ReadSequenceLength(); + pathsWithAccounts.Add(new PathWithAccount(ctx.DecodeKeccak(), _decoder.Decode(ref ctx))); + } - byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); + message.PathsWithAccounts = pathsWithAccounts; + pathsWithAccounts = null; + message.Proofs = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); + memoryOwner = null; - return message; + byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); + + return message; + } + catch + { + pathsWithAccounts?.Dispose(); + message.Dispose(); + memoryOwner?.Dispose(); + throw; + } } private (int contentLength, int pwasLength) GetLength(AccountRangeMessage message) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs index 6ef2fbe7ff0c..6b64ac8fca14 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/ByteCodesMessageSerializer.cs @@ -23,17 +23,28 @@ public void Serialize(IByteBuffer byteBuffer, ByteCodesMessage message) public ByteCodesMessage Deserialize(IByteBuffer byteBuffer) { - NettyBufferMemoryOwner memoryOwner = new(byteBuffer); + NettyBufferMemoryOwner? memoryOwner = new(byteBuffer); Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); int startPos = ctx.Position; + RlpByteArrayList? list = null; - ctx.ReadSequenceLength(); - long requestId = ctx.DecodeLong(); + try + { + ctx.ReadSequenceLength(); + long requestId = ctx.DecodeLong(); - RlpByteArrayList list = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); - byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); + list = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); + memoryOwner = null; + byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); - return new ByteCodesMessage(list) { RequestId = requestId }; + return new ByteCodesMessage(list) { RequestId = requestId }; + } + catch + { + list?.Dispose(); + memoryOwner?.Dispose(); + throw; + } } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs index 6b9e232eac3e..c5433cf3608c 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/GetTrieNodesMessageSerializer.cs @@ -111,22 +111,37 @@ private static void EncodePaths(RlpStream stream, IReadOnlyList paths public GetTrieNodesMessage Deserialize(IByteBuffer byteBuffer) { - NettyBufferMemoryOwner memoryOwner = new(byteBuffer); + NettyBufferMemoryOwner? memoryOwner = new(byteBuffer); Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); int startingPosition = ctx.Position; + GetTrieNodesMessage message = new(); + IRlpItemList? rawPaths = null; - ctx.ReadSequenceLength(); - long requestId = ctx.DecodeLong(); - Hash256? rootHash = ctx.DecodeKeccak(); + try + { + ctx.ReadSequenceLength(); + message.RequestId = ctx.DecodeLong(); + Hash256? rootHash = ctx.DecodeKeccak(); + message.RootHash = rootHash; - IRlpItemList rawPaths = RlpItemList.DecodeList(ref ctx, memoryOwner); - ValidatePathGroups(rawPaths); - RlpPathGroupList paths = new(rawPaths); + rawPaths = RlpItemList.DecodeList(ref ctx, memoryOwner); + memoryOwner = null; + ValidatePathGroups(rawPaths); + message.Paths = new RlpPathGroupList(rawPaths); + rawPaths = null; - long bytes = ctx.DecodeLong(); - byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startingPosition)); + message.Bytes = ctx.DecodeLong(); + byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startingPosition)); - return new GetTrieNodesMessage { RequestId = requestId, RootHash = rootHash, Paths = paths, Bytes = bytes }; + return message; + } + catch + { + rawPaths?.Dispose(); + message.Dispose(); + memoryOwner?.Dispose(); + throw; + } } private static void ValidatePathGroups(IRlpItemList paths) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs index f3c641724391..fd776d5b6c90 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/StorageRangesMessageSerializer.cs @@ -59,28 +59,38 @@ public void Serialize(IByteBuffer byteBuffer, StorageRangeMessage message) public StorageRangeMessage Deserialize(IByteBuffer byteBuffer) { - NettyBufferMemoryOwner memoryOwner = new(byteBuffer); + NettyBufferMemoryOwner? memoryOwner = new(byteBuffer); Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); int startPos = ctx.Position; - ctx.ReadSequenceLength(); - StorageRangeMessage message = new(); - message.RequestId = ctx.DecodeLong(); - message.Slots = ctx.DecodeArrayPoolList>(static (ref Rlp.ValueDecoderContext outerCtx) => - outerCtx.DecodeArrayPoolList(static (ref Rlp.ValueDecoderContext innerCtx) => - { - innerCtx.ReadSequenceLength(); - Hash256 path = innerCtx.DecodeKeccak(); - byte[] value = innerCtx.DecodeByteArray(StorageSlotValueRlpLimit); - return new PathWithStorageSlot(in path.ValueHash256, value); - }, limit: SnapMessageLimits.StorageRangeSlotsPerAccountRlpLimit), limit: SnapMessageLimits.StorageRangeAccountsRlpLimit); - message.Proofs = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); + try + { + ctx.ReadSequenceLength(); + message.RequestId = ctx.DecodeLong(); + + message.Slots = ctx.DecodeArrayPoolList>(static (ref Rlp.ValueDecoderContext outerCtx) => + outerCtx.DecodeArrayPoolList(static (ref Rlp.ValueDecoderContext innerCtx) => + { + innerCtx.ReadSequenceLength(); + Hash256 path = innerCtx.DecodeKeccak(); + byte[] value = innerCtx.DecodeByteArray(StorageSlotValueRlpLimit); + return new PathWithStorageSlot(in path.ValueHash256, value); + }, limit: SnapMessageLimits.StorageRangeSlotsPerAccountRlpLimit), limit: SnapMessageLimits.StorageRangeAccountsRlpLimit); + message.Proofs = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); + memoryOwner = null; - byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); + byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); - return message; + return message; + } + catch + { + message.Dispose(); + memoryOwner?.Dispose(); + throw; + } } private static (int contentLength, int allSlotsLength, int[] accountSlotsLengths) CalculateLengths(StorageRangeMessage message) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs index 4c4055ff1666..00ec7b5a3aa3 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/TrieNodesMessageSerializer.cs @@ -23,17 +23,28 @@ public void Serialize(IByteBuffer byteBuffer, TrieNodesMessage message) public TrieNodesMessage Deserialize(IByteBuffer byteBuffer) { - NettyBufferMemoryOwner memoryOwner = new(byteBuffer); + NettyBufferMemoryOwner? memoryOwner = new(byteBuffer); Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); int startPos = ctx.Position; + RlpByteArrayList? list = null; - ctx.ReadSequenceLength(); - long requestId = ctx.DecodeLong(); + try + { + ctx.ReadSequenceLength(); + long requestId = ctx.DecodeLong(); - RlpByteArrayList list = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); - byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); + list = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); + memoryOwner = null; + byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); - return new TrieNodesMessage(list) { RequestId = requestId }; + return new TrieNodesMessage(list) { RequestId = requestId }; + } + catch + { + list?.Dispose(); + memoryOwner?.Dispose(); + throw; + } } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs index 992233495a77..191cd23fd0f6 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/NettyRlpStream.cs @@ -99,12 +99,24 @@ public static void WriteByteArrayList(IByteBuffer byteBuffer, IByteArrayList lis public static RlpByteArrayList DecodeByteArrayList(IByteBuffer byteBuffer) { - NettyBufferMemoryOwner memoryOwner = new(byteBuffer); + NettyBufferMemoryOwner? memoryOwner = new(byteBuffer); Rlp.ValueDecoderContext ctx = new(memoryOwner.Memory, true); int startPos = ctx.Position; - RlpByteArrayList list = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); - byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); - return list; + RlpByteArrayList? list = null; + + try + { + list = RlpByteArrayList.DecodeList(ref ctx, memoryOwner); + memoryOwner = null; + byteBuffer.SetReaderIndex(byteBuffer.ReaderIndex + (ctx.Position - startPos)); + return list; + } + catch + { + list?.Dispose(); + memoryOwner?.Dispose(); + throw; + } } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index 8d0df9e7b67e..8363691c9348 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -1463,25 +1463,53 @@ public ArrayPoolList DecodeArrayPoolList(DecodeRlpValue decodeItem, boo int count = PeekNumberOfItemsRemaining(checkPositions ? positionCheck : null); GuardLimit(count, limit); ArrayPoolList result = new(count, count); - for (int i = 0; i < result.Count; i++) + int i = 0; + try { - if (PeekByte() == OfEmptyList[0]) + for (; i < result.Count; i++) { - result[i] = defaultElement; - Position++; + if (PeekByte() == OfEmptyList[0]) + { + result[i] = defaultElement; + Position++; + } + else + { + result[i] = decodeItem(ref this); + } } - else + + if (checkPositions) { - result[i] = decodeItem(ref this); + Check(positionCheck); } - } - if (checkPositions) + return result; + } + catch { - Check(positionCheck); + try + { + DisposeDecodedItems(result, i); + } + finally + { + result.Dispose(); + } + + throw; } - return result; + static void DisposeDecodedItems(ArrayPoolList list, int count) + { + for (int j = 0; j < count; j++) + { + if (list[j] is IDisposable disposable) + { + disposable.Dispose(); + } + } + } } public readonly bool IsNextItemEmptyByteArray() => PeekByte() is EmptyByteArrayByte;