diff --git a/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs b/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs index fee9591bd1b..96002756623 100644 --- a/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs +++ b/src/Nethermind/Nethermind.Core.Test/Encoding/ReceiptDecoderTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -33,7 +33,7 @@ public void Can_do_roundtrip_storage([Values(true, false)] bool encodeWithTxHash TxReceipt GetExpected() { ReceiptBuilder receiptBuilder = Build.A.Receipt.WithAllFieldsFilled; - + if ((encodeBehaviors & RlpBehaviors.Eip658Receipts) != 0) { receiptBuilder.WithState(null); @@ -47,7 +47,7 @@ TxReceipt GetExpected() { receiptBuilder.WithTransactionHash(null); } - + if (!withError) { receiptBuilder.WithError(string.Empty); @@ -71,7 +71,7 @@ TxReceipt BuildReceipt() ReceiptStorageDecoder encoder = new(encodeWithTxHash); Rlp rlp = encoder.Encode(txReceipt, encodeBehaviors); - + ReceiptStorageDecoder decoder = new(); TxReceipt deserialized; if (valueDecoder) @@ -184,7 +184,7 @@ public void Can_do_roundtrip_none_rlp_stream() AssertMessageReceipt(txReceipt, deserialized); } - + [Test] public void Can_do_roundtrip_with_receipt_message_and_tx_type_access_list() { @@ -197,9 +197,9 @@ public void Can_do_roundtrip_with_receipt_message_and_tx_type_access_list() ReceiptMessageDecoder decoder = new(); - byte[] rlpStreamResult = decoder.Encode(txReceipt).Bytes; + byte[] rlpStreamResult = decoder.EncodeNew(txReceipt, RlpBehaviors.None); TxReceipt deserialized = decoder.Decode(new RlpStream(rlpStreamResult)); - + AssertMessageReceipt(txReceipt, deserialized); } @@ -227,7 +227,7 @@ public void Can_do_roundtrip_with_storage_receipt_and_tx_type_access_list() AssertStorageReceipt(txReceipt, deserialized); } - + public static IEnumerable<(TxReceipt, string)> TestCaseSource() { Bloom bloom = new(); @@ -237,7 +237,7 @@ public void Can_do_roundtrip_with_storage_receipt_and_tx_type_access_list() yield return (Build.A.Receipt.WithBloom(bloom).WithGasUsedTotal(500).WithState(TestItem.KeccakA).WithTxType(TxType.AccessList).TestObject, "access list"); yield return (Build.A.Receipt.WithBloom(bloom).WithGasUsedTotal(100).WithState(TestItem.KeccakH).WithTxType(TxType.EIP1559).TestObject, "eip 1559"); } - + [TestCaseSource(nameof(TestCaseSource))] public void Can_do_roundtrip_with_storage_receipt((TxReceipt TxReceipt, string Description) testCase) { @@ -249,7 +249,7 @@ public void Can_do_roundtrip_with_storage_receipt((TxReceipt TxReceipt, string D AssertStorageReceipt(txReceipt, deserialized); } - + [TestCaseSource(nameof(TestCaseSource))] public void Can_do_roundtrip_with_receipt_message((TxReceipt TxReceipt, string Description) testCase) { @@ -257,12 +257,12 @@ public void Can_do_roundtrip_with_receipt_message((TxReceipt TxReceipt, string D ReceiptMessageDecoder decoder = new(); - byte[] rlpStreamResult = decoder.Encode(txReceipt).Bytes; + byte[] rlpStreamResult = decoder.EncodeNew(txReceipt); TxReceipt deserialized = decoder.Decode(new RlpStream(rlpStreamResult)); AssertMessageReceipt(txReceipt, deserialized); } - + private void AssertMessageReceipt(TxReceipt txReceipt, TxReceipt deserialized) { Assert.AreEqual(txReceipt.Bloom, deserialized.Bloom, "bloom"); diff --git a/src/Nethermind/Nethermind.Network.Benchmark/InFlowBenchmarks.cs b/src/Nethermind/Nethermind.Network.Benchmark/InFlowBenchmarks.cs index 1f50704a04a..6c3311addbc 100644 --- a/src/Nethermind/Nethermind.Network.Benchmark/InFlowBenchmarks.cs +++ b/src/Nethermind/Nethermind.Network.Benchmark/InFlowBenchmarks.cs @@ -1,16 +1,16 @@ // Copyright (c) 2018 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -53,7 +53,7 @@ public void Setup() { throw new Exception("decoder buffer"); } - + SetupAll(); IterationSetup(); Current(); @@ -65,7 +65,7 @@ public void Setup() SetupAll(); IterationSetup(); } - + [IterationSetup] public void IterationSetup() { @@ -149,7 +149,7 @@ public void Current() IByteBuffer decoded = _zeroDecoder.Decode(_decoderBuffer); IByteBuffer merged = _zeroMerger.Decode(decoded); merged.ReadByte(); - _outputMessage = _newBlockMessageSerializer.Deserialize(merged.ReadAllBytes()); + _outputMessage = _newBlockMessageSerializer.Deserialize(merged.ReadAllBytesAsArray()); } } } diff --git a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs index 6c798ff5f22..4462ef06334 100644 --- a/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Discovery.Test/DiscoveryMessageSerializerTests.cs @@ -1,20 +1,21 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System.Net; +using DotNetty.Buffers; using Nethermind.Core; using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; @@ -58,7 +59,7 @@ public void PingMessageTest() new(_privateKey.PublicKey, 60 + _timestamper.UnixTime.MillisecondsLong, _farAddress, _nearAddress, new byte[32]) { FarAddress = _farAddress }; - byte[] data = _messageSerializationService.Serialize(message); + IByteBuffer data = _messageSerializationService.ZeroSerialize(message); PingMsg deserializedMessage = _messageSerializationService.Deserialize(data); Assert.AreEqual(message.MsgType, deserializedMessage.MsgType); @@ -84,7 +85,7 @@ public void PongMessageTest() FarAddress = _farAddress }; - byte[] data = _messageSerializationService.Serialize(message); + IByteBuffer data = _messageSerializationService.ZeroSerialize(message); PongMsg deserializedMessage = _messageSerializationService.Deserialize(data); Assert.AreEqual(message.MsgType, deserializedMessage.MsgType); @@ -99,21 +100,21 @@ public void Ping_with_enr_there_and_back() { PingMsg pingMsg = new (TestItem.PublicKeyA, long.MaxValue, TestItem.IPEndPointA, TestItem.IPEndPointB, new byte[32]); pingMsg.EnrSequence = 3; - byte[] serialized = _messageSerializationService.Serialize(pingMsg); + IByteBuffer serialized = _messageSerializationService.ZeroSerialize(pingMsg); pingMsg = _messageSerializationService.Deserialize(serialized); Assert.AreEqual(3, pingMsg.EnrSequence); } - + [Test] public void Enr_request_there_and_back() { EnrRequestMsg msg = new(TestItem.PublicKeyA, long.MaxValue); - byte[] serialized = _messageSerializationService.Serialize(msg); + IByteBuffer serialized = _messageSerializationService.ZeroSerialize(msg); EnrRequestMsg deserialized = _messageSerializationService.Deserialize(serialized); Assert.AreEqual(msg.ExpirationTime, deserialized.ExpirationTime); Assert.AreEqual(deserialized.FarPublicKey, _privateKey.PublicKey); } - + [Test] public void Enr_response_there_and_back() { @@ -124,7 +125,7 @@ public void Enr_response_there_and_back() signer.Sign(nodeRecord); EnrResponseMsg msg = new(TestItem.PublicKeyA, nodeRecord, TestItem.KeccakA); - byte[] serialized = _messageSerializationService.Serialize(msg); + IByteBuffer serialized = _messageSerializationService.ZeroSerialize(msg); EnrResponseMsg deserialized = _messageSerializationService.Deserialize(serialized); Assert.AreEqual(msg.NodeRecord.EnrSequence, deserialized.NodeRecord.EnrSequence); Assert.AreEqual(msg.RequestKeccak, deserialized.RequestKeccak); @@ -161,7 +162,7 @@ public void FindNodeMessageTest() FarAddress = _farAddress }; - byte[] data = _messageSerializationService.Serialize(message); + IByteBuffer data = _messageSerializationService.ZeroSerialize(message); FindNodeMsg deserializedMessage = _messageSerializationService.Deserialize(data); Assert.AreEqual(message.MsgType, deserializedMessage.MsgType); @@ -186,7 +187,7 @@ public void NeighborsMessageTest() FarAddress = _farAddress }; - byte[] data = _messageSerializationService.Serialize(message); + byte[] data = _messageSerializationService.ZeroSerialize(message).ReadAllBytesAsArray(); NeighborsMsg deserializedMessage = _messageSerializationService.Deserialize(data); Assert.AreEqual(message.MsgType, deserializedMessage.MsgType); diff --git a/src/Nethermind/Nethermind.Network.Discovery/Messages/INodeIdResolver.cs b/src/Nethermind/Nethermind.Network.Discovery/Messages/INodeIdResolver.cs index 60b5e6d9669..5af8ae34030 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Messages/INodeIdResolver.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Messages/INodeIdResolver.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -20,5 +20,5 @@ namespace Nethermind.Network.Discovery.Messages; public interface INodeIdResolver { - PublicKey GetNodeId(byte[] signature, int recoveryId, Span typeAndData); + PublicKey GetNodeId(ReadOnlySpan signature, int recoveryId, Span typeAndData); } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Messages/NodeIdResolver.cs b/src/Nethermind/Nethermind.Network.Discovery/Messages/NodeIdResolver.cs index 0ae89d7974b..73335a2fabf 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Messages/NodeIdResolver.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Messages/NodeIdResolver.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -28,8 +28,8 @@ public NodeIdResolver(IEcdsa ecdsa) _ecdsa = ecdsa; } - public PublicKey GetNodeId(byte[] signature, int recoveryId, Span typeAndData) + public PublicKey GetNodeId(ReadOnlySpan signature, int recoveryId, Span typeAndData) { - return _ecdsa.RecoverPublicKey(new Signature(signature, recoveryId), Keccak.Compute(typeAndData)); + return _ecdsa.RecoverPublicKey(new Signature(signature, recoveryId), Keccak.Compute(typeAndData)); } } diff --git a/src/Nethermind/Nethermind.Network.Discovery/NettyDiscoveryHandler.cs b/src/Nethermind/Nethermind.Network.Discovery/NettyDiscoveryHandler.cs index 9dc3a44bdaa..cc0e0e4ef65 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/NettyDiscoveryHandler.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/NettyDiscoveryHandler.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -80,12 +80,11 @@ public override void ChannelReadComplete(IChannelHandlerContext context) public async void SendMsg(DiscoveryMsg discoveryMsg) { - byte[] msgBytes; - + IByteBuffer msgBuffer; try { if (_logger.IsTrace) _logger.Trace($"Sending message: {discoveryMsg}"); - msgBytes = Serialize(discoveryMsg); + msgBuffer = Serialize(discoveryMsg, ByteBufferAllocator.UnpooledByteBufferAllocator); } catch (Exception e) { @@ -93,14 +92,13 @@ public async void SendMsg(DiscoveryMsg discoveryMsg) return; } - if (msgBytes.Length > 1280) + if (msgBuffer.ReadableBytes > 1280) { if (_logger.IsWarn) _logger.Warn($"Attempting to send message larger than 1280 bytes. This is out of spec and may not work for all client. Msg: ${discoveryMsg}"); } - IByteBuffer copiedBuffer = Unpooled.CopiedBuffer(msgBytes); - IAddressedEnvelope packet = new DatagramPacket(copiedBuffer, discoveryMsg.FarAddress); - + IAddressedEnvelope packet = new DatagramPacket(msgBuffer, discoveryMsg.FarAddress); + await _channel.WriteAndFlushAsync(packet).ContinueWith(t => { if (t.IsFaulted) @@ -109,7 +107,7 @@ await _channel.WriteAndFlushAsync(packet).ContinueWith(t => } }); - Interlocked.Add(ref Metrics.DiscoveryBytesSent, msgBytes.Length); + Interlocked.Add(ref Metrics.DiscoveryBytesSent, msgBuffer.ReadableBytes); } protected override void ChannelRead0(IChannelHandlerContext ctx, DatagramPacket packet) { @@ -118,7 +116,7 @@ protected override void ChannelRead0(IChannelHandlerContext ctx, DatagramPacket byte[] msgBytes = new byte[content.ReadableBytes]; content.ReadBytes(msgBytes); - + Interlocked.Add(ref Metrics.DiscoveryBytesReceived, msgBytes.Length); if (msgBytes.Length < 98) @@ -179,16 +177,16 @@ private DiscoveryMsg Deserialize(MsgType type, byte[] msg) }; } - private byte[] Serialize(DiscoveryMsg msg) + private IByteBuffer Serialize(DiscoveryMsg msg, ByteBufferAllocator allocator) { return msg.MsgType switch { - MsgType.Ping => _msgSerializationService.Serialize((PingMsg) msg), - MsgType.Pong => _msgSerializationService.Serialize((PongMsg) msg), - MsgType.FindNode => _msgSerializationService.Serialize((FindNodeMsg) msg), - MsgType.Neighbors => _msgSerializationService.Serialize((NeighborsMsg) msg), - MsgType.EnrRequest => _msgSerializationService.Serialize((EnrRequestMsg) msg), - MsgType.EnrResponse => _msgSerializationService.Serialize((EnrResponseMsg) msg), + MsgType.Ping => _msgSerializationService.ZeroSerialize((PingMsg)msg, allocator), + MsgType.Pong => _msgSerializationService.ZeroSerialize((PongMsg)msg, allocator), + MsgType.FindNode => _msgSerializationService.ZeroSerialize((FindNodeMsg)msg, allocator), + MsgType.Neighbors => _msgSerializationService.ZeroSerialize((NeighborsMsg)msg, allocator), + MsgType.EnrRequest => _msgSerializationService.ZeroSerialize((EnrRequestMsg)msg, allocator), + MsgType.EnrResponse => _msgSerializationService.ZeroSerialize((EnrResponseMsg)msg, allocator), _ => throw new Exception($"Unsupported messageType: {msg.MsgType}") }; } @@ -202,7 +200,7 @@ private bool ValidateMsg(DiscoveryMsg msg, MsgType type, EndPoint address, IChan if (_logger.IsDebug) _logger.Debug($"Received a discovery message that has expired {-timeToExpire} seconds ago, type: {type}, sender: {address}, message: {msg}"); return false; } - + if (msg.FarAddress == null) { if (NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(msg.FarAddress, "HANDLER disc v4", $"{msg.MsgType.ToString()} has null far address"); @@ -226,18 +224,18 @@ private bool ValidateMsg(DiscoveryMsg msg, MsgType type, EndPoint address, IChan return true; } - + private static void ReportMsgByType(DiscoveryMsg msg) { if (msg is PingMsg pingMsg) { - if(NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(pingMsg.FarAddress, "HANDLER disc v4", $"PING {pingMsg.SourceAddress.Address} -> {pingMsg.DestinationAddress?.Address}"); + if(NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(pingMsg.FarAddress, "HANDLER disc v4", $"PING {pingMsg.SourceAddress.Address} -> {pingMsg.DestinationAddress?.Address}"); } else { - if(NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(msg.FarAddress, "HANDLER disc v4", msg.MsgType.ToString()); + if(NetworkDiagTracer.IsEnabled) NetworkDiagTracer.ReportIncomingMessage(msg.FarAddress, "HANDLER disc v4", msg.MsgType.ToString()); } } - + public event EventHandler? OnChannelActivated; } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs index 13ecd1356d0..6e582857599 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/DiscoveryMsgSerializerBase.cs @@ -1,24 +1,26 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System.Net; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Crypto; using Nethermind.Network.Discovery.Messages; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Discovery.Serializers; @@ -39,68 +41,85 @@ protected DiscoveryMsgSerializerBase(IEcdsa ecdsa, _nodeIdResolver = nodeIdResolver ?? throw new ArgumentNullException(nameof(nodeIdResolver)); } - protected byte[] Serialize(byte type, Span data) + protected void Serialize(byte type, Span data, IByteBuffer byteBuffer) { - byte[] result = new byte[32 + 1 + data.Length + 64 + 1]; - Span resultSpan = result.AsSpan(); + int length = 32 + 1 + data.Length + 64 + 1; + byteBuffer.EnsureWritable(length); + Span resultSpan = stackalloc byte[length]; resultSpan[32 + 65] = type; data.CopyTo(resultSpan.Slice(32 + 65 + 1, data.Length)); - + Span payload = resultSpan.Slice(32 + 65); Keccak toSign = Keccak.Compute(payload); Signature signature = _ecdsa.Sign(_privateKey, toSign); signature.Bytes.AsSpan().CopyTo(resultSpan.Slice(32, 64)); resultSpan[32 + 64] = signature.RecoveryId; - + Span forMdc = resultSpan.Slice(32); ValueKeccak mdc = ValueKeccak.Compute(forMdc); mdc.BytesAsSpan.CopyTo(resultSpan.Slice(0,32)); - return result; + byteBuffer.EnsureWritable(resultSpan.Length); + byteBuffer.WriteBytes(resultSpan); } - protected (PublicKey FarPublicKey, byte[] Mdc, byte[] Data) PrepareForDeserialization(byte[] msg) + protected (PublicKey FarPublicKey, Memory Mdc, IByteBuffer Data) PrepareForDeserialization(IByteBuffer msg) { - if (msg.Length < 98) + if (msg.ReadableBytes < 98) { throw new NetworkingException("Incorrect message", NetworkExceptionType.Validation); } - - byte[] mdc = msg.Slice(0, 32); - Span signature = msg.AsSpan(32, 65); - // var type = new[] { msg[97] }; - byte[] data = msg.Slice(98, msg.Length - 98); - Span computedMdc = ValueKeccak.Compute(msg.AsSpan(32)).BytesAsSpan; - - if (!Bytes.AreEqual(mdc, computedMdc)) + IByteBuffer data = msg.Slice(98, msg.ReadableBytes - 98); + Memory msgBytes = msg.ReadAllBytesAsMemory(); + Memory mdc = msgBytes.Slice(0, 32); + Span sigAndData = msgBytes.Span.Slice(32); + Span computedMdc = ValueKeccak.Compute(sigAndData).BytesAsSpan; + + if (!Bytes.AreEqual(mdc.Span, computedMdc)) { throw new NetworkingException("Invalid MDC", NetworkExceptionType.Validation); } - - PublicKey nodeId = _nodeIdResolver.GetNodeId(signature.Slice(0, 64).ToArray(), signature[64], msg.AsSpan(97, msg.Length - 97)); + + PublicKey nodeId = _nodeIdResolver.GetNodeId(sigAndData.Slice(0, 64), sigAndData[64], sigAndData.Slice(65, sigAndData.Length - 65)); return (nodeId, mdc, data); } - protected static Rlp Encode(IPEndPoint address) + protected static void Encode(RlpStream stream, IPEndPoint address, int length) + { + stream.StartSequence(length); + stream.Encode(address.Address.GetAddressBytes()); + //tcp port + stream.Encode(address.Port); + //udp port + stream.Encode(address.Port); + } + + protected static int GetIPEndPointLength(IPEndPoint address) + { + int length = Rlp.LengthOf(address.Address.GetAddressBytes()); + length += Rlp.LengthOf(address.Port); + length += Rlp.LengthOf(address.Port); + return length; + } + + protected static void SerializeNode(RlpStream stream, IPEndPoint address, byte[] id) { - return Rlp.Encode( - Rlp.Encode(address.Address.GetAddressBytes()), - //tcp port - Rlp.Encode(address.Port), - //udp port - Rlp.Encode(address.Port) - ); + int length = GetLengthSerializeNode(address, id); + stream.StartSequence(length); + stream.Encode(address.Address.GetAddressBytes()); + //tcp port + stream.Encode(address.Port); + //udp port + stream.Encode(address.Port); + stream.Encode(id); } - protected static Rlp SerializeNode(IPEndPoint address, byte[] id) + protected static int GetLengthSerializeNode(IPEndPoint address, byte[] id) { - return Rlp.Encode( - Rlp.Encode(address.Address.GetAddressBytes()), - //tcp port - Rlp.Encode(address.Port), - //udp port - Rlp.Encode(address.Port), - Rlp.Encode(id) - ); + int length = Rlp.LengthOf(address.Address.GetAddressBytes()); + length += Rlp.LengthOf(address.Port); + length += Rlp.LengthOf(address.Port); + length += Rlp.LengthOf(id); + return length; } protected static IPEndPoint GetAddress(ReadOnlySpan ip, int port) diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrRequestMsgSerializer.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrRequestMsgSerializer.cs index 0c579bfa217..8547d55c13b 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrRequestMsgSerializer.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrRequestMsgSerializer.cs @@ -1,46 +1,55 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System.Buffers; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Crypto; using Nethermind.Network.Discovery.Messages; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Discovery.Serializers; -public class EnrRequestMsgSerializer : DiscoveryMsgSerializerBase, IMessageSerializer +public class EnrRequestMsgSerializer : DiscoveryMsgSerializerBase, IZeroInnerMessageSerializer { public EnrRequestMsgSerializer(IEcdsa ecdsa, IPrivateKeyGenerator nodeKey, INodeIdResolver nodeIdResolver) : base(ecdsa, nodeKey, nodeIdResolver) { } - public byte[] Serialize(EnrRequestMsg msg) + public void Serialize(IByteBuffer byteBuffer, EnrRequestMsg msg) { - // TODO: optimize - byte[] data = Rlp.Encode( - Rlp.Encode(msg.ExpirationTime) - ).Bytes; - - byte[] serializedMsg = Serialize((byte) msg.MsgType, data); - return serializedMsg; + int length = GetLength(msg, out int contentLength); + byte[] array = ArrayPool.Shared.Rent(length); + try + { + RlpStream stream = new(array); + stream.StartSequence(contentLength); + stream.Encode(msg.ExpirationTime); + Serialize((byte)msg.MsgType, stream.Data.AsSpan(0, length), byteBuffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } - public EnrRequestMsg Deserialize(byte[] msgBytes) + public EnrRequestMsg Deserialize(IByteBuffer msgBytes) { - (PublicKey FarPublicKey, byte[] Mdc, byte[] Data) results = PrepareForDeserialization(msgBytes); - RlpStream rlpStream = results.Data.AsRlpStream(); + (PublicKey FarPublicKey, Memory Mdc, IByteBuffer Data) results = PrepareForDeserialization(msgBytes); + NettyRlpStream rlpStream = new(results.Data); rlpStream.ReadSequenceLength(); long expirationTime = rlpStream.DecodeLong(); @@ -48,4 +57,10 @@ public EnrRequestMsg Deserialize(byte[] msgBytes) EnrRequestMsg msg = new (results.FarPublicKey, expirationTime); return msg; } + + public int GetLength(EnrRequestMsg message, out int contentLength) + { + contentLength = Rlp.LengthOf(message.ExpirationTime); + return Rlp.LengthOfSequence(contentLength); + } } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrResponseMsgSerializer.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrResponseMsgSerializer.cs index afde35c125a..48284856cc8 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrResponseMsgSerializer.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/EnrResponseMsgSerializer.cs @@ -1,29 +1,32 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System.Buffers; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Crypto; using Nethermind.Network.Discovery.Messages; using Nethermind.Network.Enr; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Discovery.Serializers; -public class EnrResponseMsgSerializer : DiscoveryMsgSerializerBase, IMessageSerializer +public class EnrResponseMsgSerializer : DiscoveryMsgSerializerBase, IZeroInnerMessageSerializer { private readonly NodeRecordSigner _nodeRecordSigner; @@ -33,25 +36,31 @@ public EnrResponseMsgSerializer(IEcdsa ecdsa, IPrivateKeyGenerator nodeKey, INod _nodeRecordSigner = new NodeRecordSigner(ecdsa, nodeKey.Generate()); } - public byte[] Serialize(EnrResponseMsg msg) + public void Serialize(IByteBuffer byteBuffer, EnrResponseMsg msg) { int contentLength = Rlp.LengthOfKeccakRlp; contentLength += msg.NodeRecord.GetRlpLengthWithSignature(); int totalLength = Rlp.LengthOfSequence(contentLength); - RlpStream rlpStream = new (totalLength); - rlpStream.StartSequence(contentLength); - rlpStream.Encode(msg.RequestKeccak); - msg.NodeRecord.Encode(rlpStream); - - byte[] serializedMsg = Serialize((byte)msg.MsgType, rlpStream.Data); - return serializedMsg; + byte[] array = ArrayPool.Shared.Rent(totalLength); + try + { + RlpStream rlpStream = new(array); + rlpStream.StartSequence(contentLength); + rlpStream.Encode(msg.RequestKeccak); + msg.NodeRecord.Encode(rlpStream); + Serialize((byte)msg.MsgType, rlpStream.Data.AsSpan(0, totalLength), byteBuffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } - public EnrResponseMsg Deserialize(byte[] msgBytes) + public EnrResponseMsg Deserialize(IByteBuffer msgBytes) { - (PublicKey? farPublicKey, _, byte[]? data) = PrepareForDeserialization(msgBytes); - RlpStream rlpStream = data.AsRlpStream(); + (PublicKey? farPublicKey, _, IByteBuffer? data) = PrepareForDeserialization(msgBytes); + NettyRlpStream rlpStream = new(data); rlpStream.ReadSequenceLength(); Keccak? requestKeccak = rlpStream.DecodeKeccak(); // skip (not sure if needed to verify) @@ -59,11 +68,18 @@ public EnrResponseMsg Deserialize(byte[] msgBytes) NodeRecord nodeRecord = _nodeRecordSigner.Deserialize(rlpStream); if (!_nodeRecordSigner.Verify(nodeRecord)) { - string resHex = data.Slice(positionForHex).ToHexString(); + string resHex = data.ReadBytes(positionForHex).ReadAllHex(); throw new NetworkingException($"Invalid ENR signature: {resHex}", NetworkExceptionType.Discovery); } - + EnrResponseMsg msg = new(farPublicKey, nodeRecord, requestKeccak!); return msg; } + + public int GetLength(EnrResponseMsg msg, out int contentLength) + { + contentLength = Rlp.LengthOfKeccakRlp; + contentLength += msg.NodeRecord.GetRlpLengthWithSignature(); + return Rlp.LengthOfSequence(contentLength); + } } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/FindNodeMsgSerializer.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/FindNodeMsgSerializer.cs index e2cbca0bf09..edc6bef1687 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/FindNodeMsgSerializer.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/FindNodeMsgSerializer.cs @@ -1,48 +1,56 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System.Buffers; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Crypto; using Nethermind.Network.Discovery.Messages; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Discovery.Serializers; -public class FindNodeMsgSerializer : DiscoveryMsgSerializerBase, IMessageSerializer +public class FindNodeMsgSerializer : DiscoveryMsgSerializerBase, IZeroInnerMessageSerializer { public FindNodeMsgSerializer(IEcdsa ecdsa, IPrivateKeyGenerator nodeKey, INodeIdResolver nodeIdResolver) : base(ecdsa, nodeKey, nodeIdResolver) { } - public byte[] Serialize(FindNodeMsg msg) + public void Serialize(IByteBuffer byteBuffer, FindNodeMsg msg) { - byte[] data = Rlp.Encode( - Rlp.Encode(msg.SearchedNodeId), - //verify if encoding is correct - Rlp.Encode(msg.ExpirationTime) - ).Bytes; - - byte[] serializedMsg = Serialize((byte) msg.MsgType, data); - return serializedMsg; + int length = GetLength(msg, out int contentLength); + byte[] array = ArrayPool.Shared.Rent(length); + try + { + RlpStream stream = new(array); + stream.StartSequence(contentLength); + stream.Encode(msg.SearchedNodeId); + stream.Encode(msg.ExpirationTime); + Serialize((byte)msg.MsgType, stream.Data.AsSpan(0, length), byteBuffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } - public FindNodeMsg Deserialize(byte[] msgBytes) + public FindNodeMsg Deserialize(IByteBuffer msgBytes) { - (PublicKey FarPublicKey, byte[] Mdc, byte[] Data) results = PrepareForDeserialization(msgBytes); - RlpStream rlpStream = results.Data.AsRlpStream(); - + (PublicKey FarPublicKey, Memory Mdc, IByteBuffer Data) results = PrepareForDeserialization(msgBytes); + NettyRlpStream rlpStream = new(results.Data); rlpStream.ReadSequenceLength(); byte[] searchedNodeId = rlpStream.DecodeByteArray(); long expirationTime = rlpStream.DecodeLong(); @@ -50,4 +58,12 @@ public FindNodeMsg Deserialize(byte[] msgBytes) FindNodeMsg findNodeMsg = new (results.FarPublicKey, expirationTime, searchedNodeId); return findNodeMsg; } + + public int GetLength(FindNodeMsg msg, out int contentLength) + { + contentLength = Rlp.LengthOf(msg.SearchedNodeId); + contentLength += Rlp.LengthOf(msg.ExpirationTime); + + return Rlp.LengthOfSequence(contentLength); + } } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/NeighborsMsgSerializer.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/NeighborsMsgSerializer.cs index 7787a9990ac..557487e5862 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/NeighborsMsgSerializer.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/NeighborsMsgSerializer.cs @@ -1,29 +1,32 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System.Buffers; using System.Net; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Crypto; using Nethermind.Network.Discovery.Messages; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; using Nethermind.Stats.Model; namespace Nethermind.Network.Discovery.Serializers; -public class NeighborsMsgSerializer : DiscoveryMsgSerializerBase, IMessageSerializer +public class NeighborsMsgSerializer : DiscoveryMsgSerializerBase, IZeroInnerMessageSerializer { public NeighborsMsgSerializer(IEcdsa ecdsa, IPrivateKeyGenerator nodeKey, @@ -31,34 +34,44 @@ public NeighborsMsgSerializer(IEcdsa ecdsa, { } - public byte[] Serialize(NeighborsMsg msg) + public void Serialize(IByteBuffer byteBuffer, NeighborsMsg msg) { - Rlp[]? nodes = null; - if (msg.Nodes.Any()) + (int totalLength, int contentLength, int nodesContentLength) = GetLength(msg); + + byte[] array = ArrayPool.Shared.Rent(totalLength); + try { - nodes = new Rlp[msg.Nodes.Length]; - for (int i = 0; i < msg.Nodes.Length; i++) + RlpStream stream = new(array); + stream.StartSequence(contentLength); + if (msg.Nodes.Any()) { - Node node = msg.Nodes[i]; - Rlp serializedNode = SerializeNode(node.Address, node.Id.Bytes); - nodes[i] = serializedNode; + stream.StartSequence(nodesContentLength); + for (int i = 0; i < msg.Nodes.Length; i++) + { + Node node = msg.Nodes[i]; + SerializeNode(stream, node.Address, node.Id.Bytes); + } + } + else + { + stream.Encode(Rlp.OfEmptySequence); } - } - byte[] data = Rlp.Encode( - nodes == null ? Rlp.OfEmptySequence : Rlp.Encode(nodes), - Rlp.Encode(msg.ExpirationTime) - ).Bytes; + stream.Encode(msg.ExpirationTime); - byte[] serializedMsg = Serialize((byte) msg.MsgType, data); - return serializedMsg; + Serialize((byte)msg.MsgType, stream.Data.AsSpan(0, totalLength), byteBuffer); + } + finally + { + ArrayPool.Shared.Return(array); + } } - public NeighborsMsg Deserialize(byte[] msgBytes) + public NeighborsMsg Deserialize(IByteBuffer msgBytes) { - (PublicKey FarPublicKey, byte[] Mdc, byte[] Data) results = PrepareForDeserialization(msgBytes); + (PublicKey FarPublicKey, Memory Mdc, IByteBuffer Data) results = PrepareForDeserialization(msgBytes); - RlpStream rlp = results.Data.AsRlpStream(); + NettyRlpStream rlp = new(results.Data); rlp.ReadSequenceLength(); Node[] nodes = DeserializeNodes(rlp) as Node[]; @@ -85,4 +98,39 @@ public NeighborsMsg Deserialize(byte[] msgBytes) return new Node(new PublicKey(id), address); }); } + + private int GetNodesLength(Node[] nodes, out int contentLength) + { + contentLength = 0; + for (int i = 0; i < nodes.Length; i++) + { + Node node = nodes[i]; + contentLength += Rlp.LengthOfSequence(GetLengthSerializeNode(node.Address, node.Id.Bytes)); + } + return Rlp.LengthOfSequence(contentLength); + } + + public int GetLength(NeighborsMsg msg, out int contentLength) + { + (int totalLength, contentLength, int _) = GetLength(msg); + return totalLength; + } + + private (int totalLength, int contentLength, int nodesContentLength) GetLength(NeighborsMsg msg) + { + int nodesContentLength = 0; + int contentLength = 0; + if (msg.Nodes.Any()) + { + contentLength += GetNodesLength(msg.Nodes, out nodesContentLength); + } + else + { + contentLength += Rlp.OfEmptySequence.Bytes.Length; + } + + contentLength += Rlp.LengthOf(msg.ExpirationTime); + + return (Rlp.LengthOfSequence(contentLength), contentLength, nodesContentLength); + } } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/PingMsgSerializer.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/PingMsgSerializer.cs index 2f327be7ae5..7471a22b60e 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/PingMsgSerializer.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/PingMsgSerializer.cs @@ -1,82 +1,85 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System.Buffers; using System.Net; +using DotNetty.Buffers; using DotNetty.Common.Utilities; using Nethermind.Core.Crypto; using Nethermind.Crypto; using Nethermind.Network.Discovery.Messages; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Discovery.Serializers; -public class PingMsgSerializer : DiscoveryMsgSerializerBase, IMessageSerializer +public class PingMsgSerializer : DiscoveryMsgSerializerBase, IZeroInnerMessageSerializer { public PingMsgSerializer(IEcdsa ecdsa, IPrivateKeyGenerator nodeKey, INodeIdResolver nodeIdResolver) : base(ecdsa, nodeKey, nodeIdResolver) { } - public byte[] Serialize(PingMsg msg) + public void Serialize(IByteBuffer byteBuffer, PingMsg msg) { - byte typeByte = (byte)msg.MsgType; - Rlp source = Encode(msg.SourceAddress); - Rlp destination = Encode(msg.DestinationAddress); + (int totalLength, int contentLength, int sourceAddressLength, int destinationAddressLength) = GetLength(msg); - byte[] data; - if (msg.EnrSequence.HasValue) + byte[] array = ArrayPool.Shared.Rent(totalLength); + try { - data = Rlp.Encode( - Rlp.Encode(msg.Version), - source, - destination, - //verify if encoding is correct - Rlp.Encode(msg.ExpirationTime), - Rlp.Encode(msg.EnrSequence.Value)).Bytes; + RlpStream stream = new(array); + + byte typeByte = (byte)msg.MsgType; + + stream.StartSequence(contentLength); + stream.Encode(msg.Version); + Encode(stream, msg.SourceAddress, sourceAddressLength); + Encode(stream, msg.DestinationAddress, destinationAddressLength); + stream.Encode(msg.ExpirationTime); + + if (msg.EnrSequence.HasValue) + { + stream.Encode(msg.EnrSequence.Value); + } + + Serialize(typeByte, stream.Data.AsSpan(0, totalLength), byteBuffer); + byteBuffer.MarkReaderIndex(); + msg.Mdc = byteBuffer.Slice(0, 32).ReadAllBytesAsArray(); + byteBuffer.ResetReaderIndex(); } - else + finally { - data = Rlp.Encode( - Rlp.Encode(msg.Version), - source, - destination, - //verify if encoding is correct - Rlp.Encode(msg.ExpirationTime)).Bytes; + ArrayPool.Shared.Return(array); } - - byte[] serializedMsg = Serialize(typeByte, data); - msg.Mdc = serializedMsg.Slice(0, 32); - - return serializedMsg; } - public PingMsg Deserialize(byte[] msgBytes) + public PingMsg Deserialize(IByteBuffer msgBytes) { - (PublicKey FarPublicKey, byte[] Mdc, byte[] Data) results = PrepareForDeserialization(msgBytes); - RlpStream rlp = results.Data.AsRlpStream(); + (PublicKey FarPublicKey, Memory Mdc, IByteBuffer Data) results = PrepareForDeserialization(msgBytes); + NettyRlpStream rlp = new (results.Data); rlp.ReadSequenceLength(); int version = rlp.DecodeInt(); rlp.ReadSequenceLength(); ReadOnlySpan sourceAddress = rlp.DecodeByteArraySpan(); - + // TODO: please note that we decode only one field for port and if the UDP is different from TCP then // our discovery messages will not be routed correctly (the fix will not be part of this commit) rlp.DecodeInt(); // UDP port - int tcpPort = rlp.DecodeInt(); // we assume here that UDP and TCP port are same + int tcpPort = rlp.DecodeInt(); // we assume here that UDP and TCP port are same IPEndPoint source = GetAddress(sourceAddress, tcpPort); rlp.ReadSequenceLength(); @@ -85,9 +88,8 @@ public PingMsg Deserialize(byte[] msgBytes) rlp.DecodeInt(); // UDP port long expireTime = rlp.DecodeLong(); - PingMsg msg = new(results.FarPublicKey, expireTime, source, destination, results.Mdc); - - msg.Version = version; + PingMsg msg = new(results.FarPublicKey, expireTime, source, destination, results.Mdc.ToArray()) { Version = version }; + if (version == 4) { if (!rlp.HasBeenRead) @@ -103,4 +105,30 @@ public PingMsg Deserialize(byte[] msgBytes) return msg; } + + public int GetLength(PingMsg msg, out int contentLength) + { + (int totalLength, contentLength, int _, int _) = + GetLength(msg); + return totalLength; + } + + + private (int totalLength, int contentLength, int sourceAddressLength, int destinationAddressLength) GetLength(PingMsg msg) + { + int sourceAddressLength = GetIPEndPointLength(msg.SourceAddress); + int destinationAddressLength = GetIPEndPointLength(msg.DestinationAddress); + + int contentLength = Rlp.LengthOf(msg.Version) + + Rlp.LengthOfSequence(sourceAddressLength) + + Rlp.LengthOfSequence(destinationAddressLength) + + Rlp.LengthOf(msg.ExpirationTime); + + if (msg.EnrSequence.HasValue) + { + contentLength += Rlp.LengthOf(msg.EnrSequence.Value); + } + + return (Rlp.LengthOfSequence(contentLength), contentLength, sourceAddressLength, destinationAddressLength); + } } diff --git a/src/Nethermind/Nethermind.Network.Discovery/Serializers/PongMsgSerializer.cs b/src/Nethermind/Nethermind.Network.Discovery/Serializers/PongMsgSerializer.cs index a2cb9150475..0e2960a687f 100644 --- a/src/Nethermind/Nethermind.Network.Discovery/Serializers/PongMsgSerializer.cs +++ b/src/Nethermind/Nethermind.Network.Discovery/Serializers/PongMsgSerializer.cs @@ -1,55 +1,67 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System.Buffers; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Crypto; using Nethermind.Network.Discovery.Messages; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Discovery.Serializers; -public class PongMsgSerializer : DiscoveryMsgSerializerBase, IMessageSerializer +public class PongMsgSerializer : DiscoveryMsgSerializerBase, IZeroInnerMessageSerializer { public PongMsgSerializer(IEcdsa ecdsa, IPrivateKeyGenerator nodeKey, INodeIdResolver nodeIdResolver) : base(ecdsa, nodeKey, nodeIdResolver) { } - public byte[] Serialize(PongMsg msg) + public void Serialize(IByteBuffer byteBuffer, PongMsg msg) { if (msg.FarAddress is null) { - throw new NetworkingException($"Sending discovery message without {nameof(msg.FarAddress)} set.", - NetworkExceptionType.Discovery); + throw new NetworkingException($"Sending discovery message without {nameof(msg.FarAddress)} set.", NetworkExceptionType.Discovery); + } + + (int totalLength, int contentLength, int farAddressLength) = GetLength(msg); + byteBuffer.EnsureWritable(totalLength); + + byte[] array = ArrayPool.Shared.Rent(totalLength); + try + { + RlpStream stream = new(array); + stream.StartSequence(contentLength); + Encode(stream, msg.FarAddress, farAddressLength); + stream.Encode(msg.PingMdc); + stream.Encode(msg.ExpirationTime); + + Serialize((byte)msg.MsgType, stream.Data.AsSpan(0, totalLength), byteBuffer); + } + finally + { + ArrayPool.Shared.Return(array); } - - byte[] data = Rlp.Encode( - Encode(msg.FarAddress), - Rlp.Encode(msg.PingMdc), - Rlp.Encode(msg.ExpirationTime) - ).Bytes; - - byte[] serializedMsg = Serialize((byte) msg.MsgType, data); - return serializedMsg; } - public PongMsg Deserialize(byte[] msgBytes) + public PongMsg Deserialize(IByteBuffer msgBytes) { - (PublicKey FarPublicKey, byte[] Mdc, byte[] Data) results = PrepareForDeserialization(msgBytes); + (PublicKey FarPublicKey, Memory Mdc, IByteBuffer Data) results = PrepareForDeserialization(msgBytes); - RlpStream rlp = results.Data.AsRlpStream(); + NettyRlpStream rlp = new(results.Data); rlp.ReadSequenceLength(); rlp.ReadSequenceLength(); @@ -64,4 +76,26 @@ public PongMsg Deserialize(byte[] msgBytes) PongMsg msg = new(results.FarPublicKey, expirationTime, token); return msg; } + + public int GetLength(PongMsg message, out int contentLength) + { + (int totalLength, contentLength, int _) = GetLength(message); + return totalLength; + } + + private (int totalLength, int contentLength, int farAddressLength) GetLength(PongMsg message) + { + if (message.FarAddress is null) + { + throw new NetworkingException($"Sending discovery message without {nameof(message.FarAddress)} set.", + NetworkExceptionType.Discovery); + } + + int farAddressLength = GetIPEndPointLength(message.FarAddress); + int contentLength = Rlp.LengthOfSequence(farAddressLength); + contentLength += Rlp.LengthOf(message.PingMdc); + contentLength += Rlp.LengthOf(message.ExpirationTime); + + return (Rlp.LengthOfSequence(contentLength), contentLength, farAddressLength); + } } diff --git a/src/Nethermind/Nethermind.Network.Test/Builders/SerializationBuilder.cs b/src/Nethermind/Nethermind.Network.Test/Builders/SerializationBuilder.cs index 9637cbc68da..1092135b411 100644 --- a/src/Nethermind/Nethermind.Network.Test/Builders/SerializationBuilder.cs +++ b/src/Nethermind/Nethermind.Network.Test/Builders/SerializationBuilder.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -37,12 +37,6 @@ public SerializationBuilder(ITimestamper timestamper = null) TestObject = new MessageSerializationService(); } - public SerializationBuilder With(IMessageSerializer serializer) where T : MessageBase - { - TestObject.Register(serializer); - return this; - } - public SerializationBuilder With(IZeroMessageSerializer serializer) where T : MessageBase { TestObject.Register(serializer); @@ -84,7 +78,7 @@ public SerializationBuilder WithEth65() .With(new GetPooledTransactionsMessageSerializer()) .With(new PooledTransactionsMessageSerializer()); } - + public SerializationBuilder WithEth66() { return WithEth65() diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs index 3541691bb82..f7c62ff73b8 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/P2PProtocolHandlerTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -45,7 +45,7 @@ public void Setup() private Packet CreatePacket(P2PMessage message) { - return new(message.Protocol, message.PacketType, _serializer.Serialize(message)); + return new(message.Protocol, message.PacketType, _serializer.ZeroSerialize(message).ReadAllBytesAsArray()); } private const int ListenPort = 8003; @@ -59,7 +59,7 @@ private P2PProtocolHandler CreateSession() return new P2PProtocolHandler( _session, TestItem.PublicKeyA, - new NodeStatsManager(timerFactory, LimboLogs.Instance), + new NodeStatsManager(timerFactory, LimboLogs.Instance), _serializer, LimboLogs.Instance); } @@ -72,7 +72,7 @@ public void On_init_sends_a_hello_message() _session.Received(1).DeliverMessage(Arg.Any()); } - + [Test] public void On_init_sends_a_hello_message_with_capabilities() { diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs index c2e80917cd7..bcbf0bfeac1 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/PacketSenderTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -31,32 +31,32 @@ public class PacketSenderTests [Test] public void Does_send_on_active_channel() { - byte[] serialized = new byte[2]; + IByteBuffer serialized = PooledByteBufferAllocator.Default.Buffer(2); var serializer = Substitute.For(); - serializer.Serialize(PingMessage.Instance).Returns(serialized); + serializer.ZeroSerialize(PingMessage.Instance).Returns(serialized); IChannelHandlerContext context = Substitute.For(); IChannel channel = Substitute.For(); channel.Active.Returns(true); context.Channel.Returns(channel); - + PacketSender packetSender = new(serializer, LimboLogs.Instance); packetSender.HandlerAdded(context); packetSender.Enqueue(PingMessage.Instance); context.Received(1).WriteAndFlushAsync(Arg.Any()); } - + [Test] public void Does_not_try_to_send_on_inactive_channel() { - byte[] serialized = new byte[2]; + IByteBuffer serialized = PooledByteBufferAllocator.Default.Buffer(2); var serializer = Substitute.For(); - serializer.Serialize(PingMessage.Instance).Returns(serialized); + serializer.ZeroSerialize(PingMessage.Instance).Returns(serialized); IChannelHandlerContext context = Substitute.For(); IChannel channel = Substitute.For(); channel.Active.Returns(false); context.Channel.Returns(channel); - + PacketSender packetSender = new(serializer ,LimboLogs.Instance); packetSender.HandlerAdded(context); packetSender.Enqueue(PingMessage.Instance); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs b/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs index 91cdc191053..41578b0c9e3 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/SerializerTester.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -27,19 +27,6 @@ namespace Nethermind.Network.Test.P2P { public static class SerializerTester { - public static void Test(IMessageSerializer serializer, T message, string expectedData = null) where T : P2PMessage - { - byte[] serialized = serializer.Serialize(message); - T deserialized = serializer.Deserialize(serialized); - deserialized.Should().BeEquivalentTo(message); - byte[] serializedAgain = serializer.Serialize(deserialized); - Assert.AreEqual(serialized.ToHexString(), serializedAgain.ToHexString(), "test old way"); - - if (expectedData != null) - { - Assert.AreEqual(expectedData, serialized.ToHexString()); - } - } public static void TestZero(IZeroMessageSerializer serializer, T message, string expectedData = null) where T : P2PMessage { @@ -49,18 +36,18 @@ public static void TestZero(IZeroMessageSerializer serializer, T message, { serializer.Serialize(buffer, message); T deserialized = serializer.Deserialize(buffer); - + // RlpLength is calculated explicitly when serializing an object by Calculate method. It's null after deserialization. deserialized.Should().BeEquivalentTo(message, options => options.Excluding(c => c.Name == "RlpLength")); - + Assert.AreEqual(0, buffer.ReadableBytes, "readable bytes"); - + serializer.Serialize(buffer2, deserialized); buffer.SetReaderIndex(0); string allHex = buffer.ReadAllHex(); Assert.AreEqual(allHex, buffer2.ReadAllHex(), "test zero"); - + if (expectedData != null) { allHex.Should().BeEquivalentTo(expectedData); diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs index 1f48b9cce24..9f8194c0690 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V62/ZeroNewBlockMessageSerializerTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -41,7 +41,7 @@ public void Roundtrip() NewBlockMessageSerializer serializer = new(); serializer.Serialize(byteBuffer, newBlockMessage); byte[] expectedBytes = Bytes.FromHexString("f90243f9023ff901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a01afbbda2cfebd56d2d0d1288617084931eb82bc346c678cac5eeff7c7a078e36a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8f840df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080c080"); - byte[] bytes = byteBuffer.ReadAllBytes(); + byte[] bytes = byteBuffer.ReadAllBytesAsArray(); Assert.AreEqual(expectedBytes.ToHexString(), bytes.ToHexString(), "bytes"); } @@ -67,7 +67,7 @@ public void Roundtrip2() serializer.Serialize(byteBuffer, newBlockMessage); byte[] expectedBytes = Bytes.FromHexString("f90243f9023ff901f9a0ff483e972a04a9a62bb4b7d04ae403c615604e4090521ecc5bb7af67f71be09ca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a01afbbda2cfebd56d2d0d1288617084931eb82bc346c678cac5eeff7c7a078e36a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830f424080833d090080830f424083010203a02ba5557a4c62a513c7e56d1bf13373e0da6bec016755483e91589fe1c6d212e28800000000000003e8f840df80018252089400000000000000000000000000000000000000000180808080df80018252089400000000000000000000000000000000000000000180808080c080"); - byte[] bytes = byteBuffer.ReadAllBytes(); + byte[] bytes = byteBuffer.ReadAllBytesAsArray(); Assert.AreEqual(expectedBytes.ToHexString(), bytes.ToHexString(), "bytes"); } diff --git a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs index 59644bddc2d..d71a79d57bc 100644 --- a/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/P2P/Subprotocols/Eth/V63/ReceiptsMessageSerializerTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -69,26 +69,29 @@ private static void Test(TxReceipt[][] txReceipts) Assert.AreEqual(0L, deserialized.TxReceipts[i][j].BlockNumber, $"receipts[{i}][{j}].BlockNumber"); Assert.Null(deserialized.TxReceipts[i][j].ContractAddress, $"receipts[{i}][{j}].ContractAddress"); Assert.AreEqual(0L, deserialized.TxReceipts[i][j].GasUsed, $"receipts[{i}][{j}].GasUsed"); - Assert.AreEqual(txReceipts[i][j].BlockNumber < RopstenSpecProvider.ByzantiumBlockNumber ? 0 : txReceipts[i][j].StatusCode, deserialized.TxReceipts[i][j].StatusCode, $"receipts[{i}][{j}].StatusCode"); Assert.AreEqual(txReceipts[i][j].GasUsedTotal, deserialized.TxReceipts[i][j].GasUsedTotal, $"receipts[{i}][{j}].GasUsedTotal"); - Assert.AreEqual(txReceipts[i][j].BlockNumber < RopstenSpecProvider.ByzantiumBlockNumber ? txReceipts[i][j].PostTransactionState : null, deserialized.TxReceipts[i][j].PostTransactionState, $"receipts[{i}][{j}].PostTransactionState"); + if (!txReceipts[i][j].SkipStateAndStatusInRlp) + { + Assert.AreEqual(txReceipts[i][j].BlockNumber < RopstenSpecProvider.ByzantiumBlockNumber ? 0 : txReceipts[i][j].StatusCode, deserialized.TxReceipts[i][j].StatusCode, $"receipts[{i}][{j}].StatusCode"); + Assert.AreEqual(txReceipts[i][j].BlockNumber < RopstenSpecProvider.ByzantiumBlockNumber ? txReceipts[i][j].PostTransactionState : null, deserialized.TxReceipts[i][j].PostTransactionState, $"receipts[{i}][{j}].PostTransactionState"); + } } } } } } } - + [Test] public void Roundtrip() - { + { TxReceipt[][] data = {new[] {Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject}, new[] {Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject}}; Test(data); } - + [Test] public void Roundtrip_with_IgnoreOutputs() - { + { TxReceipt[][] data = {new[] {Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).TestObject}, new[] {Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject}}; foreach (TxReceipt[] receipts in data) { @@ -96,10 +99,10 @@ public void Roundtrip_with_IgnoreOutputs() } Test(data); } - + [Test] public void Roundtrip_with_eip658() - { + { TxReceipt[][] data = {new[] {Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject}, new[] {Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(RopstenSpecProvider.ConstantinopleBlockNumber).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject}}; Test(data); } @@ -116,14 +119,14 @@ public void Roundtrip_with_nulls() TxReceipt[][] data = {new[] {Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject}, null, new[] {null, Build.A.Receipt.WithAllFieldsFilled.TestObject}}; Test(data); } - + [Test] public void Deserialize_empty() { ReceiptsMessageSerializer serializer = new(RopstenSpecProvider.Instance); serializer.Deserialize(new byte[0]).TxReceipts.Should().HaveCount(0); } - + [Test] public void Roundtrip_mainnet_sample() { @@ -132,18 +135,18 @@ public void Roundtrip_mainnet_sample() ReceiptsMessage message = serializer.Deserialize(bytes); byte[] serialized = serializer.Serialize(message); Assert.AreEqual(bytes, serialized); - } - + } + [Test] public void Roundtrip_one_receipt_with_accessList() - { + { TxReceipt[][] data = {new[] {Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject }}; Test(data); } - + [Test] public void Roundtrip_with_both_txTypes_of_receipt() - { + { TxReceipt[][] data = {new[] {Build.A.Receipt.WithAllFieldsFilled.TestObject, Build.A.Receipt.WithAllFieldsFilled.WithBlockNumber(0).WithTxType(TxType.AccessList).TestObject}, new[] {Build.A.Receipt.WithAllFieldsFilled.WithTxType(TxType.AccessList).TestObject, Build.A.Receipt.WithAllFieldsFilled.TestObject}}; Test(data); } diff --git a/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs b/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs index a8953f48aa0..abb2893a3c2 100644 --- a/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/ProtocolsManagerTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -183,7 +183,11 @@ public Context VerifyDisconnected() public Context ReceiveDisconnect() { DisconnectMessage message = new(DisconnectReason.Other); - _currentSession.ReceiveMessage(new Packet("p2p", P2PMessageCode.Disconnect, _serializer.Serialize(message))); + IByteBuffer disconnectPacket = _serializer.ZeroSerialize(message); + + // to account for AdaptivePacketType byte + disconnectPacket.ReadByte(); + _currentSession.ReceiveMessage(new ZeroPacket(disconnectPacket){ PacketType = P2PMessageCode.Disconnect }); return this; } @@ -213,7 +217,7 @@ public Context ReceiveStatus() msg.GenesisHash = _blockTree.Genesis.Hash; msg.BestHash = _blockTree.Genesis.Hash; msg.ProtocolVersion = 63; - + return ReceiveStatus(msg); } @@ -243,6 +247,17 @@ public Context VerifySyncPeersRemoved() return this; } + private Context ReceiveHello(HelloMessage msg) + { + IByteBuffer helloPacket = _serializer.ZeroSerialize(msg); + // to account for AdaptivePacketType byte + helloPacket.ReadByte(); + + _currentSession.ReceiveMessage(new ZeroPacket(helloPacket){ PacketType = P2PMessageCode.Hello }); + return this; + } + + public Context ReceiveHello(byte p2pVersion = 5) { HelloMessage msg = new(); @@ -251,10 +266,10 @@ public Context ReceiveHello(byte p2pVersion = 5) msg.ClientId = "other client v1"; msg.P2PVersion = p2pVersion; msg.ListenPort = 30314; - _currentSession.ReceiveMessage(new Packet("p2p", P2PMessageCode.Hello, _serializer.Serialize(msg))); - return this; + + return ReceiveHello(msg); } - + public Context ReceiveHelloNoEth() { HelloMessage msg = new(); @@ -263,10 +278,9 @@ public Context ReceiveHelloNoEth() msg.ClientId = "other client v1"; msg.P2PVersion = 5; msg.ListenPort = 30314; - _currentSession.ReceiveMessage(new Packet("p2p", P2PMessageCode.Hello, _serializer.Serialize(msg))); - return this; + return ReceiveHello(msg); } - + public Context ReceiveHelloEth(int protocolVersion) { HelloMessage msg = new(); @@ -275,11 +289,10 @@ public Context ReceiveHelloEth(int protocolVersion) msg.ClientId = "other client v1"; msg.P2PVersion = 5; msg.ListenPort = 30314; - _currentSession.ReceiveMessage(new Packet("p2p", P2PMessageCode.Hello, _serializer.Serialize(msg))); - return this; + return ReceiveHello(msg); } - + public Context ReceiveHelloWrongEth() { return ReceiveHelloEth(61); @@ -412,7 +425,7 @@ public void Disconnects_on_missing_eth() .ReceiveHelloNoEth() .VerifyDisconnected(); } - + [Test] public void Disconnects_on_wrong_eth() { @@ -439,7 +452,7 @@ public void Disconnects_on_wrong_chain_id() .ReceiveStatusWrongChain() .VerifyDisconnected(); } - + [Test] public void Disconnects_on_wrong_genesis_hash() { @@ -453,7 +466,7 @@ public void Disconnects_on_wrong_genesis_hash() .ReceiveStatusWrongGenesis() .VerifyDisconnected(); } - + [Test] public void Initialized_with_eth66_only() { diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs index 0636bf265d0..891b75928e6 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/Handshake/EciesCipherTests.cs @@ -1,20 +1,21 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Core.Test.Builders; @@ -91,9 +92,8 @@ public void Can_decrypt_auth_message() Assert.AreEqual(authMessage.IsTokenUsed, false); Assert.NotNull(authMessage.Signature); - byte[] data = _messageSerializationService.Serialize(authMessage); - Array.Resize(ref data, deciphered.Length); - Assert.AreEqual(deciphered, data, "serialization"); + IByteBuffer data = _messageSerializationService.ZeroSerialize(authMessage); + Assert.AreEqual(deciphered, data.ReadAllBytesAsArray(), "serialization"); } [Test] @@ -124,10 +124,9 @@ public void Can_decrypt_auth_eip8_message() Assert.AreEqual(authMessage.Version, 4); Assert.NotNull(authMessage.Signature); - byte[] data = _messageSerializationService.Serialize(authMessage); - Array.Resize(ref data, deciphered.Length); + IByteBuffer data = _messageSerializationService.ZeroSerialize(authMessage); - Assert.AreEqual(deciphered.Slice(0, 169), data.Slice(0, 169), "serialization"); + Assert.AreEqual(deciphered.Slice(0, 169), data.Slice(0, 169).ReadAllBytesAsArray(), "serialization"); } [Test] @@ -147,9 +146,8 @@ public void Can_decrypt_ack() Assert.AreEqual(ackMessage.Nonce, NetTestVectors.NonceB); Assert.AreEqual(ackMessage.IsTokenUsed, false); - byte[] data = _messageSerializationService.Serialize(ackMessage); - Array.Resize(ref data, deciphered.Length); - Assert.AreEqual(deciphered, data, "serialization"); + IByteBuffer data = _messageSerializationService.ZeroSerialize(ackMessage); + Assert.AreEqual(deciphered, data.ReadAllBytesAsArray(), "serialization"); } [Test] @@ -181,11 +179,10 @@ public void Can_decrypt_ack_eip8_message() Assert.AreEqual(ackMessage.Nonce, NetTestVectors.NonceB); Assert.AreEqual(ackMessage.Version, 4); - byte[] data = _messageSerializationService.Serialize(ackMessage); - Array.Resize(ref data, deciphered.Length); + IByteBuffer data = _messageSerializationService.ZeroSerialize(ackMessage); // TODO: check 102 - Assert.AreEqual(deciphered.Slice(0, 102), data.Slice(0, 102), "serialization"); + Assert.AreEqual(deciphered.Slice(0, 102), data.ReadAllBytesAsArray().Slice(0, 102), "serialization"); } [Test] diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs index 140a8398c2a..6a20b9a2c94 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/SnappyTests.cs @@ -58,7 +58,7 @@ public byte[] TestEncode(byte[] input) { var result = UnpooledByteBufferAllocator.Default.Buffer(); Encode(null, input.ToUnpooledByteBuffer(), result); - return result.ReadAllBytes(); + return result.ReadAllBytesAsArray(); } } diff --git a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs index 0ee477dd22a..ac89aca4c3d 100644 --- a/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs +++ b/src/Nethermind/Nethermind.Network.Test/Rlpx/ZeroNettyFrameMergerTests.cs @@ -174,7 +174,7 @@ public void Can_decode_neth_message() Assert.AreEqual(0, output.PacketType); - byte[] outputBytes = output.Content.ReadAllBytes(); + byte[] outputBytes = output.Content.ReadAllBytesAsArray(); HelloMessageSerializer serializer = new(); HelloMessage helloMessage = serializer.Deserialize(outputBytes); @@ -204,7 +204,7 @@ public void Can_merge_big_frame() Assert.NotNull(output); Assert.AreEqual(32, output.PacketType); - output.Content.ReadAllBytes(); + output.Content.ReadAllBytesAsArray(); } finally { diff --git a/src/Nethermind/Nethermind.Network/ByteBufferExtensions.cs b/src/Nethermind/Nethermind.Network/ByteBufferExtensions.cs new file mode 100644 index 00000000000..d3fb0ac163b --- /dev/null +++ b/src/Nethermind/Nethermind.Network/ByteBufferExtensions.cs @@ -0,0 +1,70 @@ +// Copyright (c) 2021 Demerzel Solutions Limited +// This file is part of the Nethermind library. +// +// The Nethermind library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The Nethermind library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the Nethermind. If not, see . + +using System; +using DotNetty.Buffers; +using Nethermind.Core.Extensions; + +namespace Nethermind.Network +{ + public static class ByteBufferExtensions + { + public static byte[] ReadAllBytesAsArray(this IByteBuffer buffer) + { + byte[] bytes = new byte[buffer.ReadableBytes]; + buffer.ReadBytes(bytes); + return bytes; + } + + public static Span ReadAllBytesAsSpan(this IByteBuffer buffer) + { + if (buffer.HasArray) + { + Span bytes = buffer.Array.AsSpan(buffer.ArrayOffset + buffer.ReaderIndex, buffer.ReadableBytes); + buffer.SetReaderIndex(buffer.WriterIndex); + return bytes; + } + else + { + return buffer.ReadAllBytesAsArray().AsSpan(); + } + } + + public static Memory ReadAllBytesAsMemory(this IByteBuffer buffer) + { + if (buffer.HasArray) + { + Memory bytes = buffer.Array.AsMemory(buffer.ArrayOffset + buffer.ReaderIndex, buffer.ReadableBytes); + buffer.SetReaderIndex(buffer.WriterIndex); + return bytes; + } + else + { + return buffer.ReadAllBytesAsArray().AsMemory(); + } + } + + public static string ReadAllHex(this IByteBuffer buffer) => buffer.ReadAllBytesAsSpan().ToHexString(); + + public static void WriteBytes(this IByteBuffer buffer, ReadOnlySpan bytes) + { + for (int i = 0; i < bytes.Length; i++) + { + buffer.WriteByte(bytes[i]); + } + } + } +} diff --git a/src/Nethermind/Nethermind.Network/IByteArrayExtensions.cs b/src/Nethermind/Nethermind.Network/IByteArrayExtensions.cs deleted file mode 100644 index c486f61f8d8..00000000000 --- a/src/Nethermind/Nethermind.Network/IByteArrayExtensions.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2021 Demerzel Solutions Limited -// This file is part of the Nethermind library. -// -// The Nethermind library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The Nethermind library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the Nethermind. If not, see . - -using DotNetty.Buffers; -using Nethermind.Core.Extensions; - -namespace Nethermind.Network -{ - public static class IByteBufferExtensions - { - public static byte[] ReadAllBytes(this IByteBuffer buffer) - { - byte[] bytes = new byte[buffer.ReadableBytes]; - buffer.ReadBytes(bytes); - return bytes; - } - - public static string ReadAllHex(this IByteBuffer buffer) - { - byte[] bytes = new byte[buffer.ReadableBytes]; - buffer.ReadBytes(bytes); - return bytes.ToHexString(); - } - - public static void MakeSpace(this IByteBuffer output, int length, string reason = null) - { - if (output.WritableBytes < length) - { - if (output.ReaderIndex == output.WriterIndex) - { - output.Clear(); - } - else - { - output.DiscardReadBytes(); - } - - if (output.WritableBytes < length) - { - output.EnsureWritable(length, true); - } - } - } - } -} diff --git a/src/Nethermind/Nethermind.Network/IMessagePad.cs b/src/Nethermind/Nethermind.Network/IMessagePad.cs index 426a0455371..ec87d59cf61 100644 --- a/src/Nethermind/Nethermind.Network/IMessagePad.cs +++ b/src/Nethermind/Nethermind.Network/IMessagePad.cs @@ -1,23 +1,27 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using DotNetty.Buffers; + namespace Nethermind.Network { public interface IMessagePad { byte[] Pad(byte[] bytes); + void Pad(IByteBuffer bytes); } + } diff --git a/src/Nethermind/Nethermind.Network/IMessageSerializationService.cs b/src/Nethermind/Nethermind.Network/IMessageSerializationService.cs index 5bd0055d488..e001c78ab9e 100644 --- a/src/Nethermind/Nethermind.Network/IMessageSerializationService.cs +++ b/src/Nethermind/Nethermind.Network/IMessageSerializationService.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -21,12 +21,16 @@ namespace Nethermind.Network { public interface IMessageSerializationService { - IByteBuffer ZeroSerialize(T message) where T : MessageBase; - byte[] Serialize(T messageBase) where T : MessageBase; + IByteBuffer ZeroSerialize(T message, ByteBufferAllocator allocator = ByteBufferAllocator.PooledByteBufferAllocator) where T : MessageBase; T Deserialize(byte[] bytes) where T : MessageBase; T Deserialize(IByteBuffer buffer) where T : MessageBase; void Register(Assembly assembly); - void Register(IMessageSerializer messageSerializer) where T : MessageBase; void Register(IZeroMessageSerializer messageSerializer) where T : MessageBase; } + + public enum ByteBufferAllocator + { + UnpooledByteBufferAllocator, + PooledByteBufferAllocator + } } diff --git a/src/Nethermind/Nethermind.Network/IMessageSerializer.cs b/src/Nethermind/Nethermind.Network/IMessageSerializer.cs deleted file mode 100644 index 41552454e20..00000000000 --- a/src/Nethermind/Nethermind.Network/IMessageSerializer.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2021 Demerzel Solutions Limited -// This file is part of the Nethermind library. -// -// The Nethermind library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The Nethermind library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the Nethermind. If not, see . - -namespace Nethermind.Network -{ - public interface IMessageSerializer where T : MessageBase - { - byte[] Serialize(T msg); - T Deserialize(byte[] msgBytes); - } -} diff --git a/src/Nethermind/Nethermind.Network/MessageSerializationService.cs b/src/Nethermind/Nethermind.Network/MessageSerializationService.cs index 385aea38c47..11640961fc3 100644 --- a/src/Nethermind/Nethermind.Network/MessageSerializationService.cs +++ b/src/Nethermind/Nethermind.Network/MessageSerializationService.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -31,12 +31,15 @@ public class MessageSerializationService : IMessageSerializationService public T Deserialize(byte[] bytes) where T : MessageBase { - if (!TryGetSerializer(out IMessageSerializer messageSerializer)) + if (TryGetZeroSerializer(out IZeroMessageSerializer zeroMessageSerializer)) { - throw new InvalidOperationException($"No {nameof(IMessageSerializer)} registered for {typeof(T).Name}."); + IByteBuffer byteBuffer = PooledByteBufferAllocator.Default.Buffer(bytes.Length); + byteBuffer.WriteBytes(bytes); + return zeroMessageSerializer.Deserialize(byteBuffer); } - return messageSerializer.Deserialize(bytes); + throw new InvalidOperationException($"No {nameof(IZeroMessageSerializer)} registered for {typeof(T).Name}."); + } public T Deserialize(IByteBuffer buffer) where T : MessageBase @@ -45,10 +48,8 @@ public T Deserialize(IByteBuffer buffer) where T : MessageBase { return zeroMessageSerializer.Deserialize(buffer); } - - // 3% allocation of a sample run of Goerli 3 million blocks fast sync on buffer.ReadAllBytes - // this can be improved by adding ZeroMessageSerializer for a new message type - return Deserialize(buffer.ReadAllBytes()); + + throw new InvalidOperationException($"No {nameof(IZeroMessageSerializer)} registered for {typeof(T).Name}."); } @@ -70,16 +71,6 @@ public void Register(Assembly assembly) } Type interfaceGenericDefinition = implementedInterface.GetGenericTypeDefinition(); - if (interfaceGenericDefinition == typeof(IMessageSerializer<>).GetGenericTypeDefinition()) - { - ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes); - if (constructor == null) - { - continue; - } - - _serializers[implementedInterface.GenericTypeArguments[0].TypeHandle] = Activator.CreateInstance(type); - } if (interfaceGenericDefinition == typeof(IZeroMessageSerializer<>).GetGenericTypeDefinition()) { @@ -95,17 +86,12 @@ public void Register(Assembly assembly) } } - public void Register(IMessageSerializer messageSerializer) where T : MessageBase - { - _serializers[typeof(T).TypeHandle] = messageSerializer; - } - public void Register(IZeroMessageSerializer messageSerializer) where T : MessageBase { _zeroSerializers[typeof(T).TypeHandle] = messageSerializer; } - public IByteBuffer ZeroSerialize(T message) where T : MessageBase + public IByteBuffer ZeroSerialize(T message, ByteBufferAllocator allocator = ByteBufferAllocator.PooledByteBufferAllocator) where T : MessageBase { void WriteAdaptivePacketType(in IByteBuffer buffer) { @@ -116,30 +102,34 @@ void WriteAdaptivePacketType(in IByteBuffer buffer) } int p2pMessageLength = (message is P2PMessage ? sizeof(int) : 0); + IByteBuffer byteBuffer; if (TryGetZeroSerializer(out IZeroMessageSerializer zeroMessageSerializer)) { - IByteBuffer byteBuffer = PooledByteBufferAllocator.Default.Buffer( - zeroMessageSerializer is IZeroInnerMessageSerializer zeroInnerMessageSerializer - ? zeroInnerMessageSerializer.GetLength(message, out _) + p2pMessageLength - : 64); + + switch (allocator) + { + case ByteBufferAllocator.UnpooledByteBufferAllocator: + byteBuffer = UnpooledByteBufferAllocator.Default.Buffer( + zeroMessageSerializer is IZeroInnerMessageSerializer zeroInnerMessageSerializerU + ? zeroInnerMessageSerializerU.GetLength(message, out _) + p2pMessageLength + : 64); + break; + case ByteBufferAllocator.PooledByteBufferAllocator: + byteBuffer = PooledByteBufferAllocator.Default.Buffer( + zeroMessageSerializer is IZeroInnerMessageSerializer zeroInnerMessageSerializerP + ? zeroInnerMessageSerializerP.GetLength(message, out _) + p2pMessageLength + : 64); + break; + default: + throw new ArgumentOutOfRangeException(nameof(allocator), allocator, null); + } + + WriteAdaptivePacketType(byteBuffer); zeroMessageSerializer.Serialize(byteBuffer, message); return byteBuffer; } - else - { - byte[] serialized = Serialize(message); - IByteBuffer byteBuffer = PooledByteBufferAllocator.Default.Buffer(serialized.Length + p2pMessageLength); - WriteAdaptivePacketType(byteBuffer); - byteBuffer.WriteBytes(serialized); - return byteBuffer; - } - } - public byte[] Serialize(T messageBase) where T : MessageBase - { - return TryGetSerializer(out IMessageSerializer messageSerializer) - ? messageSerializer.Serialize(messageBase) - : throw new InvalidOperationException($"No {nameof(IMessageSerializer)} registered for {typeof(T).Name}."); + throw new InvalidOperationException($"No {nameof(IZeroMessageSerializer)} registered for {typeof(T).Name}."); } private bool TryGetZeroSerializer(out IZeroMessageSerializer serializer) where T : MessageBase @@ -160,22 +150,5 @@ private bool TryGetZeroSerializer(out IZeroMessageSerializer serializer) w throw new InvalidOperationException($"Zero serializer for {nameof(T)} (registered: {serializerObject?.GetType().Name}) does not implement required interfaces"); } - private bool TryGetSerializer(out IMessageSerializer serializer) where T : MessageBase - { - RuntimeTypeHandle typeHandle = typeof(T).TypeHandle; - if (!_serializers.TryGetValue(typeHandle, out object serializerObject)) - { - serializer = null; - return false; - } - - if (!(serializerObject is IMessageSerializer messageSerializer)) - { - throw new InvalidOperationException($"Serializer for {nameof(T)} (registered: {serializerObject?.GetType().Name}) does not implement required interfaces"); - } - - serializer = messageSerializer; - return true; - } } } diff --git a/src/Nethermind/Nethermind.Network/NoPad.cs b/src/Nethermind/Nethermind.Network/NoPad.cs index 74467b9decc..33defe29d7b 100644 --- a/src/Nethermind/Nethermind.Network/NoPad.cs +++ b/src/Nethermind/Nethermind.Network/NoPad.cs @@ -1,19 +1,21 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using DotNetty.Buffers; + namespace Nethermind.Network { public class NoPad : IMessagePad @@ -22,5 +24,6 @@ public byte[] Pad(byte[] bytes) { return bytes; } + public void Pad(IByteBuffer bytes) { } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Messages/AddCapabilityMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Messages/AddCapabilityMessageSerializer.cs index 545c835ec44..8be17413579 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Messages/AddCapabilityMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Messages/AddCapabilityMessageSerializer.cs @@ -1,19 +1,20 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using DotNetty.Buffers; using Nethermind.Serialization.Rlp; using Nethermind.Stats.Model; @@ -22,20 +23,34 @@ namespace Nethermind.Network.P2P.Messages /// /// This is probably used in NDM /// - public class AddCapabilityMessageSerializer : IMessageSerializer + public class AddCapabilityMessageSerializer : IZeroMessageSerializer { - public byte[] Serialize(AddCapabilityMessage msg) - => Rlp.Encode(Rlp.Encode(msg.Capability.ProtocolCode.ToLowerInvariant()), - Rlp.Encode(msg.Capability.Version)).Bytes; + public void Serialize(IByteBuffer byteBuffer, AddCapabilityMessage msg) + { + int totalLength = GetLength(msg, out int contentLength); + byteBuffer.EnsureWritable(totalLength, true); + + NettyRlpStream stream = new(byteBuffer); + stream.StartSequence(contentLength); + stream.Encode(msg.Capability.ProtocolCode.ToLowerInvariant()); + stream.Encode(msg.Capability.Version); + } - public AddCapabilityMessage Deserialize(byte[] msgBytes) + public AddCapabilityMessage Deserialize(IByteBuffer byteBuffer) { - RlpStream context = msgBytes.AsRlpStream(); + NettyRlpStream context = new(byteBuffer); context.ReadSequenceLength(); string protocolCode = context.DecodeString(); byte version = context.DecodeByte(); return new AddCapabilityMessage(new Capability(protocolCode, version)); } + private int GetLength(AddCapabilityMessage msg, out int contentLength) + { + contentLength = Rlp.LengthOf(msg.Capability.ProtocolCode.ToLowerInvariant()); + contentLength += Rlp.LengthOf(msg.Capability.Version); + + return Rlp.LengthOfSequence(contentLength); + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs index dcf97c3cc5a..7f7673b4915 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Messages/DisconnectMessageSerializer.cs @@ -1,56 +1,69 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System; using System.Linq; +using DotNetty.Buffers; using Nethermind.Core.Extensions; using Nethermind.Serialization.Rlp; using Nethermind.Stats.Model; namespace Nethermind.Network.P2P.Messages { - public class DisconnectMessageSerializer : IMessageSerializer + public class DisconnectMessageSerializer : IZeroMessageSerializer { - public byte[] Serialize(DisconnectMessage msg) + public void Serialize(IByteBuffer byteBuffer, DisconnectMessage msg) { - return Rlp.Encode( - Rlp.Encode((byte)msg.Reason) // sic!, as a list of 1 element - ).Bytes; + int length = GetLength(msg, out int contentLength); + byteBuffer.EnsureWritable(length); + NettyRlpStream rlpStream = new(byteBuffer); + + rlpStream.StartSequence(contentLength); + rlpStream.Encode((byte)msg.Reason); + } + + private int GetLength(DisconnectMessage message, out int contentLength) + { + contentLength = Rlp.LengthOf((byte)message.Reason); + + return Rlp.LengthOfSequence(contentLength); } private byte[] breach1 = Bytes.FromHexString("0204c104"); private byte[] breach2 = Bytes.FromHexString("0204c180"); - - public DisconnectMessage Deserialize(byte[] msgBytes) + + public DisconnectMessage Deserialize(IByteBuffer msgBytes) { - if (msgBytes.Length == 1) + if (msgBytes.ReadableBytes == 1) { - return new DisconnectMessage((DisconnectReason)msgBytes[0]); + return new DisconnectMessage((DisconnectReason)msgBytes.GetByte(0)); } - if (msgBytes.SequenceEqual(breach1)) + Span msg = msgBytes.ReadAllBytesAsSpan(); + if (msg.SequenceEqual(breach1)) { return new DisconnectMessage(DisconnectReason.Breach1); } - - if (msgBytes.SequenceEqual(breach2)) + + if (msg.SequenceEqual(breach2)) { return new DisconnectMessage(DisconnectReason.Breach2); } - - RlpStream rlpStream = msgBytes.AsRlpStream(); + + Rlp.ValueDecoderContext rlpStream = msg.AsRlpValueContext(); rlpStream.ReadSequenceLength(); int reason = rlpStream.DecodeInt(); DisconnectMessage disconnectMessage = new(reason); diff --git a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs index 15e82015c25..0776b542727 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Messages/HelloMessageSerializer.cs @@ -1,45 +1,74 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System; using System.Linq; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Serialization.Rlp; using Nethermind.Stats.Model; namespace Nethermind.Network.P2P.Messages { - public class HelloMessageSerializer : IMessageSerializer + public class HelloMessageSerializer : IZeroMessageSerializer { - public byte[] Serialize(HelloMessage msg) + public void Serialize(IByteBuffer byteBuffer, HelloMessage msg) { - return Rlp.Encode( - Rlp.Encode(msg.P2PVersion), - Rlp.Encode(msg.ClientId), - Rlp.Encode(msg.Capabilities.Select(c => Rlp.Encode( - Rlp.Encode(c.ProtocolCode.ToLowerInvariant()), - Rlp.Encode(c.Version))).ToArray()), - Rlp.Encode(msg.ListenPort), - Rlp.Encode(msg.NodeId.Bytes) - ).Bytes; + (int totalLength, int innerLength) length = GetLength(msg); + byteBuffer.EnsureWritable(Rlp.LengthOfSequence(length.totalLength), true); + NettyRlpStream stream = new(byteBuffer); + stream.StartSequence(length.totalLength); + stream.Encode(msg.P2PVersion); + stream.Encode(msg.ClientId); + stream.StartSequence(length.innerLength); + foreach (Capability? capability in msg.Capabilities) + { + string protocolCode = capability.ProtocolCode.ToLowerInvariant(); + int capabilityLength = Rlp.LengthOf(protocolCode); + capabilityLength += Rlp.LengthOf(capability.Version); + stream.StartSequence(capabilityLength); + stream.Encode(protocolCode); + stream.Encode(capability.Version); + } + + stream.Encode(msg.ListenPort); + stream.Encode(msg.NodeId.Bytes); } - public HelloMessage Deserialize(byte[] msgBytes) + private (int, int) GetLength(HelloMessage msg) { - RlpStream rlpStream = msgBytes.AsRlpStream(); + int contentLength = 0; + contentLength += Rlp.LengthOf(msg.P2PVersion); + contentLength += Rlp.LengthOf(msg.ClientId); + int innerContentLength = 0; + foreach (Capability? capability in msg.Capabilities) + { + int capabilityLength = Rlp.LengthOf(capability.ProtocolCode.ToLowerInvariant()); + capabilityLength += Rlp.LengthOf(capability.Version); + innerContentLength += Rlp.LengthOfSequence(capabilityLength); + } + contentLength += Rlp.LengthOfSequence(innerContentLength); + contentLength += Rlp.LengthOf(msg.ListenPort); + contentLength += Rlp.LengthOf(msg.NodeId.Bytes); + return (contentLength, innerContentLength); + } + + public HelloMessage Deserialize(IByteBuffer msgBytes) + { + NettyRlpStream rlpStream = new (msgBytes); rlpStream.ReadSequenceLength(); HelloMessage helloMessage = new(); @@ -52,7 +81,7 @@ public HelloMessage Deserialize(byte[] msgBytes) int version = ctx.DecodeByte(); return new Capability(protocolCode, version); }).ToList(); - + helloMessage.ListenPort = rlpStream.DecodeInt(); ReadOnlySpan publicKeyBytes = rlpStream.DecodeByteArraySpan(); diff --git a/src/Nethermind/Nethermind.Network/P2P/NettyRlpStream.cs b/src/Nethermind/Nethermind.Network/P2P/NettyRlpStream.cs index 8edac5b3a52..e8e83cf3795 100644 --- a/src/Nethermind/Nethermind.Network/P2P/NettyRlpStream.cs +++ b/src/Nethermind/Nethermind.Network/P2P/NettyRlpStream.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -97,7 +97,7 @@ public override int Position public override int Length => _buffer.ReadableBytes + (_buffer.ReaderIndex - _initialPosition); - public override bool HasBeenRead => _buffer.ReadableBytes > 0; + public override bool HasBeenRead => _buffer.ReadableBytes <= 0; protected override string Description => "|NettyRlpStream|description missing|"; } 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 884790f93fc..17b3950f793 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 @@ -1,19 +1,21 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using System; +using System.Configuration; using System.Linq; using DotNetty.Buffers; using Nethermind.Core; @@ -23,20 +25,43 @@ namespace Nethermind.Network.P2P.Subprotocols.Eth.V62.Messages { public class BlockBodiesMessageSerializer : IZeroInnerMessageSerializer { - public byte[] Serialize(BlockBodiesMessage message) + private readonly TxDecoder _txDecoder = new(); + private readonly HeaderDecoder _headerDecoder = new(); + + public void Serialize(IByteBuffer byteBuffer, BlockBodiesMessage message) { - return Rlp.Encode(message.Bodies.Select(b => b == null - ? Rlp.OfEmptySequence - : Rlp.Encode( - Rlp.Encode(b.Transactions), - Rlp.Encode(b.Uncles))).ToArray()).Bytes; + + int totalLength = GetLength(message, out int contentLength); + byteBuffer.EnsureWritable(totalLength, true); + NettyRlpStream stream = new(byteBuffer); + stream.StartSequence(contentLength); + foreach (BlockBody? body in message.Bodies) + { + if (body == null) + { + stream.Encode(Rlp.OfEmptySequence); + } + else + { + SerializeBody(stream, body); + } + } } - public void Serialize(IByteBuffer byteBuffer, BlockBodiesMessage message) + private void SerializeBody(NettyRlpStream stream, BlockBody body) { - byte[] oldWay = Serialize(message); - byteBuffer.EnsureWritable(oldWay.Length, true); - byteBuffer.WriteBytes(oldWay); + stream.StartSequence(GetBodyLength(body)); + stream.StartSequence(GetTxLength(body.Transactions)); + foreach (Transaction? txn in body.Transactions) + { + stream.Encode(txn); + } + + stream.StartSequence(GetUnclesLength(body.Uncles)); + foreach (var uncle in body.Uncles) + { + stream.Encode(uncle); + } } public BlockBodiesMessage Deserialize(IByteBuffer byteBuffer) @@ -47,9 +72,41 @@ public BlockBodiesMessage Deserialize(IByteBuffer byteBuffer) public int GetLength(BlockBodiesMessage message, out int contentLength) { - byte[] oldWay = Serialize(message); - contentLength = oldWay.Length; - return contentLength; + contentLength = message.Bodies.Select(b => b == null + ? Rlp.OfEmptySequence.Length + : Rlp.LengthOfSequence( + GetBodyLength(b) + ) + ).Sum(); + return Rlp.LengthOfSequence(contentLength); + } + + private int GetBodyLength(BlockBody b) + { + return Rlp.LengthOfSequence(GetTxLength(b.Transactions)) + + Rlp.LengthOfSequence(GetUnclesLength(b.Uncles)); + } + + private int GetTxLength(Transaction[] transactions) + { + int txLength = 0; + for (int i = 0; i < transactions.Length; i++) + { + txLength += _txDecoder.GetLength(transactions[i], RlpBehaviors.None); + } + + return txLength; + } + + private int GetUnclesLength(BlockHeader[] headers) + { + int unclesLength = 0; + for (int i = 0; i < headers.Length; i++) + { + unclesLength += _headerDecoder.GetLength(headers[i], RlpBehaviors.None); + } + + return unclesLength; } public static BlockBodiesMessage Deserialize(RlpStream rlpStream) diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs index 61704d98f6f..cf2e12b6d96 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Eth/V63/Messages/ReceiptsMessageSerializer.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -33,30 +33,52 @@ public ReceiptsMessageSerializer(ISpecProvider specProvider) { _specProvider = specProvider ?? throw new ArgumentNullException(nameof(specProvider)); } - + public void Serialize(IByteBuffer byteBuffer, ReceiptsMessage message) { - Rlp rlp = Rlp.Encode(message.TxReceipts.Select( - b => b == null - ? Rlp.OfEmptySequence - : Rlp.Encode( - b.Select( - n => n == null - ? Rlp.OfEmptySequence - : _decoder.Encode(n, _specProvider.GetSpec(n.BlockNumber).IsEip658Enabled ? RlpBehaviors.Eip658Receipts : RlpBehaviors.None)).ToArray())).ToArray()); - - RlpStream rlpStream = new NettyRlpStream(byteBuffer); - rlpStream.Encode(rlp); + + int totalLength = GetLength(message, out int contentLength); + + byteBuffer.EnsureWritable(totalLength, true); + NettyRlpStream stream = new(byteBuffer); + stream.StartSequence(contentLength); + + foreach (TxReceipt?[]? txReceipts in message.TxReceipts) + { + if (txReceipts is null) + { + stream.Encode(Rlp.OfEmptySequence); + continue; + } + + int innerLength = GetInnerLength(txReceipts); + stream.StartSequence(innerLength); + foreach (TxReceipt? txReceipt in txReceipts) + { + if (txReceipt is null) + { + stream.Encode(Rlp.OfEmptySequence); + continue; + } + + _decoder.Encode(stream, txReceipt, + _specProvider.GetSpec(txReceipt.BlockNumber).IsEip658Enabled + ? RlpBehaviors.Eip658Receipts + : RlpBehaviors.None); + } + + + } } public ReceiptsMessage Deserialize(IByteBuffer byteBuffer) { if (byteBuffer.Array.Length == 0 || byteBuffer.Array.First() == Rlp.OfEmptySequence[0]) return new ReceiptsMessage(null); - + RlpStream rlpStream = new NettyRlpStream(byteBuffer); return Deserialize(rlpStream); } - + public ReceiptsMessage Deserialize(RlpStream rlpStream) { TxReceipt[][] data = rlpStream.DecodeArray(itemContext => @@ -69,7 +91,7 @@ public ReceiptsMessage Deserialize(RlpStream rlpStream) public int GetLength(ReceiptsMessage message, out int contentLength) { contentLength = 0; - + for (int i = 0; i < message.TxReceipts.Length; i++) { TxReceipt?[]? txReceipts = message.TxReceipts[i]; @@ -79,23 +101,30 @@ public int GetLength(ReceiptsMessage message, out int contentLength) } else { - for (int j = 0; j < txReceipts.Length; j++) - { - TxReceipt? txReceipt = txReceipts[j]; - if (txReceipt is null) - { - contentLength += Rlp.OfEmptySequence.Length; - } - else - { - contentLength += Rlp.LengthOfSequence(_decoder.GetLength(txReceipt, _specProvider.GetSpec(txReceipt.BlockNumber).IsEip658Enabled ? RlpBehaviors.Eip658Receipts : RlpBehaviors.None)); - } - } + contentLength += Rlp.LengthOfSequence(GetInnerLength(txReceipts)); } - } - + return Rlp.LengthOfSequence(contentLength); } + + private int GetInnerLength(TxReceipt?[]? txReceipts) + { + int contentLength = 0; + for (int j = 0; j < txReceipts.Length; j++) + { + TxReceipt? txReceipt = txReceipts[j]; + if (txReceipt is null) + { + contentLength += Rlp.OfEmptySequence.Length; + } + else + { + contentLength += _decoder.GetLength(txReceipt, _specProvider.GetSpec(txReceipt.BlockNumber).IsEip658Enabled ? RlpBehaviors.Eip658Receipts : RlpBehaviors.None); + } + } + + return contentLength; + } } } diff --git a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/BlockBodiesMessageSerializer.cs b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/BlockBodiesMessageSerializer.cs index 16b11591519..983b7bf7a63 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/BlockBodiesMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Les/Messages/BlockBodiesMessageSerializer.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -24,8 +24,8 @@ public class BlockBodiesMessageSerializer: IZeroMessageSerializer. @@ -26,28 +26,25 @@ public class HelperTrieProofsMessageSerializer: IZeroMessageSerializer(T[]...) could recurse to handle arbitrary array nesting. Would clean this up a lot.")] public void Serialize(IByteBuffer byteBuffer, HelperTrieProofsMessage message) { - Rlp[] proofNodesRlp = new Rlp[message.ProofNodes.Length]; + Keccak[] proofNodesKeccak = new Keccak[message.ProofNodes.Length]; + int proofNodesContentLength = 0; for (int i = 0; i < message.ProofNodes.Length; i++) { - proofNodesRlp[i] = Rlp.Encode(new Keccak(message.ProofNodes[i])); + proofNodesKeccak[i] = new Keccak(message.ProofNodes[i]); + proofNodesContentLength += Rlp.LengthOf(proofNodesKeccak[i]); } - - Rlp proofsRlp = Rlp.Encode(proofNodesRlp); - Rlp[] tempAuxRlp = new Rlp[message.AuxiliaryData.Length]; + int tempAuxContentLength = 0; for (int i = 0; i < message.AuxiliaryData.Length; i++) { - tempAuxRlp[i] = Rlp.Encode(message.AuxiliaryData[i]); + tempAuxContentLength += Rlp.LengthOf(message.AuxiliaryData[i]); } - Rlp auxRlp = Rlp.Encode(tempAuxRlp); - - int innerContentLength = proofsRlp.Length + auxRlp.Length; + int innerContentLength = Rlp.LengthOfSequence(proofNodesContentLength) + Rlp.LengthOfSequence(tempAuxContentLength); int contentLength = Rlp.LengthOf(message.RequestId) + Rlp.LengthOf(message.BufferValue) + Rlp.LengthOfSequence(innerContentLength); - int totalLength = Rlp.LengthOfSequence(contentLength); RlpStream rlpStream = new NettyRlpStream(byteBuffer); @@ -57,8 +54,16 @@ public void Serialize(IByteBuffer byteBuffer, HelperTrieProofsMessage message) rlpStream.Encode(message.RequestId); rlpStream.Encode(message.BufferValue); rlpStream.StartSequence(innerContentLength); - rlpStream.Encode(proofsRlp); - rlpStream.Encode(auxRlp); + rlpStream.StartSequence(proofNodesContentLength); + for (int i = 0; i < message.ProofNodes.Length; i++) + { + rlpStream.Encode(proofNodesKeccak[i]); + } + rlpStream.StartSequence(tempAuxContentLength); + for (int i = 0; i < message.AuxiliaryData.Length; i++) + { + rlpStream.Encode(message.AuxiliaryData[i]); + } } public HelperTrieProofsMessage Deserialize(IByteBuffer byteBuffer) 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 11f93e5a072..2ffe5673f3b 100644 --- a/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/P2P/Subprotocols/Snap/Messages/AccountRangeMessageSerializer.cs @@ -1,19 +1,19 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . -// +// using DotNetty.Buffers; using Nethermind.Core; @@ -84,7 +84,7 @@ public AccountRangeMessage Deserialize(IByteBuffer byteBuffer) return message; } - + private PathWithAccount DecodePathWithRlpData(RlpStream stream) { stream.ReadSequenceLength(); diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckEip8MessageSerializer.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckEip8MessageSerializer.cs index e21c8c5f895..0762dae51da 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckEip8MessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckEip8MessageSerializer.cs @@ -1,25 +1,27 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using DotNetty.Buffers; using Nethermind.Core.Crypto; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Rlpx.Handshake { - public class AckEip8MessageSerializer : IMessageSerializer + public class AckEip8MessageSerializer : IZeroMessageSerializer { private readonly IMessagePad _messagePad; public const int EphemeralPublicKeyLength = 64; @@ -33,21 +35,24 @@ public AckEip8MessageSerializer(IMessagePad messagePad) { _messagePad = messagePad; } - - public byte[] Serialize(AckEip8Message msg) + + public void Serialize(IByteBuffer byteBuffer, AckEip8Message msg) { - byte[] data = Rlp.Encode( - Rlp.Encode(msg.EphemeralPublicKey.Bytes), - Rlp.Encode(msg.Nonce), - Rlp.Encode(msg.Version) - ).Bytes; + int totalLength = Rlp.LengthOf(msg.EphemeralPublicKey.Bytes); + totalLength += Rlp.LengthOf(msg.Nonce); + totalLength += Rlp.LengthOf(msg.Version); - return _messagePad?.Pad(data) ?? data; + byteBuffer.EnsureWritable(Rlp.LengthOfSequence(totalLength), true); + NettyRlpStream stream = new(byteBuffer); + stream.StartSequence(totalLength); + stream.Encode(msg.EphemeralPublicKey.Bytes); + stream.Encode(msg.Nonce); + stream.Encode(msg.Version); } - public AckEip8Message Deserialize(byte[] msgBytes) + public AckEip8Message Deserialize(IByteBuffer msgBytes) { - RlpStream rlpStream = msgBytes.AsRlpStream(); + NettyRlpStream rlpStream = new(msgBytes); AckEip8Message authEip8Message = new(); rlpStream.ReadSequenceLength(); authEip8Message.EphemeralPublicKey = new PublicKey(rlpStream.DecodeByteArraySpan()); diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs index 027ea0d6691..0ef5dcafa34 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AckMessageSerializer.cs @@ -1,26 +1,27 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; namespace Nethermind.Network.Rlpx.Handshake { - public class AckMessageSerializer : IMessageSerializer + public class AckMessageSerializer : IZeroMessageSerializer { public const int EphemeralPublicKeyLength = 64; public const int EphemeralPublicKeyOffset = 0; @@ -29,27 +30,29 @@ public class AckMessageSerializer : IMessageSerializer public const int IsTokenUsedLength = 1; public const int IsTokenUsedOffset = NonceOffset + NonceLength; public const int TotalLength = IsTokenUsedOffset + IsTokenUsedLength; - - public byte[] Serialize(AckMessage msg) + + public void Serialize(IByteBuffer byteBuffer, AckMessage msg) { + byteBuffer.EnsureWritable(TotalLength); + // TODO: find a way to now allocate this here byte[] data = new byte[TotalLength]; Buffer.BlockCopy(msg.EphemeralPublicKey.Bytes, 0, data, EphemeralPublicKeyOffset, EphemeralPublicKeyLength); Buffer.BlockCopy(msg.Nonce, 0, data, NonceOffset, NonceLength); data[IsTokenUsedOffset] = msg.IsTokenUsed ? (byte)0x01 : (byte)0x00; - return data; + byteBuffer.WriteBytes(data); } - public AckMessage Deserialize(byte[] msgBytes) + public AckMessage Deserialize(IByteBuffer msgBytes) { - if (msgBytes.Length != TotalLength) + if (msgBytes.ReadableBytes != TotalLength) { - throw new NetworkingException($"Incorrect incoming {nameof(AckMessage)} length. Expected {TotalLength} but was {msgBytes.Length}", NetworkExceptionType.Validation); + throw new NetworkingException($"Incorrect incoming {nameof(AckMessage)} length. Expected {TotalLength} but was {msgBytes.ReadableBytes}", NetworkExceptionType.Validation); } AckMessage authMessage = new(); - authMessage.EphemeralPublicKey = new PublicKey(msgBytes.AsSpan().Slice(EphemeralPublicKeyOffset, EphemeralPublicKeyLength)); - authMessage.Nonce = msgBytes.Slice(NonceOffset, NonceLength); - authMessage.IsTokenUsed = msgBytes[IsTokenUsedOffset] == 0x01; + authMessage.EphemeralPublicKey = new PublicKey(msgBytes.Slice(EphemeralPublicKeyOffset, EphemeralPublicKeyLength).ReadAllBytesAsSpan()); + authMessage.Nonce = msgBytes.Slice(NonceOffset, NonceLength).ReadAllBytesAsArray(); + authMessage.IsTokenUsed = msgBytes.GetByte(IsTokenUsedOffset) == 0x01; return authMessage; } } diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthEip8MessageSerializer.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthEip8MessageSerializer.cs index 11a82e607e0..d541b51ac6c 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthEip8MessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthEip8MessageSerializer.cs @@ -1,27 +1,29 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Rlpx.Handshake { - public class AuthEip8MessageSerializer : IMessageSerializer + public class AuthEip8MessageSerializer : IZeroMessageSerializer { private readonly IMessagePad _messagePad; @@ -29,22 +31,33 @@ public AuthEip8MessageSerializer(IMessagePad messagePad) { _messagePad = messagePad; } - - public byte[] Serialize(AuthEip8Message msg) + + public void Serialize(IByteBuffer byteBuffer, AuthEip8Message msg) { - byte[] data = Rlp.Encode( - Rlp.Encode(Bytes.Concat(msg.Signature.Bytes, msg.Signature.RecoveryId)), - Rlp.Encode(msg.PublicKey.Bytes), - Rlp.Encode(msg.Nonce), - Rlp.Encode(msg.Version) - ).Bytes; + int totalLength = GetLength(msg); + // TODO: Account for the padding + byteBuffer.EnsureWritable(Rlp.LengthOfSequence(totalLength), true); + NettyRlpStream stream = new(byteBuffer); + stream.StartSequence(totalLength); + stream.Encode(Bytes.Concat(msg.Signature.Bytes, msg.Signature.RecoveryId)); + stream.Encode(msg.PublicKey.Bytes); + stream.Encode(msg.Nonce); + stream.Encode(msg.Version); + _messagePad?.Pad(byteBuffer); + } - return _messagePad?.Pad(data) ?? data; + public int GetLength(AuthEip8Message msg) + { + int contentLength = Rlp.LengthOf(Bytes.Concat(msg.Signature.Bytes, msg.Signature.RecoveryId)) + + Rlp.LengthOf(msg.PublicKey.Bytes) + + Rlp.LengthOf(msg.Nonce) + + Rlp.LengthOf(msg.Version); + return contentLength; } - public AuthEip8Message Deserialize(byte[] msgBytes) + public AuthEip8Message Deserialize(IByteBuffer msgBytes) { - RlpStream rlpStream = msgBytes.AsRlpStream(); + NettyRlpStream rlpStream = new(msgBytes); AuthEip8Message authMessage = new(); rlpStream.ReadSequenceLength(); ReadOnlySpan sigAllBytes = rlpStream.DecodeByteArraySpan(); diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthMessageSerializer.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthMessageSerializer.cs index 54773ca9549..2372ffded7f 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthMessageSerializer.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/AuthMessageSerializer.cs @@ -1,26 +1,28 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System; +using System.Buffers; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; namespace Nethermind.Network.Rlpx.Handshake { - public class AuthMessageSerializer : IMessageSerializer + public class AuthMessageSerializer : IZeroMessageSerializer { public const int SigOffset = 0; public const int SigLength = 65; @@ -33,7 +35,7 @@ public class AuthMessageSerializer : IMessageSerializer public const int IsTokenUsedLength = 1; public const int IsTokenUsedOffset = NonceOffset + NonceLength; public const int Length = IsTokenUsedOffset + IsTokenUsedLength; - + // 65 (sig) // 32 (ephem hash) // 64 (pub) @@ -47,31 +49,31 @@ public class AuthMessageSerializer : IMessageSerializer // ============= // 307 (total) - public byte[] Serialize(AuthMessage msg) + public void Serialize(IByteBuffer byteBuffer, AuthMessage msg) { - byte[] data = new byte[Length]; - Buffer.BlockCopy(msg.Signature.Bytes, 0, data, SigOffset, SigLength - 1); - data[SigLength - 1] = msg.Signature.RecoveryId; - Buffer.BlockCopy(msg.EphemeralPublicHash.Bytes, 0, data, EphemeralHashOffset, EphemeralHashLength); - Buffer.BlockCopy(msg.PublicKey.Bytes, 0, data, PublicKeyOffset, PublicKeyLength); - Buffer.BlockCopy(msg.Nonce, 0, data, NonceOffset, NonceLength); - data[IsTokenUsedOffset] = msg.IsTokenUsed ? (byte)0x01 : (byte)0x00; - return data; + byteBuffer.EnsureWritable(Length, true); + byteBuffer.WriteBytes(msg.Signature.Bytes); + byteBuffer.WriteByte(msg.Signature.RecoveryId); + byteBuffer.WriteBytes(msg.EphemeralPublicHash.Bytes); + byteBuffer.WriteBytes(msg.PublicKey.Bytes); + byteBuffer.WriteBytes(msg.Nonce); + byteBuffer.WriteByte(msg.IsTokenUsed ? 0x01 : 0x00); } - public AuthMessage Deserialize(byte[] msgBytes) + public AuthMessage Deserialize(IByteBuffer msgBytes) { - if (msgBytes.Length != Length) + if (msgBytes.ReadableBytes != Length) { - throw new NetworkingException($"Incorrect incoming {nameof(AuthMessage)} length. Expected {Length} but was {msgBytes.Length}", NetworkExceptionType.Validation); + throw new NetworkingException($"Incorrect incoming {nameof(AuthMessage)} length. Expected {Length} but was {msgBytes.ReadableBytes}", NetworkExceptionType.Validation); } AuthMessage authMessage = new(); - authMessage.Signature = new Signature(msgBytes.AsSpan().Slice(SigOffset, SigLength - 1), msgBytes[64]); - authMessage.EphemeralPublicHash = new Keccak(msgBytes.Slice(EphemeralHashOffset, EphemeralHashLength)); - authMessage.PublicKey = new PublicKey(msgBytes.AsSpan().Slice(PublicKeyOffset, PublicKeyLength)); - authMessage.Nonce = msgBytes.Slice(NonceOffset, NonceLength); - authMessage.IsTokenUsed = msgBytes[IsTokenUsedOffset] == 0x01; + Span msg = msgBytes.ReadAllBytesAsSpan(); + authMessage.Signature = new Signature(msg.Slice(SigOffset, SigLength - 1), msg[64]); + authMessage.EphemeralPublicHash = new Keccak(msg.Slice(EphemeralHashOffset, EphemeralHashLength).ToArray()); + authMessage.PublicKey = new PublicKey(msg.Slice(PublicKeyOffset, PublicKeyLength)); + authMessage.Nonce = msg.Slice(NonceOffset, NonceLength).ToArray(); + authMessage.IsTokenUsed = msg[IsTokenUsedOffset] == 0x01; return authMessage; } } diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/Eip8MessagePad.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/Eip8MessagePad.cs index d9c896d4be5..51d632e5ea7 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/Eip8MessagePad.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/Eip8MessagePad.cs @@ -1,19 +1,20 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . +using DotNetty.Buffers; using Nethermind.Core.Extensions; using Nethermind.Crypto; @@ -33,5 +34,11 @@ public byte[] Pad(byte[] message) byte[] padding = _cryptoRandom.GenerateRandomBytes(100 + _cryptoRandom.NextInt(201)); return Bytes.Concat(message, padding); } + + public void Pad(IByteBuffer message) + { + byte[] padding = _cryptoRandom.GenerateRandomBytes(100 + _cryptoRandom.NextInt(201)); + message.WriteBytes(padding); + } } } diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs index 5c182368314..cb826c312bd 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Handshake/HandshakeService.cs @@ -1,20 +1,22 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . using System; +using System.Buffers; +using DotNetty.Buffers; using Nethermind.Core.Crypto; using Nethermind.Core.Extensions; using Nethermind.Crypto; @@ -67,31 +69,33 @@ public Packet Auth(PublicKey remoteNodeId, EncryptionHandshake handshake, bool p if (preEip8Format) { - AuthMessage authMessage = new(); - authMessage.Nonce = handshake.InitiatorNonce; - authMessage.PublicKey = _privateKey.PublicKey; - authMessage.Signature = _ecdsa.Sign(handshake.EphemeralPrivateKey, new Keccak(forSigning)); - authMessage.IsTokenUsed = false; - authMessage.EphemeralPublicHash = Keccak.Compute(handshake.EphemeralPrivateKey.PublicKey.Bytes); - - byte[] authData = _messageSerializationService.Serialize(authMessage); - byte[] packetData = _eciesCipher.Encrypt(remoteNodeId, authData, Array.Empty()); + AuthMessage authMessage = new() + { + Nonce = handshake.InitiatorNonce, + PublicKey = _privateKey.PublicKey, + Signature = _ecdsa.Sign(handshake.EphemeralPrivateKey, new Keccak(forSigning)), + IsTokenUsed = false, + EphemeralPublicHash = Keccak.Compute(handshake.EphemeralPrivateKey.PublicKey.Bytes) + }; + IByteBuffer authData = _messageSerializationService.ZeroSerialize(authMessage); + byte[] packetData = _eciesCipher.Encrypt(remoteNodeId, authData.ReadAllBytesAsArray(), Array.Empty()); handshake.AuthPacket = new Packet(packetData); return handshake.AuthPacket; } else { - AuthEip8Message authMessage = new(); - authMessage.Nonce = handshake.InitiatorNonce; - authMessage.PublicKey = _privateKey.PublicKey; - authMessage.Signature = _ecdsa.Sign(handshake.EphemeralPrivateKey, new Keccak(forSigning)); + AuthEip8Message authMessage = new() + { + Nonce = handshake.InitiatorNonce, + PublicKey = _privateKey.PublicKey, + Signature = _ecdsa.Sign(handshake.EphemeralPrivateKey, new Keccak(forSigning)) + }; - byte[] authData = _messageSerializationService.Serialize(authMessage); - int size = authData.Length + 32 + 16 + 65; // data + MAC + IV + pub + IByteBuffer authData = _messageSerializationService.ZeroSerialize(authMessage); + int size = authData.ReadableBytes + 32 + 16 + 65; // data + MAC + IV + pub byte[] sizeBytes = size.ToBigEndianByteArray().Slice(2, 2); - byte[] packetData = _eciesCipher.Encrypt(remoteNodeId, authData,sizeBytes); - + byte[] packetData = _eciesCipher.Encrypt(remoteNodeId, authData.ReadAllBytesAsArray(), sizeBytes); handshake.AuthPacket = new Packet(Bytes.Concat(sizeBytes, packetData)); return handshake.AuthPacket; } @@ -143,26 +147,30 @@ public Packet Ack(EncryptionHandshake handshake, Packet auth) if (preEip8Format) { if (_logger.IsTrace) _logger.Trace($"Building an {nameof(AckMessage)}"); - AckMessage ackMessage = new(); - ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey; - ackMessage.Nonce = handshake.RecipientNonce; - byte[] ackData = _messageSerializationService.Serialize(ackMessage); - - data = _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData, Array.Empty()); + AckMessage ackMessage = new() + { + EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey, + Nonce = handshake.RecipientNonce + }; + + IByteBuffer ackData = _messageSerializationService.ZeroSerialize(ackMessage); + data = _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData.ReadAllBytesAsArray(), Array.Empty()); } else { if (_logger.IsTrace) _logger.Trace($"Building an {nameof(AckEip8Message)}"); - AckEip8Message ackMessage = new(); - ackMessage.EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey; - ackMessage.Nonce = handshake.RecipientNonce; - byte[] ackData = _messageSerializationService.Serialize(ackMessage); - - int size = ackData.Length + 32 + 16 + 65; // data + MAC + IV + pub + AckEip8Message ackMessage = new() + { + EphemeralPublicKey = handshake.EphemeralPrivateKey.PublicKey, + Nonce = handshake.RecipientNonce + }; + IByteBuffer ackData = _messageSerializationService.ZeroSerialize(ackMessage); + + int size = ackData.ReadableBytes + 32 + 16 + 65; // data + MAC + IV + pub byte[] sizeBytes = size.ToBigEndianByteArray().Slice(2, 2); - data = Bytes.Concat(sizeBytes, _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData, sizeBytes)); + data = Bytes.Concat(sizeBytes, _eciesCipher.Encrypt(handshake.RemoteNodeId, ackData.ReadAllBytesAsArray(), sizeBytes)); } - + handshake.AckPacket = new Packet(data); SetSecrets(handshake, HandshakeRole.Recipient); return handshake.AckPacket; @@ -231,11 +239,11 @@ public static void SetSecrets(EncryptionHandshake handshake, HandshakeRole hands // byte[] token = Keccak.Compute(sharedSecret).Bytes; sharedSecret.CopyTo(tempConcat.Slice(32, 32)); byte[] aesSecret = Keccak.Compute(tempConcat).Bytes; - + sharedSecret.Clear(); aesSecret.CopyTo(tempConcat.Slice(32, 32)); byte[] macSecret = Keccak.Compute(tempConcat).Bytes; - + ephemeralSharedSecret.Clear(); handshake.Secrets = new EncryptionSecrets(); // handshake.Secrets.Token = token; diff --git a/src/Nethermind/Nethermind.Network/Rlpx/Packet.cs b/src/Nethermind/Nethermind.Network/Rlpx/Packet.cs index 35e0c9f1ed1..462437af4d9 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/Packet.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/Packet.cs @@ -25,7 +25,7 @@ public class Packet public Packet(ZeroPacket zeroPacket) { - Data = zeroPacket.Content.ReadAllBytes(); + Data = zeroPacket.Content.ReadAllBytesAsArray(); PacketType = zeroPacket.PacketType; Protocol = zeroPacket.Protocol; } diff --git a/src/Nethermind/Nethermind.Network/Rlpx/ZeroPacketSplitter.cs b/src/Nethermind/Nethermind.Network/Rlpx/ZeroPacketSplitter.cs index 26529cf271b..524a15ceb11 100644 --- a/src/Nethermind/Nethermind.Network/Rlpx/ZeroPacketSplitter.cs +++ b/src/Nethermind/Nethermind.Network/Rlpx/ZeroPacketSplitter.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -21,6 +21,7 @@ using DotNetty.Transport.Channels; using Nethermind.Core.Attributes; using Nethermind.Logging; +using Nethermind.Network.P2P; using Nethermind.Serialization.Rlp; namespace Nethermind.Network.Rlpx @@ -38,7 +39,7 @@ public void DisableFraming() { MaxFrameSize = int.MaxValue; } - + public int MaxFrameSize { get; private set; } = Frame.DefaultMaxFrameSize; private int _contextId; @@ -77,7 +78,7 @@ protected override void Encode(IChannelHandlerContext context, IByteBuffer input if (framesCount == 1) { // // commented out after Trinity reported #2052 - // // not 100% sure they are right but they may be + // // not 100% sure they are right but they may be // // 193|128 is an RLP encoded array with one element that is zero // /*3*/ // output.WriteByte(193); @@ -85,7 +86,7 @@ protected override void Encode(IChannelHandlerContext context, IByteBuffer input // output.WriteByte(128); // /*5-16*/ // output.WriteZero(11); - + // 194|128 is an RLP encoded array with two elements that are zero /*3*/ output.WriteByte(194); @@ -98,22 +99,21 @@ protected override void Encode(IChannelHandlerContext context, IByteBuffer input } else { - Rlp[] headerDataItems; + NettyRlpStream stream = new (output); + int contentLength = Rlp.LengthOf(_contextId) + Rlp.LengthOf(0); if (i == 0) { - headerDataItems = new Rlp[3]; - headerDataItems[2] = Rlp.Encode(totalPayloadSize); + contentLength += Rlp.LengthOf(totalPayloadSize); } - else + output.EnsureWritable(Rlp.LengthOfSequence(contentLength)); + stream.StartSequence(contentLength); + stream.Encode(0); + stream.Encode(_contextId); + if (i == 0) { - headerDataItems = new Rlp[2]; + stream.Encode(totalPayloadSize); } - - headerDataItems[1] = Rlp.Encode(_contextId); - headerDataItems[0] = Rlp.Encode(0); - byte[] headerDataBytes = Rlp.Encode(headerDataItems).Bytes; - output.WriteBytes(headerDataBytes); - output.WriteZero(Frame.HeaderSize - headerDataBytes.Length - 3); + output.WriteZero(Frame.HeaderSize - Rlp.LengthOfSequence(contentLength) - 3); } int framePacketTypeSize = 0; diff --git a/src/Nethermind/Nethermind.Network/ZeroMessageSerializerExtensions.cs b/src/Nethermind/Nethermind.Network/ZeroMessageSerializerExtensions.cs index f09773d190b..5c17c9f87c3 100644 --- a/src/Nethermind/Nethermind.Network/ZeroMessageSerializerExtensions.cs +++ b/src/Nethermind/Nethermind.Network/ZeroMessageSerializerExtensions.cs @@ -31,7 +31,7 @@ serializer is IZeroInnerMessageSerializer zeroInnerMessageSerializer try { serializer.Serialize(byteBuffer, message); - return byteBuffer.ReadAllBytes(); + return byteBuffer.ReadAllBytesAsArray(); } finally diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs index 85317352cfb..42430c64d13 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/BlockInfoDecoder.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -30,7 +30,7 @@ public class BlockInfoDecoder : IRlpStreamDecoder, IRlpValueDecoder, IRlpValueDecoder, IRlpValueDecoder. using System; using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; using Nethermind.Core; namespace Nethermind.Serialization.Rlp @@ -28,12 +30,12 @@ public class ChainLevelDecoder : IRlpStreamDecoder, IRlpValueDec { throw new RlpException($"Received a 0 length stream when decoding a {nameof(ChainLevelInfo)}"); } - + if (rlpStream.IsNextItemNull()) { return null; } - + int lastCheck = rlpStream.ReadSequenceLength() + rlpStream.Position; bool hasMainChainBlock = rlpStream.DecodeBool(); @@ -59,9 +61,28 @@ public class ChainLevelDecoder : IRlpStreamDecoder, IRlpValueDec return info; } - public void Encode(RlpStream stream, ChainLevelInfo item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) + public void Encode(RlpStream stream, ChainLevelInfo? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { - throw new NotImplementedException(); + if (item == null) + { + stream.Encode(Rlp.OfEmptySequence); + return; + } + + if (item.BlockInfos.Any(t => t == null)) + { + throw new InvalidOperationException($"{nameof(BlockInfo)} is null when encoding {nameof(ChainLevelInfo)}"); + } + + int contentLength = GetLength(item, rlpBehaviors); + stream.StartSequence(contentLength); + stream.Encode(item.HasBlockOnMainChain); + int infoLength = GetBlockInfoLength(item.BlockInfos); + stream.StartSequence(infoLength); + foreach (BlockInfo? blockInfo in item.BlockInfos) + { + stream.Encode(blockInfo); + } } public ChainLevelInfo? Decode(ref Rlp.ValueDecoderContext decoderContext, RlpBehaviors rlpBehaviors = RlpBehaviors.None) @@ -70,7 +91,7 @@ public void Encode(RlpStream stream, ChainLevelInfo item, RlpBehaviors rlpBehavi { return null; } - + int lastCheck = decoderContext.ReadSequenceLength() + decoderContext.Position; bool hasMainChainBlock = decoderContext.DecodeBool(); @@ -110,7 +131,7 @@ public Rlp Encode(ChainLevelInfo? item, RlpBehaviors rlpBehaviors = RlpBehaviors throw new InvalidOperationException($"{nameof(BlockInfo)} is null when encoding {nameof(ChainLevelInfo)}"); } } - + Rlp[] elements = new Rlp[2]; elements[0] = Rlp.Encode(item.HasBlockOnMainChain); elements[1] = Rlp.Encode(item.BlockInfos); @@ -121,7 +142,21 @@ public Rlp Encode(ChainLevelInfo? item, RlpBehaviors rlpBehaviors = RlpBehaviors public int GetLength(ChainLevelInfo item, RlpBehaviors rlpBehaviors) { - throw new NotImplementedException(); + int contentLength = 0; + contentLength += Rlp.LengthOf(item.HasBlockOnMainChain); + contentLength += Rlp.LengthOfSequence(GetBlockInfoLength(item.BlockInfos)); + return contentLength; + } + + private int GetBlockInfoLength(BlockInfo[] item) + { + int contentLength = 0; + foreach (BlockInfo? blockInfo in item) + { + contentLength += Rlp.LengthOf(blockInfo); + } + + return contentLength; } } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs index f57c3d4596f..b18d459a8fc 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/ReceiptMessageDecoder.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -26,7 +26,7 @@ static ReceiptMessageDecoder() { Rlp.Decoders[typeof(TxReceipt)] = new ReceiptMessageDecoder(); } - + public TxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { if (rlpStream.IsNextItemNull()) @@ -34,14 +34,14 @@ public TxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBeha rlpStream.ReadByte(); return null; } - + TxReceipt txReceipt = new(); if (!rlpStream.IsSequenceNext()) { rlpStream.SkipLength(); txReceipt.TxType = (TxType)rlpStream.ReadByte(); } - + _ = rlpStream.ReadSequenceLength(); byte[] firstItem = rlpStream.DecodeByteArray(); if (firstItem.Length == 1 && (firstItem[0] == 0 || firstItem[0] == 1)) @@ -59,7 +59,7 @@ public TxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBeha txReceipt.PostTransactionState = firstItem.Length == 0 ? null : new Keccak(firstItem); txReceipt.GasUsedTotal = (long) rlpStream.DecodeUBigInt(); } - + txReceipt.Bloom = rlpStream.DecodeBloom(); int lastCheck = rlpStream.ReadSequenceLength() + rlpStream.Position; @@ -75,29 +75,13 @@ public TxReceipt Decode(RlpStream rlpStream, RlpBehaviors rlpBehaviors = RlpBeha return txReceipt; } - public Rlp Encode(TxReceipt item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) - { - if (item.TxType == TxType.Legacy) - { - return Rlp.Encode( - (rlpBehaviors & RlpBehaviors.Eip658Receipts) == RlpBehaviors.Eip658Receipts - ? Rlp.Encode(item.StatusCode) - : Rlp.Encode(item.PostTransactionState), - Rlp.Encode(item.GasUsedTotal), - Rlp.Encode(item.Bloom), - Rlp.Encode(item.Logs)); - } - - return new Rlp(EncodeNew(item, rlpBehaviors)); - } - private (int Total, int Logs) GetContentLength(TxReceipt item, RlpBehaviors rlpBehaviors) { if (item == null) { return (0, 0); } - + int contentLength = 0; contentLength += Rlp.LengthOf(item.GasUsedTotal); contentLength += Rlp.LengthOf(item.Bloom); @@ -109,14 +93,14 @@ public Rlp Encode(TxReceipt item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) if (!item.SkipStateAndStatusInRlp) { - contentLength += isEip658Receipts - ? Rlp.LengthOf(item.StatusCode) + contentLength += isEip658Receipts + ? Rlp.LengthOf(item.StatusCode) : Rlp.LengthOf(item.PostTransactionState); } return (contentLength, logsLength); } - + private int GetLogsLength(TxReceipt item) { int logsLength = 0; @@ -124,7 +108,7 @@ private int GetLogsLength(TxReceipt item) { logsLength += Rlp.LengthOf(item.Logs[i]); } - + return logsLength; } @@ -144,20 +128,20 @@ public int GetLength(TxReceipt item, RlpBehaviors rlpBehaviors) : receiptPayloadLength; return result; } - + public byte[] EncodeNew(TxReceipt? item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { if (item is null) { return Rlp.OfEmptySequence.Bytes; } - + int length = GetLength(item, rlpBehaviors); RlpStream stream = new(length); Encode(stream, item, rlpBehaviors); return stream.Data; } - + public void Encode(RlpStream rlpStream, TxReceipt item, RlpBehaviors rlpBehaviors = RlpBehaviors.None) { if (item == null) @@ -168,16 +152,16 @@ public void Encode(RlpStream rlpStream, TxReceipt item, RlpBehaviors rlpBehavior (int totalContentLength, int logsLength) = GetContentLength(item, rlpBehaviors); int sequenceLength = Rlp.LengthOfSequence(totalContentLength); - + bool isEip658Receipts = (rlpBehaviors & RlpBehaviors.Eip658Receipts) == RlpBehaviors.Eip658Receipts; - + if (item.TxType != TxType.Legacy) { if ((rlpBehaviors & RlpBehaviors.SkipTypedWrapping) == RlpBehaviors.None) { rlpStream.StartByteArray(sequenceLength + 1, false); } - + rlpStream.WriteByte((byte)item.TxType); } @@ -196,7 +180,7 @@ public void Encode(RlpStream rlpStream, TxReceipt item, RlpBehaviors rlpBehavior rlpStream.Encode(item.GasUsedTotal); rlpStream.Encode(item.Bloom); - + rlpStream.StartSequence(logsLength); for (var i = 0; i < item.Logs.Length; i++) { diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs index 505d3235a82..77bbe8997c7 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/Rlp.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -35,11 +35,11 @@ namespace Nethermind.Serialization.Rlp public class Rlp { public const int LengthOfKeccakRlp = 33; - + public const int LengthOfAddressRlp = 21; internal const int DebugMessageContentLength = 2048; - + public const byte EmptyArrayByte = 128; public const byte NullObjectByte = 192; @@ -272,16 +272,16 @@ public static Rlp Encode( { sequence[position++] = Encode(transaction.GasPrice); } - + sequence[position++] = Encode(transaction.GasLimit); sequence[position++] = Encode(transaction.To); sequence[position++] = Encode(transaction.Value); sequence[position++] = Encode(transaction.Data); if (transaction.Type != TxType.Legacy) { - sequence[position++] = Encode(transaction.AccessList); + sequence[position++] = Encode(transaction.AccessList); } - + if (forSigning) { if (includeSigChainIdHack) @@ -304,10 +304,10 @@ public static Rlp Encode( { sequence[position++] = Encode(transaction.Type == TxType.Legacy ? signature.V : signature.RecoveryId); sequence[position++] = Encode(signature.RAsSpan.WithoutLeadingZeros()); - sequence[position++] = Encode(signature.SAsSpan.WithoutLeadingZeros()); + sequence[position++] = Encode(signature.SAsSpan.WithoutLeadingZeros()); } } - + Debug.Assert(position == 6 + extraItems); Rlp result = Encode(sequence); @@ -399,7 +399,7 @@ public static Rlp EncodeNonce(ulong value) BinaryPrimitives.WriteUInt64BigEndian(bytes, value); return Encode(bytes); } - + public static Rlp Encode(ulong value) { return Encode((long)value); @@ -812,14 +812,14 @@ public int PeekNextRlpLength() (int a, int b) = PeekPrefixAndContentLength(); return a + b; } - + public Span Peek(int length) { Span item = Read(length); Position -= item.Length; return item; } - + public (int PrefixLength, int ContentLength) ReadPrefixAndContentLength() { (int prefixLength, int contentLengt) result; @@ -865,16 +865,16 @@ public Span Peek(int length) result = (lengthOfContentLength + 1, contentLength); } - + return result; } - + public (int PrefixLength, int ContentLength) PeekPrefixAndContentLength() { int memorizedPosition = Position; (int PrefixLength, int ContentLength) result = ReadPrefixAndContentLength(); - + Position = memorizedPosition; return result; } @@ -958,7 +958,7 @@ public void Check(int nextCheck) } // This class was introduce to reduce allocations when deserializing receipts. In order to deserialize receipts we first try to deserialize it in new format and then in old format. - // If someone didn't do migration this will result in excessive allocations and GC of the not needed strings. + // If someone didn't do migration this will result in excessive allocations and GC of the not needed strings. private class DecodeKeccakRlpException : RlpException { private readonly int _prefix; @@ -1100,7 +1100,7 @@ public BigInteger DecodeUBigInt() // https://github.com/NethermindEth/nethermind/issues/113 if (Data[Position] == 249) { - Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes + Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes bloomBytes = Read(256); } else @@ -1128,7 +1128,7 @@ public void DecodeBloomStructRef(out BloomStructRef bloom) // https://github.com/NethermindEth/nethermind/issues/113 if (Data[Position] == 249) { - Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes + Position += 5; // tks: skip 249 1 2 129 127 and read 256 bytes bloomBytes = Read(256); } else @@ -1302,9 +1302,9 @@ public bool DecodeBool() throw new RlpException($"Unexpected prefix of {prefix} when decoding a byte array at position {Position} in the message of length {Length} starting with {Description}"); } - + private string Description => Data.Slice(0, Math.Min(DebugMessageContentLength, Length)).ToHexString(); - + public byte PeekByte() { return Data[Position]; @@ -1359,7 +1359,7 @@ public long DecodeLong() return result; } - + public ulong DecodeULong() { int prefix = ReadByte(); @@ -1523,7 +1523,7 @@ public static int LengthOf(Keccak? item) public static int LengthOf(Keccak[] keccaks, bool includeLengthOfSequenceStart = false) { int value = keccaks?.Length * LengthOfKeccakRlp ?? 0; - + if (includeLengthOfSequenceStart) { value = LengthOfSequence(value); @@ -1531,7 +1531,7 @@ public static int LengthOf(Keccak[] keccaks, bool includeLengthOfSequenceStart = return value; } - + public static int LengthOf(Address? item) { return item is null ? 1 : 21; @@ -1614,5 +1614,12 @@ public static int LengthOf(LogEntry item) IRlpDecoder? rlpDecoder = GetDecoder(); return rlpDecoder?.GetLength(item, RlpBehaviors.None) ?? throw new RlpException($"{nameof(Rlp)} does not support length of {nameof(LogEntry)}"); } + + public static int LengthOf(BlockInfo item) + { + IRlpDecoder? rlpDecoder = GetDecoder(); + return rlpDecoder?.GetLength(item, RlpBehaviors.None) ?? throw new RlpException($"{nameof(Rlp)} does not support length of {nameof(BlockInfo)}"); + } + } } diff --git a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs index 917c0285f3a..4e92c226398 100644 --- a/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs +++ b/src/Nethermind/Nethermind.Serialization.Rlp/RlpStream.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -29,6 +29,7 @@ public class RlpStream { private static readonly HeaderDecoder _headerDecoder = new(); private static readonly BlockDecoder _blockDecoder = new(); + private static readonly BlockInfoDecoder _blockInfoDecoder = new(); private static readonly TxDecoder _txDecoder = new(); private static readonly ReceiptMessageDecoder _receiptDecoder = new(); private static readonly LogEntryDecoder _logEntryDecoder = LogEntryDecoder.Instance; @@ -76,6 +77,11 @@ public void Encode(LogEntry value) _logEntryDecoder.Encode(this, value); } + public void Encode(BlockInfo value) + { + _blockInfoDecoder.Encode(this, value); + } + public void StartByteArray(int contentLength, bool firstByteLessThan128) { switch (contentLength) @@ -208,7 +214,7 @@ public void Encode(Keccak[] keccaks) } } } - + public void Encode(Address? address) { if (address == null) @@ -529,7 +535,7 @@ public int PeekNextRlpLength() (int a, int b) = PeekPrefixAndContentLength(); return a + b; } - + public (int PrefixLength, int ContentLength) ReadPrefixAndContentLength() { (int prefixLength, int contentLength) result; @@ -575,7 +581,7 @@ public int PeekNextRlpLength() result = (lengthOfContentLength + 1, contentLength); } - + return result; } @@ -583,11 +589,11 @@ public int PeekNextRlpLength() { int memorizedPosition = Position; (int PrefixLength, int ContentLength) result = ReadPrefixAndContentLength(); - + Position = memorizedPosition; return result; } - + public int ReadSequenceLength() { int prefix = ReadByte(); @@ -771,7 +777,7 @@ public BigInteger DecodeUBigInt() // https://github.com/NethermindEth/nethermind/issues/113 if (PeekByte() == 249) { - SkipBytes(5); // tks: skip 249 1 2 129 127 and read 256 bytes + SkipBytes(5); // tks: skip 249 1 2 129 127 and read 256 bytes bloomBytes = Read(256); } else @@ -796,7 +802,7 @@ public Span PeekNextItem() int length = PeekNextRlpLength(); return Peek(length); } - + public Span Peek(int length) { Span item = Read(length); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs index 4bae26a41a1..ee03297ab68 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/ParallelSync/SyncDispatcherTests.cs @@ -1,16 +1,16 @@ // Copyright (c) 2021 Demerzel Solutions Limited // This file is part of the Nethermind library. -// +// // The Nethermind library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // The Nethermind library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. -// +// // You should have received a copy of the GNU Lesser General Public License // along with the Nethermind. If not, see . @@ -150,7 +150,7 @@ protected override async Task Dispatch(PeerInfo allocation, TestBatch request, C } await Task.CompletedTask; - Console.WriteLine("Setting result"); + // Console.WriteLine("Setting result"); int[] result = new int[request.Length]; for (int i = 0; i < request.Length; i++) { @@ -158,7 +158,7 @@ protected override async Task Dispatch(PeerInfo allocation, TestBatch request, C } request.Result = result; - Console.WriteLine("Finished Execution"); + // Console.WriteLine("Finished Execution"); } } @@ -181,12 +181,12 @@ public override SyncResponseHandlingResult HandleResponse(TestBatch response, Pe { if (response.Result == null) { - Console.WriteLine("Handling failed response"); + // Console.WriteLine("Handling failed response"); _returned.Enqueue(response); } else { - Console.WriteLine("Handling OK response"); + // Console.WriteLine("Handling OK response"); for (int i = 0; i < response.Length; i++) { lock (_results) @@ -196,7 +196,7 @@ public override SyncResponseHandlingResult HandleResponse(TestBatch response, Pe } } - Console.WriteLine($"Decrementing Pending Requests {Interlocked.Decrement(ref _pendingRequests)}"); + // Console.WriteLine($"Decrementing Pending Requests {Interlocked.Decrement(ref _pendingRequests)}"); return SyncResponseHandlingResult.OK; } @@ -210,7 +210,7 @@ public override async Task PrepareRequest() TestBatch testBatch; if (_returned.TryDequeue(out TestBatch returned)) { - Console.WriteLine("Sending previously failed batch"); + // Console.WriteLine("Sending previously failed batch"); testBatch = returned; } else @@ -221,10 +221,10 @@ public override async Task PrepareRequest() if (_highestRequested >= Max) { - Console.WriteLine("Pending: " + _pendingRequests); + // Console.WriteLine("Pending: " + _pendingRequests); if (_pendingRequests == 0) { - Console.WriteLine("Changing to finished"); + // Console.WriteLine("Changing to finished"); Finish(); } @@ -240,7 +240,7 @@ public override async Task PrepareRequest() testBatch = new TestBatch(start, 8); } - Console.WriteLine($"Incrementing Pending Requests {Interlocked.Increment(ref _pendingRequests)}"); + // Console.WriteLine($"Incrementing Pending Requests {Interlocked.Increment(ref _pendingRequests)}"); return testBatch; } } diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs index e7e26d4d6bc..b4db2c122ef 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SyncPeerPoolTests.cs @@ -725,13 +725,13 @@ private async Task DoWork(string desc, SyncPeerAllocation allocation) if (allocation.HasPeer) { int workTime = _workRandomDelay.Next(1000); - Console.WriteLine($"{desc} will work for {workTime} ms"); + // Console.WriteLine($"{desc} will work for {workTime} ms"); await Task.Delay(workTime); - Console.WriteLine($"{desc} finished work after {workTime} ms"); + // Console.WriteLine($"{desc} finished work after {workTime} ms"); } ctx.Pool.Free(allocation); - Console.WriteLine($"{desc} freed allocation"); + // Console.WriteLine($"{desc} freed allocation"); } [Test, Retry(3)] @@ -761,12 +761,12 @@ public async Task Try_to_break_multithreaded() task.ContinueWith(t => #pragma warning restore 4014 { - Console.WriteLine($"{iterationsLocal} Decrement on {t.IsCompleted}"); + // Console.WriteLine($"{iterationsLocal} Decrement on {t.IsCompleted}"); Interlocked.Decrement(ref _pendingRequests); }); } - Console.WriteLine(iterations + " " + failures + " " + ctx.Pool.ReplaceableAllocations.Count() + " " + _pendingRequests); + // Console.WriteLine(iterations + " " + failures + " " + ctx.Pool.ReplaceableAllocations.Count() + " " + _pendingRequests); await Task.Delay(10); } while (iterations-- > 0 || _pendingRequests > 0); diff --git a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs index 3008a2380f6..a643e0a5565 100644 --- a/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs +++ b/src/Nethermind/Nethermind.Synchronization.Test/SynchronizerTests.cs @@ -182,7 +182,7 @@ public Task GetBlockHeaders(Keccak startHash, int maxBlocks, int { if (_causeTimeoutOnInit) { - Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER WITH EXCEPTION"); + // Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER WITH EXCEPTION"); await Task.FromException(new TimeoutException()); } @@ -193,11 +193,11 @@ public Task GetBlockHeaders(Keccak startHash, int maxBlocks, int } catch (Exception) { - Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER EXCEPTION"); + // Console.WriteLine("RESPONDING TO GET HEAD BLOCK HEADER EXCEPTION"); throw; } - Console.WriteLine($"RESPONDING TO GET HEAD BLOCK HEADER WITH RESULT {header.Number}"); + // Console.WriteLine($"RESPONDING TO GET HEAD BLOCK HEADER WITH RESULT {header.Number}"); return header; } @@ -744,7 +744,7 @@ public void Can_extend_chain_by_more_than_one_on_new_block_message() .AfterNewBlockMessage(peerA.HeadBlock, peerA) .BestSuggestedHeaderIs(peerA.HeadHeader).Wait().Stop(); - Console.WriteLine("why?"); + // Console.WriteLine("why?"); } [Test, Retry(3)]